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, 2 months 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

# 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 root 1.10 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 root 1.9
37 elmex 1.1 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 root 1.8 void
44 root 1.9 roguelike_layout_gen (Layout maze, int options)
45 root 1.3 {
46     int i, j;
47 elmex 1.1 Room *walk;
48 root 1.3 int nrooms = 0;
49     int tries = 0;
50 elmex 1.1
51 root 1.8 int xsize = maze->w;
52     int ysize = maze->h;
53 elmex 1.1
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 root 1.3 if (xsize < 11 || ysize < 11)
58     {
59 root 1.8 maze->clear ();
60     maze->border ();
61 root 1.7
62     maze[(xsize - 1) / 2][(ysize - 1) / 2 ] = '>';
63 root 1.3 maze[(xsize - 1) / 2][(ysize - 1) / 2 + 1] = '<';
64 root 1.7
65 root 1.8 return;
66 root 1.3 }
67 elmex 1.1
68 root 1.8 maze->clear ('#');
69    
70 elmex 1.1 /* decide on the number of rooms */
71 root 1.10 nrooms = rmg_rndm (10) + 6;
72 root 1.7 Room *rooms = salloc0<Room> (nrooms + 1);
73 elmex 1.1
74     /* actually place the rooms */
75 root 1.3 i = 0;
76     while (tries < 450 && i < nrooms)
77     {
78     /* try to place the room */
79 root 1.7 if (!roguelike_place_room (rooms, xsize, ysize, nrooms))
80 root 1.3 tries++;
81     else
82     i++;
83     }
84    
85 root 1.9 if (i == 0) /* no can do! */
86     {
87 root 1.8 maze->clear ();
88     maze->border ();
89 root 1.7
90     maze [(xsize - 1) / 2][(ysize - 1) / 2 ] = '>';
91     maze [(xsize - 1) / 2][(ysize - 1) / 2 + 1] = '<';
92    
93     sfree (rooms, nrooms + 1);
94 root 1.8 return;
95 root 1.3 }
96    
97 elmex 1.1 /* erase the areas occupied by the rooms */
98 root 1.7 roguelike_make_rooms (rooms, maze, options);
99 elmex 1.1
100 root 1.7 roguelike_link_rooms (rooms, maze, xsize, ysize);
101 elmex 1.1
102     /* put in the stairs */
103 root 1.3
104 root 1.7 maze[rooms->x][rooms->y] = '<';
105    
106 elmex 1.1 /* get the last one */
107 root 1.7 for (walk = rooms; walk->x != 0; walk++)
108     ;
109    
110 elmex 1.1 /* back up one */
111     walk--;
112 root 1.7
113     if (walk == rooms)
114 root 1.3 {
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 elmex 1.1 else
126     maze[walk->x][walk->y] = '>';
127    
128     /* convert all the '.' to 0, we're through with the '.' */
129 root 1.3 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 root 1.7
135 root 1.3 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 elmex 1.1 }
148 root 1.3
149 root 1.7 sfree (rooms, nrooms + 1);
150 elmex 1.1 }
151    
152 root 1.3 static int
153 root 1.7 roguelike_place_room (Room *rooms, int xsize, int ysize, int nrooms)
154 root 1.3 {
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 elmex 1.1 int x_basesize;
160     int y_basesize;
161     Room *walk;
162    
163     /* decide on the base x and y sizes */
164 root 1.3 x_basesize = xsize / isqrt (nrooms);
165     y_basesize = ysize / isqrt (nrooms);
166 elmex 1.1
167 root 1.10 tx = rmg_rndm (xsize);
168     ty = rmg_rndm (ysize);
169 root 1.3
170 elmex 1.1 /* generate a distribution of sizes centered about basesize */
171 root 1.10 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 root 1.3 sy = (int) (sy * .5); /* renormalize */
174 elmex 1.1
175     /* find the corners */
176     ax = tx - sx / 2;
177 root 1.3 zx = tx + sx / 2 + sx % 2;
178 elmex 1.1
179     ay = ty - sy / 2;
180 root 1.3 zy = ty + sy / 2 + sy % 2;
181 elmex 1.1
182     /* check to see if it's in the map */
183 root 1.7 if (zx > xsize - 1 || ax < 1) return 0;
184     if (zy > ysize - 1 || ay < 1) return 0;
185 root 1.3
186 elmex 1.1 /* no small fish */
187 root 1.3 if (sx < 3 || sy < 3)
188     return 0;
189 elmex 1.1
190     /* check overlap with existing rooms */
191 root 1.7 for (walk = rooms; walk->x != 0; walk++)
192 root 1.3 {
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 elmex 1.1
200     /* if we've got here, presumably the room is OK. */
201    
202     /* get a pointer to the first free room */
203 root 1.7 for (walk = rooms; walk->x != 0; walk++)
204     ;
205    
206 elmex 1.1 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 root 1.7
215 root 1.3 return 1; /* success */
216 elmex 1.1 }
217 root 1.3
218 elmex 1.1 /* write all the rooms into the maze */
219 root 1.3 static void
220 root 1.7 roguelike_make_rooms (Room *rooms, char **maze, int options)
221 root 1.3 {
222     int making_circle = 0;
223     int i, j;
224 elmex 1.1 int R;
225     Room *walk;
226    
227 root 1.7 for (walk = rooms; walk->x != 0; walk++)
228 root 1.3 {
229     /* first decide what shape to make */
230     switch (options)
231     {
232 root 1.4 case 1:
233     making_circle = 0;
234     break;
235     case 2:
236     making_circle = 1;
237     break;
238     default:
239 root 1.10 making_circle = ((rmg_rndm (3) == 0) ? 1 : 0);
240 root 1.4 break;
241 root 1.3 }
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 root 1.7 if (!making_circle || ((int) (0.5 + hypot (walk->x - i, walk->y - j))) <= R)
252     maze[i][j] = '.';
253 elmex 1.1 }
254     }
255    
256 root 1.3 static void
257 root 1.7 roguelike_link_rooms (Room *rooms, char **maze, int xsize, int ysize)
258 root 1.3 {
259 elmex 1.1 Room *walk;
260 root 1.3 int i, j;
261    
262 elmex 1.1 /* link each room to the previous room */
263 root 1.7 if (rooms[1].x == 0)
264 root 1.3 return; /* only 1 room */
265 elmex 1.1
266 root 1.7 for (walk = rooms + 1; walk->x != 0; walk++)
267 root 1.3 {
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 root 1.10 if (rmg_rndm (2))
275 root 1.3 { /* 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 elmex 1.1
327     }
328 root 1.3 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 elmex 1.1
381     }
382    
383     }
384     }
385 root 1.7