/** * Generate a char[][] dungeon with extra features given a baseDungeon that has already been * generated, and that already has staircases represented by greater than and less than signs. * Typically, you want to call generate with a TilesetType or no argument for the easiest * generation; this method is meant for adding features like water and doors to existing simple * maps. This uses '#' for walls, '.' for floors, '~' for deep water, ',' for shallow water, '^' * for traps, '+' for doors that provide horizontal passage, and '/' for doors that provide * vertical passage. Use the addDoors, addWater, addGrass, and addTraps methods of this class to * request these in the generated map. Also sets the fields stairsUp and stairsDown to null, and * expects stairs to be already handled. * * @param baseDungeon a pre-made dungeon consisting of '#' for walls and '.' for floors, with * stairs already in; may be modified in-place * @return a char[][] dungeon */ public char[][] generateRespectingStairs(char[][] baseDungeon) { if (!seedFixed) { rebuildSeed = rng.getState(); } seedFixed = false; char[][] map = DungeonUtility.wallWrap(baseDungeon); DijkstraMap dijkstra = new DijkstraMap(map); stairsUp = null; stairsDown = null; dijkstra.clearGoals(); ArrayList<Coord> stairs = DungeonUtility.allMatching(map, '<', '>'); for (int j = 0; j < stairs.size(); j++) { dijkstra.setGoal(stairs.get(j)); } dijkstra.scan(null); for (int i = 0; i < width; i++) { for (int j = 0; j < height; j++) { if (dijkstra.gradientMap[i][j] >= DijkstraMap.FLOOR) { map[i][j] = '#'; } } } return innerGenerate(map); }
/** Make a DungeonGenerator with a LightRNG using a random seed, height 40, and width 40. */ public DungeonGenerator() { rng = new StatefulRNG(); gen = new DungeonBoneGen(rng); utility = new DungeonUtility(rng); rebuildSeed = rng.getState(); height = 40; width = 40; fx = new EnumMap<>(FillEffect.class); }
/** * Copies all fields from copying and makes a new DungeonGenerator. * * @param copying the DungeonGenerator to copy */ public DungeonGenerator(DungeonGenerator copying) { rng = new StatefulRNG(copying.rng.getState()); gen = new DungeonBoneGen(rng); utility = new DungeonUtility(rng); rebuildSeed = rng.getState(); height = copying.height; width = copying.width; fx = new EnumMap<>(copying.fx); dungeon = copying.dungeon; }
/** * Generate a char[][] dungeon with extra features given a baseDungeon that has already been * generated. Typically, you want to call generate with a TilesetType or no argument for the * easiest generation; this method is meant for adding features like water and doors to existing * simple maps. This uses '#' for walls, '.' for floors, '~' for deep water, ',' for shallow * water, '^' for traps, '+' for doors that provide horizontal passage, and '/' for doors that * provide vertical passage. Use the addDoors, addWater, addGrass, and addTraps methods of this * class to request these in the generated map. Also sets the fields stairsUp and stairsDown to * two randomly chosen, distant, connected, walkable cells. <br> * Special behavior here: If tab characters are present in the 2D char array, they will be * replaced with '.' in the final dungeon, but will also be tried first as valid staircase * locations (with a high distance possible to travel away from the starting staircase). If no tab * characters are present this will search for '.' floors to place stairs on, as normal. This * tab-first behavior is useful in conjunction with some methods that establish a good path in an * existing dungeon; an example is {@code DungeonUtility.ensurePath(dungeon, rng, '\t', '#');} * then passing dungeon (which that code modifies) in as baseDungeon to this method. * * @param baseDungeon a pre-made dungeon consisting of '#' for walls and '.' for floors; may be * modified in-place * @return a char[][] dungeon */ public char[][] generate(char[][] baseDungeon) { if (!seedFixed) { rebuildSeed = rng.getState(); } seedFixed = false; char[][] map = DungeonUtility.wallWrap(baseDungeon); width = map.length; height = map[0].length; DijkstraMap dijkstra = new DijkstraMap(map); int frustrated = 0; do { dijkstra.clearGoals(); stairsUp = utility.randomMatchingTile(map, '\t'); if (stairsUp == null) { stairsUp = utility.randomFloor(map); if (stairsUp == null) { frustrated++; continue; } } dijkstra.setGoal(stairsUp); dijkstra.scan(null); frustrated++; } while (dijkstra.getMappedCount() < width + height && frustrated < 8); if (frustrated >= 8) { return generate(); } double maxDijkstra = 0.0; for (int i = 0; i < width; i++) { for (int j = 0; j < height; j++) { if (dijkstra.gradientMap[i][j] >= DijkstraMap.FLOOR) { map[i][j] = '#'; } else if (dijkstra.gradientMap[i][j] > maxDijkstra) { maxDijkstra = dijkstra.gradientMap[i][j]; } if (map[i][j] == '\t') { map[i][j] = '.'; } } } stairsDown = new GreasedRegion(dijkstra.gradientMap, maxDijkstra * 0.7, DijkstraMap.FLOOR) .singleRandom(rng); return innerGenerate(map); }
/** * Generate a char[][] dungeon given a TilesetType; the comments in that class provide some * opinions on what each TilesetType value could be used for in a game. This uses '#' for walls, * '.' for floors, '~' for deep water, ',' for shallow water, '^' for traps, '+' for doors that * provide horizontal passage, and '/' for doors that provide vertical passage. Use the addDoors, * addWater, addGrass, and addTraps methods of this class to request these in the generated map. * Also sets the fields stairsUp and stairsDown to two randomly chosen, distant, connected, * walkable cells. * * @see squidpony.squidgrid.mapping.styled.TilesetType * @param kind a TilesetType enum value, such as TilesetType.DEFAULT_DUNGEON * @return a char[][] dungeon */ public char[][] generate(TilesetType kind) { seedFixed = true; rebuildSeed = rng.getState(); return generate(gen.generate(kind, width, height)); }