ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/random_maps/rogue_layout.C
Revision: 1.10
Committed: Sun May 4 14:12:37 2008 UTC (16 years, 1 month ago) by root
Content type: text/plain
Branch: MAIN
CVS Tags: rel-2_82, rel-2_81, rel-2_80, rel-2_6, rel-2_7, rel-2_72, rel-2_73, rel-2_71, rel-2_76, rel-2_77, rel-2_74, rel-2_75, rel-2_54, rel-2_55, rel-2_56, rel-2_79, rel-2_53, rel-2_90, rel-2_78, rel-2_61
Changes since 1.9: +11 -18 lines
Log Message:
lotsa

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