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

# Content
1 /*
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 /* generate a rogue/nethack-like layout */
25 #include <global.h>
26 #include <random_map.h>
27 #include <rproto.h>
28
29 typedef struct
30 {
31 int x;
32 int y; /* coordinates of room centers */
33
34 int sx;
35 int sy; /* sizes */
36 int ax, ay, zx, zy; /* coordinates of extrema of the rectangle */
37
38 int rtype; /* circle or rectangular */
39 } Room;
40
41 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
45 int
46 surround_check (char **layout, int i, int j, int Xsize, int Ysize)
47 {
48 /* 1 = wall to left,
49 2 = wall to right,
50 4 = wall above
51 8 = wall below */
52 int surround_index = 0;
53
54 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
59 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 void
66 roguelike_layout_gen (Layout maze, int options)
67 {
68 int i, j;
69 Room *walk;
70 int nrooms = 0;
71 int tries = 0;
72
73 int xsize = maze->w;
74 int ysize = maze->h;
75
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 if (xsize < 11 || ysize < 11)
80 {
81 maze->clear ();
82 maze->border ();
83
84 maze[(xsize - 1) / 2][(ysize - 1) / 2 ] = '>';
85 maze[(xsize - 1) / 2][(ysize - 1) / 2 + 1] = '<';
86
87 return;
88 }
89
90 maze->clear ('#');
91
92 /* decide on the number of rooms */
93 nrooms = rmg_rndm (10) + 6;
94 Room *rooms = salloc0<Room> (nrooms + 1);
95
96 /* actually place the rooms */
97 i = 0;
98 while (tries < 450 && i < nrooms)
99 {
100 /* try to place the room */
101 if (!roguelike_place_room (rooms, xsize, ysize, nrooms))
102 tries++;
103 else
104 i++;
105 }
106
107 if (i == 0) /* no can do! */
108 {
109 maze->clear ();
110 maze->border ();
111
112 maze [(xsize - 1) / 2][(ysize - 1) / 2 ] = '>';
113 maze [(xsize - 1) / 2][(ysize - 1) / 2 + 1] = '<';
114
115 sfree (rooms, nrooms + 1);
116 return;
117 }
118
119 /* erase the areas occupied by the rooms */
120 roguelike_make_rooms (rooms, maze, options);
121
122 roguelike_link_rooms (rooms, maze, xsize, ysize);
123
124 /* put in the stairs */
125
126 maze[rooms->x][rooms->y] = '<';
127
128 /* get the last one */
129 for (walk = rooms; walk->x != 0; walk++)
130 ;
131
132 /* back up one */
133 walk--;
134
135 if (walk == rooms)
136 {
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 else
148 maze[walk->x][walk->y] = '>';
149
150 /* convert all the '.' to 0, we're through with the '.' */
151 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
157 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 }
170
171 sfree (rooms, nrooms + 1);
172 }
173
174 static int
175 roguelike_place_room (Room *rooms, int xsize, int ysize, int nrooms)
176 {
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 int x_basesize;
182 int y_basesize;
183 Room *walk;
184
185 /* decide on the base x and y sizes */
186 x_basesize = xsize / isqrt (nrooms);
187 y_basesize = ysize / isqrt (nrooms);
188
189 tx = rmg_rndm (xsize);
190 ty = rmg_rndm (ysize);
191
192 /* generate a distribution of sizes centered about basesize */
193 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 sy = (int) (sy * .5); /* renormalize */
196
197 /* find the corners */
198 ax = tx - sx / 2;
199 zx = tx + sx / 2 + sx % 2;
200
201 ay = ty - sy / 2;
202 zy = ty + sy / 2 + sy % 2;
203
204 /* check to see if it's in the map */
205 if (zx > xsize - 1 || ax < 1) return 0;
206 if (zy > ysize - 1 || ay < 1) return 0;
207
208 /* no small fish */
209 if (sx < 3 || sy < 3)
210 return 0;
211
212 /* check overlap with existing rooms */
213 for (walk = rooms; walk->x != 0; walk++)
214 {
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
222 /* if we've got here, presumably the room is OK. */
223
224 /* get a pointer to the first free room */
225 for (walk = rooms; walk->x != 0; walk++)
226 ;
227
228 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
237 return 1; /* success */
238 }
239
240 /* write all the rooms into the maze */
241 static void
242 roguelike_make_rooms (Room *rooms, char **maze, int options)
243 {
244 int making_circle = 0;
245 int i, j;
246 int R;
247 Room *walk;
248
249 for (walk = rooms; walk->x != 0; walk++)
250 {
251 /* first decide what shape to make */
252 switch (options)
253 {
254 case 1:
255 making_circle = 0;
256 break;
257 case 2:
258 making_circle = 1;
259 break;
260 default:
261 making_circle = ((rmg_rndm (3) == 0) ? 1 : 0);
262 break;
263 }
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 if (!making_circle || ((int) (0.5 + hypot (walk->x - i, walk->y - j))) <= R)
274 maze[i][j] = '.';
275 }
276 }
277
278 static void
279 roguelike_link_rooms (Room *rooms, char **maze, int xsize, int ysize)
280 {
281 Room *walk;
282 int i, j;
283
284 /* link each room to the previous room */
285 if (rooms[1].x == 0)
286 return; /* only 1 room */
287
288 for (walk = rooms + 1; walk->x != 0; walk++)
289 {
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 if (rmg_rndm (2))
297 { /* 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
329 j = min (y1, y2);
330
331 if (maze[i][j] == '.')
332 in_wall = 0;
333
334 if (maze[i][j] == 0 || maze[i][j] == '#')
335 in_wall = 1;
336
337 for ( /* j set already */ ; j < max (y1, y2); j++)
338 {
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
353 }
354 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 i = min (x1, x2);
386
387 if (maze[i][j] == '.')
388 in_wall = 0;
389
390 if (maze[i][j] == 0 || maze[i][j] == '#')
391 in_wall = 1;
392
393 for ( /* i set already */ ; i < max (x1, x2); i++)
394 {
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
410 }
411
412 }
413 }
414