[vassalengine-svn-trunk] [vassalengine-svn] SF.net SVN: vassalengine:[9199] VSQL-src/trunk
Brought to you by:
rodneykinney,
uckelman
From: <swa...@us...> - 2015-05-28 11:27:13
|
Revision: 9199 http://sourceforge.net/p/vassalengine/svn/9199 Author: swampwallaby Date: 2015-05-28 11:27:08 +0000 (Thu, 28 May 2015) Log Message: ----------- v6 board support full QC integration Updated icons and toolbars Modified Paths: -------------- VSQL-src/trunk/VASL/build/module/ASLMap.java VSQL-src/trunk/VASL/build/module/map/ASLBoardPicker.java VSQL-src/trunk/VASL/build/module/map/BoardSwapper.java VSQL-src/trunk/VASL/build/module/map/BoardVersionChecker.java VSQL-src/trunk/VASL/build/module/map/HindranceKeeper.java VSQL-src/trunk/VASL/build/module/map/QC.java VSQL-src/trunk/VASL/build/module/map/boardPicker/ASLBoard.java VSQL-src/trunk/VASL/build/module/map/boardPicker/ASLBoardSlot.java VSQL-src/trunk/VASL/build/module/map/boardPicker/BoardException.java VSQL-src/trunk/VASL/build/module/map/boardPicker/Overlay.java VSQL-src/trunk/VASL/build/module/map/boardPicker/SSRFilter.java VSQL-src/trunk/VASL/build/module/map/boardPicker/SSROverlay.java VSQL-src/trunk/VASL/build/module/map/boardPicker/Underlay.java VSQL-src/trunk/VSQL/VSQLHindranceKeeper.java VSQL-src/trunk/VSQL/VSQLMap.java VSQL-src/trunk/VSQL/VSQLThread.java Added Paths: ----------- VSQL-src/trunk/VASL/LOS/ VSQL-src/trunk/VASL/LOS/LOSDataEditor.java VSQL-src/trunk/VASL/LOS/Map/ VSQL-src/trunk/VASL/LOS/Map/Bridge.java VSQL-src/trunk/VASL/LOS/Map/Counter.java VSQL-src/trunk/VASL/LOS/Map/Hex.java VSQL-src/trunk/VASL/LOS/Map/LOSResult.java VSQL-src/trunk/VASL/LOS/Map/Location.java VSQL-src/trunk/VASL/LOS/Map/Map.java VSQL-src/trunk/VASL/LOS/Map/OBA.java VSQL-src/trunk/VASL/LOS/Map/Smoke.java VSQL-src/trunk/VASL/LOS/Map/Terrain.java VSQL-src/trunk/VASL/LOS/Map/VASLGameInterface.java VSQL-src/trunk/VASL/LOS/Map/Vehicle.java VSQL-src/trunk/VASL/LOS/Map/Wreck.java VSQL-src/trunk/VASL/build/module/map/ASLBrokenFinder.java VSQL-src/trunk/VASL/build/module/map/ASLImageSaver.java VSQL-src/trunk/VASL/build/module/map/ASLTextSaver.java VSQL-src/trunk/VASL/build/module/map/VASLThread.java VSQL-src/trunk/VASL/build/module/map/boardArchive/ VSQL-src/trunk/VASL/build/module/map/boardArchive/AbstractMetadata.java VSQL-src/trunk/VASL/build/module/map/boardArchive/BoardArchive.java VSQL-src/trunk/VASL/build/module/map/boardArchive/BoardColor.java VSQL-src/trunk/VASL/build/module/map/boardArchive/BoardMetadata.java VSQL-src/trunk/VASL/build/module/map/boardArchive/ColorSSRule.java VSQL-src/trunk/VASL/build/module/map/boardArchive/LOSCounterRule.java VSQL-src/trunk/VASL/build/module/map/boardArchive/LOSSSRule.java VSQL-src/trunk/VASL/build/module/map/boardArchive/OverlaySSRule.java VSQL-src/trunk/VASL/build/module/map/boardArchive/SharedBoardMetadata.java VSQL-src/trunk/VASL/build/module/map/boardArchive/Slopes.java VSQL-src/trunk/VASL/build/module/map/boardArchive/UnderlaySSRule.java VSQL-src/trunk/VASL/build/module/map/boardPicker/VASLBoard.java VSQL-src/trunk/VSQL/VSQLLayerControl.java VSQL-src/trunk/VSQL/VSQLLayeredPieceCollection.java Added: VSQL-src/trunk/VASL/LOS/LOSDataEditor.java =================================================================== --- VSQL-src/trunk/VASL/LOS/LOSDataEditor.java (rev 0) +++ VSQL-src/trunk/VASL/LOS/LOSDataEditor.java 2015-05-28 11:27:08 UTC (rev 9199) @@ -0,0 +1,724 @@ +package VASL.LOS; + +import VASL.LOS.Map.*; +import VASL.build.module.map.boardArchive.BoardArchive; +import VASL.build.module.map.boardArchive.SharedBoardMetadata; + +import java.awt.*; +import java.awt.geom.AffineTransform; +import java.awt.image.BufferedImage; +import java.io.IOException; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Vector; + + +/** + * LOSDataEditor is used to edit the LOS data. + * It's used by the LOS GUI and dynamically by VASL to perform SSR terrain changes + */ +public class LOSDataEditor { + + // the LOS data + Map map; + + // the board archive and shared board metadata + BoardArchive boardArchive; + SharedBoardMetadata sharedBoardMetadata; + + // for terrain and elevation encoding while creating LOS data + private static final int UNKNOWN_TERRAIN = 255; + private static final int TERRAIN_OFFSET = 128; + private static final int UNKNOWN_ELEVATION = -10; + private static final int ELEVATION_OFFSET = 50; + + /** + * Creates an LOS data editor for a VASL archive + * + * @param boardName the name of the VASL board archive file + * @param boardDirectory the VASL board archive directory + * @throws java.io.IOException if the archive cannot be opened + */ + public LOSDataEditor(String boardName, String boardDirectory, SharedBoardMetadata sharedBoardMetadata) throws IOException { + + boardArchive = new BoardArchive(boardName, boardDirectory, sharedBoardMetadata); + this.sharedBoardMetadata = sharedBoardMetadata; + + // create an empty map + map = createNewLOSData(); + } + + /** + * Creates an LOS data editor for an existing map + * IMPORTANT use only for changing the terrain on an existing map + * + * @param map the map + */ + public LOSDataEditor(Map map) { + this.map = map; + } + + public Map createNewLOSData() { + + Map m; + if (boardArchive.isGEO()) { + + m = new Map( + boardArchive.getBoardWidth(), + boardArchive.getBoardHeight(), + sharedBoardMetadata.getTerrainTypes()); + m.setSlopes(boardArchive.getSlopes()); + } else { + m = new Map( + boardArchive.getBoardWidth(), + boardArchive.getBoardHeight(), + boardArchive.getA1CenterX(), + boardArchive.getA1CenterY(), + boardArchive.getBoardImage().getWidth(), + boardArchive.getBoardImage().getHeight(), + sharedBoardMetadata.getTerrainTypes()); + m.setSlopes(boardArchive.getSlopes()); + } + return m; + } + + //TODO: removed redundancy in these private methods + + /** + * Find the nearest terrain to a pixel of unknown terrain. E.g. the hex center dot will have unknown terrain + * + * @param x x value of pixel + * @param y y value of pixel + * @return + */ + private Terrain getNearestTerrain(int x, int y) { + + int min = 0; + int max = 1; + Terrain terrainType; + + // search at most 5 pixels out + while (max <= 5) { + for (int i = x - max; i <= x + max; i++) { + for (int j = y - max; j <= y + max; j++) { + + // this logic make the search radius circular + if (map.onMap(i, j) && Point.distance((double) x, (double) y, (double) i, (double) j) > min && + Point.distance((double) x, (double) y, (double) i, (double) j) <= max && + map.getGridTerrainCode(i, j) != UNKNOWN_TERRAIN && + map.getGridTerrainCode(i, j) < TERRAIN_OFFSET) { + + terrainType = map.getGridTerrain(i, j); + + // ignore inherent terrain + if (!terrainType.isInherentTerrain()) { + return terrainType; + } + } + } + } + + min++; + max++; + } + + // if no terrain within 5 pixels then punt and use open ground + return map.getTerrain("Open Ground"); + } + + /** + * Find the nearest elevation to a pixel of unknown elevation. E.g. the hex center dot will have unknown elevation + * + * @param x x value of pixel + * @param y y value of pixel + * @return + */ + private int getNearestElevation(int x, int y) { + + int min = 0; + int max = 1; + + // search at most 50 pixels out + while (max <= 50) { + for (int i = x - max; i <= x + max; i++) { + for (int j = y - max; j <= y + max; j++) { + + // this logic makes the search radius circular + if (map.onMap(i, j) && Point.distance((double) x, (double) y, (double) i, (double) j) > min && + Point.distance((double) x, (double) y, (double) i, (double) j) <= max && + map.getGridElevation(i, j) != UNKNOWN_ELEVATION && + map.getGridElevation(i, j) < ELEVATION_OFFSET - 5) { // need a buffer for negative elevations + + return map.getGridElevation(i, j); + } + } + } + + min++; + max++; + } + + // if no elevation within 5 pixels then punt and use level 0 + return 0; + } + + /** + * Add the elevation and terrain code for each pixel in the map. + * If the terrain/elevation is unknown mark it as such. + */ + private void setAllTerrain() { + + // read the board image + BufferedImage boardImage = boardArchive.getBoardImage(); + + for (int x = 0; x < map.getGridWidth(); x++) { + for (int y = 0; y < map.getGridHeight(); y++) { + + Color color = getRGBColor(boardImage, x, y); + + int elevation = boardArchive.getElevationForColor(color); + int terrain = boardArchive.getTerrainForColor(color); + + // set the elevation in the map grid + if (boardArchive.boardHasElevations()) { // ignore boards without elevation + + if (elevation == BoardArchive.getNoElevationColorCode()) { + map.setGridElevation(UNKNOWN_ELEVATION, x, y); + } else { + map.setGridElevation(elevation, x, y); + } + } + + // set the terrain type in the map grid + if (terrain == BoardArchive.getNoTerrainColorCode()) { + map.setGridTerrainCode(UNKNOWN_TERRAIN, x, y); + } else { + map.setGridTerrainCode(terrain, x, y); + } + } + } + } + + /** + * find nearest terrains for unknown terrain or elevation + * The "offset" is a temporary encoding that records the correct terrain/elevation + * but allows us to ignore the pixel when finding the nearest terrain/elevation of its neighbors. + * Otherwise the "nearest terrain" will bleed to pixels it shouldn't + */ + private void setAllUnknownTerrain() { + + // find the nearest terrain encoding as we go + for (int x = 0; x < map.getGridWidth(); x++) { + for (int y = 0; y < map.getGridHeight(); y++) { + + if (map.getGridTerrainCode(x, y) == UNKNOWN_TERRAIN) { + map.setGridTerrainCode(getNearestTerrain(x, y).getType() + TERRAIN_OFFSET, x, y); + } + + if (map.getGridElevation(x, y) == UNKNOWN_ELEVATION) { + map.setGridElevation(getNearestElevation(x, y) + ELEVATION_OFFSET, x, y); + } + } + } + + // remove the terrain encoding + for (int x = 0; x < map.getGridWidth(); x++) { + for (int y = 0; y < map.getGridHeight(); y++) { + if (map.getGridTerrainCode(x, y) >= TERRAIN_OFFSET) { + map.setGridTerrainCode(map.getGridTerrainCode(x, y) - TERRAIN_OFFSET, x, y); + } + if (map.getGridElevation(x, y) >= ELEVATION_OFFSET / 2) { + map.setGridElevation(map.getGridElevation(x, y) - ELEVATION_OFFSET, x, y); + } + } + } + } + + /** + * Create the LOS data from the board image in the VASL archive + * Assumes the file helpers have been set + */ + public void createLOSData() { + + // create an empty map + map = createNewLOSData(); + + // spin through the terrain and elevation grids and add the terrain codes + setAllTerrain(); + + // fix pixels that have no terrain or elevation code (E.g. the hex center dot) + setAllUnknownTerrain(); + + // we need to occasionally update the hex grid as the following processes need updated hex information + map.resetHexTerrain(); + + // fix cliff elevation pixels - set them to the lower of the two hex elevations + for (int x = 0; x < map.getGridWidth(); x++) { + for (int y = 0; y < map.getGridHeight(); y++) { + + if (map.getGridTerrain(x, y) == map.getTerrain("Cliff")) { + + Hex hex = map.gridToHex(x, y); + Hex oppositeHex = map.getAdjacentHex(hex, hex.getLocationHexside(hex.getNearestLocation(x, y))); + + if (oppositeHex == null) { + map.setGridElevation(hex.getBaseHeight(), x, y); + } else { + map.setGridElevation(Math.min(hex.getBaseHeight(), oppositeHex.getBaseHeight()), x, y); + } + } + } + } + + // apply building-type transformations + HashMap<String, String> buildingTypes = boardArchive.getBuildingTypes(); + for (String hex : buildingTypes.keySet()) { + + Hex h = map.getHex(hex); + Terrain toTerrain = map.getTerrain(buildingTypes.get(hex)); + changeAllTerrain(h.getCenterLocation().getTerrain(), toTerrain, h.getHexBorder()); + } + setExteriorFactoryWalls(); + + map.resetHexTerrain(); + + // set depression elevations + for (int x = 0; x < map.getGridWidth(); x++) { + for (int y = 0; y < map.getGridHeight(); y++) { + + if (map.getGridTerrain(x, y).isDepression()) { + + map.setGridElevation(map.getGridElevation(x, y) - 1, x, y); + } + } + } + + map.resetHexTerrain(); + + fixElevatedSunkenRoads(); + + map.resetHexTerrain(); + + addStairways(); + } + + /** + * Spins through the map and adds stairways + */ + private void addStairways() { + + BufferedImage boardImage = boardArchive.getBoardImage(); + + for (int x = 0; x < map.getGridWidth(); x++) { + for (int y = 0; y < map.getGridHeight(); y++) { + + if (boardArchive.isStairwayColor(getRGBColor(boardImage, x, y))) { + map.gridToHex(x, y).setStairway(true); + } + } + } + } + + /** + * This is a kludge to fix elevated and sunken roads as they use the same colors + */ + private void fixElevatedSunkenRoads() { + + for (int x = 0; x < map.getGridWidth(); x++) { + for (int y = 0; y < map.getGridHeight(); y++) { + + if (map.getGridTerrain(x, y).getName().equals("Sunken Road")) { + + // fix elevated roads + if (map.gridToHex(x, y).getBaseHeight() == 1) { + map.setGridElevation(1, x, y); + map.setGridTerrainCode(map.getTerrain("Elevated Road").getType(), x, y); + } + + // fix sunken roads + else { + map.setGridElevation(-1, x, y); + } + } + } + } + } + + /* + Get a <code>Color</code> object for a given pixel + */ + private Color getRGBColor(BufferedImage image, int x, int y) { + + int c = image.getRGB(x, y); + int red = (c & 0x00ff0000) >> 16; + int green = (c & 0x0000ff00) >> 8; + int blue = c & 0x000000ff; + return new Color(red, green, blue); + + } + + public Map getMap() { + return map; + } + + /** + * Determine where exterior factory wall exist + * For factories, we need to set where the "boundary" of the factory is, + * replacing it with the appropriate factory wall terrain. + */ + private void setExteriorFactoryWalls() { + + // set the walls + for (int x = 0; x < map.getGridWidth(); x++) { + for (int y = 0; y < map.getGridHeight(); y++) { + + Terrain terr = map.getGridTerrain(x, y); + int newTerr = terr.getType(); + if (terr.getName().equals("Wooden Factory, 1.5 Level")) { + newTerr = map.getTerrain("Wooden Factory Wall, 1.5 Level").getType(); + } else if (terr.getName().equals("Wooden Factory, 2.5 Level")) { + newTerr = map.getTerrain("Wooden Factory Wall, 2.5 Level").getType(); + } else if (terr.getName().equals("Stone Factory, 1.5 Level")) { + newTerr = map.getTerrain("Stone Factory Wall, 1.5 Level").getType(); + } else if (terr.getName().equals("Stone Factory, 2.5 Level")) { + newTerr = map.getTerrain("Stone Factory Wall, 2.5 Level").getType(); + } + + if (map.getGridTerrain(x, y).isFactoryTerrain() && + (!map.getGridTerrain(Math.max(x - 1, 0), y).isFactoryTerrain() || + !map.getGridTerrain(Math.min(x + 1, map.getGridWidth()), y).isFactoryTerrain() || + !map.getGridTerrain(x, Math.max(y - 1, 0)).isFactoryTerrain() || + !map.getGridTerrain(x, Math.min(y + 1, map.getGridHeight())).isFactoryTerrain()) + ) { + map.setGridTerrainCode(newTerr, x, y); + } + } + } + } + + /** + * Determine where factory wall exist for the given terrain type within a rectangular area. + * For factories, we need to set where the "boundry" of the factory is, + * replacing it with the appropriate factory wall terrian. + * + * @param rect map area to update + * @param terr building terrain type + */ + protected void setFactoryWalls(Rectangle rect, Terrain terr) { + + int startX = (int) rect.getX(); + int startY = (int) rect.getY(); + + // map the terrain + int newTerr = terr.getType(); + if (terr.getName().equals("Wooden Factory, 1.5 Level")) { + newTerr = map.getTerrain("Wooden Factory Wall, 1.5 Level").getType(); + } else if (terr.getName().equals("Wooden Factory, 2.5 Level")) { + newTerr = map.getTerrain("Wooden Factory Wall, 2.5 Level").getType(); + } + if (terr.getName().equals("Stone Factory, 1.5 Level")) { + newTerr = map.getTerrain("Stone Factory Wall, 1.5 Level").getType(); + } + if (terr.getName().equals("Stone Factory, 2.5 Level")) { + newTerr = map.getTerrain("Stone Factory Wall, 2.5 Level").getType(); + } + + // set the walls + for (int x = Math.max(startX, 0); + x < Math.min(startX + rect.getWidth(), map.getGridWidth()); + x++) { + for (int y = Math.max(startY, 0); + y < Math.min(startY + rect.getHeight(), map.getGridHeight()); + y++) { + + if (map.getGridTerrain(x, y).isFactoryTerrain() && + (!map.getGridTerrain(Math.max(x - 1, 0), y).isFactoryTerrain() || + !map.getGridTerrain(Math.min(x + 1, map.getGridWidth()), y).isFactoryTerrain() || + !map.getGridTerrain(x, Math.max(y - 1, 0)).isFactoryTerrain() || + !map.getGridTerrain(x, Math.min(y + 1, map.getGridHeight())).isFactoryTerrain()) + ) { + map.setGridTerrainCode(newTerr, x, y); + } + } + } + } + + /** + * Sets all pixels within the given shape to the new terrain type. + * + * @param s map area to update + * @param terr new terrain type + */ + // set the grid terrain for an arbitrary shape + public void setGridTerrain(Shape s, Terrain terr) { + + Rectangle rect = s.getBounds(); + int startX = (int) rect.getX(); + int startY = (int) rect.getY(); + int terrType = terr.getType(); + + // set the terrain in the map grid + for (int x = Math.max(startX, 0); + x < Math.min(startX + rect.getWidth(), map.getGridWidth()); + x++) { + for (int y = Math.max(startY, 0); + y < Math.min(startY + rect.getHeight(), map.getGridHeight()); + y++) { + + if (s.contains(x, y)) { + + // only apply rowhouse/factory walls to buildings + if (terr.isRowhouseWall()) { + + Terrain currentTerrain = map.getGridTerrain(x, y); + + //map rowhouse height to current building height + if (currentTerrain.getName().equals("Stone Building") || currentTerrain.getName().equals("Wooden Building")) { + map.setGridTerrainCode(map.getTerrain("Rowhouse Wall").getType(), x, y); + } else if (currentTerrain.getName().equals("Stone Building, 1 Level") || + currentTerrain.getName().equals("Wooden Building, 1 Level") || + currentTerrain.getName().equals("Stone Factory, 1.5 Level") || + currentTerrain.getName().equals("Wooden Factory, 1.5 Level")) { + map.setGridTerrainCode(map.getTerrain("Rowhouse Wall, 1 Level").getType(), x, y); + } else if (currentTerrain.getName().equals("Stone Building, 2 Level") || + currentTerrain.getName().equals("Wooden Building, 2 Level") || + currentTerrain.getName().equals("Stone Factory, 2.5 Level") || + currentTerrain.getName().equals("Wooden Factory, 2.5 Level")) { + map.setGridTerrainCode(map.getTerrain("Rowhouse Wall, 2 Level").getType(), x, y); + } else if (currentTerrain.getName().equals("Stone Building, 3 Level") || currentTerrain.getName().equals("Wooden Building, 3 Level")) { + map.setGridTerrainCode(map.getTerrain("Rowhouse Wall, 3 Level").getType(), x, y); + } else if (currentTerrain.getName().equals("Stone Building, 4 Level") || currentTerrain.getName().equals("Wooden Building, 4 Level")) { + map.setGridTerrainCode(map.getTerrain("Rowhouse Wall, 4 Level").getType(), x, y); + } + } + + // special rule for Heavy Jungle - don't replace water + else if ("Dense Jungle".equals(terr.getName())) { + + if (!(map.getGridTerrain(x, y).getLOSCategory() == Terrain.LOSCategories.WATER)) { + map.setGridTerrainCode(terrType, x, y); + } + } else { + map.setGridTerrainCode(terrType, x, y); + } + } + } + } + } + + + /** + * Sets the ground level of all pixels within the given shape to the new terrain height. + * + * @param s map area to update + * @param terr applicable depression terrain + * @param level new ground level + */ + public void setGridGroundLevel(Shape s, Terrain terr, int level) { + + setGridGroundLevel(s, s.getBounds(), terr, level); + } + + /** + * Returns a set of hexes that intersect ("touch") the given rectangle. + * + * @param rect map area + * @return a Vector containing the intersecting hexes + */ + public Vector intersectedHexes(Map map, Rectangle rect) { + + Vector<Hex> hexes = new Vector<Hex>(5, 5); + Hex currentHex; + + // find the hexes in the corner of the rectangle, clip to map boundry + Hex upperLeft = map.gridToHex( + Math.max((int) rect.getX(), 0), + Math.max((int) rect.getY(), 0)); + Hex lowerRight = map.gridToHex( + Math.min((int) (rect.getX() + rect.getWidth()), map.getGridWidth() - 1), + Math.min((int) (rect.getY() + rect.getHeight()), map.getGridHeight() - 1)); + + // Rectangle completely in a single hex? Add the hex and quit + if (upperLeft == lowerRight) { + + hexes.addElement(upperLeft); + return hexes; + } + + // our desired bounds + int minX = Math.max(upperLeft.getColumnNumber() - 1, 0); + int minY = Math.max(upperLeft.getRowNumber() - 1, 0); + int maxX = Math.min(lowerRight.getColumnNumber() + 1, map.getWidth() - 1); + int maxY = Math.min(lowerRight.getRowNumber() + 1, map.getHeight()); + + // check all hexes bound by the corners to the vector + for (int x = minX; x <= maxX; x++) { + for (int y = minY; + y <= Math.min(maxY, map.getHexGrid()[x].length - 1); + y++) { + currentHex = map.getHex(x, y); + + // add hexes that touch + if (currentHex.isTouchedBy(rect)) { + hexes.addElement(map.getHex(x, y)); + } + } + } + return hexes; + } + + //TODO: does area need to be a parameter? + + /** + * Sets the grid map ground level for a section of map + * + * @param s the area to set + * @param area area of the map to update + * @param terr applicable depression terrain + * @param newElevation the new elevation + */ + private void setGridGroundLevel(Shape s, Rectangle area, Terrain terr, int newElevation) { + + // get the rectangle variables once + int locX = (int) area.getX(); + int locY = (int) area.getY(); + int width = (int) area.getWidth(); + int height = (int) area.getHeight(); + + Hex currentHex; + + // step through each pixel in the rectangle + for (int x = Math.max(locX, 0); x <= Math.min(locX + width, map.getGridWidth() - 1); x++) { + for (int y = Math.max(locY, 0); y <= Math.min(locY + height, map.getGridHeight() - 1); y++) { + + // point in brush? + if (s == null || s.contains(x, y)) { + + // setting to depression hex? + if (terr != null) { + + // set the current hex + currentHex = map.gridToHex(x, y); + + // if we're already a depression, use the current elevation + if (currentHex.isDepressionTerrain()) { + map.setGridElevation(currentHex.getBaseHeight(), x, y); + } else { + map.setGridElevation(currentHex.getBaseHeight() - 1, x, y); + } + } else { + map.setGridElevation(newElevation, x, y); + } + } + } + } + } + + /** + * Maps all terrain from one type to another within a given shape. + * + * @parameter fromTerrain original terrain to replace + * @parameter toTerrain new terrain type + * @parameter s area of the map to change + */ + public boolean changeAllTerrain(Terrain fromTerrain, Terrain toTerrain, Shape s) { + + char fromTerrainType = (char) fromTerrain.getType(); + char toTerrainType = (char) toTerrain.getType(); + + boolean changed = false; + + // change the map grid + for (int i = 0; i < map.getGridWidth(); i++) { + for (int j = 0; j < map.getGridHeight(); j++) { + if (map.getGridTerrain(i, j).getType() == fromTerrainType && s.contains((double) i, (double) j)) { + + map.setGridTerrainCode(toTerrainType, i, j); + changed = true; + } + } + } + + // change the hex grid + for (int col = 0; col < map.getWidth(); col++) { + for (int row = 0; row < map.getHeight() + (col % 2); row++) { + + Hex[][] hexGrid = map.getHexGrid(); + + if (hexGrid[col][row].getHexBorder().intersects(s.getBounds())) { + + hexGrid[col][row].changeAllTerrain(fromTerrain, toTerrain, s); + changed = true; + } + } + } + + return changed; + } + + /** + * Maps all ground level elevation from one level to another within a given shape. + * + * @parameter fromElevation original ground level elevation to replace + * @parameter toTerrain new ground level elevation + */ + public boolean changeAllGroundLevel(int fromElevation, int toElevation, Shape s) { + + boolean changed = false; + + // change the map grid + for (int i = 0; i < map.getGridWidth(); i++) { + for (int j = 0; j < map.getGridHeight(); j++) { + if (map.getGridElevation(i, j) == fromElevation && s.contains((double) i, (double) j)) { + + map.setGridElevation(toElevation, i, j); + changed = true; + } + } + } + + // change the base height of the hex grid + for (int col = 0; col < map.getWidth(); col++) { + for (int row = 0; row < map.getHeight() + (col % 2); row++) { + + Hex[][] hexGrid = map.getHexGrid(); + + if (hexGrid[col][row].getBaseHeight() == fromElevation && + hexGrid[col][row].getHexBorder().intersects(s.getBounds())) { + + hexGrid[col][row].setBaseHeight(toElevation); + changed = true; + } + } + } + return changed; + } + + /** + * Rotates the map 180 degrees. Should only be used for geomorphic map boards + */ + public void flip() { + + map.flip(); + } + + /** + * Read the LOS data or create it if it doesn't exist + */ + public void readLOSData() { + + map = boardArchive.getLOSData(); + + if (map == null) { + + // convert the image + createLOSData(); + } + } + + public BufferedImage getBoardImage() { + + return boardArchive.getBoardImage(); + } + +} Property changes on: VSQL-src/trunk/VASL/LOS/LOSDataEditor.java ___________________________________________________________________ Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Added: VSQL-src/trunk/VASL/LOS/Map/Bridge.java =================================================================== --- VSQL-src/trunk/VASL/LOS/Map/Bridge.java (rev 0) +++ VSQL-src/trunk/VASL/LOS/Map/Bridge.java 2015-05-28 11:27:08 UTC (rev 9199) @@ -0,0 +1,221 @@ +/* + * Copyright (c) 2000-2003 by David Sullivan + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License (LGPL) as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, copies are available + * at http://www.opensource.org. + */ +package VASL.LOS.Map; + +import VASL.build.module.map.boardArchive.BoardArchive; + +import java.awt.*; +import java.awt.geom.AffineTransform; + +/** + * Title: Bridge.java + * Copyright: Copyright (c) 2001 David Sullivan Zuericher Strasse 6 12205 Berlin Germany. All rights reserved. + * @author David Sullivan + * @version 1.0 + */ +public class Bridge { + + // public constants + public static final int CUSTOM_BRIDGE_WIDTH = (int) BoardArchive.GEO_HEX_HEIGHT /4; + public static final int CUSTOM_BRIDGE_HEIGHT = (int) BoardArchive.GEO_HEX_HEIGHT; + public static final int ROAD_AREA_INSET = 2; + + public static final int SINGLE_HEX_CUSTOM_BRIDGE_WIDTH = 32; + public static final int SINGLE_HEX_CUSTOM_BRIDGE_HEIGHT = 48; + public static final int SINGLE_HEX_ROAD_AREA_INSET = 9; + + // private variables + private Terrain terrain; // woodBridge or stoneBridge + private int roadLevel; // absolute level of the road + private int rotation; // orientation of road + private Location location; // unit location on bridge + private boolean singleHex; // single hex bridge or span two hexsides? + private Point center; // center point of bridge + private transient Shape shape; + private transient Shape roadShape; + + // constructors + public Bridge( + Terrain newTerrain, + int newRoadLevel, + int newRotation, + Location newLocation, + boolean newSingleHex, + Point newCenter + ) { + + terrain = newTerrain; + roadLevel = newRoadLevel; + rotation = newRotation; + location = newLocation; + singleHex = newSingleHex; + center = newCenter; + + setShape(); + setRoadShape(); + } + + public Bridge( + Terrain newTerrain, + int newRoadLevel, + int newRotation, + Location newLocation, + boolean newSingleHex + ) { + + terrain = newTerrain; + roadLevel = newRoadLevel; + rotation = newRotation; + location = newLocation; + singleHex = newSingleHex; + center = new Point(0, 0); + + setShape(); + setRoadShape(); + } + + public Terrain getTerrain(){ return terrain;} + public int getRoadLevel(){ return roadLevel;} + public int getRotation(){ return rotation;} + public Location getLocation(){ return location;} + public void setLocation(Location newLocation){ location = newLocation;} + public Point getCenter(){ return center;} + public void setCenter(Point newCenter){ + + center = newCenter; + setShape(); + setRoadShape(); + } + + public void setRotation(int newRotation){ + + rotation = newRotation; + setShape(); + setRoadShape(); + } + public boolean isSingleHex(){return singleHex;} + public Shape getShape(){ + + if (shape == null){ + + setShape(); + } + return shape; + } + public Shape getRoadShape(){ + + if (roadShape == null){ + + setRoadShape(); + } + return roadShape; + } + + private void setShape(){ + + AffineTransform at = AffineTransform.getRotateInstance( + Math.toRadians(rotation), (int) center.getX(), (int) center.getY()); + + if (singleHex){ + + shape = at.createTransformedShape(new Rectangle( + (int) center.getX() - SINGLE_HEX_CUSTOM_BRIDGE_WIDTH/2, + (int) center.getY() - SINGLE_HEX_CUSTOM_BRIDGE_HEIGHT/2, + SINGLE_HEX_CUSTOM_BRIDGE_WIDTH, + SINGLE_HEX_CUSTOM_BRIDGE_HEIGHT)); + } + else { + + shape = at.createTransformedShape(new Rectangle( + (int) center.getX() - CUSTOM_BRIDGE_WIDTH/2, + (int) center.getY() - CUSTOM_BRIDGE_HEIGHT/2, + CUSTOM_BRIDGE_WIDTH, + CUSTOM_BRIDGE_HEIGHT)); + } + } + + private void setRoadShape(){ + + AffineTransform at = AffineTransform.getRotateInstance( + Math.toRadians(rotation), (int) center.getX(), (int) center.getY()); + + if (singleHex){ + + roadShape = at.createTransformedShape(new Rectangle( + (int) center.getX() - SINGLE_HEX_CUSTOM_BRIDGE_WIDTH/2 + SINGLE_HEX_ROAD_AREA_INSET, + (int) center.getY() - SINGLE_HEX_CUSTOM_BRIDGE_HEIGHT/2, + SINGLE_HEX_CUSTOM_BRIDGE_WIDTH - SINGLE_HEX_ROAD_AREA_INSET * 2, + SINGLE_HEX_CUSTOM_BRIDGE_HEIGHT)); + } + else { + + roadShape = at.createTransformedShape(new Rectangle( + (int) center.getX() - CUSTOM_BRIDGE_WIDTH/2 + ROAD_AREA_INSET, + (int) center.getY() - CUSTOM_BRIDGE_HEIGHT/2, + CUSTOM_BRIDGE_WIDTH - ROAD_AREA_INSET * 2, + CUSTOM_BRIDGE_HEIGHT)); + } + } +} + +/* + public Shape getShape(){ + + AffineTransform at = AffineTransform.getRotateInstance( + Math.toRadians(rotation), (int) center.getX(), (int) center.getY()); + + if (singleHex){ + + return at.createTransformedShape(new Rectangle( + (int) center.getX() - SINGLE_HEX_CUSTOM_BRIDGE_WIDTH/2, + (int) center.getY() - SINGLE_HEX_CUSTOM_BRIDGE_HEIGHT/2, + SINGLE_HEX_CUSTOM_BRIDGE_WIDTH, + SINGLE_HEX_CUSTOM_BRIDGE_HEIGHT)); + } + else { + + return at.createTransformedShape(new Rectangle( + (int) center.getX() - CUSTOM_BRIDGE_WIDTH/2, + (int) center.getY() - CUSTOM_BRIDGE_HEIGHT/2, + CUSTOM_BRIDGE_WIDTH, + CUSTOM_BRIDGE_HEIGHT)); + } + } + + public Shape getRoadShape(){ + + AffineTransform at = AffineTransform.getRotateInstance( + Math.toRadians(rotation), (int) center.getX(), (int) center.getY()); + + if (singleHex){ + + return at.createTransformedShape(new Rectangle( + (int) center.getX() - SINGLE_HEX_CUSTOM_BRIDGE_WIDTH/2 + SINGLE_HEX_ROAD_AREA_INSET, + (int) center.getY() - SINGLE_HEX_CUSTOM_BRIDGE_HEIGHT/2, + SINGLE_HEX_CUSTOM_BRIDGE_WIDTH - SINGLE_HEX_ROAD_AREA_INSET * 2, + SINGLE_HEX_CUSTOM_BRIDGE_HEIGHT)); + } + else { + + return at.createTransformedShape(new Rectangle( + (int) center.getX() - CUSTOM_BRIDGE_WIDTH/2 + ROAD_AREA_INSET, + (int) center.getY() - CUSTOM_BRIDGE_HEIGHT/2, + CUSTOM_BRIDGE_WIDTH - ROAD_AREA_INSET * 2, + CUSTOM_BRIDGE_HEIGHT)); + } + } +*/ Property changes on: VSQL-src/trunk/VASL/LOS/Map/Bridge.java ___________________________________________________________________ Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Added: VSQL-src/trunk/VASL/LOS/Map/Counter.java =================================================================== --- VSQL-src/trunk/VASL/LOS/Map/Counter.java (rev 0) +++ VSQL-src/trunk/VASL/LOS/Map/Counter.java 2015-05-28 11:27:08 UTC (rev 9199) @@ -0,0 +1,32 @@ +/* + * $Id: Counter 2/16/14 davidsullivan1 $ + * + * Copyright (c) 2013 by David Sullivan + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License (LGPL) as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, copies are available + * at http://www.opensource.org. + */ +package VASL.LOS.Map; + +/** + * A simple class that represents a VASL counter + */ +public class Counter { + String name; + + public Counter(String name) { + this.name = name; + } + + public String getName() { return name;} +} Property changes on: VSQL-src/trunk/VASL/LOS/Map/Counter.java ___________________________________________________________________ Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Added: VSQL-src/trunk/VASL/LOS/Map/Hex.java =================================================================== --- VSQL-src/trunk/VASL/LOS/Map/Hex.java (rev 0) +++ VSQL-src/trunk/VASL/LOS/Map/Hex.java 2015-05-28 11:27:08 UTC (rev 9199) @@ -0,0 +1,1102 @@ +/* + * Copyright (c) 2000-2003 by David Sullivan + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License (LGPL) as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, copies are available + * at http://www.opensource.org. + */ +package VASL.LOS.Map; + +import java.awt.Point; +import java.awt.Polygon; +import java.awt.Rectangle; +import java.awt.Shape; +import java.awt.geom.Point2D; + +import static java.lang.StrictMath.cos; + +/** + * Title: Hex.java + * Copyright: Copyright (c) 2001 David Sullivan Zuericher Strasse 6 12205 Berlin Germany. All rights reserved. + * @author David Sullivan + * @version 1.0+ + */ +public class Hex { + + // Property variables + private String name; + private int columnNumber; + private int rowNumber; + private int baseHeight; + private boolean northOnMap = true; + private boolean northEastOnMap = true; + private boolean southEastOnMap = true; + private boolean southOnMap = true; + private boolean southWestOnMap = true; + private boolean northWestOnMap = true; + + // the parent map + private Map map; + + // geometric variables + private Point2D.Double center; + private Polygon hexBorder = new Polygon(); // the hex border + private Polygon extendedHexBorder = new Polygon(); // one pixel larger than the hex border + + // location variables (center and each hexside) + // the point for each hexside location will be the midpoint of the hexside offset one pixel toward the center of the hex + private Location[] hexsideLocations = new Location[6]; + private Location centerLocation; + + // terrain variables + private Terrain[] hexsideTerrain = new Terrain[6]; // hexside terrain is wall, hedge, etc. + private boolean[] hexsideHasCliff = new boolean[6]; + + // other stuff + //TODO: bridge object no longer used + private Bridge bridge; + private boolean stairway; + + /** + * Create a new hex + * @param col the hex column - the first is 0 + * @param row the hex row - first is 0 + * @param name hex name + * @param centerDot location of hex center dot on map + * @param hexHeight hex height + * @param hexWidth hex width + * @param map the map + * @param baseHeight base height/elevation + * @param terrain default terrain used for all locations + */ + public Hex(int col, int row, String name, Point2D.Double centerDot, double hexHeight, double hexWidth, Map map, int baseHeight, Terrain terrain) { + + this.baseHeight = baseHeight; + columnNumber = col; + rowNumber = row; + this.map = map; + this.name = name; + center = fixMapEdgePoints(centerDot.getX(), centerDot.getY()); + initHexNew(centerDot, hexHeight, hexWidth, terrain); + + } + + /** + * Initialized the hex using custom geometry + */ + private void initHexNew(Point2D.Double centerDot, double hexHeight, double hexWidth, Terrain terr){ + + final double x = centerDot.getX(); + final double y = centerDot.getY(); + + // create the hex geometry. Hexes are assumed to be oriented with the top and bottom hexsides + // parallel to the map top/bottom + + // the length of the a hexside equals the distance from the center point to the vertexes + // final double hexside = hexHeight/(2.0*cos(Math.toRadians(30.0))); + final double hexside = hexWidth*2.0/3.0; + final double verticalOffset = hexHeight/2.0; + + // [0] is the left-most vertex on the top hexside and the other points are clockwise from there + Point2D.Double[] vertexPoints = new Point2D.Double[6]; + vertexPoints[0] = fixMapEdgePoints(-hexside / 2.0 + x, -verticalOffset + y); + vertexPoints[1] = fixMapEdgePoints(hexside / 2.0 + x, -verticalOffset + y); + vertexPoints[2] = fixMapEdgePoints(hexside + x, y); + vertexPoints[3] = fixMapEdgePoints(hexside / 2.0 + x, verticalOffset + y); + vertexPoints[4] = fixMapEdgePoints(-hexside / 2.0 + x, verticalOffset + y); + vertexPoints[5] = fixMapEdgePoints(-hexside + x, y); + for (int i = 0; i < 6; i++) { + + // create the hex borders - extended being one pixel larger + hexBorder.addPoint((int) Math.round(vertexPoints[i].x), (int) Math.round(vertexPoints[i].y)); + switch (i) { + case 0: + extendedHexBorder.addPoint((int) vertexPoints[i].x - 1, (int) vertexPoints[i].y - 1); + break; + case 1: + extendedHexBorder.addPoint((int) vertexPoints[i].x - 1, (int) vertexPoints[i].y + 1); + break; + case 2: + extendedHexBorder.addPoint((int) vertexPoints[i].x + 1, (int) vertexPoints[i].y); + break; + case 3: + extendedHexBorder.addPoint((int) vertexPoints[i].x + 1, (int) vertexPoints[i].y + 1); + break; + case 4: + extendedHexBorder.addPoint((int) vertexPoints[i].x - 1, (int) vertexPoints[i].y + 1); + break; + case 5: + extendedHexBorder.addPoint((int) vertexPoints[i].x - 1, (int) vertexPoints[i].y); + break; + } + + } + + // the hexside point is the hexside center point translated one pixel toward the hex center point + // [0] is the top hexside and the other points are clock-wise from there + Point2D.Double[] hexsidePoints = new Point2D.Double[6]; + final double horizontalOffset = cos(Math.toRadians(30.0)) * verticalOffset; + + hexsidePoints[0] = fixMapEdgePoints((int) x, (int) (-verticalOffset + y + 1.0)); + hexsidePoints[1] = fixMapEdgePoints((int) (horizontalOffset + x - 1), (int) (-verticalOffset/2.0 + y + 1.0)); + hexsidePoints[2] = fixMapEdgePoints((int) (horizontalOffset + x - 1), (int) (verticalOffset/2.0 + y - 1.0)); + hexsidePoints[3] = fixMapEdgePoints((int) x, (int) (verticalOffset + y - 1.0)); + hexsidePoints[4] = fixMapEdgePoints((int) (-horizontalOffset + x + 1), (int) (verticalOffset/2.0 + y - 1.0)); + hexsidePoints[5] = fixMapEdgePoints((int) (-horizontalOffset + x + 1), (int) (-verticalOffset/2.0 + y + 1.0)); + + setHexFlags(); + + createLocations(terr, vertexPoints, hexsidePoints); + } + + /** + * Create the the set of "empty" hex locations - i.e they will not reflect the grid terrain + * @param terr a default terrain used for all locations + * @param vertexPoints the hex vertex points + * @param hexsidePoints the hex hexside points + */ + private void createLocations(Terrain terr, Point2D.Double[] vertexPoints, Point2D.Double[] hexsidePoints) { + + // create center and hexside locations + centerLocation = new Location( + name, + baseHeight, + getHexCenter(), + getHexCenter(), + getHexCenter(), + this, + terr + ); + + hexsideLocations[0] = new Location( + name + ":North", + baseHeight, + new Point((int)vertexPoints[0].getX(), + (int)vertexPoints[0].getY()), + new Point((int)vertexPoints[1].getX(), + (int)vertexPoints[1].getY()), + new Point((int)hexsidePoints[0].getX(), + (int)hexsidePoints[0].getY()), + this, + terr + ); + + hexsideLocations[1] = new Location( + name + ":NorthEast", + baseHeight, + new Point((int)vertexPoints[1].getX(), + (int)vertexPoints[1].getY()), + new Point((int)vertexPoints[2].getX(), + (int)vertexPoints[2].getY()), + new Point((int)hexsidePoints[1].getX(), + (int)hexsidePoints[1].getY()), + this, + terr + ); + + hexsideLocations[2] = new Location( + name + ":SouthEast", + baseHeight, + new Point((int)vertexPoints[2].getX(), + (int)vertexPoints[2].getY()), + new Point((int)vertexPoints[3].getX(), + (int)vertexPoints[3].getY()), + new Point((int)hexsidePoints[2].getX(), + (int)hexsidePoints[2].getY()), + this, + terr + ); + + hexsideLocations[3] = new Location( + name + ":South", + baseHeight, + new Point((int)vertexPoints[3].getX(), + (int)vertexPoints[3].getY()), + new Point((int)vertexPoints[4].getX(), + (int)vertexPoints[4].getY()), + new Point((int)hexsidePoints[3].getX(), + (int)hexsidePoints[3].getY()), + this, + terr + ); + + hexsideLocations[4] = new Location( + name + ":SouthWest", + baseHeight, + new Point((int)vertexPoints[4].getX(), + (int)vertexPoints[4].getY()), + new Point((int)vertexPoints[5].getX(), + (int)vertexPoints[5].getY()), + new Point((int)hexsidePoints[4].getX(), + (int)hexsidePoints[4].getY()), + this, + terr + ); + + hexsideLocations[5] = new Location( + name + ":NorthWest", + baseHeight, + new Point((int)vertexPoints[5].getX(), + (int)vertexPoints[5].getY()), + new Point((int)vertexPoints[0].getX(), + (int)vertexPoints[0].getY()), + new Point((int)hexsidePoints[5].getX(), + (int)hexsidePoints[5].getY()), + this, + terr + ); + } + + /** + * @param x the x coordinate of the point + * @param y the y coordinate of the point + * @return a point that has been adjusted so it is on the map if x or y are off the map by a pixel or two + */ + private Point2D.Double fixMapEdgePoints(double x, double y) { + + double newX = x == -1.0 ? 0.0 : x; + double newY = y == -1.0 ? 0.0 : y; + newX = (int) newX == map.getGridWidth() || (int) newX == map.getGridWidth() || (int) newX == (map.getGridWidth() + 1.0) ? (map.getGridWidth() - 1.0) : newX; + newY = (int) newY == map.getGridHeight() || (int) newY == map.getGridHeight() || (int) newY == (map.getGridHeight() + 1.0) ? (map.getGridHeight() - 1.0) : newY; + + return new Point2D.Double(newX, newY); + } + + /** + * set the "on map?" flags + */ + private void setHexFlags() { + + // first column? + if (columnNumber == 0) { + + southWestOnMap = false; + northWestOnMap = false; + } + + // last column? + if (columnNumber + 1 == map.getWidth()) { + + southEastOnMap = false; + northEastOnMap = false; + } + + // first hex in odd column? + if ((columnNumber%2 == 1) && (rowNumber == 0)){ + + northOnMap = false; + northEastOnMap = false; + northWestOnMap = false; + } + + // last hex in odd column? + if ((columnNumber%2 == 1) && (rowNumber == map.getHeight())){ + + southOnMap = false; + southEastOnMap = false; + southWestOnMap = false; + } + + } + + // used to update the hexside location once the map has been fully initialized + public void resetHexsideLocationNames(){ + + if (map.getAdjacentHex(this, 0) != null) hexsideLocations[0].setName(name + "/" + map.getAdjacentHex(this, 0).getName()); + if (map.getAdjacentHex(this, 1) != null) hexsideLocations[1].setName(name + "/" + map.getAdjacentHex(this, 1).getName()); + if (map.getAdjacentHex(this, 2) != null) hexsideLocations[2].setName(name + "/" + map.getAdjacentHex(this, 2).getName()); + if (map.getAdjacentHex(this, 3) != null) hexsideLocations[3].setName(name + "/" + map.getAdjacentHex(this, 3).getName()); + if (map.getAdjacentHex(this, 4) != null) hexsideLocations[4].setName(name + "/" + map.getAdjacentHex(this, 4).getName()); + if (map.getAdjacentHex(this, 5) != null) hexsideLocations[5].setName(name + "/" + map.getAdjacentHex(this, 5).getName()); + } + + // get the map + public Map getMap() { return map;} + + // bridge methods + public Bridge getBridge(){ return bridge;} + public void setBridge(Bridge bridge){ + + this.bridge = bridge; + + // create the new bridge location + final Location l = new Location( + name + ":Bridge", + bridge.getRoadLevel() - baseHeight, + new Point((int) center.getX(), (int)center.getY()), + new Point((int) center.getX(), (int)center.getY()), + new Point((int) center.getX(), (int)center.getY()), + this, + bridge.getTerrain() + ); + bridge.setLocation(l); + + // set the location up/down pointers + l.setDownLocation(centerLocation); + centerLocation.setUpLocation(l); + } + + public boolean hasBridge(){ + + return (bridge != null); + } + + // Property methods + public boolean isSouthEastOnMap() {return southEastOnMap;} + public boolean isSouthOnMap() {return southOnMap;} + public boolean isSouthWestOnMap() {return southWestOnMap;} + public boolean isNorthEastOnMap() {return northEastOnMap;} + public boolean isNorthOnMap(){return northOnMap;} + public boolean isNorthWestOnMap() {return northWestOnMap;} + public boolean isHexsideOnMap(int hexside) { + + switch (hexside){ + + case 0 : return isNorthOnMap(); + case 1 : return isNorthEastOnMap(); + case 2 : return isSouthEastOnMap(); + case 3 : return isSouthOnMap(); + case 4 : return isSouthWestOnMap(); + case 5 : return isNorthWestOnMap(); + + default: return false; + } + } + + public int getColumnNumber() {return columnNumber;} + public void setColumnNumber(int newColumnNumber) {columnNumber = newColumnNumber; + } + + public String getName(){return name;} + + public int getRowNumber() {return rowNumber;} + public Polygon getHexBorder() {return hexBorder;} + public Polygon getExtendedHexBorder() {return extendedHexBorder;} + public Point getHexCenter() {return new Point((int) center.getX(), (int) center.getY());} + public int getBaseHeight() {return baseHeight;} + + private boolean[] slopes = new boolean[6]; // flags for hexsides having slopes - all false by default + + /** + * Set the hexside slopes flags + * @param slopes the slopes array of length 6 - [0] is the top hexside and the others are clockwise from there + */ + public void setSlopes(boolean[] slopes) { + + // must be an array of 6 flags; + if(slopes.length != 6) { + return; + } + this.slopes = slopes; + } + + /** + * @param hexside the hexside - 0 is the top hexside and the others are clockwise from there + * @return true if hexside has slope + */ + public boolean hasSlope(int hexside) { + return slopes[hexside]; + } + + public Location getCenterLocation() { return centerLocation;} + + public void setHexBorder(Polygon newHexBorder) { + hexBorder = newHexBorder; + } + + public void setExtendedHexBorder(Polygon newHexBorder) { + extendedHexBorder = newHexBorder; + } + + public void setRowNumber(int newRowNumber) { + rowNumber = newRowNumber; + } + + public static int getOppositeHexside(int hexside){ + + switch (hexside){ + case 0: + case 1: + case 2: return hexside + 3; + case 3: + case 4: + case 5: return hexside - 3; + default: return -1; + } + } + + /** + * @param l a location + * @return true if l is the center location or any location above/below the center location + */ + public boolean isCenterLocation(Location l) { + + if(centerLocation.equals(l)) { + return true; + } + + // center, up locations + Location temp1 = centerLocation; + while(temp1.getUpLocation() != null){ + if (l.equals(temp1.getUpLocation())){ + return true; + } + else { + temp1 = temp1.getUpLocation(); + } + } + + // down locations + Location temp2 = centerLocation; + while(temp2.getDownLocation() != null){ + if (l.equals(temp2.getDownLocation())){ + return true; + } + else { + temp2 = temp2.getDownLocation(); + } + } + return false; + } + + public int getLocationHexside(Location l){ + + for(int x = 0; x < 6; x++) { + if (l.equals(hexsideLocations[x])){ + return x; + } + } + return -1; + } + + /** + * Set the depression terrain + * @param terr the depression terrain - pass null to remove depression terrain + */ + public void setDepressionTerrain(Terrain terr) { + + // change the depression terrain in the center location + centerLocation.setDepressionTerrain(terr); + + // if were removing the depression terrain, ensure all hexside + // depression terrain is also removed + if (terr == null) { + for(int x = 0; x < 6; x++){ + hexsideLocations[x].setDepressionTerrain(terr); + } + } + } + + public void setHexsideDepressionTerrain(int side) { + + // change the depression terrain in the hexside location + hexsideLocations[side].setDepressionTerrain(centerLocation.getDepressionTerrain()); + } + + /** + * @return true if terrain is depression terrain + */ + public boolean isDepressionTerrain() { + + return centerLocation.isDepressionTerrain(); + } + + /** + * Resets the hex locations using the terrain information in the map terrain grid + */ + public void resetTerrain() { + + // set the center location terrain + Terrain centerLocationTerrain = map.getGridTerrain((int) centerLocation.getLOSPoint().getX(), (int) centerLocation.getLOSPoint().getY()); + + // fix center location when building misses the center dot + if(!centerLocationTerrain.isBuilding() && getHexsideBuildingTerrain() != null) { + centerLocationTerrain = getHexsideBuildingTerrain(); + } + + centerLocation.setTerrain(centerLocationTerrain); + + boolean oldStairway = false; + + // add building locations + if (centerLocationTerrain.isBuilding()){ + + // keep stairway if resetting a multi-level building + oldStairway = stairway && + !"Stone Building, 1 Level".equals(centerLocation.getTerrain().getName()) && + !"Wooden Building, 1 Level".equals(centerLocation.getTerrain().getName()); + + // special case for marketplace + if(centerLocationTerrain.getLOSCategory() == Terrain.LOSCategories.MARKETPLACE) { + centerLocation.setTerrain(map.getTerrain("Open Ground")); + } + + // add upper level building locations + Location previousLocation = centerLocation; + for (int level = 1; level <= centerLocationTerrain.getHeight(); level++) { + + // need to ignore buildings without upper level locations - bit of a hack so we can use the building height + if(!"Wooden Building".equals(centerLocationTerrain.getName()) && + !"Stone Building".equals(centerLocationTerrain.getName())) { + final Location l = new Location( + centerLocation.getName() + " Level " + level, + level, + centerLocation.getLOSPoint(), + centerLocation.getLOSPoint(), + null, + this, + centerLocationTerrain + ); + + previousLocation.setUpLocation(l); + l.setDownLocation(previousLocation); + previousLocation = l; + } + } + + // set inherent stairway + stairway = + "Stone Building, 1 Level".equals(centerLocation.getTerrain().getName()) || + "Wooden Building, 1 Level".equals(centerLocation.getTerrain().getName()) || + oldStairway; + ... [truncated message content] |