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

# 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 root 1.9
35 root 1.3 if ((i < Xsize - 1) && (layout[i + 1][j] != 0 && layout[i + 1][j] != '.'))
36     surround_index += 2;
37 root 1.9
38 root 1.3 if ((j > 0) && (layout[i][j - 1] != 0 && layout[i][j - 1] != '.'))
39     surround_index += 4;
40 root 1.9
41 root 1.3 if ((j < Ysize - 1) && (layout[i][j + 1] != 0 && layout[i][j + 1] != '.'))
42     surround_index += 8;
43 root 1.9
44 elmex 1.1 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 root 1.8 void
51 root 1.9 roguelike_layout_gen (Layout maze, int options)
52 root 1.3 {
53     int i, j;
54 elmex 1.1 Room *walk;
55 root 1.3 int nrooms = 0;
56     int tries = 0;
57 elmex 1.1
58 root 1.8 int xsize = maze->w;
59     int ysize = maze->h;
60 elmex 1.1
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 root 1.3 if (xsize < 11 || ysize < 11)
65     {
66 root 1.8 maze->clear ();
67     maze->border ();
68 root 1.7
69     maze[(xsize - 1) / 2][(ysize - 1) / 2 ] = '>';
70 root 1.3 maze[(xsize - 1) / 2][(ysize - 1) / 2 + 1] = '<';
71 root 1.7
72 root 1.8 return;
73 root 1.3 }
74 elmex 1.1
75 root 1.8 maze->clear ('#');
76    
77 elmex 1.1 /* decide on the number of rooms */
78 root 1.5 nrooms = rndm (10) + 6;
79 root 1.7 Room *rooms = salloc0<Room> (nrooms + 1);
80 elmex 1.1
81     /* actually place the rooms */
82 root 1.3 i = 0;
83     while (tries < 450 && i < nrooms)
84     {
85     /* try to place the room */
86 root 1.7 if (!roguelike_place_room (rooms, xsize, ysize, nrooms))
87 root 1.3 tries++;
88     else
89     i++;
90     }
91    
92 root 1.9 if (i == 0) /* no can do! */
93     {
94 root 1.8 maze->clear ();
95     maze->border ();
96 root 1.7
97     maze [(xsize - 1) / 2][(ysize - 1) / 2 ] = '>';
98     maze [(xsize - 1) / 2][(ysize - 1) / 2 + 1] = '<';
99    
100     sfree (rooms, nrooms + 1);
101 root 1.8 return;
102 root 1.3 }
103    
104 elmex 1.1 /* erase the areas occupied by the rooms */
105 root 1.7 roguelike_make_rooms (rooms, maze, options);
106 elmex 1.1
107 root 1.7 roguelike_link_rooms (rooms, maze, xsize, ysize);
108 elmex 1.1
109     /* put in the stairs */
110 root 1.3
111 root 1.7 maze[rooms->x][rooms->y] = '<';
112    
113 elmex 1.1 /* get the last one */
114 root 1.7 for (walk = rooms; walk->x != 0; walk++)
115     ;
116    
117 elmex 1.1 /* back up one */
118     walk--;
119 root 1.7
120     if (walk == rooms)
121 root 1.3 {
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 elmex 1.1 else
133     maze[walk->x][walk->y] = '>';
134    
135     /* convert all the '.' to 0, we're through with the '.' */
136 root 1.3 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 root 1.7
142 root 1.3 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 elmex 1.1 }
155 root 1.3
156 root 1.7 sfree (rooms, nrooms + 1);
157 elmex 1.1 }
158    
159 root 1.3 static int
160 root 1.7 roguelike_place_room (Room *rooms, int xsize, int ysize, int nrooms)
161 root 1.3 {
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 elmex 1.1 int x_basesize;
167     int y_basesize;
168     Room *walk;
169    
170     /* decide on the base x and y sizes */
171 root 1.3 x_basesize = xsize / isqrt (nrooms);
172     y_basesize = ysize / isqrt (nrooms);
173 elmex 1.1
174 root 1.6 tx = rndm (xsize);
175     ty = rndm (ysize);
176 root 1.3
177 elmex 1.1 /* generate a distribution of sizes centered about basesize */
178 root 1.6 sx = rndm (x_basesize) + rndm (x_basesize) + rndm (x_basesize);
179     sy = rndm (y_basesize) + rndm (y_basesize) + rndm (y_basesize);
180 root 1.3 sy = (int) (sy * .5); /* renormalize */
181 elmex 1.1
182     /* find the corners */
183     ax = tx - sx / 2;
184 root 1.3 zx = tx + sx / 2 + sx % 2;
185 elmex 1.1
186     ay = ty - sy / 2;
187 root 1.3 zy = ty + sy / 2 + sy % 2;
188 elmex 1.1
189     /* check to see if it's in the map */
190 root 1.7 if (zx > xsize - 1 || ax < 1) return 0;
191     if (zy > ysize - 1 || ay < 1) return 0;
192 root 1.3
193 elmex 1.1 /* no small fish */
194 root 1.3 if (sx < 3 || sy < 3)
195     return 0;
196 elmex 1.1
197     /* check overlap with existing rooms */
198 root 1.7 for (walk = rooms; walk->x != 0; walk++)
199 root 1.3 {
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 elmex 1.1
207     /* if we've got here, presumably the room is OK. */
208    
209     /* get a pointer to the first free room */
210 root 1.7 for (walk = rooms; walk->x != 0; walk++)
211     ;
212    
213 elmex 1.1 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 root 1.7
222 root 1.3 return 1; /* success */
223 elmex 1.1 }
224 root 1.3
225 elmex 1.1 /* write all the rooms into the maze */
226 root 1.3 static void
227 root 1.7 roguelike_make_rooms (Room *rooms, char **maze, int options)
228 root 1.3 {
229     int making_circle = 0;
230     int i, j;
231 elmex 1.1 int R;
232     Room *walk;
233    
234 root 1.7 for (walk = rooms; walk->x != 0; walk++)
235 root 1.3 {
236     /* first decide what shape to make */
237     switch (options)
238     {
239 root 1.4 case 1:
240     making_circle = 0;
241     break;
242     case 2:
243     making_circle = 1;
244     break;
245     default:
246 root 1.5 making_circle = ((rndm (3) == 0) ? 1 : 0);
247 root 1.4 break;
248 root 1.3 }
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 root 1.7 if (!making_circle || ((int) (0.5 + hypot (walk->x - i, walk->y - j))) <= R)
259     maze[i][j] = '.';
260 elmex 1.1 }
261     }
262    
263 root 1.3 static void
264 root 1.7 roguelike_link_rooms (Room *rooms, char **maze, int xsize, int ysize)
265 root 1.3 {
266 elmex 1.1 Room *walk;
267 root 1.3 int i, j;
268    
269 elmex 1.1 /* link each room to the previous room */
270 root 1.7 if (rooms[1].x == 0)
271 root 1.3 return; /* only 1 room */
272 elmex 1.1
273 root 1.7 for (walk = rooms + 1; walk->x != 0; walk++)
274 root 1.3 {
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 root 1.5 if (rndm (2))
282 root 1.3 { /* 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 elmex 1.1
334     }
335 root 1.3 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 elmex 1.1
388     }
389    
390     }
391     }
392 root 1.7