1 /**********************************************************************
2 Freeciv - Copyright (C) 2004 - Marcelo J. Burda
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 ***********************************************************************/
14 #include <fc_config.h>
21 #include "support.h" /* bool type */
29 #include "utilities.h"
31 /****************************************************************************
32 Map that contains, according to circumstances, information on whether
33 we have already placed terrain (special, hut) here.
34 ****************************************************************************/
35 static bool *placed_map
;
37 /**************************************************************************
38 return TRUE if initialized
39 *************************************************************************/
40 bool placed_map_is_initialized(void)
42 return placed_map
!= NULL
;
45 /****************************************************************************
47 ****************************************************************************/
48 void create_placed_map(void)
50 fc_assert_ret(!placed_map_is_initialized());
51 placed_map
= fc_malloc (sizeof(bool) * MAP_INDEX_SIZE
);
52 INITIALIZE_ARRAY(placed_map
, MAP_INDEX_SIZE
, FALSE
);
55 /****************************************************************************
57 ****************************************************************************/
58 void destroy_placed_map(void)
60 fc_assert_ret(placed_map_is_initialized());
67 #define pmap(_tile) (placed_map[tile_index(_tile)])
69 /**************************************************************************
70 Checks if land has not yet been placed on pmap at (x, y)
71 **************************************************************************/
72 bool not_placed(const struct tile
*ptile
)
77 /**************************************************************************
78 Mark tile terrain as placed.
79 **************************************************************************/
80 void map_set_placed(struct tile
*ptile
)
85 /**************************************************************************
86 Mark tile terrain as not placed.
87 **************************************************************************/
88 void map_unset_placed(struct tile
*ptile
)
93 /****************************************************************************
94 set all oceanics tiles in placed_map
95 ****************************************************************************/
96 void set_all_ocean_tiles_placed(void)
98 whole_map_iterate(ptile
) {
99 if (is_ocean_tile(ptile
)) {
100 map_set_placed(ptile
);
102 } whole_map_iterate_end
;
105 /****************************************************************************
106 Set all nearby tiles as placed on pmap.
107 ****************************************************************************/
108 void set_placed_near_pos(struct tile
*ptile
, int dist
)
110 square_iterate(ptile
, dist
, tile1
) {
111 map_set_placed(tile1
);
112 } square_iterate_end
;
115 /**************************************************************************
116 Change the values of the integer map, so that they contain ranking of each
117 tile scaled to [0 .. int_map_max].
118 The lowest 20% of tiles will have values lower than 0.2 * int_map_max.
120 If filter is non-null then it only tiles for which filter(ptile, data) is
121 TRUE will be considered.
122 **************************************************************************/
123 void adjust_int_map_filtered(int *int_map
, int int_map_max
, void *data
,
124 bool (*filter
)(const struct tile
*ptile
,
127 int minval
= 0, maxval
= 0, total
= 0;
130 /* Determine minimum and maximum value. */
131 whole_map_iterate_filtered(ptile
, data
, filter
) {
133 minval
= int_map
[tile_index(ptile
)];
134 maxval
= int_map
[tile_index(ptile
)];
136 maxval
= MAX(maxval
, int_map
[tile_index(ptile
)]);
137 minval
= MIN(minval
, int_map
[tile_index(ptile
)]);
141 } whole_map_iterate_filtered_end
;
148 int const size
= 1 + maxval
- minval
;
149 int i
, count
= 0, frequencies
[size
];
151 INITIALIZE_ARRAY(frequencies
, size
, 0);
153 /* Translate value so the minimum value is 0
154 and count the number of occurencies of all values to initialize the
156 whole_map_iterate_filtered(ptile
, data
, filter
) {
157 int_map
[tile_index(ptile
)] -= minval
;
158 frequencies
[int_map
[tile_index(ptile
)]]++;
159 } whole_map_iterate_filtered_end
;
161 /* create the linearize function as "incremental" frequencies */
162 for(i
= 0; i
< size
; i
++) {
163 count
+= frequencies
[i
];
164 frequencies
[i
] = (count
* int_map_max
) / total
;
167 /* apply the linearize function */
168 whole_map_iterate_filtered(ptile
, data
, filter
) {
169 int_map
[tile_index(ptile
)] = frequencies
[int_map
[tile_index(ptile
)]];
170 } whole_map_iterate_filtered_end
;
174 /****************************************************************************
175 Is given native position normal position
176 ****************************************************************************/
177 bool is_normal_nat_pos(int x
, int y
)
179 NATIVE_TO_MAP_POS(&x
, &y
, x
, y
);
180 return is_normal_map_pos(x
, y
);
183 /*******************************************************************************
184 Apply a Gaussian diffusion filter on the map. The size of the map is
185 MAP_INDEX_SIZE and the map is indexed by native_pos_to_index function.
186 If zeroes_at_edges is set, any unreal position on diffusion has 0 value
187 if zeroes_at_edges in unset the unreal position are not counted.
188 *******************************************************************************/
189 void smooth_int_map(int *int_map
, bool zeroes_at_edges
)
191 static const float weight_standard
[5] = { 0.13, 0.19, 0.37, 0.19, 0.13 };
192 static const float weight_isometric
[5] = { 0.15, 0.21, 0.29, 0.21, 0.15 };
195 int *target_map
, *source_map
;
196 int *alt_int_map
= fc_calloc(MAP_INDEX_SIZE
, sizeof(*alt_int_map
));
198 fc_assert_ret(NULL
!= int_map
);
200 weight
= weight_standard
;
201 target_map
= alt_int_map
;
202 source_map
= int_map
;
205 whole_map_iterate(ptile
) {
208 axis_iterate(ptile
, pnear
, i
, 2, axe
) {
210 N
+= weight
[i
+ 2] * source_map
[tile_index(pnear
)];
212 if (zeroes_at_edges
) {
215 target_map
[tile_index(ptile
)] = (float)N
/ D
;
216 } whole_map_iterate_end
;
218 if (MAP_IS_ISOMETRIC
) {
219 weight
= weight_isometric
;
224 source_map
= alt_int_map
;
225 target_map
= int_map
;
229 FC_FREE(alt_int_map
);
232 /* These arrays are indexed by continent number (or negative of the
233 * ocean number) so the 0th element is unused and the array is 1 element
234 * larger than you'd expect.
236 * The lake surrounders array tells how many land continents surround each
237 * ocean (or -1 if the ocean touches more than one continent).
239 * The _sizes arrays give the sizes (in tiles) of each continent and
242 static Continent_id
*lake_surrounders
= NULL
;
243 static int *continent_sizes
= NULL
;
244 static int *ocean_sizes
= NULL
;
246 /**************************************************************************
247 Calculate lake_surrounders[] array
248 **************************************************************************/
249 static void recalculate_lake_surrounders(void)
251 const size_t size
= (game
.map
.num_oceans
+ 1) * sizeof(*lake_surrounders
);
253 lake_surrounders
= fc_realloc(lake_surrounders
, size
);
254 memset(lake_surrounders
, 0, size
);
256 whole_map_iterate(ptile
) {
257 const struct terrain
*pterrain
= tile_terrain(ptile
);
258 Continent_id cont
= tile_continent(ptile
);
260 if (T_UNKNOWN
== pterrain
) {
264 if (terrain_type_terrain_class(pterrain
) != TC_OCEAN
) {
265 adjc_iterate(ptile
, tile2
) {
266 Continent_id cont2
= tile_continent(tile2
);
267 if (is_ocean_tile(tile2
)) {
268 if (lake_surrounders
[-cont2
] == 0) {
269 lake_surrounders
[-cont2
] = cont
;
270 } else if (lake_surrounders
[-cont2
] != cont
) {
271 lake_surrounders
[-cont2
] = -1;
276 } whole_map_iterate_end
;
279 /*******************************************************************************
280 Number this tile and nearby tiles with the specified continent number 'nr'.
281 Due to the number of recursion for large maps a non-recursive algorithm is
284 is_land tells us whether we are assigning continent numbers or ocean
286 *******************************************************************************/
287 static void assign_continent_flood(struct tile
*ptile
, bool is_land
, int nr
)
289 struct tile_list
*tlist
= NULL
;
290 const struct terrain
*pterrain
= NULL
;
292 fc_assert_ret(ptile
!= NULL
);
294 pterrain
= tile_terrain(ptile
);
295 /* Check if the initial tile is a valid tile for continent / ocean. */
296 fc_assert_ret(tile_continent(ptile
) == 0
297 && T_UNKNOWN
!= pterrain
298 && XOR(is_land
, terrain_type_terrain_class(pterrain
) == TC_OCEAN
));
300 /* Create tile list and insert the initial tile. */
301 tlist
= tile_list_new();
302 tile_list_append(tlist
, ptile
);
304 while (tile_list_size(tlist
) > 0) {
305 /* Iterate over all unchecked tiles. */
306 tile_list_iterate(tlist
, ptile2
) {
307 /* Iterate over the adjacent tiles. */
308 adjc_iterate(ptile2
, ptile3
) {
309 pterrain
= tile_terrain(ptile3
);
311 /* Check if it is a valid tile for continent / ocean. */
312 if (tile_continent(ptile3
) != 0
313 || T_UNKNOWN
== pterrain
314 || !XOR(is_land
, terrain_type_terrain_class(pterrain
) == TC_OCEAN
)) {
318 /* Add the tile to the list of tiles to check. */
319 if (!tile_list_search(tlist
, ptile3
)) {
320 tile_list_append(tlist
, ptile3
);
324 /* Set the continent data and remove the tile from the list. */
325 tile_set_continent(ptile2
, nr
);
326 tile_list_remove(tlist
, ptile2
);
331 continent_sizes
[nr
]++;
333 } tile_list_iterate_end
;
336 tile_list_destroy(tlist
);
339 /**************************************************************************
340 Regenerate all oceanic tiles for small water bodies as lakes.
341 Assumes assign_continent_numbers() and recalculate_lake_surrounders()
342 have already been done!
343 FIXME: insufficiently generalized, use terrain property.
344 **************************************************************************/
345 void regenerate_lakes(void)
347 struct terrain
*lake_for_ocean
[2][game
.map
.num_oceans
];
350 struct terrain
*lakes
[2][5];
351 int num_laketypes
[2] = { 0, 0 };
354 terrain_type_iterate(pterr
) {
355 if (terrain_has_flag(pterr
, TER_FRESHWATER
)
356 && !terrain_has_flag(pterr
, TER_NOT_GENERATED
)) {
357 int frozen
= terrain_has_flag(pterr
, TER_FROZEN
);
359 if (num_laketypes
[frozen
] < ARRAY_SIZE(lakes
[frozen
])) {
360 lakes
[frozen
][num_laketypes
[frozen
]++] = pterr
;
362 log_verbose("Ruleset has more than %d %s lake types, ignoring %s",
363 (int) ARRAY_SIZE(lakes
[frozen
]),
364 frozen
? "frozen" : "unfrozen",
365 terrain_rule_name(pterr
));
368 } terrain_type_iterate_end
;
370 /* We don't want to generate any boundaries between fresh and
372 * If there are no unfrozen lake types, just give up.
373 * Else if there are no frozen lake types, use unfrozen lake instead.
374 * If both are available, preserve frozenness of previous terrain. */
375 if (num_laketypes
[0] == 0) {
377 } else if (num_laketypes
[1] == 0) {
378 for (i
= 0; i
< game
.map
.num_oceans
; i
++) {
379 lake_for_ocean
[0][i
] = lake_for_ocean
[1][i
]
380 = lakes
[0][fc_rand(num_laketypes
[0])];
383 for (i
= 0; i
< game
.map
.num_oceans
; i
++) {
385 for (frozen
= 0; frozen
< 2; frozen
++) {
386 lake_for_ocean
[frozen
][i
]
387 = lakes
[frozen
][fc_rand(num_laketypes
[frozen
])];
393 whole_map_iterate(ptile
) {
394 struct terrain
*pterrain
= tile_terrain(ptile
);
395 Continent_id here
= tile_continent(ptile
);
397 if (T_UNKNOWN
== pterrain
) {
400 if (terrain_type_terrain_class(pterrain
) != TC_OCEAN
) {
403 if (0 < lake_surrounders
[-here
]) {
404 if (terrain_control
.lake_max_size
>= ocean_sizes
[-here
]) {
405 int frozen
= terrain_has_flag(pterrain
, TER_FROZEN
);
406 tile_change_terrain(ptile
, lake_for_ocean
[frozen
][-here
-1]);
409 } whole_map_iterate_end
;
412 /**************************************************************************
413 Get continent surrounding lake, or -1 if there is multiple continents.
414 **************************************************************************/
415 int get_lake_surrounders(Continent_id cont
)
417 return lake_surrounders
[-cont
];
420 /*************************************************************************
421 Return size in tiles of the given continent(not ocean)
422 *************************************************************************/
423 int get_continent_size(Continent_id id
)
425 fc_assert_ret_val(id
> 0, -1);
426 return continent_sizes
[id
];
429 /*************************************************************************
430 Return size in tiles of the given ocean. You should use positive ocean
432 *************************************************************************/
433 int get_ocean_size(Continent_id id
)
435 fc_assert_ret_val(id
> 0, -1);
436 return ocean_sizes
[id
];
439 /**************************************************************************
440 Assigns continent and ocean numbers to all tiles, and set
441 map.num_continents and map.num_oceans. Recalculates continent and
442 ocean sizes, and lake_surrounders[] arrays.
444 Continents have numbers 1 to map.num_continents _inclusive_.
445 Oceans have (negative) numbers -1 to -map.num_oceans _inclusive_.
446 **************************************************************************/
447 void assign_continent_numbers(void)
450 game
.map
.num_continents
= 0;
451 game
.map
.num_oceans
= 0;
453 whole_map_iterate(ptile
) {
454 tile_set_continent(ptile
, 0);
455 } whole_map_iterate_end
;
457 /* Assign new numbers */
458 whole_map_iterate(ptile
) {
459 const struct terrain
*pterrain
= tile_terrain(ptile
);
461 if (tile_continent(ptile
) != 0) {
462 /* Already assigned. */
466 if (T_UNKNOWN
== pterrain
) {
467 continue; /* Can't assign this. */
470 if (terrain_type_terrain_class(pterrain
) != TC_OCEAN
) {
471 game
.map
.num_continents
++;
472 continent_sizes
= fc_realloc(continent_sizes
,
473 (game
.map
.num_continents
+ 1) * sizeof(*continent_sizes
));
474 continent_sizes
[game
.map
.num_continents
] = 0;
475 assign_continent_flood(ptile
, TRUE
, game
.map
.num_continents
);
477 game
.map
.num_oceans
++;
478 ocean_sizes
= fc_realloc(ocean_sizes
,
479 (game
.map
.num_oceans
+ 1) * sizeof(*ocean_sizes
));
480 ocean_sizes
[game
.map
.num_oceans
] = 0;
481 assign_continent_flood(ptile
, FALSE
, -game
.map
.num_oceans
);
483 } whole_map_iterate_end
;
485 recalculate_lake_surrounders();
487 log_verbose("Map has %d continents and %d oceans",
488 game
.map
.num_continents
, game
.map
.num_oceans
);
491 /**************************************************************************
492 Return most shallow ocean terrain type. Prefers not to return freshwater
493 terrain, and will ignore 'frozen' rather than do so.
494 **************************************************************************/
495 struct terrain
*most_shallow_ocean(bool frozen
)
497 bool oceans
= FALSE
, frozenmatch
= FALSE
;
498 struct terrain
*shallow
= NULL
;
500 terrain_type_iterate(pterr
) {
501 if (is_ocean(pterr
) && !terrain_has_flag(pterr
, TER_NOT_GENERATED
)) {
502 bool nonfresh
= !terrain_has_flag(pterr
, TER_FRESHWATER
);
503 bool frozen_ok
= terrain_has_flag(pterr
, TER_FROZEN
) == frozen
;
505 if (!oceans
&& nonfresh
) {
506 /* First ocean type seen, reset even if frozenness doesn't match */
509 frozenmatch
= frozen_ok
;
511 } else if (oceans
&& !nonfresh
) {
512 /* Dismiss any step backward on freshness */
515 if (!frozenmatch
&& frozen_ok
) {
516 /* Prefer terrain that matches frozenness (as long as we don't go
517 * backwards on freshness) */
521 } else if (frozenmatch
&& !frozen_ok
) {
522 /* Dismiss any step backward on frozenness */
526 || pterr
->property
[MG_OCEAN_DEPTH
] <
527 shallow
->property
[MG_OCEAN_DEPTH
]) {
531 } terrain_type_iterate_end
;
536 /**************************************************************************
537 Picks an ocean terrain to match the given depth.
538 Only considers terrains with/without Frozen flag depending on 'frozen'.
539 Return NULL when there is no available ocean.
540 **************************************************************************/
541 struct terrain
*pick_ocean(int depth
, bool frozen
)
543 struct terrain
*best_terrain
= NULL
;
544 int best_match
= TERRAIN_OCEAN_DEPTH_MAXIMUM
;
546 terrain_type_iterate(pterrain
) {
547 if (terrain_type_terrain_class(pterrain
) == TC_OCEAN
548 && TERRAIN_OCEAN_DEPTH_MINIMUM
<= pterrain
->property
[MG_OCEAN_DEPTH
]
549 && !!frozen
== terrain_has_flag(pterrain
, TER_FROZEN
)
550 && !terrain_has_flag(pterrain
, TER_NOT_GENERATED
)) {
551 int match
= abs(depth
- pterrain
->property
[MG_OCEAN_DEPTH
]);
553 if (best_match
> match
) {
555 best_terrain
= pterrain
;
558 } terrain_type_iterate_end
;
563 /**************************************************************************
564 Determines the minimal distance to the land.
565 **************************************************************************/
566 static int real_distance_to_land(const struct tile
*ptile
, int max
)
568 square_dxy_iterate(ptile
, max
, atile
, dx
, dy
) {
569 if (terrain_type_terrain_class(tile_terrain(atile
)) != TC_OCEAN
) {
570 return map_vector_to_real_distance(dx
, dy
);
572 } square_dxy_iterate_end
;
576 /**************************************************************************
577 Determines what is the most popular ocean type arround (need 2/3 of the
579 **************************************************************************/
580 static struct terrain
*most_adjacent_ocean_type(const struct tile
*ptile
)
582 const int need
= 2 * game
.map
.num_valid_dirs
/ 3;
585 terrain_type_iterate(pterrain
) {
586 if (terrain_type_terrain_class(pterrain
) != TC_OCEAN
) {
591 adjc_iterate(ptile
, atile
) {
592 if (pterrain
== tile_terrain(atile
) && need
<= ++count
) {
596 } terrain_type_iterate_end
;
600 /**************************************************************************
601 Makes a simple depth map for all ocean tiles based on their proximity
602 to any land tiles and reassignes ocean terrain types based on their
603 MG_OCEAN_DEPTH property values.
604 **************************************************************************/
605 void smooth_water_depth(void)
607 const int OCEAN_DEPTH_STEP
= 25;
608 const int OCEAN_DEPTH_RAND
= 15;
609 const int OCEAN_DIST_MAX
= TERRAIN_OCEAN_DEPTH_MAXIMUM
/ OCEAN_DEPTH_STEP
;
610 struct terrain
*ocean
;
613 /* First, improve the coasts. */
614 whole_map_iterate(ptile
) {
615 if (terrain_type_terrain_class(tile_terrain(ptile
)) != TC_OCEAN
) {
619 dist
= real_distance_to_land(ptile
, OCEAN_DIST_MAX
);
620 if (dist
<= OCEAN_DIST_MAX
) {
621 /* Overwrite the terrain (but preserve frozenness). */
622 ocean
= pick_ocean(dist
* OCEAN_DEPTH_STEP
623 + fc_rand(OCEAN_DEPTH_RAND
),
624 terrain_has_flag(tile_terrain(ptile
), TER_FROZEN
));
625 if (NULL
!= ocean
&& ocean
!= tile_terrain(ptile
)) {
626 log_debug("Replacing %s by %s at (%d, %d) "
627 "to have shallow ocean on coast.",
628 terrain_rule_name(tile_terrain(ptile
)),
629 terrain_rule_name(ocean
), TILE_XY(ptile
));
630 tile_set_terrain(ptile
, ocean
);
633 } whole_map_iterate_end
;
635 /* Now, try to have something more continuous. */
636 whole_map_iterate(ptile
) {
637 if (terrain_type_terrain_class(tile_terrain(ptile
)) != TC_OCEAN
) {
641 ocean
= most_adjacent_ocean_type(ptile
);
642 if (NULL
!= ocean
&& ocean
!= tile_terrain(ptile
)) {
643 log_debug("Replacing %s by %s at (%d, %d) "
644 "to smooth the ocean types.",
645 terrain_rule_name(tile_terrain(ptile
)),
646 terrain_rule_name(ocean
), TILE_XY(ptile
));
647 tile_set_terrain(ptile
, ocean
);
649 } whole_map_iterate_end
;
652 /**************************************************************************
653 Free resources allocated by the generator.
654 **************************************************************************/
655 void generator_free(void)
657 if (lake_surrounders
!= NULL
) {
658 free(lake_surrounders
);
659 lake_surrounders
= NULL
;
661 if (continent_sizes
!= NULL
) {
662 free(continent_sizes
);
663 continent_sizes
= NULL
;
665 if (ocean_sizes
!= NULL
) {
671 /****************************************************************************
672 Return a random terrain that has the specified flag.
673 Returns T_UNKNOWN when there is no matching terrain.
674 ****************************************************************************/
675 struct terrain
*pick_terrain_by_flag(enum terrain_flag_id flag
)
677 bool has_flag
[terrain_count()];
680 terrain_type_iterate(pterrain
) {
681 if ((has_flag
[terrain_index(pterrain
)]
682 = (terrain_has_flag(pterrain
, flag
)
683 && !terrain_has_flag(pterrain
, TER_NOT_GENERATED
)))) {
686 } terrain_type_iterate_end
;
688 count
= fc_rand(count
);
689 terrain_type_iterate(pterrain
) {
690 if (has_flag
[terrain_index(pterrain
)]) {
696 } terrain_type_iterate_end
;
702 /****************************************************************************
703 Pick a terrain based on the target property and a property to avoid.
705 If the target property is given, then all terrains with that property
706 will be considered and one will be picked at random based on the amount
707 of the property each terrain has. If no target property is given all
708 terrains will be assigned equal likelihood.
710 If the preferred property is given, only terrains with (some of) that
711 property will be chosen.
713 If the avoid property is given, then any terrain with (any of) that
714 property will be avoided.
716 This function must always return a valid terrain.
717 ****************************************************************************/
718 struct terrain
*pick_terrain(enum mapgen_terrain_property target
,
719 enum mapgen_terrain_property prefer
,
720 enum mapgen_terrain_property avoid
)
724 /* Find the total weight. */
725 terrain_type_iterate(pterrain
) {
726 if (!terrain_has_flag(pterrain
, TER_NOT_GENERATED
)) {
727 if (avoid
!= MG_UNUSED
&& pterrain
->property
[avoid
] > 0) {
730 if (prefer
!= MG_UNUSED
&& pterrain
->property
[prefer
] == 0) {
734 if (target
!= MG_UNUSED
) {
735 sum
+= pterrain
->property
[target
];
740 } terrain_type_iterate_end
;
745 /* Finally figure out which one we picked. */
746 terrain_type_iterate(pterrain
) {
747 if (!terrain_has_flag(pterrain
, TER_NOT_GENERATED
)) {
750 if (avoid
!= MG_UNUSED
&& pterrain
->property
[avoid
] > 0) {
753 if (prefer
!= MG_UNUSED
&& pterrain
->property
[prefer
] == 0) {
757 if (target
!= MG_UNUSED
) {
758 property
= pterrain
->property
[target
];
762 if (sum
< property
) {
767 } terrain_type_iterate_end
;
769 /* This can happen with sufficient quantities of preferred and avoided
770 * characteristics. Drop a requirement and try again. */
771 if (prefer
!= MG_UNUSED
) {
772 log_debug("pick_terrain(target: %s, [dropping prefer: %s], avoid: %s)",
773 mapgen_terrain_property_name(target
),
774 mapgen_terrain_property_name(prefer
),
775 mapgen_terrain_property_name(avoid
));
776 return pick_terrain(target
, MG_UNUSED
, avoid
);
777 } else if (avoid
!= MG_UNUSED
) {
778 log_debug("pick_terrain(target: %s, prefer: %s, [dropping avoid: %s])",
779 mapgen_terrain_property_name(target
),
780 mapgen_terrain_property_name(prefer
),
781 mapgen_terrain_property_name(avoid
));
782 return pick_terrain(target
, prefer
, MG_UNUSED
);
784 log_debug("pick_terrain([dropping target: %s], prefer: %s, avoid: %s)",
785 mapgen_terrain_property_name(target
),
786 mapgen_terrain_property_name(prefer
),
787 mapgen_terrain_property_name(avoid
));
788 return pick_terrain(MG_UNUSED
, prefer
, avoid
);