ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/random_maps/rogue_layout.C
(Generate patch)

Comparing deliantra/server/random_maps/rogue_layout.C (file contents):
Revision 1.6 by root, Sat Jan 27 02:19:37 2007 UTC vs.
Revision 1.24 by root, Sat Nov 17 23:40:02 2018 UTC

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 */
1 24
2/* generate a rogue/nethack-like layout */ 25/* generate a rogue/nethack-like maze */
3#include <global.h> 26#include <global.h>
4#include <random_map.h>
5#include <math.h> 27#include <rmg.h>
28#include <rproto.h>
6 29
7typedef struct 30typedef struct
8{ 31{
9 int x; 32 int x;
10 int y; /* coordinates of room centers */ 33 int y; /* coordinates of room centers */
14 int ax, ay, zx, zy; /* coordinates of extrema of the rectangle */ 37 int ax, ay, zx, zy; /* coordinates of extrema of the rectangle */
15 38
16 int rtype; /* circle or rectangular */ 39 int rtype; /* circle or rectangular */
17} Room; 40} Room;
18 41
19static int roguelike_place_room (Room * Rooms, int xsize, int ysize, int nrooms); 42static int roguelike_place_room (Room *rooms, int xsize, int ysize, int nrooms);
20static void roguelike_make_rooms (Room * Rooms, char **maze, int options); 43static void roguelike_make_rooms (Room *rooms, char **maze, int options);
21static void roguelike_link_rooms (Room * Rooms, char **maze, int xsize, int ysize); 44static void roguelike_link_rooms (Room *rooms, layout &maze);
22 45
23int 46int
24surround_check (char **layout, int i, int j, int Xsize, int Ysize) 47surround_check (layout &maze, int i, int j)
25{ 48{
26 /* 1 = wall to left, 49 /* 1 = wall to left,
27 2 = wall to right, 50 2 = wall to right,
28 4 = wall above 51 4 = wall above
29 8 = wall below */ 52 8 = wall below */
30 int surround_index = 0; 53 int surround_index = 0;
31 54
32 if ((i > 0) && (layout[i - 1][j] != 0 && layout[i - 1][j] != '.')) 55 if ((i > 0) && (maze[i - 1][j] != 0 && maze[i - 1][j] != '.')) surround_index |= 1;
33 surround_index += 1; 56 if ((i < maze.w - 1) && (maze[i + 1][j] != 0 && maze[i + 1][j] != '.')) surround_index |= 2;
34 if ((i < Xsize - 1) && (layout[i + 1][j] != 0 && layout[i + 1][j] != '.')) 57 if ((j > 0) && (maze[i][j - 1] != 0 && maze[i][j - 1] != '.')) surround_index |= 4;
35 surround_index += 2; 58 if ((j < maze.h - 1) && (maze[i][j + 1] != 0 && maze[i][j + 1] != '.')) surround_index |= 8;
36 if ((j > 0) && (layout[i][j - 1] != 0 && layout[i][j - 1] != '.')) 59
37 surround_index += 4;
38 if ((j < Ysize - 1) && (layout[i][j + 1] != 0 && layout[i][j + 1] != '.'))
39 surround_index += 8;
40 return surround_index; 60 return surround_index;
41} 61}
42 62
43
44/* actually make the layout: we work by a reduction process: 63/* actually make the maze: we work by a reduction process:
45 * first we make everything a wall, then we remove areas to make rooms 64 * first we make everything a wall, then we remove areas to make rooms
46 */ 65 */
47 66void
48char ** 67roguelike_layout_gen (layout &maze, int options)
49roguelike_layout_gen (int xsize, int ysize, int options)
50{ 68{
51 int i, j; 69 int i, j;
52 Room *Rooms = 0;
53 Room *walk; 70 Room *walk;
54 int nrooms = 0; 71 int nrooms = 0;
55 int tries = 0; 72 int tries = 0;
56 73
57 /* allocate that array, write walls everywhere up */ 74 int xsize = maze.w;
58 char **maze = (char **) malloc (sizeof (char *) * xsize); 75 int ysize = maze.h;
59
60 for (i = 0; i < xsize; i++)
61 {
62 maze[i] = (char *) malloc (sizeof (char) * ysize);
63 for (j = 0; j < ysize; j++)
64 maze[i][j] = '#';
65 }
66 76
67 /* minimum room size is basically 5x5: if xsize/ysize is 77 /* minimum room size is basically 5x5: if xsize/ysize is
68 less than 3x that then hollow things out, stick in 78 less than 3x that then hollow things out, stick in
69 a stairsup and stairs down, and exit */ 79 a stairsup and stairs down, and exit */
70
71 if (xsize < 11 || ysize < 11) 80 if (xsize < 11 || ysize < 11)
72 { 81 {
73 for (i = 1; i < xsize - 1; i++) 82 maze.clear ();
74 for (j = 1; j < ysize - 1; j++) 83 maze.border ();
75 maze[i][j] = 0; 84
76 maze[(xsize - 1) / 2][(ysize - 1) / 2] = '>'; 85 maze[(xsize - 1) / 2][(ysize - 1) / 2 ] = '>';
77 maze[(xsize - 1) / 2][(ysize - 1) / 2 + 1] = '<'; 86 maze[(xsize - 1) / 2][(ysize - 1) / 2 + 1] = '<';
87
78 return maze; 88 return;
79 } 89 }
90
91 maze.fill ('#');
80 92
81 /* decide on the number of rooms */ 93 /* decide on the number of rooms */
82 nrooms = rndm (10) + 6; 94 nrooms = rmg_rndm (10) + 6;
83 Rooms = (Room *) calloc (nrooms + 1, sizeof (Room)); 95 Room *rooms = salloc0<Room> (nrooms + 1);
84 96
85 /* actually place the rooms */ 97 /* actually place the rooms */
86 i = 0; 98 i = 0;
87 while (tries < 450 && i < nrooms) 99 while (tries < 450 && i < nrooms)
88 { 100 {
89 /* try to place the room */ 101 /* try to place the room */
90 if (!roguelike_place_room (Rooms, xsize, ysize, nrooms)) 102 if (!roguelike_place_room (rooms, xsize, ysize, nrooms))
91 tries++; 103 tries++;
92 else 104 else
93 i++; 105 i++;
94 } 106 }
95 107
96 if (i == 0) 108 if (i == 0) /* no can do! */
97 { /* no can do! */ 109 {
98 for (i = 1; i < xsize - 1; i++) 110 maze.clear ();
99 for (j = 1; j < ysize - 1; j++) 111 maze.border ();
100 maze[i][j] = 0; 112
101 maze[(xsize - 1) / 2][(ysize - 1) / 2] = '>'; 113 maze [(xsize - 1) / 2][(ysize - 1) / 2 ] = '>';
102 maze[(xsize - 1) / 2][(ysize - 1) / 2 + 1] = '<'; 114 maze [(xsize - 1) / 2][(ysize - 1) / 2 + 1] = '<';
103 free (Rooms); 115
116 sfree (rooms, nrooms + 1);
104 return maze; 117 return;
105 } 118 }
106
107 119
108 /* erase the areas occupied by the rooms */ 120 /* erase the areas occupied by the rooms */
109 roguelike_make_rooms (Rooms, maze, options); 121 roguelike_make_rooms (rooms, maze, options);
110 122
111 roguelike_link_rooms (Rooms, maze, xsize, ysize); 123 roguelike_link_rooms (rooms, maze);
112 124
113 /* put in the stairs */ 125 /* put in the stairs */
114 126
115 maze[Rooms->x][Rooms->y] = '<'; 127 maze[rooms->x][rooms->y] = '<';
128
116 /* get the last one */ 129 /* get the last one */
117 for (walk = Rooms; walk->x != 0; walk++); 130 for (walk = rooms; walk->x != 0; walk++)
131 ;
132
118 /* back up one */ 133 /* back up one */
119 walk--; 134 walk--;
135
120 if (walk == Rooms) 136 if (walk == rooms)
121 { 137 {
122 /* In this case, there is only a single room. We don't want to 138 /* In this case, there is only a single room. We don't want to
123 * clobber are up exit (above) with a down exit, so put the 139 * clobber are up exit (above) with a down exit, so put the
124 * other exit one space up/down, depending which is a space 140 * other exit one space up/down, depending which is a space
125 * and not a wall. 141 * and not a wall.
136 for (i = 0; i < xsize; i++) 152 for (i = 0; i < xsize; i++)
137 for (j = 0; j < ysize; j++) 153 for (j = 0; j < ysize; j++)
138 { 154 {
139 if (maze[i][j] == '.') 155 if (maze[i][j] == '.')
140 maze[i][j] = 0; 156 maze[i][j] = 0;
157
141 if (maze[i][j] == 'D') 158 if (maze[i][j] == 'D')
142 { /* remove bad door. */ 159 { /* remove bad door. */
143 int si = surround_check (maze, i, j, xsize, ysize); 160 int si = surround_check (maze, i, j);
144 161
145 if (si != 3 && si != 12) 162 if (si != 3 && si != 12)
146 { 163 {
147 maze[i][j] = 0; 164 maze[i][j] = 0;
148 /* back up and recheck any nearby doors */ 165 /* back up and recheck any nearby doors */
150 j = 0; 167 j = 0;
151 } 168 }
152 } 169 }
153 } 170 }
154 171
155 free (Rooms); 172 sfree (rooms, nrooms + 1);
156 return maze;
157} 173}
158 174
159
160
161static int 175static int
162roguelike_place_room (Room * Rooms, int xsize, int ysize, int nrooms) 176roguelike_place_room (Room *rooms, int xsize, int ysize, int nrooms)
163{ 177{
164
165 int tx, ty; /* trial center locations */ 178 int tx, ty; /* trial center locations */
166 int sx, sy; /* trial sizes */ 179 int sx, sy; /* trial sizes */
167 int ax, ay; /* min coords of rect */ 180 int ax, ay; /* min coords of rect */
168 int zx, zy; /* max coords of rect */ 181 int zx, zy; /* max coords of rect */
169 int x_basesize; 182 int x_basesize;
170 int y_basesize; 183 int y_basesize;
171 Room *walk; 184 Room *walk;
172 185
173 /* decide on the base x and y sizes */ 186 /* decide on the base x and y sizes */
174
175 x_basesize = xsize / isqrt (nrooms); 187 x_basesize = xsize / isqrt (nrooms);
176 y_basesize = ysize / isqrt (nrooms); 188 y_basesize = ysize / isqrt (nrooms);
177 189
178 tx = rndm (xsize); 190 tx = rmg_rndm (xsize);
179 ty = rndm (ysize); 191 ty = rmg_rndm (ysize);
180 192
181 /* generate a distribution of sizes centered about basesize */ 193 /* generate a distribution of sizes centered about basesize */
182 sx = rndm (x_basesize) + rndm (x_basesize) + rndm (x_basesize); 194 sx = rmg_rndm (x_basesize) + rmg_rndm (x_basesize) + rmg_rndm (x_basesize);
183 sy = rndm (y_basesize) + rndm (y_basesize) + rndm (y_basesize); 195 sy = rmg_rndm (y_basesize) + rmg_rndm (y_basesize) + rmg_rndm (y_basesize);
184 sy = (int) (sy * .5); /* renormalize */ 196 sy >>= 1; /* renormalize */
185 197
186 /* find the corners */ 198 /* find the corners */
187 ax = tx - sx / 2; 199 ax = tx - sx / 2;
188 zx = tx + sx / 2 + sx % 2; 200 zx = tx + sx / 2 + sx % 2;
189 201
190 ay = ty - sy / 2; 202 ay = ty - sy / 2;
191 zy = ty + sy / 2 + sy % 2; 203 zy = ty + sy / 2 + sy % 2;
192 204
193 /* check to see if it's in the map */ 205 /* check to see if it's in the map */
194 if (zx > xsize - 1 || ax < 1) 206 if (zx > xsize - 1 || ax < 1) return 0;
195 return 0;
196 if (zy > ysize - 1 || ay < 1) 207 if (zy > ysize - 1 || ay < 1) return 0;
197 return 0;
198 208
199 /* no small fish */ 209 /* no small fish */
200 if (sx < 3 || sy < 3) 210 if (sx < 3 || sy < 3)
201 return 0; 211 return 0;
202 212
203 /* check overlap with existing rooms */ 213 /* check overlap with existing rooms */
204 for (walk = Rooms; walk->x != 0; walk++) 214 for (walk = rooms; walk->x != 0; walk++)
205 { 215 {
206 int dx = abs (tx - walk->x); 216 int dx = abs (tx - walk->x);
207 int dy = abs (ty - walk->y); 217 int dy = abs (ty - walk->y);
208 218
209 if ((dx < (walk->sx + sx) / 2 + 2) && (dy < (walk->sy + sy) / 2 + 2)) 219 if ((dx < (walk->sx + sx) / 2 + 2) && (dy < (walk->sy + sy) / 2 + 2))
211 } 221 }
212 222
213 /* if we've got here, presumably the room is OK. */ 223 /* if we've got here, presumably the room is OK. */
214 224
215 /* get a pointer to the first free room */ 225 /* get a pointer to the first free room */
216 for (walk = Rooms; walk->x != 0; walk++); 226 for (walk = rooms; walk->x; walk++)
227 ;
228
217 walk->x = tx; 229 walk->x = tx;
218 walk->y = ty; 230 walk->y = ty;
219 walk->sx = sx; 231 walk->sx = sx;
220 walk->sy = sy; 232 walk->sy = sy;
221 walk->ax = ax; 233 walk->ax = ax;
222 walk->ay = ay; 234 walk->ay = ay;
223 walk->zx = zx; 235 walk->zx = zx;
224 walk->zy = zy; 236 walk->zy = zy;
237
225 return 1; /* success */ 238 return 1; /* success */
226
227} 239}
228
229 240
230/* write all the rooms into the maze */ 241/* write all the rooms into the maze */
231static void 242static void
232roguelike_make_rooms (Room * Rooms, char **maze, int options) 243roguelike_make_rooms (Room *rooms, char **maze, int options)
233{ 244{
234 int making_circle = 0; 245 int making_circle = 0;
235 int i, j;
236 int R; 246 int R;
237 Room *walk; 247 Room *walk;
238 248
239 for (walk = Rooms; walk->x != 0; walk++) 249 for (walk = rooms; walk->x; walk++)
240 { 250 {
241 /* first decide what shape to make */ 251 /* first decide what shape to make */
242 switch (options) 252 switch (options)
243 { 253 {
244 case 1: 254 case 1:
246 break; 256 break;
247 case 2: 257 case 2:
248 making_circle = 1; 258 making_circle = 1;
249 break; 259 break;
250 default: 260 default:
251 making_circle = ((rndm (3) == 0) ? 1 : 0); 261 making_circle = ((rmg_rndm (3) == 0) ? 1 : 0);
252 break; 262 break;
253 } 263 }
254 264
255 if (walk->sx < walk->sy) 265 if (walk->sx < walk->sy)
256 R = walk->sx / 2; 266 R = walk->sx / 2;
257 else 267 else
258 R = walk->sy / 2; 268 R = walk->sy / 2;
259 269
260 /* enscribe a rectangle */ 270 /* enscribe a rectangle */
261 for (i = walk->ax; i < walk->zx; i++) 271 for (int i = walk->ax; i < walk->zx; i++)
262 for (j = walk->ay; j < walk->zy; j++) 272 for (int j = walk->ay; j < walk->zy; j++)
263 {
264 if (!making_circle || ((int) (0.5 + hypot (walk->x - i, walk->y - j))) <= R) 273 if (!making_circle || ((int) (0.5 + hypot (walk->x - i, walk->y - j))) <= R)
265 maze[i][j] = '.'; 274 maze[i][j] = '.';
266 }
267 } 275 }
268} 276}
269 277
270
271
272static void 278static void
273roguelike_link_rooms (Room * Rooms, char **maze, int xsize, int ysize) 279roguelike_link_rooms (Room *rooms, layout &maze)
274{ 280{
275 Room *walk; 281 Room *walk;
276 int i, j; 282 int i, j;
277 283
278 /* link each room to the previous room */ 284 /* link each room to the previous room */
279 if (Rooms[1].x == 0) 285 if (rooms[1].x == 0)
280 return; /* only 1 room */ 286 return; /* only 1 room */
281 287
282 for (walk = Rooms + 1; walk->x != 0; walk++) 288 for (walk = rooms + 1; walk->x != 0; walk++)
283 { 289 {
284 int x1 = walk->x; 290 int x1 = walk->x;
285 int y1 = walk->y; 291 int y1 = walk->y;
286 int x2 = (walk - 1)->x; 292 int x2 = (walk - 1)->x;
287 int y2 = (walk - 1)->y; 293 int y2 = (walk - 1)->y;
288 int in_wall = 0; 294 int in_wall = 0;
289 295
290 if (rndm (2)) 296 if (rmg_rndm (2))
291 { /* connect in x direction first */ 297 { /* connect in x direction first */
292 /* horizontal connect */ 298 /* horizontal connect */
293 /* swap (x1,y1) (x2,y2) if necessary */ 299 /* swap (x1,y1) (x2,y2) if necessary */
294 300
295 if (x2 < x1) 301 if (x2 < x1)
317 maze[i - 1][j] = 'D'; 323 maze[i - 1][j] = 'D';
318 } 324 }
319 else if (maze[i][j] != 'D' && maze[i][j] != '.') 325 else if (maze[i][j] != 'D' && maze[i][j] != '.')
320 maze[i][j] = 0; 326 maze[i][j] = 0;
321 } 327 }
328
322 j = MIN (y1, y2); 329 j = min (y1, y2);
330
323 if (maze[i][j] == '.') 331 if (maze[i][j] == '.')
324 in_wall = 0; 332 in_wall = 0;
333
325 if (maze[i][j] == 0 || maze[i][j] == '#') 334 if (maze[i][j] == 0 || maze[i][j] == '#')
326 in_wall = 1; 335 in_wall = 1;
336
327 for ( /* j set already */ ; j < MAX (y1, y2); j++) 337 for ( /* j set already */ ; j < max (y1, y2); j++)
328 { 338 {
329 if (in_wall == 0 && maze[i][j] == '#') 339 if (in_wall == 0 && maze[i][j] == '#')
330 { 340 {
331 in_wall = 1; 341 in_wall = 1;
332 maze[i][j] = 'D'; 342 maze[i][j] = 'D';
370 } 380 }
371 else if (maze[i][j] != 'D' && maze[i][j] != '.') 381 else if (maze[i][j] != 'D' && maze[i][j] != '.')
372 maze[i][j] = 0; 382 maze[i][j] = 0;
373 } 383 }
374 384
375 i = MIN (x1, x2); 385 i = min (x1, x2);
386
376 if (maze[i][j] == '.') 387 if (maze[i][j] == '.')
377 in_wall = 0; 388 in_wall = 0;
389
378 if (maze[i][j] == 0 || maze[i][j] == '#') 390 if (maze[i][j] == 0 || maze[i][j] == '#')
379 in_wall = 1; 391 in_wall = 1;
392
380 for ( /* i set already */ ; i < MAX (x1, x2); i++) 393 for ( /* i set already */ ; i < max (x1, x2); i++)
381 { 394 {
382 if (in_wall == 0 && maze[i][j] == '#') 395 if (in_wall == 0 && maze[i][j] == '#')
383 { 396 {
384 in_wall = 1; 397 in_wall = 1;
385 maze[i][j] = 'D'; 398 maze[i][j] = 'D';
396 409
397 } 410 }
398 411
399 } 412 }
400} 413}
414

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines