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, 1 month 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

# User Rev Content
1 root 1.3
2 elmex 1.1 /* generate a rogue/nethack-like layout */
3     #include <global.h>
4     #include <random_map.h>
5     #include <math.h>
6    
7 root 1.3 typedef struct
8     {
9 elmex 1.1 int x;
10 root 1.3 int y; /* coordinates of room centers */
11 elmex 1.1
12     int sx;
13 root 1.3 int sy; /* sizes */
14     int ax, ay, zx, zy; /* coordinates of extrema of the rectangle */
15 elmex 1.1
16 root 1.3 int rtype; /* circle or rectangular */
17 elmex 1.1 } Room;
18    
19 root 1.7 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 elmex 1.1
23 root 1.3 int
24     surround_check (char **layout, int i, int j, int Xsize, int Ysize)
25     {
26 elmex 1.1 /* 1 = wall to left,
27 root 1.3 2 = wall to right,
28     4 = wall above
29     8 = wall below */
30 elmex 1.1 int surround_index = 0;
31 root 1.3
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 elmex 1.1 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 root 1.8 void
47     roguelike_layout_gen (Maze maze, int options)
48 root 1.3 {
49     int i, j;
50 elmex 1.1 Room *walk;
51 root 1.3 int nrooms = 0;
52     int tries = 0;
53 elmex 1.1
54 root 1.8 int xsize = maze->w;
55     int ysize = maze->h;
56 elmex 1.1
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 root 1.3 if (xsize < 11 || ysize < 11)
61     {
62 root 1.8 maze->clear ();
63     maze->border ();
64 root 1.7
65     maze[(xsize - 1) / 2][(ysize - 1) / 2 ] = '>';
66 root 1.3 maze[(xsize - 1) / 2][(ysize - 1) / 2 + 1] = '<';
67 root 1.7
68 root 1.8 return;
69 root 1.3 }
70 elmex 1.1
71 root 1.8 maze->clear ('#');
72    
73 elmex 1.1 /* decide on the number of rooms */
74 root 1.5 nrooms = rndm (10) + 6;
75 root 1.7 Room *rooms = salloc0<Room> (nrooms + 1);
76 elmex 1.1
77     /* actually place the rooms */
78 root 1.3 i = 0;
79     while (tries < 450 && i < nrooms)
80     {
81     /* try to place the room */
82 root 1.7 if (!roguelike_place_room (rooms, xsize, ysize, nrooms))
83 root 1.3 tries++;
84     else
85     i++;
86     }
87    
88     if (i == 0)
89     { /* no can do! */
90 root 1.8 maze->clear ();
91     maze->border ();
92 root 1.7
93     maze [(xsize - 1) / 2][(ysize - 1) / 2 ] = '>';
94     maze [(xsize - 1) / 2][(ysize - 1) / 2 + 1] = '<';
95    
96     sfree (rooms, nrooms + 1);
97 root 1.8 return;
98 root 1.3 }
99    
100    
101 elmex 1.1 /* erase the areas occupied by the rooms */
102 root 1.7 roguelike_make_rooms (rooms, maze, options);
103 elmex 1.1
104 root 1.7 roguelike_link_rooms (rooms, maze, xsize, ysize);
105 elmex 1.1
106     /* put in the stairs */
107 root 1.3
108 root 1.7 maze[rooms->x][rooms->y] = '<';
109    
110 elmex 1.1 /* get the last one */
111 root 1.7 for (walk = rooms; walk->x != 0; walk++)
112     ;
113    
114 elmex 1.1 /* back up one */
115     walk--;
116 root 1.7
117     if (walk == rooms)
118 root 1.3 {
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 elmex 1.1 else
130     maze[walk->x][walk->y] = '>';
131    
132     /* convert all the '.' to 0, we're through with the '.' */
133 root 1.3 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 root 1.7
139 root 1.3 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 elmex 1.1 }
152 root 1.3
153 root 1.7 sfree (rooms, nrooms + 1);
154 elmex 1.1 }
155    
156 root 1.3 static int
157 root 1.7 roguelike_place_room (Room *rooms, int xsize, int ysize, int nrooms)
158 root 1.3 {
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 elmex 1.1 int x_basesize;
164     int y_basesize;
165     Room *walk;
166    
167     /* decide on the base x and y sizes */
168 root 1.3 x_basesize = xsize / isqrt (nrooms);
169     y_basesize = ysize / isqrt (nrooms);
170 elmex 1.1
171 root 1.6 tx = rndm (xsize);
172     ty = rndm (ysize);
173 root 1.3
174 elmex 1.1 /* generate a distribution of sizes centered about basesize */
175 root 1.6 sx = rndm (x_basesize) + rndm (x_basesize) + rndm (x_basesize);
176     sy = rndm (y_basesize) + rndm (y_basesize) + rndm (y_basesize);
177 root 1.3 sy = (int) (sy * .5); /* renormalize */
178 elmex 1.1
179     /* find the corners */
180     ax = tx - sx / 2;
181 root 1.3 zx = tx + sx / 2 + sx % 2;
182 elmex 1.1
183     ay = ty - sy / 2;
184 root 1.3 zy = ty + sy / 2 + sy % 2;
185 elmex 1.1
186     /* check to see if it's in the map */
187 root 1.7 if (zx > xsize - 1 || ax < 1) return 0;
188     if (zy > ysize - 1 || ay < 1) return 0;
189 root 1.3
190 elmex 1.1 /* no small fish */
191 root 1.3 if (sx < 3 || sy < 3)
192     return 0;
193 elmex 1.1
194     /* check overlap with existing rooms */
195 root 1.7 for (walk = rooms; walk->x != 0; walk++)
196 root 1.3 {
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 elmex 1.1
204     /* if we've got here, presumably the room is OK. */
205    
206     /* get a pointer to the first free room */
207 root 1.7 for (walk = rooms; walk->x != 0; walk++)
208     ;
209    
210 elmex 1.1 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 root 1.7
219 root 1.3 return 1; /* success */
220 elmex 1.1 }
221 root 1.3
222 elmex 1.1 /* write all the rooms into the maze */
223 root 1.3 static void
224 root 1.7 roguelike_make_rooms (Room *rooms, char **maze, int options)
225 root 1.3 {
226     int making_circle = 0;
227     int i, j;
228 elmex 1.1 int R;
229     Room *walk;
230    
231 root 1.7 for (walk = rooms; walk->x != 0; walk++)
232 root 1.3 {
233     /* first decide what shape to make */
234     switch (options)
235     {
236 root 1.4 case 1:
237     making_circle = 0;
238     break;
239     case 2:
240     making_circle = 1;
241     break;
242     default:
243 root 1.5 making_circle = ((rndm (3) == 0) ? 1 : 0);
244 root 1.4 break;
245 root 1.3 }
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 root 1.7 if (!making_circle || ((int) (0.5 + hypot (walk->x - i, walk->y - j))) <= R)
256     maze[i][j] = '.';
257 elmex 1.1 }
258     }
259    
260 root 1.3 static void
261 root 1.7 roguelike_link_rooms (Room *rooms, char **maze, int xsize, int ysize)
262 root 1.3 {
263 elmex 1.1 Room *walk;
264 root 1.3 int i, j;
265    
266 elmex 1.1 /* link each room to the previous room */
267 root 1.7 if (rooms[1].x == 0)
268 root 1.3 return; /* only 1 room */
269 elmex 1.1
270 root 1.7 for (walk = rooms + 1; walk->x != 0; walk++)
271 root 1.3 {
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 root 1.5 if (rndm (2))
279 root 1.3 { /* 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 elmex 1.1
331     }
332 root 1.3 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 elmex 1.1
385     }
386    
387     }
388     }
389 root 1.7