1 |
elmex |
1.1 |
/* |
2 |
root |
1.31 |
* This file is part of Deliantra, the Roguelike Realtime MMORPG. |
3 |
pippijn |
1.20 |
* |
4 |
root |
1.47 |
* Copyright (©) 2005,2006,2007,2008,2009,2010 Marc Alexander Lehmann / Robin Redeker / the Deliantra team |
5 |
root |
1.46 |
* Copyright (©) 2001 Mark Wedel & Crossfire Development Team |
6 |
|
|
* Copyright (©) 1992 Frank Tore Johansen |
7 |
pippijn |
1.20 |
* |
8 |
root |
1.42 |
* 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 |
pippijn |
1.20 |
* |
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 |
root |
1.30 |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
16 |
pippijn |
1.20 |
* GNU General Public License for more details. |
17 |
|
|
* |
18 |
root |
1.42 |
* 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 |
root |
1.30 |
* |
22 |
root |
1.31 |
* The authors can be reached via e-mail to <support@deliantra.net> |
23 |
pippijn |
1.20 |
*/ |
24 |
elmex |
1.1 |
|
25 |
|
|
#include <time.h> |
26 |
|
|
#include <stdio.h> |
27 |
|
|
#include <global.h> |
28 |
|
|
#include <random_map.h> |
29 |
|
|
#include <rproto.h> |
30 |
|
|
#include <sproto.h> |
31 |
|
|
|
32 |
root |
1.39 |
#define CEDE coroapi::cede_to_tick () |
33 |
root |
1.22 |
|
34 |
root |
1.34 |
static void symmetrize_layout (Layout maze, random_map_params *RP); |
35 |
|
|
static void rotate_layout (Layout maze, int rotation); |
36 |
root |
1.33 |
|
37 |
root |
1.55 |
noinline SV * |
38 |
|
|
random_map_params::get_sv (const char *option) const |
39 |
root |
1.51 |
{ |
40 |
|
|
SV **he = hv_fetch (hv, option, strlen (option), 0); |
41 |
|
|
|
42 |
root |
1.55 |
return he ? *he : 0; |
43 |
root |
1.51 |
} |
44 |
|
|
|
45 |
root |
1.55 |
noinline const_utf8_string |
46 |
|
|
random_map_params::get_str (const char *option, const_utf8_string fallback) const |
47 |
|
|
{ |
48 |
|
|
SV *sv = get_sv (option); |
49 |
|
|
return sv ? cfSvPVutf8_nolen (sv) : fallback; |
50 |
|
|
} |
51 |
|
|
|
52 |
|
|
noinline IV |
53 |
root |
1.51 |
random_map_params::get_iv (const char *option, IV fallback) const |
54 |
|
|
{ |
55 |
root |
1.55 |
SV *sv = get_sv (option); |
56 |
|
|
return sv ? SvIV (sv) : fallback; |
57 |
|
|
} |
58 |
|
|
|
59 |
|
|
noinline UV |
60 |
|
|
random_map_params::get_uv (const char *option, UV fallback) const |
61 |
|
|
{ |
62 |
|
|
SV *sv = get_sv (option); |
63 |
|
|
return sv ? SvUV (sv) : fallback; |
64 |
|
|
} |
65 |
|
|
|
66 |
|
|
noinline NV |
67 |
|
|
random_map_params::get_nv (const char *option, NV fallback) const |
68 |
|
|
{ |
69 |
|
|
SV *sv = get_sv (option); |
70 |
|
|
return sv ? SvNV (sv) : fallback; |
71 |
|
|
} |
72 |
|
|
|
73 |
|
|
noinline void |
74 |
|
|
random_map_params::set (const char *option, SV *value) const |
75 |
|
|
{ |
76 |
|
|
int len = strlen (option); |
77 |
|
|
|
78 |
|
|
if (value) |
79 |
|
|
hv_store (hv, option, len, value, 0); |
80 |
|
|
else |
81 |
|
|
hv_delete (hv, option, len, G_DISCARD); |
82 |
|
|
} |
83 |
|
|
|
84 |
|
|
noinline void |
85 |
|
|
random_map_params::set (const char *option, const_utf8_string value) const |
86 |
|
|
{ |
87 |
|
|
set (option, value && *value ? newSVpvn_utf8 (value, strlen (value), 1) : 0); |
88 |
|
|
} |
89 |
|
|
|
90 |
|
|
void |
91 |
|
|
random_map_params::set (const char *option, IV value) const |
92 |
|
|
{ |
93 |
|
|
set (option, newSViv (value)); |
94 |
|
|
} |
95 |
|
|
|
96 |
|
|
void |
97 |
|
|
random_map_params::set (const char *option, UV value) const |
98 |
|
|
{ |
99 |
|
|
set (option, newSVuv (value)); |
100 |
|
|
} |
101 |
|
|
|
102 |
|
|
void |
103 |
|
|
random_map_params::set (const char *option, NV value) const |
104 |
|
|
{ |
105 |
|
|
set (option, newSVnv (value)); |
106 |
|
|
} |
107 |
|
|
|
108 |
|
|
void |
109 |
|
|
random_map_params::hv_clone () |
110 |
|
|
{ |
111 |
|
|
HV *copy = newHV (); |
112 |
|
|
|
113 |
|
|
hv_iterinit (hv); |
114 |
|
|
|
115 |
|
|
// does not work for utf-8 keys |
116 |
|
|
while (HE *he = hv_iternext (hv)) |
117 |
|
|
{ |
118 |
|
|
STRLEN klen; const char *key = HePV (he, klen); |
119 |
|
|
hv_store (copy, key, klen, newSVsv (HeVAL (he)), HeHASH (he)); |
120 |
|
|
} |
121 |
|
|
|
122 |
|
|
SvREFCNT_dec (hv); |
123 |
|
|
hv = copy; |
124 |
|
|
} |
125 |
|
|
|
126 |
|
|
shstr_tmp |
127 |
|
|
random_map_params::as_shstr () const |
128 |
|
|
{ |
129 |
|
|
set ("xsize" , xsize); |
130 |
|
|
set ("ysize" , ysize); |
131 |
|
|
set ("monsterstyle" , monsterstyle); |
132 |
|
|
set ("exit_on_final_map" , exit_on_final_map); |
133 |
|
|
set ("layoutstyle" , layoutstyle); |
134 |
|
|
set ("doorstyle" , doorstyle); |
135 |
|
|
set ("final_map" , final_map); |
136 |
|
|
set ("this_map" , this_map); |
137 |
|
|
set ("expand2x" , expand2x); |
138 |
|
|
set ("layoutoptions1" , layoutoptions1); |
139 |
|
|
set ("layoutoptions2" , layoutoptions2); |
140 |
|
|
set ("layoutoptions3" , layoutoptions3); |
141 |
|
|
set ("symmetry" , symmetry); |
142 |
|
|
set ("dungeon_depth" , dungeon_depth); |
143 |
|
|
set ("orientation" , orientation); |
144 |
|
|
set ("origin_x" , origin_x); |
145 |
|
|
set ("origin_y" , origin_y); |
146 |
|
|
set ("random_seed" , (UV)random_seed); |
147 |
|
|
set ("difficulty" , difficulty && difficulty_given ? difficulty : 0); |
148 |
|
|
set ("difficulty_increase", difficulty_increase); |
149 |
|
|
set ("dungeon_level" , dungeon_level); |
150 |
|
|
|
151 |
|
|
dynbuf_text buf; |
152 |
|
|
hv_iterinit (hv); |
153 |
|
|
|
154 |
|
|
// does not work for utf-8 keys |
155 |
|
|
while (HE *he = hv_iternext (hv)) |
156 |
|
|
{ |
157 |
|
|
STRLEN klen; const char *key = HePV (he, klen); |
158 |
|
|
STRLEN vlen; const char *value = SvPVutf8 (HeVAL (he), vlen); |
159 |
|
|
|
160 |
|
|
buf.fadd (key, klen); |
161 |
|
|
buf << ' '; |
162 |
|
|
buf.fadd (value, vlen); |
163 |
|
|
buf << '\n'; |
164 |
|
|
} |
165 |
root |
1.51 |
|
166 |
root |
1.55 |
return shstr (buf); |
167 |
root |
1.51 |
} |
168 |
|
|
|
169 |
|
|
random_map_params::~random_map_params () |
170 |
|
|
{ |
171 |
|
|
SvREFCNT_dec (hv); |
172 |
|
|
} |
173 |
|
|
|
174 |
root |
1.34 |
/* takes a map and makes it symmetric: adjusts Xsize and |
175 |
|
|
* Ysize to produce a symmetric map. |
176 |
|
|
*/ |
177 |
root |
1.33 |
static void |
178 |
root |
1.34 |
symmetrize_layout (Layout layout, random_map_params *RP) |
179 |
root |
1.3 |
{ |
180 |
root |
1.33 |
if (RP->symmetry_used == SYMMETRY_NONE) |
181 |
|
|
return; |
182 |
root |
1.32 |
|
183 |
root |
1.34 |
Layout sym_layout ( |
184 |
|
|
RP->symmetry_used == SYMMETRY_X || RP->symmetry_used == SYMMETRY_XY ? layout->w * 2 - 3 : layout->w, |
185 |
|
|
RP->symmetry_used == SYMMETRY_Y || RP->symmetry_used == SYMMETRY_XY ? layout->h * 2 - 3 : layout->h |
186 |
root |
1.33 |
); |
187 |
root |
1.32 |
|
188 |
root |
1.33 |
if (RP->symmetry_used == SYMMETRY_X) |
189 |
root |
1.34 |
for (int i = 0; i < sym_layout->w / 2 + 1; i++) |
190 |
|
|
for (int j = 0; j < sym_layout->h; j++) |
191 |
root |
1.3 |
{ |
192 |
root |
1.34 |
sym_layout[i ][j] = |
193 |
|
|
sym_layout[sym_layout->w - i - 1][j] = layout[i][j]; |
194 |
root |
1.32 |
} |
195 |
|
|
|
196 |
root |
1.33 |
if (RP->symmetry_used == SYMMETRY_Y) |
197 |
root |
1.34 |
for (int i = 0; i < sym_layout->w; i++) |
198 |
|
|
for (int j = 0; j < sym_layout->h / 2 + 1; j++) |
199 |
root |
1.3 |
{ |
200 |
root |
1.34 |
sym_layout[i][j ] = |
201 |
|
|
sym_layout[i][sym_layout->h - j - 1] = layout[i][j]; |
202 |
root |
1.3 |
} |
203 |
root |
1.32 |
|
204 |
root |
1.33 |
if (RP->symmetry_used == SYMMETRY_XY) |
205 |
root |
1.34 |
for (int i = 0; i < sym_layout->w / 2 + 1; i++) |
206 |
|
|
for (int j = 0; j < sym_layout->h / 2 + 1; j++) |
207 |
root |
1.3 |
{ |
208 |
root |
1.34 |
sym_layout[i ][j ] = |
209 |
|
|
sym_layout[i ][sym_layout->h - j - 1] = |
210 |
|
|
sym_layout[sym_layout->w - i - 1][j ] = |
211 |
|
|
sym_layout[sym_layout->w - i - 1][sym_layout->h - j - 1] = layout[i][j]; |
212 |
root |
1.3 |
} |
213 |
root |
1.32 |
|
214 |
root |
1.34 |
layout.swap (sym_layout); |
215 |
|
|
sym_layout.free (); |
216 |
root |
1.32 |
|
217 |
elmex |
1.1 |
/* reconnect disjointed spirals */ |
218 |
root |
1.34 |
/* reconnect disjointed nethacklayouts: the routine for |
219 |
root |
1.3 |
spirals will do the trick? */ |
220 |
root |
1.33 |
if (RP->map_layout_style == LAYOUT_SPIRAL |
221 |
|
|
|| RP->map_layout_style == LAYOUT_ROGUELIKE) |
222 |
root |
1.34 |
connect_spirals (layout->w, layout->h, RP->symmetry_used, layout); |
223 |
elmex |
1.1 |
} |
224 |
|
|
|
225 |
|
|
/* takes a map and rotates it. This completes the |
226 |
|
|
onion layouts, making them possibly centered on any wall. |
227 |
|
|
It'll modify Xsize and Ysize if they're swapped. |
228 |
|
|
*/ |
229 |
root |
1.33 |
static void |
230 |
root |
1.34 |
rotate_layout (Layout layout, int rotation) |
231 |
root |
1.3 |
{ |
232 |
root |
1.34 |
int w = layout->w; |
233 |
|
|
int h = layout->h; |
234 |
|
|
|
235 |
root |
1.3 |
switch (rotation) |
236 |
|
|
{ |
237 |
root |
1.13 |
case 2: /* a reflection */ |
238 |
root |
1.11 |
{ |
239 |
root |
1.34 |
Layout new_layout (w, h); |
240 |
root |
1.32 |
|
241 |
root |
1.34 |
for (int i = 0; i < w; i++) /* copy a reflection back */ |
242 |
|
|
for (int j = 0; j < h; j++) |
243 |
|
|
new_layout[i][j] = layout[w - i - 1][h - j - 1]; |
244 |
root |
1.11 |
|
245 |
root |
1.34 |
layout.swap (new_layout); |
246 |
|
|
new_layout.free (); |
247 |
root |
1.11 |
} |
248 |
root |
1.34 |
break; |
249 |
root |
1.32 |
|
250 |
root |
1.11 |
case 1: |
251 |
|
|
case 3: |
252 |
|
|
{ |
253 |
root |
1.34 |
Layout new_layout (h, w); |
254 |
root |
1.32 |
|
255 |
root |
1.13 |
if (rotation == 1) /* swap x and y */ |
256 |
root |
1.34 |
for (int i = 0; i < w; i++) |
257 |
|
|
for (int j = 0; j < h; j++) |
258 |
|
|
new_layout[j][i] = layout[i][j]; |
259 |
root |
1.3 |
|
260 |
root |
1.32 |
if (rotation == 3) /* swap x and y */ |
261 |
root |
1.34 |
for (int i = 0; i < w; i++) |
262 |
|
|
for (int j = 0; j < h; j++) |
263 |
|
|
new_layout[j][i] = layout[w - i - 1][h - j - 1]; |
264 |
root |
1.33 |
|
265 |
root |
1.34 |
layout.swap (new_layout); |
266 |
|
|
new_layout.free (); |
267 |
root |
1.11 |
} |
268 |
root |
1.34 |
break; |
269 |
elmex |
1.1 |
} |
270 |
|
|
} |
271 |
|
|
|
272 |
|
|
/* checks the layout to see if I can stick a horizontal(dir = 0) wall |
273 |
|
|
(or vertical, dir == 1) |
274 |
|
|
here which ends up on other walls sensibly. */ |
275 |
root |
1.44 |
static int |
276 |
root |
1.13 |
can_make_wall (char **maze, int dx, int dy, int dir, random_map_params *RP) |
277 |
root |
1.3 |
{ |
278 |
elmex |
1.1 |
int i1; |
279 |
root |
1.3 |
int length = 0; |
280 |
elmex |
1.1 |
|
281 |
|
|
/* dont make walls if we're on the edge. */ |
282 |
root |
1.3 |
if (dx == 0 || dx == (RP->Xsize - 1) || dy == 0 || dy == (RP->Ysize - 1)) |
283 |
|
|
return -1; |
284 |
elmex |
1.1 |
|
285 |
|
|
/* don't make walls if we're ON a wall. */ |
286 |
root |
1.3 |
if (maze[dx][dy] != 0) |
287 |
|
|
return -1; |
288 |
elmex |
1.1 |
|
289 |
root |
1.3 |
if (dir == 0) /* horizontal */ |
290 |
elmex |
1.1 |
{ |
291 |
|
|
int y = dy; |
292 |
root |
1.3 |
|
293 |
|
|
for (i1 = dx - 1; i1 > 0; i1--) |
294 |
|
|
{ |
295 |
|
|
int sindex = surround_flag2 (maze, i1, y, RP); |
296 |
|
|
|
297 |
|
|
if (sindex == 1) |
298 |
|
|
break; |
299 |
|
|
if (sindex != 0) |
300 |
|
|
return -1; /* can't make horiz. wall here */ |
301 |
|
|
if (maze[i1][y] != 0) |
302 |
|
|
return -1; /* can't make horiz. wall here */ |
303 |
|
|
length++; |
304 |
|
|
} |
305 |
|
|
|
306 |
|
|
for (i1 = dx + 1; i1 < RP->Xsize - 1; i1++) |
307 |
|
|
{ |
308 |
|
|
int sindex = surround_flag2 (maze, i1, y, RP); |
309 |
|
|
|
310 |
|
|
if (sindex == 2) |
311 |
|
|
break; |
312 |
|
|
if (sindex != 0) |
313 |
|
|
return -1; /* can't make horiz. wall here */ |
314 |
|
|
if (maze[i1][y] != 0) |
315 |
|
|
return -1; /* can't make horiz. wall here */ |
316 |
|
|
length++; |
317 |
|
|
} |
318 |
elmex |
1.1 |
return length; |
319 |
|
|
} |
320 |
root |
1.3 |
else |
321 |
|
|
{ /* vertical */ |
322 |
|
|
int x = dx; |
323 |
|
|
|
324 |
|
|
for (i1 = dy - 1; i1 > 0; i1--) |
325 |
|
|
{ |
326 |
|
|
int sindex = surround_flag2 (maze, x, i1, RP); |
327 |
|
|
|
328 |
|
|
if (sindex == 4) |
329 |
|
|
break; |
330 |
|
|
if (sindex != 0) |
331 |
|
|
return -1; /* can't make vert. wall here */ |
332 |
|
|
if (maze[x][i1] != 0) |
333 |
|
|
return -1; /* can't make horiz. wall here */ |
334 |
|
|
length++; |
335 |
|
|
} |
336 |
|
|
|
337 |
|
|
for (i1 = dy + 1; i1 < RP->Ysize - 1; i1++) |
338 |
|
|
{ |
339 |
root |
1.43 |
int sindex = surround_flag2 (maze, x, i1, RP); |
340 |
|
|
|
341 |
|
|
if (sindex == 8) |
342 |
|
|
break; |
343 |
|
|
if (sindex != 0) |
344 |
|
|
return -1; /* can't make verti. wall here */ |
345 |
|
|
if (maze[x][i1] != 0) |
346 |
|
|
return -1; /* can't make horiz. wall here */ |
347 |
|
|
length++; |
348 |
|
|
} |
349 |
|
|
|
350 |
|
|
return length; |
351 |
|
|
} |
352 |
|
|
|
353 |
|
|
return -1; |
354 |
|
|
} |
355 |
|
|
|
356 |
|
|
/* take a layout and make some rooms in it. |
357 |
|
|
--works best on onions.*/ |
358 |
root |
1.44 |
static void |
359 |
root |
1.43 |
roomify_layout (char **maze, random_map_params *RP) |
360 |
|
|
{ |
361 |
|
|
int tries = RP->Xsize * RP->Ysize / 30; |
362 |
|
|
|
363 |
root |
1.50 |
for (int ti = 0; ti < tries; ti++) |
364 |
root |
1.43 |
{ |
365 |
root |
1.50 |
/* starting location for looking at creating a door */ |
366 |
|
|
int dx = rmg_rndm (RP->Xsize); |
367 |
|
|
int dy = rmg_rndm (RP->Ysize); |
368 |
|
|
|
369 |
|
|
/* results of checking on creating walls. */ |
370 |
|
|
int cx = can_make_wall (maze, dx, dy, 0, RP); /* horizontal */ |
371 |
|
|
int cy = can_make_wall (maze, dx, dy, 1, RP); /* vertical */ |
372 |
root |
1.43 |
|
373 |
|
|
if (cx == -1) |
374 |
|
|
{ |
375 |
|
|
if (cy != -1) |
376 |
|
|
make_wall (maze, dx, dy, 1); |
377 |
|
|
|
378 |
|
|
continue; |
379 |
|
|
} |
380 |
|
|
|
381 |
|
|
if (cy == -1) |
382 |
|
|
{ |
383 |
|
|
make_wall (maze, dx, dy, 0); |
384 |
|
|
continue; |
385 |
|
|
} |
386 |
root |
1.3 |
|
387 |
root |
1.43 |
if (cx < cy) |
388 |
|
|
make_wall (maze, dx, dy, 0); |
389 |
|
|
else |
390 |
|
|
make_wall (maze, dx, dy, 1); |
391 |
elmex |
1.1 |
} |
392 |
|
|
} |
393 |
|
|
|
394 |
root |
1.3 |
int |
395 |
|
|
make_wall (char **maze, int x, int y, int dir) |
396 |
|
|
{ |
397 |
|
|
maze[x][y] = 'D'; /* mark a door */ |
398 |
root |
1.50 |
|
399 |
root |
1.3 |
switch (dir) |
400 |
elmex |
1.1 |
{ |
401 |
root |
1.13 |
case 0: /* horizontal */ |
402 |
|
|
{ |
403 |
root |
1.50 |
for (int i1 = x - 1; maze[i1][y] == 0; --i1) maze[i1][y] = '#'; |
404 |
|
|
for (int i1 = x + 1; maze[i1][y] == 0; ++i1) maze[i1][y] = '#'; |
405 |
root |
1.13 |
break; |
406 |
|
|
} |
407 |
|
|
case 1: /* vertical */ |
408 |
|
|
{ |
409 |
root |
1.50 |
for (int i1 = y - 1; maze[x][i1] == 0; --i1) maze[x][i1] = '#'; |
410 |
|
|
for (int i1 = y + 1; maze[x][i1] == 0; ++i1) maze[x][i1] = '#'; |
411 |
root |
1.13 |
break; |
412 |
|
|
} |
413 |
elmex |
1.1 |
} |
414 |
|
|
|
415 |
|
|
return 0; |
416 |
|
|
} |
417 |
|
|
|
418 |
|
|
/* puts doors at appropriate locations in a layout. */ |
419 |
root |
1.44 |
static void |
420 |
root |
1.13 |
doorify_layout (char **maze, random_map_params *RP) |
421 |
root |
1.3 |
{ |
422 |
|
|
int ndoors = RP->Xsize * RP->Ysize / 60; /* reasonable number of doors. */ |
423 |
|
|
int doorlocs = 0; /* # of available doorlocations */ |
424 |
|
|
|
425 |
root |
1.41 |
uint16 *doorlist_x = salloc<uint16> (RP->Xsize * RP->Ysize); |
426 |
|
|
uint16 *doorlist_y = salloc<uint16> (RP->Xsize * RP->Ysize); |
427 |
elmex |
1.1 |
|
428 |
|
|
/* make a list of possible door locations */ |
429 |
root |
1.41 |
for (int i = 1; i < RP->Xsize - 1; i++) |
430 |
|
|
for (int j = 1; j < RP->Ysize - 1; j++) |
431 |
root |
1.3 |
{ |
432 |
|
|
int sindex = surround_flag (maze, i, j, RP); |
433 |
|
|
|
434 |
|
|
if (sindex == 3 || sindex == 12) /* these are possible door sindex */ |
435 |
|
|
{ |
436 |
|
|
doorlist_x[doorlocs] = i; |
437 |
|
|
doorlist_y[doorlocs] = j; |
438 |
|
|
doorlocs++; |
439 |
|
|
} |
440 |
|
|
} |
441 |
root |
1.12 |
|
442 |
root |
1.3 |
while (ndoors > 0 && doorlocs > 0) |
443 |
|
|
{ |
444 |
root |
1.41 |
int di = rmg_rndm (doorlocs); |
445 |
|
|
int i = doorlist_x[di]; |
446 |
|
|
int j = doorlist_y[di]; |
447 |
|
|
int sindex = surround_flag (maze, i, j, RP); |
448 |
root |
1.27 |
|
449 |
root |
1.3 |
if (sindex == 3 || sindex == 12) /* these are possible door sindex */ |
450 |
|
|
{ |
451 |
|
|
maze[i][j] = 'D'; |
452 |
|
|
ndoors--; |
453 |
elmex |
1.1 |
} |
454 |
root |
1.27 |
|
455 |
root |
1.3 |
/* reduce the size of the list */ |
456 |
|
|
doorlocs--; |
457 |
|
|
doorlist_x[di] = doorlist_x[doorlocs]; |
458 |
|
|
doorlist_y[di] = doorlist_y[doorlocs]; |
459 |
elmex |
1.1 |
} |
460 |
root |
1.12 |
|
461 |
root |
1.32 |
sfree (doorlist_x, RP->Xsize * RP->Ysize); |
462 |
|
|
sfree (doorlist_y, RP->Xsize * RP->Ysize); |
463 |
elmex |
1.1 |
} |
464 |
|
|
|
465 |
root |
1.43 |
/* function selects the layout function and gives it whatever |
466 |
|
|
arguments it needs. */ |
467 |
root |
1.44 |
static Layout |
468 |
root |
1.43 |
layoutgen (random_map_params *RP) |
469 |
|
|
{ |
470 |
|
|
Layout layout (RP); |
471 |
|
|
|
472 |
|
|
switch (RP->map_layout_style) |
473 |
|
|
{ |
474 |
|
|
case LAYOUT_ONION: |
475 |
|
|
map_gen_onion (layout, RP->layoutoptions1, RP->layoutoptions2); |
476 |
|
|
|
477 |
root |
1.50 |
if (!(rmg_rndm (3)) && !(RP->layoutoptions1 & (RMOPT_WALLS_ONLY | RMOPT_WALL_OFF))) |
478 |
root |
1.43 |
roomify_layout (layout, RP); |
479 |
|
|
|
480 |
|
|
break; |
481 |
|
|
|
482 |
|
|
case LAYOUT_MAZE: |
483 |
root |
1.54 |
maze_gen (layout, RP->get_iv ("maze_type", rmg_rndm (4))); |
484 |
root |
1.43 |
|
485 |
|
|
if (!(rmg_rndm (2))) |
486 |
|
|
doorify_layout (layout, RP); |
487 |
|
|
|
488 |
|
|
break; |
489 |
|
|
|
490 |
|
|
case LAYOUT_SPIRAL: |
491 |
|
|
map_gen_spiral (layout, RP->layoutoptions1); |
492 |
|
|
|
493 |
|
|
if (!(rmg_rndm (2))) |
494 |
|
|
doorify_layout (layout, RP); |
495 |
|
|
|
496 |
|
|
break; |
497 |
|
|
|
498 |
|
|
case LAYOUT_ROGUELIKE: |
499 |
|
|
/* Don't put symmetry in rogue maps. There isn't much reason to |
500 |
|
|
* do so in the first place (doesn't make it any more interesting), |
501 |
|
|
* but more importantly, the symmetry code presumes we are symmetrizing |
502 |
|
|
* spirals, or maps with lots of passages - making a symmetric rogue |
503 |
|
|
* map fails because its likely that the passages the symmetry process |
504 |
|
|
* creates may not connect the rooms. |
505 |
|
|
*/ |
506 |
|
|
RP->symmetry_used = SYMMETRY_NONE; |
507 |
|
|
roguelike_layout_gen (layout, RP->layoutoptions1); |
508 |
|
|
/* no doorifying... done already */ |
509 |
|
|
break; |
510 |
|
|
|
511 |
|
|
case LAYOUT_SNAKE: |
512 |
|
|
make_snake_layout (layout, RP->layoutoptions1); |
513 |
|
|
|
514 |
|
|
if (rmg_rndm (2)) |
515 |
|
|
roomify_layout (layout, RP); |
516 |
|
|
|
517 |
|
|
break; |
518 |
|
|
|
519 |
|
|
case LAYOUT_SQUARE_SPIRAL: |
520 |
|
|
make_square_spiral_layout (layout, RP->layoutoptions1); |
521 |
|
|
|
522 |
|
|
if (rmg_rndm (2)) |
523 |
|
|
roomify_layout (layout, RP); |
524 |
|
|
|
525 |
|
|
break; |
526 |
|
|
|
527 |
root |
1.57 |
case LAYOUT_CAVE: |
528 |
|
|
layout->gen_cave (RP->get_iv ("cave_type", rmg_rndm (4))); |
529 |
|
|
|
530 |
|
|
if (!(rmg_rndm (2))) |
531 |
|
|
doorify_layout (layout, RP); |
532 |
|
|
|
533 |
|
|
break; |
534 |
|
|
|
535 |
root |
1.43 |
default: |
536 |
|
|
abort (); |
537 |
|
|
} |
538 |
|
|
|
539 |
|
|
/* rotate the layout randomly */ |
540 |
|
|
rotate_layout (layout, rmg_rndm (4)); |
541 |
|
|
|
542 |
|
|
symmetrize_layout (layout, RP); |
543 |
|
|
|
544 |
|
|
#ifdef RMAP_DEBUG |
545 |
|
|
dump_layout (layout); |
546 |
|
|
#endif |
547 |
|
|
|
548 |
|
|
if (RP->expand2x) |
549 |
|
|
expand2x (layout); |
550 |
|
|
|
551 |
|
|
return layout; |
552 |
|
|
} |
553 |
|
|
|
554 |
|
|
bool |
555 |
|
|
maptile::generate_random_map (random_map_params *RP) |
556 |
|
|
{ |
557 |
|
|
RP->Xsize = RP->xsize; |
558 |
|
|
RP->Ysize = RP->ysize; |
559 |
|
|
|
560 |
|
|
/* pick a random seed, or use the one from the input file */ |
561 |
|
|
RP->random_seed = RP->random_seed |
562 |
|
|
? RP->random_seed + RP->dungeon_level |
563 |
|
|
: time (0); |
564 |
|
|
|
565 |
|
|
// we run "single-threaded" |
566 |
|
|
rmg_rndm.seed (RP->random_seed); |
567 |
|
|
|
568 |
root |
1.55 |
shstr buf = RP->as_shstr (); |
569 |
root |
1.43 |
|
570 |
|
|
if (RP->difficulty == 0) |
571 |
|
|
{ |
572 |
|
|
RP->difficulty = RP->dungeon_level; /* use this instead of a map difficulty */ |
573 |
|
|
|
574 |
|
|
if (RP->difficulty_increase > 0.001) |
575 |
|
|
RP->difficulty = (int) ((float) RP->dungeon_level * RP->difficulty_increase); |
576 |
|
|
|
577 |
|
|
if (RP->difficulty < 1) |
578 |
|
|
RP->difficulty = 1; |
579 |
|
|
} |
580 |
|
|
else |
581 |
|
|
RP->difficulty_given = 1; |
582 |
|
|
|
583 |
|
|
if (RP->Xsize < MIN_RANDOM_MAP_SIZE) |
584 |
|
|
RP->Xsize = MIN_RANDOM_MAP_SIZE + rmg_rndm (25) + 5; |
585 |
|
|
|
586 |
|
|
if (RP->Ysize < MIN_RANDOM_MAP_SIZE) |
587 |
|
|
RP->Ysize = MIN_RANDOM_MAP_SIZE + rmg_rndm (25) + 5; |
588 |
|
|
|
589 |
|
|
if (RP->symmetry == SYMMETRY_RANDOM) |
590 |
|
|
RP->symmetry_used = rmg_rndm (SYMMETRY_XY) + 1; |
591 |
|
|
else |
592 |
|
|
RP->symmetry_used = RP->symmetry; |
593 |
|
|
|
594 |
|
|
if (RP->symmetry_used == SYMMETRY_Y || RP->symmetry_used == SYMMETRY_XY) |
595 |
|
|
RP->Ysize = RP->Ysize / 2 + 1; |
596 |
|
|
|
597 |
|
|
if (RP->symmetry_used == SYMMETRY_X || RP->symmetry_used == SYMMETRY_XY) |
598 |
|
|
RP->Xsize = RP->Xsize / 2 + 1; |
599 |
|
|
|
600 |
|
|
if (RP->expand2x > 0) |
601 |
|
|
{ |
602 |
|
|
RP->Xsize /= 2; |
603 |
|
|
RP->Ysize /= 2; |
604 |
|
|
} |
605 |
|
|
|
606 |
|
|
RP->map_layout_style = LAYOUT_NONE; |
607 |
|
|
|
608 |
|
|
/* Redo this - there was a lot of redundant code of checking for preset |
609 |
|
|
* layout style and then random layout style. Instead, figure out |
610 |
|
|
* the numeric layoutstyle, so there is only one area that actually |
611 |
|
|
* calls the code to make the maps. |
612 |
|
|
*/ |
613 |
|
|
if (strstr (RP->layoutstyle, "onion")) |
614 |
|
|
RP->map_layout_style = LAYOUT_ONION; |
615 |
|
|
else if (strstr (RP->layoutstyle, "maze")) |
616 |
|
|
RP->map_layout_style = LAYOUT_MAZE; |
617 |
|
|
else if (strstr (RP->layoutstyle, "spiral")) |
618 |
|
|
RP->map_layout_style = LAYOUT_SPIRAL; |
619 |
|
|
else if (strstr (RP->layoutstyle, "rogue")) |
620 |
|
|
RP->map_layout_style = LAYOUT_ROGUELIKE; |
621 |
|
|
else if (strstr (RP->layoutstyle, "snake")) |
622 |
|
|
RP->map_layout_style = LAYOUT_SNAKE; |
623 |
|
|
else if (strstr (RP->layoutstyle, "squarespiral")) |
624 |
|
|
RP->map_layout_style = LAYOUT_SQUARE_SPIRAL; |
625 |
root |
1.57 |
else if (strstr (RP->layoutstyle, "cave")) |
626 |
|
|
RP->map_layout_style = LAYOUT_CAVE; |
627 |
root |
1.43 |
else if (RP->map_layout_style == LAYOUT_NONE) |
628 |
|
|
RP->map_layout_style = rmg_rndm (NROFLAYOUTS - 1) + 1; /* No style found - choose one randomly */ |
629 |
|
|
else |
630 |
|
|
abort (); |
631 |
|
|
|
632 |
|
|
Layout layout = layoutgen (RP); |
633 |
|
|
|
634 |
|
|
#ifdef RMAP_DEBUG |
635 |
|
|
dump_layout (layout); |
636 |
|
|
#endif |
637 |
|
|
|
638 |
|
|
/* increment these for the current map */ |
639 |
|
|
++RP->dungeon_level; |
640 |
|
|
|
641 |
|
|
// need to patch RP becasue following code doesn't use the Layout object |
642 |
|
|
RP->Xsize = layout->w; |
643 |
|
|
RP->Ysize = layout->h; |
644 |
|
|
|
645 |
|
|
/* allocate the map and set the floor */ |
646 |
root |
1.51 |
make_map_floor (layout, RP->get_str ("floorstyle", ""), RP); |
647 |
root |
1.43 |
|
648 |
|
|
/* set region */ |
649 |
|
|
default_region = RP->region; |
650 |
|
|
|
651 |
|
|
CEDE; |
652 |
|
|
|
653 |
|
|
place_specials_in_map (this, layout, RP); |
654 |
|
|
|
655 |
|
|
CEDE; |
656 |
|
|
|
657 |
root |
1.51 |
const char *wallstyle = RP->get_str ("wallstyle", 0); |
658 |
|
|
|
659 |
root |
1.43 |
/* create walls unless the wallstyle is "none" */ |
660 |
root |
1.51 |
if (strcmp (wallstyle, "none")) |
661 |
root |
1.43 |
{ |
662 |
root |
1.51 |
make_map_walls (this, layout, wallstyle, RP->get_str ("miningstyle", ""), RP); |
663 |
root |
1.43 |
|
664 |
|
|
/* place doors unless doorstyle or wallstyle is "none" */ |
665 |
|
|
if (strcmp (RP->doorstyle, "none")) |
666 |
|
|
put_doors (this, layout, RP->doorstyle, RP); |
667 |
|
|
} |
668 |
|
|
|
669 |
|
|
CEDE; |
670 |
|
|
|
671 |
root |
1.51 |
const char *exitstyle = RP->get_str ("exitstyle", ""); |
672 |
|
|
|
673 |
root |
1.43 |
/* create exits unless the exitstyle is "none" */ |
674 |
root |
1.51 |
if (strcmp (exitstyle, "none")) |
675 |
|
|
place_exits (this, layout, exitstyle, RP->orientation, RP); |
676 |
root |
1.43 |
|
677 |
|
|
CEDE; |
678 |
|
|
|
679 |
|
|
/* create monsters unless the monsterstyle is "none" */ |
680 |
|
|
if (strcmp (RP->monsterstyle, "none")) |
681 |
|
|
place_monsters (this, RP->monsterstyle, RP->difficulty, RP); |
682 |
|
|
|
683 |
|
|
CEDE; |
684 |
|
|
|
685 |
|
|
/* treasures needs to have a proper difficulty set for the map. */ |
686 |
|
|
difficulty = estimate_difficulty (); |
687 |
|
|
|
688 |
|
|
CEDE; |
689 |
|
|
|
690 |
root |
1.55 |
const char *treasurestyle = RP->get_str ("treasurestyle", ""); |
691 |
|
|
|
692 |
root |
1.43 |
/* create treasure unless the treasurestyle is "none" */ |
693 |
root |
1.55 |
place_treasure (this, layout, treasurestyle, RP->get_iv ("treasureoptions"), RP); |
694 |
root |
1.43 |
|
695 |
|
|
CEDE; |
696 |
|
|
|
697 |
root |
1.55 |
const char *decorstyle = RP->get_str ("treasurestyle", ""); |
698 |
|
|
|
699 |
root |
1.43 |
/* create decor unless the decorstyle is "none" */ |
700 |
root |
1.55 |
if (strcmp (decorstyle, "none")) |
701 |
|
|
put_decor (this, layout, decorstyle, RP->get_iv ("decoroptions"), RP); |
702 |
root |
1.43 |
|
703 |
|
|
CEDE; |
704 |
|
|
|
705 |
|
|
/* generate treasures, etc. */ |
706 |
|
|
fix_auto_apply (); |
707 |
|
|
|
708 |
|
|
CEDE; |
709 |
|
|
|
710 |
|
|
unblock_exits (this, layout, RP); |
711 |
|
|
|
712 |
root |
1.51 |
msg = buf; |
713 |
root |
1.43 |
in_memory = MAP_ACTIVE; |
714 |
|
|
|
715 |
|
|
CEDE; |
716 |
|
|
|
717 |
|
|
return 1; |
718 |
|
|
} |
719 |
|
|
|