ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/random_maps/rogue_layout.C
Revision: 1.11
Committed: Sat Nov 7 18:30:05 2009 UTC (14 years, 7 months ago) by root
Content type: text/plain
Branch: MAIN
Changes since 1.10: +12 -6 lines
Log Message:
lots of cleanups

File Contents

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