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 const struct civ_map *nmap = &(wld.map);
109
110 if (!city_can_work_tile(pcity, ptile)) {
111 return;
112 }
113
114 orig_value = city_tile_value(pcity, ptile, 0, 0);
115
116 if (tile_worked(ptile) == pcity
117 && orig_value < state->worst_worked) {
118 state->worst_worked = orig_value;
119 state->orig_worst_worked = orig_value;
120 potential_worst_worked = TRUE;
121 }
122
124 bool consider = TRUE;
125 bool possible = FALSE;
126 struct extra_type *tgt = NULL;
127 enum extra_cause cause;
128 enum extra_rmcause rmcause;
129
130 /* Do not request activities that already are under way. */
131 unit_list_iterate(ptile->units, punit) {
132 if (unit_owner(punit) == pplayer
133 && unit_has_type_flag(punit, UTYF_SETTLERS)
135 consider = FALSE;
136 break;
137 }
139
140 if (!consider) {
141 continue;
142 }
143
146
147 unit_list_iterate(units, punit) {
148 if (cause != EC_NONE) {
149 tgt = next_extra_for_tile(ptile, cause, pplayer, punit);
150 } else if (rmcause != ERM_NONE) {
151 tgt = prev_extra_in_tile(ptile, rmcause, pplayer, punit);
152 }
153
156 punit, unit_home(punit), ptile,
157 TRUE,
158 ptile, tgt))) {
159 possible = TRUE;
160 break;
161 }
163
164 if (possible) {
165 int value = adv_city_worker_act_get(pcity, cindex,
167
168 if (tile_worked(ptile) == pcity) {
169 if ((value - orig_value) * TWMP > worked->want) {
170 worked->want = TWMP * (value - orig_value);
171 worked->ptile = ptile;
172 worked->act = action_id_get_activity(act);
173 worked->tgt = NULL;
174 worked->tgt = NULL;
175 if (limit == TWTL_BUILDABLE_UNITS) {
176 unit_list_iterate(units, punit) {
180 ptile,
181 TRUE,
182 ptile, tgt))) {
183 state->wants[utype_index(unit_type_get(punit))] += worked->want;
184 }
186 }
187 }
188 if (value > state->old_worst_worked) {
189 /* After improvement it would not be the worst */
190 potential_worst_worked = FALSE;
191 } else {
192 state->worst_worked = value;
193 }
194 } else {
195 if (value > orig_value && value > state->uw_max) {
196 state->uw_max = value;
197 state->uw_max_base = value;
198 unworked->want = TWMP * (value - orig_value);
199 unworked->ptile = ptile;
200 unworked->act = action_id_get_activity(act);
201 unworked->tgt = NULL;
202 if (limit == TWTL_BUILDABLE_UNITS) {
203 unit_list_iterate(units, punit) {
207 ptile,
208 TRUE,
209 ptile, tgt))) {
210 state->wants[utype_index(unit_type_get(punit))] += unworked->want;
211 }
213 }
214 }
215 }
216 }
218
219 extra_type_iterate(tgt) {
220 struct action *paction = NULL;
221 bool removing = tile_has_extra(ptile, tgt);
222
223 unit_list_iterate(units, punit) {
224 if (removing) {
226 struct action *taction = action_by_number(try_act);
227
228 if (is_extra_removed_by_action(tgt, taction)
230 action_speculate_unit_on_tile(nmap, try_act,
231 punit,
232 unit_home(punit), ptile,
233 TRUE,
234 ptile, tgt))) {
235 paction = taction;
236 break;
237 }
239 } else {
240 as_extra_action_iterate(try_act) {
241 struct action *taction = action_by_number(try_act);
242
243 if (is_extra_caused_by_action(tgt, taction)
245 action_speculate_unit_on_tile(nmap, try_act,
246 punit,
247 unit_home(punit), ptile,
248 TRUE,
249 ptile, tgt))) {
250 paction = taction;
251 break;
252 }
254 }
256
257 if (paction != NULL) {
258 adv_want base_value;
259 int value;
260 adv_want extra;
261 bool consider = TRUE;
262 struct road_type *proad;
263
264 /* Do not request activities that already are under way. */
265 unit_list_iterate(ptile->units, punit) {
266 if (unit_owner(punit) == pplayer
267 && unit_has_type_flag(punit, UTYF_SETTLERS)
268 && punit->activity == actres_get_activity(paction->result)) {
269 consider = FALSE;
270 break;
271 }
273
274 if (!consider) {
275 continue;
276 }
277
278 proad = extra_road_get(tgt);
279
280 if (removing) {
281 base_value = adv_city_worker_rmextra_get(pcity, cindex, tgt);
282 } else {
283 base_value = adv_city_worker_extra_get(pcity, cindex, tgt);
284 }
285
286 if (proad != NULL && road_provides_move_bonus(proad)) {
287 int old_move_cost;
288 int mc_multiplier = 1;
289 int mc_divisor = 1;
290
291 /* Here 'old' means actually 'without the evaluated': In case of
292 * removal activity it's the value after the removal. */
293 old_move_cost = tile_terrain(ptile)->movement_cost * SINGLE_MOVE;
294
295 extra_type_by_cause_iterate(EC_ROAD, poe) {
296 struct road_type *pold = extra_road_get(poe);
297
298 if (tile_has_extra(ptile, poe) && poe != tgt) {
300 && pold->move_cost < old_move_cost) {
301 old_move_cost = pold->move_cost;
302 }
303 }
305
306 if (proad->move_cost < old_move_cost) {
307 if (proad->move_cost >= terrain_control.move_fragments) {
308 mc_divisor = proad->move_cost / terrain_control.move_fragments;
309 } else {
310 if (proad->move_cost == 0) {
311 mc_multiplier = 2;
312 } else {
313 mc_multiplier = 1 - proad->move_cost;
314 }
315 mc_multiplier += old_move_cost;
316 }
317 }
318
319 extra = adv_settlers_road_bonus(&(wld.map), ptile, proad) * mc_multiplier / mc_divisor;
320
321 if (removing) {
322 extra = -extra;
323 }
324 } else {
325 extra = 0;
326 }
327
328 value = base_value + extra;
329
330 if (tile_worked(ptile) == pcity) {
331 if ((value - orig_value) * TWMP > worked->want) {
332 worked->want = TWMP * (value - orig_value);
333 worked->ptile = ptile;
334 worked->act = actres_get_activity(paction->result);
335 worked->tgt = tgt;
336 if (limit == TWTL_BUILDABLE_UNITS) {
337 unit_list_iterate(units, punit) {
338 fc_assert_action(action_get_target_kind(paction) == ATK_TILE,
339 break);
341 nmap, paction->id,
342 punit, unit_home(punit), ptile,
343 TRUE,
344 ptile, tgt))) {
345 state->wants[utype_index(unit_type_get(punit))] += worked->want;
346 }
348 }
349 }
350 if (value > state->old_worst_worked) {
351 /* After improvement it would not be the worst */
352 potential_worst_worked = FALSE;
353 } else {
354 state->worst_worked = value;
355 }
356 } else {
357 if (value > orig_value && value > state->uw_max) {
358 state->uw_max = value;
359 state->uw_max_base = base_value;
360 unworked->want = TWMP * (value - orig_value);
361 unworked->ptile = ptile;
362 unworked->act = actres_get_activity(paction->result);
363 unworked->tgt = tgt;
364 if (limit == TWTL_BUILDABLE_UNITS) {
365 unit_list_iterate(units, punit) {
366 fc_assert_action(action_get_target_kind(paction) == ATK_TILE,
367 break);
369 nmap, paction->id,
370 punit, unit_home(punit), ptile,
371 TRUE,
372 ptile, tgt))) {
373 state->wants[utype_index(unit_type_get(punit))] += unworked->want;
374 }
376 }
377 }
378 }
379 }
381
382 if (potential_worst_worked) {
383 /* Would still be worst worked even if we improved *it*. */
384 state->old_worst_worked = state->worst_worked;
385 }
386}
387
388/**********************************************************************/
391static bool tai_city_worker_task_select(struct ai_type *ait,
392 struct player *pplayer, struct city *pcity,
393 struct worker_task *task,
395{
396 struct worker_task *selected;
397 struct worker_task worked = { .ptile = NULL, .want = 0, .act = ACTIVITY_IDLE, .tgt = NULL };
398 struct worker_task unworked = { .ptile = NULL, .want = 0, .act = ACTIVITY_IDLE, .tgt = NULL };
399 struct tai_tile_state state = { .uw_max = 0, .uw_max_base = 0, .worst_worked = FC_INFINITY,
400 .orig_worst_worked = 0, .old_worst_worked = FC_INFINITY };
401 struct unit_list *units = NULL;
402 const struct civ_map *nmap = &(wld.map);
403
404 switch (limit) {
406 units = pplayer->units;
407 state.wants = NULL;
408 break;
410 units = unit_list_new();
411 unit_type_iterate(ptype) {
412 if (can_city_build_unit_now(nmap, pcity, ptype)) {
413 unit_list_append(units, unit_virtual_create(pplayer, pcity, ptype, 0));
414 }
416 state.wants = dummy_wants;
417 break;
418 }
419
421 ptile, cindex) {
422 tai_tile_worker_task_select(pplayer, pcity, ptile, cindex, units, &worked, &unworked,
423 &state, limit);
425
426 if (worked.ptile == NULL
427 || (state.old_worst_worked < state.uw_max
428 && (state.uw_max - state.orig_worst_worked) * TWMP > worked.want)
429 || (state.uw_max - state.uw_max_base * TWMP > worked.want)) {
430 /* It's better to improve best yet unworked tile and take it to use after that,
431 than to improve already worked tile. OR it's more important to
432 improve road connectivity outside worked tiles than improve worked tiles */
433 selected = &unworked;
434 } else {
435 selected = &worked;
436 }
437
438 if (limit == TWTL_BUILDABLE_UNITS) {
439 unit_list_iterate(units, punit) {
442 unit_list_destroy(units);
443 }
444
445 if (selected->ptile != NULL) {
446 struct extra_type *target = NULL;
447
448 if (selected->tgt == NULL) {
449 enum extra_cause cause = activity_to_extra_cause(selected->act);
450
451 if (cause != EC_NONE) {
452 target = next_extra_for_tile(selected->ptile, cause, pplayer, NULL);
453 } else {
454 enum extra_rmcause rmcause = activity_to_extra_rmcause(selected->act);
455
456 if (rmcause != ERM_NONE) {
457 target = prev_extra_in_tile(selected->ptile, rmcause, pplayer, NULL);
458 }
459 }
460 } else {
461 target = selected->tgt;
462 }
463
464 task->ptile = selected->ptile;
465 task->act = selected->act;
466 task->tgt = target;
467 task->want = selected->want;
468
469 return TRUE;
470 }
471
472 return FALSE;
473}
474
475/**********************************************************************/
479{
480 struct tai_worker_task_req *data = (struct tai_worker_task_req *)req->data;
481 struct city *pcity;
482
483 pcity = game_city_by_number(data->city_id);
484
485 if (pcity != NULL && city_owner(pcity) == req->plr) {
486 /* City has not been lost meanwhile */
487 struct worker_task *ptask = worker_task_list_get(pcity->task_reqs, 0);
488
489 if (ptask == NULL) {
490 ptask = fc_malloc(sizeof(struct worker_task));
491 worker_task_init(ptask);
492 worker_task_list_append(pcity->task_reqs, ptask);
493 }
494
495 log_debug("%s storing req for act %d at (%d,%d)",
496 pcity->name, data->task.act, TILE_XY(data->task.ptile));
497 ptask->ptile = data->task.ptile;
498 ptask->act = data->task.act;
499 ptask->tgt = data->task.tgt;
500 ptask->want = data->task.want;
501
502 /* Send info to observers */
504 }
505
506 free(data);
507}
bool action_prob_possible(const struct act_prob probability)
Definition actions.c:6703
enum unit_activity actres_get_activity(enum action_result result)
Definition actions.c:2136
struct act_prob action_speculate_unit_on_tile(const struct civ_map *nmap, 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:6557
enum action_target_kind action_get_target_kind(const struct action *paction)
Definition actions.c:1740
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 can_city_build_unit_now(const struct civ_map *nmap, const struct city *pcity, const struct unit_type *punittype)
Definition city.c:927
bool city_can_work_tile(const struct city *pcity, const struct tile *ptile)
Definition city.c:1429
#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:3512
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:478
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:391
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:1617
void unit_virtual_destroy(struct unit *punit)
Definition unit.c:1713
#define unit_owner(_pu)
Definition unit.h:394
#define unit_home(_pu_)
Definition unit.h:393
#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:841
#define U_LAST
Definition unittype.h:40
#define unit_type_iterate_end
Definition unittype.h:848
void worker_task_init(struct worker_task *ptask)
Definition workertask.c:31