ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/random_maps/rogue_layout.C
Revision: 1.12
Committed: Sat Nov 7 18:32:45 2009 UTC (14 years, 7 months ago) by root
Content type: text/plain
Branch: MAIN
CVS Tags: rel-3_0, rel-2_92, rel-2_93
Changes since 1.11: +23 -0 lines
Log Message:
add copyright notices to .C files

File Contents

# User Rev Content
1 root 1.12 /*
2     * This file is part of Deliantra, the Roguelike Realtime MMORPG.
3     *
4     * Copyright (©) 2005,2006,2007,2008,2009 Marc Alexander Lehmann / Robin Redeker / the Deliantra team
5     * Copyright (©) Crossfire Development Team (restored, original file without copyright notice)
6     *
7     * Deliantra is free software: you can redistribute it and/or modify it under
8     * the terms of the Affero GNU General Public License as published by the
9     * Free Software Foundation, either version 3 of the License, or (at your
10     * option) any later version.
11     *
12     * This program is distributed in the hope that it will be useful,
13     * but WITHOUT ANY WARRANTY; without even the implied warranty of
14     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15     * GNU General Public License for more details.
16     *
17     * You should have received a copy of the Affero GNU General Public License
18     * and the GNU General Public License along with this program. If not, see
19     * <http://www.gnu.org/licenses/>.
20     *
21     * The authors can be reached via e-mail to <support@deliantra.net>
22     */
23    
24 elmex 1.1 /* generate a rogue/nethack-like layout */
25     #include <global.h>
26     #include <random_map.h>
27 root 1.11 #include <rproto.h>
28 elmex 1.1
29 root 1.3 typedef struct
30     {
31 elmex 1.1 int x;
32 root 1.3 int y; /* coordinates of room centers */
33 elmex 1.1
34     int sx;
35 root 1.3 int sy; /* sizes */
36     int ax, ay, zx, zy; /* coordinates of extrema of the rectangle */
37 elmex 1.1
38 root 1.3 int rtype; /* circle or rectangular */
39 elmex 1.1 } Room;
40    
41 root 1.7 static int roguelike_place_room (Room *rooms, int xsize, int ysize, int nrooms);
42     static void roguelike_make_rooms (Room *rooms, char **maze, int options);
43     static void roguelike_link_rooms (Room *rooms, char **maze, int xsize, int ysize);
44 elmex 1.1
45 root 1.3 int
46     surround_check (char **layout, int i, int j, int Xsize, int Ysize)
47     {
48 elmex 1.1 /* 1 = wall to left,
49 root 1.3 2 = wall to right,
50     4 = wall above
51     8 = wall below */
52 elmex 1.1 int surround_index = 0;
53 root 1.3
54 root 1.10 if ((i > 0) && (layout[i - 1][j] != 0 && layout[i - 1][j] != '.')) surround_index |= 1;
55     if ((i < Xsize - 1) && (layout[i + 1][j] != 0 && layout[i + 1][j] != '.')) surround_index |= 2;
56     if ((j > 0) && (layout[i][j - 1] != 0 && layout[i][j - 1] != '.')) surround_index |= 4;
57     if ((j < Ysize - 1) && (layout[i][j + 1] != 0 && layout[i][j + 1] != '.')) surround_index |= 8;
58 root 1.9
59 elmex 1.1 return surround_index;
60     }
61    
62     /* actually make the layout: we work by a reduction process:
63     * first we make everything a wall, then we remove areas to make rooms
64     */
65 root 1.8 void
66 root 1.9 roguelike_layout_gen (Layout maze, int options)
67 root 1.3 {
68     int i, j;
69 elmex 1.1 Room *walk;
70 root 1.3 int nrooms = 0;
71     int tries = 0;
72 elmex 1.1
73 root 1.8 int xsize = maze->w;
74     int ysize = maze->h;
75 elmex 1.1
76     /* minimum room size is basically 5x5: if xsize/ysize is
77     less than 3x that then hollow things out, stick in
78     a stairsup and stairs down, and exit */
79 root 1.3 if (xsize < 11 || ysize < 11)
80     {
81 root 1.8 maze->clear ();
82     maze->border ();
83 root 1.7
84     maze[(xsize - 1) / 2][(ysize - 1) / 2 ] = '>';
85 root 1.3 maze[(xsize - 1) / 2][(ysize - 1) / 2 + 1] = '<';
86 root 1.7
87 root 1.8 return;
88 root 1.3 }
89 elmex 1.1
90 root 1.8 maze->clear ('#');
91    
92 elmex 1.1 /* decide on the number of rooms */
93 root 1.10 nrooms = rmg_rndm (10) + 6;
94 root 1.7 Room *rooms = salloc0<Room> (nrooms + 1);
95 elmex 1.1
96     /* actually place the rooms */
97 root 1.3 i = 0;
98     while (tries < 450 && i < nrooms)
99     {
100     /* try to place the room */
101 root 1.7 if (!roguelike_place_room (rooms, xsize, ysize, nrooms))
102 root 1.3 tries++;
103     else
104     i++;
105     }
106    
107 root 1.9 if (i == 0) /* no can do! */
108     {
109 root 1.8 maze->clear ();
110     maze->border ();
111 root 1.7
112     maze [(xsize - 1) / 2][(ysize - 1) / 2 ] = '>';
113     maze [(xsize - 1) / 2][(ysize - 1) / 2 + 1] = '<';
114    
115     sfree (rooms, nrooms + 1);
116 root 1.8 return;
117 root 1.3 }
118    
119 elmex 1.1 /* erase the areas occupied by the rooms */
120 root 1.7 roguelike_make_rooms (rooms, maze, options);
121 elmex 1.1
122 root 1.7 roguelike_link_rooms (rooms, maze, xsize, ysize);
123 elmex 1.1
124     /* put in the stairs */
125 root 1.3
126 root 1.7 maze[rooms->x][rooms->y] = '<';
127    
128 elmex 1.1 /* get the last one */
129 root 1.7 for (walk = rooms; walk->x != 0; walk++)
130     ;
131    
132 elmex 1.1 /* back up one */
133     walk--;
134 root 1.7
135     if (walk == rooms)
136 root 1.3 {
137     /* In this case, there is only a single room. We don't want to
138     * clobber are up exit (above) with a down exit, so put the
139     * other exit one space up/down, depending which is a space
140     * and not a wall.
141     */
142     if (maze[walk->x][walk->y + 1] == '.')
143     maze[walk->x][walk->y + 1] = '>';
144     else
145     maze[walk->x][walk->y - 1] = '>';
146     }
147 elmex 1.1 else
148     maze[walk->x][walk->y] = '>';
149    
150     /* convert all the '.' to 0, we're through with the '.' */
151 root 1.3 for (i = 0; i < xsize; i++)
152     for (j = 0; j < ysize; j++)
153     {
154     if (maze[i][j] == '.')
155     maze[i][j] = 0;
156 root 1.7
157 root 1.3 if (maze[i][j] == 'D')
158     { /* remove bad door. */
159     int si = surround_check (maze, i, j, xsize, ysize);
160    
161     if (si != 3 && si != 12)
162     {
163     maze[i][j] = 0;
164     /* back up and recheck any nearby doors */
165     i = 0;
166     j = 0;
167     }
168     }
169 elmex 1.1 }
170 root 1.3
171 root 1.7 sfree (rooms, nrooms + 1);
172 elmex 1.1 }
173    
174 root 1.3 static int
175 root 1.7 roguelike_place_room (Room *rooms, int xsize, int ysize, int nrooms)
176 root 1.3 {
177     int tx, ty; /* trial center locations */
178     int sx, sy; /* trial sizes */
179     int ax, ay; /* min coords of rect */
180     int zx, zy; /* max coords of rect */
181 elmex 1.1 int x_basesize;
182     int y_basesize;
183     Room *walk;
184    
185     /* decide on the base x and y sizes */
186 root 1.3 x_basesize = xsize / isqrt (nrooms);
187     y_basesize = ysize / isqrt (nrooms);
188 elmex 1.1
189 root 1.10 tx = rmg_rndm (xsize);
190     ty = rmg_rndm (ysize);
191 root 1.3
192 elmex 1.1 /* generate a distribution of sizes centered about basesize */
193 root 1.10 sx = rmg_rndm (x_basesize) + rmg_rndm (x_basesize) + rmg_rndm (x_basesize);
194     sy = rmg_rndm (y_basesize) + rmg_rndm (y_basesize) + rmg_rndm (y_basesize);
195 root 1.3 sy = (int) (sy * .5); /* renormalize */
196 elmex 1.1
197     /* find the corners */
198     ax = tx - sx / 2;
199 root 1.3 zx = tx + sx / 2 + sx % 2;
200 elmex 1.1
201     ay = ty - sy / 2;
202 root 1.3 zy = ty + sy / 2 + sy % 2;
203 elmex 1.1
204     /* check to see if it's in the map */
205 root 1.7 if (zx > xsize - 1 || ax < 1) return 0;
206     if (zy > ysize - 1 || ay < 1) return 0;
207 root 1.3
208 elmex 1.1 /* no small fish */
209 root 1.3 if (sx < 3 || sy < 3)
210     return 0;
211 elmex 1.1
212     /* check overlap with existing rooms */
213 root 1.7 for (walk = rooms; walk->x != 0; walk++)
214 root 1.3 {
215     int dx = abs (tx - walk->x);
216     int dy = abs (ty - walk->y);
217    
218     if ((dx < (walk->sx + sx) / 2 + 2) && (dy < (walk->sy + sy) / 2 + 2))
219     return 0;
220     }
221 elmex 1.1
222     /* if we've got here, presumably the room is OK. */
223    
224     /* get a pointer to the first free room */
225 root 1.7 for (walk = rooms; walk->x != 0; walk++)
226     ;
227    
228 elmex 1.1 walk->x = tx;
229     walk->y = ty;
230     walk->sx = sx;
231     walk->sy = sy;
232     walk->ax = ax;
233     walk->ay = ay;
234     walk->zx = zx;
235     walk->zy = zy;
236 root 1.7
237 root 1.3 return 1; /* success */
238 elmex 1.1 }
239 root 1.3
240 elmex 1.1 /* write all the rooms into the maze */
241 root 1.3 static void
242 root 1.7 roguelike_make_rooms (Room *rooms, char **maze, int options)
243 root 1.3 {
244     int making_circle = 0;
245     int i, j;
246 elmex 1.1 int R;
247     Room *walk;
248    
249 root 1.7 for (walk = rooms; walk->x != 0; walk++)
250 root 1.3 {
251     /* first decide what shape to make */
252     switch (options)
253     {
254 root 1.4 case 1:
255     making_circle = 0;
256     break;
257     case 2:
258     making_circle = 1;
259     break;
260     default:
261 root 1.10 making_circle = ((rmg_rndm (3) == 0) ? 1 : 0);
262 root 1.4 break;
263 root 1.3 }
264    
265     if (walk->sx < walk->sy)
266     R = walk->sx / 2;
267     else
268     R = walk->sy / 2;
269    
270     /* enscribe a rectangle */
271     for (i = walk->ax; i < walk->zx; i++)
272     for (j = walk->ay; j < walk->zy; j++)
273 root 1.7 if (!making_circle || ((int) (0.5 + hypot (walk->x - i, walk->y - j))) <= R)
274     maze[i][j] = '.';
275 elmex 1.1 }
276     }
277    
278 root 1.3 static void
279 root 1.7 roguelike_link_rooms (Room *rooms, char **maze, int xsize, int ysize)
280 root 1.3 {
281 elmex 1.1 Room *walk;
282 root 1.3 int i, j;
283    
284 elmex 1.1 /* link each room to the previous room */
285 root 1.7 if (rooms[1].x == 0)
286 root 1.3 return; /* only 1 room */
287 elmex 1.1
288 root 1.7 for (walk = rooms + 1; walk->x != 0; walk++)
289 root 1.3 {
290     int x1 = walk->x;
291     int y1 = walk->y;
292     int x2 = (walk - 1)->x;
293     int y2 = (walk - 1)->y;
294     int in_wall = 0;
295    
296 root 1.10 if (rmg_rndm (2))
297 root 1.3 { /* connect in x direction first */
298     /* horizontal connect */
299     /* swap (x1,y1) (x2,y2) if necessary */
300    
301     if (x2 < x1)
302     {
303     int tx = x2, ty = y2;
304    
305     x2 = x1;
306     y2 = y1;
307     x1 = tx;
308     y1 = ty;
309     }
310    
311    
312     j = y1;
313     for (i = x1; i < x2; i++)
314     {
315     if (in_wall == 0 && maze[i][j] == '#')
316     {
317     in_wall = 1;
318     maze[i][j] = 'D';
319     }
320     else if (in_wall && maze[i][j] == '.')
321     {
322     in_wall = 0;
323     maze[i - 1][j] = 'D';
324     }
325     else if (maze[i][j] != 'D' && maze[i][j] != '.')
326     maze[i][j] = 0;
327     }
328 root 1.11
329     j = min (y1, y2);
330    
331 root 1.3 if (maze[i][j] == '.')
332     in_wall = 0;
333 root 1.11
334 root 1.3 if (maze[i][j] == 0 || maze[i][j] == '#')
335     in_wall = 1;
336 root 1.11
337     for ( /* j set already */ ; j < max (y1, y2); j++)
338 root 1.3 {
339     if (in_wall == 0 && maze[i][j] == '#')
340     {
341     in_wall = 1;
342     maze[i][j] = 'D';
343     }
344     else if (in_wall && maze[i][j] == '.')
345     {
346     in_wall = 0;
347     maze[i][j - 1] = 'D';
348     }
349     else if (maze[i][j] != 'D' && maze[i][j] != '.')
350     maze[i][j] = 0;
351     }
352 elmex 1.1
353     }
354 root 1.3 else
355     { /* connect in y direction first */
356     in_wall = 0;
357     /* swap if necessary */
358     if (y2 < y1)
359     {
360     int tx = x2, ty = y2;
361    
362     x2 = x1;
363     y2 = y1;
364     x1 = tx;
365     y1 = ty;
366     }
367     i = x1;
368     /* vertical connect */
369     for (j = y1; j < y2; j++)
370     {
371     if (in_wall == 0 && maze[i][j] == '#')
372     {
373     in_wall = 1;
374     maze[i][j] = 'D';
375     }
376     else if (in_wall && maze[i][j] == '.')
377     {
378     in_wall = 0;
379     maze[i][j - 1] = 'D';
380     }
381     else if (maze[i][j] != 'D' && maze[i][j] != '.')
382     maze[i][j] = 0;
383     }
384    
385 root 1.11 i = min (x1, x2);
386    
387 root 1.3 if (maze[i][j] == '.')
388     in_wall = 0;
389 root 1.11
390 root 1.3 if (maze[i][j] == 0 || maze[i][j] == '#')
391     in_wall = 1;
392 root 1.11
393     for ( /* i set already */ ; i < max (x1, x2); i++)
394 root 1.3 {
395     if (in_wall == 0 && maze[i][j] == '#')
396     {
397     in_wall = 1;
398     maze[i][j] = 'D';
399     }
400     else if (in_wall && maze[i][j] == '.')
401     {
402     in_wall = 0;
403     maze[i - 1][j] = 'D';
404     }
405     else if (maze[i][j] != 'D' && maze[i][j] != '.')
406     maze[i][j] = 0;
407    
408     }
409 elmex 1.1
410     }
411    
412     }
413     }
414 root 1.7