Freeciv21
Develop your civilization from humble roots to a global empire
taicity.c
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 #include <fc_config.h>
15 
16 /* utility */
17 #include "log.h"
18 
19 /* common */
20 #include "city.h"
21 #include "game.h"
22 #include "map.h"
23 #include "movement.h"
24 #include "tile.h"
25 #include "unit.h"
26 #include "workertask.h"
27 
28 /* server */
29 #include "citytools.h"
30 
31 /* server/advisors */
32 #include "autosettlers.h"
33 #include "infracache.h"
34 
35 /* ai/threaded */
36 #include "taimsg.h"
37 
38 #include "taicity.h"
39 
40 /* Task Want Multiplier */
41 #define TWMP 100
42 
44  int city_id;
45  struct worker_task task;
46 };
47 
49 
50 static bool
51 tai_city_worker_task_select(struct ai_type *ait, struct player *pplayer,
52  struct city *pcity, struct worker_task *task,
53  enum tai_worker_task_limitation limit);
54 
55 /**********************************************************************/
60  struct player *pplayer,
61  struct city *pcity)
62 {
63  struct worker_task task;
64 
65  if (tai_city_worker_task_select(ait, pplayer, pcity, &task,
67  struct tai_worker_task_req *data = fc_malloc(sizeof(*data));
68 
69  data->city_id = pcity->id;
70  data->task.ptile = task.ptile;
71  data->task.act = task.act;
72  data->task.tgt = task.tgt;
73  data->task.want = task.want;
74 
75  tai_send_req(TAI_REQ_WORKER_TASK, pplayer, data);
76  }
77 }
78 
80  int uw_max_base; /* Value for the city working the tile */
81  int uw_max; /* With road connectivity bonus */
85  int *wants;
86 };
87 
88 static int dummy_wants[U_LAST];
89 
90 /**********************************************************************/
94  struct player *pplayer, struct city *pcity, struct tile *ptile,
95  int cindex, struct unit_list *units, struct worker_task *worked,
96  struct worker_task *unworked, struct tai_tile_state *state,
97  enum tai_worker_task_limitation limit)
98 {
99  int orig_value;
100  bool potential_worst_worked = false;
101 
102  if (!city_can_work_tile(pcity, ptile)) {
103  return;
104  }
105 
106  orig_value = city_tile_value(pcity, ptile, 0, 0);
107 
108  if (tile_worked(ptile) == pcity && orig_value < state->worst_worked) {
109  state->worst_worked = orig_value;
110  state->orig_worst_worked = orig_value;
111  potential_worst_worked = true;
112  }
113 
115  {
116  bool consider = true;
117  bool possible = false;
118  struct extra_type *tgt = NULL;
119  enum extra_cause cause;
120  enum extra_rmcause rmcause;
121 
122  /* Do not request activities that already are under way. */
123  unit_list_iterate(ptile->units, punit)
124  {
125  if (unit_owner(punit) == pplayer
126  && unit_has_type_flag(punit, UTYF_SETTLERS)
127  && punit->activity == action_id_get_activity(act)) {
128  consider = false;
129  break;
130  }
131  }
133 
134  if (!consider) {
135  continue;
136  }
137 
140 
141  unit_list_iterate(units, punit)
142  {
143  if (cause != EC_NONE) {
144  tgt = next_extra_for_tile(ptile, cause, pplayer, punit);
145  } else if (rmcause != ERM_NONE) {
146  tgt = prev_extra_in_tile(ptile, rmcause, pplayer, punit);
147  }
148 
150  act, punit, unit_home(punit), ptile, true, ptile, tgt))) {
151  possible = true;
152  break;
153  }
154  }
156 
157  if (possible) {
158  int value = adv_city_worker_act_get(pcity, cindex,
160 
161  if (tile_worked(ptile) == pcity) {
162  if ((value - orig_value) * TWMP > worked->want) {
163  worked->want = TWMP * (value - orig_value);
164  worked->ptile = ptile;
165  worked->act = action_id_get_activity(act);
166  worked->tgt = NULL;
167  worked->tgt = NULL;
168  if (limit == TWTL_BUILDABLE_UNITS) {
169  unit_list_iterate(units, punit)
170  {
172  act, punit, unit_home(punit), ptile, true, ptile,
173  tgt))) {
174  state->wants[utype_index(unit_type_get(punit))] +=
175  worked->want;
176  }
177  }
179  }
180  }
181  if (value > state->old_worst_worked) {
182  /* After improvement it would not be the worst */
183  potential_worst_worked = false;
184  } else {
185  state->worst_worked = value;
186  }
187  } else {
188  if (value > orig_value && value > state->uw_max) {
189  state->uw_max = value;
190  state->uw_max_base = value;
191  unworked->want = TWMP * (value - orig_value);
192  unworked->ptile = ptile;
193  unworked->act = action_id_get_activity(act);
194  unworked->tgt = NULL;
195  if (limit == TWTL_BUILDABLE_UNITS) {
196  unit_list_iterate(units, punit)
197  {
199  act, punit, unit_home(punit), ptile, true, ptile,
200  tgt))) {
201  state->wants[utype_index(unit_type_get(punit))] +=
202  unworked->want;
203  }
204  }
206  }
207  }
208  }
209  }
210  }
212 
213  extra_type_iterate(tgt)
214  {
215  struct action *paction = NULL;
216  bool removing = tile_has_extra(ptile, tgt);
217 
218  unit_list_iterate(units, punit)
219  {
220  if (removing) {
222  {
223  struct action *taction = action_by_number(try_act);
224  if (is_extra_removed_by_action(tgt, taction)
226  try_act, punit, unit_home(punit), ptile, true, ptile,
227  tgt))) {
228  paction = taction;
229  break;
230  }
231  }
233  } else {
234  as_extra_action_iterate(try_act)
235  {
236  struct action *taction = action_by_number(try_act);
237  if (is_extra_caused_by_action(tgt, taction)
239  try_act, punit, unit_home(punit), ptile, true, ptile,
240  tgt))) {
241  paction = taction;
242  break;
243  }
244  }
246  }
247  }
249 
250  if (paction != NULL) {
251  adv_want base_value;
252  int value;
253  adv_want extra;
254  bool consider = true;
255  struct road_type *proad;
256 
257  /* Do not request activities that already are under way. */
258  unit_list_iterate(ptile->units, punit)
259  {
260  if (unit_owner(punit) == pplayer
261  && unit_has_type_flag(punit, UTYF_SETTLERS)
262  && punit->activity == action_get_activity(paction)) {
263  consider = false;
264  break;
265  }
266  }
268 
269  if (!consider) {
270  continue;
271  }
272 
273  proad = extra_road_get(tgt);
274 
275  if (removing) {
276  base_value = adv_city_worker_rmextra_get(pcity, cindex, tgt);
277  } else {
278  base_value = adv_city_worker_extra_get(pcity, cindex, tgt);
279  }
280 
281  if (proad != NULL && road_provides_move_bonus(proad)) {
282  int old_move_cost;
283  int mc_multiplier = 1;
284  int mc_divisor = 1;
285 
286  /* Here 'old' means actually 'without the evaluated': In case of
287  * removal activity it's the value after the removal. */
288  old_move_cost = tile_terrain(ptile)->movement_cost * SINGLE_MOVE;
289 
290  extra_type_by_cause_iterate(EC_ROAD, poe)
291  {
292  struct road_type *pold = extra_road_get(poe);
293 
294  if (tile_has_extra(ptile, poe) && poe != tgt) {
295  if (road_provides_move_bonus(pold)
296  && pold->move_cost < old_move_cost) {
297  old_move_cost = pold->move_cost;
298  }
299  }
300  }
302 
303  if (proad->move_cost < old_move_cost) {
304  if (proad->move_cost >= terrain_control.move_fragments) {
305  mc_divisor = proad->move_cost / terrain_control.move_fragments;
306  } else {
307  if (proad->move_cost == 0) {
308  mc_multiplier = 2;
309  } else {
310  mc_multiplier = 1 - proad->move_cost;
311  }
312  mc_multiplier += old_move_cost;
313  }
314  }
315 
316  extra = adv_settlers_road_bonus(ptile, proad) * mc_multiplier
317  / mc_divisor;
318 
319  if (removing) {
320  extra = -extra;
321  }
322  } else {
323  extra = 0;
324  }
325 
326  value = base_value + extra;
327 
328  if (tile_worked(ptile) == pcity) {
329  if ((value - orig_value) * TWMP > worked->want) {
330  worked->want = TWMP * (value - orig_value);
331  worked->ptile = ptile;
332  worked->act = action_get_activity(paction);
333  worked->tgt = tgt;
334  if (limit == TWTL_BUILDABLE_UNITS) {
335  unit_list_iterate(units, punit)
336  {
337  fc_assert_action(action_get_target_kind(paction) == ATK_TILE,
338  break);
340  paction->id, punit, unit_home(punit), ptile, true,
341  ptile, tgt))) {
342  state->wants[utype_index(unit_type_get(punit))] +=
343  worked->want;
344  }
345  }
347  }
348  }
349  if (value > state->old_worst_worked) {
350  /* After improvement it would not be the worst */
351  potential_worst_worked = false;
352  } else {
353  state->worst_worked = value;
354  }
355  } else {
356  if (value > orig_value && value > state->uw_max) {
357  state->uw_max = value;
358  state->uw_max_base = base_value;
359  unworked->want = TWMP * (value - orig_value);
360  unworked->ptile = ptile;
361  unworked->act = action_get_activity(paction);
362  unworked->tgt = tgt;
363  if (limit == TWTL_BUILDABLE_UNITS) {
364  unit_list_iterate(units, punit)
365  {
366  fc_assert_action(action_get_target_kind(paction) == ATK_TILE,
367  break);
369  paction->id, punit, unit_home(punit), ptile, true,
370  ptile, tgt))) {
371  state->wants[utype_index(unit_type_get(punit))] +=
372  unworked->want;
373  }
374  }
376  }
377  }
378  }
379  }
380  }
382 
383  if (potential_worst_worked) {
384  /* Would still be worst worked even if we improved *it*. */
385  state->old_worst_worked = state->worst_worked;
386  }
387 }
388 
389 /**********************************************************************/
392 static bool
393 tai_city_worker_task_select(struct ai_type *ait, struct player *pplayer,
394  struct city *pcity, struct worker_task *task,
395  enum tai_worker_task_limitation limit)
396 {
397  struct worker_task *selected;
398  struct worker_task worked = {
399  .ptile = NULL, .want = 0, .act = ACTIVITY_IDLE, .tgt = NULL};
400  struct worker_task unworked = {
401  .ptile = NULL, .want = 0, .act = ACTIVITY_IDLE, .tgt = NULL};
402  struct tai_tile_state state = {.uw_max = 0,
403  .uw_max_base = 0,
404  .worst_worked = FC_INFINITY,
405  .orig_worst_worked = 0,
406  .old_worst_worked = FC_INFINITY};
407  struct unit_list *units = NULL;
408 
409  switch (limit) {
410  case TWTL_CURRENT_UNITS:
411  units = pplayer->units;
412  state.wants = NULL;
413  break;
415  units = unit_list_new();
416  unit_type_iterate(ptype)
417  {
418  if (can_city_build_unit_now(pcity, ptype)) {
419  unit_list_append(units,
420  unit_virtual_create(pplayer, pcity, ptype, 0));
421  }
422  }
424  state.wants = dummy_wants;
425  break;
426  }
427 
429  ptile, cindex)
430  {
431  tai_tile_worker_task_select(pplayer, pcity, ptile, cindex, units,
432  &worked, &unworked, &state, limit);
433  }
435 
436  if (worked.ptile == NULL
437  || (state.old_worst_worked < state.uw_max
438  && (state.uw_max - state.orig_worst_worked) * TWMP > worked.want)
439  || (state.uw_max - state.uw_max_base * TWMP > worked.want)) {
440  /* It's better to improve best yet unworked tile and take it to use after
441  that, than to improve already worked tile. OR it's more important to
442  improve road connectivity outside worked tiles than improve worked
443  tiles */
444  selected = &unworked;
445  } else {
446  selected = &worked;
447  }
448 
449  if (limit == TWTL_BUILDABLE_UNITS) {
450  unit_list_iterate(units, punit) { unit_virtual_destroy(punit); }
452  unit_list_destroy(units);
453  }
454 
455  if (selected->ptile != NULL) {
456  struct extra_type *target = NULL;
457 
458  if (selected->tgt == NULL) {
459  enum extra_cause cause = activity_to_extra_cause(selected->act);
460 
461  if (cause != EC_NONE) {
462  target = next_extra_for_tile(selected->ptile, cause, pplayer, NULL);
463  } else {
464  enum extra_rmcause rmcause =
465  activity_to_extra_rmcause(selected->act);
466 
467  if (rmcause != ERM_NONE) {
468  target =
469  prev_extra_in_tile(selected->ptile, rmcause, pplayer, NULL);
470  }
471  }
472  } else {
473  target = selected->tgt;
474  }
475 
476  task->ptile = selected->ptile;
477  task->act = selected->act;
478  task->tgt = target;
479  task->want = selected->want;
480 
481  return true;
482  }
483 
484  return false;
485 }
486 
487 /**********************************************************************/
491 {
492  struct tai_worker_task_req *data =
493  (struct tai_worker_task_req *) req->data;
494  struct city *pcity;
495 
496  pcity = game_city_by_number(data->city_id);
497 
498  if (pcity != NULL && city_owner(pcity) == req->plr) {
499  /* City has not been lost meanwhile */
500  struct worker_task *ptask = worker_task_list_get(pcity->task_reqs, 0);
501 
502  if (ptask == NULL) {
503  ptask = new worker_task{};
504  worker_task_init(ptask);
505  worker_task_list_append(pcity->task_reqs, ptask);
506  }
507 
508  log_debug("%s storing req for act %d at (%d,%d)", pcity->name,
509  data->task.act, TILE_XY(data->task.ptile));
510  ptask->ptile = data->task.ptile;
511  ptask->act = data->task.act;
512  ptask->tgt = data->task.tgt;
513  ptask->want = data->task.want;
514 
515  /* Send info to observers */
517  }
518 
519  free(data);
520 }
bool action_prob_possible(const struct act_prob probability)
Returns TRUE iff the given action probability belongs to an action that may be possible.
Definition: actions.cpp:5380
struct action * action_by_number(action_id act_id)
Return the action with the given id.
Definition: actions.cpp:1149
enum unit_activity action_get_activity(const struct action *paction)
Returns the unit activity this action may cause or ACTIVITY_LAST if the action doesn't result in a un...
Definition: actions.cpp:1557
enum action_target_kind action_get_target_kind(const struct action *paction)
Get the target kind of an action.
Definition: actions.cpp:1198
struct act_prob action_speculate_unit_on_tile(action_id act_id, const struct unit *actor, const struct city *actor_home, const struct tile *actor_tile, bool omniscient_cheat, const struct tile *target_tile, const struct extra_type *target_extra)
Returns a speculation about the actor unit's probability of successfully performing the chosen action...
Definition: actions.cpp:5273
#define action_id_get_activity(act_id)
Definition: actions.h:583
adv_want adv_settlers_road_bonus(struct tile *ptile, struct road_type *proad)
Calculate the attractiveness of building a road/rail at the given tile.
#define as_transform_action_iterate_end
Definition: autosettlers.h:69
#define as_rmextra_action_iterate(_act_)
Definition: autosettlers.h:85
#define as_rmextra_action_iterate_end
Definition: autosettlers.h:89
#define as_extra_action_iterate_end
Definition: autosettlers.h:79
#define as_extra_action_iterate(_act_)
Definition: autosettlers.h:75
#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
int city_map_radius_sq_get(const struct city *pcity)
Returns the current squared radius of the city.
Definition: city.cpp:130
bool city_can_work_tile(const struct city *pcity, const struct tile *ptile)
Returns TRUE when a tile is available to be worked, or the city itself is currently working the tile ...
Definition: city.cpp:1392
bool can_city_build_unit_now(const struct city *pcity, const struct unit_type *punittype)
Return whether given city can build given unit; returns FALSE if unit is obsolete.
Definition: city.cpp:894
#define city_tile_iterate_end
Definition: city.h:209
#define city_tile_iterate_index(_radius_sq, _city_tile, _tile, _index)
Definition: city.h:169
void package_and_send_worker_tasks(struct city *pcity)
Send city worker task to owner.
Definition: citytools.cpp:3433
enum extra_cause activity_to_extra_cause(enum unit_activity act)
What extra cause activity is considered to be?
Definition: extras.cpp:973
struct extra_type * prev_extra_in_tile(const struct tile *ptile, enum extra_rmcause rmcause, const struct player *pplayer, const struct unit *punit)
Returns prev extra by cause that unit or player can remove from tile.
Definition: extras.cpp:732
bool is_extra_caused_by_action(const struct extra_type *pextra, const struct action *paction)
Is the extra caused by specific worker action?
Definition: extras.cpp:953
bool is_extra_removed_by_action(const struct extra_type *pextra, const struct action *paction)
Is the extra removed by specific worker action?
Definition: extras.cpp:963
enum extra_rmcause activity_to_extra_rmcause(enum unit_activity act)
What extra rmcause activity is considered to be?
Definition: extras.cpp:994
struct extra_type * next_extra_for_tile(const struct tile *ptile, enum extra_cause cause, const struct player *pplayer, const struct unit *punit)
Returns next extra by cause that unit or player can build to tile.
Definition: extras.cpp:687
#define extra_type_iterate(_p)
Definition: extras.h:279
#define extra_type_iterate_end
Definition: extras.h:285
#define extra_road_get(_e_)
Definition: extras.h:171
#define extra_type_by_cause_iterate_end
Definition: extras.h:307
#define extra_type_by_cause_iterate(_cause, _extra)
Definition: extras.h:299
float adv_want
Definition: fc_types.h:1144
#define EC_NONE
Definition: fc_types.h:934
#define ERM_NONE
Definition: fc_types.h:958
struct city * game_city_by_number(int id)
Often used function to get a city pointer from a city ID.
Definition: game.cpp:103
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
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
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
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
#define fc_assert_action(condition, action)
Definition: log.h:104
#define log_debug(message,...)
Definition: log.h:65
struct terrain_misc terrain_control
Definition: map.cpp:40
#define SINGLE_MOVE
Definition: movement.h:17
bool road_provides_move_bonus(const struct road_type *proad)
Does road type provide move bonus.
Definition: road.cpp:437
#define FC_INFINITY
Definition: shared.h:32
action_id id
Definition: actions.h:306
Definition: ai.h:42
Definition: city.h:291
int id
Definition: city.h:296
Definition: player.h:231
struct unit_list * units
Definition: player.h:264
Definition: road.h:54
int move_cost
Definition: road.h:57
Definition: taimsg.h:37
struct player * plr
Definition: taimsg.h:39
void * data
Definition: taimsg.h:40
int orig_worst_worked
Definition: taicity.c:83
int uw_max_base
Definition: taicity.c:80
int old_worst_worked
Definition: taicity.c:84
int worst_worked
Definition: taicity.c:82
int * wants
Definition: taicity.c:85
struct worker_task task
Definition: taicity.c:45
Definition: tile.h:42
struct unit_list * units
Definition: tile.h:50
enum unit_activity act
Definition: workertask.h:17
struct tile * ptile
Definition: workertask.h:16
struct extra_type * tgt
Definition: workertask.h:18
#define fc_malloc(sz)
Definition: support.h:58
void tai_city_worker_requests_create(struct ai_type *ait, struct player *pplayer, struct city *pcity)
Create worker request for the city.
Definition: taicity.c:59
#define TWMP
Definition: taicity.c:41
static int dummy_wants[U_LAST]
Definition: taicity.c:88
void tai_req_worker_task_rcv(struct tai_req *req)
Receive message from thread to main thread.
Definition: taicity.c:490
tai_worker_task_limitation
Definition: taicity.c:48
@ TWTL_BUILDABLE_UNITS
Definition: taicity.c:48
@ TWTL_CURRENT_UNITS
Definition: taicity.c:48
static bool tai_city_worker_task_select(struct ai_type *ait, struct player *pplayer, struct city *pcity, struct worker_task *task, enum tai_worker_task_limitation limit)
Select worker task suitable for the city.
Definition: taicity.c:393
static void tai_tile_worker_task_select(struct player *pplayer, struct city *pcity, struct tile *ptile, int cindex, struct unit_list *units, struct worker_task *worked, struct worker_task *unworked, struct tai_tile_state *state, enum tai_worker_task_limitation limit)
Select worker task suitable for the tile.
Definition: taicity.c:93
void tai_send_req(enum taireqtype type, struct player *pplayer, void *data)
Construct and send request from player thread.
Definition: taimsg.c:45
#define tile_worked(_tile)
Definition: tile.h:97
#define tile_terrain(_tile)
Definition: tile.h:93
#define TILE_XY(ptile)
Definition: tile.h:36
#define tile_has_extra(ptile, pextra)
Definition: tile.h:130
void unit_virtual_destroy(struct unit *punit)
Free the memory used by virtual unit.
Definition: unit.cpp:1588
struct unit * unit_virtual_create(struct player *pplayer, struct city *pcity, const struct unit_type *punittype, int veteran_level)
Create a virtual unit skeleton.
Definition: unit.cpp:1490
#define unit_owner(_pu)
Definition: unit.h:370
#define unit_home(_pu_)
Definition: unit.h:369
#define unit_list_iterate(unitlist, punit)
Definition: unitlist.h:25
#define unit_list_iterate_end
Definition: unitlist.h:27
const struct unit_type * unit_type_get(const struct unit *punit)
Return the unit type for this unit.
Definition: unittype.cpp:114
bool unit_has_type_flag(const struct unit *punit, enum unit_type_flag_id flag)
Return whether the unit has the given flag.
Definition: unittype.cpp:176
Unit_type_id utype_index(const struct unit_type *punittype)
Return the unit type index.
Definition: unittype.cpp:82
#define unit_type_iterate(_p)
Definition: unittype.h:785
#define U_LAST
Definition: unittype.h:31
#define unit_type_iterate_end
Definition: unittype.h:791
void worker_task_init(struct worker_task *ptask)
Initialize empty worker_task.
Definition: workertask.cpp:18