ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/random_maps/rogue_layout.C
Revision: 1.23
Committed: Sun Jan 29 02:47:05 2017 UTC (7 years, 4 months ago) by root
Content type: text/plain
Branch: MAIN
Changes since 1.22: +1 -1 lines
Log Message:
remove eol whitespace

File Contents

# User Rev Content
1 root 1.12 /*
2     * This file is part of Deliantra, the Roguelike Realtime MMORPG.
3 root 1.21 *
4 root 1.22 * Copyright (©) 2005,2006,2007,2008,2009,2010,2011,2012,2013,2014,2015,2016 Marc Alexander Lehmann / Robin Redeker / the Deliantra team
5 root 1.19 * Copyright (©) 1994-2004 Crossfire Development Team (restored, original file without copyright notice)
6 root 1.21 *
7 root 1.12 * 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 root 1.21 *
12 root 1.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 root 1.21 *
17 root 1.12 * 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 root 1.21 *
21 root 1.12 * The authors can be reached via e-mail to <support@deliantra.net>
22     */
23    
24 root 1.15 /* generate a rogue/nethack-like maze */
25 elmex 1.1 #include <global.h>
26 root 1.18 #include <rmg.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 root 1.16 static void roguelike_link_rooms (Room *rooms, layout &maze);
44 elmex 1.1
45 root 1.3 int
46 root 1.16 surround_check (layout &maze, int i, int j)
47 root 1.3 {
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.16 if ((i > 0) && (maze[i - 1][j] != 0 && maze[i - 1][j] != '.')) surround_index |= 1;
55     if ((i < maze.w - 1) && (maze[i + 1][j] != 0 && maze[i + 1][j] != '.')) surround_index |= 2;
56     if ((j > 0) && (maze[i][j - 1] != 0 && maze[i][j - 1] != '.')) surround_index |= 4;
57     if ((j < maze.h - 1) && (maze[i][j + 1] != 0 && maze[i][j + 1] != '.')) surround_index |= 8;
58 root 1.9
59 elmex 1.1 return surround_index;
60     }
61    
62 root 1.15 /* actually make the maze: we work by a reduction process:
63 root 1.23 * first we make everything a wall, then we remove areas to make rooms
64 elmex 1.1 */
65 root 1.8 void
66 root 1.15 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.14 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.14 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.14 maze.fill ('#');
91 root 1.8
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.14 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.16 roguelike_link_rooms (rooms, maze);
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 root 1.16 int si = surround_check (maze, i, j);
160 root 1.3
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.17 sy >>= 1; /* 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.17 for (walk = rooms; walk->x; walk++)
226 root 1.7 ;
227    
228 root 1.17 walk->x = tx;
229     walk->y = ty;
230 elmex 1.1 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 elmex 1.1 int R;
246     Room *walk;
247    
248 root 1.17 for (walk = rooms; walk->x; walk++)
249 root 1.3 {
250     /* first decide what shape to make */
251     switch (options)
252     {
253 root 1.4 case 1:
254     making_circle = 0;
255     break;
256     case 2:
257     making_circle = 1;
258     break;
259     default:
260 root 1.10 making_circle = ((rmg_rndm (3) == 0) ? 1 : 0);
261 root 1.4 break;
262 root 1.3 }
263    
264     if (walk->sx < walk->sy)
265     R = walk->sx / 2;
266     else
267     R = walk->sy / 2;
268    
269     /* enscribe a rectangle */
270 root 1.17 for (int i = walk->ax; i < walk->zx; i++)
271     for (int j = walk->ay; j < walk->zy; j++)
272 root 1.7 if (!making_circle || ((int) (0.5 + hypot (walk->x - i, walk->y - j))) <= R)
273     maze[i][j] = '.';
274 elmex 1.1 }
275     }
276    
277 root 1.3 static void
278 root 1.16 roguelike_link_rooms (Room *rooms, layout &maze)
279 root 1.3 {
280 elmex 1.1 Room *walk;
281 root 1.3 int i, j;
282    
283 elmex 1.1 /* link each room to the previous room */
284 root 1.7 if (rooms[1].x == 0)
285 root 1.3 return; /* only 1 room */
286 elmex 1.1
287 root 1.7 for (walk = rooms + 1; walk->x != 0; walk++)
288 root 1.3 {
289     int x1 = walk->x;
290     int y1 = walk->y;
291     int x2 = (walk - 1)->x;
292     int y2 = (walk - 1)->y;
293     int in_wall = 0;
294    
295 root 1.10 if (rmg_rndm (2))
296 root 1.3 { /* connect in x direction first */
297     /* horizontal connect */
298     /* swap (x1,y1) (x2,y2) if necessary */
299    
300     if (x2 < x1)
301     {
302     int tx = x2, ty = y2;
303    
304     x2 = x1;
305     y2 = y1;
306     x1 = tx;
307     y1 = ty;
308     }
309    
310    
311     j = y1;
312     for (i = x1; i < x2; i++)
313     {
314     if (in_wall == 0 && maze[i][j] == '#')
315     {
316     in_wall = 1;
317     maze[i][j] = 'D';
318     }
319     else if (in_wall && maze[i][j] == '.')
320     {
321     in_wall = 0;
322     maze[i - 1][j] = 'D';
323     }
324     else if (maze[i][j] != 'D' && maze[i][j] != '.')
325     maze[i][j] = 0;
326     }
327 root 1.11
328     j = min (y1, y2);
329    
330 root 1.3 if (maze[i][j] == '.')
331     in_wall = 0;
332 root 1.11
333 root 1.3 if (maze[i][j] == 0 || maze[i][j] == '#')
334     in_wall = 1;
335 root 1.11
336     for ( /* j set already */ ; j < max (y1, y2); j++)
337 root 1.3 {
338     if (in_wall == 0 && maze[i][j] == '#')
339     {
340     in_wall = 1;
341     maze[i][j] = 'D';
342     }
343     else if (in_wall && maze[i][j] == '.')
344     {
345     in_wall = 0;
346     maze[i][j - 1] = 'D';
347     }
348     else if (maze[i][j] != 'D' && maze[i][j] != '.')
349     maze[i][j] = 0;
350     }
351 elmex 1.1
352     }
353 root 1.3 else
354     { /* connect in y direction first */
355     in_wall = 0;
356     /* swap if necessary */
357     if (y2 < y1)
358     {
359     int tx = x2, ty = y2;
360    
361     x2 = x1;
362     y2 = y1;
363     x1 = tx;
364     y1 = ty;
365     }
366     i = x1;
367     /* vertical connect */
368     for (j = y1; j < y2; j++)
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][j - 1] = 'D';
379     }
380     else if (maze[i][j] != 'D' && maze[i][j] != '.')
381     maze[i][j] = 0;
382     }
383    
384 root 1.11 i = min (x1, x2);
385    
386 root 1.3 if (maze[i][j] == '.')
387     in_wall = 0;
388 root 1.11
389 root 1.3 if (maze[i][j] == 0 || maze[i][j] == '#')
390     in_wall = 1;
391 root 1.11
392     for ( /* i set already */ ; i < max (x1, x2); i++)
393 root 1.3 {
394     if (in_wall == 0 && maze[i][j] == '#')
395     {
396     in_wall = 1;
397     maze[i][j] = 'D';
398     }
399     else if (in_wall && maze[i][j] == '.')
400     {
401     in_wall = 0;
402     maze[i - 1][j] = 'D';
403     }
404     else if (maze[i][j] != 'D' && maze[i][j] != '.')
405     maze[i][j] = 0;
406    
407     }
408 elmex 1.1
409     }
410    
411     }
412     }
413 root 1.7