1 /***********************************************************************
2 Freeciv - Copyright (C) 1996 - A Kjeldberg, L Gregersen, P Unold
3 This program is free software; you can redistribute it and/or modify
4 it under the terms of the GNU General Public License as published by
5 the Free Software Foundation; either version 2, or (at your option)
8 This program is distributed in the hope that it will be useful,
9 but WITHOUT ANY WARRANTY; without even the implied warranty of
10 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 GNU General Public License for more details.
12 ***********************************************************************/
15 #include <fc_config.h>
24 #include "bitvector.h"
27 #include "maphand.h" /* assign_continent_numbers(), MAP_NCONT */
37 /* server/generator */
38 #include "fracture_map.h"
39 #include "height_map.h"
40 #include "mapgen_topology.h"
41 #include "mapgen_utils.h"
43 #include "temperature_map.h"
47 static void make_huts(int number
);
48 static void add_resources(int prob
);
49 static void mapgenerator2(void);
50 static void mapgenerator3(void);
51 static void mapgenerator4(void);
52 static bool map_generate_fair_islands(void);
53 static void adjust_terrain_param(void);
55 /* common variables for generator 2, 3 and 4 */
57 int isleindex
, n
, e
, s
, w
;
61 /* define one terrain selection */
62 struct terrain_select
{
64 enum mapgen_terrain_property target
;
65 enum mapgen_terrain_property prefer
;
66 enum mapgen_terrain_property avoid
;
72 static struct extra_type
*river_types
[MAX_ROAD_TYPES
];
73 static int river_type_count
= 0;
75 #define SPECLIST_TAG terrain_select
77 /* list iterator for terrain_select */
78 #define terrain_select_list_iterate(tersel_list, ptersel) \
79 TYPED_LIST_ITERATE(struct terrain_select, tersel_list, ptersel)
80 #define terrain_select_list_iterate_end \
83 static struct terrain_select
*tersel_new(int weight
,
84 enum mapgen_terrain_property target
,
85 enum mapgen_terrain_property prefer
,
86 enum mapgen_terrain_property avoid
,
89 static void tersel_free(struct terrain_select
*ptersel
);
91 /* terrain selection lists for make_island() */
94 struct terrain_select_list
*forest
;
95 struct terrain_select_list
*desert
;
96 struct terrain_select_list
*mountain
;
97 struct terrain_select_list
*swamp
;
98 } island_terrain
= { .init
= FALSE
};
100 static void island_terrain_init(void);
101 static void island_terrain_free(void);
103 static void fill_island(int coast
, long int *bucket
,
104 const struct terrain_select_list
*tersel_list
,
105 const struct gen234_state
*const pstate
);
106 static bool make_island(int islemass
, int starters
,
107 struct gen234_state
*pstate
,
108 int min_specific_island_size
);
110 #define RIVERS_MAXTRIES 32767
111 /* This struct includes two dynamic bitvectors. They are needed to mark
112 tiles as blocked to prevent a river from falling into itself, and for
113 storing rivers temporarly. */
119 static int river_test_blocked(struct river_map
*privermap
,
121 struct extra_type
*priver
);
122 static int river_test_rivergrid(struct river_map
*privermap
,
124 struct extra_type
*priver
);
125 static int river_test_highlands(struct river_map
*privermap
,
127 struct extra_type
*priver
);
128 static int river_test_adjacent_ocean(struct river_map
*privermap
,
130 struct extra_type
*priver
);
131 static int river_test_adjacent_river(struct river_map
*privermap
,
133 struct extra_type
*priver
);
134 static int river_test_adjacent_highlands(struct river_map
*privermap
,
136 struct extra_type
*priver
);
137 static int river_test_swamp(struct river_map
*privermap
,
139 struct extra_type
*priver
);
140 static int river_test_adjacent_swamp(struct river_map
*privermap
,
142 struct extra_type
*priver
);
143 static int river_test_height_map(struct river_map
*privermap
,
145 struct extra_type
*priver
);
146 static void river_blockmark(struct river_map
*privermap
,
148 static bool make_river(struct river_map
*privermap
,
150 struct extra_type
*priver
);
151 static void make_rivers(void);
153 static void river_types_init(void);
155 #define HAS_POLES (wld.map.server.temperature < 70 && !wld.map.server.alltemperate)
157 /* These are the old parameters of terrains types in %
158 TODO: they depend on the hardcoded terrains */
159 static int forest_pct
= 0;
160 static int desert_pct
= 0;
161 static int swamp_pct
= 0;
162 static int mountain_pct
= 0;
163 static int jungle_pct
= 0;
164 static int river_pct
= 0;
166 /****************************************************************************
167 * Conditions used mainly in rand_map_pos_characteristic()
168 ****************************************************************************/
171 /* necessary condition of deserts placement */
172 #define map_pos_is_dry(ptile) \
173 (map_colatitude((ptile)) <= DRY_MAX_LEVEL \
174 && map_colatitude((ptile)) > DRY_MIN_LEVEL \
175 && count_terrain_class_near_tile((ptile), FALSE, TRUE, TC_OCEAN) <= 35)
176 typedef enum { WC_ALL
= 200, WC_DRY
, WC_NDRY
} wetness_c
;
178 /* MISCELANEOUS (OTHER CONDITIONS) */
180 /* necessary condition of swamp placement */
181 static int hmap_low_level
= 0;
182 #define ini_hmap_low_level() \
184 hmap_low_level = (4 * swamp_pct * \
185 (hmap_max_level - hmap_shore_level)) / 100 + hmap_shore_level; \
187 /* should be used after having hmap_low_level initialized */
188 #define map_pos_is_low(ptile) ((hmap((ptile)) < hmap_low_level))
190 typedef enum { MC_NONE
, MC_LOW
, MC_NLOW
} miscellaneous_c
;
192 /***************************************************************************
193 These functions test for conditions used in rand_map_pos_characteristic
194 ***************************************************************************/
196 /***************************************************************************
197 Checks if the given location satisfy some wetness condition
198 ***************************************************************************/
199 static bool test_wetness(const struct tile
*ptile
, wetness_c c
)
205 return map_pos_is_dry(ptile
);
207 return !map_pos_is_dry(ptile
);
209 log_error("Invalid wetness_c %d", c
);
213 /***************************************************************************
214 Checks if the given location satisfy some miscellaneous condition
215 ***************************************************************************/
216 static bool test_miscellaneous(const struct tile
*ptile
, miscellaneous_c c
)
222 return map_pos_is_low(ptile
);
224 return !map_pos_is_low(ptile
);
226 log_error("Invalid miscellaneous_c %d", c
);
230 /***************************************************************************
231 Passed as data to rand_map_pos_filtered() by rand_map_pos_characteristic()
232 ***************************************************************************/
239 /****************************************************************************
240 A filter function to be passed to rand_map_pos_filtered(). See
241 rand_map_pos_characteristic for more explanation.
242 ****************************************************************************/
243 static bool condition_filter(const struct tile
*ptile
, const void *data
)
245 const struct DataFilter
*filter
= data
;
247 return not_placed(ptile
)
248 && tmap_is(ptile
, filter
->tc
)
249 && test_wetness(ptile
, filter
->wc
)
250 && test_miscellaneous(ptile
, filter
->mc
) ;
253 /****************************************************************************
254 Return random map coordinates which have some conditions and which are
255 not yet placed on pmap.
256 Returns FALSE if there is no such position.
257 ****************************************************************************/
258 static struct tile
*rand_map_pos_characteristic(wetness_c wc
,
262 struct DataFilter filter
;
268 return rand_map_pos_filtered(&(wld
.map
), &filter
, condition_filter
);
271 /**************************************************************************
272 we don't want huge areas of hill/mountains,
273 so we put in a plains here and there, where it gets too 'heigh'
275 Return TRUE if the terrain at the given map position is too heigh.
276 ****************************************************************************/
277 static bool terrain_is_too_high(struct tile
*ptile
,
278 int thill
, int my_height
)
280 square_iterate(&(wld
.map
), ptile
, 1, tile1
) {
281 if (hmap(tile1
) + (hmap_max_level
- hmap_mountain_level
) / 5 < thill
) {
284 } square_iterate_end
;
288 /**************************************************************************
289 make_relief() will convert all squares that are higher than thill to
290 mountains and hills. Note that thill will be adjusted according to
291 the map.server.steepness value, so increasing map.mountains will result
292 in more hills and mountains.
293 **************************************************************************/
294 static void make_relief(void)
296 /* Calculate the mountain level. map.server.mountains specifies the
297 * percentage of land that is turned into hills and mountains. */
298 hmap_mountain_level
= (((hmap_max_level
- hmap_shore_level
)
299 * (100 - wld
.map
.server
.steepness
))
300 / 100 + hmap_shore_level
);
302 whole_map_iterate(&(wld
.map
), ptile
) {
303 if (not_placed(ptile
)
304 && ((hmap_mountain_level
< hmap(ptile
)
306 || !terrain_is_too_high(ptile
, hmap_mountain_level
,
308 || area_is_too_flat(ptile
, hmap_mountain_level
, hmap(ptile
)))) {
309 if (tmap_is(ptile
, TT_HOT
)) {
310 /* Prefer hills to mountains in hot regions. */
311 tile_set_terrain(ptile
,
312 pick_terrain(MG_MOUNTAINOUS
, fc_rand(10) < 4
313 ? MG_UNUSED
: MG_GREEN
, MG_UNUSED
));
315 /* Prefer mountains hills to in cold regions. */
316 tile_set_terrain(ptile
,
317 pick_terrain(MG_MOUNTAINOUS
, MG_UNUSED
,
318 fc_rand(10) < 8 ? MG_GREEN
: MG_UNUSED
));
320 map_set_placed(ptile
);
322 } whole_map_iterate_end
;
325 /****************************************************************************
326 Add frozen tiles in the arctic zone.
327 If ruleset has frozen ocean, use that, else use frozen land terrains with
328 appropriate texturing.
329 This is used in generators 2-4.
330 ****************************************************************************/
331 static void make_polar(void)
333 struct terrain
*ocean
= pick_ocean(TERRAIN_OCEAN_DEPTH_MAXIMUM
, TRUE
);
335 whole_map_iterate(&(wld
.map
), ptile
) {
336 if (tmap_is(ptile
, TT_FROZEN
)
337 || (tmap_is(ptile
, TT_COLD
)
339 && is_temperature_type_near(ptile
, TT_FROZEN
))) {
341 tile_set_terrain(ptile
, ocean
);
343 tile_set_terrain(ptile
,
344 pick_terrain(MG_FROZEN
, MG_UNUSED
, MG_TROPICAL
));
347 } whole_map_iterate_end
;
350 /*************************************************************************
351 If separatepoles is set, return false if this tile has to keep ocean
352 *************************************************************************/
353 static bool ok_for_separate_poles(struct tile
*ptile
)
355 if (!wld
.map
.server
.separatepoles
) {
358 adjc_iterate(&(wld
.map
), ptile
, tile1
) {
359 if (tile_continent(tile1
) > 0) {
366 /****************************************************************************
367 Place untextured land at the poles on any tile that is not already
368 covered with TER_FROZEN terrain.
369 This is used by generators 1 and 5.
370 ****************************************************************************/
371 static void make_polar_land(void)
373 assign_continent_numbers();
375 whole_map_iterate(&(wld
.map
), ptile
) {
376 if ((tile_terrain(ptile
) == T_UNKNOWN
377 || !terrain_has_flag(tile_terrain(ptile
), TER_FROZEN
))
378 && ((tmap_is(ptile
, TT_FROZEN
)
379 && ok_for_separate_poles(ptile
))
380 || (tmap_is(ptile
, TT_COLD
)
382 && is_temperature_type_near(ptile
, TT_FROZEN
)
383 && ok_for_separate_poles(ptile
)))) {
384 tile_set_terrain(ptile
, T_UNKNOWN
);
385 tile_set_continent(ptile
, 0);
387 } whole_map_iterate_end
;
390 /**************************************************************************
391 Recursively generate terrains.
392 **************************************************************************/
393 static void place_terrain(struct tile
*ptile
, int diff
,
394 struct terrain
*pterrain
, int *to_be_placed
,
399 if (*to_be_placed
<= 0) {
402 fc_assert_ret(not_placed(ptile
));
403 tile_set_terrain(ptile
, pterrain
);
404 map_set_placed(ptile
);
407 cardinal_adjc_iterate(&(wld
.map
), ptile
, tile1
) {
408 /* Check L_UNIT and H_UNIT against 0. */
409 int Delta
= (abs(map_colatitude(tile1
) - map_colatitude(ptile
))
411 + abs(hmap(tile1
) - (hmap(ptile
))) / MAX(H_UNIT
, 1));
412 if (not_placed(tile1
)
413 && tmap_is(tile1
, tc
)
414 && test_wetness(tile1
, wc
)
415 && test_miscellaneous(tile1
, mc
)
417 && fc_rand(10) > 4) {
418 place_terrain(tile1
, diff
- 1 - Delta
, pterrain
,
419 to_be_placed
, wc
, tc
, mc
);
421 } cardinal_adjc_iterate_end
;
424 /**************************************************************************
425 a simple function that adds plains grassland or tundra to the
427 **************************************************************************/
428 static void make_plain(struct tile
*ptile
, int *to_be_placed
)
430 /* in cold place we get tundra instead */
431 if (tmap_is(ptile
, TT_FROZEN
)) {
432 tile_set_terrain(ptile
,
433 pick_terrain(MG_FROZEN
, MG_UNUSED
, MG_MOUNTAINOUS
));
434 } else if (tmap_is(ptile
, TT_COLD
)) {
435 tile_set_terrain(ptile
,
436 pick_terrain(MG_COLD
, MG_UNUSED
, MG_MOUNTAINOUS
));
438 tile_set_terrain(ptile
,
439 pick_terrain(MG_TEMPERATE
, MG_GREEN
, MG_MOUNTAINOUS
));
441 map_set_placed(ptile
);
445 /**************************************************************************
446 make_plains converts all not yet placed terrains to plains (tundra, grass)
447 used by generators 2-4
448 **************************************************************************/
449 static void make_plains(void)
453 whole_map_iterate(&(wld
.map
), ptile
) {
454 if (not_placed(ptile
)) {
456 make_plain(ptile
, &to_be_placed
);
458 } whole_map_iterate_end
;
461 /**************************************************************************
462 This place randomly a cluster of terrains with some characteristics
463 **************************************************************************/
464 #define PLACE_ONE_TYPE(count, alternate, ter, wc, tc, mc, weight) \
466 struct tile *ptile; \
467 /* Place some terrains */ \
468 if ((ptile = rand_map_pos_characteristic((wc), (tc), (mc)))) { \
469 place_terrain(ptile, (weight), (ter), &(count), (wc),(tc), (mc)); \
471 /* If rand_map_pos_temperature returns FALSE we may as well stop */ \
472 /* looking for this time and go to alternate type. */ \
473 (alternate) += (count); \
478 /**************************************************************************
479 make_terrains calls make_forest, make_dessert,etc with random free
480 locations until there has been made enough.
481 Comment: funtions as make_swamp, etc. has to have a non 0 probability
482 to place one terrains in called position. Else make_terrains will get
484 **************************************************************************/
485 static void make_terrains(void)
488 int forests_count
= 0;
489 int jungles_count
= 0;
490 int deserts_count
= 0;
491 int alt_deserts_count
= 0;
492 int plains_count
= 0;
493 int swamps_count
= 0;
495 whole_map_iterate(&(wld
.map
), ptile
) {
496 if (not_placed(ptile
)) {
499 } whole_map_iterate_end
;
501 forests_count
= total
* forest_pct
/ (100 - mountain_pct
);
502 jungles_count
= total
* jungle_pct
/ (100 - mountain_pct
);
504 deserts_count
= total
* desert_pct
/ (100 - mountain_pct
);
505 swamps_count
= total
* swamp_pct
/ (100 - mountain_pct
);
507 /* grassland, tundra,arctic and plains is counted in plains_count */
508 plains_count
= total
- forests_count
- deserts_count
509 - swamps_count
- jungles_count
;
511 /* the placement loop */
514 PLACE_ONE_TYPE(forests_count
, plains_count
,
515 pick_terrain(MG_FOLIAGE
, MG_TEMPERATE
, MG_TROPICAL
),
516 WC_ALL
, TT_NFROZEN
, MC_NONE
, 60);
517 PLACE_ONE_TYPE(jungles_count
, forests_count
,
518 pick_terrain(MG_FOLIAGE
, MG_TROPICAL
, MG_COLD
),
519 WC_ALL
, TT_TROPICAL
, MC_NONE
, 50);
520 PLACE_ONE_TYPE(swamps_count
, forests_count
,
521 pick_terrain(MG_WET
, MG_UNUSED
, MG_FOLIAGE
),
522 WC_NDRY
, TT_HOT
, MC_LOW
, 50);
523 PLACE_ONE_TYPE(deserts_count
, alt_deserts_count
,
524 pick_terrain(MG_DRY
, MG_TROPICAL
, MG_COLD
),
525 WC_DRY
, TT_NFROZEN
, MC_NLOW
, 80);
526 PLACE_ONE_TYPE(alt_deserts_count
, plains_count
,
527 pick_terrain(MG_DRY
, MG_TROPICAL
, MG_WET
),
528 WC_ALL
, TT_NFROZEN
, MC_NLOW
, 40);
530 /* make the plains and tundras */
531 if (plains_count
> 0) {
534 /* Don't use any restriction here ! */
535 if ((ptile
= rand_map_pos_characteristic(WC_ALL
, TT_ALL
, MC_NONE
))) {
536 make_plain(ptile
, &plains_count
);
538 /* If rand_map_pos_temperature returns FALSE we may as well stop
539 * looking for plains. */
543 } while (forests_count
> 0 || jungles_count
> 0
544 || deserts_count
> 0 || alt_deserts_count
> 0
545 || plains_count
> 0 || swamps_count
> 0 );
548 /*********************************************************************
549 Help function used in make_river(). See the help there.
550 *********************************************************************/
551 static int river_test_blocked(struct river_map
*privermap
,
553 struct extra_type
*priver
)
555 if (dbv_isset(&privermap
->blocked
, tile_index(ptile
))) {
559 /* any un-blocked? */
560 cardinal_adjc_iterate(&(wld
.map
), ptile
, ptile1
) {
561 if (!dbv_isset(&privermap
->blocked
, tile_index(ptile1
))) {
564 } cardinal_adjc_iterate_end
;
566 return 1; /* none non-blocked |- all blocked */
569 /*********************************************************************
570 Help function used in make_river(). See the help there.
571 *********************************************************************/
572 static int river_test_rivergrid(struct river_map
*privermap
,
574 struct extra_type
*priver
)
576 return (count_river_type_tile_card(ptile
, priver
, FALSE
) > 1) ? 1 : 0;
579 /*********************************************************************
580 Help function used in make_river(). See the help there.
581 *********************************************************************/
582 static int river_test_highlands(struct river_map
*privermap
,
584 struct extra_type
*priver
)
586 return tile_terrain(ptile
)->property
[MG_MOUNTAINOUS
];
589 /*********************************************************************
590 Help function used in make_river(). See the help there.
591 *********************************************************************/
592 static int river_test_adjacent_ocean(struct river_map
*privermap
,
594 struct extra_type
*priver
)
596 return 100 - count_terrain_class_near_tile(ptile
, TRUE
, TRUE
, TC_OCEAN
);
599 /*********************************************************************
600 Help function used in make_river(). See the help there.
601 *********************************************************************/
602 static int river_test_adjacent_river(struct river_map
*privermap
,
604 struct extra_type
*priver
)
606 return 100 - count_river_type_tile_card(ptile
, priver
, TRUE
);
609 /*********************************************************************
610 Help function used in make_river(). See the help there.
611 *********************************************************************/
612 static int river_test_adjacent_highlands(struct river_map
*privermap
,
614 struct extra_type
*priver
)
618 adjc_iterate(&(wld
.map
), ptile
, ptile2
) {
619 sum
+= tile_terrain(ptile2
)->property
[MG_MOUNTAINOUS
];
625 /*********************************************************************
626 Help function used in make_river(). See the help there.
627 *********************************************************************/
628 static int river_test_swamp(struct river_map
*privermap
,
630 struct extra_type
*priver
)
632 return FC_INFINITY
- tile_terrain(ptile
)->property
[MG_WET
];
635 /*********************************************************************
636 Help function used in make_river(). See the help there.
637 *********************************************************************/
638 static int river_test_adjacent_swamp(struct river_map
*privermap
,
640 struct extra_type
*priver
)
644 adjc_iterate(&(wld
.map
), ptile
, ptile2
) {
645 sum
+= tile_terrain(ptile2
)->property
[MG_WET
];
648 return FC_INFINITY
- sum
;
651 /*********************************************************************
652 Help function used in make_river(). See the help there.
653 *********************************************************************/
654 static int river_test_height_map(struct river_map
*privermap
,
656 struct extra_type
*priver
)
661 /*********************************************************************
662 Called from make_river. Marks all directions as blocked. -Erik Sigra
663 *********************************************************************/
664 static void river_blockmark(struct river_map
*privermap
,
667 log_debug("Blockmarking (%d, %d) and adjacent tiles.", TILE_XY(ptile
));
669 dbv_set(&privermap
->blocked
, tile_index(ptile
));
671 cardinal_adjc_iterate(&(wld
.map
), ptile
, ptile1
) {
672 dbv_set(&privermap
->blocked
, tile_index(ptile1
));
673 } cardinal_adjc_iterate_end
;
677 int (*func
)(struct river_map
*privermap
, struct tile
*ptile
, struct extra_type
*priver
);
681 #define NUM_TEST_FUNCTIONS 9
682 static struct test_func test_funcs
[NUM_TEST_FUNCTIONS
] = {
683 {river_test_blocked
, TRUE
},
684 {river_test_rivergrid
, TRUE
},
685 {river_test_highlands
, FALSE
},
686 {river_test_adjacent_ocean
, FALSE
},
687 {river_test_adjacent_river
, FALSE
},
688 {river_test_adjacent_highlands
, FALSE
},
689 {river_test_swamp
, FALSE
},
690 {river_test_adjacent_swamp
, FALSE
},
691 {river_test_height_map
, FALSE
}
694 /********************************************************************
695 Makes a river starting at (x, y). Returns 1 if it succeeds.
696 Return 0 if it fails. The river is stored in river_map.
698 How to make a river path look natural
699 =====================================
700 Rivers always flow down. Thus rivers are best implemented on maps
701 where every tile has an explicit height value. However, Freeciv has a
702 flat map. But there are certain things that help the user imagine
703 differences in height between tiles. The selection of direction for
704 rivers should confirm and even amplify the user's image of the map's
707 To decide which direction the river takes, the possible directions
708 are tested in a series of test until there is only 1 direction
709 left. Some tests are fatal. This means that they can sort away all
710 remaining directions. If they do so, the river is aborted. Here
711 follows a description of the test series.
713 * Falling into itself: fatal
715 This is tested by looking up in the river_map array if a tile or
716 every tile surrounding the tile is marked as blocked. A tile is
717 marked as blocked if it belongs to the current river or has been
718 evaluated in a previous iteration in the creation of the current
722 0: Is not falling into itself.
723 1: Is falling into itself.
725 * Forming a 4-river-grid: optionally fatal
726 (river_test_rivergrid)
727 A minimal 4-river-grid is formed when an intersection in the map
728 grid is surrounded by 4 river tiles. There can be larger river
729 grids consisting of several overlapping minimal 4-river-grids.
732 0: Is not forming a 4-river-grid.
733 1: Is forming a 4-river-grid.
736 (river_test_highlands)
737 Rivers must not flow up in mountains or hills if there are
741 0: Is not hills and not mountains.
746 (river_test_adjacent_ocean)
747 Rivers must flow down to coastal areas when possible:
749 Possible values: 0-100
752 (river_test_adjacent_river)
753 Rivers must flow down to areas near other rivers when possible:
755 Possible values: 0-100
757 * Adjacent highlands:
758 (river_test_adjacent_highlands)
759 Rivers must not flow towards highlands if there are alternatives.
763 Rivers must flow down in swamps when possible.
770 (river_test_adjacent_swamp)
771 Rivers must flow towards swamps when possible.
774 (river_test_height_map)
775 Rivers must flow in the direction which takes it to the tile with
776 the lowest value on the height_map.
781 If these rules haven't decided the direction, the random number
782 generator gets the desicion. -Erik Sigra
783 *********************************************************************/
784 static bool make_river(struct river_map
*privermap
, struct tile
*ptile
,
785 struct extra_type
*priver
)
787 /* Comparison value for each tile surrounding the current tile. It is
788 * the suitability to continue a river to the tile in that direction;
789 * lower is better. However rivers may only run in cardinal directions;
790 * the other directions are ignored entirely. */
791 int rd_comparison_val
[8];
793 bool rd_direction_is_valid
[8];
794 int num_valid_directions
, func_num
, direction
;
797 /* Mark the current tile as river. */
798 dbv_set(&privermap
->ok
, tile_index(ptile
));
799 log_debug("The tile at (%d, %d) has been marked as river in river_map.",
802 /* Test if the river is done. */
803 /* We arbitrarily make rivers end at the poles. */
804 if (count_river_near_tile(ptile
, priver
) > 0
805 || count_terrain_class_near_tile(ptile
, TRUE
, TRUE
, TC_OCEAN
) > 0
806 || (tile_terrain(ptile
)->property
[MG_FROZEN
] > 0
807 && map_colatitude(ptile
) < 0.8 * COLD_LEVEL
)) {
809 log_debug("The river ended at (%d, %d).", TILE_XY(ptile
));
813 /* Else choose a direction to continue the river. */
814 log_debug("The river did not end at (%d, %d). Evaluating directions...",
817 /* Mark all available cardinal directions as available. */
818 memset(rd_direction_is_valid
, 0, sizeof(rd_direction_is_valid
));
819 cardinal_adjc_dir_base_iterate(&(wld
.map
), ptile
, dir
) {
820 rd_direction_is_valid
[dir
] = TRUE
;
821 } cardinal_adjc_dir_base_iterate_end
;
823 /* Test series that selects a direction for the river. */
824 for (func_num
= 0; func_num
< NUM_TEST_FUNCTIONS
; func_num
++) {
827 /* first get the tile values for the function */
828 cardinal_adjc_dir_iterate(&(wld
.map
), ptile
, ptile1
, dir
) {
829 if (rd_direction_is_valid
[dir
]) {
830 rd_comparison_val
[dir
] = (test_funcs
[func_num
].func
)(privermap
,
832 fc_assert_action(rd_comparison_val
[dir
] >= 0, continue);
833 if (best_val
== -1) {
834 best_val
= rd_comparison_val
[dir
];
836 best_val
= MIN(rd_comparison_val
[dir
], best_val
);
839 } cardinal_adjc_dir_iterate_end
;
840 fc_assert_action(best_val
!= -1, continue);
842 /* should we abort? */
843 if (best_val
> 0 && test_funcs
[func_num
].fatal
) {
847 /* mark the less attractive directions as invalid */
848 cardinal_adjc_dir_base_iterate(&(wld
.map
), ptile
, dir
) {
849 if (rd_direction_is_valid
[dir
]) {
850 if (rd_comparison_val
[dir
] != best_val
) {
851 rd_direction_is_valid
[dir
] = FALSE
;
854 } cardinal_adjc_dir_base_iterate_end
;
857 /* Directions evaluated with all functions. Now choose the best
858 direction before going to the next iteration of the while loop */
859 num_valid_directions
= 0;
860 cardinal_adjc_dir_base_iterate(&(wld
.map
), ptile
, dir
) {
861 if (rd_direction_is_valid
[dir
]) {
862 num_valid_directions
++;
864 } cardinal_adjc_dir_base_iterate_end
;
866 if (num_valid_directions
== 0) {
867 return FALSE
; /* river aborted */
870 /* One or more valid directions: choose randomly. */
871 log_debug("mapgen.c: Had to let the random number"
872 " generator select a direction for a river.");
873 direction
= fc_rand(num_valid_directions
);
874 log_debug("mapgen.c: direction: %d", direction
);
876 /* Find the direction that the random number generator selected. */
877 cardinal_adjc_dir_iterate(&(wld
.map
), ptile
, tile1
, dir
) {
878 if (rd_direction_is_valid
[dir
]) {
882 river_blockmark(privermap
, ptile
);
887 } cardinal_adjc_dir_iterate_end
;
888 fc_assert_ret_val(direction
== 0, FALSE
);
890 } /* end while; (Make a river.) */
893 /**************************************************************************
894 Calls make_river until there are enough river tiles on the map. It stops
895 when it has tried to create RIVERS_MAXTRIES rivers. -Erik Sigra
896 **************************************************************************/
897 static void make_rivers(void)
900 struct terrain
*pterrain
;
901 struct river_map rivermap
;
902 struct extra_type
*road_river
= NULL
;
904 /* Formula to make the river density similar om different sized maps. Avoids
905 too few rivers on large maps and too many rivers on small maps. */
906 int desirable_riverlength
=
908 /* The size of the map (poles counted in river_pct). */
910 /* Rivers need to be on land only. */
911 wld
.map
.server
.landpercent
/
912 /* Adjustment value. Tested by me. Gives no rivers with 'set
913 rivers 0', gives a reasonable amount of rivers with default
914 settings and as many rivers as possible with 'set rivers 100'. */
917 /* The number of river tiles that have been set. */
918 int current_riverlength
= 0;
920 /* Counts the number of iterations (should increase with 1 during
921 every iteration of the main loop in this function).
922 Is needed to stop a potentially infinite loop. */
923 int iteration_counter
= 0;
925 if (river_type_count
<= 0) {
926 /* No river type available */
930 create_placed_map(); /* needed bu rand_map_characteristic */
931 set_all_ocean_tiles_placed();
933 dbv_init(&rivermap
.blocked
, MAP_INDEX_SIZE
);
934 dbv_init(&rivermap
.ok
, MAP_INDEX_SIZE
);
936 /* The main loop in this function. */
937 while (current_riverlength
< desirable_riverlength
938 && iteration_counter
< RIVERS_MAXTRIES
) {
940 if (!(ptile
= rand_map_pos_characteristic(WC_ALL
, TT_NFROZEN
,
942 break; /* mo more spring places */
944 pterrain
= tile_terrain(ptile
);
946 /* Check if it is suitable to start a river on the current tile.
949 /* Don't start a river on ocean. */
952 /* Don't start a river on river. */
953 && !tile_has_river(ptile
)
955 /* Don't start a river on a tile is surrounded by > 1 river +
957 && (count_river_near_tile(ptile
, NULL
)
958 + count_terrain_class_near_tile(ptile
, TRUE
, FALSE
, TC_OCEAN
) <= 1)
960 /* Don't start a river on a tile that is surrounded by hills or
961 mountains unless it is hard to find somewhere else to start
963 && (count_terrain_property_near_tile(ptile
, TRUE
, TRUE
,
965 || iteration_counter
>= RIVERS_MAXTRIES
/ 10 * 5)
967 /* Don't start a river on hills unless it is hard to find
968 somewhere else to start it. */
969 && (pterrain
->property
[MG_MOUNTAINOUS
] == 0
970 || iteration_counter
>= RIVERS_MAXTRIES
/ 10 * 6)
972 /* Don't start a river on arctic unless it is hard to find
973 somewhere else to start it. */
974 && (pterrain
->property
[MG_FROZEN
] == 0
975 || iteration_counter
>= RIVERS_MAXTRIES
/ 10 * 8)
977 /* Don't start a river on desert unless it is hard to find
978 somewhere else to start it. */
979 && (pterrain
->property
[MG_DRY
] == 0
980 || iteration_counter
>= RIVERS_MAXTRIES
/ 10 * 9)) {
982 /* Reset river map before making a new river. */
983 dbv_clr_all(&rivermap
.blocked
);
984 dbv_clr_all(&rivermap
.ok
);
986 road_river
= river_types
[fc_rand(river_type_count
)];
988 extra_type_by_cause_iterate(EC_ROAD
, oriver
) {
989 if (oriver
!= road_river
) {
990 whole_map_iterate(&(wld
.map
), rtile
) {
991 if (tile_has_extra(rtile
, oriver
)) {
992 dbv_set(&rivermap
.blocked
, tile_index(rtile
));
994 } whole_map_iterate_end
;
996 } extra_type_by_cause_iterate_end
;
998 log_debug("Found a suitable starting tile for a river at (%d, %d)."
999 " Starting to make it.", TILE_XY(ptile
));
1001 /* Try to make a river. If it is OK, apply it to the map. */
1002 if (make_river(&rivermap
, ptile
, road_river
)) {
1003 whole_map_iterate(&(wld
.map
), ptile1
) {
1004 if (dbv_isset(&rivermap
.ok
, tile_index(ptile1
))) {
1005 struct terrain
*river_terrain
= tile_terrain(ptile1
);
1007 if (!terrain_has_flag(river_terrain
, TER_CAN_HAVE_RIVER
)) {
1008 /* We have to change the terrain to put a river here. */
1009 river_terrain
= pick_terrain_by_flag(TER_CAN_HAVE_RIVER
);
1010 if (river_terrain
!= NULL
) {
1011 tile_set_terrain(ptile1
, river_terrain
);
1015 tile_add_extra(ptile1
, road_river
);
1016 current_riverlength
++;
1017 map_set_placed(ptile1
);
1018 log_debug("Applied a river to (%d, %d).", TILE_XY(ptile1
));
1020 } whole_map_iterate_end
;
1022 log_debug("mapgen.c: A river failed. It might have gotten stuck "
1026 iteration_counter
++;
1027 log_debug("current_riverlength: %d; desirable_riverlength: %d; "
1028 "iteration_counter: %d",
1029 current_riverlength
, desirable_riverlength
, iteration_counter
);
1032 dbv_free(&rivermap
.blocked
);
1033 dbv_free(&rivermap
.ok
);
1035 destroy_placed_map();
1038 /**************************************************************************
1039 make land simply does it all based on a generated heightmap
1040 1) with map.server.landpercent it generates a ocean/unknown map
1041 2) it then calls the above functions to generate the different terrains
1042 **************************************************************************/
1043 static void make_land(void)
1045 struct terrain
*land_fill
= NULL
;
1048 normalize_hmap_poles();
1051 /* Pick a non-ocean terrain just once and fill all land tiles with "
1052 * that terrain. We must set some terrain (and not T_UNKNOWN) so that "
1053 * continent number assignment works. */
1054 terrain_type_iterate(pterrain
) {
1055 if (!is_ocean(pterrain
) && !terrain_has_flag(pterrain
, TER_NOT_GENERATED
)) {
1056 land_fill
= pterrain
;
1059 } terrain_type_iterate_end
;
1061 fc_assert_exit_msg(NULL
!= land_fill
,
1062 "No land terrain type could be found for the purpose "
1063 "of temporarily filling in land tiles during map "
1064 "generation. This could be an error in Freeciv, or a "
1065 "mistake in the terrain.ruleset file. Please make sure "
1066 "there is at least one land terrain type in the "
1067 "ruleset, or use a different map generator. If this "
1068 "error persists, please report it at: %s", BUG_URL
);
1070 hmap_shore_level
= (hmap_max_level
* (100 - wld
.map
.server
.landpercent
)) / 100;
1071 ini_hmap_low_level();
1072 whole_map_iterate(&(wld
.map
), ptile
) {
1073 tile_set_terrain(ptile
, T_UNKNOWN
); /* set as oceans count is used */
1074 if (hmap(ptile
) < hmap_shore_level
) {
1075 int depth
= (hmap_shore_level
- hmap(ptile
)) * 100 / hmap_shore_level
;
1079 /* This is to make shallow connection between continents less likely */
1080 adjc_iterate(&(wld
.map
), ptile
, other
) {
1081 if (hmap(other
) < hmap_shore_level
) {
1089 depth
+= 30 * (ocean
- land
) / MAX(1, (ocean
+ land
));
1091 depth
= MIN(depth
, TERRAIN_OCEAN_DEPTH_MAXIMUM
);
1093 /* Generate sea ice here, if ruleset supports it. Dummy temperature
1094 * map is sufficient for this. If ruleset doesn't support it,
1095 * use unfrozen ocean; make_polar_land() will later fill in with
1096 * land-based ice. Ice has a ragged margin. */
1098 bool frozen
= HAS_POLES
1099 && (tmap_is(ptile
, TT_FROZEN
)
1100 || (tmap_is(ptile
, TT_COLD
)
1102 && is_temperature_type_near(ptile
, TT_FROZEN
)));
1103 struct terrain
*pterrain
= pick_ocean(depth
, frozen
);
1105 if (frozen
&& !pterrain
) {
1106 pterrain
= pick_ocean(depth
, FALSE
);
1107 fc_assert(pterrain
);
1109 tile_set_terrain(ptile
, pterrain
);
1112 /* See note above for 'land_fill'. */
1113 tile_set_terrain(ptile
, land_fill
);
1115 } whole_map_iterate_end
;
1118 renormalize_hmap_poles();
1121 /* destroy old dummy temperature map ... */
1123 /* ... and create a real temperature map (needs hmap and oceans) */
1126 if (HAS_POLES
) { /* this is a hack to terrains set with not frizzed oceans*/
1127 make_polar_land(); /* make extra land at poles*/
1130 create_placed_map(); /* here it means land terrains to be placed */
1131 set_all_ocean_tiles_placed();
1132 if (MAPGEN_FRACTURE
== wld
.map
.server
.generator
) {
1133 make_fracture_relief();
1135 make_relief(); /* base relief on map */
1137 make_terrains(); /* place all exept mountains and hill */
1138 destroy_placed_map();
1140 make_rivers(); /* use a new placed_map. destroy older before call */
1143 /**************************************************************************
1144 Returns if this is a 1x1 island
1145 **************************************************************************/
1146 static bool is_tiny_island(struct tile
*ptile
)
1148 struct terrain
*pterrain
= tile_terrain(ptile
);
1150 if (is_ocean(pterrain
) || pterrain
->property
[MG_FROZEN
] > 0) {
1151 /* The arctic check is needed for iso-maps: the poles may not have
1152 * any cardinally adjacent land tiles, but that's okay. */
1156 adjc_iterate(&(wld
.map
), ptile
, tile1
) {
1157 /* This was originally a cardinal_adjc_iterate, which seemed to cause
1158 * two or three problems. /MSS */
1159 if (!is_ocean_tile(tile1
)) {
1167 /**************************************************************************
1168 Removes all 1x1 islands (sets them to ocean).
1169 This happens before regenerate_lakes(), so don't need to worry about
1170 TER_FRESHWATER here.
1171 **************************************************************************/
1172 static void remove_tiny_islands(void)
1174 whole_map_iterate(&(wld
.map
), ptile
) {
1175 if (is_tiny_island(ptile
)) {
1176 struct terrain
*shallow
1177 = most_shallow_ocean(terrain_has_flag(tile_terrain(ptile
), TER_FROZEN
));
1179 fc_assert_ret(NULL
!= shallow
);
1180 tile_set_terrain(ptile
, shallow
);
1181 extra_type_by_cause_iterate(EC_ROAD
, priver
) {
1182 if (tile_has_extra(ptile
, priver
)
1183 && road_has_flag(extra_road_get(priver
), RF_RIVER
)) {
1184 tile_extra_rm_apply(ptile
, priver
);
1186 } extra_type_by_cause_iterate_end
;
1187 tile_set_continent(ptile
, 0);
1189 } whole_map_iterate_end
;
1192 /**************************************************************************
1193 Debugging function to print information about the map that's been
1195 **************************************************************************/
1196 static void print_mapgen_map(void)
1198 int terrain_counts
[terrain_count()];
1199 int total
= 0, ocean
= 0;
1201 terrain_type_iterate(pterrain
) {
1202 terrain_counts
[terrain_index(pterrain
)] = 0;
1203 } terrain_type_iterate_end
;
1205 whole_map_iterate(&(wld
.map
), ptile
) {
1206 struct terrain
*pterrain
= tile_terrain(ptile
);
1208 terrain_counts
[terrain_index(pterrain
)]++;
1209 if (is_ocean(pterrain
)) {
1213 } whole_map_iterate_end
;
1215 log_verbose("map settings:");
1216 log_verbose(" %-20s : %5d%%", "mountain_pct", mountain_pct
);
1217 log_verbose(" %-20s : %5d%%", "desert_pct", desert_pct
);
1218 log_verbose(" %-20s : %5d%%", "forest_pct", forest_pct
);
1219 log_verbose(" %-20s : %5d%%", "jungle_pct", jungle_pct
);
1220 log_verbose(" %-20s : %5d%%", "swamp_pct", swamp_pct
);
1222 log_verbose("map statistics:");
1223 terrain_type_iterate(pterrain
) {
1224 if (is_ocean(pterrain
)) {
1225 log_verbose(" %-20s : %6d %5.1f%% (ocean: %5.1f%%)",
1226 terrain_rule_name(pterrain
),
1227 terrain_counts
[terrain_index(pterrain
)],
1228 (float) terrain_counts
[terrain_index(pterrain
)] * 100
1230 (float) terrain_counts
[terrain_index(pterrain
)] * 100
1233 log_verbose(" %-20s : %6d %5.1f%% (land: %5.1f%%)",
1234 terrain_rule_name(pterrain
),
1235 terrain_counts
[terrain_index(pterrain
)],
1236 (float) terrain_counts
[terrain_index(pterrain
)] * 100
1238 (float) terrain_counts
[terrain_index(pterrain
)] * 100
1241 } terrain_type_iterate_end
;
1244 /**************************************************************************
1245 See stdinhand.c for information on map generation methods.
1247 FIXME: Some continent numbers are unused at the end of this function, fx
1248 removed completely by remove_tiny_islands.
1249 When this function is finished various data is written to "islands",
1250 indexed by continent numbers, so a simple renumbering would not
1253 If "autosize" is specified then mapgen will automatically size the map
1254 based on the map.server.size server parameter and the specified topology.
1255 If not map.xsize and map.ysize will be used.
1256 **************************************************************************/
1257 bool map_fractal_generate(bool autosize
, struct unit_type
*initial_unit
)
1259 /* save the current random state: */
1260 RANDOM_STATE rstate
;
1261 RANDOM_TYPE seed_rand
;
1263 /* Call fc_rand() even when result is not needed to make sure
1264 * random state proceeds equally for random seeds and explicitly
1266 seed_rand
= fc_rand(MAX_UINT32
);
1268 if (wld
.map
.server
.seed_setting
== 0) {
1269 /* Create a "random" map seed. */
1270 wld
.map
.server
.seed
= seed_rand
& (MAX_UINT32
>> 1);
1271 #ifdef FREECIV_TESTMATIC
1272 /* Log command to reproduce the mapseed */
1273 log_testmatic("set mapseed %d", wld
.map
.server
.seed
);
1274 #else /* FREECIV_TESTMATICE */
1275 log_debug("Setting map.seed:%d", wld
.map
.server
.seed
);
1276 #endif /* FREECIV_TESTMATIC */
1278 wld
.map
.server
.seed
= wld
.map
.server
.seed_setting
;
1281 rstate
= fc_rand_state();
1283 fc_srand(wld
.map
.server
.seed
);
1285 /* don't generate tiles with mapgen == MAPGEN_SCENARIO as we've loaded *
1287 Also, don't delete (the handcrafted!) tiny islands in a scenario */
1288 if (wld
.map
.server
.generator
!= MAPGEN_SCENARIO
) {
1291 generator_init_topology(autosize
);
1292 /* Map can be already allocated, if we failed first map generation */
1293 if (map_is_empty()) {
1294 main_map_allocate();
1296 adjust_terrain_param();
1297 /* if one mapgenerator fails, it will choose another mapgenerator */
1298 /* with a lower number to try again */
1300 /* create a temperature map */
1303 if (MAPGEN_FAIR
== wld
.map
.server
.generator
1304 && !map_generate_fair_islands()) {
1305 wld
.map
.server
.generator
= MAPGEN_ISLAND
;
1308 if (MAPGEN_ISLAND
== wld
.map
.server
.generator
) {
1309 /* initialise terrain selection lists used by make_island() */
1310 island_terrain_init();
1312 /* 2 or 3 players per isle? */
1313 if (MAPSTARTPOS_2or3
== wld
.map
.server
.startpos
1314 || MAPSTARTPOS_ALL
== wld
.map
.server
.startpos
) {
1317 if (MAPSTARTPOS_DEFAULT
== wld
.map
.server
.startpos
1318 || MAPSTARTPOS_SINGLE
== wld
.map
.server
.startpos
) {
1319 /* Single player per isle. */
1322 if (MAPSTARTPOS_VARIABLE
== wld
.map
.server
.startpos
) {
1323 /* "Variable" single player. */
1327 /* free terrain selection lists used by make_island() */
1328 island_terrain_free();
1331 if (MAPGEN_FRACTAL
== wld
.map
.server
.generator
) {
1332 make_pseudofractal1_hmap(1 +
1333 ((MAPSTARTPOS_DEFAULT
== wld
.map
.server
.startpos
1334 || MAPSTARTPOS_ALL
== wld
.map
.server
.startpos
)
1335 ? 0 : player_count()));
1338 if (MAPGEN_RANDOM
== wld
.map
.server
.generator
) {
1339 make_random_hmap(MAX(1, 1 + get_sqsize()
1340 - (MAPSTARTPOS_DEFAULT
!= wld
.map
.server
.startpos
1341 ? player_count() / 4 : 0)));
1344 if (MAPGEN_FRACTURE
== wld
.map
.server
.generator
) {
1345 make_fracture_map();
1348 /* if hmap only generator make anything else */
1349 if (MAPGEN_RANDOM
== wld
.map
.server
.generator
1350 || MAPGEN_FRACTAL
== wld
.map
.server
.generator
1351 || MAPGEN_FRACTURE
== wld
.map
.server
.generator
) {
1357 if (!wld
.map
.server
.tinyisles
) {
1358 remove_tiny_islands();
1361 smooth_water_depth();
1363 /* Continent numbers must be assigned before regenerate_lakes() */
1364 assign_continent_numbers();
1366 /* Turn small oceans into lakes. */
1369 assign_continent_numbers();
1372 /* create a temperature map if it was not done before */
1373 if (!temperature_is_initialized()) {
1377 /* some scenarios already provide specials */
1378 if (!wld
.map
.server
.have_resources
) {
1379 add_resources(wld
.map
.server
.riches
);
1382 if (!wld
.map
.server
.have_huts
) {
1383 make_huts(wld
.map
.server
.huts
* map_num_tiles() / 1000);
1386 /* restore previous random state: */
1387 fc_rand_set_state(rstate
);
1389 /* We don't want random start positions in a scenario which already
1391 if (0 == map_startpos_count()) {
1392 enum map_startpos mode
= MAPSTARTPOS_ALL
;
1394 switch (wld
.map
.server
.generator
) {
1396 fc_assert_msg(FALSE
,
1397 "Fair island generator failed to allocated "
1398 "start positions!");
1399 case MAPGEN_SCENARIO
:
1401 case MAPGEN_FRACTURE
:
1402 mode
= wld
.map
.server
.startpos
;
1404 case MAPGEN_FRACTAL
:
1405 if (wld
.map
.server
.startpos
== MAPSTARTPOS_DEFAULT
) {
1406 log_verbose("Map generator chose startpos=ALL");
1407 mode
= MAPSTARTPOS_ALL
;
1409 mode
= wld
.map
.server
.startpos
;
1413 switch(wld
.map
.server
.startpos
) {
1414 case MAPSTARTPOS_DEFAULT
:
1415 case MAPSTARTPOS_VARIABLE
:
1416 log_verbose("Map generator chose startpos=SINGLE");
1418 case MAPSTARTPOS_SINGLE
:
1419 mode
= MAPSTARTPOS_SINGLE
;
1422 log_verbose("Map generator chose startpos=2or3");
1424 case MAPSTARTPOS_2or3
:
1425 mode
= MAPSTARTPOS_2or3
;
1434 success
= create_start_positions(mode
, initial_unit
);
1436 wld
.map
.server
.startpos
= mode
;
1441 case MAPSTARTPOS_SINGLE
:
1442 log_verbose("Falling back to startpos=2or3");
1443 mode
= MAPSTARTPOS_2or3
;
1445 case MAPSTARTPOS_2or3
:
1446 log_verbose("Falling back to startpos=ALL");
1447 mode
= MAPSTARTPOS_ALL
;
1449 case MAPSTARTPOS_ALL
:
1450 log_verbose("Falling back to startpos=VARIABLE");
1451 mode
= MAPSTARTPOS_VARIABLE
;
1454 log_error(_("The server couldn't allocate starting positions."));
1461 /* destroy temperature map */
1469 /**************************************************************************
1470 Convert parameters from the server into terrains percents parameters for
1472 **************************************************************************/
1473 static void adjust_terrain_param(void)
1475 int polar
= 2 * ICE_BASE_LEVEL
* wld
.map
.server
.landpercent
/ MAX_COLATITUDE
;
1476 float factor
= (100.0 - polar
- wld
.map
.server
.steepness
* 0.8 ) / 10000;
1479 mountain_pct
= factor
* wld
.map
.server
.steepness
* 90;
1481 /* 27 % if wetness == 50 & */
1482 forest_pct
= factor
* (wld
.map
.server
.wetness
* 40 + 700) ;
1483 jungle_pct
= forest_pct
* (MAX_COLATITUDE
- TROPICAL_LEVEL
) /
1484 (MAX_COLATITUDE
* 2);
1485 forest_pct
-= jungle_pct
;
1488 river_pct
= (100 - polar
) * (3 + wld
.map
.server
.wetness
/ 12) / 100;
1490 /* 7 % if wetness == 50 && temperature == 50 */
1491 swamp_pct
= factor
* MAX(0, (wld
.map
.server
.wetness
* 12 - 150
1492 + wld
.map
.server
.temperature
* 10));
1493 desert_pct
= factor
* MAX(0, (wld
.map
.server
.temperature
* 15 - 250
1494 + (100 - wld
.map
.server
.wetness
) * 10)) ;
1497 /****************************************************************************
1498 Return TRUE if a safe tile is in a radius of 1. This function is used to
1499 test where to place specials on the sea.
1500 ****************************************************************************/
1501 static bool near_safe_tiles(struct tile
*ptile
)
1503 square_iterate(&(wld
.map
), ptile
, 1, tile1
) {
1504 if (!terrain_has_flag(tile_terrain(tile1
), TER_UNSAFE_COAST
)) {
1507 } square_iterate_end
;
1512 /**************************************************************************
1513 this function spreads out huts on the map, a position can be used for a
1514 hut if there isn't another hut close and if it's not on the ocean.
1515 **************************************************************************/
1516 static void make_huts(int number
)
1521 create_placed_map(); /* here it means placed huts */
1523 while (number
> 0 && count
++ < map_num_tiles() * 2) {
1525 /* Add a hut. But not on a polar area, on an ocean, or too close to
1527 if ((ptile
= rand_map_pos_characteristic(WC_ALL
, TT_NFROZEN
, MC_NONE
))) {
1528 struct extra_type
*phut
= rand_extra_for_tile(ptile
, EC_HUT
);
1532 tile_add_extra(ptile
, phut
);
1534 set_placed_near_pos(ptile
, 3);
1537 destroy_placed_map();
1540 /****************************************************************************
1541 Return TRUE iff there's a resource within one tile of the given map
1543 ****************************************************************************/
1544 static bool is_resource_close(const struct tile
*ptile
)
1546 square_iterate(&(wld
.map
), ptile
, 1, tile1
) {
1547 if (NULL
!= tile_resource(tile1
)) {
1550 } square_iterate_end
;
1555 /****************************************************************************
1556 Add specials to the map with given probability (out of 1000).
1557 ****************************************************************************/
1558 static void add_resources(int prob
)
1560 whole_map_iterate(&(wld
.map
), ptile
) {
1561 const struct terrain
*pterrain
= tile_terrain(ptile
);
1563 if (is_resource_close (ptile
) || fc_rand (1000) > prob
) {
1566 if (!is_ocean(pterrain
) || near_safe_tiles(ptile
)
1567 || wld
.map
.server
.ocean_resources
) {
1569 struct extra_type
**r
;
1571 for (r
= pterrain
->resources
; *r
; r
++) {
1572 /* This is a standard way to get a random element from the
1573 * pterrain->resources list, without computing its length in
1574 * advance. Note that if *(pterrain->resources) == NULL, then
1575 * this loop is a no-op. */
1576 if (0 == fc_rand(++i
)) {
1577 tile_set_resource(ptile
, *r
);
1581 } whole_map_iterate_end
;
1583 wld
.map
.server
.have_resources
= TRUE
;
1586 /**************************************************************************
1587 Returns a random position in the rectangle denoted by the given state.
1588 **************************************************************************/
1589 static struct tile
*get_random_map_position_from_state(
1590 const struct gen234_state
*const pstate
)
1594 fc_assert_ret_val((pstate
->e
- pstate
->w
) > 0, NULL
);
1595 fc_assert_ret_val((pstate
->e
- pstate
->w
) < wld
.map
.xsize
, NULL
);
1596 fc_assert_ret_val((pstate
->s
- pstate
->n
) > 0, NULL
);
1597 fc_assert_ret_val((pstate
->s
- pstate
->n
) < wld
.map
.ysize
, NULL
);
1599 xrnd
= pstate
->w
+ fc_rand(pstate
->e
- pstate
->w
);
1600 yrnd
= pstate
->n
+ fc_rand(pstate
->s
- pstate
->n
);
1602 return native_pos_to_tile(&(wld
.map
), xrnd
, yrnd
);
1605 /**************************************************************************
1606 Allocate and initialize new terrain_select structure.
1607 **************************************************************************/
1608 static struct terrain_select
*tersel_new(int weight
,
1609 enum mapgen_terrain_property target
,
1610 enum mapgen_terrain_property prefer
,
1611 enum mapgen_terrain_property avoid
,
1615 struct terrain_select
*ptersel
= fc_malloc(sizeof(*ptersel
));
1617 ptersel
->weight
= weight
;
1618 ptersel
->target
= target
;
1619 ptersel
->prefer
= prefer
;
1620 ptersel
->avoid
= avoid
;
1621 ptersel
->temp_condition
= temp_condition
;
1622 ptersel
->wet_condition
= wet_condition
;
1627 /**************************************************************************
1628 Free resources allocated for terrain_select structure.
1629 **************************************************************************/
1630 static void tersel_free(struct terrain_select
*ptersel
)
1632 if (ptersel
!= NULL
) {
1637 /**************************************************************************
1638 Fill an island with different types of terrains; rivers have extra code.
1639 **************************************************************************/
1640 static void fill_island(int coast
, long int *bucket
,
1641 const struct terrain_select_list
*tersel_list
,
1642 const struct gen234_state
*const pstate
)
1644 int i
, k
, capac
, total_weight
= 0;
1645 int ntersel
= terrain_select_list_size(tersel_list
);
1648 if (*bucket
<= 0 ) {
1652 /* must have at least one terrain selection given in tersel_list */
1653 fc_assert_ret(ntersel
!= 0);
1655 capac
= pstate
->totalmass
;
1656 i
= *bucket
/ capac
;
1658 *bucket
-= i
* capac
;
1661 failsafe
= i
* (pstate
->s
- pstate
->n
) * (pstate
->e
- pstate
->w
);
1663 failsafe
= -failsafe
;
1666 terrain_select_list_iterate(tersel_list
, ptersel
) {
1667 total_weight
+= ptersel
->weight
;
1668 } terrain_select_list_iterate_end
;
1670 if (total_weight
<= 0) {
1674 while (i
> 0 && (failsafe
--) > 0) {
1675 struct tile
*ptile
= get_random_map_position_from_state(pstate
);
1677 if (tile_continent(ptile
) != pstate
->isleindex
|| !not_placed(ptile
)) {
1681 struct terrain_select
*ptersel
1682 = terrain_select_list_get(tersel_list
, fc_rand(ntersel
));
1684 if (fc_rand(total_weight
) > ptersel
->weight
) {
1688 if (!tmap_is(ptile
, ptersel
->temp_condition
)
1689 || !test_wetness(ptile
, ptersel
->wet_condition
)) {
1693 struct terrain
*pterrain
= pick_terrain(ptersel
->target
, ptersel
->prefer
,
1696 /* the first condition helps make terrain more contiguous,
1697 the second lets it avoid the coast: */
1699 || fc_rand(100) < 50
1700 || is_terrain_near_tile(ptile
, pterrain
, FALSE
))
1701 && (!is_terrain_class_card_near(ptile
, TC_OCEAN
)
1702 || fc_rand(100) < coast
)) {
1703 tile_set_terrain(ptile
, pterrain
);
1704 map_set_placed(ptile
);
1706 log_debug("[fill_island] placed terrain '%s' at (%2d,%2d)",
1707 terrain_rule_name(pterrain
), TILE_XY(ptile
));
1710 if (!not_placed(ptile
)) {
1716 /**************************************************************************
1717 Returns TRUE if ptile is suitable for a river mouth.
1718 **************************************************************************/
1719 static bool island_river_mouth_suitability(const struct tile
*ptile
,
1720 const struct extra_type
*priver
)
1722 int num_card_ocean
, pct_adj_ocean
, num_adj_river
;
1724 num_card_ocean
= count_terrain_class_near_tile(ptile
, C_CARDINAL
, C_NUMBER
,
1726 pct_adj_ocean
= count_terrain_class_near_tile(ptile
, C_ADJACENT
, C_PERCENT
,
1728 num_adj_river
= count_river_type_tile_card(ptile
, priver
, FALSE
);
1730 return (num_card_ocean
== 1 && pct_adj_ocean
<= 35
1731 && num_adj_river
== 0);
1734 /**************************************************************************
1735 Returns TRUE if there is a river in a cardinal direction near the tile
1736 and the tile is suitable for extending it.
1737 **************************************************************************/
1738 static bool island_river_suitability(const struct tile
*ptile
,
1739 const struct extra_type
*priver
)
1741 int pct_adj_ocean
, num_card_ocean
, pct_adj_river
, num_card_river
;
1743 num_card_river
= count_river_type_tile_card(ptile
, priver
, FALSE
);
1744 num_card_ocean
= count_terrain_class_near_tile(ptile
, C_CARDINAL
, C_NUMBER
,
1746 pct_adj_ocean
= count_terrain_class_near_tile(ptile
, C_ADJACENT
, C_PERCENT
,
1748 pct_adj_river
= count_river_type_near_tile(ptile
, priver
, TRUE
);
1750 return (num_card_river
== 1 && num_card_ocean
== 0
1751 && pct_adj_ocean
< 20 && pct_adj_river
< 35
1752 /* The following expression helps with straightness,
1753 * ocean avoidance, and reduces forking. */
1754 && (pct_adj_river
+ pct_adj_ocean
* 2) < fc_rand(25) + 25);
1757 /**************************************************************************
1758 Fill an island with rivers.
1759 **************************************************************************/
1760 static void fill_island_rivers(int coast
, long int *bucket
,
1761 const struct gen234_state
*const pstate
)
1763 long int failsafe
, capac
, i
, k
;
1769 if (river_type_count
<= 0) {
1773 capac
= pstate
->totalmass
;
1774 i
= *bucket
/ capac
;
1776 *bucket
-= i
* capac
;
1778 /* generate 75% more rivers than generator 1 */
1779 i
= (i
* 175) / 100;
1782 failsafe
= i
* (pstate
->s
- pstate
->n
) * (pstate
->e
- pstate
->w
) * 5;
1784 failsafe
= -failsafe
;
1787 while (i
> 0 && failsafe
-- > 0) {
1788 struct extra_type
*priver
;
1790 ptile
= get_random_map_position_from_state(pstate
);
1791 if (tile_continent(ptile
) != pstate
->isleindex
1792 || tile_has_river(ptile
)) {
1796 priver
= river_types
[fc_rand(river_type_count
)];
1798 if (test_wetness(ptile
, WC_DRY
) && fc_rand(100) < 50) {
1799 /* rivers don't like dry locations */
1803 if ((island_river_mouth_suitability(ptile
, priver
)
1804 && (fc_rand(100) < coast
|| i
== k
))
1805 || island_river_suitability(ptile
, priver
)) {
1806 tile_add_extra(ptile
, priver
);
1812 /****************************************************************************
1813 Return TRUE if the ocean position is near land. This is used in the
1814 creation of islands, so it differs logically from near_safe_tiles().
1815 ****************************************************************************/
1816 static bool is_near_land(struct tile
*ptile
)
1818 /* Note this function may sometimes be called on land tiles. */
1819 adjc_iterate(&(wld
.map
), ptile
, tile1
) {
1820 if (!is_ocean(tile_terrain(tile1
))) {
1828 static long int checkmass
;
1830 /**************************************************************************
1831 Finds a place and drop the island created when called with islemass != 0
1832 **************************************************************************/
1833 static bool place_island(struct gen234_state
*pstate
)
1835 int i
= 0, xcur
, ycur
, nat_x
, nat_y
;
1838 ptile
= rand_map_pos(&(wld
.map
));
1839 index_to_native_pos(&nat_x
, &nat_y
, tile_index(ptile
));
1841 /* this helps a lot for maps with high landmass */
1842 for (ycur
= pstate
->n
, xcur
= pstate
->w
;
1843 ycur
< pstate
->s
&& xcur
< pstate
->e
;
1845 struct tile
*tile0
= native_pos_to_tile(&(wld
.map
), xcur
, ycur
);
1846 struct tile
*tile1
= native_pos_to_tile(&(wld
.map
),
1847 xcur
+ nat_x
- pstate
->w
,
1848 ycur
+ nat_y
- pstate
->n
);
1850 if (!tile0
|| !tile1
) {
1853 if (hmap(tile0
) != 0 && is_near_land(tile1
)) {
1858 for (ycur
= pstate
->n
; ycur
< pstate
->s
; ycur
++) {
1859 for (xcur
= pstate
->w
; xcur
< pstate
->e
; xcur
++) {
1860 struct tile
*tile0
= native_pos_to_tile(&(wld
.map
), xcur
, ycur
);
1861 struct tile
*tile1
= native_pos_to_tile(&(wld
.map
),
1862 xcur
+ nat_x
- pstate
->w
,
1863 ycur
+ nat_y
- pstate
->n
);
1865 if (!tile0
|| !tile1
) {
1868 if (hmap(tile0
) != 0 && is_near_land(tile1
)) {
1874 for (ycur
= pstate
->n
; ycur
< pstate
->s
; ycur
++) {
1875 for (xcur
= pstate
->w
; xcur
< pstate
->e
; xcur
++) {
1876 if (hmap(native_pos_to_tile(&(wld
.map
), xcur
, ycur
)) != 0) {
1877 struct tile
*tile1
= native_pos_to_tile(&(wld
.map
),
1878 xcur
+ nat_x
- pstate
->w
,
1879 ycur
+ nat_y
- pstate
->n
);
1882 if (checkmass
<= 0) {
1883 log_error("mapgen.c: mass doesn't sum up.");
1887 tile_set_terrain(tile1
, T_UNKNOWN
);
1888 map_unset_placed(tile1
);
1890 tile_set_continent(tile1
, pstate
->isleindex
);
1896 pstate
->s
+= nat_y
- pstate
->n
;
1897 pstate
->e
+= nat_x
- pstate
->w
;
1904 /****************************************************************************
1905 Returns the number of cardinally adjacent tiles have a non-zero elevation.
1906 ****************************************************************************/
1907 static int count_card_adjc_elevated_tiles(struct tile
*ptile
)
1911 cardinal_adjc_iterate(&(wld
.map
), ptile
, tile1
) {
1912 if (hmap(tile1
) != 0) {
1915 } cardinal_adjc_iterate_end
;
1920 /**************************************************************************
1921 finds a place and drop the island created when called with islemass != 0
1922 **************************************************************************/
1923 static bool create_island(int islemass
, struct gen234_state
*pstate
)
1925 int i
, nat_x
, nat_y
;
1926 long int tries
= islemass
*(2+islemass
/20)+99;
1928 struct tile
*ptile
= native_pos_to_tile(&(wld
.map
),
1929 wld
.map
.xsize
/ 2, wld
.map
.ysize
/ 2);
1931 memset(height_map
, '\0', MAP_INDEX_SIZE
* sizeof(*height_map
));
1932 hmap(native_pos_to_tile(&(wld
.map
),
1933 wld
.map
.xsize
/ 2, wld
.map
.ysize
/ 2)) = 1;
1935 index_to_native_pos(&nat_x
, &nat_y
, tile_index(ptile
));
1936 pstate
->n
= nat_y
- 1;
1937 pstate
->w
= nat_x
- 1;
1938 pstate
->s
= nat_y
+ 2;
1939 pstate
->e
= nat_x
+ 2;
1941 while (i
> 0 && tries
-->0) {
1942 ptile
= get_random_map_position_from_state(pstate
);
1943 index_to_native_pos(&nat_x
, &nat_y
, tile_index(ptile
));
1945 if ((!near_singularity(ptile
) || fc_rand(50) < 25 )
1946 && hmap(ptile
) == 0 && count_card_adjc_elevated_tiles(ptile
) > 0) {
1949 if (nat_y
>= pstate
->s
- 1 && pstate
->s
< wld
.map
.ysize
- 2) {
1952 if (nat_x
>= pstate
->e
- 1 && pstate
->e
< wld
.map
.xsize
- 2) {
1955 if (nat_y
<= pstate
->n
&& pstate
->n
> 2) {
1958 if (nat_x
<= pstate
->w
&& pstate
->w
> 2) {
1962 if (i
< islemass
/ 10) {
1965 for (ycur
= pstate
->n
; ycur
< pstate
->s
; ycur
++) {
1966 for (xcur
= pstate
->w
; xcur
< pstate
->e
; xcur
++) {
1967 ptile
= native_pos_to_tile(&(wld
.map
), xcur
, ycur
);
1968 if (hmap(ptile
) == 0 && i
> 0
1969 && count_card_adjc_elevated_tiles(ptile
) == 4) {
1978 log_error("create_island ended early with %d/%d.", islemass
-i
, islemass
);
1981 tries
= map_num_tiles() / 4; /* on a 40x60 map, there are 2400 places */
1982 while (!(j
= place_island(pstate
)) && (--tries
) > 0) {
1988 /*************************************************************************/
1990 /**************************************************************************
1991 Initialize terrain selection lists for make_island().
1992 ***************************************************************************/
1993 static void island_terrain_init(void)
1995 struct terrain_select
*ptersel
;
1998 island_terrain
.forest
= terrain_select_list_new_full(tersel_free
);
1999 ptersel
= tersel_new(1, MG_FOLIAGE
, MG_TROPICAL
, MG_DRY
,
2000 TT_TROPICAL
, WC_ALL
);
2001 terrain_select_list_append(island_terrain
.forest
, ptersel
);
2002 ptersel
= tersel_new(3, MG_FOLIAGE
, MG_TEMPERATE
, MG_UNUSED
,
2004 terrain_select_list_append(island_terrain
.forest
, ptersel
);
2005 ptersel
= tersel_new(1, MG_FOLIAGE
, MG_WET
, MG_FROZEN
,
2006 TT_TROPICAL
, WC_NDRY
);
2007 terrain_select_list_append(island_terrain
.forest
, ptersel
);
2008 ptersel
= tersel_new(1, MG_FOLIAGE
, MG_COLD
, MG_UNUSED
,
2009 TT_NFROZEN
, WC_ALL
);
2010 terrain_select_list_append(island_terrain
.forest
, ptersel
);
2013 island_terrain
.desert
= terrain_select_list_new_full(tersel_free
);
2014 ptersel
= tersel_new(3, MG_DRY
, MG_TROPICAL
, MG_GREEN
,
2016 terrain_select_list_append(island_terrain
.desert
, ptersel
);
2017 ptersel
= tersel_new(2, MG_DRY
, MG_TEMPERATE
, MG_GREEN
,
2018 TT_NFROZEN
, WC_DRY
);
2019 terrain_select_list_append(island_terrain
.desert
, ptersel
);
2020 ptersel
= tersel_new(1, MG_COLD
, MG_DRY
, MG_TROPICAL
,
2022 terrain_select_list_append(island_terrain
.desert
, ptersel
);
2023 ptersel
= tersel_new(1, MG_FROZEN
, MG_DRY
, MG_UNUSED
,
2025 terrain_select_list_append(island_terrain
.desert
, ptersel
);
2028 island_terrain
.mountain
= terrain_select_list_new_full(tersel_free
);
2029 ptersel
= tersel_new(2, MG_MOUNTAINOUS
, MG_GREEN
, MG_UNUSED
,
2031 terrain_select_list_append(island_terrain
.mountain
, ptersel
);
2032 ptersel
= tersel_new(1, MG_MOUNTAINOUS
, MG_UNUSED
, MG_GREEN
,
2034 terrain_select_list_append(island_terrain
.mountain
, ptersel
);
2037 island_terrain
.swamp
= terrain_select_list_new_full(tersel_free
);
2038 ptersel
= tersel_new(1, MG_WET
, MG_TROPICAL
, MG_FOLIAGE
,
2039 TT_TROPICAL
, WC_NDRY
);
2040 terrain_select_list_append(island_terrain
.swamp
, ptersel
);
2041 ptersel
= tersel_new(2, MG_WET
, MG_TEMPERATE
, MG_FOLIAGE
,
2043 terrain_select_list_append(island_terrain
.swamp
, ptersel
);
2044 ptersel
= tersel_new(1, MG_WET
, MG_COLD
, MG_FOLIAGE
,
2046 terrain_select_list_append(island_terrain
.swamp
, ptersel
);
2048 island_terrain
.init
= TRUE
;
2051 /**************************************************************************
2052 Free memory allocated for terrain selection lists.
2053 ***************************************************************************/
2054 static void island_terrain_free(void)
2056 if (!island_terrain
.init
) {
2060 terrain_select_list_destroy(island_terrain
.forest
);
2061 terrain_select_list_destroy(island_terrain
.desert
);
2062 terrain_select_list_destroy(island_terrain
.mountain
);
2063 terrain_select_list_destroy(island_terrain
.swamp
);
2065 island_terrain
.init
= FALSE
;
2068 /**************************************************************************
2069 make an island, fill every tile type except plains
2070 note: you have to create big islands first.
2071 Return TRUE if successful.
2072 min_specific_island_size is a percent value.
2073 ***************************************************************************/
2074 static bool make_island(int islemass
, int starters
,
2075 struct gen234_state
*pstate
,
2076 int min_specific_island_size
)
2078 /* int may be only 2 byte ! */
2079 static long int tilefactor
, balance
, lastplaced
;
2080 static long int riverbuck
, mountbuck
, desertbuck
, forestbuck
, swampbuck
;
2083 /* The terrain selection lists have to be initialised.
2084 * (see island_terrain_init()) */
2085 fc_assert_ret_val(island_terrain
.init
, FALSE
);
2087 if (islemass
== 0) {
2088 /* this only runs to initialise static things, not to actually
2089 * create an island. */
2091 /* 0 = none, poles, then isles */
2092 pstate
->isleindex
= wld
.map
.num_continents
+ 1;
2094 checkmass
= pstate
->totalmass
;
2096 /* caveat: this should really be sent to all players */
2097 if (pstate
->totalmass
> 3000) {
2098 log_normal(_("High landmass - this may take a few seconds."));
2101 i
= river_pct
+ mountain_pct
+ desert_pct
+ forest_pct
+ swamp_pct
;
2102 i
= (i
<= 90) ? 100 : i
* 11 / 10;
2103 tilefactor
= pstate
->totalmass
/ i
;
2104 riverbuck
= -(long int) fc_rand(pstate
->totalmass
);
2105 mountbuck
= -(long int) fc_rand(pstate
->totalmass
);
2106 desertbuck
= -(long int) fc_rand(pstate
->totalmass
);
2107 forestbuck
= -(long int) fc_rand(pstate
->totalmass
);
2108 swampbuck
= -(long int) fc_rand(pstate
->totalmass
);
2109 lastplaced
= pstate
->totalmass
;
2112 /* makes the islands this big */
2113 islemass
= islemass
- balance
;
2115 if (islemass
> lastplaced
+ 1 + lastplaced
/ 50) {
2116 /* don't create big isles we can't place */
2117 islemass
= lastplaced
+ 1 + lastplaced
/ 50;
2120 /* isle creation does not perform well for nonsquare islands */
2121 if (islemass
> (wld
.map
.ysize
- 6) * (wld
.map
.ysize
- 6)) {
2122 islemass
= (wld
.map
.ysize
- 6) * (wld
.map
.ysize
- 6);
2125 if (islemass
> (wld
.map
.xsize
- 2) * (wld
.map
.xsize
- 2)) {
2126 islemass
= (wld
.map
.xsize
- 2) * (wld
.map
.xsize
- 2);
2133 fc_assert_ret_val(starters
>= 0, FALSE
);
2134 log_verbose("island %i", pstate
->isleindex
);
2136 /* keep trying to place an island, and decrease the size of
2137 * the island we're trying to create until we succeed.
2138 * If we get too small, return an error. */
2139 while (!create_island(i
, pstate
)) {
2140 if (i
< islemass
* min_specific_island_size
/ 100) {
2147 if (i
* 10 > islemass
) {
2148 balance
= i
- islemass
;
2153 log_verbose("ini=%d, plc=%d, bal=%ld, tot=%ld",
2154 islemass
, i
, balance
, checkmass
);
2158 riverbuck
+= river_pct
* i
;
2159 fill_island_rivers(1, &riverbuck
, pstate
);
2162 forestbuck
+= forest_pct
* i
;
2163 fill_island(60, &forestbuck
, island_terrain
.forest
, pstate
);
2166 desertbuck
+= desert_pct
* i
;
2167 fill_island(40, &desertbuck
, island_terrain
.desert
, pstate
);
2170 mountbuck
+= mountain_pct
* i
;
2171 fill_island(20, &mountbuck
, island_terrain
.mountain
, pstate
);
2174 swampbuck
+= swamp_pct
* i
;
2175 fill_island(80, &swampbuck
, island_terrain
.swamp
, pstate
);
2177 pstate
->isleindex
++;
2178 wld
.map
.num_continents
++;
2183 /**************************************************************************
2184 fill ocean and make polar
2185 A temperature map is created in map_fractal_generate().
2186 **************************************************************************/
2187 static void initworld(struct gen234_state
*pstate
)
2189 struct terrain
*deepest_ocean
= pick_ocean(TERRAIN_OCEAN_DEPTH_MAXIMUM
,
2192 fc_assert(NULL
!= deepest_ocean
);
2193 height_map
= fc_malloc(MAP_INDEX_SIZE
* sizeof(*height_map
));
2194 create_placed_map(); /* land tiles which aren't placed yet */
2196 whole_map_iterate(&(wld
.map
), ptile
) {
2197 tile_set_terrain(ptile
, deepest_ocean
);
2198 tile_set_continent(ptile
, 0);
2199 map_set_placed(ptile
); /* not a land tile */
2200 BV_CLR_ALL(ptile
->extras
);
2201 tile_set_owner(ptile
, NULL
, NULL
);
2202 ptile
->extras_owner
= NULL
;
2203 } whole_map_iterate_end
;
2209 /* Set poles numbers. After the map is generated continents will
2211 make_island(0, 0, pstate
, 0);
2214 /* This variable is the Default Minimum Specific Island Size,
2215 * ie the smallest size we'll typically permit our island, as a % of
2216 * the size we wanted. So if we ask for an island of size x, the island
2217 * creation will return if it would create an island smaller than
2218 * x * DMSIS / 100 */
2221 /**************************************************************************
2222 island base map generators
2223 **************************************************************************/
2224 static void mapgenerator2(void)
2226 long int totalweight
;
2227 struct gen234_state state
;
2228 struct gen234_state
*pstate
= &state
;
2232 /* constant that makes up that an island actually needs additional space */
2234 /* put 70% of land in big continents,
2235 * 20% in medium, and
2237 int bigfrac
= 70, midfrac
= 20, smallfrac
= 10;
2239 if (wld
.map
.server
.landpercent
> 85) {
2240 log_verbose("ISLAND generator: falling back to RANDOM generator");
2241 wld
.map
.server
.generator
= MAPGEN_RANDOM
;
2245 pstate
->totalmass
= ((wld
.map
.ysize
- 6 - spares
) * wld
.map
.server
.landpercent
2246 * (wld
.map
.xsize
- spares
)) / 100;
2247 totalweight
= 100 * player_count();
2249 fc_assert_action(!placed_map_is_initialized(),
2250 wld
.map
.server
.generator
= MAPGEN_RANDOM
; return);
2252 while (!done
&& bigfrac
> midfrac
) {
2255 if (placed_map_is_initialized()) {
2256 destroy_placed_map();
2261 /* Create one big island for each player. */
2262 for (i
= player_count(); i
> 0; i
--) {
2263 if (!make_island(bigfrac
* pstate
->totalmass
/ totalweight
,
2265 /* we couldn't make an island at least 95% as big as we wanted,
2266 * and since we're trying hard to be fair, we need to start again,
2267 * with all big islands reduced slightly in size.
2268 * Take the size reduction from the big islands and add it to the
2269 * small islands to keep overall landmass unchanged.
2270 * Note that the big islands can get very small if necessary, and
2271 * the smaller islands will not exist if we can't place them
2273 log_verbose("Island too small, trying again with all smaller "
2275 midfrac
+= bigfrac
* 0.01;
2276 smallfrac
+= bigfrac
* 0.04;
2284 if (bigfrac
<= midfrac
) {
2285 /* We could never make adequately big islands. */
2286 log_verbose("ISLAND generator: falling back to RANDOM generator");
2287 wld
.map
.server
.generator
= MAPGEN_RANDOM
;
2289 /* init world created this map, destroy it before abort */
2290 destroy_placed_map();
2296 /* Now place smaller islands, but don't worry if they're small,
2297 * or even non-existent. One medium and one small per player. */
2298 for (i
= player_count(); i
> 0; i
--) {
2299 make_island(midfrac
* pstate
->totalmass
/ totalweight
, 0, pstate
, DMSIS
);
2301 for (i
= player_count(); i
> 0; i
--) {
2302 make_island(smallfrac
* pstate
->totalmass
/ totalweight
, 0, pstate
, DMSIS
);
2306 destroy_placed_map();
2310 if (checkmass
> wld
.map
.xsize
+ wld
.map
.ysize
+ totalweight
) {
2311 log_verbose("%ld mass left unplaced", checkmass
);
2315 /**************************************************************************
2316 On popular demand, this tries to mimick the generator 3 as best as possible.
2317 **************************************************************************/
2318 static void mapgenerator3(void)
2323 long int islandmass
,landmass
, size
;
2324 long int maxmassdiv6
=20;
2326 struct gen234_state state
;
2327 struct gen234_state
*pstate
= &state
;
2329 if (wld
.map
.server
.landpercent
> 80) {
2330 log_verbose("ISLAND generator: falling back to FRACTAL generator due "
2331 "to landpercent > 80.");
2332 wld
.map
.server
.generator
= MAPGEN_FRACTAL
;
2336 if (wld
.map
.xsize
< 40 || wld
.map
.ysize
< 40) {
2337 log_verbose("ISLAND generator: falling back to FRACTAL generator due "
2338 "to unsupported map size.");
2339 wld
.map
.server
.generator
= MAPGEN_FRACTAL
;
2343 pstate
->totalmass
= (((wld
.map
.ysize
- 6 - spares
) * wld
.map
.server
.landpercent
2344 * (wld
.map
.xsize
- spares
)) / 100);
2346 bigislands
= player_count();
2348 landmass
= (wld
.map
.xsize
* (wld
.map
.ysize
- 6) * wld
.map
.server
.landpercent
)/100;
2349 /* subtracting the arctics */
2350 if (landmass
> 3 * wld
.map
.ysize
+ player_count() * 3){
2351 landmass
-= 3 * wld
.map
.ysize
;
2355 islandmass
= (landmass
)/(3 * bigislands
);
2356 if (islandmass
< 4 * maxmassdiv6
) {
2357 islandmass
= (landmass
)/(2 * bigislands
);
2359 if (islandmass
< 3 * maxmassdiv6
&& player_count() * 2 < landmass
) {
2360 islandmass
= (landmass
)/(bigislands
);
2363 if (islandmass
< 2) {
2366 if (islandmass
> maxmassdiv6
* 6) {
2367 islandmass
= maxmassdiv6
* 6;/* !PS: let's try this */
2372 while (pstate
->isleindex
- 2 <= bigislands
&& checkmass
> islandmass
2374 make_island(islandmass
, 1, pstate
, DMSIS
);
2378 log_normal(_("Generator 3 didn't place all big islands."));
2381 islandmass
= (islandmass
* 11)/8;
2382 /*!PS: I'd like to mult by 3/2, but starters might make trouble then*/
2383 if (islandmass
< 2) {
2387 while (checkmass
> islandmass
&& ++j
< 1500) {
2389 size
= fc_rand((islandmass
+ 1) / 2 + 1) + islandmass
/ 2;
2391 size
= fc_rand((islandmass
+ 1) / 2 + 1);
2397 make_island(size
, (pstate
->isleindex
- 2 <= player_count()) ? 1 : 0,
2402 destroy_placed_map();
2407 log_normal(_("Generator 3 left %li landmass unplaced."), checkmass
);
2408 } else if (checkmass
> wld
.map
.xsize
+ wld
.map
.ysize
) {
2409 log_verbose("%ld mass left unplaced", checkmass
);
2413 /**************************************************************************
2414 Generator for placing a couple of players to each island.
2415 **************************************************************************/
2416 static void mapgenerator4(void)
2421 long int totalweight
;
2422 struct gen234_state state
;
2423 struct gen234_state
*pstate
= &state
;
2426 /* no islands with mass >> sqr(min(xsize,ysize)) */
2428 if (player_count() < 2 || wld
.map
.server
.landpercent
> 80) {
2429 log_verbose("ISLAND generator: falling back to startpos=SINGLE");
2430 wld
.map
.server
.startpos
= MAPSTARTPOS_SINGLE
;
2434 if (wld
.map
.server
.landpercent
> 60) {
2436 } else if (wld
.map
.server
.landpercent
> 40) {
2442 spares
= (wld
.map
.server
.landpercent
- 5) / 30;
2444 pstate
->totalmass
= (((wld
.map
.ysize
- 6 - spares
) * wld
.map
.server
.landpercent
2445 * (wld
.map
.xsize
- spares
)) / 100);
2447 /*!PS: The weights NEED to sum up to totalweight (dammit) */
2448 totalweight
= (30 + bigweight
) * player_count();
2452 i
= player_count() / 2;
2453 if ((player_count() % 2) == 1) {
2454 make_island(bigweight
* 3 * pstate
->totalmass
/ totalweight
, 3,
2460 make_island(bigweight
* 2 * pstate
->totalmass
/ totalweight
, 2,
2463 for (i
= player_count(); i
> 0; i
--) {
2464 make_island(20 * pstate
->totalmass
/ totalweight
, 0, pstate
, DMSIS
);
2466 for (i
= player_count(); i
> 0; i
--) {
2467 make_island(10 * pstate
->totalmass
/ totalweight
, 0, pstate
, DMSIS
);
2470 destroy_placed_map();
2474 if (checkmass
> wld
.map
.xsize
+ wld
.map
.ysize
+ totalweight
) {
2475 log_verbose("%ld mass left unplaced", checkmass
);
2481 /**************************************************************************
2482 Initialize river types array
2483 **************************************************************************/
2484 static void river_types_init(void)
2486 river_type_count
= 0;
2488 extra_type_by_cause_iterate(EC_ROAD
, priver
) {
2489 if (road_has_flag(extra_road_get(priver
), RF_RIVER
)) {
2490 river_types
[river_type_count
++] = priver
;
2492 } extra_type_by_cause_iterate_end
;
2496 /****************************************************************************
2497 Fair island generator types.
2498 ****************************************************************************/
2499 enum fair_tile_flag
{
2501 FTF_ASSIGNED
= 1 << 0,
2503 FTF_STARTPOS
= 1 << 2,
2504 FTF_NO_RESOURCE
= 1 << 3,
2505 FTF_HAS_HUT
= 1 << 4,
2510 enum fair_tile_flag flags
;
2511 struct terrain
*pterrain
;
2512 struct extra_type
*presource
;
2514 int startpos_team_id
;
2517 typedef void (*fair_geometry_func
)(int *x
, int *y
);
2518 struct fair_geometry_data
{
2519 fair_geometry_func transform
[4];
2523 /****************************************************************************
2524 Create a map. Note that all maps have the same dimensions, to be able to
2526 ****************************************************************************/
2527 static inline struct fair_tile
*fair_map_new(void)
2529 return fc_calloc(MAP_INDEX_SIZE
, sizeof(struct fair_tile
));
2532 /****************************************************************************
2534 ****************************************************************************/
2535 static inline void fair_map_destroy(struct fair_tile
*pmap
)
2540 /****************************************************************************
2541 Get the coordinates of tile 'ptile'.
2542 ****************************************************************************/
2543 static inline void fair_map_tile_pos(struct fair_tile
*pmap
,
2544 struct fair_tile
*ptile
, int *x
, int *y
)
2546 index_to_map_pos(x
, y
, ptile
- pmap
);
2549 /****************************************************************************
2550 Get the tile at the position ('x', 'y').
2551 ****************************************************************************/
2552 static inline struct fair_tile
*
2553 fair_map_pos_tile(struct fair_tile
*pmap
, int x
, int y
)
2557 MAP_TO_NATIVE_POS(&nat_x
, &nat_y
, x
, y
);
2559 /* Wrap in X and Y directions, as needed. */
2560 if (nat_x
< 0 || nat_x
>= wld
.map
.xsize
) {
2561 if (current_topo_has_flag(TF_WRAPX
)) {
2562 nat_x
= FC_WRAP(nat_x
, wld
.map
.xsize
);
2567 if (nat_y
< 0 || nat_y
>= wld
.map
.ysize
) {
2568 if (current_topo_has_flag(TF_WRAPY
)) {
2569 nat_y
= FC_WRAP(nat_y
, wld
.map
.ysize
);
2575 return pmap
+ native_pos_to_index(nat_x
, nat_y
);
2578 /****************************************************************************
2579 Get the next tile in direction 'dir'.
2580 ****************************************************************************/
2581 static inline struct fair_tile
*
2582 fair_map_tile_step(struct fair_tile
*pmap
, struct fair_tile
*ptile
,
2583 enum direction8 dir
)
2587 fair_map_tile_pos(pmap
, ptile
, &x
, &y
);
2588 DIRSTEP(dx
, dy
, dir
);
2589 return fair_map_pos_tile(pmap
, x
+ dx
, y
+ dy
);
2592 /****************************************************************************
2593 Returns whether 'ptile' is at least at 'dist' tiles (in real distance)
2594 to the border. Note is also take in account map wrapping.
2595 ****************************************************************************/
2597 fair_map_tile_border(struct fair_tile
*pmap
, struct fair_tile
*ptile
,
2602 index_to_native_pos(&nat_x
, &nat_y
, ptile
- pmap
);
2604 if (!current_topo_has_flag(TF_WRAPX
)
2605 && (nat_x
< dist
|| nat_x
>= wld
.map
.xsize
- dist
)) {
2609 if (MAP_IS_ISOMETRIC
) {
2613 if (!current_topo_has_flag(TF_WRAPY
)
2614 && (nat_y
< dist
|| nat_y
>= wld
.map
.ysize
- dist
)) {
2621 /****************************************************************************
2622 Compare two iter_index values for doing closest team placement.
2623 ****************************************************************************/
2624 static int fair_team_placement_closest(const void *a
, const void *b
)
2626 const struct iter_index
*index1
= a
, *index2
= b
;
2628 return index1
->dist
- index2
->dist
;
2631 /****************************************************************************
2632 Compare two iter_index values for doing horizontal team placement.
2633 ****************************************************************************/
2634 static int fair_team_placement_horizontal(const void *a
, const void *b
)
2636 const struct iter_index
*index1
= a
, *index2
= b
;
2637 /* Map vector to natural vector (Y axis). */
2638 int diff
= (MAP_IS_ISOMETRIC
2639 ? abs(index1
->dx
+ index1
->dy
) - abs(index2
->dx
+ index2
->dy
)
2640 : abs(index1
->dy
) - abs(index2
->dy
));
2642 return (diff
!= 0 ? diff
: index1
->dist
- index2
->dist
);
2645 /****************************************************************************
2646 Compare two iter_index values for doing vertical team placement.
2647 ****************************************************************************/
2648 static int fair_team_placement_vertical(const void *a
, const void *b
)
2650 const struct iter_index
*index1
= a
, *index2
= b
;
2651 /* Map vector to natural vector (X axis). */
2652 int diff
= (MAP_IS_ISOMETRIC
2653 ? abs(index1
->dx
- index1
->dy
) - abs(index2
->dx
- index2
->dy
)
2654 : abs(index1
->dx
) - abs(index2
->dx
));
2656 return (diff
!= 0 ? diff
: index1
->dist
- index2
->dist
);
2659 /****************************************************************************
2661 ****************************************************************************/
2662 static void fair_do_symetry1(int *x
, int *y
)
2667 /****************************************************************************
2669 ****************************************************************************/
2670 static void fair_do_symetry2(int *x
, int *y
)
2675 /****************************************************************************
2676 Symetry matrix for hexagonal topologies.
2677 ****************************************************************************/
2678 static void fair_do_hex_symetry1(int *x
, int *y
)
2683 /****************************************************************************
2684 Symetry matrix for hexagonal topologies.
2685 ****************************************************************************/
2686 static void fair_do_hex_symetry2(int *x
, int *y
)
2692 /****************************************************************************
2693 Symetry matrix for hexgonal-isometric topology.
2694 ****************************************************************************/
2695 static void fair_do_iso_hex_symetry1(int *x
, int *y
)
2700 #define fair_do_iso_hex_symetry2 fair_do_rotation
2702 /****************************************************************************
2703 Rotation matrix, also symetry matrix for hexagonal-isometric topology.
2704 ****************************************************************************/
2705 static void fair_do_rotation(int *x
, int *y
)
2713 /****************************************************************************
2714 Rotation matrix for hexgonal topology.
2715 ****************************************************************************/
2716 static void fair_do_hex_rotation(int *x
, int *y
)
2724 /****************************************************************************
2725 Rotation matrix for hexgonal-isometric topology.
2726 ****************************************************************************/
2727 static void fair_do_iso_hex_rotation(int *x
, int *y
)
2735 /****************************************************************************
2736 Perform transformations defined into 'data' to position ('x', 'y').
2737 ****************************************************************************/
2738 static void fair_do_geometry(const struct fair_geometry_data
*data
,
2743 for (i
= 0; i
< data
->transform_num
; i
++) {
2744 data
->transform
[i
](x
, y
);
2748 /****************************************************************************
2749 Push random transformations to 'data'.
2750 ****************************************************************************/
2751 static void fair_geometry_rand(struct fair_geometry_data
*data
)
2755 if (!current_topo_has_flag(TF_HEX
)) {
2756 if (fc_rand(100) < 50) {
2757 data
->transform
[i
++] = fair_do_symetry1
;
2759 if (fc_rand(100) < 50) {
2760 data
->transform
[i
++] = fair_do_symetry2
;
2762 if (fc_rand(100) < 50) {
2763 data
->transform
[i
++] = fair_do_rotation
;
2765 } else if (!current_topo_has_flag(TF_ISO
)) {
2768 if (fc_rand(100) < 50) {
2769 data
->transform
[i
++] = fair_do_hex_symetry1
;
2771 if (fc_rand(100) < 50) {
2772 data
->transform
[i
++] = fair_do_hex_symetry2
;
2774 /* Rotations have 2 steps on hexgonal topologies. */
2775 for (steps
= fc_rand(99) % 3; steps
> 0; steps
--) {
2776 data
->transform
[i
++] = fair_do_hex_rotation
;
2781 if (fc_rand(100) < 50) {
2782 data
->transform
[i
++] = fair_do_iso_hex_symetry1
;
2784 if (fc_rand(100) < 50) {
2785 data
->transform
[i
++] = fair_do_iso_hex_symetry2
;
2787 /* Rotations have 2 steps on hexgonal topologies. */
2788 for (steps
= fc_rand(99) % 3; steps
> 0; steps
--) {
2789 data
->transform
[i
++] = fair_do_iso_hex_rotation
;
2792 fc_assert(i
<= ARRAY_SIZE(data
->transform
));
2793 data
->transform_num
= i
;
2796 /****************************************************************************
2797 Copy 'psource' on 'ptarget' at position ('tx', 'ty'), performing
2798 transformations defined into 'data'. Assign start positions for team
2799 'startpos_team_id'. Return TRUE if we have copied the map, FALSE if the
2800 copy was not possible.
2801 ****************************************************************************/
2802 static bool fair_map_copy(struct fair_tile
*ptarget
, int tx
, int ty
,
2803 struct fair_tile
*psource
,
2804 const struct fair_geometry_data
*data
,
2805 int startpos_team_id
)
2807 int sdx
= wld
.map
.xsize
/ 2, sdy
= wld
.map
.ysize
/ 2;
2808 struct fair_tile
*smax_tile
= psource
+ MAP_INDEX_SIZE
;
2809 struct fair_tile
*pstile
, *pttile
;
2813 for (pstile
= psource
; pstile
< smax_tile
; pstile
++) {
2814 if (pstile
->flags
== FTF_NONE
) {
2818 /* Do translation and eventually other transformations. */
2819 fair_map_tile_pos(psource
, pstile
, &x
, &y
);
2822 fair_do_geometry(data
, &x
, &y
);
2825 pttile
= fair_map_pos_tile(ptarget
, x
, y
);
2826 if (pttile
== NULL
) {
2827 return FALSE
; /* Limit of the map. */
2829 if (pttile
->flags
& FTF_ASSIGNED
) {
2830 if (pstile
->flags
& FTF_ASSIGNED
2831 || !(pttile
->flags
& FTF_OCEAN
)
2832 || !(pstile
->flags
& FTF_OCEAN
)) {
2833 return FALSE
; /* Already assigned for another usage. */
2835 } else if (pttile
->flags
& FTF_OCEAN
&& !(pstile
->flags
& FTF_OCEAN
)) {
2836 return FALSE
; /* We clearly want a sea tile here. */
2838 if ((pttile
->flags
& FTF_NO_RESOURCE
&& pstile
->presource
!= NULL
)
2839 || (pstile
->flags
& FTF_NO_RESOURCE
&& pttile
->presource
!= NULL
)) {
2840 return FALSE
; /* Resource disallowed there. */
2842 if ((pttile
->flags
& FTF_NO_HUT
&& pstile
->flags
& FTF_HAS_HUT
)
2843 || (pstile
->flags
& FTF_NO_HUT
&& pttile
->flags
& FTF_HAS_HUT
)) {
2844 return FALSE
; /* Resource disallowed there. */
2849 for (pstile
= psource
; pstile
< smax_tile
; pstile
++) {
2850 if (pstile
->flags
== FTF_NONE
) {
2854 /* Do translation and eventually other transformations. */
2855 fair_map_tile_pos(psource
, pstile
, &x
, &y
);
2858 fair_do_geometry(data
, &x
, &y
);
2861 pttile
= fair_map_pos_tile(ptarget
, x
, y
);
2862 fc_assert_ret_val(pttile
!= NULL
, FALSE
);
2863 pttile
->flags
|= pstile
->flags
;
2864 if (pstile
->pterrain
!= NULL
) {
2865 pttile
->pterrain
= pstile
->pterrain
;
2866 pttile
->presource
= pstile
->presource
;
2867 pttile
->extras
= pstile
->extras
;
2869 if (pstile
->flags
& FTF_STARTPOS
) {
2870 pttile
->startpos_team_id
= startpos_team_id
;
2873 return TRUE
; /* Looks ok. */
2876 /****************************************************************************
2877 Attempts to copy 'psource' to 'ptarget' at a random position, with random
2879 ****************************************************************************/
2880 static bool fair_map_place_island_rand(struct fair_tile
*ptarget
,
2881 struct fair_tile
*psource
)
2883 struct fair_geometry_data geometry
;
2886 fair_geometry_rand(&geometry
);
2888 /* Try random positions. */
2889 for (i
= 0; i
< 10; i
++) {
2890 r
= fc_rand(MAP_INDEX_SIZE
);
2891 index_to_map_pos(&x
, &y
, r
);
2892 if (fair_map_copy(ptarget
, x
, y
, psource
, &geometry
, -1)) {
2897 /* Try hard placement. */
2898 r
= fc_rand(MAP_INDEX_SIZE
);
2899 for (i
= (r
+ 1) % MAP_INDEX_SIZE
; i
!= r
; i
= (i
+ 1) % MAP_INDEX_SIZE
) {
2900 index_to_map_pos(&x
, &y
, i
);
2901 if (fair_map_copy(ptarget
, x
, y
, psource
, &geometry
, -1)) {
2906 /* Impossible placement. */
2910 /****************************************************************************
2911 Attempts to copy 'psource' to 'ptarget' as close as possible of position
2912 'x', 'y' for players of the team 'team_id'.
2913 ****************************************************************************/
2915 fair_map_place_island_team(struct fair_tile
*ptarget
, int tx
, int ty
,
2916 struct fair_tile
*psource
,
2917 const struct iter_index
*outwards_indices
,
2918 int startpos_team_id
)
2920 struct fair_geometry_data geometry
;
2923 fair_geometry_rand(&geometry
);
2925 /* Iterate positions, beginning by a random index of the outwards
2927 for (i
= fc_rand(wld
.map
.num_iterate_outwards_indices
/ 200);
2928 i
< wld
.map
.num_iterate_outwards_indices
; i
++) {
2929 x
= tx
+ outwards_indices
[i
].dx
;
2930 y
= ty
+ outwards_indices
[i
].dy
;
2931 if (normalize_map_pos(&(wld
.map
), &x
, &y
)
2932 && fair_map_copy(ptarget
, x
, y
, psource
, &geometry
,
2933 startpos_team_id
)) {
2938 /* Impossible placement. */
2942 /****************************************************************************
2943 Add resources on 'pmap'.
2944 ****************************************************************************/
2945 static void fair_map_make_resources(struct fair_tile
*pmap
)
2947 struct fair_tile
*pftile
, *pftile2
;
2948 struct extra_type
**r
;
2951 for (i
= 0; i
< MAP_INDEX_SIZE
; i
++) {
2953 if (pftile
->flags
== FTF_NONE
2954 || pftile
->flags
& FTF_NO_RESOURCE
2955 || fc_rand (1000) > wld
.map
.server
.riches
) {
2959 if (pftile
->flags
& FTF_OCEAN
) {
2960 bool land_around
= FALSE
;
2962 for (j
= 0; j
< wld
.map
.num_valid_dirs
; j
++) {
2963 pftile2
= fair_map_tile_step(pmap
, pftile
, wld
.map
.valid_dirs
[j
]);
2965 && pftile2
->flags
& FTF_ASSIGNED
2966 && !(pftile2
->flags
& FTF_OCEAN
)) {
2977 for (r
= pftile
->pterrain
->resources
; *r
!= NULL
; r
++) {
2978 if (fc_rand(++j
) == 0) {
2979 pftile
->presource
= *r
;
2982 /* Note that 'pftile->presource' might be NULL if there is no suitable
2983 * resource for the terrain. */
2984 if (pftile
->presource
!= NULL
) {
2985 pftile
->flags
|= FTF_NO_RESOURCE
;
2986 for (j
= 0; j
< wld
.map
.num_valid_dirs
; j
++) {
2987 pftile2
= fair_map_tile_step(pmap
, pftile
, wld
.map
.valid_dirs
[j
]);
2988 if (pftile2
!= NULL
) {
2989 pftile2
->flags
|= FTF_NO_RESOURCE
;
2993 BV_SET(pftile
->extras
, extra_index(pftile
->presource
));
2998 /****************************************************************************
3000 ****************************************************************************/
3001 static void fair_map_make_huts(struct fair_tile
*pmap
)
3003 struct fair_tile
*pftile
;
3004 struct tile
*pvtile
= tile_virtual_new(NULL
);
3005 struct extra_type
*phut
;
3008 for (i
= wld
.map
.server
.huts
* map_num_tiles() / 1000, j
= 0;
3009 i
> 0 && j
< map_num_tiles() * 2; j
++) {
3010 k
= fc_rand(MAP_INDEX_SIZE
);
3012 while (pftile
->flags
& FTF_NO_HUT
) {
3014 if (pftile
- pmap
== MAP_INDEX_SIZE
) {
3017 if (pftile
- pmap
== k
) {
3021 if (pftile
->flags
& FTF_NO_HUT
) {
3022 break; /* Cannot make huts anymore. */
3026 if (pftile
->pterrain
== NULL
) {
3027 continue; /* Not an used tile. */
3030 pvtile
->index
= pftile
- pmap
;
3031 tile_set_terrain(pvtile
, pftile
->pterrain
);
3032 tile_set_resource(pvtile
, pftile
->presource
);
3033 pvtile
->extras
= pftile
->extras
;
3035 phut
= rand_extra_for_tile(pvtile
, EC_HUT
);
3037 tile_add_extra(pvtile
, phut
);
3038 pftile
->extras
= pvtile
->extras
;
3039 pftile
->flags
|= FTF_HAS_HUT
;
3040 square_iterate(&(wld
.map
), index_to_tile(&(wld
.map
), pftile
- pmap
),
3042 pmap
[tile_index(ptile
)].flags
|= FTF_NO_HUT
;
3043 } square_iterate_end
;
3047 tile_virtual_destroy(pvtile
);
3050 /****************************************************************************
3051 Generate a map where an island would be placed in the center.
3052 ****************************************************************************/
3053 static struct fair_tile
*fair_map_island_new(int size
, int startpos_num
)
3066 enum mapgen_terrain_property target
;
3067 enum mapgen_terrain_property prefer
;
3068 enum mapgen_terrain_property avoid
;
3069 } terrain
[FT_COUNT
] = {
3070 { 0, MG_TEMPERATE
, MG_GREEN
, MG_MOUNTAINOUS
},
3071 { 0, MG_FOLIAGE
, MG_TEMPERATE
, MG_UNUSED
},
3072 { 0, MG_DRY
, MG_TEMPERATE
, MG_GREEN
},
3073 { 0, MG_MOUNTAINOUS
, MG_GREEN
, MG_UNUSED
},
3074 { 0, MG_MOUNTAINOUS
, MG_UNUSED
, MG_GREEN
},
3075 { 0, MG_WET
, MG_TEMPERATE
, MG_FOLIAGE
},
3078 struct fair_tile
*pisland
;
3079 struct fair_tile
*land_tiles
[1000];
3080 struct fair_tile
*pftile
, *pftile2
, *pftile3
;
3082 const int sea_around_island
= (startpos_num
> 0
3083 ? CITY_MAP_DEFAULT_RADIUS
: 1);
3084 const int sea_around_island_sq
= (startpos_num
> 0
3085 ? CITY_MAP_DEFAULT_RADIUS_SQ
: 2);
3088 size
= CLIP(startpos_num
, size
, ARRAY_SIZE(land_tiles
));
3089 fantasy
= (size
* 2) / 5;
3090 pisland
= fair_map_new();
3091 pftile
= fair_map_pos_tile(pisland
, wld
.map
.xsize
/ 2, wld
.map
.ysize
/ 2);
3092 fc_assert(!fair_map_tile_border(pisland
, pftile
, sea_around_island
));
3093 pftile
->flags
|= FTF_ASSIGNED
;
3094 land_tiles
[0] = pftile
;
3097 log_debug("Generating an island with %d land tiles [fantasy=%d].",
3101 while (i
< fantasy
) {
3102 pftile
= land_tiles
[fc_rand(i
)];
3104 for (j
= 0; j
< wld
.map
.num_valid_dirs
; j
++) {
3105 pftile2
= fair_map_tile_step(pisland
, pftile
, wld
.map
.valid_dirs
[j
]);
3106 fc_assert(pftile2
!= NULL
);
3107 if (fair_map_tile_border(pisland
, pftile2
, sea_around_island
)) {
3111 if (pftile2
->flags
== FTF_NONE
) {
3112 pftile2
->flags
= FTF_ASSIGNED
;
3113 land_tiles
[i
++] = pftile2
;
3121 pftile
= land_tiles
[i
- fc_rand(fantasy
) - 1];
3122 pftile2
= fair_map_tile_step(pisland
, pftile
, wld
.map
.cardinal_dirs
3123 [fc_rand(wld
.map
.num_cardinal_dirs
)]);
3124 fc_assert(pftile2
!= NULL
);
3125 if (fair_map_tile_border(pisland
, pftile2
, sea_around_island
)) {
3129 if (pftile2
->flags
== FTF_NONE
) {
3130 pftile2
->flags
= FTF_ASSIGNED
;
3131 land_tiles
[i
++] = pftile2
;
3134 fc_assert(i
== size
);
3136 /* Add start positions. */
3137 for (i
= 0; i
< startpos_num
;) {
3138 pftile
= land_tiles
[fc_rand(size
- fantasy
)];
3139 fc_assert(pftile
->flags
& FTF_ASSIGNED
);
3140 if (!(pftile
->flags
& FTF_STARTPOS
)) {
3141 pftile
->flags
|= FTF_STARTPOS
;
3147 terrain
[FT_GRASSLAND
].count
= size
- startpos_num
;
3148 terrain
[FT_FOREST
].count
= ((forest_pct
+ jungle_pct
) * size
) / 100;
3149 terrain
[FT_DESERT
].count
= (desert_pct
* size
) / 100;
3150 terrain
[FT_HILL
].count
= (mountain_pct
* size
) / 150;
3151 terrain
[FT_MOUNTAIN
].count
= (mountain_pct
* size
) / 300;
3152 terrain
[FT_SWAMP
].count
= (swamp_pct
* size
) / 100;
3155 for (i
= 0; i
< size
; i
++) {
3156 pftile
= land_tiles
[i
];
3158 if (pftile
->flags
& FTF_STARTPOS
) {
3159 pftile
->pterrain
= pick_terrain_by_flag(TER_STARTER
);
3161 if (terrain
[j
].count
== 0 || fc_rand(100) < 70) {
3163 j
= fc_rand(FT_COUNT
);
3164 } while (terrain
[j
].count
== 0);
3166 pftile
->pterrain
= pick_terrain(terrain
[j
].target
, terrain
[j
].prefer
,
3172 /* Make sea around the island. */
3173 for (i
= 0; i
< size
; i
++) {
3174 circle_iterate(&(wld
.map
),
3175 index_to_tile(&(wld
.map
), land_tiles
[i
] - pisland
),
3176 sea_around_island_sq
, ptile
) {
3177 pftile
= pisland
+ tile_index(ptile
);
3179 if (pftile
->flags
== FTF_NONE
) {
3180 pftile
->flags
= FTF_OCEAN
;
3181 /* No ice around island */
3183 pick_ocean(TERRAIN_OCEAN_DEPTH_MINIMUM
3184 + fc_rand(TERRAIN_OCEAN_DEPTH_MAXIMUM
/ 2), FALSE
);
3185 if (startpos_num
> 0) {
3186 pftile
->flags
|= FTF_ASSIGNED
;
3189 } circle_iterate_end
;
3193 if (river_type_count
> 0) {
3194 struct extra_type
*priver
;
3195 struct fair_tile
*pend
;
3196 int n
= ((river_pct
* size
* wld
.map
.num_cardinal_dirs
3197 * wld
.map
.num_cardinal_dirs
) / 200);
3198 int length_max
= 3, length
, l
;
3199 enum direction8 dir
;
3203 bool connectable_river_around
, ocean_around
;
3207 for (i
= 0; i
< n
; i
++) {
3208 pftile
= land_tiles
[fc_rand(size
)];
3209 if (!terrain_has_flag(pftile
->pterrain
, TER_CAN_HAVE_RIVER
)) {
3213 priver
= river_types
[fc_rand(river_type_count
)];
3214 extra_idx
= extra_index(priver
);
3215 if (BV_ISSET(pftile
->extras
, extra_idx
)) {
3218 cardinal_only
= is_cardinal_only_road(priver
);
3221 connectable_river_around
= FALSE
;
3222 ocean_around
= FALSE
;
3223 for (j
= 0; j
< wld
.map
.num_valid_dirs
; j
++) {
3224 pftile2
= fair_map_tile_step(pisland
, pftile
, wld
.map
.valid_dirs
[j
]);
3225 if (pftile2
== NULL
) {
3229 if (pftile2
->flags
& FTF_OCEAN
) {
3230 ocean_around
= TRUE
;
3232 } else if (BV_ISSET(pftile2
->extras
, extra_idx
)) {
3234 if (!cardinal_only
|| is_cardinal_dir(wld
.map
.valid_dirs
[j
])) {
3235 connectable_river_around
= TRUE
;
3241 || (river_around
== 1 && !connectable_river_around
)) {
3245 if (connectable_river_around
) {
3246 log_debug("Adding river at (%d, %d)",
3247 index_to_map_pos_x(pftile
- pisland
),
3248 index_to_map_pos_y(pftile
- pisland
));
3249 BV_SET(pftile
->extras
, extra_idx
);
3253 /* Check a river in one direction. */
3256 dir
= direction8_invalid();
3258 for (j
= 0; j
< wld
.map
.num_valid_dirs
; j
++) {
3259 if (cardinal_only
&& !is_cardinal_dir(wld
.map
.valid_dirs
[j
])) {
3265 for (l
= 2; l
< length_max
; l
++) {
3266 pftile2
= fair_map_tile_step(pisland
, pftile2
, wld
.map
.valid_dirs
[j
]);
3268 || !terrain_has_flag(pftile2
->pterrain
, TER_CAN_HAVE_RIVER
)) {
3273 connectable_river_around
= FALSE
;
3274 ocean_around
= FALSE
;
3275 for (k
= 0; k
< wld
.map
.num_valid_dirs
; k
++) {
3276 if (wld
.map
.valid_dirs
[k
] == DIR_REVERSE(wld
.map
.valid_dirs
[j
])) {
3280 pftile3
= fair_map_tile_step(pisland
, pftile2
,
3281 wld
.map
.valid_dirs
[k
]);
3282 if (pftile3
== NULL
) {
3286 if (pftile3
->flags
& FTF_OCEAN
) {
3287 if (!cardinal_only
|| is_cardinal_dir(wld
.map
.valid_dirs
[k
])) {
3288 ocean_around
= TRUE
;
3290 } else if (BV_ISSET(pftile3
->extras
, extra_idx
)) {
3292 if (!cardinal_only
|| is_cardinal_dir(wld
.map
.valid_dirs
[k
])) {
3293 connectable_river_around
= TRUE
;
3297 if (river_around
> 1 && !connectable_river_around
) {
3299 } else if (ocean_around
|| connectable_river_around
) {
3304 if (finished
&& fc_rand(++dirs_num
) == 0) {
3305 dir
= wld
.map
.valid_dirs
[j
];
3314 log_debug("Make river from (%d, %d) to (%d, %d) [dir=%s, length=%d]",
3315 index_to_map_pos_x(pftile
- pisland
),
3316 index_to_map_pos_y(pftile
- pisland
),
3317 index_to_map_pos_x(pend
- pisland
),
3318 index_to_map_pos_y(pend
- pisland
),
3319 direction8_name(dir
),
3322 BV_SET(pftile
->extras
, extra_idx
);
3324 if (pftile
== pend
) {
3325 fc_assert(length
== 0);
3328 pftile
= fair_map_tile_step(pisland
, pftile
, dir
);
3329 fc_assert(pftile
!= NULL
);
3334 if (startpos_num
> 0) {
3335 /* Islands with start positions must have the same resources and the
3336 * same huts. Other ones don't matter. */
3338 /* Make resources. */
3339 if (wld
.map
.server
.riches
> 0) {
3340 fair_map_make_resources(pisland
);
3344 if (wld
.map
.server
.huts
> 0) {
3345 fair_map_make_huts(pisland
);
3348 /* Make sure there will be no more resources and huts on assigned
3350 for (i
= 0; i
< MAP_INDEX_SIZE
; i
++) {
3351 pftile
= pisland
+ i
;
3352 if (pftile
->flags
& FTF_ASSIGNED
) {
3353 pftile
->flags
|= (FTF_NO_RESOURCE
| FTF_NO_HUT
);
3361 /****************************************************************************
3362 Build a map using generator 'FAIR'.
3363 ****************************************************************************/
3364 static bool map_generate_fair_islands(void)
3366 struct terrain
*deepest_ocean
3367 = pick_ocean(TERRAIN_OCEAN_DEPTH_MAXIMUM
, FALSE
);
3368 struct fair_tile
*pmap
, *pisland
;
3369 int playermass
, islandmass1
, islandmass2
, islandmass3
;
3370 int min_island_size
= wld
.map
.server
.tinyisles
? 1 : 2;
3371 int players_per_island
= 1;
3372 int teams_num
= 0, team_players_num
= 0, single_players_num
= 0;
3373 int i
, iter
= CLIP(1, 100000 / map_num_tiles(), 10);
3376 teams_iterate(pteam
) {
3377 i
= player_list_size(team_members(pteam
));
3380 single_players_num
++;
3383 team_players_num
+= i
;
3385 } teams_iterate_end
;
3386 fc_assert(team_players_num
+ single_players_num
== player_count());
3388 /* Take in account the 'startpos' setting. */
3389 if (wld
.map
.server
.startpos
== MAPSTARTPOS_DEFAULT
3390 && wld
.map
.server
.team_placement
== TEAM_PLACEMENT_CONTINENT
) {
3391 wld
.map
.server
.startpos
= MAPSTARTPOS_ALL
;
3394 switch (wld
.map
.server
.startpos
) {
3395 case MAPSTARTPOS_2or3
:
3397 bool maybe2
= (0 == player_count() % 2);
3398 bool maybe3
= (0 == player_count() % 3);
3400 if (wld
.map
.server
.team_placement
!= TEAM_PLACEMENT_DISABLED
) {
3401 teams_iterate(pteam
) {
3402 i
= player_list_size(team_members(pteam
));
3411 } teams_iterate_end
;
3415 players_per_island
= 3;
3416 } else if (maybe2
) {
3417 players_per_island
= 2;
3421 case MAPSTARTPOS_ALL
:
3422 if (wld
.map
.server
.team_placement
== TEAM_PLACEMENT_CONTINENT
) {
3423 teams_iterate(pteam
) {
3424 i
= player_list_size(team_members(pteam
));
3426 if (players_per_island
== 1) {
3427 players_per_island
= i
;
3428 } else if (i
!= players_per_island
) {
3429 /* Every team doesn't have the same number of players. Cannot
3430 * consider this option. */
3431 players_per_island
= 1;
3432 wld
.map
.server
.team_placement
= TEAM_PLACEMENT_CLOSEST
;
3436 } teams_iterate_end
;
3439 case MAPSTARTPOS_DEFAULT
:
3440 case MAPSTARTPOS_SINGLE
:
3441 case MAPSTARTPOS_VARIABLE
:
3444 if (players_per_island
== 1) {
3445 wld
.map
.server
.startpos
= MAPSTARTPOS_SINGLE
;
3448 whole_map_iterate(&(wld
.map
), ptile
) {
3449 tile_set_terrain(ptile
, deepest_ocean
);
3450 tile_set_continent(ptile
, 0);
3451 BV_CLR_ALL(ptile
->extras
);
3452 tile_set_owner(ptile
, NULL
, NULL
);
3453 ptile
->extras_owner
= NULL
;
3454 } whole_map_iterate_end
;
3460 whole_map_iterate(&(wld
.map
), ptile
) {
3461 if (tile_terrain(ptile
) != deepest_ocean
) {
3464 } whole_map_iterate_end
;
3467 if (wld
.map
.server
.mapsize
== MAPSIZE_PLAYER
) {
3468 playermass
= wld
.map
.server
.tilesperplayer
- i
/ player_count();
3470 playermass
= ((map_num_tiles() * wld
.map
.server
.landpercent
- i
)
3471 / (player_count() * 100));
3473 islandmass1
= (players_per_island
* playermass
* 7) / 10;
3474 if (islandmass1
< min_island_size
) {
3475 islandmass1
= min_island_size
;
3477 islandmass2
= (playermass
* 2) / 10;
3478 if (islandmass2
< min_island_size
) {
3479 islandmass2
= min_island_size
;
3481 islandmass3
= playermass
/ 10;
3482 if (islandmass3
< min_island_size
) {
3483 islandmass3
= min_island_size
;
3486 log_verbose("Creating a map with fair island generator");
3487 log_debug("max iterations=%d", iter
);
3488 log_debug("players_per_island=%d", players_per_island
);
3489 log_debug("team_placement=%s",
3490 team_placement_name(wld
.map
.server
.team_placement
));
3491 log_debug("teams_num=%d, team_players_num=%d, single_players_num=%d",
3492 teams_num
, team_players_num
, single_players_num
);
3493 log_debug("playermass=%d, islandmass1=%d, islandmass2=%d, islandmass3=%d",
3494 playermass
, islandmass1
, islandmass2
, islandmass3
);
3496 pmap
= fair_map_new();
3498 while (--iter
>= 0) {
3501 whole_map_iterate(&(wld
.map
), ptile
) {
3502 struct fair_tile
*pftile
= pmap
+ tile_index(ptile
);
3504 if (tile_terrain(ptile
) != deepest_ocean
) {
3505 pftile
->flags
|= (FTF_ASSIGNED
| FTF_NO_HUT
);
3506 adjc_iterate(&(wld
.map
), ptile
, atile
) {
3507 struct fair_tile
*aftile
= pmap
+ tile_index(atile
);
3509 if (!(aftile
->flags
& FTF_ASSIGNED
)
3510 && tile_terrain(atile
) == deepest_ocean
) {
3511 aftile
->flags
|= FTF_OCEAN
;
3515 pftile
->pterrain
= tile_terrain(ptile
);
3516 pftile
->presource
= tile_resource(ptile
);
3517 pftile
->extras
= *tile_extras(ptile
);
3518 } whole_map_iterate_end
;
3520 /* Create main player island. */
3521 log_debug("Making main island.");
3522 pisland
= fair_map_island_new(islandmass1
, players_per_island
);
3524 log_debug("Place main islands on the map.");
3527 if (wld
.map
.server
.team_placement
!= TEAM_PLACEMENT_DISABLED
3528 && team_players_num
> 0) {
3529 /* Do team placement. */
3530 struct iter_index outwards_indices
[wld
.map
.num_iterate_outwards_indices
];
3531 int start_x
[teams_num
], start_y
[teams_num
];
3535 /* Build outwards_indices. */
3536 memcpy(outwards_indices
, wld
.map
.iterate_outwards_indices
,
3537 sizeof(outwards_indices
));
3538 switch (wld
.map
.server
.team_placement
) {
3539 case TEAM_PLACEMENT_DISABLED
:
3540 fc_assert(wld
.map
.server
.team_placement
!= TEAM_PLACEMENT_DISABLED
);
3541 case TEAM_PLACEMENT_CLOSEST
:
3542 case TEAM_PLACEMENT_CONTINENT
:
3543 for (j
= 0; j
< wld
.map
.num_iterate_outwards_indices
; j
++) {
3544 /* We want square distances for comparing. */
3545 outwards_indices
[j
].dist
=
3546 map_vector_to_sq_distance(outwards_indices
[j
].dx
,
3547 outwards_indices
[j
].dy
);
3549 qsort(outwards_indices
, wld
.map
.num_iterate_outwards_indices
,
3550 sizeof(outwards_indices
[0]), fair_team_placement_closest
);
3552 case TEAM_PLACEMENT_HORIZONTAL
:
3553 qsort(outwards_indices
, wld
.map
.num_iterate_outwards_indices
,
3554 sizeof(outwards_indices
[0]), fair_team_placement_horizontal
);
3556 case TEAM_PLACEMENT_VERTICAL
:
3557 qsort(outwards_indices
, wld
.map
.num_iterate_outwards_indices
,
3558 sizeof(outwards_indices
[0]), fair_team_placement_vertical
);
3562 /* Make start point for teams. */
3563 if (current_topo_has_flag(TF_WRAPX
)) {
3564 dx
= fc_rand(wld
.map
.xsize
);
3566 if (current_topo_has_flag(TF_WRAPY
)) {
3567 dy
= fc_rand(wld
.map
.ysize
);
3569 for (j
= 0; j
< teams_num
; j
++) {
3570 start_x
[j
] = (wld
.map
.xsize
* (2 * j
+ 1)) / (2 * teams_num
) + dx
;
3571 start_y
[j
] = (wld
.map
.ysize
* (2 * j
+ 1)) / (2 * teams_num
) + dy
;
3572 if (current_topo_has_flag(TF_WRAPX
)) {
3573 start_x
[j
] = FC_WRAP(start_x
[j
], wld
.map
.xsize
);
3575 if (current_topo_has_flag(TF_WRAPY
)) {
3576 start_y
[j
] = FC_WRAP(start_y
[j
], wld
.map
.ysize
);
3580 array_shuffle(start_x
, teams_num
);
3581 array_shuffle(start_y
, teams_num
);
3584 teams_iterate(pteam
) {
3585 int members_count
= player_list_size(team_members(pteam
));
3589 if (members_count
<= 1) {
3592 team_id
= team_number(pteam
);
3594 NATIVE_TO_MAP_POS(&x
, &y
, start_x
[j
], start_y
[j
]);
3595 log_verbose("Team %d (%s) will start on (%d, %d)",
3596 team_id
, team_rule_name(pteam
), x
, y
);
3598 for (k
= 0; k
< members_count
; k
+= players_per_island
) {
3599 if (!fair_map_place_island_team(pmap
, x
, y
, pisland
,
3600 outwards_indices
, team_id
)) {
3601 log_verbose("Failed to place island number %d for team %d (%s).",
3602 k
, team_id
, team_rule_name(pteam
));
3612 } teams_iterate_end
;
3614 fc_assert(!done
|| i
== team_players_num
);
3618 /* Place last player islands. */
3619 for (; i
< player_count(); i
+= players_per_island
) {
3620 if (!fair_map_place_island_rand(pmap
, pisland
)) {
3621 log_verbose("Failed to place island number %d.", i
);
3626 fc_assert(!done
|| i
== player_count());
3628 fair_map_destroy(pisland
);
3631 log_debug("Create and place small islands on the map.");
3632 for (i
= 0; i
< player_count(); i
++) {
3633 pisland
= fair_map_island_new(islandmass2
, 0);
3634 if (!fair_map_place_island_rand(pmap
, pisland
)) {
3635 log_verbose("Failed to place small island2 number %d.", i
);
3637 fair_map_destroy(pisland
);
3640 fair_map_destroy(pisland
);
3644 for (i
= 0; i
< player_count(); i
++) {
3645 pisland
= fair_map_island_new(islandmass3
, 0);
3646 if (!fair_map_place_island_rand(pmap
, pisland
)) {
3647 log_verbose("Failed to place small island3 number %d.", i
);
3649 fair_map_destroy(pisland
);
3652 fair_map_destroy(pisland
);
3660 fair_map_destroy(pmap
);
3661 pmap
= fair_map_new();
3663 /* Decrease land mass, for better chances. */
3664 islandmass1
= (islandmass1
* 99) / 100;
3665 if (islandmass1
< min_island_size
) {
3666 islandmass1
= min_island_size
;
3668 islandmass2
= (islandmass2
* 99) / 100;
3669 if (islandmass2
< min_island_size
) {
3670 islandmass2
= min_island_size
;
3672 islandmass3
= (islandmass3
* 99) / 100;
3673 if (islandmass3
< min_island_size
) {
3674 islandmass3
= min_island_size
;
3679 log_verbose("Failed to create map after %d iterations.", iter
);
3680 wld
.map
.server
.generator
= MAPGEN_ISLAND
;
3684 /* Finalize the map. */
3685 for (i
= 0; i
< MAP_INDEX_SIZE
; i
++) {
3686 /* Mark all tiles as assigned, for adding resources and huts. */
3687 pmap
[i
].flags
|= FTF_ASSIGNED
;
3689 if (wld
.map
.server
.riches
> 0) {
3690 fair_map_make_resources(pmap
);
3692 if (wld
.map
.server
.huts
> 0) {
3693 fair_map_make_huts(pmap
);
3696 /* Apply the map. */
3697 log_debug("Applying the map...");
3698 whole_map_iterate(&(wld
.map
), ptile
) {
3699 struct fair_tile
*pftile
= pmap
+ tile_index(ptile
);
3701 fc_assert(pftile
->pterrain
!= NULL
);
3702 tile_set_terrain(ptile
, pftile
->pterrain
);
3703 ptile
->extras
= pftile
->extras
;
3704 tile_set_resource(ptile
, pftile
->presource
);
3705 if (pftile
->flags
& FTF_STARTPOS
) {
3706 struct startpos
*psp
= map_startpos_new(ptile
);
3708 if (pftile
->startpos_team_id
!= -1) {
3709 player_list_iterate(team_members(team_by_number
3710 (pftile
->startpos_team_id
)), pplayer
) {
3711 startpos_allow(psp
, nation_of_player(pplayer
));
3712 } player_list_iterate_end
;
3714 startpos_allows_all(psp
);
3717 } whole_map_iterate_end
;
3719 wld
.map
.server
.have_resources
= TRUE
;
3720 wld
.map
.server
.have_huts
= TRUE
;
3722 fair_map_destroy(pmap
);
3724 log_verbose("Fair island map created with success!");