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

File Contents

# User Rev Content
1 elmex 1.1 /*
2 root 1.31 * This file is part of Deliantra, the Roguelike Realtime MMORPG.
3 root 1.82 *
4 root 1.85 * Copyright (©) 2017,2018 Marc Alexander Lehmann / the Deliantra team
5 root 1.83 * Copyright (©) 2005,2006,2007,2008,2009,2010,2011,2012,2013,2014,2015,2016 Marc Alexander Lehmann / Robin Redeker / the Deliantra team
6 root 1.46 * Copyright (©) 2001 Mark Wedel & Crossfire Development Team
7     * Copyright (©) 1992 Frank Tore Johansen
8 root 1.82 *
9 root 1.42 * Deliantra is free software: you can redistribute it and/or modify it under
10     * the terms of the Affero GNU General Public License as published by the
11     * Free Software Foundation, either version 3 of the License, or (at your
12     * option) any later version.
13 root 1.82 *
14 pippijn 1.20 * This program is distributed in the hope that it will be useful,
15     * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 root 1.30 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 pippijn 1.20 * GNU General Public License for more details.
18 root 1.82 *
19 root 1.42 * You should have received a copy of the Affero GNU General Public License
20     * and the GNU General Public License along with this program. If not, see
21     * <http://www.gnu.org/licenses/>.
22 root 1.82 *
23 root 1.31 * The authors can be reached via e-mail to <support@deliantra.net>
24 pippijn 1.20 */
25 elmex 1.1
26     #include <time.h>
27     #include <stdio.h>
28     #include <global.h>
29 root 1.73 #include <rmg.h>
30 elmex 1.1 #include <rproto.h>
31     #include <sproto.h>
32    
33 root 1.39 #define CEDE coroapi::cede_to_tick ()
34 root 1.22
35 root 1.63 random_map_params::random_map_params ()
36     {
37     hv = newHV ();
38     }
39    
40 root 1.64 random_map_params::random_map_params (random_map_params *RP)
41     {
42     *this = *RP;
43    
44     HV *copy = newHV ();
45    
46     hv_iterinit (hv);
47    
48     // does not work for utf-8 keys
49     while (HE *he = hv_iternext (hv))
50     {
51     STRLEN klen; const char *key = HePV (he, klen);
52     hv_store (copy, key, klen, newSVsv (HeVAL (he)), HeHASH (he));
53     }
54    
55     hv = copy;
56     }
57    
58 root 1.63 random_map_params::random_map_params (HV *hv)
59     {
60     this->hv = (HV *)SvREFCNT_inc_NN ((SV *)hv);
61    
62     assign (wall_name, get_str ("wall_name"));
63    
64     xsize = get_iv ("xsize");
65     ysize = get_iv ("ysize");
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     total_map_hp = get_nv ("total_map_hp"); // actually val64, but I am too lazy
75     symmetry_used = get_iv ("symmetry_used");
76     }
77    
78     random_map_params::~random_map_params ()
79     {
80     SvREFCNT_dec (hv);
81     }
82    
83     shstr_tmp
84     random_map_params::as_shstr () const
85     {
86     set ("xsize" , xsize);
87     set ("ysize" , ysize);
88     set ("layoutoptions1" , layoutoptions1);
89     set ("layoutoptions2" , layoutoptions2);
90     set ("layoutoptions3" , layoutoptions3);
91     set ("dungeon_depth" , dungeon_depth);
92     set ("difficulty" , difficulty && difficulty_given ? difficulty : 0);
93     set ("difficulty_increase", difficulty_increase);
94     set ("dungeon_level" , dungeon_level);
95    
96     dynbuf_text buf;
97     hv_iterinit (hv);
98    
99     // does not work for utf-8 keys
100     while (HE *he = hv_iternext (hv))
101     {
102     STRLEN klen; const char *key = HePV (he, klen);
103     STRLEN vlen; const char *value = SvPVutf8 (HeVAL (he), vlen);
104    
105     buf.fadd (key, klen);
106     buf << ' ';
107     buf.fadd (value, vlen);
108     buf << '\n';
109     }
110    
111     return shstr (buf);
112     }
113    
114 root 1.84 ecb_noinline SV *
115 root 1.76 random_map_params::opt_sv (const char *option) const
116 root 1.51 {
117     SV **he = hv_fetch (hv, option, strlen (option), 0);
118    
119 root 1.55 return he ? *he : 0;
120 root 1.51 }
121    
122 root 1.84 ecb_noinline const_utf8_string
123 root 1.55 random_map_params::get_str (const char *option, const_utf8_string fallback) const
124     {
125 root 1.76 SV *sv = opt_sv (option);
126 root 1.55 return sv ? cfSvPVutf8_nolen (sv) : fallback;
127     }
128    
129 root 1.84 ecb_noinline IV
130 root 1.51 random_map_params::get_iv (const char *option, IV fallback) const
131     {
132 root 1.76 SV *sv = opt_sv (option);
133 root 1.55 return sv ? SvIV (sv) : fallback;
134     }
135    
136 root 1.84 ecb_noinline UV
137 root 1.55 random_map_params::get_uv (const char *option, UV fallback) const
138     {
139 root 1.76 SV *sv = opt_sv (option);
140 root 1.55 return sv ? SvUV (sv) : fallback;
141     }
142    
143 root 1.84 ecb_noinline NV
144 root 1.55 random_map_params::get_nv (const char *option, NV fallback) const
145     {
146 root 1.76 SV *sv = opt_sv (option);
147 root 1.55 return sv ? SvNV (sv) : fallback;
148     }
149    
150 root 1.84 ecb_noinline void
151 root 1.55 random_map_params::set (const char *option, SV *value) const
152     {
153     int len = strlen (option);
154    
155     if (value)
156     hv_store (hv, option, len, value, 0);
157     else
158     hv_delete (hv, option, len, G_DISCARD);
159     }
160    
161 root 1.84 ecb_noinline void
162 root 1.55 random_map_params::set (const char *option, const_utf8_string value) const
163     {
164     set (option, value && *value ? newSVpvn_utf8 (value, strlen (value), 1) : 0);
165     }
166    
167     void
168     random_map_params::set (const char *option, IV value) const
169     {
170     set (option, newSViv (value));
171     }
172    
173     void
174     random_map_params::set (const char *option, UV value) const
175     {
176     set (option, newSVuv (value));
177     }
178    
179     void
180     random_map_params::set (const char *option, NV value) const
181     {
182     set (option, newSVnv (value));
183     }
184    
185 root 1.43 bool
186     maptile::generate_random_map (random_map_params *RP)
187     {
188     RP->Xsize = RP->xsize;
189     RP->Ysize = RP->ysize;
190    
191 root 1.68 max_it (RP->dungeon_level, 1);
192    
193 root 1.75 IV expand2x = RP->get_iv ("expand2x");
194     UV random_seed = RP->get_uv ("random_seed");
195    
196 root 1.43 /* pick a random seed, or use the one from the input file */
197 root 1.75 random_seed = random_seed
198     ? random_seed + RP->dungeon_level
199 root 1.80 : server_tick;
200 root 1.43
201     // we run "single-threaded"
202 root 1.75 rmg_rndm.seed (random_seed);
203 root 1.43
204 root 1.55 shstr buf = RP->as_shstr ();
205 root 1.43
206     if (RP->difficulty == 0)
207     {
208     RP->difficulty = RP->dungeon_level; /* use this instead of a map difficulty */
209    
210 root 1.67 if (RP->difficulty_increase > 0.001f)
211     RP->difficulty = RP->dungeon_level * RP->difficulty_increase;
212 root 1.43
213     if (RP->difficulty < 1)
214     RP->difficulty = 1;
215     }
216     else
217     RP->difficulty_given = 1;
218    
219     if (RP->Xsize < MIN_RANDOM_MAP_SIZE)
220     RP->Xsize = MIN_RANDOM_MAP_SIZE + rmg_rndm (25) + 5;
221    
222     if (RP->Ysize < MIN_RANDOM_MAP_SIZE)
223     RP->Ysize = MIN_RANDOM_MAP_SIZE + rmg_rndm (25) + 5;
224    
225 root 1.58 min_it (RP->Xsize, MAX_RANDOM_MAP_SIZE);
226     min_it (RP->Ysize, MAX_RANDOM_MAP_SIZE);
227    
228 root 1.70 int symmetry = RP->get_iv ("symmetry", SYMMETRY_NONE);
229    
230     if (symmetry == SYMMETRY_RANDOM)
231 root 1.43 RP->symmetry_used = rmg_rndm (SYMMETRY_XY) + 1;
232     else
233 root 1.70 RP->symmetry_used = symmetry;
234 root 1.43
235     if (RP->symmetry_used == SYMMETRY_Y || RP->symmetry_used == SYMMETRY_XY)
236     RP->Ysize = RP->Ysize / 2 + 1;
237    
238     if (RP->symmetry_used == SYMMETRY_X || RP->symmetry_used == SYMMETRY_XY)
239     RP->Xsize = RP->Xsize / 2 + 1;
240    
241 root 1.75 if (expand2x)
242 root 1.43 {
243     RP->Xsize /= 2;
244     RP->Ysize /= 2;
245     }
246    
247 root 1.62 const char *layoutstyle = RP->get_str ("layoutstyle", "");
248    
249     if (strstr (layoutstyle, "onion"))
250 root 1.43 RP->map_layout_style = LAYOUT_ONION;
251 root 1.62 else if (strstr (layoutstyle, "maze"))
252 root 1.43 RP->map_layout_style = LAYOUT_MAZE;
253 root 1.62 else if (strstr (layoutstyle, "spiral"))
254 root 1.43 RP->map_layout_style = LAYOUT_SPIRAL;
255 root 1.62 else if (strstr (layoutstyle, "rogue"))
256 root 1.43 RP->map_layout_style = LAYOUT_ROGUELIKE;
257 root 1.62 else if (strstr (layoutstyle, "snake"))
258 root 1.43 RP->map_layout_style = LAYOUT_SNAKE;
259 root 1.62 else if (strstr (layoutstyle, "squarespiral"))
260 root 1.43 RP->map_layout_style = LAYOUT_SQUARE_SPIRAL;
261 root 1.62 else if (strstr (layoutstyle, "cave"))
262 root 1.57 RP->map_layout_style = LAYOUT_CAVE;
263 root 1.69 else if (strstr (layoutstyle, "castle"))
264     RP->map_layout_style = LAYOUT_CASTLE;
265 root 1.64 else if (strstr (layoutstyle, "multiple"))
266     RP->map_layout_style = LAYOUT_MULTIPLE;
267 root 1.43 else
268 root 1.59 RP->map_layout_style = rmg_rndm (NROFLAYOUTS - 1) + 1; /* No style found - choose one randomly */
269 root 1.43
270 root 1.61 layout maze (RP->Xsize, RP->Ysize);
271     maze.generate (RP);
272 root 1.70
273     if (RP->get_iv ("rotate", 1))
274     maze.rotate (rmg_rndm (4));
275    
276 root 1.64 maze.symmetrize (RP->symmetry_used);
277    
278 root 1.75 if (expand2x)
279 root 1.64 maze.expand2x ();
280    
281 root 1.65 #if 0
282 root 1.64 maze.print ();//D
283     #endif
284 root 1.43
285     /* increment these for the current map */
286     ++RP->dungeon_level;
287    
288 root 1.61 // need to patch RP becasue following code doesn't use the layout object
289     RP->Xsize = maze.w;
290     RP->Ysize = maze.h;
291 root 1.43
292     /* allocate the map and set the floor */
293 root 1.61 make_map_floor (maze, RP->get_str ("floorstyle", ""), RP);
294 root 1.43
295     /* set region */
296 root 1.63 default_region = region::find (RP->get_str ("region", 0));
297 root 1.43
298     CEDE;
299    
300 root 1.61 place_specials_in_map (this, maze, RP);
301 root 1.43
302     CEDE;
303    
304 root 1.62 const char *wallstyle = RP->get_str ("wallstyle", "");
305 root 1.51
306 root 1.43 /* create walls unless the wallstyle is "none" */
307 root 1.51 if (strcmp (wallstyle, "none"))
308 root 1.43 {
309 root 1.61 make_map_walls (this, maze, wallstyle, RP->get_str ("miningstyle", ""), RP);
310 root 1.43
311 root 1.62 const char *doorstyle = RP->get_str ("doorstyle", "");
312    
313 root 1.43 /* place doors unless doorstyle or wallstyle is "none" */
314 root 1.62 if (strcmp (doorstyle, "none"))
315     put_doors (this, maze, doorstyle, RP);
316 root 1.43 }
317    
318     CEDE;
319    
320 root 1.51 const char *exitstyle = RP->get_str ("exitstyle", "");
321    
322 root 1.43 /* create exits unless the exitstyle is "none" */
323 root 1.51 if (strcmp (exitstyle, "none"))
324 root 1.70 place_exits (this, maze, exitstyle, RP->get_iv ("orientation", 0), RP);
325 root 1.43
326     CEDE;
327    
328 root 1.62 const char *monsterstyle = RP->get_str ("monsterstyle", "");
329    
330 root 1.43 /* create monsters unless the monsterstyle is "none" */
331 root 1.62 if (strcmp (monsterstyle, "none"))
332     place_monsters (this, monsterstyle, RP->difficulty, RP);
333 root 1.43
334     CEDE;
335    
336     /* treasures needs to have a proper difficulty set for the map. */
337     difficulty = estimate_difficulty ();
338    
339     CEDE;
340    
341 root 1.55 const char *treasurestyle = RP->get_str ("treasurestyle", "");
342    
343 root 1.43 /* create treasure unless the treasurestyle is "none" */
344 root 1.61 place_treasure (this, maze, treasurestyle, RP->get_iv ("treasureoptions"), RP);
345 root 1.43
346     CEDE;
347    
348 root 1.74 const char *decorstyle = RP->get_str ("decorstyle", "");
349 root 1.55
350 root 1.43 /* create decor unless the decorstyle is "none" */
351 root 1.55 if (strcmp (decorstyle, "none"))
352 root 1.61 put_decor (this, maze, decorstyle, RP->get_iv ("decoroptions"), RP);
353 root 1.43
354     CEDE;
355    
356     /* generate treasures, etc. */
357     fix_auto_apply ();
358    
359     CEDE;
360    
361 root 1.71 unblock_exits (this, maze);
362 root 1.43
363 root 1.51 msg = buf;
364 root 1.79 state = MAP_INACTIVE; // this is probably a lie, but currently works with ext/map-random.ext
365 root 1.43
366     CEDE;
367    
368     return 1;
369     }
370