Freeciv21
Develop your civilization from humble roots to a global empire
infracache.cpp
Go to the documentation of this file.
1 /*__ ___ ***************************************
2 / \ / \ Copyright (c) 1996-2020 Freeciv21 and Freeciv
3 \_ \ / __/ contributors. This file is part of Freeciv21.
4  _\ \ / /__ Freeciv21 is free software: you can redistribute it
5  \___ \____/ __/ and/or modify it under the terms of the GNU General
6  \_ _/ Public License as published by the Free Software
7  | @ @ \_ Foundation, either version 3 of the License,
8  | or (at your option) any later version.
9  _/ /\ You should have received a copy of the GNU
10  /o) (o/\ \_ General Public License along with Freeciv21.
11  \_____/ / If not, see https://www.gnu.org/licenses/.
12  \____/ ********************************************************/
13 
14 // common
15 #include "city.h"
16 #include "game.h"
17 #include "map.h"
18 #include "player.h"
19 #include "tile.h"
20 
21 // server
22 #include "maphand.h"
23 
24 /* server/advisors */
25 #include "advbuilding.h"
26 #include "autosettlers.h"
27 
28 #include "infracache.h"
29 
30 // cache activities within the city map
32  int act[ACTIVITY_LAST];
35 };
36 
37 static int adv_calc_irrigate_transform(const struct city *pcity,
38  const struct tile *ptile);
39 static int adv_calc_mine_transform(const struct city *pcity,
40  const struct tile *ptile);
41 static int adv_calc_transform(const struct city *pcity,
42  const struct tile *ptile);
43 static int adv_calc_extra(const struct city *pcity, const struct tile *ptile,
44  const struct extra_type *pextra);
45 static int adv_calc_rmextra(const struct city *pcity,
46  const struct tile *ptile,
47  const struct extra_type *pextra);
48 
57 static int adv_calc_irrigate_transform(const struct city *pcity,
58  const struct tile *ptile)
59 {
60  int goodness;
61  struct terrain *old_terrain, *new_terrain;
62 
63  fc_assert_ret_val(ptile != nullptr, 0);
64 
65  old_terrain = tile_terrain(ptile);
66  new_terrain = old_terrain->irrigation_result;
67 
68  if (new_terrain != old_terrain && new_terrain != T_NONE) {
69  struct tile *vtile;
70 
71  if (tile_city(ptile) && terrain_has_flag(new_terrain, TER_NO_CITIES)) {
72  // Not a valid activity.
73  return -1;
74  }
75  /* Irrigation would change the terrain type, clearing conflicting
76  * extras in the process. Calculate the benefit of doing so. */
77  vtile = tile_virtual_new(ptile);
78 
79  tile_change_terrain(vtile, new_terrain);
80  goodness = city_tile_value(pcity, vtile, 0, 0);
81  tile_virtual_destroy(vtile);
82 
83  return goodness;
84  } else {
85  return -1;
86  }
87 }
88 
97 static int adv_calc_mine_transform(const struct city *pcity,
98  const struct tile *ptile)
99 {
100  int goodness;
101  struct terrain *old_terrain, *new_terrain;
102 
103  fc_assert_ret_val(ptile != nullptr, 0);
104 
105  old_terrain = tile_terrain(ptile);
106  new_terrain = old_terrain->mining_result;
107 
108  if (old_terrain != new_terrain && new_terrain != T_NONE) {
109  struct tile *vtile;
110 
111  if (tile_city(ptile) && terrain_has_flag(new_terrain, TER_NO_CITIES)) {
112  // Not a valid activity.
113  return -1;
114  }
115  /* Mining would change the terrain type, clearing conflicting
116  * extras in the process. Calculate the benefit of doing so. */
117  vtile = tile_virtual_new(ptile);
118 
119  tile_change_terrain(vtile, new_terrain);
120  goodness = city_tile_value(pcity, vtile, 0, 0);
121  tile_virtual_destroy(vtile);
122 
123  return goodness;
124  } else {
125  return -1;
126  }
127 }
128 
137 static int adv_calc_transform(const struct city *pcity,
138  const struct tile *ptile)
139 {
140  int goodness;
141  struct tile *vtile;
142  struct terrain *old_terrain, *new_terrain;
143 
144  fc_assert_ret_val(ptile != nullptr, 0);
145 
146  old_terrain = tile_terrain(ptile);
147  new_terrain = old_terrain->transform_result;
148 
149  if (old_terrain == new_terrain || new_terrain == T_NONE) {
150  return -1;
151  }
152 
153  if (!terrain_surroundings_allow_change(ptile, new_terrain)) {
154  // Can't do this terrain conversion here.
155  return -1;
156  }
157 
158  if (tile_city(ptile) && terrain_has_flag(new_terrain, TER_NO_CITIES)) {
159  return -1;
160  }
161 
162  vtile = tile_virtual_new(ptile);
163  tile_change_terrain(vtile, new_terrain);
164  goodness = city_tile_value(pcity, vtile, 0, 0);
165  tile_virtual_destroy(vtile);
166 
167  return goodness;
168 }
169 
182 static int adv_calc_extra(const struct city *pcity, const struct tile *ptile,
183  const struct extra_type *pextra)
184 {
185  int goodness = -1;
186 
187  fc_assert_ret_val(ptile != nullptr, 0);
188 
189  if (player_can_build_extra(pextra, city_owner(pcity), ptile)) {
190  struct tile *vtile = tile_virtual_new(ptile);
191 
192  tile_add_extra(vtile, pextra);
193 
194  extra_type_iterate(cextra)
195  {
196  if (tile_has_extra(vtile, cextra)
197  && !can_extras_coexist(pextra, cextra)) {
198  tile_remove_extra(vtile, cextra);
199  }
200  }
202 
203  goodness = city_tile_value(pcity, vtile, 0, 0);
204  tile_virtual_destroy(vtile);
205  }
206 
207  return goodness;
208 }
209 
218 static int adv_calc_rmextra(const struct city *pcity,
219  const struct tile *ptile,
220  const struct extra_type *pextra)
221 {
222  int goodness = -1;
223 
224  fc_assert_ret_val(ptile != nullptr, 0);
225 
226  if (player_can_remove_extra(pextra, city_owner(pcity), ptile)) {
227  struct tile *vtile = tile_virtual_new(ptile);
228 
229  tile_remove_extra(vtile, pextra);
230 
231  goodness = city_tile_value(pcity, vtile, 0, 0);
232  tile_virtual_destroy(vtile);
233  }
234 
235  return goodness;
236 }
237 
246 {
247  city_list_iterate(pplayer->cities, pcity)
248  {
249  struct tile *pcenter = city_tile(pcity);
250  int radius_sq = city_map_radius_sq_get(pcity);
251 
252  city_map_iterate(radius_sq, city_index, city_x, city_y)
253  {
255  {
256  adv_city_worker_act_set(pcity, city_index,
257  action_id_get_activity(act), -1);
258  }
260  }
262 
263  city_tile_iterate_index(radius_sq, pcenter, ptile, cindex)
264  {
265  adv_city_worker_act_set(pcity, cindex, ACTIVITY_MINE,
266  adv_calc_mine_transform(pcity, ptile));
267  adv_city_worker_act_set(pcity, cindex, ACTIVITY_IRRIGATE,
268  adv_calc_irrigate_transform(pcity, ptile));
269  adv_city_worker_act_set(pcity, cindex, ACTIVITY_TRANSFORM,
270  adv_calc_transform(pcity, ptile));
271 
272  /* road_bonus() is handled dynamically later; it takes into
273  * account settlers that have already been assigned to building
274  * roads this turn. */
275  extra_type_iterate(pextra)
276  {
277  /* We have no use for extra value, if workers cannot be assigned
278  * to build it, so don't use time to calculate values otherwise */
279  if (pextra->buildable && is_extra_caused_by_worker_action(pextra)) {
280  adv_city_worker_extra_set(pcity, cindex, pextra,
281  adv_calc_extra(pcity, ptile, pextra));
282  } else {
283  adv_city_worker_extra_set(pcity, cindex, pextra, 0);
284  }
285  if (tile_has_extra(ptile, pextra)
288  pcity, cindex, pextra, adv_calc_rmextra(pcity, ptile, pextra));
289  } else {
290  adv_city_worker_rmextra_set(pcity, cindex, pextra, 0);
291  }
292  }
294  }
296  }
298 }
299 
305 int city_tile_value(const struct city *pcity, const struct tile *ptile,
306  int foodneed, int prodneed)
307 {
308  int food = city_tile_output_now(pcity, ptile, O_FOOD);
309  int shield = city_tile_output_now(pcity, ptile, O_SHIELD);
310  int trade = city_tile_output_now(pcity, ptile, O_TRADE);
311  int value = 0;
312 
313  /* Each food, trade, and shield gets a certain weighting. We also benefit
314  * tiles that have at least one of an item - this promotes balance and
315  * also accounts for INC_TILE effects. */
316  value += food * FOOD_WEIGHTING;
317  if (food > 0) {
318  value += FOOD_WEIGHTING / 2;
319  }
320  value += shield * SHIELD_WEIGHTING;
321  if (shield > 0) {
322  value += SHIELD_WEIGHTING / 2;
323  }
324  value += trade * TRADE_WEIGHTING;
325  if (trade > 0) {
326  value += TRADE_WEIGHTING / 2;
327  }
328 
329  return value;
330 }
331 
336 void adv_city_worker_act_set(struct city *pcity, int city_tile_index,
337  enum unit_activity act_id, int value)
338 {
339  if (pcity->server.adv->act_cache_radius_sq
340  != city_map_radius_sq_get(pcity)) {
341  log_debug("update activity cache for %s: radius_sq changed from "
342  "%d to %d",
343  city_name_get(pcity), pcity->server.adv->act_cache_radius_sq,
344  city_map_radius_sq_get(pcity));
345  adv_city_update(pcity);
346  }
347 
348  fc_assert_ret(nullptr != pcity);
349  fc_assert_ret(nullptr != pcity->server.adv);
350  fc_assert_ret(nullptr != pcity->server.adv->act_cache);
351  fc_assert_ret(pcity->server.adv->act_cache_radius_sq
352  == city_map_radius_sq_get(pcity));
353  fc_assert_ret(city_tile_index < city_map_tiles_from_city(pcity));
354 
355  (pcity->server.adv->act_cache[city_tile_index]).act[act_id] = value;
356 }
357 
362 int adv_city_worker_act_get(const struct city *pcity, int city_tile_index,
363  enum unit_activity act_id)
364 {
365  fc_assert_ret_val(nullptr != pcity, 0);
366  fc_assert_ret_val(nullptr != pcity->server.adv, 0);
367  fc_assert_ret_val(nullptr != pcity->server.adv->act_cache, 0);
368  fc_assert_ret_val(pcity->server.adv->act_cache_radius_sq
369  == city_map_radius_sq_get(pcity),
370  0);
371  fc_assert_ret_val(city_tile_index < city_map_tiles_from_city(pcity), 0);
372 
373  return (pcity->server.adv->act_cache[city_tile_index]).act[act_id];
374 }
375 
380 void adv_city_worker_extra_set(struct city *pcity, int city_tile_index,
381  const struct extra_type *pextra, int value)
382 {
383  if (pcity->server.adv->act_cache_radius_sq
384  != city_map_radius_sq_get(pcity)) {
385  log_debug("update activity cache for %s: radius_sq changed from "
386  "%d to %d",
387  city_name_get(pcity), pcity->server.adv->act_cache_radius_sq,
388  city_map_radius_sq_get(pcity));
389  adv_city_update(pcity);
390  }
391 
392  fc_assert_ret(nullptr != pcity);
393  fc_assert_ret(nullptr != pcity->server.adv);
394  fc_assert_ret(nullptr != pcity->server.adv->act_cache);
395  fc_assert_ret(pcity->server.adv->act_cache_radius_sq
396  == city_map_radius_sq_get(pcity));
397  fc_assert_ret(city_tile_index < city_map_tiles_from_city(pcity));
398 
399  (pcity->server.adv->act_cache[city_tile_index])
400  .extra[extra_index(pextra)] = value;
401 }
402 
407 void adv_city_worker_rmextra_set(struct city *pcity, int city_tile_index,
408  const struct extra_type *pextra, int value)
409 {
410  if (pcity->server.adv->act_cache_radius_sq
411  != city_map_radius_sq_get(pcity)) {
412  log_debug("update activity cache for %s: radius_sq changed from "
413  "%d to %d",
414  city_name_get(pcity), pcity->server.adv->act_cache_radius_sq,
415  city_map_radius_sq_get(pcity));
416  adv_city_update(pcity);
417  }
418 
419  fc_assert_ret(nullptr != pcity);
420  fc_assert_ret(nullptr != pcity->server.adv);
421  fc_assert_ret(nullptr != pcity->server.adv->act_cache);
422  fc_assert_ret(pcity->server.adv->act_cache_radius_sq
423  == city_map_radius_sq_get(pcity));
424  fc_assert_ret(city_tile_index < city_map_tiles_from_city(pcity));
425 
426  (pcity->server.adv->act_cache[city_tile_index])
427  .rmextra[extra_index(pextra)] = value;
428 }
429 
434 int adv_city_worker_extra_get(const struct city *pcity, int city_tile_index,
435  const struct extra_type *pextra)
436 {
437  fc_assert_ret_val(nullptr != pcity, 0);
438  fc_assert_ret_val(nullptr != pcity->server.adv, 0);
439  fc_assert_ret_val(nullptr != pcity->server.adv->act_cache, 0);
440  fc_assert_ret_val(pcity->server.adv->act_cache_radius_sq
441  == city_map_radius_sq_get(pcity),
442  0);
443  fc_assert_ret_val(city_tile_index < city_map_tiles_from_city(pcity), 0);
444 
445  return (pcity->server.adv->act_cache[city_tile_index])
446  .extra[extra_index(pextra)];
447 }
448 
453 int adv_city_worker_rmextra_get(const struct city *pcity,
454  int city_tile_index,
455  const struct extra_type *pextra)
456 {
457  fc_assert_ret_val(nullptr != pcity, 0);
458  fc_assert_ret_val(nullptr != pcity->server.adv, 0);
459  fc_assert_ret_val(nullptr != pcity->server.adv->act_cache, 0);
460  fc_assert_ret_val(pcity->server.adv->act_cache_radius_sq
461  == city_map_radius_sq_get(pcity),
462  0);
463  fc_assert_ret_val(city_tile_index < city_map_tiles_from_city(pcity), 0);
464 
465  return (pcity->server.adv->act_cache[city_tile_index])
466  .rmextra[extra_index(pextra)];
467 }
468 
472 void adv_city_update(struct city *pcity)
473 {
474  int radius_sq = city_map_radius_sq_get(pcity);
475 
476  fc_assert_ret(nullptr != pcity);
477  fc_assert_ret(nullptr != pcity->server.adv);
478 
479  // initialize act_cache if needed
480  if (pcity->server.adv->act_cache == nullptr
481  || pcity->server.adv->act_cache_radius_sq == -1
482  || pcity->server.adv->act_cache_radius_sq != radius_sq) {
483  pcity->server.adv->act_cache = static_cast<worker_activity_cache *>(
484  fc_realloc(pcity->server.adv->act_cache,
485  city_map_tiles(radius_sq)
486  * sizeof(*(pcity->server.adv->act_cache))));
487  // initialize with 0
488  memset(pcity->server.adv->act_cache, 0,
489  city_map_tiles(radius_sq)
490  * sizeof(*(pcity->server.adv->act_cache)));
491  pcity->server.adv->act_cache_radius_sq = radius_sq;
492  }
493 }
494 
498 void adv_city_alloc(struct city *pcity)
499 {
500  pcity->server.adv = new adv_city[1]();
501  pcity->server.adv->act_cache = nullptr;
502  pcity->server.adv->act_cache_radius_sq = -1;
503  // allocate memory for pcity->ai->act_cache
504  adv_city_update(pcity);
505 }
506 
510 void adv_city_free(struct city *pcity)
511 {
512  fc_assert_ret(nullptr != pcity);
513 
514  if (pcity->server.adv) {
515  if (pcity->server.adv->act_cache) {
516  free(pcity->server.adv->act_cache); // realloc
517  pcity->server.adv->act_cache = nullptr;
518  }
519  delete[] pcity->server.adv;
520  pcity->server.adv = nullptr;
521  }
522 }
#define action_id_get_activity(act_id)
Definition: actions.h:583
#define TRADE_WEIGHTING
Definition: advbuilding.h:18
#define FOOD_WEIGHTING
Definition: advbuilding.h:16
#define SHIELD_WEIGHTING
Definition: advbuilding.h:17
#define as_transform_action_iterate_end
Definition: autosettlers.h:69
#define as_transform_action_iterate(_act_)
Definition: autosettlers.h:65
struct player * city_owner(const struct city *pcity)
Return the owner of the city.
Definition: city.cpp:1083
struct tile * city_tile(const struct city *pcity)
Return the tile location of the city.
Definition: city.cpp:1095
const char * city_name_get(const struct city *pcity)
Return the name of the city.
Definition: city.cpp:1077
int city_tile_output_now(const struct city *pcity, const struct tile *ptile, Output_type_id otype)
Calculate the production output the given tile is capable of producing for the city.
Definition: city.cpp:1322
int city_map_radius_sq_get(const struct city *pcity)
Returns the current squared radius of the city.
Definition: city.cpp:130
int city_map_tiles(int city_radius_sq)
Return the number of tiles for the given city radius.
Definition: city.cpp:164
#define city_list_iterate(citylist, pcity)
Definition: city.h:482
#define city_tile_iterate_index_end
Definition: city.h:177
#define city_list_iterate_end
Definition: city.h:484
#define city_map_iterate_end
Definition: city.h:148
#define city_map_iterate(_radius_sq, _index, _x, _y)
Definition: city.h:144
#define city_tile_iterate_index(_radius_sq, _city_tile, _tile, _index)
Definition: city.h:169
#define city_map_tiles_from_city(_pcity)
Definition: city.h:100
bool is_extra_removed_by_worker_action(const struct extra_type *pextra)
Is the extra removed by some kind of worker action?
Definition: extras.cpp:942
bool is_extra_caused_by_worker_action(const struct extra_type *pextra)
Is the extra caused by some kind of worker action?
Definition: extras.cpp:931
bool player_can_build_extra(const struct extra_type *pextra, const struct player *pplayer, const struct tile *ptile)
Tells if player can build extra to tile with suitable unit.
Definition: extras.cpp:414
bool can_extras_coexist(const struct extra_type *pextra1, const struct extra_type *pextra2)
Can two extras coexist in same tile?
Definition: extras.cpp:902
bool player_can_remove_extra(const struct extra_type *pextra, const struct player *pplayer, const struct tile *ptile)
Tells if player can remove extra from tile with suitable unit.
Definition: extras.cpp:525
#define extra_type_iterate(_p)
Definition: extras.h:279
#define extra_type_iterate_end
Definition: extras.h:285
#define extra_index(_e_)
Definition: extras.h:163
#define MAX_EXTRA_TYPES
Definition: fc_types.h:42
@ O_SHIELD
Definition: fc_types.h:86
@ O_FOOD
Definition: fc_types.h:85
@ O_TRADE
Definition: fc_types.h:87
void adv_city_free(struct city *pcity)
Free advisors related city data.
Definition: infracache.cpp:510
int adv_city_worker_act_get(const struct city *pcity, int city_tile_index, enum unit_activity act_id)
Return the value for activity 'doing' on tile 'city_tile_index' of city 'pcity'.
Definition: infracache.cpp:362
static int adv_calc_transform(const struct city *pcity, const struct tile *ptile)
Calculate the benefit of transforming the given tile.
Definition: infracache.cpp:137
void adv_city_worker_extra_set(struct city *pcity, int city_tile_index, const struct extra_type *pextra, int value)
Set the value for extra on tile 'city_tile_index' of city 'pcity'.
Definition: infracache.cpp:380
void adv_city_update(struct city *pcity)
Update the memory allocated for AI city handling.
Definition: infracache.cpp:472
static int adv_calc_extra(const struct city *pcity, const struct tile *ptile, const struct extra_type *pextra)
Calculate the benefit of building an extra at the given tile.
Definition: infracache.cpp:182
int adv_city_worker_extra_get(const struct city *pcity, int city_tile_index, const struct extra_type *pextra)
Return the value for extra on tile 'city_tile_index' of city 'pcity'.
Definition: infracache.cpp:434
static int adv_calc_mine_transform(const struct city *pcity, const struct tile *ptile)
Calculate the benefit of mining the given tile.
Definition: infracache.cpp:97
void initialize_infrastructure_cache(struct player *pplayer)
Do all tile improvement calculations and cache them for later.
Definition: infracache.cpp:245
void adv_city_worker_act_set(struct city *pcity, int city_tile_index, enum unit_activity act_id, int value)
Set the value for activity 'doing' on tile 'city_tile_index' of city 'pcity'.
Definition: infracache.cpp:336
void adv_city_worker_rmextra_set(struct city *pcity, int city_tile_index, const struct extra_type *pextra, int value)
Set the value for extra removal on tile 'city_tile_index' of city 'pcity'.
Definition: infracache.cpp:407
int adv_city_worker_rmextra_get(const struct city *pcity, int city_tile_index, const struct extra_type *pextra)
Return the value for extra removal on tile 'city_tile_index' of city 'pcity'.
Definition: infracache.cpp:453
static int adv_calc_rmextra(const struct city *pcity, const struct tile *ptile, const struct extra_type *pextra)
Calculate the benefit of removing an extra from the given tile.
Definition: infracache.cpp:218
int city_tile_value(const struct city *pcity, const struct tile *ptile, int foodneed, int prodneed)
Returns a measure of goodness of a tile to pcity.
Definition: infracache.cpp:305
static int adv_calc_irrigate_transform(const struct city *pcity, const struct tile *ptile)
Calculate the benefit of irrigating the given tile.
Definition: infracache.cpp:57
void adv_city_alloc(struct city *pcity)
Allocate advisors related city data.
Definition: infracache.cpp:498
#define fc_assert_ret(condition)
Definition: log.h:112
#define fc_assert_ret_val(condition, val)
Definition: log.h:114
#define log_debug(message,...)
Definition: log.h:65
bool terrain_surroundings_allow_change(const struct tile *ptile, const struct terrain *pterrain)
Returns FALSE if a terrain change to 'pterrain' would be prevented by not having enough similar terra...
Definition: map.cpp:706
Definition: city.h:291
struct city::@15::@17 server
Definition: player.h:231
struct city_list * cities
Definition: player.h:263
struct terrain * irrigation_result
Definition: terrain.h:200
struct terrain * mining_result
Definition: terrain.h:204
struct terrain * transform_result
Definition: terrain.h:210
Definition: tile.h:42
int rmextra[MAX_EXTRA_TYPES]
Definition: infracache.cpp:34
int act[ACTIVITY_LAST]
Definition: infracache.cpp:32
int extra[MAX_EXTRA_TYPES]
Definition: infracache.cpp:33
#define fc_realloc(ptr, sz)
Definition: support.h:59
#define T_NONE
Definition: terrain.h:50
#define terrain_has_flag(terr, flag)
Definition: terrain.h:260
void tile_add_extra(struct tile *ptile, const struct extra_type *pextra)
Adds extra to tile.
Definition: tile.cpp:974
void tile_virtual_destroy(struct tile *vtile)
Frees all memory used by the virtual tile, including freeing virtual units in the tile's unit list an...
Definition: tile.cpp:1051
void tile_remove_extra(struct tile *ptile, const struct extra_type *pextra)
Removes extra from tile if such exist.
Definition: tile.cpp:984
void tile_change_terrain(struct tile *ptile, struct terrain *pterrain)
Change the terrain to the given type.
Definition: tile.cpp:491
struct city * tile_city(const struct tile *ptile)
Return the city on this tile (or nullptr), checking for city center.
Definition: tile.cpp:72
struct tile * tile_virtual_new(const struct tile *ptile)
Returns a virtual tile.
Definition: tile.cpp:997
#define tile_terrain(_tile)
Definition: tile.h:93
#define tile_has_extra(ptile, pextra)
Definition: tile.h:130