Freeciv-3.1
Loading...
Searching...
No Matches
taicity.c
Go to the documentation of this file.
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)
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/* utility */
19#include "log.h"
20
21/* common */
22#include "city.h"
23#include "game.h"
24#include "map.h"
25#include "movement.h"
26#include "tile.h"
27#include "unit.h"
28#include "workertask.h"
29
30/* server */
31#include "citytools.h"
32
33/* server/advisors */
34#include "autosettlers.h"
35#include "infracache.h"
36
37/* ai/threaded */
38#include "taimsg.h"
39
40#include "taicity.h"
41
42/* Task Want Multiplier */
43#define TWMP 100
44
50
55
56static bool tai_city_worker_task_select(struct ai_type *ait,
57 struct player *pplayer, struct city *pcity,
58 struct worker_task *task,
60
61/**********************************************************************/
66 struct player *pplayer, struct city *pcity)
67{
68 struct worker_task task;
69
70 if (tai_city_worker_task_select(ait, pplayer, pcity, &task, TWTL_CURRENT_UNITS)) {
71 struct tai_worker_task_req *data = fc_malloc(sizeof(*data));
72
73 data->city_id = pcity->id;
74 data->task.ptile = task.ptile;
75 data->task.act = task.act;
76 data->task.tgt = task.tgt;
77 data->task.want = task.want;
78
79 tai_send_req(TAI_REQ_WORKER_TASK, pplayer, data);
80 }
81}
82
84{
85 int uw_max_base; /* Value for the city working the tile */
86 int uw_max; /* With road connectivity bonus */
90 int *wants;
91};
92
93static int dummy_wants[U_LAST];
94
95/**********************************************************************/
98static void tai_tile_worker_task_select(struct player *pplayer,
99 struct city *pcity, struct tile *ptile,
100 int cindex, struct unit_list *units,
101 struct worker_task *worked,
102 struct worker_task *unworked,
103 struct tai_tile_state *state,
105{
106 int orig_value;
107 bool potential_worst_worked = FALSE;
108
109 if (!city_can_work_tile(pcity, ptile)) {
110 return;
111 }
112
113 orig_value = city_tile_value(pcity, ptile, 0, 0);
114
115 if (tile_worked(ptile) == pcity
116 && orig_value < state->worst_worked) {
117 state->worst_worked = orig_value;
118 state->orig_worst_worked = orig_value;
119 potential_worst_worked = TRUE;
120 }
121
123 bool consider = TRUE;
124 bool possible = FALSE;
125 struct extra_type *tgt = NULL;
126 enum extra_cause cause;
127 enum extra_rmcause rmcause;
128
129 /* Do not request activities that already are under way. */
130 unit_list_iterate(ptile->units, punit) {
131 if (unit_owner(punit) == pplayer
132 && unit_has_type_flag(punit, UTYF_SETTLERS)
134 consider = FALSE;
135 break;
136 }
138
139 if (!consider) {
140 continue;
141 }
142
145
146 unit_list_iterate(units, punit) {
147 if (cause != EC_NONE) {
148 tgt = next_extra_for_tile(ptile, cause, pplayer, punit);
149 } else if (rmcause != ERM_NONE) {
150 tgt = prev_extra_in_tile(ptile, rmcause, pplayer, punit);
151 }
152
155 punit, unit_home(punit), ptile,
156 TRUE,
157 ptile, tgt))) {
158 possible = TRUE;
159 break;
160 }
162
163 if (possible) {
164 int value = adv_city_worker_act_get(pcity, cindex,
166
167 if (tile_worked(ptile) == pcity) {
168 if ((value - orig_value) * TWMP > worked->want) {
169 worked->want = TWMP * (value - orig_value);
170 worked->ptile = ptile;
171 worked->act = action_id_get_activity(act);
172 worked->tgt = NULL;
173 worked->tgt = NULL;
174 if (limit == TWTL_BUILDABLE_UNITS) {
175 unit_list_iterate(units, punit) {
179 ptile,
180 TRUE,
181 ptile, tgt))) {
182 state->wants[utype_index(unit_type_get(punit))] += worked->want;
183 }
185 }
186 }
187 if (value > state->old_worst_worked) {
188 /* After improvement it would not be the worst */
189 potential_worst_worked = FALSE;
190 } else {
191 state->worst_worked = value;
192 }
193 } else {
194 if (value > orig_value && value > state->uw_max) {
195 state->uw_max = value;
196 state->uw_max_base = value;
197 unworked->want = TWMP * (value - orig_value);
198 unworked->ptile = ptile;
199 unworked->act = action_id_get_activity(act);
200 unworked->tgt = NULL;
201 if (limit == TWTL_BUILDABLE_UNITS) {
202 unit_list_iterate(units, punit) {
206 ptile,
207 TRUE,
208 ptile, tgt))) {
209 state->wants[utype_index(unit_type_get(punit))] += unworked->want;
210 }
212 }
213 }
214 }
215 }
217
218 extra_type_iterate(tgt) {
219 struct action *paction = NULL;
220 bool removing = tile_has_extra(ptile, tgt);
221
222 unit_list_iterate(units, punit) {
223 if (removing) {
225 struct action *taction = action_by_number(try_act);
226 if (is_extra_removed_by_action(tgt, taction)
229 punit,
230 unit_home(punit), ptile,
231 TRUE,
232 ptile, tgt))) {
233 paction = taction;
234 break;
235 }
237 } else {
238 as_extra_action_iterate(try_act) {
239 struct action *taction = action_by_number(try_act);
240 if (is_extra_caused_by_action(tgt, taction)
243 punit,
244 unit_home(punit), ptile,
245 TRUE,
246 ptile, tgt))) {
247 paction = taction;
248 break;
249 }
251 }
253
254 if (paction != NULL) {
255 adv_want base_value;
256 int value;
257 adv_want extra;
258 bool consider = TRUE;
259 struct road_type *proad;
260
261 /* Do not request activities that already are under way. */
262 unit_list_iterate(ptile->units, punit) {
263 if (unit_owner(punit) == pplayer
264 && unit_has_type_flag(punit, UTYF_SETTLERS)
265 && punit->activity == actres_get_activity(paction->result)) {
266 consider = FALSE;
267 break;
268 }
270
271 if (!consider) {
272 continue;
273 }
274
275 proad = extra_road_get(tgt);
276
277 if (removing) {
278 base_value = adv_city_worker_rmextra_get(pcity, cindex, tgt);
279 } else {
280 base_value = adv_city_worker_extra_get(pcity, cindex, tgt);
281 }
282
283 if (proad != NULL && road_provides_move_bonus(proad)) {
284 int old_move_cost;
285 int mc_multiplier = 1;
286 int mc_divisor = 1;
287
288 /* Here 'old' means actually 'without the evaluated': In case of
289 * removal activity it's the value after the removal. */
290 old_move_cost = tile_terrain(ptile)->movement_cost * SINGLE_MOVE;
291
292 extra_type_by_cause_iterate(EC_ROAD, poe) {
293 struct road_type *pold = extra_road_get(poe);
294
295 if (tile_has_extra(ptile, poe) && poe != tgt) {
297 && pold->move_cost < old_move_cost) {
298 old_move_cost = pold->move_cost;
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(&(wld.map), ptile, proad) * mc_multiplier / mc_divisor;
317
318 if (removing) {
319 extra = -extra;
320 }
321 } else {
322 extra = 0;
323 }
324
325 value = base_value + extra;
326
327 if (tile_worked(ptile) == pcity) {
328 if ((value - orig_value) * TWMP > worked->want) {
329 worked->want = TWMP * (value - orig_value);
330 worked->ptile = ptile;
331 worked->act = actres_get_activity(paction->result);
332 worked->tgt = tgt;
333 if (limit == TWTL_BUILDABLE_UNITS) {
334 unit_list_iterate(units, punit) {
335 fc_assert_action(action_get_target_kind(paction) == ATK_TILE,
336 break);
338 paction->id,
339 punit, unit_home(punit), ptile,
340 TRUE,
341 ptile, tgt))) {
342 state->wants[utype_index(unit_type_get(punit))] += worked->want;
343 }
345 }
346 }
347 if (value > state->old_worst_worked) {
348 /* After improvement it would not be the worst */
349 potential_worst_worked = FALSE;
350 } else {
351 state->worst_worked = value;
352 }
353 } else {
354 if (value > orig_value && value > state->uw_max) {
355 state->uw_max = value;
356 state->uw_max_base = base_value;
357 unworked->want = TWMP * (value - orig_value);
358 unworked->ptile = ptile;
359 unworked->act = actres_get_activity(paction->result);
360 unworked->tgt = tgt;
361 if (limit == TWTL_BUILDABLE_UNITS) {
362 unit_list_iterate(units, punit) {
363 fc_assert_action(action_get_target_kind(paction) == ATK_TILE,
364 break);
366 paction->id,
367 punit, unit_home(punit), ptile,
368 TRUE,
369 ptile, tgt))) {
370 state->wants[utype_index(unit_type_get(punit))] += unworked->want;
371 }
373 }
374 }
375 }
376 }
378
379 if (potential_worst_worked) {
380 /* Would still be worst worked even if we improved *it*. */
381 state->old_worst_worked = state->worst_worked;
382 }
383}
384
385/**********************************************************************/
388static bool tai_city_worker_task_select(struct ai_type *ait,
389 struct player *pplayer, struct city *pcity,
390 struct worker_task *task,
392{
393 struct worker_task *selected;
394 struct worker_task worked = { .ptile = NULL, .want = 0, .act = ACTIVITY_IDLE, .tgt = NULL };
395 struct worker_task unworked = { .ptile = NULL, .want = 0, .act = ACTIVITY_IDLE, .tgt = NULL };
396 struct tai_tile_state state = { .uw_max = 0, .uw_max_base = 0, .worst_worked = FC_INFINITY,
397 .orig_worst_worked = 0, .old_worst_worked = FC_INFINITY };
398 struct unit_list *units = NULL;
399 const struct civ_map *nmap = &(wld.map);
400
401 switch (limit) {
403 units = pplayer->units;
404 state.wants = NULL;
405 break;
407 units = unit_list_new();
408 unit_type_iterate(ptype) {
409 if (can_city_build_unit_now(pcity, ptype)) {
410 unit_list_append(units, unit_virtual_create(pplayer, pcity, ptype, 0));
411 }
413 state.wants = dummy_wants;
414 break;
415 }
416
418 ptile, cindex) {
419 tai_tile_worker_task_select(pplayer, pcity, ptile, cindex, units, &worked, &unworked,
420 &state, limit);
422
423 if (worked.ptile == NULL
424 || (state.old_worst_worked < state.uw_max
425 && (state.uw_max - state.orig_worst_worked) * TWMP > worked.want)
426 || (state.uw_max - state.uw_max_base * TWMP > worked.want)) {
427 /* It's better to improve best yet unworked tile and take it to use after that,
428 than to improve already worked tile. OR it's more important to
429 improve road connectivity outside worked tiles than improve worked tiles */
430 selected = &unworked;
431 } else {
432 selected = &worked;
433 }
434
435 if (limit == TWTL_BUILDABLE_UNITS) {
436 unit_list_iterate(units, punit) {
439 unit_list_destroy(units);
440 }
441
442 if (selected->ptile != NULL) {
443 struct extra_type *target = NULL;
444
445 if (selected->tgt == NULL) {
446 enum extra_cause cause = activity_to_extra_cause(selected->act);
447
448 if (cause != EC_NONE) {
449 target = next_extra_for_tile(selected->ptile, cause, pplayer, NULL);
450 } else {
451 enum extra_rmcause rmcause = activity_to_extra_rmcause(selected->act);
452
453 if (rmcause != ERM_NONE) {
454 target = prev_extra_in_tile(selected->ptile, rmcause, pplayer, NULL);
455 }
456 }
457 } else {
458 target = selected->tgt;
459 }
460
461 task->ptile = selected->ptile;
462 task->act = selected->act;
463 task->tgt = target;
464 task->want = selected->want;
465
466 return TRUE;
467 }
468
469 return FALSE;
470}
471
472/**********************************************************************/
476{
477 struct tai_worker_task_req *data = (struct tai_worker_task_req *)req->data;
478 struct city *pcity;
479
480 pcity = game_city_by_number(data->city_id);
481
482 if (pcity != NULL && city_owner(pcity) == req->plr) {
483 /* City has not been lost meanwhile */
484 struct worker_task *ptask = worker_task_list_get(pcity->task_reqs, 0);
485
486 if (ptask == NULL) {
487 ptask = fc_malloc(sizeof(struct worker_task));
488 worker_task_init(ptask);
489 worker_task_list_append(pcity->task_reqs, ptask);
490 }
491
492 log_debug("%s storing req for act %d at (%d,%d)",
493 pcity->name, data->task.act, TILE_XY(data->task.ptile));
494 ptask->ptile = data->task.ptile;
495 ptask->act = data->task.act;
496 ptask->tgt = data->task.tgt;
497 ptask->want = data->task.want;
498
499 /* Send info to observers */
501 }
502
503 free(data);
504}
bool action_prob_possible(const struct act_prob probability)
Definition actions.c:6707
enum unit_activity actres_get_activity(enum action_result result)
Definition actions.c:2136
enum action_target_kind action_get_target_kind(const struct action *paction)
Definition actions.c:1740
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)
Definition actions.c:6560
static struct action * action_by_number(action_id act_id)
Definition actions.h:638
#define action_id_get_activity(act_id)
Definition actions.h:712
adv_want adv_settlers_road_bonus(const struct civ_map *nmap, struct tile *ptile, struct road_type *proad)
#define as_transform_action_iterate_end
#define as_rmextra_action_iterate(_act_)
#define as_rmextra_action_iterate_end
#define as_extra_action_iterate_end
#define as_extra_action_iterate(_act_)
#define as_transform_action_iterate(_act_)
int city_map_radius_sq_get(const struct city *pcity)
Definition city.c:132
bool city_can_work_tile(const struct city *pcity, const struct tile *ptile)
Definition city.c:1425
bool can_city_build_unit_now(const struct city *pcity, const struct unit_type *punittype)
Definition city.c:928
#define city_tile(_pcity_)
Definition city.h:544
#define city_tile_iterate_index(_nmap, _radius_sq, _city_tile, _tile, _index)
Definition city.h:193
#define city_owner(_pcity_)
Definition city.h:543
#define city_tile_iterate_end
Definition city.h:230
void package_and_send_worker_tasks(struct city *pcity)
Definition citytools.c:3505
struct unit struct city struct unit struct tile struct extra_type const struct act_prob *act_probs int actor_unit_id struct unit struct unit * punit
Definition dialogs_g.h:73
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:740
struct extra_type * prev_extra_in_tile(const struct tile *ptile, enum extra_rmcause rmcause, const struct player *pplayer, const struct unit *punit)
Definition extras.c:765
enum extra_cause activity_to_extra_cause(enum unit_activity act)
Definition extras.c:1028
bool is_extra_caused_by_action(const struct extra_type *pextra, const struct action *paction)
Definition extras.c:1006
bool is_extra_removed_by_action(const struct extra_type *pextra, const struct action *paction)
Definition extras.c:1017
enum extra_rmcause activity_to_extra_rmcause(enum unit_activity act)
Definition extras.c:1049
#define extra_type_iterate(_p)
Definition extras.h:291
#define extra_type_iterate_end
Definition extras.h:297
#define extra_road_get(_e_)
Definition extras.h:185
#define extra_type_by_cause_iterate_end
Definition extras.h:315
#define extra_type_by_cause_iterate(_cause, _extra)
Definition extras.h:309
float adv_want
Definition fc_types.h:1206
#define EC_NONE
Definition fc_types.h:967
#define ERM_NONE
Definition fc_types.h:992
struct world wld
Definition game.c:58
struct city * game_city_by_number(int id)
Definition game.c:102
adv_want adv_city_worker_act_get(const struct city *pcity, int city_tile_index, enum unit_activity act_id)
Definition infracache.c:359
int adv_city_worker_extra_get(const struct city *pcity, int city_tile_index, const struct extra_type *pextra)
Definition infracache.c:429
int adv_city_worker_rmextra_get(const struct city *pcity, int city_tile_index, const struct extra_type *pextra)
Definition infracache.c:446
adv_want city_tile_value(const struct city *pcity, const struct tile *ptile, int foodneed, int prodneed)
Definition infracache.c:302
#define fc_assert_action(condition, action)
Definition log.h:187
#define log_debug(message,...)
Definition log.h:115
struct terrain_misc terrain_control
Definition map.c:69
#define fc_malloc(sz)
Definition mem.h:34
#define SINGLE_MOVE
Definition movement.h:24
bool road_provides_move_bonus(const struct road_type *proad)
Definition road.c:499
#define FC_INFINITY
Definition shared.h:36
action_id id
Definition actions.h:380
enum action_result result
Definition actions.h:382
Definition ai.h:50
Definition city.h:309
struct worker_task_list * task_reqs
Definition city.h:395
int id
Definition city.h:315
char * name
Definition city.h:310
struct unit_list * units
Definition player.h:282
int move_cost
Definition road.h:78
struct player * plr
Definition taimsg.h:42
void * data
Definition taimsg.h:43
int orig_worst_worked
Definition taicity.c:88
int uw_max_base
Definition taicity.c:85
int old_worst_worked
Definition taicity.c:89
int worst_worked
Definition taicity.c:87
int * wants
Definition taicity.c:90
struct worker_task task
Definition taicity.c:48
Definition tile.h:49
struct unit_list * units
Definition tile.h:57
enum unit_activity activity
Definition unit.h:157
enum unit_activity act
Definition workertask.h:23
struct tile * ptile
Definition workertask.h:22
struct extra_type * tgt
Definition workertask.h:24
struct civ_map map
#define TRUE
Definition support.h:46
#define FALSE
Definition support.h:47
void tai_city_worker_requests_create(struct ai_type *ait, struct player *pplayer, struct city *pcity)
Definition taicity.c:65
#define TWMP
Definition taicity.c:43
static int dummy_wants[U_LAST]
Definition taicity.c:93
void tai_req_worker_task_rcv(struct tai_req *req)
Definition taicity.c:475
tai_worker_task_limitation
Definition taicity.c:51
@ TWTL_BUILDABLE_UNITS
Definition taicity.c:53
@ TWTL_CURRENT_UNITS
Definition taicity.c:52
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)
Definition taicity.c:388
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)
Definition taicity.c:98
void tai_send_req(enum taireqtype type, struct player *pplayer, void *data)
Definition taimsg.c:48
#define tile_worked(_tile)
Definition tile.h:113
#define tile_terrain(_tile)
Definition tile.h:109
#define TILE_XY(ptile)
Definition tile.h:42
#define tile_has_extra(ptile, pextra)
Definition tile.h:146
struct unit * unit_virtual_create(struct player *pplayer, struct city *pcity, const struct unit_type *punittype, int veteran_level)
Definition unit.c:1619
void unit_virtual_destroy(struct unit *punit)
Definition unit.c:1715
#define unit_owner(_pu)
Definition unit.h:387
#define unit_home(_pu_)
Definition unit.h:386
#define unit_list_iterate(unitlist, punit)
Definition unitlist.h:31
#define unit_list_iterate_end
Definition unitlist.h:33
const struct unit_type * unit_type_get(const struct unit *punit)
Definition unittype.c:123
bool unit_has_type_flag(const struct unit *punit, enum unit_type_flag_id flag)
Definition unittype.c:184
Unit_type_id utype_index(const struct unit_type *punittype)
Definition unittype.c:91
#define unit_type_iterate(_p)
Definition unittype.h:838
#define U_LAST
Definition unittype.h:40
#define unit_type_iterate_end
Definition unittype.h:845
void worker_task_init(struct worker_task *ptask)
Definition workertask.c:31