ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/random_maps/rogue_layout.C
Revision: 1.7
Committed: Fri Apr 11 21:09:53 2008 UTC (16 years, 2 months ago) by root
Content type: text/plain
Branch: MAIN
Changes since 1.6: +44 -50 lines
Log Message:
*** empty log message ***

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