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}