Freeciv-3.2
Loading...
Searching...
No Matches
startpos.c
Go to the documentation of this file.
1/***********************************************************************
2 Freeciv - Copyright (C) 1996 - 2004 The Freeciv Project Team
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)
6 any later version.
7
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***********************************************************************/
13
14#ifdef HAVE_CONFIG_H
15#include <fc_config.h>
16#endif
17
18#include <math.h> /* sqrt, HUGE_VAL */
19
20/* utility */
21#include "log.h"
22#include "fcintl.h"
23
24/* common */
25#include "game.h"
26#include "map.h"
27#include "movement.h"
28
29/* server */
30#include "maphand.h"
31
32/* server/generator */
33#include "mapgen_topology.h"
34#include "mapgen_utils.h"
35#include "startpos.h"
36#include "temperature_map.h"
37
46static int *islands_index;
47
48/************************************************************************/
51static int get_tile_value(struct tile *ptile)
52{
53 int value;
54 int irrig_bonus = 0;
55 int mine_bonus = 0;
56 struct tile *roaded;
57 struct extra_type *nextra;
58
59 /* Give one point for each food / shield / trade produced. */
60 value = 0;
62 value += city_tile_output(NULL, ptile, FALSE, o);
64
65 roaded = tile_virtual_new(ptile);
66
67 if (num_role_units(L_SETTLERS) > 0) {
68 const struct req_context start_worker_ctxt = {
69 .tile = roaded,
70 .unittype = get_role_unit(L_SETTLERS, 0),
71 };
72
74 struct road_type *proad = extra_road_get(pextra);
75
78 &pextra->reqs, RPT_CERTAIN)) {
79 tile_add_extra(roaded, pextra);
80 }
82 }
83
85
86 if (nextra != NULL) {
87 struct tile *vtile;
88
91 irrig_bonus = -value;
96 }
97
99
100 /* Same set of roads used with mine as with irrigation. */
101 if (nextra != NULL) {
102 struct tile *vtile;
103
106 mine_bonus = -value;
111 }
112
114
115 value += MAX(0, MAX(mine_bonus, irrig_bonus)) / 2;
116
117 return value;
118}
119
125
126/************************************************************************/
130static bool check_native_area(const struct unit_type *utype,
131 const struct tile *ptile,
132 int min_area)
133{
134 int tiles = 1; /* There's the central tile already. */
135 struct tile_list *tlist = tile_list_new();
136 struct tile *central = tile_virtual_new(ptile); /* Non-const virtual tile */
137 struct dbv handled;
138
140
141 tile_list_append(tlist, central);
142
143 while (tile_list_size(tlist) > 0 && tiles < min_area) {
146 int idx = tile_index(ptile3);
147
148 if (!dbv_isset(&handled, idx) && is_native_tile(utype, ptile3)) {
149 tiles++;
151 dbv_set(&handled, idx);
152 if (tiles >= min_area) {
153 /* Break out when we already know that area is sufficient. */
154 break;
155 }
156 }
158
160
161 if (tiles >= min_area) {
162 /* Break out when we already know that area is sufficient. */
163 break;
164 }
166 }
167
169
171
172 tile_virtual_destroy(central);
173
174 return tiles >= min_area;
175}
176
177/************************************************************************/
187static bool is_valid_start_pos(const struct tile *ptile, const void *dataptr)
188{
189 const struct start_filter_data *pdata = dataptr;
191 int cont_size, cont = tile_continent(ptile);
192
193 /* Only start on certain terrain types. */
194 if (pdata->value[tile_index(ptile)] < pdata->min_value) {
195 return FALSE;
196 }
197
198 fc_assert_ret_val(cont > 0, FALSE);
199 if (islands[islands_index[cont]].starters == 0) {
200 return FALSE;
201 }
202
203 /* Don't start on a hut. */
204 /* FIXME: Could be ok for unit not entering or frightening hut */
205 if (hut_on_tile(ptile)) {
206 return FALSE;
207 }
208
209 /* Has to be native tile for initial unit */
210 if (!is_native_tile(pdata->initial_unit, ptile)) {
211 return FALSE;
212 }
213
214 /* Check native area size. */
215 if (!check_native_area(pdata->initial_unit, ptile,
216 terrain_control.min_start_native_area)) {
217 return FALSE;
218 }
219
221 return FALSE;
222 }
223
224 /* A longstanding bug allowed starting positions to exist on poles,
225 * sometimes. This hack prevents it by setting a fixed distance from
226 * the pole (dependent on map temperature) that a start pos must be.
227 * Cold and frozen tiles are not allowed for start pos placement. */
228 if (tmap_is(ptile, TT_NHOT)) {
229 return FALSE;
230 }
231
232 /* Don't start too close to someone else. */
234 island = islands + islands_index[cont];
236 struct tile *tile1 = startpos_tile(psp);
237
238 if ((tile_continent(ptile) == tile_continent(tile1)
239 && (real_map_distance(ptile, tile1) * 1000 / pdata->min_value
240 <= (sqrt(cont_size / island->total))))
241 || (real_map_distance(ptile, tile1) * 1000 / pdata->min_value < 5)) {
242 return FALSE;
243 }
245
246 return TRUE;
247}
248
249/************************************************************************/
252static int compare_islands(const void *A_, const void *B_)
253{
254 const struct islands_data_type *A = A_, *B = B_;
255
256 return B->goodies - A->goodies;
257}
258
259/************************************************************************/
262static void initialize_isle_data(void)
263{
264 int nr;
265
266 islands = fc_malloc((wld.map.num_continents + 1) * sizeof(*islands));
268 * sizeof(*islands_index));
269
270 /* islands[0] is unused. */
271 for (nr = 1; nr <= wld.map.num_continents; nr++) {
272 islands[nr].id = nr;
274 islands[nr].goodies = 0;
275 islands[nr].starters = 0;
276 islands[nr].total = 0;
277 }
278}
279
280/************************************************************************/
283static bool filter_starters(const struct tile *ptile, const void *data)
284{
286}
287
288/************************************************************************/
301 struct unit_type *initial_unit)
302{
303 struct tile *ptile;
304 int k, sum;
305 struct start_filter_data data;
306 int *tile_value_aux = NULL;
307 int *tile_value = NULL;
308 int min_goodies_per_player = 1500;
309 int total_goodies = 0;
310 /* This is factor is used to maximize land used in extreme little maps */
311 float efactor = player_count() / map_size_checked() / 4;
312 bool failure = FALSE;
314 const struct civ_map *nmap = &(wld.map);
315
316 if (wld.map.num_continents < 1) {
317 /* Currently we can only place starters on land terrain, so fail
318 * immediately if there isn't any on the map. */
319 log_verbose("Map has no land, so cannot assign start positions!");
320 return FALSE;
321 }
322
323 if (!is_tmap) {
324 /* The temperature map has already been destroyed by the time start
325 * positions have been placed. We check for this and then create a
326 * false temperature map. This is used in the tmap_is() call above.
327 * We don't create a "real" map here because that requires the height
328 * map and other information which has already been destroyed. */
330 }
331
332 /* If the default is given, just use MAPSTARTPOS_VARIABLE. */
333 if (MAPSTARTPOS_DEFAULT == mode) {
334 log_verbose("Using startpos=VARIABLE");
336 }
337
340
341 /* Get the tile value */
345
346 /* Select the best tiles */
349 int lcount = 0, bcount = 0;
350
351 /* Check all tiles within the default city radius */
354 lcount++;
356 bcount++;
357 }
359
360 if (lcount <= bcount) {
361 this_tile_value = 0;
362 }
365 /* Get an average value */
367
369
370 /* Only consider tiles marked as 'starter terrains' by ruleset */
374 } else {
375 /* Oceanic terrain cannot be starter terrain currently */
379 }
381
382 /* evaluate the best places on the map */
384
385 /* Sort the islands so the best ones come first. Note that islands[0] is
386 * unused so we just skip it. */
388 sizeof(*islands), compare_islands);
389
390 /* If we can't place starters according to the first choice, change the
391 * choice. */
392 if (MAPSTARTPOS_SINGLE == mode
393 && wld.map.num_continents < player_count() + 3) {
394 log_verbose("Not enough continents; falling back to startpos=2or3");
395 mode = MAPSTARTPOS_2or3;
396 }
397
398 if (MAPSTARTPOS_2or3 == mode
399 && wld.map.num_continents < player_count() / 2 + 4) {
400 log_verbose("Not enough continents; falling back to startpos=VARIABLE");
402 }
403
404 if (MAPSTARTPOS_ALL == mode
405 && (islands[1].goodies < player_count() * min_goodies_per_player
406 || islands[1].goodies < total_goodies * (0.5 + 0.8 * efactor)
407 / (1 + efactor))) {
408 log_verbose("No good enough island; falling back to startpos=VARIABLE");
410 }
411
412 /* the variable way is the last possibility */
413 if (MAPSTARTPOS_VARIABLE == mode) {
415 / (1 + efactor) / player_count();
416 }
417
418 {
419 int nr, to_place = player_count(), first = 1;
420
421 /* inizialize islands_index */
422 for (nr = 1; nr <= wld.map.num_continents; nr++) {
424 }
425
426 /* When placing a fixed number of players per island, for fairness, try
427 * to avoid sets of populated islands where there is more than 10%
428 * variation in "goodness" within the entire set. (Fallback if that fails:
429 * place players on the worst available islands.) */
430 if (MAPSTARTPOS_SINGLE == mode || MAPSTARTPOS_2or3 == mode) {
431 float var_goodies, best = HUGE_VAL;
432 int num_islands = (MAPSTARTPOS_SINGLE == mode
433 ? player_count() : player_count() / 2);
434
435 for (nr = 1; nr <= 1 + wld.map.num_continents - num_islands; nr++) {
436 if (islands[nr + num_islands - 1].goodies < min_goodies_per_player) {
437 break;
438 }
441 / (islands[nr + num_islands - 1].goodies);
442
443 if (var_goodies < best * 0.9) {
444 best = var_goodies;
445 first = nr;
446 }
447 }
448 }
449
450 /* set starters per isle */
451 if (MAPSTARTPOS_ALL == mode) {
454 to_place = 0;
455 }
456 for (nr = 1; nr <= wld.map.num_continents; nr++) {
457 if (MAPSTARTPOS_SINGLE == mode && 0 < to_place && nr >= first) {
458 islands[nr].starters = 1;
459 islands[nr].total = 1;
460 to_place--;
461 }
462 if (MAPSTARTPOS_2or3 == mode && 0 < to_place && nr >= first) {
463 islands[nr].starters = 2 + (nr == 1 ? (player_count() % 2) : 0);
465 }
466
467 if (MAPSTARTPOS_VARIABLE == mode && 0 < to_place) {
468 islands[nr].starters = MAX(1, islands[nr].goodies
471 }
472 }
473 }
474
475 data.value = tile_value;
476 data.min_value = 900;
477 data.initial_unit = initial_unit;
478 sum = 0;
479 for (k = 1; k <= wld.map.num_continents; k++) {
480 sum += islands[islands_index[k]].starters;
481 if (islands[islands_index[k]].starters != 0) {
482 log_verbose("starters on isle %i", k);
483 }
484 }
486
487 /* now search for the best place and set start_positions */
488 while (map_startpos_count() < player_count()) {
489 if ((ptile = rand_map_pos_filtered(&(wld.map), &data,
492 log_debug("Adding (%d, %d) as starting position %d, %d goodies on "
493 "islands.", TILE_XY(ptile), map_startpos_count(),
494 islands[islands_index[(int) tile_continent(ptile)]].goodies);
495 (void) map_startpos_new(ptile);
496 } else {
497 data.min_value *= 0.95;
498 if (data.min_value <= 10) {
499 log_normal(_("The server appears to have gotten into an infinite "
500 "loop in the allocation of starting positions.\nMaybe "
501 "the number of players is too high for this map."));
502 failure = TRUE;
503 break;
504 }
505 }
506 }
507
508 free(islands);
510 islands = NULL;
512
513 if (!is_tmap) {
514 destroy_tmap();
515 }
516
519
520 return !failure;
521}
void dbv_init(struct dbv *pdbv, int bits)
Definition bitvector.c:50
void dbv_set(struct dbv *pdbv, int bit)
Definition bitvector.c:144
bool dbv_isset(const struct dbv *pdbv, int bit)
Definition bitvector.c:120
void dbv_free(struct dbv *pdbv)
Definition bitvector.c:95
int city_tile_output(const struct city *pcity, const struct tile *ptile, bool is_celebrating, Output_type_id otype)
Definition city.c:1283
#define output_type_iterate(output)
Definition city.h:845
#define city_tile_iterate(_nmap, _radius_sq, _city_tile, _tile)
Definition city.h:230
#define CITY_MAP_DEFAULT_RADIUS_SQ
Definition city.h:82
#define city_tile_iterate_end
Definition city.h:238
#define output_type_iterate_end
Definition city.h:851
char * incite_cost
Definition comments.c:75
struct extra_type * next_extra_for_tile(const struct tile *ptile, enum extra_cause cause, const struct player *pplayer, const struct unit *punit)
Definition extras.c:765
bool hut_on_tile(const struct tile *ptile)
Definition extras.c:697
#define extra_road_get(_e_)
Definition extras.h:191
#define extra_type_by_cause_iterate_end
Definition extras.h:339
#define extra_type_by_cause_iterate(_cause, _extra)
Definition extras.h:333
@ RPT_CERTAIN
Definition fc_types.h:701
signed short Continent_id
Definition fc_types.h:372
#define _(String)
Definition fcintl.h:67
struct civ_game game
Definition game.c:62
struct world wld
Definition game.c:63
#define log_verbose(message,...)
Definition log.h:109
#define fc_assert_ret_val(condition, val)
Definition log.h:194
#define fc_assert_action(condition, action)
Definition log.h:187
#define log_debug(message,...)
Definition log.h:115
#define log_normal(message,...)
Definition log.h:107
struct startpos * map_startpos_new(struct tile *ptile)
Definition map.c:1866
struct tile * startpos_tile(const struct startpos *psp)
Definition map.c:1676
struct tile * rand_map_pos_filtered(const struct civ_map *nmap, void *data, bool(*filter)(const struct tile *ptile, const void *data))
Definition map.c:1101
int map_startpos_count(void)
Definition map.c:1853
int real_map_distance(const struct tile *tile0, const struct tile *tile1)
Definition map.c:630
struct terrain_misc terrain_control
Definition map.c:69
#define map_startpos_iterate(NAME_psp)
Definition map.h:130
#define adjc_iterate_end
Definition map.h:433
#define MAP_INDEX_SIZE
Definition map.h:137
#define adjc_iterate(nmap, center_tile, itr_tile)
Definition map.h:428
#define map_startpos_iterate_end
Definition map.h:133
#define whole_map_iterate(_map, _tile)
Definition map.h:545
#define map_size_checked()
Definition map.h:271
#define whole_map_iterate_end
Definition map.h:554
map_startpos
Definition map_types.h:55
@ MAPSTARTPOS_VARIABLE
Definition map_types.h:60
@ MAPSTARTPOS_2or3
Definition map_types.h:58
@ MAPSTARTPOS_ALL
Definition map_types.h:59
@ MAPSTARTPOS_DEFAULT
Definition map_types.h:56
@ MAPSTARTPOS_SINGLE
Definition map_types.h:57
int get_continent_size(Continent_id id)
void smooth_int_map(int *int_map, bool zeroes_at_edges)
void adjust_int_map_filtered(int *int_map, int int_map_min, int int_map_max, void *data, bool(*filter)(const struct tile *ptile, const void *data))
#define fc_calloc(n, esz)
Definition mem.h:38
#define FC_FREE(ptr)
Definition mem.h:41
#define fc_malloc(sz)
Definition mem.h:34
bool is_native_tile(const struct unit_type *punittype, const struct tile *ptile)
Definition movement.c:331
int player_count(void)
Definition player.c:817
bool are_reqs_active(const struct req_context *context, const struct player *other_player, const struct requirement_vector *reqs, const enum req_problem_type prob_type)
bool road_can_be_built(const struct road_type *proad, const struct tile *ptile)
Definition road.c:200
#define MAX(x, y)
Definition shared.h:54
static int compare_islands(const void *A_, const void *B_)
Definition startpos.c:252
bool create_start_positions(enum map_startpos mode, struct unit_type *initial_unit)
Definition startpos.c:300
static bool filter_starters(const struct tile *ptile, const void *data)
Definition startpos.c:283
static void initialize_isle_data(void)
Definition startpos.c:262
static int * islands_index
Definition startpos.c:46
static struct islands_data_type * islands
Definition startpos.c:45
static int get_tile_value(struct tile *ptile)
Definition startpos.c:51
static bool check_native_area(const struct unit_type *utype, const struct tile *ptile, int min_area)
Definition startpos.c:130
static bool is_valid_start_pos(const struct tile *ptile, const void *dataptr)
Definition startpos.c:187
struct civ_game::@31::@35 server
bool start_city
Definition game.h:194
Continent_id num_continents
Definition map_types.h:81
Continent_id id
Definition startpos.c:39
const struct tile * tile
struct unit_type * initial_unit
Definition startpos.c:122
Definition tile.h:50
struct civ_map map
#define TRUE
Definition support.h:46
#define FALSE
Definition support.h:47
bool temperature_is_initialized(void)
void destroy_tmap(void)
bool tmap_is(const struct tile *ptile, temperature_type tt)
void create_tmap(bool real)
#define TT_NHOT
#define terrain_has_flag(terr, flag)
Definition terrain.h:283
void tile_add_extra(struct tile *ptile, const struct extra_type *pextra)
Definition tile.c:955
void tile_virtual_destroy(struct tile *vtile)
Definition tile.c:1033
bool tile_apply_activity(struct tile *ptile, Activity_type_id act, struct extra_type *tgt)
Definition tile.c:681
struct tile * tile_virtual_new(const struct tile *ptile)
Definition tile.c:981
#define tile_index(_pt_)
Definition tile.h:88
#define tile_list_iterate(tile_list, ptile)
Definition tile.h:73
#define tile_terrain(_tile)
Definition tile.h:110
#define TILE_XY(ptile)
Definition tile.h:43
#define tile_list_iterate_end
Definition tile.h:75
#define tile_continent(_tile)
Definition tile.h:92
struct unit_type * get_role_unit(int role, int role_index)
Definition unittype.c:2253
int num_role_units(int role)
Definition unittype.c:2203