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

Comparing deliantra/server/random_maps/maze_gen.C (file contents):
Revision 1.16 by root, Sat Nov 7 18:32:45 2009 UTC vs.
Revision 1.27 by root, Sat Apr 23 04:56:52 2011 UTC

1/* 1/*
2 * This file is part of Deliantra, the Roguelike Realtime MMORPG. 2 * This file is part of Deliantra, the Roguelike Realtime MMORPG.
3 * 3 *
4 * Copyright (©) 2005,2006,2007,2008,2009 Marc Alexander Lehmann / Robin Redeker / the Deliantra team 4 * Copyright (©) 2005,2006,2007,2008,2009,2010,2011 Marc Alexander Lehmann / Robin Redeker / the Deliantra team
5 * Copyright (©) Crossfire Development Team (restored, original file without copyright notice) 5 * Copyright (©) 1994-2004 Crossfire Development Team (restored, original file without copyright notice)
6 * 6 *
7 * Deliantra is free software: you can redistribute it and/or modify it under 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 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 9 * Free Software Foundation, either version 3 of the License, or (at your
10 * option) any later version. 10 * option) any later version.
35 35
36/* we need to maintain a list of wall points to generate 36/* we need to maintain a list of wall points to generate
37 reasonable mazes: a straightforward recursive random walk maze 37 reasonable mazes: a straightforward recursive random walk maze
38 generator would generate a map with a trivial circle-the-outer-wall solution */ 38 generator would generate a map with a trivial circle-the-outer-wall solution */
39 39
40#include <vector>
41
40#include <global.h> 42#include <global.h>
41 43
42#include "random_map.h" 44#include <rmg.h>
43#include "rproto.h" 45#include "rproto.h"
44 46
45/* global variables that everyone needs: don't want to pass them in 47/* global variables that everyone needs: don't want to pass them in
46 as parameters every time. */ 48 as parameters every time. */
47static int *wall_x_list = 0; 49static fixed_stack<point> seeds;
48static int *wall_y_list = 0; 50static int xsize, ysize;
49static int wall_free_size = 0; 51static char **maze;
52
53static void
54push (point p)
55{
56 seeds.push (p);
57 maze [p.x][p.y] = '#';
58}
59
60/* randomly returns one of the elements from the wall point list */
61static point
62pop_rand ()
63{
64 return seeds.remove (rmg_rndm (seeds.size));
65}
50 66
51/* the free wall points are those outer points which aren't corners or 67/* the free wall points are those outer points which aren't corners or
52 near corners, and don't have a maze wall growing out of them already. */ 68 near corners, and don't have a maze wall growing out of them already. */
53static void 69static void
54make_wall_free_list (int xsize, int ysize) 70push_walls ()
55{ 71{
56 int i, j, count;
57
58 count = 0; /* entries already placed in the free list */
59 /*allocate it */
60 if (wall_free_size < 0)
61 return;
62
63 wall_x_list = (int *)calloc (sizeof (int), wall_free_size);
64 wall_y_list = (int *)calloc (sizeof (int), wall_free_size);
65
66 /* top and bottom wall */ 72 /* top and bottom wall */
67 for (i = 2; i < xsize - 2; i++) 73 for (int x = 2; x < xsize - 2; x++)
68 { 74 {
69 wall_x_list[count] = i; 75 push (point (x, 0));
70 wall_y_list[count] = 0; 76 push (point (x, ysize - 1));
71 count++;
72 wall_x_list[count] = i;
73 wall_y_list[count] = ysize - 1;
74 count++;
75 } 77 }
76 78
77 /* left and right wall */ 79 /* left and right wall */
78 for (j = 2; j < ysize - 2; j++) 80 for (int y = 2; y < ysize - 2; y++)
79 {
80 wall_x_list[count] = 0;
81 wall_y_list[count] = j;
82 count++;
83 wall_x_list[count] = xsize - 1;
84 wall_y_list[count] = j;
85 count++;
86 } 81 {
87} 82 push (point ( 0, y));
88 83 push (point (xsize - 1, y));
89/* randomly returns one of the elements from the wall point list */ 84 }
90static void
91pop_wall_point (int *x, int *y)
92{
93 int index = rmg_rndm (wall_free_size);
94
95 *x = wall_x_list[index];
96 *y = wall_y_list[index];
97 /* write the last array point here */
98 wall_x_list[index] = wall_x_list[wall_free_size - 1];
99 wall_y_list[index] = wall_y_list[wall_free_size - 1];
100 wall_free_size--;
101} 85}
102 86
103/* find free point: randomly look for a square adjacent to this one where 87/* find free point: randomly look for a square adjacent to this one where
104we can place a new block without closing a path. We may only look 88we can place a new block without closing a path. We may only look
105up, down, right, or left. */ 89up, down, right, or left. */
106static int 90static int
107find_free_point (char **maze, int *x, int *y, int xc, int yc, int xsize, int ysize) 91find_free_point (point &p, point pc)
108{ 92{
109 /* we will randomly pick from this list, 1=up,2=down,3=right,4=left */ 93 /* we will randomly pick from this list, 1=up,2=down,3=right,4=left */
110 int dirlist[4]; 94 int dirlist[4];
111 int count = 0; /* # elements in dirlist */ 95 int count = 0; /* # elements in dirlist */
112 96
97 int xc = pc.x;
98 int yc = pc.y;
99
113 /* look up */ 100 /* look up */
114 if (yc < ysize - 2 && xc > 2 && xc < xsize - 2) /* it is valid to look up */ 101 if (yc < ysize - 2 && xc > 2 && xc < xsize - 2) /* it is valid to look up */
115 { 102 {
116 int cleartest = (int) maze[xc][yc + 1] + (int) maze[xc - 1][yc + 1] + (int) maze[xc + 1][yc + 1]; 103 int cleartest = maze[xc][yc + 1] + maze[xc - 1][yc + 1] + maze[xc + 1][yc + 1]
117
118 cleartest += (int) maze[xc][yc + 2] + (int) maze[xc - 1][yc + 2] + (int) maze[xc + 1][yc + 2]; 104 + maze[xc][yc + 2] + maze[xc - 1][yc + 2] + maze[xc + 1][yc + 2];
119 105
120 if (cleartest == 0) 106 if (cleartest == 0)
121 dirlist[count++] = 1; 107 dirlist[count++] = 1;
122 } 108 }
123 109
124 /* look down */ 110 /* look down */
125 if (yc > 2 && xc > 2 && xc < xsize - 2) /* it is valid to look down */ 111 if (yc > 2 && xc > 2 && xc < xsize - 2) /* it is valid to look down */
126 { 112 {
127 int cleartest = (int) maze[xc][yc - 1] + (int) maze[xc - 1][yc - 1] + (int) maze[xc + 1][yc - 1]; 113 int cleartest = maze[xc][yc - 1] + maze[xc - 1][yc - 1] + maze[xc + 1][yc - 1]
128
129 cleartest += (int) maze[xc][yc - 2] + (int) maze[xc - 1][yc - 2] + (int) maze[xc + 1][yc - 2]; 114 + maze[xc][yc - 2] + maze[xc - 1][yc - 2] + maze[xc + 1][yc - 2];
130 115
131 if (cleartest == 0) 116 if (cleartest == 0)
132 dirlist[count++] = 2; 117 dirlist[count++] = 2;
133 } 118 }
134 119
135 /* look right */ 120 /* look right */
136 if (xc < xsize - 2 && yc > 2 && yc < ysize - 2) /* it is valid to look left */ 121 if (xc < xsize - 2 && yc > 2 && yc < ysize - 2) /* it is valid to look left */
137 { 122 {
138 int cleartest = (int) maze[xc + 1][yc] + (int) maze[xc + 1][yc - 1] + (int) maze[xc + 1][yc + 1]; 123 int cleartest = maze[xc + 1][yc] + maze[xc + 1][yc - 1] + maze[xc + 1][yc + 1]
139
140 cleartest += (int) maze[xc + 2][yc] + (int) maze[xc + 2][yc - 1] + (int) maze[xc + 2][yc + 1]; 124 + maze[xc + 2][yc] + maze[xc + 2][yc - 1] + maze[xc + 2][yc + 1];
141 125
142 if (cleartest == 0) 126 if (cleartest == 0)
143 dirlist[count++] = 3; 127 dirlist[count++] = 3;
144 } 128 }
145 129
146 /* look left */ 130 /* look left */
147 if (xc > 2 && yc > 2 && yc < ysize - 2) /* it is valid to look down */ 131 if (xc > 2 && yc > 2 && yc < ysize - 2) /* it is valid to look down */
148 { 132 {
149 int cleartest = (int) maze[xc - 1][yc] + (int) maze[xc - 1][yc - 1] + (int) maze[xc - 1][yc + 1]; 133 int cleartest = maze[xc - 1][yc] + maze[xc - 1][yc - 1] + maze[xc - 1][yc + 1]
150
151 cleartest += (int) maze[xc - 2][yc] + (int) maze[xc - 2][yc - 1] + (int) maze[xc - 2][yc + 1]; 134 + maze[xc - 2][yc] + maze[xc - 2][yc - 1] + maze[xc - 2][yc + 1];
152 135
153 if (cleartest == 0) 136 if (cleartest == 0)
154 dirlist[count++] = 4; 137 dirlist[count++] = 4;
155 } 138 }
156 139
159 142
160 /* choose a random direction */ 143 /* choose a random direction */
161 switch (dirlist [rmg_rndm (count)]) 144 switch (dirlist [rmg_rndm (count)])
162 { 145 {
163 case 1: /* up */ 146 case 1: /* up */
147 p.x = xc;
164 *y = yc + 1; 148 p.y = yc + 1;
165 *x = xc;
166 break; 149 break;
167 150
168 case 2: /* down */ 151 case 2: /* down */
152 p.x = xc;
169 *y = yc - 1; 153 p.y = yc - 1;
170 *x = xc;
171 break; 154 break;
172 155
173 case 3: /* right */ 156 case 3: /* right */
174 *y = yc;
175 *x = xc + 1; 157 p.x = xc + 1;
158 p.y = yc;
176 break; 159 break;
177 160
178 case 4: /* left */ 161 case 4: /* left */
179 *x = xc - 1; 162 p.x = xc - 1;
180 *y = yc; 163 p.y = yc;
181 break; 164 break;
182
183 default: /* ??? */
184 return -1;
185
186 } 165 }
187 166
188 return 1; 167 return 1;
189}
190
191/* recursive routine which will fill every available space in the maze
192 with walls*/
193static void
194fill_maze_full (char **maze, int x, int y, int xsize, int ysize)
195{
196 int xc, yc;
197
198 /* write a wall here */
199 maze[x][y] = '#';
200
201 /* decide if we're going to pick from the wall_free_list */
202 if (rmg_rndm (4) && wall_free_size > 0)
203 {
204 pop_wall_point (&xc, &yc);
205 fill_maze_full (maze, xc, yc, xsize, ysize);
206 }
207
208 /* change the if to a while for a complete maze. */
209 while (find_free_point (maze, &xc, &yc, x, y, xsize, ysize) != -1)
210 fill_maze_full (maze, xc, yc, xsize, ysize);
211}
212
213/* recursive routine which will fill much of the maze, but will leave
214 some free spots (possibly large) toward the center.*/
215static void
216fill_maze_sparse (char **maze, int x, int y, int xsize, int ysize)
217{
218 int xc, yc;
219
220 /* write a wall here */
221 maze[x][y] = '#';
222
223 /* decide if we're going to pick from the wall_free_list */
224 if (rmg_rndm (4) && wall_free_size > 0)
225 {
226 pop_wall_point (&xc, &yc);
227 fill_maze_sparse (maze, xc, yc, xsize, ysize);
228 }
229
230 /* change the if to a while for a complete maze. */
231 if (find_free_point (maze, &xc, &yc, x, y, xsize, ysize) != -1)
232 fill_maze_sparse (maze, xc, yc, xsize, ysize);
233} 168}
234 169
235/* the outsize interface routine: accepts sizes, returns a char 170/* the outsize interface routine: accepts sizes, returns a char
236** maze. option is a flag for either a sparse or a full maze. Sparse 171** maze. option is a flag for either a sparse or a full maze. Sparse
237mazes have sizable rooms. option = 1, full, 0, sparse.*/ 172mazes have sizable rooms. option = 3=full, 2=braided, 1=sparse, 0=rooms.*/
238void 173void
239maze_gen (Layout maze, int option) 174maze_gen (layout &maze, int subtype)
240{ 175{
176 xsize = maze.w;
177 ysize = maze.h;
178 ::maze = maze;
179
241 maze->clear (); 180 maze.clear ();
242 maze->border (); 181 maze.border ();
243 182
244 /* find how many free wall spots there are */ 183 if (xsize < 4 || ysize < 4)
245 wall_free_size = 2 * (maze->w - 4) + 2 * (maze->h - 4);
246
247 make_wall_free_list (maze->w, maze->h);
248
249 /* return the empty maze */
250 if (wall_free_size <= 0)
251 return; 184 return;
185
186 seeds.reset (xsize * ysize);
187
188 if (subtype > 0)
189 push_walls ();
190
191 if (subtype == 0 || subtype == 2)
192 for (int i = (xsize + ysize) / 2; i; --i)
193 push (point (rmg_rndm (1, xsize - 2), rmg_rndm (1, ysize - 2)));
194
195 bool full = subtype == 3;
252 196
253 /* recursively generate the walls of the maze */ 197 /* recursively generate the walls of the maze */
254 /* first pop a random starting point */ 198 /* first pop a random starting point */
255 while (wall_free_size > 0) 199 while (seeds.size)
256 {
257 int i, j;
258
259 pop_wall_point (&i, &j);
260
261 if (option)
262 fill_maze_full (maze, i, j, maze->w, maze->h);
263 else
264 fill_maze_sparse (maze, i, j, maze->w, maze->h);
265 } 200 {
201 point p = pop_rand ();
266 202
267 /* clean up our intermediate data structures. */ 203 for (;;)
204 {
205 point pc;
268 206
269 free (wall_x_list); 207 maze [p.x][p.y] = '#';
270 free (wall_y_list);
271}
272 208
209 if (find_free_point (pc, p) < 0)
210 break;
211
212 if (full)
213 push (p);
214
215 if (!rmg_rndm (8))
216 {
217 if (!full)
218 push (pc);
219
220 break;
221 }
222
223 p = pc;
224 }
225 }
226
227 seeds.free ();
228}
229

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines