ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/random_maps/random_map.C
Revision: 1.70
Committed: Sun Jul 4 00:58:18 2010 UTC (13 years, 10 months ago) by root
Content type: text/plain
Branch: MAIN
Changes since 1.69: +9 -8 lines
Log Message:
*** empty log message ***

File Contents

# Content
1 /*
2 * This file is part of Deliantra, the Roguelike Realtime MMORPG.
3 *
4 * Copyright (©) 2005,2006,2007,2008,2009,2010 Marc Alexander Lehmann / Robin Redeker / the Deliantra team
5 * Copyright (©) 2001 Mark Wedel & Crossfire Development Team
6 * Copyright (©) 1992 Frank Tore Johansen
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 #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 #define CEDE coroapi::cede_to_tick ()
33
34 random_map_params::random_map_params ()
35 {
36 hv = newHV ();
37 }
38
39 random_map_params::random_map_params (random_map_params *RP)
40 {
41 *this = *RP;
42
43 HV *copy = newHV ();
44
45 hv_iterinit (hv);
46
47 // does not work for utf-8 keys
48 while (HE *he = hv_iternext (hv))
49 {
50 STRLEN klen; const char *key = HePV (he, klen);
51 hv_store (copy, key, klen, newSVsv (HeVAL (he)), HeHASH (he));
52 }
53
54 hv = copy;
55 }
56
57 random_map_params::random_map_params (HV *hv)
58 {
59 this->hv = (HV *)SvREFCNT_inc_NN ((SV *)hv);
60
61 assign (wall_name, get_str ("wall_name"));
62
63 xsize = get_iv ("xsize");
64 ysize = get_iv ("ysize");
65 expand2x = get_iv ("expand2x");
66 layoutoptions1 = get_iv ("layoutoptions1");
67 layoutoptions2 = get_iv ("layoutoptions2");
68 layoutoptions3 = get_iv ("layoutoptions3");
69 difficulty = get_iv ("difficulty");
70 difficulty_given = get_iv ("difficulty_given");
71 difficulty_increase = get_nv ("difficulty_increase");
72 dungeon_level = get_iv ("dungeon_level");
73 dungeon_depth = get_iv ("dungeon_depth");
74 random_seed = get_uv ("random_seed");
75 total_map_hp = get_nv ("total_map_hp"); // actually val64, but I am too lazy
76 symmetry_used = get_iv ("symmetry_used");
77 }
78
79 random_map_params::~random_map_params ()
80 {
81 SvREFCNT_dec (hv);
82 }
83
84 shstr_tmp
85 random_map_params::as_shstr () const
86 {
87 set ("xsize" , xsize);
88 set ("ysize" , ysize);
89 set ("layoutoptions1" , layoutoptions1);
90 set ("layoutoptions2" , layoutoptions2);
91 set ("layoutoptions3" , layoutoptions3);
92 set ("dungeon_depth" , dungeon_depth);
93 set ("random_seed" , (UV)random_seed);
94 set ("difficulty" , difficulty && difficulty_given ? difficulty : 0);
95 set ("difficulty_increase", difficulty_increase);
96 set ("dungeon_level" , dungeon_level);
97
98 dynbuf_text buf;
99 hv_iterinit (hv);
100
101 // does not work for utf-8 keys
102 while (HE *he = hv_iternext (hv))
103 {
104 STRLEN klen; const char *key = HePV (he, klen);
105 STRLEN vlen; const char *value = SvPVutf8 (HeVAL (he), vlen);
106
107 buf.fadd (key, klen);
108 buf << ' ';
109 buf.fadd (value, vlen);
110 buf << '\n';
111 }
112
113 return shstr (buf);
114 }
115
116 noinline SV *
117 random_map_params::get_sv (const char *option) const
118 {
119 SV **he = hv_fetch (hv, option, strlen (option), 0);
120
121 return he ? *he : 0;
122 }
123
124 noinline const_utf8_string
125 random_map_params::get_str (const char *option, const_utf8_string fallback) const
126 {
127 SV *sv = get_sv (option);
128 return sv ? cfSvPVutf8_nolen (sv) : fallback;
129 }
130
131 noinline IV
132 random_map_params::get_iv (const char *option, IV fallback) const
133 {
134 SV *sv = get_sv (option);
135 return sv ? SvIV (sv) : fallback;
136 }
137
138 noinline UV
139 random_map_params::get_uv (const char *option, UV fallback) const
140 {
141 SV *sv = get_sv (option);
142 return sv ? SvUV (sv) : fallback;
143 }
144
145 noinline NV
146 random_map_params::get_nv (const char *option, NV fallback) const
147 {
148 SV *sv = get_sv (option);
149 return sv ? SvNV (sv) : fallback;
150 }
151
152 noinline void
153 random_map_params::set (const char *option, SV *value) const
154 {
155 int len = strlen (option);
156
157 if (value)
158 hv_store (hv, option, len, value, 0);
159 else
160 hv_delete (hv, option, len, G_DISCARD);
161 }
162
163 noinline void
164 random_map_params::set (const char *option, const_utf8_string value) const
165 {
166 set (option, value && *value ? newSVpvn_utf8 (value, strlen (value), 1) : 0);
167 }
168
169 void
170 random_map_params::set (const char *option, IV value) const
171 {
172 set (option, newSViv (value));
173 }
174
175 void
176 random_map_params::set (const char *option, UV value) const
177 {
178 set (option, newSVuv (value));
179 }
180
181 void
182 random_map_params::set (const char *option, NV value) const
183 {
184 set (option, newSVnv (value));
185 }
186
187 bool
188 maptile::generate_random_map (random_map_params *RP)
189 {
190 RP->Xsize = RP->xsize;
191 RP->Ysize = RP->ysize;
192
193 max_it (RP->dungeon_level, 1);
194
195 /* pick a random seed, or use the one from the input file */
196 RP->random_seed = RP->random_seed
197 ? RP->random_seed + RP->dungeon_level
198 : pticks;
199
200 // we run "single-threaded"
201 rmg_rndm.seed (RP->random_seed);
202
203 shstr buf = RP->as_shstr ();
204
205 if (RP->difficulty == 0)
206 {
207 RP->difficulty = RP->dungeon_level; /* use this instead of a map difficulty */
208
209 if (RP->difficulty_increase > 0.001f)
210 RP->difficulty = RP->dungeon_level * RP->difficulty_increase;
211
212 if (RP->difficulty < 1)
213 RP->difficulty = 1;
214 }
215 else
216 RP->difficulty_given = 1;
217
218 if (RP->Xsize < MIN_RANDOM_MAP_SIZE)
219 RP->Xsize = MIN_RANDOM_MAP_SIZE + rmg_rndm (25) + 5;
220
221 if (RP->Ysize < MIN_RANDOM_MAP_SIZE)
222 RP->Ysize = MIN_RANDOM_MAP_SIZE + rmg_rndm (25) + 5;
223
224 min_it (RP->Xsize, MAX_RANDOM_MAP_SIZE);
225 min_it (RP->Ysize, MAX_RANDOM_MAP_SIZE);
226
227 int symmetry = RP->get_iv ("symmetry", SYMMETRY_NONE);
228
229 if (symmetry == SYMMETRY_RANDOM)
230 RP->symmetry_used = rmg_rndm (SYMMETRY_XY) + 1;
231 else
232 RP->symmetry_used = symmetry;
233
234 if (RP->symmetry_used == SYMMETRY_Y || RP->symmetry_used == SYMMETRY_XY)
235 RP->Ysize = RP->Ysize / 2 + 1;
236
237 if (RP->symmetry_used == SYMMETRY_X || RP->symmetry_used == SYMMETRY_XY)
238 RP->Xsize = RP->Xsize / 2 + 1;
239
240 if (RP->expand2x > 0)
241 {
242 RP->Xsize /= 2;
243 RP->Ysize /= 2;
244 }
245
246 const char *layoutstyle = RP->get_str ("layoutstyle", "");
247
248 if (strstr (layoutstyle, "onion"))
249 RP->map_layout_style = LAYOUT_ONION;
250 else if (strstr (layoutstyle, "maze"))
251 RP->map_layout_style = LAYOUT_MAZE;
252 else if (strstr (layoutstyle, "spiral"))
253 RP->map_layout_style = LAYOUT_SPIRAL;
254 else if (strstr (layoutstyle, "rogue"))
255 RP->map_layout_style = LAYOUT_ROGUELIKE;
256 else if (strstr (layoutstyle, "snake"))
257 RP->map_layout_style = LAYOUT_SNAKE;
258 else if (strstr (layoutstyle, "squarespiral"))
259 RP->map_layout_style = LAYOUT_SQUARE_SPIRAL;
260 else if (strstr (layoutstyle, "cave"))
261 RP->map_layout_style = LAYOUT_CAVE;
262 else if (strstr (layoutstyle, "castle"))
263 RP->map_layout_style = LAYOUT_CASTLE;
264 else if (strstr (layoutstyle, "multiple"))
265 RP->map_layout_style = LAYOUT_MULTIPLE;
266 else
267 RP->map_layout_style = rmg_rndm (NROFLAYOUTS - 1) + 1; /* No style found - choose one randomly */
268
269 layout maze (RP->Xsize, RP->Ysize);
270 maze.generate (RP);
271
272 if (RP->get_iv ("rotate", 1))
273 maze.rotate (rmg_rndm (4));
274
275 maze.symmetrize (RP->symmetry_used);
276
277 if (RP->expand2x)
278 maze.expand2x ();
279
280 #if 0
281 maze.print ();//D
282 #endif
283
284 /* increment these for the current map */
285 ++RP->dungeon_level;
286
287 // need to patch RP becasue following code doesn't use the layout object
288 RP->Xsize = maze.w;
289 RP->Ysize = maze.h;
290
291 /* allocate the map and set the floor */
292 make_map_floor (maze, RP->get_str ("floorstyle", ""), RP);
293
294 /* set region */
295 default_region = region::find (RP->get_str ("region", 0));
296
297 CEDE;
298
299 place_specials_in_map (this, maze, RP);
300
301 CEDE;
302
303 const char *wallstyle = RP->get_str ("wallstyle", "");
304
305 /* create walls unless the wallstyle is "none" */
306 if (strcmp (wallstyle, "none"))
307 {
308 make_map_walls (this, maze, wallstyle, RP->get_str ("miningstyle", ""), RP);
309
310 const char *doorstyle = RP->get_str ("doorstyle", "");
311
312 /* place doors unless doorstyle or wallstyle is "none" */
313 if (strcmp (doorstyle, "none"))
314 put_doors (this, maze, doorstyle, RP);
315 }
316
317 CEDE;
318
319 const char *exitstyle = RP->get_str ("exitstyle", "");
320
321 /* create exits unless the exitstyle is "none" */
322 if (strcmp (exitstyle, "none"))
323 place_exits (this, maze, exitstyle, RP->get_iv ("orientation", 0), RP);
324
325 CEDE;
326
327 const char *monsterstyle = RP->get_str ("monsterstyle", "");
328
329 /* create monsters unless the monsterstyle is "none" */
330 if (strcmp (monsterstyle, "none"))
331 place_monsters (this, monsterstyle, RP->difficulty, RP);
332
333 CEDE;
334
335 /* treasures needs to have a proper difficulty set for the map. */
336 difficulty = estimate_difficulty ();
337
338 CEDE;
339
340 const char *treasurestyle = RP->get_str ("treasurestyle", "");
341
342 /* create treasure unless the treasurestyle is "none" */
343 place_treasure (this, maze, treasurestyle, RP->get_iv ("treasureoptions"), RP);
344
345 CEDE;
346
347 const char *decorstyle = RP->get_str ("treasurestyle", "");
348
349 /* create decor unless the decorstyle is "none" */
350 if (strcmp (decorstyle, "none"))
351 put_decor (this, maze, decorstyle, RP->get_iv ("decoroptions"), RP);
352
353 CEDE;
354
355 /* generate treasures, etc. */
356 fix_auto_apply ();
357
358 CEDE;
359
360 unblock_exits (this, maze, RP);
361
362 msg = buf;
363 in_memory = MAP_ACTIVE;
364
365 CEDE;
366
367 return 1;
368 }
369