ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/random_maps/rogue_layout.C
Revision: 1.8
Committed: Mon Apr 14 22:41:17 2008 UTC (16 years, 2 months ago) by root
Content type: text/plain
Branch: MAIN
Changes since 1.7: +12 -17 lines
Log Message:
refactor random map gen more

File Contents

# Content
1
2 /* generate a rogue/nethack-like layout */
3 #include <global.h>
4 #include <random_map.h>
5 #include <math.h>
6
7 typedef struct
8 {
9 int x;
10 int y; /* coordinates of room centers */
11
12 int sx;
13 int sy; /* sizes */
14 int ax, ay, zx, zy; /* coordinates of extrema of the rectangle */
15
16 int rtype; /* circle or rectangular */
17 } Room;
18
19 static int roguelike_place_room (Room *rooms, int xsize, int ysize, int nrooms);
20 static void roguelike_make_rooms (Room *rooms, char **maze, int options);
21 static void roguelike_link_rooms (Room *rooms, char **maze, int xsize, int ysize);
22
23 int
24 surround_check (char **layout, int i, int j, int Xsize, int Ysize)
25 {
26 /* 1 = wall to left,
27 2 = wall to right,
28 4 = wall above
29 8 = wall below */
30 int surround_index = 0;
31
32 if ((i > 0) && (layout[i - 1][j] != 0 && layout[i - 1][j] != '.'))
33 surround_index += 1;
34 if ((i < Xsize - 1) && (layout[i + 1][j] != 0 && layout[i + 1][j] != '.'))
35 surround_index += 2;
36 if ((j > 0) && (layout[i][j - 1] != 0 && layout[i][j - 1] != '.'))
37 surround_index += 4;
38 if ((j < Ysize - 1) && (layout[i][j + 1] != 0 && layout[i][j + 1] != '.'))
39 surround_index += 8;
40 return surround_index;
41 }
42
43 /* actually make the layout: we work by a reduction process:
44 * first we make everything a wall, then we remove areas to make rooms
45 */
46 void
47 roguelike_layout_gen (Maze maze, int options)
48 {
49 int i, j;
50 Room *walk;
51 int nrooms = 0;
52 int tries = 0;
53
54 int xsize = maze->w;
55 int ysize = maze->h;
56
57 /* minimum room size is basically 5x5: if xsize/ysize is
58 less than 3x that then hollow things out, stick in
59 a stairsup and stairs down, and exit */
60 if (xsize < 11 || ysize < 11)
61 {
62 maze->clear ();
63 maze->border ();
64
65 maze[(xsize - 1) / 2][(ysize - 1) / 2 ] = '>';
66 maze[(xsize - 1) / 2][(ysize - 1) / 2 + 1] = '<';
67
68 return;
69 }
70
71 maze->clear ('#');
72
73 /* decide on the number of rooms */
74 nrooms = rndm (10) + 6;
75 Room *rooms = salloc0<Room> (nrooms + 1);
76
77 /* actually place the rooms */
78 i = 0;
79 while (tries < 450 && i < nrooms)
80 {
81 /* try to place the room */
82 if (!roguelike_place_room (rooms, xsize, ysize, nrooms))
83 tries++;
84 else
85 i++;
86 }
87
88 if (i == 0)
89 { /* no can do! */
90 maze->clear ();
91 maze->border ();
92
93 maze [(xsize - 1) / 2][(ysize - 1) / 2 ] = '>';
94 maze [(xsize - 1) / 2][(ysize - 1) / 2 + 1] = '<';
95
96 sfree (rooms, nrooms + 1);
97 return;
98 }
99
100
101 /* erase the areas occupied by the rooms */
102 roguelike_make_rooms (rooms, maze, options);
103
104 roguelike_link_rooms (rooms, maze, xsize, ysize);
105
106 /* put in the stairs */
107
108 maze[rooms->x][rooms->y] = '<';
109
110 /* get the last one */
111 for (walk = rooms; walk->x != 0; walk++)
112 ;
113
114 /* back up one */
115 walk--;
116
117 if (walk == rooms)
118 {
119 /* In this case, there is only a single room. We don't want to
120 * clobber are up exit (above) with a down exit, so put the
121 * other exit one space up/down, depending which is a space
122 * and not a wall.
123 */
124 if (maze[walk->x][walk->y + 1] == '.')
125 maze[walk->x][walk->y + 1] = '>';
126 else
127 maze[walk->x][walk->y - 1] = '>';
128 }
129 else
130 maze[walk->x][walk->y] = '>';
131
132 /* convert all the '.' to 0, we're through with the '.' */
133 for (i = 0; i < xsize; i++)
134 for (j = 0; j < ysize; j++)
135 {
136 if (maze[i][j] == '.')
137 maze[i][j] = 0;
138
139 if (maze[i][j] == 'D')
140 { /* remove bad door. */
141 int si = surround_check (maze, i, j, xsize, ysize);
142
143 if (si != 3 && si != 12)
144 {
145 maze[i][j] = 0;
146 /* back up and recheck any nearby doors */
147 i = 0;
148 j = 0;
149 }
150 }
151 }
152
153 sfree (rooms, nrooms + 1);
154 }
155
156 static int
157 roguelike_place_room (Room *rooms, int xsize, int ysize, int nrooms)
158 {
159 int tx, ty; /* trial center locations */
160 int sx, sy; /* trial sizes */
161 int ax, ay; /* min coords of rect */
162 int zx, zy; /* max coords of rect */
163 int x_basesize;
164 int y_basesize;
165 Room *walk;
166
167 /* decide on the base x and y sizes */
168 x_basesize = xsize / isqrt (nrooms);
169 y_basesize = ysize / isqrt (nrooms);
170
171 tx = rndm (xsize);
172 ty = rndm (ysize);
173
174 /* generate a distribution of sizes centered about basesize */
175 sx = rndm (x_basesize) + rndm (x_basesize) + rndm (x_basesize);
176 sy = rndm (y_basesize) + rndm (y_basesize) + rndm (y_basesize);
177 sy = (int) (sy * .5); /* renormalize */
178
179 /* find the corners */
180 ax = tx - sx / 2;
181 zx = tx + sx / 2 + sx % 2;
182
183 ay = ty - sy / 2;
184 zy = ty + sy / 2 + sy % 2;
185
186 /* check to see if it's in the map */
187 if (zx > xsize - 1 || ax < 1) return 0;
188 if (zy > ysize - 1 || ay < 1) return 0;
189
190 /* no small fish */
191 if (sx < 3 || sy < 3)
192 return 0;
193
194 /* check overlap with existing rooms */
195 for (walk = rooms; walk->x != 0; walk++)
196 {
197 int dx = abs (tx - walk->x);
198 int dy = abs (ty - walk->y);
199
200 if ((dx < (walk->sx + sx) / 2 + 2) && (dy < (walk->sy + sy) / 2 + 2))
201 return 0;
202 }
203
204 /* if we've got here, presumably the room is OK. */
205
206 /* get a pointer to the first free room */
207 for (walk = rooms; walk->x != 0; walk++)
208 ;
209
210 walk->x = tx;
211 walk->y = ty;
212 walk->sx = sx;
213 walk->sy = sy;
214 walk->ax = ax;
215 walk->ay = ay;
216 walk->zx = zx;
217 walk->zy = zy;
218
219 return 1; /* success */
220 }
221
222 /* write all the rooms into the maze */
223 static void
224 roguelike_make_rooms (Room *rooms, char **maze, int options)
225 {
226 int making_circle = 0;
227 int i, j;
228 int R;
229 Room *walk;
230
231 for (walk = rooms; walk->x != 0; walk++)
232 {
233 /* first decide what shape to make */
234 switch (options)
235 {
236 case 1:
237 making_circle = 0;
238 break;
239 case 2:
240 making_circle = 1;
241 break;
242 default:
243 making_circle = ((rndm (3) == 0) ? 1 : 0);
244 break;
245 }
246
247 if (walk->sx < walk->sy)
248 R = walk->sx / 2;
249 else
250 R = walk->sy / 2;
251
252 /* enscribe a rectangle */
253 for (i = walk->ax; i < walk->zx; i++)
254 for (j = walk->ay; j < walk->zy; j++)
255 if (!making_circle || ((int) (0.5 + hypot (walk->x - i, walk->y - j))) <= R)
256 maze[i][j] = '.';
257 }
258 }
259
260 static void
261 roguelike_link_rooms (Room *rooms, char **maze, int xsize, int ysize)
262 {
263 Room *walk;
264 int i, j;
265
266 /* link each room to the previous room */
267 if (rooms[1].x == 0)
268 return; /* only 1 room */
269
270 for (walk = rooms + 1; walk->x != 0; walk++)
271 {
272 int x1 = walk->x;
273 int y1 = walk->y;
274 int x2 = (walk - 1)->x;
275 int y2 = (walk - 1)->y;
276 int in_wall = 0;
277
278 if (rndm (2))
279 { /* connect in x direction first */
280 /* horizontal connect */
281 /* swap (x1,y1) (x2,y2) if necessary */
282
283 if (x2 < x1)
284 {
285 int tx = x2, ty = y2;
286
287 x2 = x1;
288 y2 = y1;
289 x1 = tx;
290 y1 = ty;
291 }
292
293
294 j = y1;
295 for (i = x1; i < x2; i++)
296 {
297 if (in_wall == 0 && maze[i][j] == '#')
298 {
299 in_wall = 1;
300 maze[i][j] = 'D';
301 }
302 else if (in_wall && maze[i][j] == '.')
303 {
304 in_wall = 0;
305 maze[i - 1][j] = 'D';
306 }
307 else if (maze[i][j] != 'D' && maze[i][j] != '.')
308 maze[i][j] = 0;
309 }
310 j = MIN (y1, y2);
311 if (maze[i][j] == '.')
312 in_wall = 0;
313 if (maze[i][j] == 0 || maze[i][j] == '#')
314 in_wall = 1;
315 for ( /* j set already */ ; j < MAX (y1, y2); j++)
316 {
317 if (in_wall == 0 && maze[i][j] == '#')
318 {
319 in_wall = 1;
320 maze[i][j] = 'D';
321 }
322 else if (in_wall && maze[i][j] == '.')
323 {
324 in_wall = 0;
325 maze[i][j - 1] = 'D';
326 }
327 else if (maze[i][j] != 'D' && maze[i][j] != '.')
328 maze[i][j] = 0;
329 }
330
331 }
332 else
333 { /* connect in y direction first */
334 in_wall = 0;
335 /* swap if necessary */
336 if (y2 < y1)
337 {
338 int tx = x2, ty = y2;
339
340 x2 = x1;
341 y2 = y1;
342 x1 = tx;
343 y1 = ty;
344 }
345 i = x1;
346 /* vertical connect */
347 for (j = y1; j < y2; j++)
348 {
349 if (in_wall == 0 && maze[i][j] == '#')
350 {
351 in_wall = 1;
352 maze[i][j] = 'D';
353 }
354 else if (in_wall && maze[i][j] == '.')
355 {
356 in_wall = 0;
357 maze[i][j - 1] = 'D';
358 }
359 else if (maze[i][j] != 'D' && maze[i][j] != '.')
360 maze[i][j] = 0;
361 }
362
363 i = MIN (x1, x2);
364 if (maze[i][j] == '.')
365 in_wall = 0;
366 if (maze[i][j] == 0 || maze[i][j] == '#')
367 in_wall = 1;
368 for ( /* i set already */ ; i < MAX (x1, x2); i++)
369 {
370 if (in_wall == 0 && maze[i][j] == '#')
371 {
372 in_wall = 1;
373 maze[i][j] = 'D';
374 }
375 else if (in_wall && maze[i][j] == '.')
376 {
377 in_wall = 0;
378 maze[i - 1][j] = 'D';
379 }
380 else if (maze[i][j] != 'D' && maze[i][j] != '.')
381 maze[i][j] = 0;
382
383 }
384
385 }
386
387 }
388 }
389