ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/random_maps/layout.C
Revision: 1.14
Committed: Sat Jul 3 02:19:10 2010 UTC (13 years, 10 months ago) by root
Content type: text/plain
Branch: MAIN
Changes since 1.13: +16 -5 lines
Log Message:
*** empty log message ***

File Contents

# Content
1 /*
2 * This file is part of Deliantra, the Roguelike Realtime MMORPG.
3 *
4 * Copyright (©) 2010 Marc Alexander Lehmann / Robin Redeker / the Deliantra team
5 * Copyright (©) Crossfire Development Team (restored, original file without copyright notice)
6 *
7 * Deliantra is free software: you can redistribute it and/or modify it under
8 * the terms of the Affero GNU General Public License as published by the
9 * Free Software Foundation, either version 3 of the License, or (at your
10 * option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the Affero GNU General Public License
18 * and the GNU General Public License along with this program. If not, see
19 * <http://www.gnu.org/licenses/>.
20 *
21 * The authors can be reached via e-mail to <support@deliantra.net>
22 */
23
24 #include <global.h>
25 #include <random_map.h>
26 #include <rproto.h>
27
28 void
29 layout::alloc (int w, int h)
30 {
31 assert (sizeof (cell) == 1);
32
33 this->w = w;
34 this->h = h;
35
36 // we store the layout in a single contiguous memory layout
37 // first part consists of pointers to each column, followed
38 // by the actual columns (not rows!)
39 size = (sizeof (cell *) + sizeof (cell) * h) * w;
40 data = (cell **)salloc<char> (size);
41
42 cell *p = (cell *)(data + w);
43
44 for (int x = 0; x < w; ++x)
45 data [x] = p + x * h;
46 }
47
48 layout::layout (int w, int h)
49 {
50 alloc (w, h);
51 }
52
53 layout::layout (layout &copy)
54 {
55 alloc (copy.w, copy.h);
56
57 memcpy (data [0], copy.data [0], sizeof (cell) * h * w);
58 }
59
60 layout::layout (layout &orig, int x1, int y1, int x2, int y2)
61 {
62 w = x2 - x1;
63 h = y2 - y1;
64
65 // we only allocate space for the pointers
66 size = sizeof (cell *) * w;
67 data = (cell **)salloc<char> (size);
68
69 // and now we point back into the original layout
70 for (int x = 0; x < w; ++x)
71 data [x] = orig.data [x + x1] + y1;
72 }
73
74 layout::~layout ()
75 {
76 sfree ((char *)data, size);
77 }
78
79 void
80 layout::fill (char fill)
81 {
82 memset (data [0], fill, w * h);
83 }
84
85 void
86 layout::rect (int x1, int y1, int x2, int y2, char fill)
87 {
88 --x2;
89
90 memset (data [x1] + y1, fill, y2 - y1);
91 memset (data [x2] + y1, fill, y2 - y1);
92
93 while (++x1 < x2)
94 data [x1][y1] = data [x1][y2 - 1] = fill;
95 }
96
97 void
98 layout::fill_rect (int x1, int y1, int x2, int y2, char fill)
99 {
100 for (; x1 < x2; ++x1)
101 memset (data [x1] + y1, fill, y2 - y1);
102 }
103
104 void layout::border (char fill)
105 {
106 rect (0, 0, w, h, fill);
107 }
108
109 void
110 layout::fill_rand (int percent)
111 {
112 percent = lerp (percent, 0, 100, 0, 256);
113
114 for (int x = w - 1; --x > 0; )
115 for (int y = h - 1; --y > 0; )
116 data [x][y] = rmg_rndm (256) > percent ? 0 : '#';
117 }
118
119 /////////////////////////////////////////////////////////////////////////////
120
121 // erode by cellular automata
122 void
123 layout::erode_1_2 (int c1, int c2, int repeat)
124 {
125 layout neu (w, h);
126
127 while (repeat--)
128 {
129 for (int x = 0; x < w; ++x)
130 {
131 coroapi::cede_to_tick ();
132
133 for (int y = 0; y < h; ++y)
134 {
135 int n1 = 0, n2 = 0;
136
137 // a 5x5 area, dx, dy, distance (1 == <= 1, 0 <= 2)
138 static I8 dds[][3] = {
139 { -2, -1, 0 }, { -2, 0, 0 }, { -2, 1, 0 },
140 { -1, -2, 0 }, { -1, -1, 1 }, { -1, 0, 1 }, { -1, 1, 1 }, { -1, 2, 0 },
141 { 0, -2, 0 }, { 0, -1, 1 }, { 0, 0, 1 }, { 0, 1, 1 }, { 0, 2, 0 },
142 { 1, -2, 0 }, { 1, -1, 1 }, { 1, 0, 1 }, { 1, 1, 1 }, { 1, 2, 0 },
143 { 2, -1, 0 }, { 2, 0, 0 }, { 2, 1, 0 },
144 };
145
146 for (int i = array_length (dds); i--; )
147 {
148 int nx = x + dds [i][0];
149 int ny = y + dds [i][1];
150
151 if (!IN_RANGE_EXC (nx, 0, w) || !IN_RANGE_EXC (ny, 0, h) || !data [nx][ny])
152 {
153 n1 += dds [i][2];
154 n2++;
155 }
156 }
157
158 neu [x][y] = n1 >= c1 || n2 <= c2 ? '#' : 0;
159 }
160 }
161
162 swap (neu);
163 }
164 }
165
166 /////////////////////////////////////////////////////////////////////////////
167
168 void
169 layout::print () const
170 {
171 for (int y = 0; y < h; y++)
172 {
173 for (int x = 0; x < w; x++)
174 {
175 U8 c = (U8)data [x][y];
176
177 if (!c)
178 c = ' ';
179 else if (c < 10)
180 c += '0';
181 else if (c < 32)
182 c += 'a' - 10;
183
184 putc ((char)c, stdout);
185 }
186
187 putc ('\n', stdout);
188 }
189
190 putc ('\n', stdout);
191 }
192
193 /////////////////////////////////////////////////////////////////////////////
194 // isolation remover - ensures single connected area
195
196 typedef fixed_stack<point> pointlist;
197
198 static void noinline
199 push_flood_fill (layout &dist, pointlist &seeds, int x, int y)
200 {
201 if (dist [x][y])
202 return;
203
204 while (y > 0 && !dist [x][y - 1])
205 --y;
206
207 int y0 = y;
208
209 while (y < dist.h && !dist [x][y])
210 {
211 seeds.push (point (x, y));
212
213 dist [x][y] = 1;
214 ++y;
215 }
216
217 while (--y >= y0)
218 {
219 if (x > 0 && !dist [x - 1][y]) push_flood_fill (dist, seeds, x - 1, y);
220 if (x < dist.w - 1 && !dist [x + 1][y]) push_flood_fill (dist, seeds, x + 1, y);
221 }
222 }
223
224 static inline void
225 make_tunnel (layout &dist, pointlist &seeds, int x, int y, U8 d)
226 {
227 for (;;)
228 {
229 point neigh[4];
230 int ncnt = 0;
231
232 if (x > 0 && U8 (dist [x - 1][y]) <= d && dist [x - 1][y] > 1) neigh [ncnt++] = point (x - 1, y);
233 if (x < dist.w - 1 && U8 (dist [x + 1][y]) <= d && dist [x + 1][y] > 1) neigh [ncnt++] = point (x + 1, y);
234 if (y > 0 && U8 (dist [x][y - 1]) <= d && dist [x][y - 1] > 1) neigh [ncnt++] = point (x, y - 1);
235 if (y < dist.h - 1 && U8 (dist [x][y + 1]) <= d && dist [x][y + 1] > 1) neigh [ncnt++] = point (x, y + 1);
236
237 if (!ncnt)
238 return;
239
240 point &p = neigh [rmg_rndm (ncnt)];
241
242 seeds.push (p);
243
244 x = p.x;
245 y = p.y;
246
247 d = dist [x][y];
248 dist [x][y] = 1;
249 }
250 }
251
252 static void inline
253 maybe_push (layout &dist, pointlist &seeds, int x, int y, U8 d)
254 {
255 char &D = dist [x][y];
256
257 if (U8 (D) > d) // if wall and higher distance, lower distance
258 D = d;
259 else if (D) // otherwise, if it's no room, this space is uninteresting
260 return;
261
262 seeds.push (point (x, y));
263 }
264
265 // isolation remover, works on a "distance" map
266 // the map must be initialised with 0 == rooms, 255 = walls
267 static void noinline
268 isolation_remover (layout &dist)
269 {
270 // dist contains
271 // 0 == invisited rooms
272 // 1 == visited rooms
273 // 2+ shortest distance to random near room
274
275 // phase 1, find seed
276 int cnt = 0;
277 int x, y;
278
279 for (int i = 0; i < dist.w; ++i)
280 for (int j = 0; j < dist.h; ++j)
281 if (!dist [i][j] && !rmg_rndm (++cnt))
282 x = i, y = j;
283
284 if (!cnt)
285 {
286 // map is completely massive, this is not good,
287 // so make it empty instead.
288 dist.fill (1);
289 return;
290 }
291
292 fixed_stack<point> seeds (dist.w * dist.h * 5);
293
294 // found first free space - picking the first one gives
295 // us a slight bias for tunnels, but usually you won't
296 // notice that in-game
297 seeds.push (point (x, y));
298
299 // phase 2, while we have seeds, if
300 // seed is empty, floodfill, else grow
301
302 while (seeds.size)
303 {
304 coroapi::cede_to_tick ();
305
306 point p = seeds.remove (rmg_rndm (seeds.size));
307
308 x = p.x;
309 y = p.y;
310
311 if (!dist [x][y])
312 {
313 // found new isolated area, make tunnel
314 push_flood_fill (dist, seeds, x, y);
315 make_tunnel (dist, seeds, x, y, 255);
316 }
317 else
318 {
319 // nothing here, continue to expand
320 U8 d = U8 (dist [x][y]) + 1;
321
322 if (x < dist.w - 1) maybe_push (dist, seeds, x + 1, y, d);
323 if (x > 0) maybe_push (dist, seeds, x - 1, y, d);
324 if (y < dist.h - 1) maybe_push (dist, seeds, x, y + 1, d);
325 if (y > 0) maybe_push (dist, seeds, x, y - 1, d);
326 }
327 }
328 }
329
330 void
331 layout::isolation_remover ()
332 {
333 layout dist (w - 2, h - 2); // map without border
334
335 for (int x = 1; x < w - 1; ++x)
336 for (int y = 1; y < h - 1; ++y)
337 dist [x - 1][y - 1] = data [x][y] == '#' ? U8 (255) : 0;
338
339 ::isolation_remover (dist);
340
341 // now copy the tunnels over
342 for (int x = 1; x < w - 1; ++x)
343 for (int y = 1; y < h - 1; ++y)
344 if (data [x][y] == '#' && dist [x - 1][y - 1] == 1)
345 data [x][y] = 0;
346 }
347
348 /////////////////////////////////////////////////////////////////////////////
349
350 // inspired mostly by http://www.jimrandomh.org/misc/caves.txt
351 void
352 layout::gen_cave (int subtype)
353 {
354 switch (subtype)
355 {
356 // a rough cave
357 case 0:
358 fill_rand (rmg_rndm (85, 97));
359 break;
360
361 // corridors
362 case 1:
363 fill_rand (rmg_rndm (5, 40));
364 erode_1_2 (5, 2, 10);
365 erode_1_2 (5, -1, 10);
366 erode_1_2 (5, 2, 1);
367 break;
368
369 // somewhat open, roundish
370 case 2:
371 fill_rand (45);
372 erode_1_2 (5, 0, 5);
373 erode_1_2 (5, 1, 1);
374 break;
375
376 // wide open, some room-like structures
377 case 3:
378 fill_rand (45);
379 erode_1_2 (5, 2, 4);
380 erode_1_2 (5, -1, 3);
381 break;
382 }
383
384 border ();
385 isolation_remover ();
386 }
387
388 /////////////////////////////////////////////////////////////////////////////
389
390 //+GPL
391
392 /* puts doors at appropriate locations in a maze. */
393 void
394 layout::doorify ()
395 {
396 int ndoors = w * h / 60; /* reasonable number of doors. */
397 int doorlocs = 0; /* # of available doorlocations */
398
399 uint16 *doorlist_x = salloc<uint16> (w * h);
400 uint16 *doorlist_y = salloc<uint16> (w * h);
401
402 /* make a list of possible door locations */
403 for (int i = 1; i < w - 1; i++)
404 for (int j = 1; j < h - 1; j++)
405 {
406 int sindex = surround_flag (*this, i, j);
407
408 if (sindex == 3 || sindex == 12) /* these are possible door sindex */
409 {
410 doorlist_x [doorlocs] = i;
411 doorlist_y [doorlocs] = j;
412 doorlocs++;
413 }
414 }
415
416 while (ndoors > 0 && doorlocs > 0)
417 {
418 int di = rmg_rndm (doorlocs);
419 int i = doorlist_x [di];
420 int j = doorlist_y [di];
421 int sindex = surround_flag (*this, i, j);
422
423 if (sindex == 3 || sindex == 12) /* these are possible door sindex */
424 {
425 data [i][j] = 'D';
426 ndoors--;
427 }
428
429 /* reduce the size of the list */
430 doorlocs--;
431 doorlist_x[di] = doorlist_x [doorlocs];
432 doorlist_y[di] = doorlist_y [doorlocs];
433 }
434
435 sfree (doorlist_x, w * h);
436 sfree (doorlist_y, w * h);
437 }
438
439 /* takes a map and makes it symmetric: adjusts Xsize and
440 * Ysize to produce a symmetric map.
441 */
442 void
443 layout::symmetrize (int symmetry)
444 {
445 if (symmetry == SYMMETRY_NONE)
446 return;
447
448 layout sym_layout (
449 symmetry == SYMMETRY_X || symmetry == SYMMETRY_XY ? w * 2 - 3 : w,
450 symmetry == SYMMETRY_Y || symmetry == SYMMETRY_XY ? h * 2 - 3 : h
451 );
452
453 if (symmetry == SYMMETRY_X)
454 for (int i = 0; i < sym_layout.w / 2 + 1; i++)
455 for (int j = 0; j < sym_layout.h; j++)
456 {
457 sym_layout[i ][j] =
458 sym_layout[sym_layout.w - i - 1][j] = data [i][j];
459 }
460
461 if (symmetry == SYMMETRY_Y)
462 for (int i = 0; i < sym_layout.w; i++)
463 for (int j = 0; j < sym_layout.h / 2 + 1; j++)
464 {
465 sym_layout[i][j ] =
466 sym_layout[i][sym_layout.h - j - 1] = data [i][j];
467 }
468
469 if (symmetry == SYMMETRY_XY)
470 for (int i = 0; i < sym_layout.w / 2 + 1; i++)
471 for (int j = 0; j < sym_layout.h / 2 + 1; j++)
472 {
473 sym_layout[i ][j ] =
474 sym_layout[i ][sym_layout.h - j - 1] =
475 sym_layout[sym_layout.w - i - 1][j ] =
476 sym_layout[sym_layout.w - i - 1][sym_layout.h - j - 1] = data [i][j];
477 }
478
479 /* need to run the isolation remover for some layouts */
480 #if 0
481 switch (RP->map_layout_style)
482 {
483 case LAYOUT_ONION:
484 case LAYOUT_SNAKE:
485 case LAYOUT_SQUARE_SPIRAL:
486 // safe
487 break;
488
489 default:
490 sym_layout.isolation_remover ();
491 break;
492 }
493 #endif
494 sym_layout.isolation_remover ();
495
496 swap (sym_layout);
497 }
498
499 //-GPL
500
501 void
502 layout::rotate (int rotation)
503 {
504 switch (rotation & 3)
505 {
506 case 2: /* a reflection */
507 {
508 layout new_layout (w, h);
509
510 for (int i = 0; i < w; i++) /* copy a reflection back */
511 for (int j = 0; j < h; j++)
512 new_layout [i][j] = data [w - i - 1][h - j - 1];
513
514 swap (new_layout);
515 }
516 break;
517
518 case 1:
519 case 3:
520 {
521 layout new_layout (h, w);
522
523 if (rotation == 1) /* swap x and y */
524 for (int i = 0; i < w; i++)
525 for (int j = 0; j < h; j++)
526 new_layout [j][i] = data [i][j];
527
528 if (rotation == 3) /* swap x and y */
529 for (int i = 0; i < w; i++)
530 for (int j = 0; j < h; j++)
531 new_layout [j][i] = data [w - i - 1][h - j - 1];
532
533 swap (new_layout);
534 }
535 break;
536 }
537 }
538
539 /////////////////////////////////////////////////////////////////////////////
540
541 //+GPL
542
543 /*
544 * Expands a maze by 2x in each dimension.
545 * H. S. Teoh
546 */
547
548 /* Copy the old tile X into the new one at location (i*2, j*2) and
549 * fill up the rest of the 2x2 result with \0:
550 * X ---> X \0
551 * \0 \0
552 */
553 static void inline
554 expand_misc (layout &newlayout, int i, int j, layout &maze)
555 {
556 newlayout[i * 2 + rmg_rndm (1)][j * 2 + rmg_rndm (1)] = maze[i][j];
557 /* (Note: no need to reset rest of 2x2 area to \0 because calloc does that
558 * for us.) */
559 }
560
561 /* Returns a bitmap that represents which squares on the right and bottom
562 * edges of a square (i,j) match the given character:
563 * 1 match on (i+1, j)
564 * 2 match on (i, j+1)
565 * 4 match on (i+1, j+1)
566 * and the possible combinations thereof.
567 */
568 static int noinline
569 calc_pattern (char ch, layout &maze, int i, int j)
570 {
571 int pattern = 0;
572
573 if (i + 1 < maze.w && maze[i + 1][j] == ch)
574 pattern |= 1;
575
576 if (j + 1 < maze.h)
577 {
578 if (maze[i][j + 1] == ch)
579 pattern |= 2;
580
581 if (i + 1 < maze.w && maze[i + 1][j + 1] == ch)
582 pattern |= 4;
583 }
584
585 return pattern;
586 }
587
588 /* Expand a wall. This function will try to sensibly connect the resulting
589 * wall to adjacent wall squares, so that the result won't have disconnected
590 * walls.
591 */
592 static void inline
593 expand_wall (layout &newlayout, int i, int j, layout &maze)
594 {
595 int wall_pattern = calc_pattern ('#', maze, i, j);
596 int door_pattern = calc_pattern ('D', maze, i, j);
597 int both_pattern = wall_pattern | door_pattern;
598
599 newlayout[i * 2][j * 2] = '#';
600
601 if (i + 1 < maze.w)
602 {
603 if (both_pattern & 1)
604 { /* join walls/doors to the right */
605 /* newlayout[i*2+1][j*2] = '#'; */
606 newlayout[i * 2 + 1][j * 2] = maze[i + 1][j];
607 }
608 }
609
610 if (j + 1 < maze.h)
611 {
612 if (both_pattern & 2)
613 { /* join walls/doors to the bottom */
614 /* newlayout[i*2][j*2+1] = '#'; */
615 newlayout[i * 2][j * 2 + 1] = maze[i][j + 1];
616 }
617
618 if (wall_pattern == 7)
619 { /* if orig maze is a 2x2 wall block,
620 * we fill the result with walls. */
621 newlayout[i * 2 + 1][j * 2 + 1] = '#';
622 }
623 }
624 }
625
626 /* This function will try to sensibly connect doors so that they meet up with
627 * adjacent walls. Note that it will also presumptuously delete (ignore) doors
628 * that it doesn't know how to correctly expand.
629 */
630 static void inline
631 expand_door (layout &newlayout, int i, int j, layout &maze)
632 {
633 int wall_pattern = calc_pattern ('#', maze, i, j);
634 int door_pattern = calc_pattern ('D', maze, i, j);
635 int join_pattern;
636
637 /* Doors "like" to connect to walls more than other doors. If there is
638 * a wall and another door, this door will connect to the wall and
639 * disconnect from the other door. */
640 if (wall_pattern & 3)
641 join_pattern = wall_pattern;
642 else
643 join_pattern = door_pattern;
644
645 newlayout[i * 2][j * 2] = 'D';
646
647 if (i + 1 < maze.w)
648 if (join_pattern & 1)
649 /* there is a door/wall to the right */
650 newlayout[i * 2 + 1][j * 2] = 'D';
651
652 if (j + 1 < maze.h)
653 if (join_pattern & 2)
654 /* there is a door/wall below */
655 newlayout[i * 2][j * 2 + 1] = 'D';
656 }
657
658 void
659 layout::expand2x ()
660 {
661 layout new_layout (w * 2 - 1, h * 2 - 1);
662
663 new_layout.clear ();
664
665 for (int i = 0; i < w; i++)
666 for (int j = 0; j < h; j++)
667 switch (data [i][j])
668 {
669 case '#': expand_wall (new_layout, i, j, *this); break;
670 case 'D': expand_door (new_layout, i, j, *this); break;
671 default: expand_misc (new_layout, i, j, *this); break;
672 }
673
674 swap (new_layout);
675 }
676
677 /////////////////////////////////////////////////////////////////////////////
678
679 /* checks the maze to see if I can stick a horizontal(dir = 0) wall
680 (or vertical, dir == 1)
681 here which ends up on other walls sensibly. */
682 static int
683 can_make_wall (const layout &maze, int dx, int dy, int dir)
684 {
685 int i1;
686 int length = 0;
687
688 /* dont make walls if we're on the edge. */
689 if (dx == 0 || dx == (maze.w - 1) || dy == 0 || dy == (maze.h - 1))
690 return -1;
691
692 /* don't make walls if we're ON a wall. */
693 if (maze [dx][dy] != 0)
694 return -1;
695
696 if (dir == 0) /* horizontal */
697 {
698 int y = dy;
699
700 for (i1 = dx - 1; i1 > 0; i1--)
701 {
702 int sindex = surround_flag2 (maze, i1, y);
703
704 if (sindex == 1) break;
705 if (sindex != 0) return -1; /* can't make horiz. wall here */
706 if (maze[i1][y] != 0) return -1; /* can't make horiz. wall here */
707
708 length++;
709 }
710
711 for (i1 = dx + 1; i1 < maze.w - 1; i1++)
712 {
713 int sindex = surround_flag2 (maze, i1, y);
714
715 if (sindex == 2) break;
716 if (sindex != 0) return -1; /* can't make horiz. wall here */
717 if (maze[i1][y] != 0) return -1; /* can't make horiz. wall here */
718
719 length++;
720 }
721 return length;
722 }
723 else
724 { /* vertical */
725 int x = dx;
726
727 for (i1 = dy - 1; i1 > 0; i1--)
728 {
729 int sindex = surround_flag2 (maze, x, i1);
730
731 if (sindex == 4) break;
732 if (sindex != 0) return -1; /* can't make vert. wall here */
733 if (maze[x][i1] != 0) return -1; /* can't make horiz. wall here */
734
735 length++;
736 }
737
738 for (i1 = dy + 1; i1 < maze.h - 1; i1++)
739 {
740 int sindex = surround_flag2 (maze, x, i1);
741
742 if (sindex == 8) break;
743 if (sindex != 0) return -1; /* can't make verti. wall here */
744 if (maze[x][i1] != 0) return -1; /* can't make horiz. wall here */
745
746 length++;
747 }
748
749 return length;
750 }
751
752 return -1;
753 }
754
755 int
756 make_wall (char **maze, int x, int y, int dir)
757 {
758 maze[x][y] = 'D'; /* mark a door */
759
760 switch (dir)
761 {
762 case 0: /* horizontal */
763 {
764 for (int i1 = x - 1; maze[i1][y] == 0; --i1) maze[i1][y] = '#';
765 for (int i1 = x + 1; maze[i1][y] == 0; ++i1) maze[i1][y] = '#';
766 break;
767 }
768 case 1: /* vertical */
769 {
770 for (int i1 = y - 1; maze[x][i1] == 0; --i1) maze[x][i1] = '#';
771 for (int i1 = y + 1; maze[x][i1] == 0; ++i1) maze[x][i1] = '#';
772 break;
773 }
774 }
775
776 return 0;
777 }
778
779 void
780 layout::roomify ()
781 {
782 int tries = w * h / 30;
783
784 for (int ti = 0; ti < tries; ti++)
785 {
786 /* starting location for looking at creating a door */
787 int dx = rmg_rndm (w);
788 int dy = rmg_rndm (h);
789
790 /* results of checking on creating walls. */
791 int cx = can_make_wall (*this, dx, dy, 0); /* horizontal */
792 int cy = can_make_wall (*this, dx, dy, 1); /* vertical */
793
794 if (cx == -1)
795 {
796 if (cy != -1)
797 make_wall (*this, dx, dy, 1);
798
799 continue;
800 }
801
802 if (cy == -1)
803 {
804 make_wall (*this, dx, dy, 0);
805 continue;
806 }
807
808 if (cx < cy)
809 make_wall (*this, dx, dy, 0);
810 else
811 make_wall (*this, dx, dy, 1);
812 }
813 }
814
815 /////////////////////////////////////////////////////////////////////////////
816
817 /* function selects the maze function and gives it whatever
818 arguments it needs. */
819 void
820 layout::generate (random_map_params *RP)
821 {
822 switch (RP->map_layout_style)
823 {
824 case LAYOUT_ONION:
825 map_gen_onion (*this, RP->layoutoptions1, RP->layoutoptions2);
826
827 if (!(rmg_rndm (3)) && !(RP->layoutoptions1 & (RMOPT_WALLS_ONLY | RMOPT_WALL_OFF)))
828 roomify ();
829
830 break;
831
832 case LAYOUT_MAZE:
833 maze_gen (*this, RP->get_iv ("maze_type", rmg_rndm (4)));
834
835 if (rmg_rndm (2))
836 doorify ();
837
838 break;
839
840 case LAYOUT_SPIRAL:
841 map_gen_spiral (*this, RP->layoutoptions1);
842
843 if (rmg_rndm (2))
844 doorify ();
845
846 break;
847
848 case LAYOUT_ROGUELIKE:
849 /* Don't put symmetry in rogue maps. There isn't much reason to
850 * do so in the first place (doesn't make it any more interesting),
851 * but more importantly, the symmetry code presumes we are symmetrizing
852 * spirals, or maps with lots of passages - making a symmetric rogue
853 * map fails because its likely that the passages the symmetry process
854 * creates may not connect the rooms.
855 */
856 RP->symmetry_used = SYMMETRY_NONE;
857 roguelike_layout_gen (*this, RP->layoutoptions1);
858 /* no doorifying... done already */
859 break;
860
861 case LAYOUT_SNAKE:
862 make_snake_layout (*this, RP->layoutoptions1);
863
864 if (rmg_rndm (2))
865 roomify ();
866
867 break;
868
869 case LAYOUT_SQUARE_SPIRAL:
870 make_square_spiral_layout (*this, RP->layoutoptions1);
871
872 if (rmg_rndm (2))
873 roomify ();
874
875 break;
876
877 case LAYOUT_CAVE:
878 gen_cave (RP->get_iv ("cave_type", rmg_rndm (4)));
879
880 if (rmg_rndm (2))
881 doorify ();
882
883 break;
884
885 default:
886 abort ();
887 }
888
889 /* rotate the maze randomly */
890 rotate (rmg_rndm (4));
891
892 symmetrize (RP->symmetry_used);
893
894 #if 0
895 print ();//D
896 #endif
897
898 if (RP->expand2x)
899 expand2x ();
900 }
901
902 //-GPL
903
904 #if 0
905 static struct demo
906 {
907 demo ()
908 {
909 rmg_rndm.seed (time (0));
910
911 for(int i=1;i<100;i++)
912 {
913 layout maze (40, 25);
914 maze.fill_rand (85);
915 maze.border ();
916 maze.isolation_remover ();
917 maze.print ();
918 }
919
920 exit (1);
921 }
922 } demo;
923 #endif