001package squidpony.squidgrid.mapping; 002 003import squidpony.ArrayTools; 004import squidpony.squidmath.IRNG; 005import squidpony.squidmath.SeededNoise; 006 007/** 008 * Created by Tommy Ettinger on 8/7/2016. 009 */ 010public class ThinDungeonGenerator extends SectionDungeonGenerator { 011 public static final int 012 ROOM_WALL_RETRACT = 1, ROOM_WALL_NORMAL = 2, ROOM_WALL_EXPAND = 4, ROOM_WALL_CHAOTIC = 8, 013 CORRIDOR_WALL_RETRACT = 16, CORRIDOR_WALL_NORMAL = 32, CORRIDOR_WALL_EXPAND = 64, CORRIDOR_WALL_CHAOTIC = 128, 014 CAVE_WALL_RETRACT = 256, CAVE_WALL_NORMAL = 512, CAVE_WALL_EXPAND = 1024, CAVE_WALL_CHAOTIC = 2048; 015 public int wallShapes = ROOM_WALL_EXPAND | CORRIDOR_WALL_EXPAND | CAVE_WALL_CHAOTIC; 016 /** 017 * Make a DungeonGenerator with a LightRNG using a random seed, height 40, and width 40. 018 */ 019 public ThinDungeonGenerator() { 020 super(); 021 } 022 023 /** 024 * Make a DungeonGenerator with the given height and width; the RNG used for generating a dungeon and 025 * adding features will be a LightRNG using a random seed. 026 * 027 * @param width The width of the dungeon in cells 028 * @param height The height of the dungeon in cells 029 */ 030 public ThinDungeonGenerator(int width, int height) { 031 super(width, height); 032 } 033 034 /** 035 * Make a DungeonGenerator with the given height, width, and RNG. Use this if you want to seed the RNG. 036 * 037 * @param width The width of the dungeon in cells 038 * @param height The height of the dungeon in cells 039 * @param rng The RNG to use for all purposes in this class; if it is a StatefulRNG, then it will be used as-is, 040 */ 041 public ThinDungeonGenerator(int width, int height, IRNG rng) { 042 super(width, height, rng); 043 } 044 045 /** 046 * Make a DungeonGenerator with the given height and width; the RNG used for generating a dungeon and 047 * adding features will be a LightRNG using a random seed. You can give the static fields of this class 048 * as arguments to roomShape, corridorShape and caveShape. For clarity, the 3 fields should each be given 049 * a constant corresponding to the same kind of area, e.g. ROOM_WALL_EXPAND or ROOM_WALL_RETRACT could be 050 * given to roomShape but preferably would not be given to the others. If the combination of arguments is 051 * invalid, such as if they are all 0, this uses the default shapes: expanded room and corridor walls, and 052 * chaotic cave walls controlled by {@link SeededNoise}. 053 * <br> 054 * Though there's no constructor that takes a single int which merges roomShape, corridorShape, and 055 * caveShape, the internal representation of those shapes is one int. If you have one of those ints, or you 056 * made one yourself (such as with bitwise OR on three different constants), you can pass it to any of the 057 * three shape arguments and 0 to the other two shapes; it will be processed in the same way. 058 * 059 * @param width The width of the dungeon in cells 060 * @param height The height of the dungeon in cells 061 * @param roomShape expected to be an int constant: ROOM_WALL_EXPAND, ROOM_WALL_RETRACT, or ROOM_WALL_CHAOTIC 062 * @param corridorShape expected to be an int constant: CORRIDOR_WALL_EXPAND, CORRIDOR_WALL_RETRACT, or CORRIDOR_WALL_CHAOTIC 063 * @param caveShape expected to be an int constant: CAVE_WALL_EXPAND, CAVE_WALL_RETRACT, or CAVE_WALL_CHAOTIC 064 */ 065 public ThinDungeonGenerator(int width, int height, int roomShape, int corridorShape, int caveShape) { 066 super(width, height); 067 wallShapes = roomShape | corridorShape | caveShape; 068 if ((wallShapes & 0xF) == 0 || (wallShapes & 0xF0) == 0 || (wallShapes & 0xF00) == 0 069 || Integer.bitCount(wallShapes) != 3) 070 wallShapes = ROOM_WALL_EXPAND | CORRIDOR_WALL_EXPAND | CAVE_WALL_CHAOTIC; 071 } 072 073 /** 074 * Make a DungeonGenerator with the given height, width, and RNG for generating random features. You can 075 * give the static fields of this class as arguments to roomShape, corridorShape and caveShape. For 076 * clarity, the 3 fields should each be given a constant corresponding to the same kind of area, e.g. 077 * ROOM_WALL_EXPAND or ROOM_WALL_RETRACT could be given to roomShape but preferably would not be given to 078 * the others. If the combination of arguments is invalid, such as if they are all 0, this uses the default 079 * shapes: expanded room and corridor walls, and chaotic cave walls controlled by {@link SeededNoise}. 080 * <br> 081 * Though there's no constructor that takes a single int which merges roomShape, corridorShape, and 082 * caveShape, the internal representation of those shapes is one int. If you have one of those ints, or you 083 * made one yourself (such as with bitwise OR on three different constants), you can pass it to any of the 084 * three shape arguments and 0 to the other two shapes; it will be processed in the same way. 085 * 086 * @param width The width of the dungeon in cells 087 * @param height The height of the dungeon in cells 088 * @param roomShape expected to be an int constant: ROOM_WALL_EXPAND, ROOM_WALL_RETRACT, or ROOM_WALL_CHAOTIC 089 * @param corridorShape expected to be an int constant: CORRIDOR_WALL_EXPAND, CORRIDOR_WALL_RETRACT, or CORRIDOR_WALL_CHAOTIC 090 * @param caveShape expected to be an int constant: CAVE_WALL_EXPAND, CAVE_WALL_RETRACT, or CAVE_WALL_CHAOTIC 091 * @param rng The RNG to use for all purposes in this class; if it is a StatefulRNG, then it will be used as-is, 092 */ 093 public ThinDungeonGenerator(int width, int height, IRNG rng, int roomShape, int corridorShape, int caveShape) { 094 super(width, height, rng); 095 wallShapes = roomShape | corridorShape | caveShape; 096 if ((wallShapes & 0xF) == 0 || (wallShapes & 0xF0) == 0 || (wallShapes & 0xF00) == 0 097 || Integer.bitCount(wallShapes) != 3) 098 wallShapes = ROOM_WALL_EXPAND | CORRIDOR_WALL_EXPAND | CAVE_WALL_CHAOTIC; 099 } 100 101 102 /** 103 * Copies all fields from copying and makes a new DungeonGenerator. 104 * 105 * @param copying the DungeonGenerator to copy 106 */ 107 public ThinDungeonGenerator(ThinDungeonGenerator copying) { 108 super(copying); 109 wallShapes = copying.wallShapes; 110 } 111 112 /** 113 * Doors are not supported by this class. There's a lot of confusing and ambiguous situations that can easily 114 * result from trying to automatically place doors when any given map could need doors on walkable cells, prefer 115 * doors between walkable cells aligned to walls, have mixes of "expanded", "retracted", and "normal" wall change 116 * modes, or any number of other issues. There are also some very confusing cases where automatically-placed doors, 117 * if this class tries to reposition them in retracted-wall mode (or in any case where rooms and corridors don't 118 * have the same change mode), wind up hanging in the middle of a room or with partial connecting walls but not any 119 * sensible layout. If you want doors here, you should assign them yourself how you see fit. 120 * @param percentage ignored. 121 * @param doubleDoors ignored. 122 * @return this for chaining. 123 */ 124 @Override 125 public SectionDungeonGenerator addDoors(int percentage, boolean doubleDoors) 126 { 127 doorFX = 0; 128 return this; 129 } 130 131 public char[][] makeThin() { 132 133 int nw = (width << 1) - 1, nh = (height << 1) - 1; 134 char[][] d2 = new char[nw][nh]; 135 int[][] e2 = new int[nw][nh]; 136 137 for (int x = 0; x < width; x++) { 138 for (int y = 0; y < height; y++) { 139 d2[x * 2][y * 2] = dungeon[x][y]; 140 e2[x * 2][y * 2] = finder.environment[x][y]; 141 } 142 } 143 int eLow, eHigh; 144 char dLow, dHigh; 145 int tempShapes; 146 for (int y = 0; y < nh; y += 2) { 147 CELL_WISE: 148 for (int x = 1; x < nw - 1; x += 2) { 149 eLow = e2[x - 1][y]; 150 eHigh = e2[x + 1][y]; 151 dLow = d2[x - 1][y]; 152 dHigh = d2[x + 1][y]; 153 tempShapes = wallShapes; 154 switch (eLow) { 155 case DungeonUtility.CAVE_FLOOR: 156 tempShapes >>= 4; 157 case DungeonUtility.CORRIDOR_FLOOR: 158 tempShapes >>= 4; 159 break; 160 default: 161 switch (eHigh) { 162 case DungeonUtility.CAVE_FLOOR: 163 tempShapes >>= 4; 164 case DungeonUtility.CORRIDOR_FLOOR: 165 tempShapes >>= 4; 166 } 167 } 168 switch (tempShapes & 0xf) { 169// case ROOM_WALL_RETRACT: 170 case ROOM_WALL_NORMAL: 171 if (y > 1 && y < nh - 2) { 172 if ((dLow == '+') && (e2[x - 1][y - 2] & 1) + (e2[x - 1][y + 2] & 1) == 0) { 173 d2[x][y] = dHigh; 174 e2[x][y] = eHigh; 175 d2[x - 1][y - 1] = '#'; 176 d2[x - 1][y + 1] = '#'; 177 e2[x - 1][y - 1] = 777; 178 e2[x - 1][y + 1] = 777; 179 if (e2[x][y] != DungeonUtility.UNTOUCHED || d2[x][y] == 0) 180 d2[x][y] = 6; 181 continue CELL_WISE; 182 } /*else if ((dHigh == '+') && (e2[x+1][y - 2] & 1) + (e2[x+1][y - 2] & 1) == 0) { 183 d2[x][y] = dLow; 184 e2[x][y] = eLow; 185 d2[x+1][y-1] = '#'; 186 d2[x+1][y+1] = '#'; 187 e2[x+1][y-1] = MixedGenerator.UNTOUCHED; 188 e2[x+1][y+1] = MixedGenerator.UNTOUCHED; 189 if (e2[x][y] != MixedGenerator.UNTOUCHED || d2[x][y] == 0) 190 d2[x][y] = '\u0006'; 191 continue CELL_WISE; 192 }*/ 193 } 194 break; 195// case ROOM_WALL_RETRACT: 196// if (x > 2 && y > 1 && y < nh - 2) { 197// if ((dLow == '+') && (e2[x-1][y + 2] & 1) + (e2[x-1][y - 2] & 1) == 0) { 198// d2[x][y] = dLow; 199// e2[x][y] = eLow; 200// d2[x][y-1] = d2[x-1][y - 2]; 201// e2[x][y-1] = e2[x-1][y - 2]; 202// d2[x][y+1] = d2[x-1][y + 2]; 203// e2[x][y+1] = e2[x-1][y + 2]; 204// d2[x-1][y] = d2[x-3][y]; 205// e2[x-1][y] = e2[x-3][y]; 206// d2[x-1][y-1] = d2[x-3][y-1]; 207// d2[x-1][y+1] = d2[x-3][y+1]; 208// e2[x-1][y-1] = e2[x-3][y-1]; 209// e2[x-1][y+1] = e2[x-3][y+1]; 210// continue CELL_WISE; 211// } 212// } 213// break; 214 case ROOM_WALL_RETRACT: 215 case ROOM_WALL_EXPAND: 216 if (y > 1 && y < nh - 2) { 217 if ((dLow == '+') && ((e2[x - 1][y - 2] & 1) + (e2[x + 1][y - 2] & 1) != 0 || (e2[x - 1][y + 2] & 1) + (e2[x + 1][y + 2] & 1) != 0)) { 218 d2[x][y] = dLow; 219 e2[x][y] = eLow; 220 d2[x - 1][y] = dHigh; 221 e2[x - 1][y] = eHigh; 222 continue CELL_WISE; 223 } else if ((dHigh == '+') && ((e2[x - 1][y - 2] & 1) + (e2[x + 1][y - 2] & 1) != 0 || (e2[x - 1][y + 2] & 1) + (e2[x + 1][y + 2] & 1) != 0)) { 224 d2[x][y] = dHigh; 225 e2[x][y] = eHigh; 226 d2[x + 1][y] = dLow; 227 e2[x + 1][y] = eLow; 228 continue CELL_WISE; 229 } 230 } 231 break; 232 case ROOM_WALL_CHAOTIC: 233 if (dLow == '+') { 234 d2[x - 1][y] = dHigh; 235 e2[x - 1][y] = eHigh; 236 if (e2[x][y] != DungeonUtility.UNTOUCHED || d2[x][y] == 0) 237 d2[x][y] = 6; 238 continue CELL_WISE; 239 } else if (dHigh == '+') { 240 d2[x + 1][y] = dLow; 241 e2[x + 1][y] = eLow; 242 if (e2[x][y] != DungeonUtility.UNTOUCHED || d2[x][y] == 0) 243 d2[x][y] = 6; 244 continue CELL_WISE; 245 } 246 break; 247 } 248 tempShapes = wallShapes; 249 switch (eLow) { 250 case 777: 251 d2[x][y] = '#'; 252 e2[x][y] = DungeonUtility.UNTOUCHED; 253 continue CELL_WISE; 254 case DungeonUtility.CAVE_WALL: 255 case DungeonUtility.CORRIDOR_WALL: 256 case DungeonUtility.ROOM_WALL: 257 case DungeonUtility.UNTOUCHED: 258 switch (eHigh) { 259 case DungeonUtility.CAVE_WALL: 260 case DungeonUtility.CORRIDOR_WALL: 261 case DungeonUtility.ROOM_WALL: 262 case DungeonUtility.UNTOUCHED: 263 e2[x][y] = DungeonUtility.UNTOUCHED; 264 d2[x][y] = dLow; 265 break; 266 case DungeonUtility.CAVE_FLOOR: 267 tempShapes >>= 4; 268 case DungeonUtility.CORRIDOR_FLOOR: 269 tempShapes >>= 4; 270 default: 271 switch (tempShapes & 0xF) { 272 case ROOM_WALL_CHAOTIC: 273 if (SeededNoise.noise(x * 0.666, y * 0.666, 12456789) > -0.2) { 274 e2[x][y] = eHigh; 275 d2[x][y] = dHigh; 276 } else { 277 e2[x][y] = DungeonUtility.UNTOUCHED; 278 d2[x][y] = dLow; 279 } 280 break; 281 case ROOM_WALL_RETRACT: 282 case ROOM_WALL_EXPAND: 283 e2[x][y] = DungeonUtility.UNTOUCHED; 284 d2[x][y] = dLow; 285 break; 286 287// case ROOM_WALL_RETRACT: 288// e2[x][y] = eHigh; 289// d2[x][y] = dHigh; 290// if(x > 2 && (e2[x-3][y] & 1) != 0) { // wall is thin enough 291// e2[x - 1][y] = eHigh; 292// d2[x - 1][y] = dHigh; 293// } 294// break; 295 default: 296 e2[x][y] = eHigh; 297 d2[x][y] = dHigh; 298 break; 299 } 300 break; 301 } 302 break; 303 case DungeonUtility.CAVE_FLOOR: 304 tempShapes >>= 4; 305 case DungeonUtility.CORRIDOR_FLOOR: 306 tempShapes >>= 4; 307 default: 308 switch (eHigh) { 309 case DungeonUtility.CAVE_WALL: 310 case DungeonUtility.CORRIDOR_WALL: 311 case DungeonUtility.ROOM_WALL: 312 case DungeonUtility.UNTOUCHED: 313 switch (tempShapes & 0xF) { 314 case ROOM_WALL_CHAOTIC: 315 if (SeededNoise.noise(x * 0.666, y * 0.666, 12456789) > -0.2) { 316 e2[x][y] = eLow; 317 d2[x][y] = dLow; 318 } else { 319 e2[x][y] = DungeonUtility.UNTOUCHED; 320 d2[x][y] = dHigh; 321 } 322 break; 323 case ROOM_WALL_RETRACT: 324 case ROOM_WALL_EXPAND: 325 e2[x][y] = DungeonUtility.UNTOUCHED; 326 d2[x][y] = dHigh; 327 break; 328 329// case ROOM_WALL_RETRACT: 330// e2[x][y] = eLow; 331// d2[x][y] = dLow; 332// /*if(x < nh - 3 && (e2[x+3][y] & 1) != 0) { // wall is thin enough 333// e2[x + 1][y] = eLow; 334// d2[x + 1][y] = dLow; 335// } 336// */ 337// break; 338 default: 339 e2[x][y] = eLow; 340 d2[x][y] = dLow; 341 break; 342 } 343 break; 344 case DungeonUtility.CAVE_FLOOR: 345 e2[x][y] = DungeonUtility.CAVE_FLOOR; 346 d2[x][y] = dHigh; 347 break; 348 default: 349 e2[x][y] = eLow; 350 d2[x][y] = dLow; 351 break; 352 } 353 break; 354 } 355 if (e2[x][y] != DungeonUtility.UNTOUCHED || d2[x][y] == 0) { 356 d2[x][y] = 6; 357 } 358 } 359 } 360 for (int x = 0; x < nw; x++) { 361 CELL_WISE: 362 for (int y = 1; y < nh - 1; y += 2) { 363 eLow = e2[x][y - 1]; 364 eHigh = e2[x][y + 1]; 365 dLow = d2[x][y - 1]; 366 dHigh = d2[x][y + 1]; 367 tempShapes = wallShapes; 368 switch (eLow) { 369 case DungeonUtility.CAVE_FLOOR: 370 tempShapes >>= 4; 371 case DungeonUtility.CORRIDOR_FLOOR: 372 tempShapes >>= 4; 373 break; 374 default: 375 switch (eHigh) { 376 case DungeonUtility.CAVE_FLOOR: 377 tempShapes >>= 4; 378 case DungeonUtility.CORRIDOR_FLOOR: 379 tempShapes >>= 4; 380 } 381 } 382 switch (tempShapes & 0xf) { 383 case ROOM_WALL_NORMAL: 384 if (x > 0 && x < nw - 1) { 385 if (d2[x - 1][y - 1] == '+' || d2[x - 1][y + 1] == '+' || d2[x + 1][y - 1] == '+' || d2[x + 1][y + 1] == '+') { 386 if (e2[x][y] != DungeonUtility.UNTOUCHED || d2[x][y] == 0) 387 d2[x][y] = 6; 388 continue CELL_WISE; 389 } else if ((dLow == '/') && (e2[x - 2][y - 1] & 1) + (e2[x - 2][y + 1] & 1) == 0) { 390 d2[x][y] = dHigh; 391 e2[x][y] = eHigh; 392 d2[x - 1][y - 1] = '#'; 393 d2[x + 1][y - 1] = '#'; 394 e2[x - 1][y - 1] = DungeonUtility.UNTOUCHED; 395 e2[x + 1][y - 1] = DungeonUtility.UNTOUCHED; 396 if (e2[x][y] != DungeonUtility.UNTOUCHED || d2[x][y] == 0) 397 d2[x][y] = 6; 398 continue CELL_WISE; 399 } else if ((dHigh == '/') && (e2[x - 2][y + 1] & 1) + (e2[x + 2][y + 1] & 1) == 0) { 400 d2[x][y] = dLow; 401 e2[x][y] = eLow; 402 d2[x - 1][y + 1] = '#'; 403 d2[x + 1][y + 1] = '#'; 404 e2[x - 1][y + 1] = DungeonUtility.UNTOUCHED; 405 e2[x + 1][y + 1] = DungeonUtility.UNTOUCHED; 406 if (e2[x][y] != DungeonUtility.UNTOUCHED || d2[x][y] == 0) 407 d2[x][y] = 6; 408 continue CELL_WISE; 409 } 410 } 411 break; 412// case ROOM_WALL_RETRACT: 413// if (y > 2 && x > 1 && x < nw - 2) { 414// if ((dLow == '/') && (e2[x-2][y-1] & 1) + (e2[x+2][y-1] & 1) == 0) { 415// d2[x][y] = dLow; 416// e2[x][y] = eLow; 417// d2[x-1][y] = d2[x-2][y-1]; 418// e2[x-1][y] = e2[x-2][y-1]; 419// d2[x+1][y] = d2[x+2][y-1]; 420// e2[x+1][y] = e2[x+2][y-1]; 421// d2[x][y-1] = d2[x][y-3]; 422// e2[x][y-1] = e2[x][y-3]; 423// d2[x-1][y-1] = d2[x-1][y-3]; 424// d2[x+1][y-1] = d2[x+1][y-3]; 425// e2[x-1][y-1] = e2[x-1][y-3]; 426// e2[x+1][y-1] = e2[x+1][y-3]; 427// continue CELL_WISE; 428// } 429// } 430// 431// break; 432 case ROOM_WALL_RETRACT: 433 case ROOM_WALL_EXPAND: 434 if (x > 0 && x < nw - 1) { 435 if ((dLow == '/') && ((e2[x - 1][y - 1] & 1) + (e2[x - 1][y + 1] & 1) != 0 || (e2[x + 1][y - 1] & 1) + (e2[x + 1][y + 1] & 1) != 0)) { 436 d2[x][y] = dLow; 437 e2[x][y] = eLow; 438 d2[x][y - 1] = dHigh; 439 e2[x][y - 1] = eHigh; 440 continue CELL_WISE; 441 } else if ((dHigh == '/') && ((e2[x - 1][y - 1] & 1) + (e2[x - 1][y + 1] & 1) != 0 || (e2[x + 1][y - 1] & 1) + (e2[x + 1][y + 1] & 1) != 0)) { 442 d2[x][y] = dHigh; 443 e2[x][y] = eHigh; 444 d2[x][y + 1] = dLow; 445 e2[x][y + 1] = eLow; 446 continue CELL_WISE; 447 } 448 } 449 break; 450 case ROOM_WALL_CHAOTIC: 451 if (dLow == '/') { 452 d2[x][y - 1] = dHigh; 453 e2[x][y - 1] = eHigh; 454 if (e2[x][y] != DungeonUtility.UNTOUCHED || d2[x][y] == 0) 455 d2[x][y] = 6; 456 continue CELL_WISE; 457 } else if (dHigh == '/') { 458 d2[x][y + 1] = dLow; 459 e2[x][y + 1] = eLow; 460 if (e2[x][y] != DungeonUtility.UNTOUCHED || d2[x][y] == 0) 461 d2[x][y] = 6; 462 continue CELL_WISE; 463 } 464 break; 465 } 466 tempShapes = wallShapes; 467 468 switch (eLow) { 469 case 777: 470 d2[x][y] = '#'; 471 e2[x][y] = DungeonUtility.UNTOUCHED; 472 break; 473 case DungeonUtility.CAVE_WALL: 474 case DungeonUtility.CORRIDOR_WALL: 475 case DungeonUtility.ROOM_WALL: 476 case DungeonUtility.UNTOUCHED: 477 switch (eHigh) { 478 case DungeonUtility.CAVE_WALL: 479 case DungeonUtility.CORRIDOR_WALL: 480 case DungeonUtility.ROOM_WALL: 481 case DungeonUtility.UNTOUCHED: 482 e2[x][y] = DungeonUtility.UNTOUCHED; 483 d2[x][y] = dLow; 484 break; 485 case DungeonUtility.CAVE_FLOOR: 486 tempShapes >>= 4; 487 case DungeonUtility.CORRIDOR_FLOOR: 488 tempShapes >>= 4; 489 default: 490 switch (tempShapes & 0xF) { 491 case ROOM_WALL_CHAOTIC: 492 if (SeededNoise.noise(x * 0.666, y * 0.666, 12456789) > -0.2) { 493 e2[x][y] = eHigh; 494 d2[x][y] = dHigh; 495 } else { 496 e2[x][y] = DungeonUtility.UNTOUCHED; 497 d2[x][y] = dLow; 498 } 499 break; 500 case ROOM_WALL_RETRACT: 501 case ROOM_WALL_EXPAND: 502 e2[x][y] = DungeonUtility.UNTOUCHED; 503 d2[x][y] = dLow; 504 break; 505 506// case ROOM_WALL_RETRACT: 507// e2[x][y] = eHigh; 508// d2[x][y] = dHigh; 509// if(y > 2 && (e2[x][y-3] & 1) != 0) { // wall is thin enough 510// e2[x][y - 1] = eHigh; 511// d2[x][y - 1] = dHigh; 512// } 513// break; 514 default: 515 e2[x][y] = eLow; 516 d2[x][y] = dLow; 517 break; 518 } 519 break; 520 } 521 break; 522 case DungeonUtility.CAVE_FLOOR: 523 tempShapes >>= 4; 524 case DungeonUtility.CORRIDOR_FLOOR: 525 tempShapes >>= 4; 526 default: 527 switch (eHigh) { 528 case DungeonUtility.CAVE_WALL: 529 case DungeonUtility.CORRIDOR_WALL: 530 case DungeonUtility.ROOM_WALL: 531 case DungeonUtility.UNTOUCHED: 532 switch (tempShapes & 0xF) { 533 case ROOM_WALL_CHAOTIC: 534 if (SeededNoise.noise(x * 0.666, y * 0.666, 12456789) > -0.2) { 535 e2[x][y] = eLow; 536 d2[x][y] = dLow; 537 } else { 538 e2[x][y] = DungeonUtility.UNTOUCHED; 539 d2[x][y] = dHigh; 540 } 541 break; 542 case ROOM_WALL_RETRACT: 543 case ROOM_WALL_EXPAND: 544 e2[x][y] = DungeonUtility.UNTOUCHED; 545 d2[x][y] = dHigh; 546 break; 547 548// case ROOM_WALL_RETRACT: 549// e2[x][y] = eLow; 550// d2[x][y] = dLow; 551// /*if(y > 2 && (e2[x][y-3] & 1) != 0) { // wall is thin enough 552// e2[x][y + 1] = eLow; 553// d2[x][y + 1] = dLow; 554// } */ 555// break; 556 default: 557 e2[x][y] = eLow; 558 d2[x][y] = dLow; 559 break; 560 } 561 break; 562 case DungeonUtility.CAVE_FLOOR: 563 e2[x][y] = DungeonUtility.CAVE_FLOOR; 564 d2[x][y] = dHigh; 565 break; 566 default: 567 e2[x][y] = eHigh; 568 d2[x][y] = dHigh; 569 break; 570 } 571 break; 572 } 573 574 if (e2[x][y] != DungeonUtility.UNTOUCHED || d2[x][y] == 0) { 575 d2[x][y] = 6; 576 } 577 } 578 } 579 int currentEnv, offset; 580 char currentDun; 581 int[][] eArchive = ArrayTools.copy(e2); 582 if ((wallShapes & 0x111) != 0) // any environments are retracting 583 { 584 for (int x = 2; x < nw - 2; x += 2) { 585 for (int y = 0; y < nh - 2; y++) { 586 offset = (d2[x - 1][y] == '+') ? 1 : 2; 587 if ((eArchive[x][y] & 1) == 0 && ((currentEnv = eArchive[x - offset][y]) & 1) != 0) { 588 currentDun = d2[x - offset][y]; 589 if (currentDun == '+' || currentDun == '/') { 590 switch (currentEnv) { 591 case DungeonUtility.ROOM_FLOOR: 592 if ((wallShapes & ROOM_WALL_RETRACT) != 0) { 593 e2[x + 2 - offset][y] = currentEnv; 594 d2[x + 2 - offset][y] = currentDun; 595 e2[x + 1 - offset][y] = eArchive[x - 1 - offset][y]; 596 d2[x + 1 - offset][y] = d2[x - 1 - offset][y]; 597 e2[x - offset][y] = eArchive[x - 1 - offset][y]; 598 d2[x - offset][y] = d2[x - 1 - offset][y]; 599 } 600 break; 601 case DungeonUtility.CAVE_FLOOR: 602 if ((wallShapes & CAVE_WALL_RETRACT) != 0) { 603 604// e2[x][y] = (currentDun == '+' || currentDun == '/') ? MixedGenerator.UNTOUCHED : currentEnv; 605// d2[x][y] = (currentDun == '+' || currentDun == '/') ? '\u0005' : currentDun; 606// e2[x-1][y] = (currentDun == '+' || currentDun == '/') ? MixedGenerator.UNTOUCHED : currentEnv; 607// d2[x-1][y] = (currentDun == '+' || currentDun == '/') ? '\u0005' : 6; 608 e2[x + 2 - offset][y] = currentEnv; 609 d2[x + 2 - offset][y] = currentDun; 610 e2[x + 1 - offset][y] = eArchive[x - 1 - offset][y]; 611 d2[x + 1 - offset][y] = d2[x - 1 - offset][y]; 612 e2[x - offset][y] = eArchive[x - 1 - offset][y]; 613 d2[x - offset][y] = d2[x - 1 - offset][y]; 614 } 615 break; 616 case DungeonUtility.CORRIDOR_FLOOR: 617 if ((wallShapes & CORRIDOR_WALL_RETRACT) != 0) { 618 e2[x + 2 - offset][y] = currentEnv; 619 d2[x + 2 - offset][y] = currentDun; 620 e2[x + 1 - offset][y] = eArchive[x - 1 - offset][y]; 621 d2[x + 1 - offset][y] = d2[x - 1 - offset][y]; 622 e2[x - offset][y] = eArchive[x - 1 - offset][y]; 623 d2[x - offset][y] = d2[x - 1 - offset][y]; 624 625 } 626 break; 627 } 628 } else { 629 switch (currentEnv) { 630 case DungeonUtility.ROOM_FLOOR: 631 if ((wallShapes & ROOM_WALL_RETRACT) != 0) { 632 e2[x][y] = currentEnv; 633 d2[x][y] = currentDun; 634 e2[x - 1][y] = currentEnv; 635 d2[x - 1][y] = 6; 636 637 } 638 break; 639 case DungeonUtility.CAVE_FLOOR: 640 if ((wallShapes & CAVE_WALL_RETRACT) != 0) { 641 642// e2[x][y] = (currentDun == '+' || currentDun == '/') ? MixedGenerator.UNTOUCHED : currentEnv; 643// d2[x][y] = (currentDun == '+' || currentDun == '/') ? '\u0005' : currentDun; 644// e2[x-1][y] = (currentDun == '+' || currentDun == '/') ? MixedGenerator.UNTOUCHED : currentEnv; 645// d2[x-1][y] = (currentDun == '+' || currentDun == '/') ? '\u0005' : 6; 646 e2[x][y] = currentEnv; 647 d2[x][y] = currentDun; 648 e2[x - 1][y] = currentEnv; 649 d2[x - 1][y] = 6; 650 651 652 } 653 break; 654 case DungeonUtility.CORRIDOR_FLOOR: 655 if ((wallShapes & CORRIDOR_WALL_RETRACT) != 0) { 656 e2[x][y] = currentEnv; 657 d2[x][y] = currentDun; 658 e2[x - 1][y] = currentEnv; 659 d2[x - 1][y] = 6; 660 661 } 662 break; 663 } 664 } 665 } 666 } 667 } 668 669// for (int x = nw - 2; x > 1; x -= 2) { 670// for (int y = 0; y < nh; y++) { 671// if(((env2 = e2[x - 1][y]) & 1) == 0 && ((currentEnv = e2[x + 1][y]) & 1) != 0) { 672// currentDun = d2[x - 1][y]; 673// switch (currentEnv) { 674// case MixedGenerator.ROOM_FLOOR: 675// if ((wallShapes & ROOM_WALL_RETRACT) != 0) { 676// e2[x][y] = env2; 677// d2[x][y] = currentDun; 678// } 679// break; 680// case MixedGenerator.CAVE_FLOOR: 681// if ((wallShapes & CAVE_WALL_RETRACT) != 0) { 682// e2[x][y] = env2; 683// d2[x][y] = currentDun; 684// } 685// break; 686// case MixedGenerator.CORRIDOR_FLOOR: 687// if ((wallShapes & CORRIDOR_WALL_RETRACT) != 0) { 688// e2[x][y] = env2; 689// d2[x][y] = currentDun; 690// } 691// break; 692// } 693// } 694// } 695// } 696 697 eArchive = ArrayTools.copy(e2); 698 for (int x = 0; x < nw - 2; x++) { 699 for (int y = 2; y < nh - 2; y += 2) { 700 offset = (d2[x][y - 1] == '+') ? 1 : 2; 701 if ((eArchive[x][y] & 1) == 0 && ((currentEnv = eArchive[x][y - offset]) & 1) != 0) { 702 currentDun = d2[x][y - offset]; 703 if (currentDun == '+' || currentDun == '/') { 704 switch (currentEnv) { 705 case DungeonUtility.ROOM_FLOOR: 706 if ((wallShapes & ROOM_WALL_RETRACT) != 0) { 707 e2[x][y + 2 - offset] = currentEnv; 708 d2[x][y + 2 - offset] = currentDun; 709 e2[x][y + 1 - offset] = eArchive[x][y - 1 - offset]; 710 d2[x][y + 1 - offset] = d2[x][y - 1 - offset]; 711 e2[x][y - offset] = eArchive[x][y - 1 - offset]; 712 d2[x][y - offset] = d2[x][y - 1 - offset]; 713 } 714 break; 715 case DungeonUtility.CAVE_FLOOR: 716 if ((wallShapes & CAVE_WALL_RETRACT) != 0) { 717 e2[x][y + 2 - offset] = currentEnv; 718 d2[x][y + 2 - offset] = currentDun; 719 e2[x][y + 1 - offset] = eArchive[x][y - 1 - offset]; 720 d2[x][y + 1 - offset] = d2[x][y - 1 - offset]; 721 e2[x][y - offset] = eArchive[x][y - 1 - offset]; 722 d2[x][y - offset] = d2[x][y - 1 - offset]; 723 } 724 break; 725 case DungeonUtility.CORRIDOR_FLOOR: 726 if ((wallShapes & CORRIDOR_WALL_RETRACT) != 0) { 727 e2[x][y + 2 - offset] = currentEnv; 728 d2[x][y + 2 - offset] = currentDun; 729 e2[x][y + 1 - offset] = eArchive[x][y - 1 - offset]; 730 d2[x][y + 1 - offset] = d2[x][y - 1 - offset]; 731 e2[x][y - offset] = eArchive[x][y - 1 - offset]; 732 d2[x][y - offset] = d2[x][y - 1 - offset]; 733 } 734 break; 735 } 736 737 } else { 738 switch (currentEnv) { 739 case DungeonUtility.ROOM_FLOOR: 740 if ((wallShapes & ROOM_WALL_RETRACT) != 0) { 741 e2[x][y] = currentEnv; 742 d2[x][y] = currentDun; 743 e2[x][y - 1] = currentEnv; 744 d2[x][y - 1] = 6; 745 } 746 break; 747 case DungeonUtility.CAVE_FLOOR: 748 if ((wallShapes & CAVE_WALL_RETRACT) != 0) { 749 e2[x][y] = currentEnv; 750 d2[x][y] = currentDun; 751 e2[x][y - 1] = currentEnv; 752 d2[x][y - 1] = 6; 753 } 754 break; 755 case DungeonUtility.CORRIDOR_FLOOR: 756 if ((wallShapes & CORRIDOR_WALL_RETRACT) != 0) { 757 e2[x][y] = currentEnv; 758 d2[x][y] = currentDun; 759 e2[x][y - 1] = currentEnv; 760 d2[x][y - 1] = 6; 761 } 762 break; 763 } 764 } 765 } 766 } 767 } 768 769// for (int x = 0; x < nw; x++) { 770// for (int y = nh - 2; y > 1; y -= 2) { 771// if(((env2 = e2[x][y - 1]) & 1) == 0 && ((currentEnv = e2[x][y + 1]) & 1) != 0) { 772// currentDun = d2[x][y + 1]; 773// switch (currentEnv) { 774// case MixedGenerator.ROOM_FLOOR: 775// if ((wallShapes & ROOM_WALL_RETRACT) != 0) { 776// e2[x][y] = env2; 777// d2[x][y] = currentDun; 778// } 779// break; 780// case MixedGenerator.CAVE_FLOOR: 781// if ((wallShapes & CAVE_WALL_RETRACT) != 0) { 782// e2[x][y] = env2; 783// d2[x][y] = currentDun; 784// } 785// break; 786// case MixedGenerator.CORRIDOR_FLOOR: 787// if ((wallShapes & CORRIDOR_WALL_RETRACT) != 0) { 788// e2[x][y] = env2; 789// d2[x][y] = currentDun; 790// } 791// break; 792// } 793// } 794// } 795// } 796 } 797 798 799 for (int x = 0; x < nw; x++) { 800 for (int y = 0; y < nh; y++) { 801 if (d2[x][y] == '\u0005') { 802 e2[x][y] = DungeonUtility.UNTOUCHED; 803 d2[x][y] = '#'; 804 } 805 } 806 } 807 808 for (int x = 1; x < nw - 1; x += 2) { 809 for (int y = 1; y < nh - 1; y += 2) { 810 if (d2[x - 1][y] == '#' && d2[x + 1][y] == '#') { 811 e2[x][y] = DungeonUtility.UNTOUCHED; 812 d2[x][y] = '#'; 813 } 814 } 815 } 816 for (int x = 1; x < nw - 1; x++) { 817 for (int y = 1; y < nh - 1; y += 2) { 818 if (e2[x][y - 1] == DungeonUtility.UNTOUCHED || e2[x][y + 1] == DungeonUtility.UNTOUCHED) { 819 if (e2[x - 1][y] == DungeonUtility.UNTOUCHED) { 820 e2[x][y] = DungeonUtility.UNTOUCHED; 821 d2[x][y] = '#'; 822 } else if (e2[x + 1][y] == DungeonUtility.UNTOUCHED) { 823 e2[x][y] = DungeonUtility.UNTOUCHED; 824 d2[x][y] = '#'; 825 } 826 } 827 } 828 } 829 dungeon = d2; 830 width = nw; 831 height = nh; 832 if (stairsUp != null) { 833 stairsUp = stairsUp.multiply(2); 834 } 835 if (stairsDown != null) { 836 stairsDown = stairsDown.multiply(2); 837 } 838 finder = new RoomFinder(dungeon, e2); 839 placement = new Placement(finder); 840 return dungeon; 841 } 842 843 @Override 844 protected char[][] innerGenerate() { 845 super.innerGenerate(); 846 makeThin(); 847 return dungeon; 848 } 849 850 /** 851 * Modifies this ThinDungeonGenerator to remove corners between thin walls (truncating the corners, effectively). 852 * Regenerates the RoomFinder and Placement objects this uses. 853 */ 854 public void removeHardCorners() 855 { 856 final int[][] environment = finder.environment; 857 final int width = dungeon.length, height = dungeon[0].length; 858 for (int x = 1; x < width - 1; x += 2) { 859 for (int y = 1; y < height - 1; y += 2) { 860 if((environment[x+1][y] & 1) != (environment[x-1][y] & 1) && 861 (environment[x][y+1] & 1) != (environment[x][y-1] & 1)) { 862 dungeon[x][y] = 6; 863 } 864 } 865 } 866 finder = new RoomFinder(dungeon, environment); 867 placement = new Placement(finder); 868 869 } 870 871 /** 872 * Provides a string representation of the latest generated dungeon. 873 * Because the spaces between occupy-able cells, when walkable, use the control character U+0006 874 * to indicate that they're not meant to be displayed, this replaces any instances of that character 875 * in the printable output with ordinary space characters, while keeping the internal representation 876 * as the control character. 877 * 878 * @return a printable string version of the latest generated dungeon. 879 */ 880 @Override 881 public String toString() { 882 return super.toString().replace('\u0006', ' '); 883 } 884 885}