ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/random_maps/rogue_layout.C
Revision: 1.9
Committed: Tue Apr 15 03:00:24 2008 UTC (16 years, 2 months ago) by root
Content type: text/plain
Branch: MAIN
CVS Tags: rel-2_5, rel-2_52
Changes since 1.8: +7 -4 lines
Log Message:
new logging thread, fix bugs in random map generator

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