ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/random_maps/rogue_layout.C
Revision: 1.24
Committed: Sat Nov 17 23:40:02 2018 UTC (5 years, 5 months ago) by root
Content type: text/plain
Branch: MAIN
CVS Tags: HEAD
Changes since 1.23: +1 -0 lines
Log Message:
copyright update 2018

File Contents

# Content
1 /*
2 * This file is part of Deliantra, the Roguelike Realtime MMORPG.
3 *
4 * Copyright (©) 2017,2018 Marc Alexander Lehmann / the Deliantra team
5 * Copyright (©) 2005,2006,2007,2008,2009,2010,2011,2012,2013,2014,2015,2016 Marc Alexander Lehmann / Robin Redeker / the Deliantra team
6 * Copyright (©) 1994-2004 Crossfire Development Team (restored, original file without copyright notice)
7 *
8 * Deliantra is free software: you can redistribute it and/or modify it under
9 * the terms of the Affero GNU General Public License as published by the
10 * Free Software Foundation, either version 3 of the License, or (at your
11 * option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the Affero GNU General Public License
19 * and the GNU General Public License along with this program. If not, see
20 * <http://www.gnu.org/licenses/>.
21 *
22 * The authors can be reached via e-mail to <support@deliantra.net>
23 */
24
25 /* generate a rogue/nethack-like maze */
26 #include <global.h>
27 #include <rmg.h>
28 #include <rproto.h>
29
30 typedef struct
31 {
32 int x;
33 int y; /* coordinates of room centers */
34
35 int sx;
36 int sy; /* sizes */
37 int ax, ay, zx, zy; /* coordinates of extrema of the rectangle */
38
39 int rtype; /* circle or rectangular */
40 } Room;
41
42 static int roguelike_place_room (Room *rooms, int xsize, int ysize, int nrooms);
43 static void roguelike_make_rooms (Room *rooms, char **maze, int options);
44 static void roguelike_link_rooms (Room *rooms, layout &maze);
45
46 int
47 surround_check (layout &maze, int i, int j)
48 {
49 /* 1 = wall to left,
50 2 = wall to right,
51 4 = wall above
52 8 = wall below */
53 int surround_index = 0;
54
55 if ((i > 0) && (maze[i - 1][j] != 0 && maze[i - 1][j] != '.')) surround_index |= 1;
56 if ((i < maze.w - 1) && (maze[i + 1][j] != 0 && maze[i + 1][j] != '.')) surround_index |= 2;
57 if ((j > 0) && (maze[i][j - 1] != 0 && maze[i][j - 1] != '.')) surround_index |= 4;
58 if ((j < maze.h - 1) && (maze[i][j + 1] != 0 && maze[i][j + 1] != '.')) surround_index |= 8;
59
60 return surround_index;
61 }
62
63 /* actually make the maze: we work by a reduction process:
64 * first we make everything a wall, then we remove areas to make rooms
65 */
66 void
67 roguelike_layout_gen (layout &maze, int options)
68 {
69 int i, j;
70 Room *walk;
71 int nrooms = 0;
72 int tries = 0;
73
74 int xsize = maze.w;
75 int ysize = maze.h;
76
77 /* minimum room size is basically 5x5: if xsize/ysize is
78 less than 3x that then hollow things out, stick in
79 a stairsup and stairs down, and exit */
80 if (xsize < 11 || ysize < 11)
81 {
82 maze.clear ();
83 maze.border ();
84
85 maze[(xsize - 1) / 2][(ysize - 1) / 2 ] = '>';
86 maze[(xsize - 1) / 2][(ysize - 1) / 2 + 1] = '<';
87
88 return;
89 }
90
91 maze.fill ('#');
92
93 /* decide on the number of rooms */
94 nrooms = rmg_rndm (10) + 6;
95 Room *rooms = salloc0<Room> (nrooms + 1);
96
97 /* actually place the rooms */
98 i = 0;
99 while (tries < 450 && i < nrooms)
100 {
101 /* try to place the room */
102 if (!roguelike_place_room (rooms, xsize, ysize, nrooms))
103 tries++;
104 else
105 i++;
106 }
107
108 if (i == 0) /* no can do! */
109 {
110 maze.clear ();
111 maze.border ();
112
113 maze [(xsize - 1) / 2][(ysize - 1) / 2 ] = '>';
114 maze [(xsize - 1) / 2][(ysize - 1) / 2 + 1] = '<';
115
116 sfree (rooms, nrooms + 1);
117 return;
118 }
119
120 /* erase the areas occupied by the rooms */
121 roguelike_make_rooms (rooms, maze, options);
122
123 roguelike_link_rooms (rooms, maze);
124
125 /* put in the stairs */
126
127 maze[rooms->x][rooms->y] = '<';
128
129 /* get the last one */
130 for (walk = rooms; walk->x != 0; walk++)
131 ;
132
133 /* back up one */
134 walk--;
135
136 if (walk == rooms)
137 {
138 /* In this case, there is only a single room. We don't want to
139 * clobber are up exit (above) with a down exit, so put the
140 * other exit one space up/down, depending which is a space
141 * and not a wall.
142 */
143 if (maze[walk->x][walk->y + 1] == '.')
144 maze[walk->x][walk->y + 1] = '>';
145 else
146 maze[walk->x][walk->y - 1] = '>';
147 }
148 else
149 maze[walk->x][walk->y] = '>';
150
151 /* convert all the '.' to 0, we're through with the '.' */
152 for (i = 0; i < xsize; i++)
153 for (j = 0; j < ysize; j++)
154 {
155 if (maze[i][j] == '.')
156 maze[i][j] = 0;
157
158 if (maze[i][j] == 'D')
159 { /* remove bad door. */
160 int si = surround_check (maze, i, j);
161
162 if (si != 3 && si != 12)
163 {
164 maze[i][j] = 0;
165 /* back up and recheck any nearby doors */
166 i = 0;
167 j = 0;
168 }
169 }
170 }
171
172 sfree (rooms, nrooms + 1);
173 }
174
175 static int
176 roguelike_place_room (Room *rooms, int xsize, int ysize, int nrooms)
177 {
178 int tx, ty; /* trial center locations */
179 int sx, sy; /* trial sizes */
180 int ax, ay; /* min coords of rect */
181 int zx, zy; /* max coords of rect */
182 int x_basesize;
183 int y_basesize;
184 Room *walk;
185
186 /* decide on the base x and y sizes */
187 x_basesize = xsize / isqrt (nrooms);
188 y_basesize = ysize / isqrt (nrooms);
189
190 tx = rmg_rndm (xsize);
191 ty = rmg_rndm (ysize);
192
193 /* generate a distribution of sizes centered about basesize */
194 sx = rmg_rndm (x_basesize) + rmg_rndm (x_basesize) + rmg_rndm (x_basesize);
195 sy = rmg_rndm (y_basesize) + rmg_rndm (y_basesize) + rmg_rndm (y_basesize);
196 sy >>= 1; /* renormalize */
197
198 /* find the corners */
199 ax = tx - sx / 2;
200 zx = tx + sx / 2 + sx % 2;
201
202 ay = ty - sy / 2;
203 zy = ty + sy / 2 + sy % 2;
204
205 /* check to see if it's in the map */
206 if (zx > xsize - 1 || ax < 1) return 0;
207 if (zy > ysize - 1 || ay < 1) return 0;
208
209 /* no small fish */
210 if (sx < 3 || sy < 3)
211 return 0;
212
213 /* check overlap with existing rooms */
214 for (walk = rooms; walk->x != 0; walk++)
215 {
216 int dx = abs (tx - walk->x);
217 int dy = abs (ty - walk->y);
218
219 if ((dx < (walk->sx + sx) / 2 + 2) && (dy < (walk->sy + sy) / 2 + 2))
220 return 0;
221 }
222
223 /* if we've got here, presumably the room is OK. */
224
225 /* get a pointer to the first free room */
226 for (walk = rooms; walk->x; walk++)
227 ;
228
229 walk->x = tx;
230 walk->y = ty;
231 walk->sx = sx;
232 walk->sy = sy;
233 walk->ax = ax;
234 walk->ay = ay;
235 walk->zx = zx;
236 walk->zy = zy;
237
238 return 1; /* success */
239 }
240
241 /* write all the rooms into the maze */
242 static void
243 roguelike_make_rooms (Room *rooms, char **maze, int options)
244 {
245 int making_circle = 0;
246 int R;
247 Room *walk;
248
249 for (walk = rooms; walk->x; 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 (int i = walk->ax; i < walk->zx; i++)
272 for (int 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, layout &maze)
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