Bug Summary

File:map_generator.cc
Location:line 778, column 2
Description:Declared variable-length array (VLA) has zero size

Annotated Source Code

1/*
2 * Copyright (C) 2002-2004, 2006-2010, 2013 by the Widelands Development Team
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version 2
7 * of the License, or (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 *
18 */
19
20#include "map_generator.h"
21#include "log.h"
22#include "logic/findnode.h"
23#include "logic/map.h"
24#include "logic/editor_game_base.h"
25#include "editor/tools/editor_increase_resources_tool.h"
26
27#include <boost/scoped_array.hpp>
28
29#define AVG_ELEVATION(0x80000000) (0x80000000)
30#define MAX_ELEVATION(0xffffffff) (0xffffffff)
31#define MAP_ID_DIGITS24 24
32#define ISLAND_BORDER10 10
33#define MAX_ELEVATION_HALF(0x80000000) (0x80000000)
34
35using boost::scoped_array;
36
37namespace Widelands
38{
39
40MapGenerator::MapGenerator
41 (Map & map, const UniqueRandomMapInfo & mapInfo,
42 Editor_Game_Base & egbase)
43 : m_map(map), m_mapInfo(mapInfo), m_egbase(egbase)
44{
45
46}
47
48void MapGenerator::generate_bobs
49 (scoped_array<uint32_t> const * random_bobs,
50 Coords const fc,
51 RNG & rng,
52 MapGenAreaInfo::MapGenTerrainType const terrType)
53{
54 // Figure out which bob area is due here...
55
56 MapGenInfo & mapGenInfo = m_map.world().getMapGenInfo();
57
58 size_t num = mapGenInfo.getNumBobAreas();
59 size_t found = num;
60 uint32_t sum_weight = mapGenInfo.getSumBobAreaWeight();
61 uint32_t max_val = 0;
62 for (size_t ix = 0; ix < num; ++ix) {
63 uint32_t val = random_bobs[ix][fc.x + m_mapInfo.w * fc.y];
64 val = (val / sum_weight) * mapGenInfo.getBobArea(ix).getWeight();
65 if (val >= max_val) {
66 found = ix;
67 max_val = val;
68 }
69 }
70 if (found >= num)
71 return;
72
73 // Figure out if we really need to set a bob here...
74
75 const MapGenBobArea & bobArea = mapGenInfo.getBobArea(found);
76
77 const MapGenBobKind * bobKind = bobArea.getBobKind(terrType);
78
79 if (not bobKind) // no bobs defined here...
80 return;
81
82 uint32_t immovDens = bobArea.getImmovableDensity();
83 uint32_t movDens = bobArea.getMoveableDensity();
84
85 immovDens *= max_val / 100;
86 movDens *= max_val / 100;
87
88 immovDens = immovDens >= MAX_ELEVATION_HALF(0x80000000) ? MAX_ELEVATION(0xffffffff) : immovDens * 2;
89 movDens = movDens >= MAX_ELEVATION_HALF(0x80000000) ? MAX_ELEVATION(0xffffffff) : movDens * 2;
90
91 uint32_t val = rng.rand();
92 bool set_immovable = (val <= immovDens);
93 val = rng.rand();
94 bool set_moveable = (val <= movDens);
95
96
97 // Set bob according to bob area
98
99 if (set_immovable and (num = bobKind->getNumImmovableBobs()))
100 m_egbase.create_immovable
101 (fc,
102 bobKind->getImmovableBob
103 (static_cast<size_t>(rng.rand() / (MAX_ELEVATION(0xffffffff) / num))),
104 0);
105
106 if (set_moveable and (num = bobKind->getNumMoveableBobs()))
107 m_egbase.create_bob
108 (fc,
109 m_map.world().get_bob
110 (bobKind->getMoveableBob
111 (static_cast<size_t>(rng.rand() / (MAX_ELEVATION(0xffffffff) / num)))
112 .c_str()),
113 0);
114}
115
116#define set_resource_helper(rnd1, res){ Resource_Index const res_idx = terr.get_valid_resource(res)
; uint32_t const max_amount = m_map.world().get_resource(res_idx
)->get_max_amount(); uint8_t res_val = static_cast<uint8_t
>(rnd1 / ((0xffffffff) / max_amount)); res_val *= static_cast
<uint8_t>(m_mapInfo.resource_amount) + 1; res_val /= 3;
if (Editor_Change_Resource_Tool_Callback(fc, &m_map, res_idx
)) { fc.field->set_resources(res_idx, res_val); fc.field->
set_starting_res_amount(res_val); } }
\
117 { \
118 Resource_Index const res_idx = terr.get_valid_resource(res); \
119 uint32_t const max_amount = \
120 m_map.world().get_resource(res_idx)->get_max_amount(); \
121 uint8_t res_val = \
122 static_cast<uint8_t>(rnd1 / (MAX_ELEVATION(0xffffffff) / max_amount)); \
123 res_val *= static_cast<uint8_t>(m_mapInfo.resource_amount) + 1; \
124 res_val /= 3; \
125 if (Editor_Change_Resource_Tool_Callback(fc, &m_map, res_idx)) { \
126 fc.field->set_resources(res_idx, res_val); \
127 fc.field->set_starting_res_amount(res_val); \
128 } \
129 } \
130
131void MapGenerator::generate_resources
132 (uint32_t const * const random1,
133 uint32_t const * const random2,
134 uint32_t const * const random3,
135 uint32_t const * const random4,
136 FCoords const fc)
137{
138 // We'll take the "D" terrain at first...
139 // TODO: Check how the editor handles this...
140
141 Terrain_Index const tix = fc.field->get_terrains().d;
142 const Terrain_Descr & terr = m_map.world().get_ter(tix);
143 switch (terr.get_num_valid_resources()) {
144 case 1: {
145 uint32_t const rnd1 = random1[fc.x + m_mapInfo.w * fc.y];
146 set_resource_helper(rnd1, 0){ Resource_Index const res_idx = terr.get_valid_resource(0); uint32_t
const max_amount = m_map.world().get_resource(res_idx)->get_max_amount
(); uint8_t res_val = static_cast<uint8_t>(rnd1 / ((0xffffffff
) / max_amount)); res_val *= static_cast<uint8_t>(m_mapInfo
.resource_amount) + 1; res_val /= 3; if (Editor_Change_Resource_Tool_Callback
(fc, &m_map, res_idx)) { fc.field->set_resources(res_idx
, res_val); fc.field->set_starting_res_amount(res_val); } }
;
147 break;
148 }
149 case 2: {
150 uint32_t const rnd1 = random1[fc.x + m_mapInfo.w * fc.y];
151 uint32_t const rnd2 = random2[fc.x + m_mapInfo.w * fc.y];
152 if (rnd1 > rnd2) {
153 set_resource_helper(rnd1, 0){ Resource_Index const res_idx = terr.get_valid_resource(0); uint32_t
const max_amount = m_map.world().get_resource(res_idx)->get_max_amount
(); uint8_t res_val = static_cast<uint8_t>(rnd1 / ((0xffffffff
) / max_amount)); res_val *= static_cast<uint8_t>(m_mapInfo
.resource_amount) + 1; res_val /= 3; if (Editor_Change_Resource_Tool_Callback
(fc, &m_map, res_idx)) { fc.field->set_resources(res_idx
, res_val); fc.field->set_starting_res_amount(res_val); } }
154 } else
155 set_resource_helper(rnd2, 1){ Resource_Index const res_idx = terr.get_valid_resource(1); uint32_t
const max_amount = m_map.world().get_resource(res_idx)->get_max_amount
(); uint8_t res_val = static_cast<uint8_t>(rnd2 / ((0xffffffff
) / max_amount)); res_val *= static_cast<uint8_t>(m_mapInfo
.resource_amount) + 1; res_val /= 3; if (Editor_Change_Resource_Tool_Callback
(fc, &m_map, res_idx)) { fc.field->set_resources(res_idx
, res_val); fc.field->set_starting_res_amount(res_val); } }
;
156 break;
157 }
158 case 3: {
159 uint32_t const rnd1 = random1[fc.x + m_mapInfo.w * fc.y];
160 uint32_t const rnd2 = random2[fc.x + m_mapInfo.w * fc.y];
161 uint32_t const rnd3 = random3[fc.x + m_mapInfo.w * fc.y];
162 if (rnd1 > rnd2 && rnd1 > rnd3) {
163 set_resource_helper(rnd1, 0){ Resource_Index const res_idx = terr.get_valid_resource(0); uint32_t
const max_amount = m_map.world().get_resource(res_idx)->get_max_amount
(); uint8_t res_val = static_cast<uint8_t>(rnd1 / ((0xffffffff
) / max_amount)); res_val *= static_cast<uint8_t>(m_mapInfo
.resource_amount) + 1; res_val /= 3; if (Editor_Change_Resource_Tool_Callback
(fc, &m_map, res_idx)) { fc.field->set_resources(res_idx
, res_val); fc.field->set_starting_res_amount(res_val); } }
;
164 } else if (rnd2 > rnd1 && rnd2 > rnd3) {
165 set_resource_helper(rnd2, 1){ Resource_Index const res_idx = terr.get_valid_resource(1); uint32_t
const max_amount = m_map.world().get_resource(res_idx)->get_max_amount
(); uint8_t res_val = static_cast<uint8_t>(rnd2 / ((0xffffffff
) / max_amount)); res_val *= static_cast<uint8_t>(m_mapInfo
.resource_amount) + 1; res_val /= 3; if (Editor_Change_Resource_Tool_Callback
(fc, &m_map, res_idx)) { fc.field->set_resources(res_idx
, res_val); fc.field->set_starting_res_amount(res_val); } }
;
166 } else
167 set_resource_helper(rnd3, 2){ Resource_Index const res_idx = terr.get_valid_resource(2); uint32_t
const max_amount = m_map.world().get_resource(res_idx)->get_max_amount
(); uint8_t res_val = static_cast<uint8_t>(rnd3 / ((0xffffffff
) / max_amount)); res_val *= static_cast<uint8_t>(m_mapInfo
.resource_amount) + 1; res_val /= 3; if (Editor_Change_Resource_Tool_Callback
(fc, &m_map, res_idx)) { fc.field->set_resources(res_idx
, res_val); fc.field->set_starting_res_amount(res_val); } }
;
168 break;
169 }
170 case 4: {
171 uint32_t const rnd1 = random1[fc.x + m_mapInfo.w * fc.y];
172 uint32_t const rnd2 = random2[fc.x + m_mapInfo.w * fc.y];
173 uint32_t const rnd3 = random3[fc.x + m_mapInfo.w * fc.y];
174 uint32_t const rnd4 = random4[fc.x + m_mapInfo.w * fc.y];
175 if (rnd1 > rnd2 && rnd1 > rnd3 && rnd1 > rnd4) {
176 set_resource_helper(rnd1, 0){ Resource_Index const res_idx = terr.get_valid_resource(0); uint32_t
const max_amount = m_map.world().get_resource(res_idx)->get_max_amount
(); uint8_t res_val = static_cast<uint8_t>(rnd1 / ((0xffffffff
) / max_amount)); res_val *= static_cast<uint8_t>(m_mapInfo
.resource_amount) + 1; res_val /= 3; if (Editor_Change_Resource_Tool_Callback
(fc, &m_map, res_idx)) { fc.field->set_resources(res_idx
, res_val); fc.field->set_starting_res_amount(res_val); } }
;
177 } else if (rnd2 > rnd1 && rnd2 > rnd3 && rnd2 > rnd4) {
178 set_resource_helper(rnd2, 1){ Resource_Index const res_idx = terr.get_valid_resource(1); uint32_t
const max_amount = m_map.world().get_resource(res_idx)->get_max_amount
(); uint8_t res_val = static_cast<uint8_t>(rnd2 / ((0xffffffff
) / max_amount)); res_val *= static_cast<uint8_t>(m_mapInfo
.resource_amount) + 1; res_val /= 3; if (Editor_Change_Resource_Tool_Callback
(fc, &m_map, res_idx)) { fc.field->set_resources(res_idx
, res_val); fc.field->set_starting_res_amount(res_val); } }
;
179 } else if (rnd3 > rnd1 && rnd3 > rnd2 && rnd3 > rnd4) {
180 set_resource_helper(rnd3, 2){ Resource_Index const res_idx = terr.get_valid_resource(2); uint32_t
const max_amount = m_map.world().get_resource(res_idx)->get_max_amount
(); uint8_t res_val = static_cast<uint8_t>(rnd3 / ((0xffffffff
) / max_amount)); res_val *= static_cast<uint8_t>(m_mapInfo
.resource_amount) + 1; res_val /= 3; if (Editor_Change_Resource_Tool_Callback
(fc, &m_map, res_idx)) { fc.field->set_resources(res_idx
, res_val); fc.field->set_starting_res_amount(res_val); } }
;
181 } else
182 set_resource_helper(rnd4, 3){ Resource_Index const res_idx = terr.get_valid_resource(3); uint32_t
const max_amount = m_map.world().get_resource(res_idx)->get_max_amount
(); uint8_t res_val = static_cast<uint8_t>(rnd4 / ((0xffffffff
) / max_amount)); res_val *= static_cast<uint8_t>(m_mapInfo
.resource_amount) + 1; res_val /= 3; if (Editor_Change_Resource_Tool_Callback
(fc, &m_map, res_idx)) { fc.field->set_resources(res_idx
, res_val); fc.field->set_starting_res_amount(res_val); } }
;
183 break;
184 }
185 default:
186 break; // currently mountains have the maximum of allowed resources, which is 4
187 }
188}
189
190/// Translates a random value into a map node height. This method is used
191/// within the random map generation methods.
192///
193/// \param elevation Random value.
194/// \param mapGenInfo Map generator information used to translate random values
195/// to height information (world specific info).
196/// \param c position within map
197/// \param mapInfo Information about the random map currently begin created
198/// (map specific info).
199///
200/// \returns A map height value corresponding to elevation.
201uint8_t MapGenerator::make_node_elevation
202 (double const elevation,
203 Coords const c)
204{
205 MapGenInfo & mapGenInfo = m_map.world().getMapGenInfo();
206
207 int32_t const water_h = mapGenInfo.getWaterShallowHeight();
208 int32_t const mount_h = mapGenInfo.getMountainFootHeight();
209 int32_t const summit_h = mapGenInfo.getSummitHeight ();
210
211 double const water_fac = m_mapInfo.waterRatio;
212 double const land_fac = m_mapInfo.landRatio;
213
214 uint8_t res_h =
215 elevation < water_fac ? water_h :
216 elevation < water_fac + land_fac ?
217 water_h + 1 +
218 ((elevation - water_fac) / land_fac) * (mount_h - water_h)
219 :
220 mount_h +
221 ((elevation - water_fac - land_fac) / (1 - water_fac - land_fac))
222 *
223 (summit_h - mount_h);
224
225 // Handle Map Border in island mode
226 if (m_mapInfo.islandMode) {
227 int32_t const border_dist =
228 std::min
229 (std::min<X_Coordinate>(c.x, m_mapInfo.w - c.x),
230 std::min<Y_Coordinate>(c.y, m_mapInfo.h - c.y));
231 if (border_dist <= ISLAND_BORDER10) {
232 res_h =
233 static_cast<uint8_t>
234 (static_cast<double>(res_h) * border_dist /
235 static_cast<double>(ISLAND_BORDER10));
236 if (res_h < water_h)
237 res_h = water_h;
238 }
239 }
240
241 return res_h;
242}
243
244/**
245===============
246Generate a "continuous" array of "reasonable" random values.
247The array generated is in fact organized in a two-dimensional
248way. "Reasonable" means that the values are not purely random.
249Neighboring values (in a two-dimensional way) are fitting
250together so that such an array can be used to directly generate
251height information for mountains, wasteland, resources etc.
252"Continuous" means that also value of the left border fit to
253the right border values and values of the top border fit to the
254bottom border values. This means we have some kind of "endlessly"
255repeating set of random values.
256What is more, the different heights are weighed so that the
257random distribution of all random values in the array is linear.
258The minimum valu will be 0, the maximum value will be MAX_ELEVATION,
259the average will be AVG_ELEVATION.
260
261w, h: are width and height of the two-dimensional array
262 produced. Thus, the array has w * h entries. To access a certain
263 "coordinate" in the array, use array[x + w * y] to retrieve the entry.
264
265rng: is the random number generator to be used.
266 This will mostly be the current rng of the random map currently being
267 created.
268===============
269*/
270uint32_t * MapGenerator::generate_random_value_map
271 (uint32_t const w, uint32_t const h, RNG & rng)
272{
273 uint32_t const numFields = h * w; // Size of the resulting array
274
275 uint32_t * const values = new uint32_t[numFields]; // Array to be filled
276
277 try {
278 // We will do some initing here...
279
280 for (uint32_t ix = 0; ix < numFields; ++ix)
281 values[ix] = AVG_ELEVATION(0x80000000);
282
283 // This will be the first starting random values...
284
285 for (uint32_t x = 0; x < w; x += 16)
286 for (uint32_t y = 0; y < h; y += 16) {
287 values[x + y * w] = rng.rand();
288 if (x % 32 or y % 32) {
289 values[x + y * w] += AVG_ELEVATION(0x80000000);
290 values[x + y * w] /= 2;
291 }
292 }
293
294 // randomize the values
295
296 uint32_t step_x = std::min(16U, w), step_y = std::min(16U, h);
297 uint32_t max = AVG_ELEVATION(0x80000000), min = AVG_ELEVATION(0x80000000);
298 double ele_fac = 0.15;
299
300 bool end = false;
301
302 while (!end) {
303 for (uint32_t x = 0; x < w; x += step_x) {
304 for (uint32_t y = 0; y < h; y += step_y) {
305 // Calculate coordinates of left and bottom left neighbours of
306 // the current node.
307
308 uint32_t right_x = x + step_x;
309 uint32_t lower_y = y + step_y;
310 if (right_x >= w)
311 right_x -= w;
312 if (lower_y >= h)
313 lower_y -= h;
314
315 // Get the current values of my neighbor nodes and of my node.
316
317 uint32_t const x_0_y_0 = values[x + w * y];
318 uint32_t const x_1_y_0 = values[right_x + w * y];
319 uint32_t const x_0_y_1 = values[x + w * lower_y];
320 uint32_t const x_1_y_1 = values[right_x + w * lower_y];
321
322 // calculate the in-between values
323
324 uint32_t x_new =
325 x_0_y_0 / 2 + x_1_y_0 / 2 +
326 static_cast<uint32_t>
327 (ele_fac * rng.rand() - ele_fac * AVG_ELEVATION(0x80000000));
328
329 uint32_t y_new =
330 x_0_y_0 / 2 + x_0_y_1 / 2 +
331 static_cast<uint32_t>
332 (ele_fac * rng.rand() - ele_fac * AVG_ELEVATION(0x80000000));
333
334 uint32_t xy_new =
335 x_0_y_0 / 4 + x_1_y_1 / 4 + x_1_y_0 / 4 + x_0_y_1 / 4 +
336 static_cast<uint32_t>
337 (ele_fac * rng.rand() - ele_fac * AVG_ELEVATION(0x80000000));
338
339 values[x + step_x / 2 + w * (y)] = x_new;
340 values[x + step_x / 2 + w * (y + step_y / 2)] = xy_new;
341 values[x + w * (y + step_y / 2)] = y_new;
342
343 // see if we have got a new min or max value
344
345 if (x_new > max)
346 max = x_new;
347 if (y_new > max)
348 max = y_new;
349 if (xy_new > max)
350 max = xy_new;
351
352 if (x_new < min)
353 min = x_new;
354 if (y_new < min)
355 min = y_new;
356 if (xy_new < min)
357 min = xy_new;
358 }
359 }
360
361 // preparations for the next iteration
362 if (step_y == 2 && step_x == 2)
363 end = true;
364 step_x /= 2;
365 step_y /= 2;
366 if (step_x <= 1)
367 step_x = 2;
368 if (step_y <= 1)
369 step_y = 2;
370 ele_fac *= 0.9;
371 }
372
373 // make a histogram of the heights
374
375 uint32_t histo[1024];
376
377 for (uint32_t x = 0; x < 1024; ++x)
378 histo[x] = 0;
379
380 for (uint32_t x = 0; x < w; ++x)
381 for (uint32_t y = 0; y < h; ++y) {
382 values[x + y * w] =
383 ((static_cast<double>(values[x + y * w] - min))
384 /
385 static_cast<double>(max - min))
386 *
387 MAX_ELEVATION(0xffffffff);
388 ++histo[values[x + y * w] >> 22];
389 }
390
391 // sort the histo out
392
393 double minVals[1024];
394
395 double currVal = 0.0;
396
397 for (uint32_t x = 0; x < 1024; ++x) {
398 minVals[x] = currVal;
399 currVal +=
400 static_cast<double>(histo[x]) / static_cast<double>(numFields);
401 }
402
403 // Adjust the heights so that all height values are equal of density.
404 // This is done to have reliable water/land ratio later on.
405 for (uint32_t x = 0; x < w; ++x)
406 for (uint32_t y = 0; y < h; ++y)
407 values[x + y * w] =
408 minVals[values[x + y * w] >> 22]
409 *
410 static_cast<double>(MAX_ELEVATION(0xffffffff));
411 return values;
412 } catch (...) {
413 delete[] values;
414 throw;
415 }
416
417 return 0; // Should not be reached
418}
419
420
421/**
422===============
423Figures out terrain info for a field in a random map.
424
425mapGenInfo: Map generator information used to translate
426 Random values to height information (world-
427 specific info)
428x, y: first coordinate of the current triangle
429x1, y1: second coordinate of the current triangle
430x2, y2: third coordinate of the current triangle
431random2: Random array for generating different
432 terrain types on land
433random3: Random array for generating different
434 terrain types on land
435random4: Random array for wasteland generation
436h1, h2, h3: Map height information for the three triangle coords
437mapInfo: Information about the random map currently
438 begin created (map specific info)
439rng: is the random number generator to be used.
440 This will mostly be the current rng of the random map
441 currently being created.
442terrType: Returns the terrain-Type fpor this triangle
443===============
444*/
445Terrain_Index MapGenerator::figure_out_terrain
446 (uint32_t * const random2,
447 uint32_t * const random3,
448 uint32_t * const random4,
449 Coords const c0, Coords const c1, Coords const c2,
450 uint32_t const h1, uint32_t const h2, uint32_t const h3,
451 RNG & rng,
452 MapGenAreaInfo::MapGenTerrainType & terrType)
453{
454 MapGenInfo & mapGenInfo = m_map.world().getMapGenInfo();
455
456 uint32_t numLandAreas =
457 mapGenInfo.getNumAreas(MapGenAreaInfo::atLand);
458 uint32_t const numWasteLandAreas =
459 mapGenInfo.getNumAreas(MapGenAreaInfo::atWasteland);
460
461 bool isDesert = false;
462 bool isDesertOuter = false;
463 uint32_t landAreaIndex = 0;
464 MapGenAreaInfo::MapGenAreaType landType = MapGenAreaInfo::atLand;
465
466 uint32_t rand2 =
467 random2[c0.x + m_mapInfo.w * c0.y] / 3 +
468 random2[c1.x + m_mapInfo.w * c1.y] / 3 +
469 random2[c2.x + m_mapInfo.w * c2.y] / 3;
470 uint32_t rand3 =
471 random3[c0.x + m_mapInfo.w * c0.y] / 3 +
472 random3[c1.x + m_mapInfo.w * c1.y] / 3 +
473 random3[c2.x + m_mapInfo.w * c2.y] / 3;
474 uint32_t rand4 =
475 random4[c0.x + m_mapInfo.w * c0.y] / 3 +
476 random4[c1.x + m_mapInfo.w * c1.y] / 3 +
477 random4[c2.x + m_mapInfo.w * c2.y] / 3;
478
479 // At first we figure out if it is wasteland or not.
480
481 if (numWasteLandAreas == 0) {
482 } else if (numWasteLandAreas == 1) {
483 if (rand4 < (AVG_ELEVATION(0x80000000) * m_mapInfo.wastelandRatio)) {
484 numLandAreas = numWasteLandAreas;
485 isDesert = true;
486 isDesertOuter =
487 rand4 > (AVG_ELEVATION(0x80000000) * m_mapInfo.wastelandRatio / 4) * 3;
488 landAreaIndex = 0;
489 }
490 } else {
491 if (rand4<(AVG_ELEVATION(0x80000000) * m_mapInfo.wastelandRatio * 0.5)) {
492 numLandAreas = numWasteLandAreas;
493 isDesert = true;
494 isDesertOuter =
495 rand4 > (AVG_ELEVATION(0x80000000) * m_mapInfo.wastelandRatio * 0.5 / 4) * 3;
496 landAreaIndex = 0;
497 }
498 else if
499 (rand4
500 >
501 (MAX_ELEVATION(0xffffffff) - AVG_ELEVATION(0x80000000) * m_mapInfo.wastelandRatio * 0.5))
502 {
503 numLandAreas = numWasteLandAreas;
504 isDesert = true;
505 isDesertOuter =
506 rand4
507 <
508 1 - AVG_ELEVATION(0x80000000) * m_mapInfo.wastelandRatio * 0.5 / 4 * 3;
509 landAreaIndex = 1;
510 }
511 }
512
513 MapGenAreaInfo::MapGenAreaType atp = MapGenAreaInfo::atLand;
514 MapGenAreaInfo::MapGenTerrainType ttp = MapGenAreaInfo::ttLandLand;
515
516 if (!isDesert) { // see what kind of land it is
517
518 if (numLandAreas == 1)
519 landAreaIndex = 0;
520 else if (numLandAreas == 2) {
521 uint32_t const weight1 =
522 mapGenInfo.getArea(MapGenAreaInfo::atLand, 0).getWeight();
523 uint32_t const weight2 =
524 mapGenInfo.getArea(MapGenAreaInfo::atLand, 1).getWeight();
525 uint32_t const sum = mapGenInfo.getSumLandWeight();
526 if
527 (weight1 * (random2[c0.x + m_mapInfo.w * c0.y] / sum)
528 >=
529 weight2 * (AVG_ELEVATION(0x80000000) / sum))
530 landAreaIndex = 0;
531 else
532 landAreaIndex = 1;
533 } else {
534 uint32_t const weight1 =
535 mapGenInfo.getArea(MapGenAreaInfo::atLand, 0).getWeight();
536 uint32_t const weight2 =
537 mapGenInfo.getArea(MapGenAreaInfo::atLand, 1).getWeight();
538 uint32_t const weight3 =
539 mapGenInfo.getArea(MapGenAreaInfo::atLand, 2).getWeight();
540 uint32_t const sum = mapGenInfo.getSumLandWeight();
541 uint32_t const randomX = (rand2 + rand3) / 2;
542 if
543 (weight1 * (rand2 / sum) > weight2 * (rand3 / sum) &&
544 weight1 * (rand2 / sum) > weight3 * (randomX / sum))
545 landAreaIndex = 0;
546 else if
547 (weight2 * (rand3 / sum) > weight1 * (rand2 / sum) &&
548 weight2 * (rand3 / sum) > weight3 * (randomX / sum))
549 landAreaIndex = 1;
550 else
551 landAreaIndex = 2;
552 }
553
554 atp = MapGenAreaInfo::atLand;
555 ttp = MapGenAreaInfo::ttLandLand;
556 } else {
557 atp = MapGenAreaInfo::atWasteland;
558 ttp = MapGenAreaInfo::ttWastelandInner;
559 }
560
561 // see whether it is water
562
563 uint32_t const coast_h = mapGenInfo.getLandCoastHeight();
564 if (h1 <= coast_h && h2 <= coast_h && h3 <= coast_h) { // water or coast...
565 atp = landType;
566 ttp = MapGenAreaInfo::ttLandCoast;
567
568 uint32_t const ocean_h = mapGenInfo.getWaterOceanHeight();
569 uint32_t const shelf_h = mapGenInfo.getWaterShelfHeight();
570 uint32_t const shallow_h = mapGenInfo.getWaterShallowHeight();
571
572 // TODO: The heights can not be lower than water-Shallow --
573 // TODO: there will never be an ocean yet
574
575 if (h1 <= ocean_h && h2 <= ocean_h && h3 <= ocean_h) {
576 atp = MapGenAreaInfo::atWater;
577 ttp = MapGenAreaInfo::ttWaterOcean;
578 } else if (h1 <= shelf_h && h2 <= shelf_h && h3 <= shelf_h) {
579 atp = MapGenAreaInfo::atWater;
580 ttp = MapGenAreaInfo::ttWaterShelf;
581 } else if (h1 <= shallow_h && h2 <= shallow_h && h3 <= shallow_h) {
582 atp = MapGenAreaInfo::atWater;
583 ttp = MapGenAreaInfo::ttWaterShallow;
584 }
585 } else { // it is not water
586 uint32_t const upper_h = mapGenInfo.getLandUpperHeight ();
587 uint32_t const foot_h = mapGenInfo.getMountainFootHeight();
588 uint32_t const mount_h = mapGenInfo.getMountainHeight ();
589 uint32_t const snow_h = mapGenInfo.getSnowHeight ();
590 if (h1 >= snow_h && h2 >= snow_h && h3 >= snow_h) {
591 atp = MapGenAreaInfo::atMountains;
592 ttp = MapGenAreaInfo::ttMountainsSnow;
593 } else if (h1 >= mount_h && h2 >= mount_h && h3 >= mount_h) {
594 atp = MapGenAreaInfo::atMountains;
595 ttp = MapGenAreaInfo::ttMountainsMountain;
596 } else if (h1 >= foot_h && h2 >= foot_h && h3 >= foot_h) {
597 atp = MapGenAreaInfo::atMountains;
598 ttp = MapGenAreaInfo::ttMountainsFoot;
599 } else if (h1 >= upper_h && h2 >= upper_h && h3 >= upper_h) {
600 atp = MapGenAreaInfo::atLand;
601 ttp = MapGenAreaInfo::ttLandUpper;
602 }
603 }
604
605 // Aftermath for land/Wasteland.
606
607 uint32_t usedLandIndex = landAreaIndex;
608 if (atp != MapGenAreaInfo::atLand && atp != MapGenAreaInfo::atWasteland)
609 usedLandIndex = 0;
610 else if (isDesert) {
611 atp = MapGenAreaInfo::atWasteland;
612 ttp =
613 ttp == MapGenAreaInfo::ttLandCoast || isDesertOuter ?
614 MapGenAreaInfo::ttWastelandOuter : MapGenAreaInfo::ttWastelandInner;
615 }
616
617 // Return terrain type
618 terrType = ttp;
619
620 // Figure out which terrain to use at this point in the map...
621 return
622 mapGenInfo.getArea(atp, usedLandIndex).getTerrain
623 (ttp,
624 rng.rand()
625 %
626 mapGenInfo.getArea(atp, usedLandIndex).getNumTerrains(ttp));
627
628}
629
630
631void MapGenerator::create_random_map()
632{
633 // Init random number generator with map number
634
635 // We will use our own random number generator here so we do not influence
636 // someone else...
637 RNG rng;
638
639 rng.seed(m_mapInfo.mapNumber);
640
641 // get world generator info
642 MapGenInfo & mapGenInfo = m_map.world().getMapGenInfo();
643
644 // Create a "raw" random elevation matrix.
645 // We will transform this into reasonable elevations and terrains later on.
646
647 scoped_array<uint32_t> elevations
648 (generate_random_value_map(m_mapInfo.w, m_mapInfo.h, rng));
649
650 // for land stuff
651 scoped_array<uint32_t> random2
652 (generate_random_value_map(m_mapInfo.w, m_mapInfo.h, rng));
653 scoped_array<uint32_t> random3
654 (generate_random_value_map(m_mapInfo.w, m_mapInfo.h, rng));
655
656 // for desert/land
657 scoped_array<uint32_t> random4
658 (generate_random_value_map(m_mapInfo.w, m_mapInfo.h, rng));
659
660 // for resources
661 scoped_array<uint32_t> random_rsrc_1
662 (generate_random_value_map(m_mapInfo.w, m_mapInfo.h, rng));
663 scoped_array<uint32_t> random_rsrc_2
664 (generate_random_value_map(m_mapInfo.w, m_mapInfo.h, rng));
665 scoped_array<uint32_t> random_rsrc_3
666 (generate_random_value_map(m_mapInfo.w, m_mapInfo.h, rng));
667 scoped_array<uint32_t> random_rsrc_4
668 (generate_random_value_map(m_mapInfo.w, m_mapInfo.h, rng));
669
670 // for bobs
671 scoped_array<scoped_array<uint32_t> > random_bobs
672 (new scoped_array<uint32_t> [mapGenInfo.getNumBobAreas()]);
673
674 for (size_t ix = 0; ix < mapGenInfo.getNumBobAreas(); ++ix)
1
Loop condition is false. Execution continues on line 680
675 random_bobs[ix].reset
676 (generate_random_value_map(m_mapInfo.w, m_mapInfo.h, rng));
677
678 // Now we have generated a lot of random data!!
679 // Lets use it !!!
680 iterate_Map_FCoords(m_map, m_mapInfo, fc)for (Widelands::FCoords fc = (m_map).get_fcoords(Widelands::Coords
(0, 0)); fc.y < static_cast<Widelands::Y_Coordinate>
(m_mapInfo.h); ++fc.y) for (fc.x = 0; fc.x < static_cast<
Widelands::X_Coordinate>(m_mapInfo.w); ++fc.x, ++fc.field)
681 fc.field->set_height
682 (make_node_elevation
683 (static_cast<double>(elevations[fc.x + m_mapInfo.w * fc.y])
684 /
685 static_cast<double>(MAX_ELEVATION(0xffffffff)),
686 fc));
687
688 // Now lets set the terrain right according to the heights.
689
690 iterate_Map_FCoords(m_map, m_mapInfo, fc)for (Widelands::FCoords fc = (m_map).get_fcoords(Widelands::Coords
(0, 0)); fc.y < static_cast<Widelands::Y_Coordinate>
(m_mapInfo.h); ++fc.y) for (fc.x = 0; fc.x < static_cast<
Widelands::X_Coordinate>(m_mapInfo.w); ++fc.x, ++fc.field)
{
691 // Calculate coordinates of left and bottom left neighbours of the
692 // current node.
693
694 // ... Treat "even" and "uneven" row numbers differently
695 uint32_t const x_dec = fc.y % 2 == 0;
696
697 uint32_t right_x = fc.x + 1;
698 uint32_t lower_y = fc.y + 1;
699 uint32_t lower_x = fc.x - x_dec;
700 uint32_t lower_right_x = fc.x - x_dec + 1;
701
702 if (lower_x > m_mapInfo.w) lower_x += m_mapInfo.w;
703 if (right_x >= m_mapInfo.w) right_x -= m_mapInfo.w;
704 if (lower_x >= m_mapInfo.w) lower_x -= m_mapInfo.w;
705 if (lower_right_x >= m_mapInfo.w) lower_right_x -= m_mapInfo.w;
706 if (lower_y >= m_mapInfo.h) lower_y -= m_mapInfo.h;
707
708 // get the heights of my neighbour nodes and of my current node
709
710 uint8_t height_x0_y0 =
711 fc.field ->get_height();
712 uint8_t height_x1_y0 =
713 m_map[Coords(right_x, fc.y)].get_height();
714 uint8_t height_x0_y1 =
715 m_map[Coords(lower_x, lower_y)].get_height();
716 uint8_t height_x1_y1 =
717 m_map[Coords(lower_right_x, lower_y)].get_height();
718
719 MapGenAreaInfo::MapGenTerrainType terrType;
720
721 fc.field->set_terrain_d
722 (figure_out_terrain
723 (random2.get(), random3.get(), random4.get(),
724 fc, Coords(lower_x, lower_y), Coords(lower_right_x, lower_y),
725 height_x0_y0, height_x0_y1, height_x1_y1,
726 rng, terrType));
727
728 fc.field->set_terrain_r
729 (figure_out_terrain
730 (random2.get(), random3.get(), random4.get(),
731 fc, Coords(right_x, fc.y), Coords(lower_right_x, lower_y),
732 height_x0_y0, height_x1_y0, height_x1_y1,
733 rng, terrType));
734
735 // set resources for this field
736 generate_resources
737 (random_rsrc_1.get(), random_rsrc_2.get(),
738 random_rsrc_3.get(), random_rsrc_4.get(),
739 fc);
740
741 // set bobs and immovables for this field
742 generate_bobs(random_bobs.get(), fc, rng, terrType);
743 }
744
745 // Aftermaths...
746 m_map.recalc_whole_map();
747
748 // Care about players and place their start positions
749 const std::string tribe = m_map.get_scenario_player_tribe(1);
750 const std::string ai = m_map.get_scenario_player_ai(1);
751 m_map.set_nrplayers(m_mapInfo.numPlayers);
752 FindNodeSize functor(FindNodeSize::sizeBig);
753 Coords playerstart;
754
755 // Build a basic structure how player start positions are placed
756 uint8_t line[3];
757 uint8_t rows = 1, lines = 1;
758 if (m_mapInfo.numPlayers > 1) {
2
Taking false branch
759 ++lines;
760 if (m_mapInfo.numPlayers > 2) {
761 ++rows;
762 if (m_mapInfo.numPlayers > 4) {
763 ++lines;
764 if (m_mapInfo.numPlayers > 6) {
765 ++rows;
766 }
767 }
768 }
769 }
770 line[0] = line[1] = line[2] = rows;
771 if (rows * lines > m_mapInfo.numPlayers) {
3
Taking true branch
772 --line[1];
773 if (rows * lines - 1 > m_mapInfo.numPlayers)
4
Taking false branch
774 --line[2];
775 }
776
777 // Random placement of starting positions
778 Player_Number pn[m_mapInfo.numPlayers];
5
Declared variable-length array (VLA) has zero size
779 for (Player_Number n = 1; n <= m_mapInfo.numPlayers; ++n) {
780 bool okay = false;
781 // This is a kinda dump algorithm -> we generate a random number and increase it until it fits.
782 // However it's working and simple ;) - if you've got a better idea, feel free to fix it.
783 Player_Number x = rng.rand() % m_mapInfo.numPlayers;
784 while (!okay) {
785 okay = true;
786 ++x; // Player_Number begins at 1 not at 0
787 for (Player_Number p = 1; p < n; ++p) {
788 if (pn[p - 1] == x) {
789 okay = false;
790 x = x % m_mapInfo.numPlayers;
791 break;
792 }
793 }
794 }
795 pn[n - 1] = x;
796 }
797
798 for (Player_Number n = 1; n <= m_mapInfo.numPlayers; ++n) {
799 // Set scenario information - needed even if it's not a scenario
800 m_map.set_scenario_player_name(n, "Random Player");
801 m_map.set_scenario_player_tribe(n, tribe);
802 m_map.set_scenario_player_ai(n, ai);
803 m_map.set_scenario_player_closeable(n, false);
804
805 // Calculate wished coords for player starting position
806 if (line[0] + 1 > pn[n - 1]) {
807 // X-Coordinates
808 playerstart.x = m_mapInfo.w * (line[0] * line[0] + 1 - pn[n - 1] * pn[n - 1]);
809 playerstart.x /= line[0] * line[0] + 1;
810 // Y-Coordinates
811 if (lines == 1)
812 playerstart.y = m_mapInfo.h / 2;
813 else
814 playerstart.y = m_mapInfo.h / 7 + ISLAND_BORDER10;
815 } else if (line[0] + line[1] + 1 > pn[n - 1]) {
816 // X-Coordinates
817 uint8_t pos = pn[n - 1] - line[0];
818 playerstart.x = m_mapInfo.w;
819 playerstart.x *= line[1] * line[1] + 1 - pos * pos;
820 playerstart.x /= line[1] * line[1] + 1;
821 // Y-Coordinates
822 if (lines == 3)
823 playerstart.y = m_mapInfo.h / 2;
824 else
825 playerstart.y = m_mapInfo.h - m_mapInfo.h / 7 - ISLAND_BORDER10;
826 } else {
827 // X-Coordinates
828 uint8_t pos = pn[n - 1] - line[0] - line[1];
829 playerstart.x = m_mapInfo.w;
830 playerstart.x *= line[2] * line[2] + 1 - pos * pos;
831 playerstart.x /= line[2] * line[2] + 1;
832 // Y-Coordinates
833 playerstart.y = m_mapInfo.h - m_mapInfo.h / 7 - ISLAND_BORDER10;
834 }
835
836 // Now try to find a place as near as possible to the wished
837 // starting position
838 std::vector<Coords> coords;
839 m_map.find_fields
840 (Area<FCoords>(m_map.get_fcoords(playerstart), 20),
841 &coords, functor);
842
843 // Take the nearest ones
844 uint32_t min_distance = -1;
845 Coords coords2;
846 for (uint16_t i = 0; i < coords.size(); ++i) {
847 uint32_t test = m_map.calc_distance(coords[i], playerstart);
848 if (test < min_distance) {
849 min_distance = test;
850 coords2 = coords[i];
851 }
852 }
853
854 if (coords.empty()) {
855 // TODO inform players via popup
856 log("WARNING: Could not find a suitable place for player %u\n", n);
857 // Let's hope that one is at least on dry ground.
858 coords2 = playerstart;
859 }
860
861 // Finally set the found starting position
862 m_map.set_starting_pos(n, coords2);
863 }
864}
865
866/**
867===============
868Converts a character out of a mapId-String into an integer value.
869Valid characters are 'a'-'z' (or 'A'-'Z') and '2'-'9'. 'i' and 'o'
870(or 'I' and 'O') are not valid.
871The character is treated case-insensitive.
872
873num: Number to convert
874Return value: The resulting number (0-31) or -1 if the character
875 was no legal character.
876===============
877*/
878
879int UniqueRandomMapInfo::mapIdCharToNumber(char ch)
880{
881 if ((ch == '0') || (ch == 'o') || (ch == 'O'))
882 return 22;
883 else if
884 ((ch == '1') || (ch == 'l') || (ch == 'L') ||
885 (ch == 'I') || (ch == 'i') || (ch == 'J') || (ch == 'j'))
886 return 23;
887 else if (ch >= 'A' && ch < 'O') {
888 char res = ch - 'A';
889 if (ch > 'I')
890 --res;
891 if (ch > 'J')
892 --res;
893 if (ch > 'L')
894 --res;
895 if (ch > 'O')
896 --res;
897 return res;
898 }
899 else if (ch >= 'a' && ch <= 'z') {
900 char res = ch - 'a';
901 if (ch > 'i')
902 --res;
903 if (ch > 'j')
904 --res;
905 if (ch > 'l')
906 --res;
907 if (ch > 'o')
908 --res;
909 return res;
910 }
911 else if (ch >= '2' && ch <= '9')
912 return 24 + ch - '2';
913 return -1;
914}
915
916/**
917===============
918Converts an integer number (0-31) to a characted usable in
919a map id string.
920
921num: Number to convert
922Return value: The converted value as a character
923===============
924*/
925char UniqueRandomMapInfo::mapIdNumberToChar(int32_t const num)
926{
927 if (num == 22)
928 return '0';
929 else if (num == 23)
930 return '1';
931 else if ((0 <= num) && (num < 22)) {
932 char result = num + 'a';
933 if (result >= 'i')
934 ++result;
935 if (result >= 'j')
936 ++result;
937 if (result >= 'l')
938 ++result;
939 if (result >= 'o')
940 ++result;
941 return result;
942 } else if ((24 <= num) && (num < 32))
943 return (num - 24) + '2';
944 else
945 return '?';
946}
947
948/**
949===============
950Fills a UniqueRandomMapInfo structure from a given Map-id-string.
951
952mapIdString: Map-Id-String
953mapInfo_out: UniqueRandomMapInfo-Structure to be filled
954Return value: true if the map-id-string was valid, false otherwise
955===============
956*/
957
958bool UniqueRandomMapInfo::setFromIdString
959 (UniqueRandomMapInfo & mapInfo_out, const std::string & mapIdString,
960 const std::vector<std::string> & worlds)
961{
962 // check string
963
964 if (mapIdString.length() != MAP_ID_DIGITS24 + MAP_ID_DIGITS24 / 4 - 1)
965 return false;
966
967 for (uint32_t ix = 4; ix < MAP_ID_DIGITS24; ix += 5)
968 if (mapIdString[ix] != '-')
969 return false;
970
971 // convert digits to values
972
973 int32_t nums[MAP_ID_DIGITS24];
974
975 for (uint32_t ix = 0; ix < MAP_ID_DIGITS24; ++ix) {
976 int const num = mapIdCharToNumber(mapIdString[ix + (ix / 4)]);
977 if (num < 0)
978 return false;
979 nums[ix] = num;
980 }
981
982 // get xxor start value
983
984 int32_t xorr = nums[MAP_ID_DIGITS24 - 1];
985
986 for (int32_t ix = MAP_ID_DIGITS24 - 1; ix >= 0; --ix) {
987 nums[ix] = nums[ix] ^ xorr;
988 xorr -= 7;
989 xorr -= ix;
990 if (xorr < 0)
991 xorr &= 0x0000001f;
992 }
993
994 // check if xxor was right
995 if (nums[MAP_ID_DIGITS24 - 1])
996 return false;
997
998 // check if version number is 1
999 if (nums[MAP_ID_DIGITS24 - 2] != 1)
1000 return false;
1001
1002 // check if csm is right
1003 if (nums[MAP_ID_DIGITS24 - 3] != 0x15)
1004 return false;
1005
1006
1007 // convert map number
1008 mapInfo_out.mapNumber =
1009 (nums[0]) |
1010 (nums[1] << 5) |
1011 (nums[2] << 10) |
1012 (nums[3] << 15) |
1013 (nums[4] << 20) |
1014 (nums[5] << 25) |
1015 ((nums[6] & 3) << 30);
1016
1017 // Convert amount of resources
1018 mapInfo_out.resource_amount =
1019 static_cast<Widelands::UniqueRandomMapInfo::Resource_Amount>
1020 ((nums[6] & 0xc) >> 2);
1021
1022 if
1023 (mapInfo_out.resource_amount >
1024 Widelands::UniqueRandomMapInfo::raHigh)
1025 return false;
1026
1027 // Convert map size
1028 mapInfo_out.w = nums[7] * 16 + 64;
1029 mapInfo_out.h = nums[8] * 16 + 64;
1030
1031 // Convert water percent
1032 mapInfo_out.waterRatio = static_cast<double>(nums[9]) / 20.0;
1033 // Convert land percent
1034 mapInfo_out.landRatio = static_cast<double>(nums[10]) / 20.0;
1035 // Convert wasteland percent
1036 mapInfo_out.wastelandRatio = static_cast<double>(nums[11]) / 20.0;
1037 // Number of players
1038 mapInfo_out.numPlayers = nums[12];
1039 // Island mode
1040 mapInfo_out.islandMode = (nums[13] == 1) ? true : false;
1041
1042 // World name hash
1043 uint16_t nameHash = nums[14];
1044 nameHash |= nums[15] << 5;
1045 nameHash |= nums[16] << 10;
1046 nameHash |= nums[17] << 15;
1047
1048 for (size_t idx = 0; idx<worlds.size(); idx++)
1049 if (generateWorldNameHash(worlds[idx]) == nameHash) {
1050 mapInfo_out.worldName = worlds[idx];
1051 return true;
1052 }
1053
1054 return false; // No valid world name found
1055}
1056
1057/**
1058===============
1059Generates an ID-String for map generation.
1060The ID-String is an encoded version of the
1061information in a UniqueMapInfo structure.
1062Thus, the ID_String will contain all info
1063necessary to re-create a given random map.
1064
1065mapIdsString_out: Output buffer for the resulting
1066 Map-ID-String
1067mapInfo: Information about the random map currently
1068 begin created (map specific info)
1069===============
1070*/
1071void UniqueRandomMapInfo::generateIdString
1072 (std::string & mapIdsString_out, const UniqueRandomMapInfo & mapInfo)
1073{
1074 // Init
1075 assert(mapInfo.w <= 560)((mapInfo.w <= 560) ? static_cast<void> (0) : __assert_fail
("mapInfo.w <= 560", "/home/arch/widelands/src/map_generator.cc"
, 1075, __PRETTY_FUNCTION__))
;
1076 assert(mapInfo.h <= 560)((mapInfo.h <= 560) ? static_cast<void> (0) : __assert_fail
("mapInfo.h <= 560", "/home/arch/widelands/src/map_generator.cc"
, 1076, __PRETTY_FUNCTION__))
;
1077 assert(mapInfo.waterRatio >= 0.0)((mapInfo.waterRatio >= 0.0) ? static_cast<void> (0)
: __assert_fail ("mapInfo.waterRatio >= 0.0", "/home/arch/widelands/src/map_generator.cc"
, 1077, __PRETTY_FUNCTION__))
;
1078 assert(mapInfo.waterRatio <= 1.0)((mapInfo.waterRatio <= 1.0) ? static_cast<void> (0)
: __assert_fail ("mapInfo.waterRatio <= 1.0", "/home/arch/widelands/src/map_generator.cc"
, 1078, __PRETTY_FUNCTION__))
;
1079 assert(mapInfo.landRatio >= 0.0)((mapInfo.landRatio >= 0.0) ? static_cast<void> (0) :
__assert_fail ("mapInfo.landRatio >= 0.0", "/home/arch/widelands/src/map_generator.cc"
, 1079, __PRETTY_FUNCTION__))
;
1080 assert(mapInfo.landRatio <= 1.0)((mapInfo.landRatio <= 1.0) ? static_cast<void> (0) :
__assert_fail ("mapInfo.landRatio <= 1.0", "/home/arch/widelands/src/map_generator.cc"
, 1080, __PRETTY_FUNCTION__))
;
1081 assert(mapInfo.wastelandRatio >= 0.0)((mapInfo.wastelandRatio >= 0.0) ? static_cast<void>
(0) : __assert_fail ("mapInfo.wastelandRatio >= 0.0", "/home/arch/widelands/src/map_generator.cc"
, 1081, __PRETTY_FUNCTION__))
;
1082 assert(mapInfo.wastelandRatio <= 1.0)((mapInfo.wastelandRatio <= 1.0) ? static_cast<void>
(0) : __assert_fail ("mapInfo.wastelandRatio <= 1.0", "/home/arch/widelands/src/map_generator.cc"
, 1082, __PRETTY_FUNCTION__))
;
1083 assert(mapInfo.resource_amount <= Widelands::UniqueRandomMapInfo::raHigh)((mapInfo.resource_amount <= Widelands::UniqueRandomMapInfo
::raHigh) ? static_cast<void> (0) : __assert_fail ("mapInfo.resource_amount <= Widelands::UniqueRandomMapInfo::raHigh"
, "/home/arch/widelands/src/map_generator.cc", 1083, __PRETTY_FUNCTION__
))
;
1084
1085 mapIdsString_out = "";
1086 int32_t nums[MAP_ID_DIGITS24];
1087 for (uint32_t ix = 0; ix < MAP_ID_DIGITS24; ++ix)
1088 nums[ix] = 0;
1089
1090 // Generate world name hash
1091 uint16_t nameHash = generateWorldNameHash(mapInfo.worldName);
1092
1093 // Convert map random number
1094 nums [0] = mapInfo.mapNumber & 31;
1095 nums [1] = (mapInfo.mapNumber >> 5) & 31;
1096 nums [2] = (mapInfo.mapNumber >> 10) & 31;
1097 nums [3] = (mapInfo.mapNumber >> 15) & 31;
1098
1099 nums [4] = (mapInfo.mapNumber >> 20) & 31;
1100 nums [5] = (mapInfo.mapNumber >> 25) & 31;
1101 nums [6] = (mapInfo.mapNumber >> 30) & 3;
1102
1103 // Convert amount of resources
1104 nums [6] |= (mapInfo.resource_amount & 3) << 2;
1105 // Convert width
1106 nums [7] = (mapInfo.w - 64) / 16;
1107
1108
1109 // Convert height
1110 nums [8] = (mapInfo.h - 64) / 16;
1111 // Convert water percent
1112 nums [9] = (mapInfo.waterRatio + 0.025) * 20.0;
1113 // Convert land percent
1114 nums[10] = (mapInfo.landRatio + 0.025) * 20.0;
1115 // Convert wasteland percent
1116 nums[11] = (mapInfo.wastelandRatio + 0.025) * 20.0;
1117
1118 // Set number of islands
1119 nums[12] = mapInfo.numPlayers;
1120 // Island mode
1121 nums[13] = mapInfo.islandMode ? 1 : 0;
1122 // World name hash (16 bit)
1123 nums[14] = nameHash & 31;
1124 nums[15] = (nameHash >> 5) & 31;
1125
1126 nums[16] = (nameHash >> 10) & 31;
1127 nums[17] = (nameHash >> 15) & 1;
1128
1129 // Set id csm
1130 nums[MAP_ID_DIGITS24 - 3] = 0x15;
1131 // Set id version number
1132 nums[MAP_ID_DIGITS24 - 2] = 0x01;
1133 // Last number intentionally left blank
1134 nums[MAP_ID_DIGITS24 - 1] = 0x00;
1135
1136
1137 // Nox xor everything
1138 // This lets it look better
1139 // Every change in a digit will result in a complete id change
1140
1141 int32_t xorr = 0x0a;
1142 for (uint32_t ix = 0; ix < MAP_ID_DIGITS24; ++ix)
1143 xorr = xorr ^ nums[ix];
1144
1145 for (int32_t ix = MAP_ID_DIGITS24 - 1; ix >= 0; --ix) {
1146 nums[ix] = nums[ix] ^ xorr;
1147 xorr -= 7;
1148 xorr -= ix;
1149 if (xorr < 0)
1150 xorr &= 0x0000001f;
1151 }
1152
1153 // translate it to ASCII
1154 for (uint32_t ix = 0; ix < MAP_ID_DIGITS24; ++ix) {
1155 mapIdsString_out += mapIdNumberToChar(nums[ix]);
1156 if (ix % 4 == 3 && ix != MAP_ID_DIGITS24 - 1)
1157 mapIdsString_out += "-";
1158 }
1159}
1160
1161
1162uint16_t Widelands::UniqueRandomMapInfo::generateWorldNameHash
1163 (const std::string & name)
1164{
1165 // This is only a simple digest algorithm. Thats enough for our purposes.
1166
1167 uint16_t hash = 0xa5a5;
1168 int32_t posInHash = 0;
1169
1170 for (size_t idx = 0; idx<name.size(); idx++) {
1171 hash ^= static_cast<uint8_t>(name[idx] & 0xff) << posInHash;
1172 posInHash ^= 8;
1173 }
1174
1175 hash ^= (name.size() & 0xff) << 4;
1176
1177 return hash;
1178}
1179
1180// TODO: Also take mountain and water areas into bob generation
1181// (we have ducks and chamois)
1182// TODO: Move other map generation functions from Map to MapGenerator
1183// TODO: Define the "none"-bob to weigh other bobs lower within BobKinds...
1184// TODO: Clean up code
1185// TODO: Improve mapgenconf files for nicer generated worlds
1186// TODO: MapGen: Bob generation, configurable in mapgenconf
1187// TODO: MapGen: How to handle "Bob layers" ???
1188// TODO: MapGen: Resource generation, configurable in mapgenconf
1189// TODO: MapGen: Check out sample map
1190// TODO: MapGen: Generate Start positions
1191// TODO: MapGen: How to handle height profile in make_blah...
1192// TODO: MapGen: Display something else than
1193// TODO: "Preparing..." when generating map...
1194// TODO: MapGen: Allow up to 3 different water areas
1195
1196};