package Roguelike.DungeonGeneration.RoomGenerators; import java.util.Random; import Roguelike.DungeonGeneration.DungeonFileParser; import Roguelike.DungeonGeneration.Symbol; import com.badlogic.gdx.utils.XmlReader.Element; public class Polygon extends AbstractRoomGenerator { private static final int REGION = 25; /* * The following 3 functions (floodfill, floodall, joinall) are creditted to Ray Dillinger. * * These can be used to join disconnected regions. */ private void floodfill(int[][] map, int size_y, int size_x, int y, int x, int mark, int[] miny, int[] minx) { int i; int j; for (i=-1;i<=1;i++) for (j=-1;j<=1;j++) if (i+x < size_x && i+x >= 0 && j+y < size_y && j+y >= 0 && map[j+y][i+x] != 0 && map[j+y][i+x] != mark) { map[j+y][i+x] = mark; /* side effect of floodfilling is recording minimum x and y for each region*/ if (mark < REGION) { if (i+x < minx[mark]) minx[mark] = i+x; if (j+y < miny[mark]) miny[mark] = j+y; } floodfill(map, size_y, size_x, j+y, i+x, mark, miny, minx); } } /* find all regions, mark each open cell (by floodfill) with an integer 2 or greater indicating what region it's in. */ private int floodall(int[][] map, int size_y, int size_x, int[] miny,int[] minx) { int x; int y; int count = 2; int retval = 0; /* start by setting all floor tiles to 1. */ /* wall spaces are marked 0. */ for (y=0;y< size_y;y++) { for (x=0;x< size_x;x++) { if (map[y][x] != 0) { map[y][x] = 1; } } } /* reset region extent marks to -1 invalid */ for (x=0;x<REGION;x++) { minx[x] = -1; miny[x] = -1; } /* now mark regions starting with the number 2. */ for (y=0;y< size_y;y++) { for (x=0;x< size_x;x++) { if (map[y][x] == 1) { if (count < REGION) { minx[count] = x; miny[count] = y; } floodfill(map, size_y, size_x, y, x, count, miny, minx); count++; retval++; } } } /* return the number of floodfill regions found */ return(retval); } /* * Instead of joining the regions, we remove all but the largest region, and renumber * this largest region */ private int removeallbutlargest(int[][] map, int size_y, int size_x) { int[] count = new int[REGION]; int y, x, c = 2; int retval; retval = floodall(map, size_y, size_x, count, count); /* if we have multiple unconnected regions */ if (retval > 1) { for (x = 0; x < REGION; x++) { count[x]=0; } for (y = 0; y < size_y; y++) for (x = 0; x < size_x; x++) { count[map[y][x]]++; } c = 0; for (x = 0; x < REGION; x++) { if (count[x] > count[c]) c = x; } } /* Remove all but largest region */ for (y = 0; y < size_y; y++) for (x = 0; x < size_x; x++) if (map[y][x] == c) map[y][x] = 1; else map[y][x] = 0; return(1); } /* * The following function is from http://www.ecse.rpi.edu/Homepages/wrf/Research/Short_Notes/pnpoly.html#The%20C%20Code * * Copyright (c) 1970-2003, Wm. Randolph Franklin * * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files * (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, * publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do * so, subject to the following conditions: * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimers. * 2. Redistributions in binary form must reproduce the above copyright notice in the documentation and/or other materials provided * with the distribution. * 3. The name of W. Randolph Franklin may not be used to endorse or promote products derived from this Software without specific * prior written permission. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE * FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ private boolean pnpoly(int nvert, float[] vertx, float[] verty, float testx, float testy) { int i; int j; boolean c = false; for (i = 0, j = nvert-1; i < nvert; j = i++) { if ( ((verty[i]>testy) != (verty[j]>testy)) && (testx < (vertx[j]-vertx[i]) * (testy-verty[i]) / (verty[j]-verty[i]) + vertx[i]) ) { c = !c; } } return c; } /* It is possible to generate poly rooms with very small sizes. We ensure that these rooms have * a minimum size */ private final int MIN_POLY_ROOM_SIZE = 17; /* * Generates a room from a convex or concave polygon. We don't completely handle the complex (self-intersecting) case * but it could be extended to do so. Most of the smarts are on pnpoly (above). * * *y and *x represent pairs of vertex coordinates. These should probably be ordered but may not require this. */ private boolean generate_poly_room(int n, int[] y, int[] x, Symbol[][] grid, Symbol floor, Symbol wall) { float[] verty = new float[n+1]; float[] vertx = new float[n+1]; int i, xi, yi, size_y, size_x; int y0 = 256; int x0 = 256; int y1 = 0; int x1 = 0; int floors = 0; /* Copy contents to floating array */ for (i = 0; i < n-1; i++) { verty[i] = (float)y[i]; vertx[i] = (float)x[i]; /* Determine extents */ if (y[i] > y1) y1 = y[i]; if (y[i] < y0) y0 = y[i]; if (x[i] > x1) x1 = x[i]; if (x[i] < x0) x0 = x[i]; } /* Safety - repeat initial vertex at end of polygon */ if ((y[n-1] != y[0]) || (x[n-1] != x[0])) { verty[n] = (float)y[0]; vertx[n] = (float)x[0]; n++; } /* Allocate space for the region borders */ //y0--; x0--; y1++; x1++; /* Get grid size */ size_y = y1 - y0 - 1; size_x = x1 - x0 - 1; int[][] tgrid = new int[size_y][size_x]; /* Draw the polygon */ for (yi = 0; yi < size_y; yi++) { for (xi = 0; xi < size_x; xi++) { /* Point in the polygon */ if (pnpoly(n, verty, vertx, (float)(yi + y0), (float)(xi + x0))) { tgrid[yi][xi] = 0; floors++; } else { tgrid[yi][xi] = 1; } } } /* Ensure minimum size */ if (floors < MIN_POLY_ROOM_SIZE) return false; /* Remove all but largest region */ removeallbutlargest(tgrid, size_y, size_x); /* Write final grids out to map */ for(yi=0; yi<size_y; yi++) { for(xi=0; xi<size_x; xi++) { if (tgrid[yi][xi] == 1) { grid[xi][yi] = wall; } else { grid[xi][yi] = floor; } } } return true; } /* * Helper function for build_type_concave. We use this to generate * inner concave spaces as well. */ public void process(Symbol[][] grid, Symbol floor, Symbol wall, Random ran, DungeonFileParser dfp) { int[] verty = new int[12]; int[] vertx = new int[12]; int n = 0; int d, i; int points = 4; int y1a = 0; int x1a = 0; int y2a = 0; int x2a = grid.length; int y1b = grid[0].length; int x1b = 0; int y2b = grid[0].length; int x2b = grid.length; /* Generate 1 or more points for each edge */ d = ran.nextInt(points-1)+1; /* Add vertices */ for (i = 0; i < d; i++) { int y1w = (x1a < x1b ? y1a : (x1a == x1b ? Math.min(y1a, y1b) : y1b)); int y2w = (x1a < x1b ? y2a : (x1a == x1b ? Math.max(y2a, y2b) : y2b)); int x1w = Math.min(x1a, x1b); int x2w = (x1a == x1b ? x1a + 1 : Math.max(x1a, x1b) - 1); int y = y1w + ran.nextInt(y2w - y1w + 1); int x = x1w + ran.nextInt(x2w - x1w + 1); int j = n; /* Sort from highest to lowest y */ while ((j > 0) && (verty[j-1] <= y)) { verty[j] = verty[j-1]; vertx[j] = vertx[j-1]; j--; } /* Insert new value */ verty[j] = y; vertx[j] = x; n++; } /* Generate 1 or more points for each edge */ d = ran.nextInt(points-1)+1; /* Add vertices */ for (i = 0; i < d; i++) { int y1n = Math.min(y1a, y1b); int y2n = (y1a == y1b ? y1a + 1 : Math.max(y1a, y1b) - 1); int x1n = (y1a < y1b ? x1a : (y1a == y1b ? Math.min(x1a, x1b): x1b)); int x2n = (y1a < y1b ? x2a : (y1a == y1b ? Math.max(x2a, x2b): x2b)); int y = y1n + ran.nextInt(y2n - y1n + 1); int x = x1n + ran.nextInt(x2n - x1n + 1); int j = n; /* Sort from lowest to highest x */ while ((j > 0) && (vertx[j-1] >= x)) { verty[j] = verty[j-1]; vertx[j] = vertx[j-1]; j--; } /* Insert new value */ verty[j] = y; vertx[j] = x; n++; } /* Generate 1 or more points for each edge */ d = ran.nextInt(points-1)+1; /* Add vertices */ for (i = 0; i < d; i++) { int y1e = (x2a > x2b ? y1a : (x1a == x1b ? Math.min(y1a, y1b): y1b)); int y2e = (x2a > x2b ? y2a : (x1a == x1b ? Math.max(y2a, y2b): y2b)); int x1e = (x2a == x2b ? x2a - 1 : Math.min(x2a, x2b) + 1); int x2e = Math.max(x2a, x2b); int y = y1e + ran.nextInt(y2e - y1e + 1); int x = x1e + ran.nextInt(x2e - x1e + 1); int j = n; /* Sort from lowest to highest y */ while ((j > 0) && (verty[j-1] >= y)) { verty[j] = verty[j-1]; vertx[j] = vertx[j-1]; j--; } /* Insert new value */ verty[j] = y; vertx[j] = x; n++; } /* Generate 1 or more points for each edge */ d = ran.nextInt(points-1)+1; /* Add vertices */ for (i = 0; i < d; i++) { int y1s = (y2a == y2b ? y2a - 1 : Math.min(y2a, y2b) + 1); int y2s = Math.max(y2a, y2b); int x1s = (y2a > y2b ? x1a : (y2a == y2b ? Math.min(x1a, x1b): x1b)); int x2s = (y2a > y2b ? x2a : (y2a == y2b ? Math.max(x2a, x2b): x2b)); int y = y1s + ran.nextInt(y2s - y1s + 1); int x = x1s + ran.nextInt(x2s - x1s + 1); int j = n; /* Sort from highest to lowest x */ while ((j > 0) && (vertx[j-1] <= x)) { verty[j] = verty[j-1]; vertx[j] = vertx[j-1]; j--; } /* Insert new value */ verty[j] = y; vertx[j] = x; n++; } /* Remove duplicate vertices */ for (i = 1; i < n; i++) { if ((verty[i] == verty[i-1]) && (vertx[i] == vertx[i-1])) { int j; for (j = i + 1; j < n; j++) { verty[j-1] = verty[j]; vertx[j-1] = vertx[j]; } n--; } } /* Generate the polygon */ generate_poly_room(n, verty, vertx, grid, floor, wall); } @Override public void parse(Element xml) { } }