From 84c405ef2bbd7751b5657ed3fb0c3055ba3463ca Mon Sep 17 00:00:00 2001 From: Evan Debenham Date: Wed, 5 Apr 2017 19:59:02 -0400 Subject: [PATCH] v0.6.0: lots of line builder implementation and general improvements --- .../shatteredpixeldungeon/levels/Level.java | 36 +++----- .../levels/builders/Builder.java | 85 +++++++++++++++++++ .../levels/builders/LineBuilder.java | 31 +++++-- .../levels/rooms/Room.java | 26 ++++-- .../scenes/InterlevelScene.java | 3 +- 5 files changed, 144 insertions(+), 37 deletions(-) diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/levels/Level.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/levels/Level.java index 79bb70f9d..02e714e00 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/levels/Level.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/levels/Level.java @@ -261,14 +261,6 @@ public abstract class Level implements Bundlable { decorate(); PathFinder.setMapSize(width(), height()); - passable = new boolean[length()]; - losBlocking = new boolean[length()]; - flamable = new boolean[length()]; - secret = new boolean[length()]; - solid = new boolean[length()]; - avoid = new boolean[length()]; - water = new boolean[length()]; - pit = new boolean[length()]; buildFlagMaps(); cleanWalls(); @@ -292,6 +284,17 @@ public abstract class Level implements Bundlable { visited = new boolean[length]; mapped = new boolean[length]; Dungeon.visible = new boolean[length]; + + fieldOfView = new boolean[length()]; + + passable = new boolean[length()]; + losBlocking = new boolean[length()]; + flamable = new boolean[length()]; + secret = new boolean[length()]; + solid = new boolean[length()]; + avoid = new boolean[length()]; + water = new boolean[length()]; + pit = new boolean[length()]; } public void reset() { @@ -315,11 +318,9 @@ public abstract class Level implements Bundlable { } if (bundle.contains("width") && bundle.contains("height")){ - width = bundle.getInt("width"); - height = bundle.getInt("height"); + setSize( bundle.getInt("width"), bundle.getInt("height")); } else - width = height = 32; //default sizes - length = width * height; + setSize( 32, 32); //default sizes PathFinder.setMapSize(width(), height()); mobs = new HashSet<>(); @@ -593,17 +594,6 @@ public abstract class Level implements Bundlable { } protected void buildFlagMaps() { - - fieldOfView = new boolean[length()]; - - passable = new boolean[length()]; - losBlocking = new boolean[length()]; - flamable = new boolean[length()]; - secret = new boolean[length()]; - solid = new boolean[length()]; - avoid = new boolean[length()]; - water = new boolean[length()]; - pit = new boolean[length()]; for (int i=0; i < length(); i++) { int flags = Terrain.flags[map[i]]; diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/levels/builders/Builder.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/levels/builders/Builder.java index 91fa7bd53..3b83e0365 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/levels/builders/Builder.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/levels/builders/Builder.java @@ -22,8 +22,12 @@ package com.shatteredpixel.shatteredpixeldungeon.levels.builders; import com.shatteredpixel.shatteredpixeldungeon.levels.rooms.Room; +import com.watabou.utils.Point; +import com.watabou.utils.Random; +import com.watabou.utils.Rect; import java.util.ArrayList; +import java.util.Iterator; public abstract class Builder { @@ -34,4 +38,85 @@ public abstract class Builder { //returns null on failure public abstract ArrayList build(ArrayList rooms); + protected Rect findFreeSpace(Point start, ArrayList rooms, int maxSize){ + Rect space = new Rect(start.x-maxSize, start.y-maxSize, start.x+maxSize, start.y+maxSize); + + ArrayList colliding = new ArrayList<>(rooms); + do{ + + //remove any rooms we aren't currently overlapping + Iterator it = colliding.iterator(); + while (it.hasNext()){ + Room room = it.next(); + //if not colliding + if ( Math.max(space.left, room.left) >= Math.min(space.right, room.right) + || Math.max(space.top, room.top) >= Math.min(space.bottom, room.bottom) ){ + it.remove(); + } + } + + //iterate through all rooms we are overlapping, and find which one would take + //the largest area reduction to resolve the overlapping + Room biggestCollision = null; + int wDiff, hDiff, biggestDiff = 0; + boolean widthCollision = false; + for (Room room : colliding){ + wDiff = Integer.MAX_VALUE; + if (room.left >= start.x){ + wDiff = (space.right - room.left) * (space.height() + 1); + } else if (room.right <= start.x){ + wDiff = (room.right - space.left) * (space.height() + 1); + } + + hDiff = Integer.MAX_VALUE; + if (room.top >= start.y){ + hDiff = (space.bottom - room.top) * (space.width() + 1); + } else if (room.bottom <= start.y){ + hDiff = (room.bottom - space.top) * (space.width() + 1); + } + + //our start is inside this room, return an empty rect + if (hDiff == Integer.MAX_VALUE && wDiff == Integer.MAX_VALUE){ + space.set(0, 0, 0, 0); + return space; + + } else { + if (wDiff < hDiff || (wDiff == hDiff && Random.Int(2) == 0)){ + if (wDiff >= biggestDiff){ + biggestDiff = wDiff; + biggestCollision = room; + widthCollision = true; + } + + } else { + if (hDiff >= biggestDiff){ + biggestDiff = hDiff; + biggestCollision = room; + widthCollision = false; + } + } + + } + + } + + //reduce the available space in order to not overlap with the biggest collision we found + if (biggestCollision != null){ + if (widthCollision){ + if (biggestCollision.left >= start.x && biggestCollision.left < space.right) space.right = biggestCollision.left; + if (biggestCollision.right <= start.x && biggestCollision.right > space.left) space.left = biggestCollision.right; + } else { + if (biggestCollision.top >= start.y && biggestCollision.top < space.bottom) space.bottom = biggestCollision.top; + if (biggestCollision.bottom <= start.y && biggestCollision.bottom > space.top) space.top = biggestCollision.bottom; + } + colliding.remove(biggestCollision); + } else { + colliding.clear(); + } + + //loop until we are no longer colliding with any rooms + } while (!colliding.isEmpty()); + + return space; + } } diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/levels/builders/LineBuilder.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/levels/builders/LineBuilder.java index 0457030f6..5e7270530 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/levels/builders/LineBuilder.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/levels/builders/LineBuilder.java @@ -28,7 +28,9 @@ import com.shatteredpixel.shatteredpixeldungeon.levels.rooms.standard.EntranceRo import com.shatteredpixel.shatteredpixeldungeon.levels.rooms.standard.ExitRoom; import com.shatteredpixel.shatteredpixeldungeon.levels.rooms.standard.StandardRoom; import com.shatteredpixel.shatteredpixeldungeon.levels.rooms.tunnel.TunnelRoom; +import com.watabou.utils.Point; import com.watabou.utils.Random; +import com.watabou.utils.Rect; import java.util.ArrayList; @@ -73,7 +75,7 @@ public class LineBuilder extends Builder { shop.connect(entrance); } - int standardsOnPath = standards.size()/2 + Random.Int(3) - 1; + int standardsOnPath = standards.size()/5 + Random.Int(2); standardsOnPath = Math.min(standardsOnPath, standards.size()); //standardsOnPath = standards.size(); @@ -157,7 +159,7 @@ public class LineBuilder extends Builder { if (!placeBranchRoom(up, curr, r, rooms)){ continue; } - if (r instanceof StandardRoom) { + if (r instanceof StandardRoom && Random.Int(3) == 0) { if (up) upBrancheable.add(r); else downBrancheable.add(r); } @@ -169,11 +171,24 @@ public class LineBuilder extends Builder { } private boolean placeBranchRoom(boolean up, Room curr, Room next, ArrayList collision){ - next.setSize(); - next.setPos( curr.left + (curr.width()-next.width())/2, up ? curr.top - next.height()+1 : curr.bottom); - next.connect(curr); - return true; + Rect space = findFreeSpace( + new Point( curr.left + curr.width()/2, up ? curr.top : curr.bottom), + collision, + Math.max(next.maxWidth(), next.maxHeight())); + + if (next.setSizeWithLimit(space.width()+1,space.height()+1 )){ + next.setPos( curr.left + (curr.width()-next.width())/2, up ? curr.top - next.height()+1 : curr.bottom); + + if (next.right > space.right){ + next.shift( space.right - next.right, 0); + } else if (next.left < space.left){ + next.shift( space.left - next.left, 0); + } + + return next.connect(curr); + + } else { + return false; + } } - - } diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/levels/rooms/Room.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/levels/rooms/Room.java index a4b3eb550..4a1b6c271 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/levels/rooms/Room.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/levels/rooms/Room.java @@ -83,20 +83,36 @@ public class Room extends Rect implements Graph.Node, Bundlable { return setSize(minWidth(), maxWidth(), minHeight(), maxHeight()); } - public boolean setSize( int w, int h){ + public boolean forceSize( int w, int h ){ return setSize( w, w, h, h ); } - public boolean setSize(int minW, int maxW, int minH, int maxH) { + public boolean setSizeWithLimit( int w, int h ){ + if ( w < minWidth() || h < minHeight()) { + return false; + } else { + setSize(); + + if (width() > w || height() > h){ + resize(Math.min(width(), w)-1, Math.min(height(), h)-1); + } + + return true; + } + } + + protected boolean setSize(int minW, int maxW, int minH, int maxH) { if (minW < minWidth() || maxW > maxWidth() || minH < minHeight() - || maxH > maxHeight()){ + || maxH > maxHeight() + || minW > maxW + || minH > maxH){ return false; } else { //subtract one because rooms are inclusive to their right and bottom sides - resize(left + Random.NormalIntRange(minW, maxW) - 1, - top + Random.NormalIntRange(minH, maxH) - 1); + resize(Random.NormalIntRange(minW, maxW) - 1, + Random.NormalIntRange(minH, maxH) - 1); return true; } } diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/InterlevelScene.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/InterlevelScene.java index b52e54fd8..fe0cd7173 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/InterlevelScene.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/InterlevelScene.java @@ -175,7 +175,8 @@ public class InterlevelScene extends PixelScene { String errorMsg; if (error instanceof FileNotFoundException) errorMsg = Messages.get(this, "file_not_found"); else if (error instanceof IOException) errorMsg = Messages.get(this, "io_error"); - else if (error.getMessage().equals("old save")) errorMsg = Messages.get(this, "io_error"); + else if (error.getMessage() != null && + error.getMessage().equals("old save")) errorMsg = Messages.get(this, "io_error"); else throw new RuntimeException("fatal error occured while moving between floors", error);