diff --git a/src/com/shatteredpixel/shatteredpixeldungeon/levels/SewerBossLevel.java b/src/com/shatteredpixel/shatteredpixeldungeon/levels/SewerBossLevel.java index 1aed5c22c..100c7a937 100644 --- a/src/com/shatteredpixel/shatteredpixeldungeon/levels/SewerBossLevel.java +++ b/src/com/shatteredpixel/shatteredpixeldungeon/levels/SewerBossLevel.java @@ -60,76 +60,104 @@ public class SewerBossLevel extends RegularLevel { initRooms(); int distance; + //if we ever need to try 20 or more times to find a room, better to give up and try again. int retry = 0; - int minDistance = (int)Math.sqrt( rooms.size() ); - do { - int innerRetry = 0; - do { - if (innerRetry++ > 10) { - return false; - } - roomEntrance = Random.element( rooms ); - } while (roomEntrance.width() < 4 || roomEntrance.height() < 4); - - innerRetry = 0; - do { - if (innerRetry++ > 10) { - return false; - } - roomExit = Random.element( rooms ); - } while (roomExit == roomEntrance || roomExit.width() < 6 || roomExit.height() < 6 || roomExit.top == 0); - - Graph.buildDistanceMap( rooms, roomExit ); - distance = roomEntrance.distance(); - - if (retry++ > 10) { - return false; - } - - } while (distance < minDistance); - - roomEntrance.type = Type.ENTRANCE; - roomExit.type = Type.BOSS_EXIT; - - Graph.buildDistanceMap( rooms, roomExit ); - List path = Graph.buildPath( rooms, roomEntrance, roomExit ); - - Graph.setPrice( path, roomEntrance.distance ); - - Graph.buildDistanceMap( rooms, roomExit ); - path = Graph.buildPath( rooms, roomEntrance, roomExit ); - - Room room = roomEntrance; - for (Room next : path) { - room.connect( next ); - room = next; - } - - room = (Room)roomExit.connected.keySet().toArray()[0]; - if (roomExit.top == room.bottom) { - return false; - } - + + //start with finding an entrance room (will also contain exit) + //the room must be at least 4x4 and be at the top of the map(so that nothing can connect with the top) + do { + if (retry++ > 20) { + return false; + } + roomEntrance = Random.element( rooms ); + } while (roomEntrance.width() < 4 || roomEntrance.height() < 4 || roomEntrance.top != 0); + + roomEntrance.type = Type.ENTRANCE; + roomExit = roomEntrance; + + + //now find the rest of the rooms for this boss mini-maze + Room curRoom = null; + Room lastRoom = roomEntrance; + //we make 4 rooms, last iteration is tieing the final toom to the start + for(int i = 0; i <= 4; i++){ + retry = 0; + //find a suitable room the first four times + //sutiable room should be empty and have a distance of 2 from the current room + if (i < 4) { + do { + if (retry++ > 20) { + return false; + } + curRoom = Random.element(rooms); + Graph.buildDistanceMap(rooms, curRoom); + distance = lastRoom.distance(); + } while (curRoom.type != Type.NULL || distance != 2); + + curRoom.type = Type.STANDARD; + + //otherwise, we're on the last iteration. + } else { + //set the current room to the entrance, so we can build a connection to it. + curRoom = roomEntrance; + } + + //now build a connection between the current room and the last one. + Graph.buildDistanceMap( rooms, curRoom ); + List path = Graph.buildPath( rooms, lastRoom, curRoom ); + + Graph.setPrice( path, lastRoom.distance ); + + path = Graph.buildPath( rooms, lastRoom, curRoom ); + + Room room = lastRoom; + for (Room next : path) { + room.connect( next ); + room = next; + } + + if (i == 4) { + + //we must find a room for his royal highness! + //look at rooms adjacent to the final found room (likely to be furthest from start) + ArrayList candidates = new ArrayList(); + for (Room r : lastRoom.neigbours) { + if (r.type == Type.NULL && r.connected.size() == 0) { + candidates.add(r); + } + } + + //if we have candidates, pick a room and put the king there + if (candidates.size() > 0) { + Room kingsRoom = Random.element(candidates); + kingsRoom.connect(lastRoom); + kingsRoom.type = Room.Type.RAT_KING; + + //unacceptable! make a new level... + } else { + return false; + } + } + lastRoom = curRoom; + } + + //the connection structure ensures that (most of the time) there is a nice loop for the player to kite the + //boss around. What's nice is that there is enough chaos such that the loop is rarely straightforward + //and boring. + + //fills our connection rooms in with tunnel for (Room r : rooms) { if (r.type == Type.NULL && r.connected.size() > 0) { - r.type = Type.TUNNEL; + r.type = Type.TUNNEL; } } - ArrayList candidates = new ArrayList(); - for (Room r : roomExit.neigbours) { - if (!roomExit.connected.containsKey( r ) && - (roomExit.left == r.right || roomExit.right == r.left || roomExit.bottom == r.top)) { - candidates.add( r ); - } - } - if (candidates.size() > 0) { - Room kingsRoom = Random.element( candidates ); - kingsRoom.connect( roomExit ); - kingsRoom.type = Room.Type.RAT_KING; - } - paint(); + + //TODO: not handling this through a painter is kinda iffy, separate into a painter if you use it again. + //sticks the exit in the room entrance. + exit = roomEntrance.top * Level.WIDTH + (roomEntrance.left + roomEntrance.right) / 2; + map[exit] = Terrain.LOCKED_EXIT; paintWater(); paintGrass(); @@ -178,7 +206,11 @@ public class SewerBossLevel extends RegularLevel { @Override protected void createMobs() { Mob mob = Bestiary.mob( Dungeon.depth ); - mob.pos = roomExit.random(); + Room room; + do { + room = Random.element(rooms); + } while (room.type != Type.STANDARD); + mob.pos = room.random(); mobs.add( mob ); }