package nl.tudelft.bw4t.environmentstore.editor.model; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.util.ArrayList; import java.util.List; import javax.xml.bind.JAXBException; import nl.tudelft.bw4t.map.Door; import nl.tudelft.bw4t.map.Entity; import nl.tudelft.bw4t.map.MapFormatException; import nl.tudelft.bw4t.map.NewMap; import nl.tudelft.bw4t.map.Point; import nl.tudelft.bw4t.map.Rectangle; import nl.tudelft.bw4t.map.Zone; import nl.tudelft.bw4t.map.Zone.Type; public class MapConverter { /** * bot initial displacements */ static final int XDISP = 4; static final int YDISP = 2; /* constants that map rooms to real positions on the map. */ public static final int ROOMHEIGHT = 10; public static final int ROOMWIDTH = 10; private MapConverter() { } public static EnvironmentMap loadMap(File file) throws MapFormatException { final NewMap map; try { map = NewMap.create(new FileInputStream(file)); } catch (FileNotFoundException | JAXBException e) { throw new MapFormatException("Failed to open map", e); } final int nrows = calcRows(map); int ncols = calcColumns(map); List<ZoneModel> data = getZoneData(map); // Send this data to the grid that will be edited. EnvironmentMap model = new EnvironmentMap(nrows, ncols); // Set the saved zones. for (ZoneModel zModel : data) { int rowSet = ZoneModel.calcRow(zModel.getZone()); int colSet = ZoneModel.calcColumn(zModel.getZone()); final ZoneModel zone = model.getZone(rowSet, colSet); zone.setType(zModel.getType()); zone.setDropZone(zModel.isDropZone()); zone.setColors(zModel.getColors()); // Set the doors for this room. for (int i = 0; i < zModel.getDoorsBool().length; i++) { if (zModel.getDoorsBool()[i] == true) { zone.setDoor(i, true); } } } for (Entity entity : map.getEntities()) { final Point pos = entity.getPosition(); final int row = ZoneModel.calcRow(pos.getY()); final int col = ZoneModel.calcColumn(pos.getX()); final ZoneModel zone = model.getZone(row, col); zone.setStartZone(true); } // Set the saved sequence. model.setSequence(map.getSequence()); return model; } private static List<ZoneModel> getZoneData(NewMap map) { List<ZoneModel> data = new ArrayList<ZoneModel>(); for (Zone zone : map.getZones()) { data.add(new ZoneModel(zone)); } return data; } /** * @param map * The map to be edited. * @return The row the zone belongs to. */ private static int calcRows(NewMap map) { double height = MapConverter.ROOMHEIGHT; double y = map.getArea().getY(); return (int) ((y - height / 2) / height) + 1; } /** * @param map * The map to be edited. * @return The column the zone belongs to. */ private static int calcColumns(NewMap map) { double width = MapConverter.ROOMWIDTH; double x = map.getArea().getX(); return (int) ((x - width / 2) / width) + 1; } /** * Create the real map object using the settings * * @return NewMap the new map that has been created. * @throws MapFormatException * if no dropZone or no startZone is found. */ public static NewMap createMap(EnvironmentMap model) throws MapFormatException { NewMap map = new NewMap(); // set the general fields of the map map.setArea(new Point(model.getColumns() * MapConverter.ROOMWIDTH, model.getRows() * MapConverter.ROOMHEIGHT)); map.setSequence(model.getSequence()); // Check for dropzoness // For each zonemodel, add the corresponding Zone boolean foundDropzone = false; Zone[][] output = new Zone[model.getRows()][model.getColumns()]; for (int row = 0; row < model.getRows(); row++) { for (int col = 0; col < model.getColumns(); col++) { ZoneModel room = model.getZone(row, col); if (room.isDropZone()) { if (foundDropzone) { throw new MapFormatException("Only one DropZone allowed per map!"); } foundDropzone = true; } output[row][col] = new Zone(room.getName(), new Rectangle(col * ROOMWIDTH + ROOMWIDTH / 2, row * ROOMHEIGHT + ROOMHEIGHT / 2, ROOMWIDTH, ROOMHEIGHT), room.getType()); int x = (int) output[row][col].getBoundingbox().getX(); int y = (int) output[row][col].getBoundingbox().getY(); if (output[row][col].getType() == Type.ROOM) { if (room.hasDoor(ZoneModel.NORTH)) { output[row][col] .addDoor(new Door(new Point(x, y - ROOMHEIGHT / 2), Door.Orientation.HORIZONTAL)); } if (room.hasDoor(ZoneModel.EAST)) { output[row][col].addDoor(new Door(new Point(x + ROOMWIDTH / 2, y), Door.Orientation.VERTICAL)); } if (room.hasDoor(ZoneModel.SOUTH)) { output[row][col] .addDoor(new Door(new Point(x, y + ROOMHEIGHT / 2), Door.Orientation.HORIZONTAL)); } if (room.hasDoor(ZoneModel.WEST)) { output[row][col].addDoor(new Door(new Point(x - ROOMWIDTH / 2, y), Door.Orientation.VERTICAL)); } } if (room.isStartZone()) { addEntities(map, x, y, room.getSpawnCount()); } map.addZone(output[row][col]); output[row][col].setBlocks(room.getColors()); } } // connect all the zones connect(output); return map; } /** * Check what type of zone the current zone is. Then call the correct connect method. * * @param zones * - matrix of the map */ private static void connect(Zone[][] zones) { for (int row = 0; row < zones.length; row++) { for (int col = 0; col < zones[0].length; col++) { if (zones[row][col].isOpenSpace()) { connectCorridor(zones, row, col); } else if (zones[row][col].getType() == Type.ROOM) { connectRoom(zones, row, col); } else { // it is a blockade and thus it should not be connected. } } } } /** * For a corridor all adjacent zones should be added. * * @param zones * - matrix of the map * @param row * indicates where the current zone is * @param col * indicates where the current zone is */ private static void connectCorridor(Zone[][] zones, int row, int col) { connectCorridor(zones, row, col, row, col - 1); connectCorridor(zones, row, col, row + 1, col); connectCorridor(zones, row, col, row, col + 1); connectCorridor(zones, row, col, row - 1, col); } /** * For a room, only adjacent zones where a door is positioned should be added. * * @param zones * - matrix of the map * @param row * indicates where the current zone is * @param col * indicates where the current zone is */ private static void connectRoom(Zone[][] zones, int row, int col) { if (zones[row][col].hasNorth()) { connectZone(zones, row, col, row - 1, col); } if (zones[row][col].hasEast()) { connectZone(zones, row, col, row, col + 1); } if (zones[row][col].hasSouth()) { connectZone(zones, row, col, row + 1, col); } if (zones[row][col].hasWest()) { connectZone(zones, row, col, row, col - 1); } } /** * Checks whether two given positions in the grid are open space and connects them. * * @param zones * matrix of the map * @param row * indicates where the current zone is * @param col * indicates where the current zone is * @param row2 * indicates where the other zone is * @param col2 * indicates where the other zone is */ private static void connectCorridor(Zone[][] zones, int row, int col, int row2, int col2) { try { final Zone zone1 = zones[row][col]; final Zone zone2 = zones[row2][col2]; if (zone1.isOpenSpace() && zone2.isOpenSpace()) { connectZone(zones, row, col, row2, col2); } } catch (ArrayIndexOutOfBoundsException e) { // ignore trying to connect non-existent zones } } /** * Connects two positions in the grid if they are valid. * * @param zones * matrix of the map * @param row * indicates where the current zone is * @param col * indicates where the current zone is * @param row2 * indicates where the other zone is * @param col2 * indicates where the other zone is */ private static void connectZone(Zone[][] zones, int row, int col, int row2, int col2) { try { final Zone zone1 = zones[row][col]; final Zone zone2 = zones[row2][col2]; if (!zone1.getNeighbours().contains(zone2)) { zone1.addNeighbour(zone2); } if (!zone2.getNeighbours().contains(zone1)) { zone2.addNeighbour(zone1); } } catch (ArrayIndexOutOfBoundsException e) { // ignore trying to connect non-existent zones } } /** * Add entities to map * * @param map * @param centerx * the position of first entity * @param centery * the position of first entity */ private static void addEntities(NewMap map, double centerx, double centery, int numberOfEntities) { for (int n = 1; n <= numberOfEntities; n++) { final int n4 = n % 4; Point p; if (n4 == 1) { p = new Point(centerx - 2.5, centery - 2.5); } else if (n4 == 2) { p = new Point(centerx + 2.5, centery - 2.5); } else if (n4 == 3) { p = new Point(centerx - 2.5, centery + 2.5); } else { p = new Point(centerx + 2.5, centery + 2.5); } map.addEntity(new Entity("Bot", p)); } } }