From f500ba87ec7f0b9732991a3139e9f9938fa1b5e5 Mon Sep 17 00:00:00 2001 From: Evan Debenham Date: Tue, 1 Aug 2017 16:45:37 -0400 Subject: [PATCH] v0.6.1: improved sewer pipe rooms when they have many connections --- .../levels/rooms/standard/SewerPipeRoom.java | 197 ++++++++++++++---- 1 file changed, 160 insertions(+), 37 deletions(-) diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/levels/rooms/standard/SewerPipeRoom.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/levels/rooms/standard/SewerPipeRoom.java index adec93c53..d5ba767cb 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/levels/rooms/standard/SewerPipeRoom.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/levels/rooms/standard/SewerPipeRoom.java @@ -31,6 +31,8 @@ import com.watabou.utils.PointF; import com.watabou.utils.Random; import com.watabou.utils.Rect; +import java.util.ArrayList; + public class SewerPipeRoom extends StandardRoom { @Override @@ -54,7 +56,7 @@ public class SewerPipeRoom extends StandardRoom { return super.canConnect(p) && ((p.x > left+1 && p.x < right-1) || (p.y > top+1 && p.y < bottom-1)); } - //FIXME lots of copy-pasta from tunnel rooms here + //FIXME this class is a total mess, lots of copy-pasta from tunnel and perimeter rooms here @Override public void paint(Level level) { @@ -62,43 +64,82 @@ public class SewerPipeRoom extends StandardRoom { Rect c = getConnectionSpace(); - for (Door door : connected.values()) { - - Point start; - Point mid; - Point end; - - start = new Point(door); - if (start.x == left) start.x+=2; - else if (start.y == top) start.y+=2; - else if (start.x == right) start.x-=2; - else if (start.y == bottom) start.y-=2; - - int rightShift; - int downShift; - - if (start.x < c.left) rightShift = c.left - start.x; - else if (start.x > c.right) rightShift = c.right - start.x; - else rightShift = 0; - - if (start.y < c.top) downShift = c.top - start.y; - else if (start.y > c.bottom) downShift = c.bottom - start.y; - else downShift = 0; - - //always goes inward first - if (door.x == left || door.x == right){ - mid = new Point(start.x + rightShift, start.y); - end = new Point(mid.x, mid.y + downShift); - - } else { - mid = new Point(start.x, start.y + downShift); - end = new Point(mid.x + rightShift, mid.y); - + if (connected.size() <= 3) { + for (Door door : connected.values()) { + + Point start; + Point mid; + Point end; + + start = new Point(door); + if (start.x == left) start.x += 2; + else if (start.y == top) start.y += 2; + else if (start.x == right) start.x -= 2; + else if (start.y == bottom) start.y -= 2; + + int rightShift; + int downShift; + + if (start.x < c.left) rightShift = c.left - start.x; + else if (start.x > c.right) rightShift = c.right - start.x; + else rightShift = 0; + + if (start.y < c.top) downShift = c.top - start.y; + else if (start.y > c.bottom) downShift = c.bottom - start.y; + else downShift = 0; + + //always goes inward first + if (door.x == left || door.x == right) { + mid = new Point(start.x + rightShift, start.y); + end = new Point(mid.x, mid.y + downShift); + + } else { + mid = new Point(start.x, start.y + downShift); + end = new Point(mid.x + rightShift, mid.y); + + } + + Painter.drawLine(level, start, mid, Terrain.WATER); + Painter.drawLine(level, mid, end, Terrain.WATER); + + } + } else { + ArrayList pointsToFill = new ArrayList<>(); + for (Point door : connected.values()) { + Point p = new Point(door); + if (p.y == top){ + p.y+=2; + } else if (p.y == bottom) { + p.y-=2; + } else if (p.x == left){ + p.x+=2; + } else { + p.x-=2; + } + pointsToFill.add( p ); + } + + ArrayList pointsFilled = new ArrayList<>(); + pointsFilled.add(pointsToFill.remove(0)); + + Point from = null, to = null; + int shortestDistance; + while(!pointsToFill.isEmpty()){ + shortestDistance = Integer.MAX_VALUE; + for (Point f : pointsFilled){ + for (Point t : pointsToFill){ + int dist = distanceBetweenPoints(f, t); + if (dist < shortestDistance){ + from = f; + to = t; + shortestDistance = dist; + } + } + } + fillBetweenPoints(level, from, to, Terrain.WATER); + pointsFilled.add(to); + pointsToFill.remove(to); } - - Painter.drawLine( level, start, mid, Terrain.WATER); - Painter.drawLine( level, mid, end, Terrain.WATER ); - } for(Point p : getPoints()){ @@ -147,5 +188,87 @@ public class SewerPipeRoom extends StandardRoom { return c; } + + private int spaceBetween(int a, int b){ + return Math.abs(a - b)-1; + } + + //gets the path distance between two points + private int distanceBetweenPoints(Point a, Point b){ + //on the same side + if (a.y == b.y || a.x == b.x){ + return Math.max(spaceBetween(a.x, b.x), spaceBetween(a.y, b.y)); + } + + //otherwise... + //subtract 1 at the end to account for overlap + return + Math.min(spaceBetween(left, a.x) + spaceBetween(left, b.x), + spaceBetween(right, a.x) + spaceBetween(right, b.x)) + + + Math.min(spaceBetween(top, a.y) + spaceBetween(top, b.y), + spaceBetween(bottom, a.y) + spaceBetween(bottom, b.y)) + - + 1; + } + + private Point[] corners; + + //picks the smallest path to fill between two points + private void fillBetweenPoints(Level level, Point from, Point to, int floor){ + + //doors are along the same side + if (from.y == to.y || from.x == to.x){ + Painter.fill(level, + Math.min(from.x, to.x), + Math.min(from.y, to.y), + spaceBetween(from.x, to.x) + 2, + spaceBetween(from.y, to.y) + 2, + floor); + return; + } + + //set up corners + if (corners == null){ + corners = new Point[4]; + corners[0] = new Point(left+2, top+2); + corners[1] = new Point(right-2, top+2); + corners[2] = new Point(right-2, bottom-2); + corners[3] = new Point(left+2, bottom-2); + } + + //doors on adjacent sides + for (Point c : corners){ + if ((c.x == from.x || c.y == from.y) && (c.x == to.x || c.y == to.y)){ + Painter.drawLine(level, from, c, floor); + Painter.drawLine(level, c, to, floor); + return; + } + } + + //doors on opposite sides + Point side; + if (from.y == top+1 || from.y == bottom-1){ + //connect along the left, or right side + if (spaceBetween(left, from.x) + spaceBetween(left, to.x) <= + spaceBetween(right, from.x) + spaceBetween(right, to.x)){ + side = new Point(left+1, top + height()/2); + } else { + side = new Point(right-1, top + height()/2); + } + + } else { + //connect along the top, or bottom side + if (spaceBetween(top, from.y) + spaceBetween(top, to.y) <= + spaceBetween(bottom, from.y) + spaceBetween(bottom, to.y)){ + side = new Point(left + width()/2, top+1); + } else { + side = new Point(left + width()/2, bottom-1); + } + } + //treat this as two connections with adjacent sides + fillBetweenPoints(level, from, side, floor); + fillBetweenPoints(level, side, to, floor); + } }