diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/levels/painters/Painter.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/levels/painters/Painter.java index 6d7e60633..ed7b79aa6 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/levels/painters/Painter.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/levels/painters/Painter.java @@ -73,6 +73,30 @@ public abstract class Painter { fill( level, rect.left + l, rect.top + t, rect.width() - (l + r), rect.height() - (t + b), value ); } + public static void drawLine( Level level, Point from, Point to, int value){ + float x = from.x; + float y = from.y; + float dx = to.x - from.x; + float dy = to.y - from.y; + + boolean movingbyX = Math.abs(dx) >= Math.abs(dy); + //normalize + if (movingbyX){ + dy /= Math.abs(dx); + dx /= Math.abs(dx); + } else { + dx /= Math.abs(dy); + dy /= Math.abs(dy); + } + + set(level, Math.round(x), Math.round(y), value); + while((movingbyX && to.x != x) || (!movingbyX && to.y != y)){ + x += dx; + y += dy; + set(level, Math.round(x), Math.round(y), value); + } + } + public static Point drawInside( Level level, Room room, Point from, int n, int value ) { Point step = new Point(); diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/levels/rooms/connection/PerimeterRoom.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/levels/rooms/connection/PerimeterRoom.java index fa9541907..4169a8245 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/levels/rooms/connection/PerimeterRoom.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/levels/rooms/connection/PerimeterRoom.java @@ -23,101 +23,138 @@ package com.shatteredpixel.shatteredpixeldungeon.levels.rooms.connection; import com.shatteredpixel.shatteredpixeldungeon.levels.Level; import com.shatteredpixel.shatteredpixeldungeon.levels.painters.Painter; -import com.shatteredpixel.shatteredpixeldungeon.levels.rooms.Room; import com.watabou.utils.Point; import java.util.ArrayList; -import java.util.Collections; //tunnels along the room's perimeter -//FIXME should be refactored, like shop rooms (which use perimiter logic for item placement) public class PerimeterRoom extends ConnectionRoom { - private static int pasWidth; - private static int pasHeight; - public void paint( Level level ) { - pasWidth = width() - 3; - pasHeight = height() - 3; - int floor = level.tunnelTile(); - ArrayList joints = new ArrayList(); + ArrayList pointsToFill = new ArrayList<>(); for (Point door : connected.values()) { - joints.add( xy2p( this, door ) ); - } - Collections.sort( joints ); - - int nJoints = joints.size(); - int perimeter = pasWidth * 2 + pasHeight * 2; - - int start = 0; - int maxD = joints.get( 0 ) + perimeter - joints.get( nJoints - 1 ); - for (int i=1; i < nJoints; i++) { - int d = joints.get( i ) - joints.get( i - 1 ); - if (d > maxD) { - maxD = d; - start = i; + Point p = new Point(door); + if (p.y == top){ + p.y++; + } else if (p.y == bottom) { + p.y--; + } else if (p.x == left){ + p.x++; + } else { + p.x--; } + pointsToFill.add( p ); } - int end = (start + nJoints - 1) % nJoints; + ArrayList pointsFilled = new ArrayList<>(); + pointsFilled.add(pointsToFill.remove(0)); - int p = joints.get( start ); - do { - Painter.set( level, p2xy( this, p ), floor ); - p = (p + 1) % perimeter; - } while (p != joints.get( end )); - - Painter.set( level, p2xy( this, p ), floor ); + 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, floor); + pointsFilled.add(to); + pointsToFill.remove(to); + } for (Door door : connected.values()) { door.set( Door.Type.TUNNEL ); } } - private static int xy2p( Room room, Point xy ) { - if (xy.y == room.top) { - - return (xy.x - room.left - 1); - - } else if (xy.x == room.right) { - - return (xy.y - room.top - 1) + pasWidth; - - } else if (xy.y == room.bottom) { - - return (room.right - xy.x - 1) + pasWidth + pasHeight; - - } else { - - if (xy.y == room.top + 1) { - return 0; - } else { - return (room.bottom - xy.y - 1) + pasWidth * 2 + pasHeight; - } - - } + private int spaceBetween(int a, int b){ + return Math.abs(a - b)-1; } - private static Point p2xy( Room room, int p ) { - if (p < pasWidth) { - - return new Point( room.left + 1 + p, room.top + 1); - - } else if (p < pasWidth + pasHeight) { - - return new Point( room.right - 1, room.top + 1 + (p - pasWidth) ); - - } else if (p < pasWidth * 2 + pasHeight) { - - return new Point( room.right - 1 - (p - (pasWidth + pasHeight)), room.bottom - 1 ); - - } else { - - return new Point( room.left + 1, room.bottom - 1 - (p - (pasWidth * 2 + pasHeight)) ); - + //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+1, top+1); + corners[1] = new Point(right-1, top+1); + corners[2] = new Point(right-1, bottom-1); + corners[3] = new Point(left+1, bottom-1); + } + + //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); } }