ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/random_maps/layout.C
(Generate patch)

Comparing deliantra/server/random_maps/layout.C (file contents):
Revision 1.6 by root, Fri Jul 2 04:05:15 2010 UTC vs.
Revision 1.7 by root, Fri Jul 2 15:03:57 2010 UTC

23 23
24#include <global.h> 24#include <global.h>
25#include <random_map.h> 25#include <random_map.h>
26#include <rproto.h> 26#include <rproto.h>
27 27
28Layout::Layout (int w, int h) 28layout::layout (int w, int h)
29: w(w), h(h) 29: w(w), h(h)
30{ 30{
31 int size = (sizeof (char *) + sizeof (char) * h) * w; 31 int size = (sizeof (char *) + sizeof (char) * h) * w;
32 32
33 col = (char **)salloc<char> (size); 33 col = (char **)salloc<char> (size);
36 36
37 for (int x = w; x--; ) 37 for (int x = w; x--; )
38 col [x] = data + x * h; 38 col [x] = data + x * h;
39} 39}
40 40
41Layout::~Layout () 41layout::~layout ()
42{ 42{
43 int size = (sizeof (char *) + sizeof (char) * h) * w; 43 int size = (sizeof (char *) + sizeof (char) * h) * w;
44 44
45 sfree ((char *)col, size); 45 sfree ((char *)col, size);
46} 46}
47 47
48void 48void
49Layout::fill (char fill) 49layout::fill (char fill)
50{ 50{
51 memset (col [0], fill, w * h); 51 memset (col [0], fill, w * h);
52} 52}
53 53
54void 54void
55Layout::rect (int x1, int y1, int x2, int y2, char fill) 55layout::rect (int x1, int y1, int x2, int y2, char fill)
56{ 56{
57 for (; x1 < x2; ++x1) 57 for (; x1 < x2; ++x1)
58 memset (col [x1] + y1, fill, y2 - y1); 58 memset (col [x1] + y1, fill, y2 - y1);
59} 59}
60 60
61void Layout::border (char fill) 61void layout::border (char fill)
62{ 62{
63 for (int i = 0; i < w; i++) col [i][0] = col [i][h - 1] = fill; 63 for (int i = 0; i < w; i++) col [i][0] = col [i][h - 1] = fill;
64 for (int j = 0; j < h; j++) col [0][j] = col [w - 1][j] = fill; 64 for (int j = 0; j < h; j++) col [0][j] = col [w - 1][j] = fill;
65} 65}
66 66
67void 67void
68Layout::fill_rand (int percent) 68layout::fill_rand (int percent)
69{ 69{
70 percent = lerp (percent, 0, 100, 0, 256); 70 percent = lerp (percent, 0, 100, 0, 256);
71 71
72 for (int x = w - 1; --x > 0; ) 72 for (int x = w - 1; --x > 0; )
73 for (int y = h - 1; --y > 0; ) 73 for (int y = h - 1; --y > 0; )
76 76
77///////////////////////////////////////////////////////////////////////////// 77/////////////////////////////////////////////////////////////////////////////
78 78
79// erode by cellular automata 79// erode by cellular automata
80void 80void
81Layout::erode_1_2 (int c1, int c2, int repeat) 81layout::erode_1_2 (int c1, int c2, int repeat)
82{ 82{
83 Layout neu (w, h); 83 layout neu (w, h);
84 84
85 while (repeat--) 85 while (repeat--)
86 { 86 {
87 for (int x = 0; x < w; ++x) 87 for (int x = 0; x < w; ++x)
88 { 88 {
122} 122}
123 123
124///////////////////////////////////////////////////////////////////////////// 124/////////////////////////////////////////////////////////////////////////////
125 125
126void 126void
127Layout::print () const 127layout::print () const
128{ 128{
129 for (int y = 0; y < h; y++) 129 for (int y = 0; y < h; y++)
130 { 130 {
131 for (int x = 0; x < w; x++) 131 for (int x = 0; x < w; x++)
132 { 132 {
152// isolation remover - ensures single connected area 152// isolation remover - ensures single connected area
153 153
154typedef fixed_stack<point> pointlist; 154typedef fixed_stack<point> pointlist;
155 155
156static noinline void 156static noinline void
157push_flood_fill (Layout &dist, pointlist &seeds, int x, int y) 157push_flood_fill (layout &dist, pointlist &seeds, int x, int y)
158{ 158{
159 if (dist [x][y]) 159 if (dist [x][y])
160 return; 160 return;
161 161
162 while (y > 0 && !dist [x][y - 1]) 162 while (y > 0 && !dist [x][y - 1])
178 if (x < dist.w - 1) push_flood_fill (dist, seeds, x + 1, y); 178 if (x < dist.w - 1) push_flood_fill (dist, seeds, x + 1, y);
179 } 179 }
180} 180}
181 181
182static inline void 182static inline void
183make_tunnel (Layout &dist, pointlist &seeds, int x, int y, U8 d) 183make_tunnel (layout &dist, pointlist &seeds, int x, int y, U8 d)
184{ 184{
185 for (;;) 185 for (;;)
186 { 186 {
187 if (x > 1 && U8 (dist [x - 1][y]) < d && dist [x - 1][y] > 1) 187 if (x > 1 && U8 (dist [x - 1][y]) < d && dist [x - 1][y] > 1)
188 --x; 188 --x;
200 seeds.push (point (x, y)); 200 seeds.push (point (x, y));
201 } 201 }
202} 202}
203 203
204static void inline 204static void inline
205maybe_push (Layout &dist, pointlist &seeds, int x, int y, U8 d) 205maybe_push (layout &dist, pointlist &seeds, int x, int y, U8 d)
206{ 206{
207 char &D = dist [x][y]; 207 char &D = dist [x][y];
208 208
209 if (U8 (D) > d) // if wall and higher distance, lower distance 209 if (U8 (D) > d) // if wall and higher distance, lower distance
210 D = d; 210 D = d;
213 213
214 seeds.push (point (x, y)); 214 seeds.push (point (x, y));
215} 215}
216 216
217void 217void
218Layout::isolation_remover (bool dirty) 218layout::isolation_remover (bool dirty)
219{ 219{
220 Layout dist (w, h); 220 layout dist (w, h);
221 221
222 // dist contains 222 // dist contains
223 // 0 == invisited rooms 223 // 0 == invisited rooms
224 // 1 == visited rooms 224 // 1 == visited rooms
225 // 2+ shortest distance to random near room 225 // 2+ shortest distance to random near room
301 301
302///////////////////////////////////////////////////////////////////////////// 302/////////////////////////////////////////////////////////////////////////////
303 303
304// inspired mostly by http://www.jimrandomh.org/misc/caves.txt 304// inspired mostly by http://www.jimrandomh.org/misc/caves.txt
305void 305void
306Layout::gen_cave (int subtype) 306layout::gen_cave (int subtype)
307{ 307{
308 switch (subtype) 308 switch (subtype)
309 { 309 {
310 // a rough cave 310 // a rough cave
311 case 0: 311 case 0:
341 341
342///////////////////////////////////////////////////////////////////////////// 342/////////////////////////////////////////////////////////////////////////////
343 343
344//+GPL 344//+GPL
345 345
346/* puts doors at appropriate locations in a layout. */ 346/* puts doors at appropriate locations in a maze. */
347void 347void
348Layout::doorify () 348layout::doorify ()
349{ 349{
350 int ndoors = w * h / 60; /* reasonable number of doors. */ 350 int ndoors = w * h / 60; /* reasonable number of doors. */
351 int doorlocs = 0; /* # of available doorlocations */ 351 int doorlocs = 0; /* # of available doorlocations */
352 352
353 uint16 *doorlist_x = salloc<uint16> (w * h); 353 uint16 *doorlist_x = salloc<uint16> (w * h);
392 392
393/* takes a map and makes it symmetric: adjusts Xsize and 393/* takes a map and makes it symmetric: adjusts Xsize and
394 * Ysize to produce a symmetric map. 394 * Ysize to produce a symmetric map.
395 */ 395 */
396void 396void
397Layout::symmetrize (int symmetry) 397layout::symmetrize (int symmetry)
398{ 398{
399 if (symmetry == SYMMETRY_NONE) 399 if (symmetry == SYMMETRY_NONE)
400 return; 400 return;
401 401
402 Layout sym_layout ( 402 layout sym_layout (
403 symmetry == SYMMETRY_X || symmetry == SYMMETRY_XY ? w * 2 - 3 : w, 403 symmetry == SYMMETRY_X || symmetry == SYMMETRY_XY ? w * 2 - 3 : w,
404 symmetry == SYMMETRY_Y || symmetry == SYMMETRY_XY ? h * 2 - 3 : h 404 symmetry == SYMMETRY_Y || symmetry == SYMMETRY_XY ? h * 2 - 3 : h
405 ); 405 );
406 406
407 if (symmetry == SYMMETRY_X) 407 if (symmetry == SYMMETRY_X)
451} 451}
452 452
453//-GPL 453//-GPL
454 454
455void 455void
456Layout::rotate (int rotation) 456layout::rotate (int rotation)
457{ 457{
458 switch (rotation & 3) 458 switch (rotation & 3)
459 { 459 {
460 case 2: /* a reflection */ 460 case 2: /* a reflection */
461 { 461 {
462 Layout new_layout (w, h); 462 layout new_layout (w, h);
463 463
464 for (int i = 0; i < w; i++) /* copy a reflection back */ 464 for (int i = 0; i < w; i++) /* copy a reflection back */
465 for (int j = 0; j < h; j++) 465 for (int j = 0; j < h; j++)
466 new_layout [i][j] = col [w - i - 1][h - j - 1]; 466 new_layout [i][j] = col [w - i - 1][h - j - 1];
467 467
470 break; 470 break;
471 471
472 case 1: 472 case 1:
473 case 3: 473 case 3:
474 { 474 {
475 Layout new_layout (h, w); 475 layout new_layout (h, w);
476 476
477 if (rotation == 1) /* swap x and y */ 477 if (rotation == 1) /* swap x and y */
478 for (int i = 0; i < w; i++) 478 for (int i = 0; i < w; i++)
479 for (int j = 0; j < h; j++) 479 for (int j = 0; j < h; j++)
480 new_layout [j][i] = col [i][j]; 480 new_layout [j][i] = col [i][j];
493///////////////////////////////////////////////////////////////////////////// 493/////////////////////////////////////////////////////////////////////////////
494 494
495//+GPL 495//+GPL
496 496
497/* 497/*
498 * Expands a layout by 2x in each dimension. 498 * Expands a maze by 2x in each dimension.
499 * H. S. Teoh 499 * H. S. Teoh
500 */ 500 */
501 501
502/* Copy the old tile X into the new one at location (i*2, j*2) and 502/* Copy the old tile X into the new one at location (i*2, j*2) and
503 * fill up the rest of the 2x2 result with \0: 503 * fill up the rest of the 2x2 result with \0:
504 * X ---> X \0 504 * X ---> X \0
505 * \0 \0 505 * \0 \0
506 */ 506 */
507static void inline 507static void inline
508expand_misc (Layout &newlayout, int i, int j, Layout &layout) 508expand_misc (layout &newlayout, int i, int j, layout &maze)
509{ 509{
510 newlayout[i * 2 + rmg_rndm (1)][j * 2 + rmg_rndm (1)] = layout[i][j]; 510 newlayout[i * 2 + rmg_rndm (1)][j * 2 + rmg_rndm (1)] = maze[i][j];
511 /* (Note: no need to reset rest of 2x2 area to \0 because calloc does that 511 /* (Note: no need to reset rest of 2x2 area to \0 because calloc does that
512 * for us.) */ 512 * for us.) */
513} 513}
514 514
515/* Returns a bitmap that represents which squares on the right and bottom 515/* Returns a bitmap that represents which squares on the right and bottom
518 * 2 match on (i, j+1) 518 * 2 match on (i, j+1)
519 * 4 match on (i+1, j+1) 519 * 4 match on (i+1, j+1)
520 * and the possible combinations thereof. 520 * and the possible combinations thereof.
521 */ 521 */
522static int noinline 522static int noinline
523calc_pattern (char ch, Layout &layout, int i, int j) 523calc_pattern (char ch, layout &maze, int i, int j)
524{ 524{
525 int pattern = 0; 525 int pattern = 0;
526 526
527 if (i + 1 < layout.w && layout[i + 1][j] == ch) 527 if (i + 1 < maze.w && maze[i + 1][j] == ch)
528 pattern |= 1; 528 pattern |= 1;
529 529
530 if (j + 1 < layout.h) 530 if (j + 1 < maze.h)
531 { 531 {
532 if (layout[i][j + 1] == ch) 532 if (maze[i][j + 1] == ch)
533 pattern |= 2; 533 pattern |= 2;
534 534
535 if (i + 1 < layout.w && layout[i + 1][j + 1] == ch) 535 if (i + 1 < maze.w && maze[i + 1][j + 1] == ch)
536 pattern |= 4; 536 pattern |= 4;
537 } 537 }
538 538
539 return pattern; 539 return pattern;
540} 540}
542/* Expand a wall. This function will try to sensibly connect the resulting 542/* Expand a wall. This function will try to sensibly connect the resulting
543 * wall to adjacent wall squares, so that the result won't have disconnected 543 * wall to adjacent wall squares, so that the result won't have disconnected
544 * walls. 544 * walls.
545 */ 545 */
546static void inline 546static void inline
547expand_wall (Layout &newlayout, int i, int j, Layout &layout) 547expand_wall (layout &newlayout, int i, int j, layout &maze)
548{ 548{
549 int wall_pattern = calc_pattern ('#', layout, i, j); 549 int wall_pattern = calc_pattern ('#', maze, i, j);
550 int door_pattern = calc_pattern ('D', layout, i, j); 550 int door_pattern = calc_pattern ('D', maze, i, j);
551 int both_pattern = wall_pattern | door_pattern; 551 int both_pattern = wall_pattern | door_pattern;
552 552
553 newlayout[i * 2][j * 2] = '#'; 553 newlayout[i * 2][j * 2] = '#';
554 554
555 if (i + 1 < layout.w) 555 if (i + 1 < maze.w)
556 { 556 {
557 if (both_pattern & 1) 557 if (both_pattern & 1)
558 { /* join walls/doors to the right */ 558 { /* join walls/doors to the right */
559/* newlayout[i*2+1][j*2] = '#'; */ 559/* newlayout[i*2+1][j*2] = '#'; */
560 newlayout[i * 2 + 1][j * 2] = layout[i + 1][j]; 560 newlayout[i * 2 + 1][j * 2] = maze[i + 1][j];
561 } 561 }
562 } 562 }
563 563
564 if (j + 1 < layout.h) 564 if (j + 1 < maze.h)
565 { 565 {
566 if (both_pattern & 2) 566 if (both_pattern & 2)
567 { /* join walls/doors to the bottom */ 567 { /* join walls/doors to the bottom */
568/* newlayout[i*2][j*2+1] = '#'; */ 568/* newlayout[i*2][j*2+1] = '#'; */
569 newlayout[i * 2][j * 2 + 1] = layout[i][j + 1]; 569 newlayout[i * 2][j * 2 + 1] = maze[i][j + 1];
570 } 570 }
571 571
572 if (wall_pattern == 7) 572 if (wall_pattern == 7)
573 { /* if orig layout is a 2x2 wall block, 573 { /* if orig maze is a 2x2 wall block,
574 * we fill the result with walls. */ 574 * we fill the result with walls. */
575 newlayout[i * 2 + 1][j * 2 + 1] = '#'; 575 newlayout[i * 2 + 1][j * 2 + 1] = '#';
576 } 576 }
577 } 577 }
578} 578}
580/* This function will try to sensibly connect doors so that they meet up with 580/* This function will try to sensibly connect doors so that they meet up with
581 * adjacent walls. Note that it will also presumptuously delete (ignore) doors 581 * adjacent walls. Note that it will also presumptuously delete (ignore) doors
582 * that it doesn't know how to correctly expand. 582 * that it doesn't know how to correctly expand.
583 */ 583 */
584static void inline 584static void inline
585expand_door (Layout &newlayout, int i, int j, Layout &layout) 585expand_door (layout &newlayout, int i, int j, layout &maze)
586{ 586{
587 int wall_pattern = calc_pattern ('#', layout, i, j); 587 int wall_pattern = calc_pattern ('#', maze, i, j);
588 int door_pattern = calc_pattern ('D', layout, i, j); 588 int door_pattern = calc_pattern ('D', maze, i, j);
589 int join_pattern; 589 int join_pattern;
590 590
591 /* Doors "like" to connect to walls more than other doors. If there is 591 /* Doors "like" to connect to walls more than other doors. If there is
592 * a wall and another door, this door will connect to the wall and 592 * a wall and another door, this door will connect to the wall and
593 * disconnect from the other door. */ 593 * disconnect from the other door. */
596 else 596 else
597 join_pattern = door_pattern; 597 join_pattern = door_pattern;
598 598
599 newlayout[i * 2][j * 2] = 'D'; 599 newlayout[i * 2][j * 2] = 'D';
600 600
601 if (i + 1 < layout.w) 601 if (i + 1 < maze.w)
602 if (join_pattern & 1) 602 if (join_pattern & 1)
603 /* there is a door/wall to the right */ 603 /* there is a door/wall to the right */
604 newlayout[i * 2 + 1][j * 2] = 'D'; 604 newlayout[i * 2 + 1][j * 2] = 'D';
605 605
606 if (j + 1 < layout.h) 606 if (j + 1 < maze.h)
607 if (join_pattern & 2) 607 if (join_pattern & 2)
608 /* there is a door/wall below */ 608 /* there is a door/wall below */
609 newlayout[i * 2][j * 2 + 1] = 'D'; 609 newlayout[i * 2][j * 2 + 1] = 'D';
610} 610}
611 611
612void 612void
613Layout::expand2x () 613layout::expand2x ()
614{ 614{
615 Layout new_layout (w * 2 - 1, h * 2 - 1); 615 layout new_layout (w * 2 - 1, h * 2 - 1);
616 616
617 new_layout.clear (); 617 new_layout.clear ();
618 618
619 for (int i = 0; i < w; i++) 619 for (int i = 0; i < w; i++)
620 for (int j = 0; j < h; j++) 620 for (int j = 0; j < h; j++)
628 swap (new_layout); 628 swap (new_layout);
629} 629}
630 630
631///////////////////////////////////////////////////////////////////////////// 631/////////////////////////////////////////////////////////////////////////////
632 632
633/* checks the layout to see if I can stick a horizontal(dir = 0) wall 633/* checks the maze to see if I can stick a horizontal(dir = 0) wall
634 (or vertical, dir == 1) 634 (or vertical, dir == 1)
635 here which ends up on other walls sensibly. */ 635 here which ends up on other walls sensibly. */
636static int 636static int
637can_make_wall (const Layout &maze, int dx, int dy, int dir) 637can_make_wall (const layout &maze, int dx, int dy, int dir)
638{ 638{
639 int i1; 639 int i1;
640 int length = 0; 640 int length = 0;
641 641
642 /* dont make walls if we're on the edge. */ 642 /* dont make walls if we're on the edge. */
729 729
730 return 0; 730 return 0;
731} 731}
732 732
733void 733void
734Layout::roomify () 734layout::roomify ()
735{ 735{
736 int tries = w * h / 30; 736 int tries = w * h / 30;
737 737
738 for (int ti = 0; ti < tries; ti++) 738 for (int ti = 0; ti < tries; ti++)
739 { 739 {
766 } 766 }
767} 767}
768 768
769///////////////////////////////////////////////////////////////////////////// 769/////////////////////////////////////////////////////////////////////////////
770 770
771/* function selects the layout function and gives it whatever 771/* function selects the maze function and gives it whatever
772 arguments it needs. */ 772 arguments it needs. */
773void 773void
774Layout::generate (random_map_params *RP) 774layout::generate (random_map_params *RP)
775{ 775{
776 switch (RP->map_layout_style) 776 switch (RP->map_layout_style)
777 { 777 {
778 case LAYOUT_ONION: 778 case LAYOUT_ONION:
779 map_gen_onion (*this, RP->layoutoptions1, RP->layoutoptions2); 779 map_gen_onion (*this, RP->layoutoptions1, RP->layoutoptions2);
838 838
839 default: 839 default:
840 abort (); 840 abort ();
841 } 841 }
842 842
843 /* rotate the layout randomly */ 843 /* rotate the maze randomly */
844 rotate (rmg_rndm (4)); 844 rotate (rmg_rndm (4));
845 845
846 symmetrize (RP->symmetry_used); 846 symmetrize (RP->symmetry_used);
847 847
848#if 0 848#if 0
862 { 862 {
863 rmg_rndm.seed (time (0)); 863 rmg_rndm.seed (time (0));
864 864
865 for(int i=1;i<10;i) 865 for(int i=1;i<10;i)
866 { 866 {
867 Layout maze (10, 10); 867 layout maze (10, 10);
868 maze.fill_rand (90); 868 maze.fill_rand (90);
869 maze.border (); 869 maze.border ();
870 maze.isolation_remover (); 870 maze.isolation_remover ();
871 maze.doorify (); 871 maze.doorify ();
872 maze.symmetrize (rmg_rndm (2, 4)); 872 maze.symmetrize (rmg_rndm (2, 4));

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines