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.5 by root, Thu Jan 18 19:42:10 2007 UTC vs.
Revision 1.22 by root, Wed Nov 16 23:42:02 2016 UTC

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

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines