Freeciv-3.4
Loading...
Searching...
No Matches
autoworkers.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#include <math.h>
19#include <stdio.h>
20#include <string.h>
21
22/* utility */
23#include "log.h"
24#include "mem.h"
25#include "support.h"
26#include "timing.h"
27
28/* common */
29#include "ai.h"
30#include "city.h"
31#include "game.h"
32#include "government.h"
33#include "map.h"
34#include "movement.h"
35#include "nation.h"
36#include "packets.h"
37#include "unitlist.h"
38
39/* common/aicore */
40#include "citymap.h"
41#include "path_finding.h"
42#include "pf_tools.h"
43
44/* server */
45#include "citytools.h"
46#include "maphand.h"
47#include "plrhand.h"
48#include "srv_log.h"
49#include "unithand.h"
50#include "unittools.h"
51
52/* server/advisors */
53#include "advbuilding.h"
54#include "advdata.h"
55#include "advgoto.h"
56#include "advtools.h"
57#include "infracache.h"
58
59/* ai */
60#include "handicaps.h"
61
62#include "autoworkers.h"
63
64/* This factor is multiplied on when calculating the want. This is done
65 * to avoid rounding errors in comparisons when looking for the best
66 * possible work. However before returning the final want we have to
67 * divide by it again. This loses accuracy but is needed since the want
68 * values are used for comparison by the AI in trying to calculate the
69 * goodness of building worker units. */
70#define WORKER_FACTOR 1024
71
72struct workermap {
73 int enroute; /* Unit ID of worker en route to this tile */
74 int eta; /* Estimated number of turns until enroute arrives */
75};
76
80
81static struct timer *aw_timer = NULL;
82
83/**********************************************************************/
87{
89 aw_timer = NULL;
90}
91
92/**********************************************************************/
125
126/**********************************************************************/
133 struct tile *ptile, struct road_type *proad)
134{
135#define MAX_DEP_ROADS 5
136
137 int bonus = 0, i;
138 bool potential_road[12], real_road[12], is_slow[12];
139 int dx[12] = {-1, 0, 1, -1, 1, -1, 0, 1, 0, -2, 2, 0};
140 int dy[12] = {-1, -1, -1, 0, 0, 1, 1, 1, -2, 0, 0, 2};
141 int x, y;
142 int rnbr;
145 int dep_count = 0;
146 struct extra_type *pextra;
147
148 if (proad == NULL) {
149 return 0;
150 }
151
153 pextra = road_extra_get(proad);
154
155 road_deps_iterate(&(pextra->reqs), pdep) {
156 if (dep_count < MAX_DEP_ROADS) {
159 }
161
162 index_to_map_pos(&x, &y, tile_index(ptile));
163 for (i = 0; i < 12; i++) {
164 struct tile *tile1 = map_pos_to_tile(nmap, x + dx[i], y + dy[i]);
165
166 if (!tile1) {
167 real_road[i] = FALSE;
169 is_slow[i] = FALSE; /* FIXME: should be TRUE? */
170 } else {
172 int j;
173
176 for (j = 0 ; !potential_road[i] && j < dep_count ; j++) {
178 }
179
180 /* If TRUE, this value indicates that this tile does not need
181 * a road connector. This is set for terrains which cannot have
182 * road or where road takes "too long" to build. */
183 is_slow[i] = (build_time == 0 || build_time > 5);
184
185 if (!real_road[i]) {
186 unit_list_iterate(tile1->units, punit) {
188 /* If a road, or its dependency is being built here, consider as if it's already
189 * built. */
190 int build_rnbr;
191
193
195
196 if (build_rnbr == rnbr) {
197 real_road[i] = TRUE;
199 }
200 for (j = 0 ; !potential_road[i] && j < dep_count ; j++) {
201 if (build_rnbr == dep_rnbr[j]) {
203 }
204 }
205 }
207 }
208 }
209 }
210
212 /* On hex map, road is always a benefit */
213 bonus += 20; /* Later divided by 20 */
214
215 /* Road is more valuable when even longer road around does not exist. */
216 for (i = 0; i < 12; i++) {
217 if (!real_road[i]) {
218 bonus += 3;
219 }
220 }
221
222 /* Scale down the bonus. */
223 bonus /= 20;
224 } else {
225 /*
226 * Consider the following tile arrangement (numbered in hex):
227 *
228 * 8
229 * 012
230 * 93 4A
231 * 567
232 * B
233 *
234 * these are the tiles defined by the (dx,dy) arrays above.
235 *
236 * Then the following algorithm is supposed to determine if it's a good
237 * idea to build a road here. Note this won't work well for hex maps
238 * since the (dx,dy) arrays will not cover the same tiles.
239 *
240 * FIXME: if you can understand the algorithm below please rewrite this
241 * explanation!
242 */
243 if (potential_road[0]
244 && !real_road[1] && !real_road[3]
245 && (!real_road[2] || !real_road[8])
246 && (!is_slow[2] || !is_slow[4] || !is_slow[7]
247 || !is_slow[6] || !is_slow[5])) {
248 bonus++;
249 }
250 if (potential_road[2]
251 && !real_road[1] && !real_road[4]
252 && (!real_road[7] || !real_road[10])
253 && (!is_slow[0] || !is_slow[3] || !is_slow[7]
254 || !is_slow[6] || !is_slow[5])) {
255 bonus++;
256 }
257 if (potential_road[5]
258 && !real_road[6] && !real_road[3]
259 && (!real_road[5] || !real_road[11])
260 && (!is_slow[2] || !is_slow[4] || !is_slow[7]
261 || !is_slow[1] || !is_slow[0])) {
262 bonus++;
263 }
264 if (potential_road[7]
265 && !real_road[6] && !real_road[4]
266 && (!real_road[0] || !real_road[9])
267 && (!is_slow[2] || !is_slow[3] || !is_slow[0]
268 || !is_slow[1] || !is_slow[5])) {
269 bonus++;
270 }
271
272 /* A
273 * B*B
274 * CCC
275 *
276 * We are at tile *. If tile A has a road, and neither B tile does, and
277 * one C tile is a valid destination, then we might want a road here.
278 *
279 * Of course the same logic applies if you rotate the diagram.
280 */
281 if (potential_road[1] && !real_road[4] && !real_road[3]
282 && (!is_slow[5] || !is_slow[6] || !is_slow[7])) {
283 bonus++;
284 }
285 if (potential_road[3] && !real_road[1] && !real_road[6]
286 && (!is_slow[2] || !is_slow[4] || !is_slow[7])) {
287 bonus++;
288 }
289 if (potential_road[4] && !real_road[1] && !real_road[6]
290 && (!is_slow[0] || !is_slow[3] || !is_slow[5])) {
291 bonus++;
292 }
293 if (potential_road[6] && !real_road[4] && !real_road[3]
294 && (!is_slow[0] || !is_slow[1] || !is_slow[2])) {
295 bonus++;
296 }
297 }
298
299 return bonus;
300}
301
302/**********************************************************************/
308static void consider_worker_action(const struct player *pplayer,
309 enum unit_activity act,
310 struct extra_type *target,
311 adv_want extra,
314 bool in_use, int delay,
317 int *best_extra,
318 bool *improve_worked,
319 int *best_delay,
321 struct extra_type **best_target,
322 struct tile **best_tile,
323 struct tile *ptile)
324{
325 bool improves;
327 adv_want base_value = 0;
329
330 fc_assert(act != ACTIVITY_LAST);
331
332 if (extra < 0) {
333 extra = 0;
334 }
335
337 improves = TRUE;
338 } else if (ADV_WANTS_EQ(new_tile_value, old_tile_value) && extra > 0) {
339 improves = TRUE;
340 } else {
341 improves = FALSE;
342 }
343
344 /* find the present value of the future benefit of this action */
345 if (improves || extra > 0) {
346 if (!(*improve_worked) && !in_use) {
347 /* Going to improve tile that is not yet in use.
348 * Getting the best possible total for next citizen to work on is more
349 * important than amount tile gets improved. */
355 *best_extra = extra;
356 *best_act = act;
357 *best_target = target;
358 *best_tile = ptile;
359 *best_delay = delay;
360 }
361
362 return;
363 }
364
365 /* At least one of the previous best or current tile is in use
366 * Prefer the tile that gets improved more, regardless of
367 * the resulting total */
368
369 base_value = new_tile_value - old_tile_value;
370 total_value = base_value * WORKER_FACTOR;
371 if (!in_use) {
372 total_value /= 2;
373 }
374 total_value += extra * WORKER_FACTOR;
375
376 /* Use factor to prevent rounding errors */
378
379 if (*improve_worked) {
381 } else {
382 /* Convert old best_value to improvement value compatible with in_use
383 * tile value */
385 *best_delay);
386 }
387
391 if (in_use) {
394 } else {
397 }
399 *best_extra = extra;
400 *best_act = act;
401 *best_target = target;
402 *best_tile = ptile;
403 *best_delay = delay;
404 }
405 }
406}
407
408/**********************************************************************/
411static enum tile_behavior
412autoworker_tile_behavior(const struct tile *ptile,
413 enum known_type known,
414 const struct pf_parameter *param)
415{
416 const struct player *owner = tile_owner(ptile);
417
418 if (NULL != owner && !pplayers_allied(owner, param->owner)) {
419 return TB_IGNORE;
420 }
421
422 return TB_NORMAL;
423}
424
425/**********************************************************************/
443 struct unit *punit,
445 struct extra_type **best_target,
446 struct tile **best_tile,
447 struct pf_path **ppath,
448 struct workermap *state)
449{
450 const struct player *pplayer = unit_owner(punit);
451 struct pf_parameter parameter;
452 struct pf_map *pfm;
453 struct pf_position pos;
454 adv_want oldv; /* Current value of consideration tile. */
455 adv_want best_oldv = 9999; /* oldv of best target so far; compared if
456 * newv == best_newv; not initialized to zero,
457 * so that newv = 0 activities are not chosen. */
459 bool improve_worked = FALSE;
460 int best_extra = 0;
461 int best_delay = 0;
462
463 /* Closest worker, if any, headed towards target tile */
464 struct unit *enroute = NULL;
465
466 pft_fill_unit_parameter(&parameter, nmap, punit);
467 parameter.omniscience = !has_handicap(pplayer, H_MAP);
469 pfm = pf_map_new(&parameter);
470
471 city_list_iterate(pplayer->cities, pcity) {
472 struct tile *pcenter = city_tile(pcity);
473
474 /* Try to work near the city */
476 cindex) {
477 bool consider = TRUE;
478 bool in_use = (tile_worked(ptile) == pcity);
479
480 if (!in_use && !city_can_work_tile(pcity, ptile)) {
481 /* Don't risk bothering with this tile. */
482 continue;
483 }
484
485 if (!adv_worker_safe_tile(nmap, pplayer, punit, ptile)) {
486 /* Too dangerous place */
487 continue;
488 }
489
490 /* Do not go to tiles that already have workers there. */
491 unit_list_iterate(ptile->units, aunit) {
492 if (unit_owner(aunit) == pplayer
493 && aunit->id != punit->id
495 consider = FALSE;
496 }
498
499 if (!consider) {
500 continue;
501 }
502
503 if (state) {
504 enroute = player_unit_by_number(pplayer,
505 state[tile_index(ptile)].enroute);
506 }
507
508 if (pf_map_position(pfm, ptile, &pos)) {
509 int eta = FC_INFINITY, inbound_distance = FC_INFINITY, turns;
510
511 if (enroute) {
512 eta = state[tile_index(ptile)].eta;
514 }
515
516 /* Only consider this tile if we are closer in time and space to
517 * it than our other worker (if any) travelling to the site. */
518 if ((enroute && enroute->id == punit->id)
519 || pos.turn < eta
520 || (pos.turn == eta
522 < inbound_distance))) {
523
524 if (enroute) {
526 "Considering (%d, %d) because we're closer "
527 "(%d, %d) than %d (%d, %d)",
528 TILE_XY(ptile), pos.turn,
530 enroute->id, eta, inbound_distance);
531 }
532
533 oldv = city_tile_value(pcity, ptile, 0, 0);
534
535 /* Now, consider various activities... */
537 struct extra_type *target = NULL;
538 enum extra_cause cause =
542
543 if (cause != EC_NONE) {
544 target = next_extra_for_tile(ptile, cause, pplayer,
545 punit);
546 } else if (rmcause != ERM_NONE) {
547 target = prev_extra_in_tile(ptile, rmcause, pplayer,
548 punit);
549 }
550
551 if (adv_city_worker_act_get(pcity, cindex,
552 action_id_get_activity(act)) >= 0
556 ptile,
557 parameter.omniscience,
558 ptile, target))) {
559 adv_want base_value
562
563 turns = pos.turn
566 ptile, target);
567 if (pos.moves_left == 0) {
568 /* We need moves left to begin activity immediately. */
569 turns++;
570 }
571
574 target, 0.0, base_value,
575 oldv, in_use, turns,
579 best_tile, ptile);
580
581 } /* endif: can the worker perform this action */
583
584 extra_type_iterate(pextra) {
585 enum unit_activity act = ACTIVITY_LAST;
587 adv_want base_value;
588 bool removing = tile_has_extra(ptile, pextra);
589
590 if (removing) {
593
594 if (is_extra_removed_by_action(pextra, taction)) {
595 /* We do not even evaluate actions we can't do.
596 * Removal is not considered prerequisite for anything */
599 punit,
601 ptile,
602 parameter.omniscience,
603 ptile, pextra))) {
606 break;
607 }
608 }
610 } else {
613
614 if (is_extra_caused_by_action(pextra, taction)) {
618 punit,
620 ptile,
621 parameter.omniscience,
622 ptile, pextra))) {
624 break;
625 }
626 }
628 }
629
630 if (eval_act == ACTIVITY_LAST) {
631 /* No activity can provide (or remove) the extra */
632 continue;
633 }
634
635 if (removing) {
636 base_value = adv_city_worker_rmextra_get(pcity, cindex, pextra);
637 } else {
638 base_value = adv_city_worker_extra_get(pcity, cindex, pextra);
639 }
640
641 if (base_value >= 0) {
642 adv_want extra;
643 struct road_type *proad;
644
646 ptile, pextra);
647 if (pos.moves_left == 0) {
648 /* We need moves left to begin activity immediately. */
649 turns++;
650 }
651
652 proad = extra_road_get(pextra);
653
655 int mc_multiplier = 1;
656 int mc_divisor = 1;
657 int old_move_cost = tile_terrain(ptile)->movement_cost * SINGLE_MOVE;
658
659 /* Here 'old' means actually 'without the evaluated': In case of
660 * removal activity it's the value after the removal. */
661
663 if (tile_has_extra(ptile, pold) && pold != pextra) {
665
666 /* This ignores the fact that new road may be native to units that
667 * old road is not. */
668 if (po_road->move_cost < old_move_cost) {
669 old_move_cost = po_road->move_cost;
670 }
671 }
673
674 if (proad->move_cost < old_move_cost) {
675 if (proad->move_cost >= terrain_control.move_fragments) {
676 mc_divisor = proad->move_cost / terrain_control.move_fragments;
677 } else {
678 if (proad->move_cost == 0) {
679 mc_multiplier = 2;
680 } else {
681 mc_multiplier = 1 - proad->move_cost;
682 }
684 }
685 }
686
687 extra = adv_workers_road_bonus(nmap, ptile, proad)
689
690 } else {
691 extra = 0;
692 }
693
694 if (extra_has_flag(pextra, EF_GLOBAL_WARMING)) {
695 extra -= pplayer->ai_common.warmth;
696 }
697 if (extra_has_flag(pextra, EF_NUCLEAR_WINTER)) {
698 extra -= pplayer->ai_common.frost;
699 }
700
701 if (removing) {
702 extra = -extra;
703 }
704
705 if (act != ACTIVITY_LAST) {
706 consider_worker_action(pplayer, act, pextra, extra, base_value,
707 oldv, in_use, turns,
711 best_tile, ptile);
712 } else {
714
715 road_deps_iterate(&(pextra->reqs), pdep) {
716 struct extra_type *dep_tgt;
717
719
722 punit, unit_home(punit), ptile,
723 parameter.omniscience,
724 ptile, dep_tgt))) {
725 /* Consider building dependency road for later upgrade to target extra.
726 * Here we set value to be sum of dependency
727 * road and target extra values, which increases want, and turns is sum
728 * of dependency and target build turns, which decreases want. This can
729 * result in either bigger or lesser want than when checking dependency
730 * road for the sake of itself when its turn in extra_type_iterate() is. */
731 int dep_turns
734 ptile, dep_tgt);
736 = base_value + adv_city_worker_extra_get(pcity, cindex,
737 dep_tgt);
738
740 dep_tgt, extra, dep_value,
745 best_tile, ptile);
746 }
748
749 extra_deps_iterate(&(pextra->reqs), pdep) {
750 /* Roads handled above already */
754
757
761 break;
762 }
764
768 punit, unit_home(punit), ptile,
769 parameter.omniscience,
770 ptile, pdep))) {
771 /* Consider building dependency extra for later upgrade to
772 * target extra. See similar road implementation above for
773 * extended commentary. */
774 int dep_turns
777 ptile, pdep);
779 = base_value + adv_city_worker_extra_get(pcity,
780 cindex,
781 pdep);
782
784 0.0, dep_value, oldv, in_use,
786 &best_oldv,
788 &best_delay,
790 best_tile, ptile);
791 }
792 }
793 }
795 }
796 }
798 } /* endif: can we arrive sooner than current worker, if any? */
799 } /* endif: are we travelling to a legal destination? */
802
803 if (!improve_worked) {
804 /* best_newv contains total value of improved tile. Check amount
805 * of improvement instead. */
807 best_delay);
808 }
810
811 best_newv = MAX(best_newv, 0); /* sanity */
812
813 if (best_newv > 0) {
814 log_debug("Worker %d@(%d,%d) wants to %s at (%d,%d) with desire "
818 } else {
819 /* Fill in dummy values. The callers should check if the return value
820 * is > 0 but this will avoid confusing them. */
822 *best_tile = NULL;
823 }
824
825 if (ppath) {
826 if (*ppath != nullptr) {
828 }
830 }
831
833
834 return best_newv;
835}
836
837/**********************************************************************/
841 struct worker_task **best_task,
842 struct pf_path **ppath,
843 struct workermap *state)
844{
845 const struct player *pplayer = unit_owner(punit);
846 struct pf_parameter parameter;
847 struct pf_map *pfm;
848 struct pf_position pos;
849 int best_value = -1;
850 struct worker_task *best = NULL;
851 struct city *taskcity = NULL;
852 int dist = FC_INFINITY;
853 const struct civ_map *nmap = &(wld.map);
854
855 pft_fill_unit_parameter(&parameter, nmap, punit);
856 parameter.omniscience = !has_handicap(pplayer, H_MAP);
858 pfm = pf_map_new(&parameter);
859
860 /* Have nearby cities requests? */
861 city_list_iterate(pplayer->cities, pcity) {
863 bool consider = TRUE;
864
865 /* Do not go to tiles that already have workers there. */
866 unit_list_iterate(ptask->ptile->units, aunit) {
867 if (unit_owner(aunit) == pplayer
868 && aunit->id != punit->id
870 consider = FALSE;
871 }
873
874 if (consider
876 parameter.omniscience,
877 ptask->tgt, ptask->ptile)) {
878 /* Closest worker, if any, headed towards target tile */
879 struct unit *enroute = NULL;
880
881 if (state) {
882 enroute = player_unit_by_number(pplayer,
883 state[tile_index(ptask->ptile)].enroute);
884 }
885
886 if (pf_map_position(pfm, ptask->ptile, &pos)) {
887 int value = (ptask->want + 1) * 10 / (pos.turn + 1);
888
889 if (value > best_value) {
891
892 if (enroute) {
893 eta = state[tile_index(ptask->ptile)].eta;
895 }
896
897 /* Only consider this tile if we are closer in time and space to
898 * it than our other worker (if any) travelling to the site. */
899 if (pos.turn < dist
900 && ((enroute && enroute->id == punit->id)
901 || pos.turn < eta
902 || (pos.turn == eta
904 < inbound_distance)))) {
905 dist = pos.turn;
906 best = ptask;
907 best_value = value;
908 taskcity = pcity;
909 }
910 }
911 }
912 }
915
916 *best_task = best;
917
918 if (ppath != NULL) {
919 if (*ppath != NULL) {
921 }
922 *ppath = best ? pf_map_path(pfm, best->ptile) : NULL;
923 }
924
926
927 return taskcity;
928}
929
930/**********************************************************************/
933#define LOG_WORKER LOG_DEBUG
935 struct player *pplayer,
936 struct unit *punit,
937 struct workermap *state,
938 int recursion)
939{
940 struct worker_task *best_task;
942 struct tile *best_tile = NULL;
943 struct extra_type *best_target;
944 struct pf_path *path = NULL;
945 struct city *taskcity;
946
947 /* Time it will take worker to complete its given task */
948 int completion_time = 0;
949
950 /* Terminate what might be an infinite recursion of two units
951 * displacing each other, but leave enough space for
952 * finite recursion. */
953 if (recursion > 5
954 && recursion > unit_list_size(pplayer->units) * 1.5) {
955 log_warn("Workers displacing each other recursing too much.");
956
960
961 return; /* Avoid further recursion. */
962 }
963
965
966 fc_assert_ret(pplayer && punit);
969
970 /* Have nearby cities requests? */
971
973
974 if (taskcity != NULL) {
975 if (path != NULL) {
977 }
978
980
981 best_target = best_task->tgt;
982
983 if (auto_worker_setup_work(nmap, pplayer, punit, state, recursion,
984 &path, best_task->ptile, best_task->act,
987 }
988
989 if (path != NULL) {
990 pf_path_destroy(path);
991 }
992
993 return;
994 }
995
996 /*** Try find some work ***/
997
1001 &best_tile, &path, state);
1002 if (path) {
1004 }
1006
1008
1009 auto_worker_setup_work(nmap, pplayer, punit, state, recursion, &path,
1012
1013 if (NULL != path) {
1014 pf_path_destroy(path);
1015 }
1016 }
1017}
1018
1019/**********************************************************************/
1024 struct player *pplayer, struct unit *punit,
1025 struct workermap *state, int recursion,
1026 struct pf_path **ppath,
1027 struct tile *best_tile,
1029 struct extra_type **best_target,
1030 int completion_time)
1031{
1032 /* Run the "autoworker" program */
1033 if (punit->server.adv->task == AUT_AUTO_WORKER) {
1034 struct pf_map *pfm = NULL;
1035 struct pf_parameter parameter;
1036 bool working = FALSE;
1037 struct unit *displaced;
1038
1039 if (!best_tile) {
1040 UNIT_LOG(LOG_DEBUG, punit, "giving up trying to improve terrain");
1041 return FALSE; /* We cannot do anything */
1042 }
1043
1044 /* Mark the square as taken. */
1046 state[tile_index(best_tile)].enroute);
1047
1048 if (displaced) {
1049 fc_assert(state[tile_index(best_tile)].enroute == displaced->id);
1051 || (state[tile_index(best_tile)].eta == completion_time
1054 unit_tile(displaced)))));
1055 UNIT_LOG(displaced->server.debug ? LOG_AI_TEST : LOG_DEBUG, punit,
1056 "%d (%d,%d) has displaced %d (%d,%d) for worksite %d,%d",
1059 displaced->id, state[tile_index(best_tile)].eta,
1062 }
1063
1064 state[tile_index(best_tile)].enroute = punit->id;
1066
1067 if (displaced) {
1068 struct tile *goto_tile = punit->goto_tile;
1069 int saved_id = punit->id;
1070 struct tile *old_pos = unit_tile(punit);
1071
1072 displaced->goto_tile = NULL;
1073 auto_worker_findwork(nmap, pplayer, displaced, state, recursion + 1);
1074 if (NULL == player_unit_by_number(pplayer, saved_id)) {
1075 /* Actions of the displaced worker somehow caused this worker
1076 * to die. (maybe by recursively giving control back to this unit)
1077 */
1078 return FALSE;
1079 }
1080 if (goto_tile != punit->goto_tile || old_pos != unit_tile(punit)
1081 || punit->activity != ACTIVITY_IDLE) {
1082 /* Actions of the displaced worker somehow caused this worker
1083 * to get a new job, or to already move toward current job.
1084 * (A displaced B, B displaced C, C displaced A)
1085 */
1087 "%d itself acted due to displacement recursion. "
1088 "Was going from (%d, %d) to (%d, %d). "
1089 "Now heading from (%d, %d) to (%d, %d).",
1090 punit->id,
1091 TILE_XY(old_pos), TILE_XY(goto_tile),
1093 return FALSE;
1094 }
1095 }
1096
1098 "is heading to do %s(%s) at (%d, %d)",
1102
1103 if (ppath != nullptr && *ppath == nullptr) {
1104 pft_fill_unit_parameter(&parameter, nmap, punit);
1105 parameter.omniscience = !has_handicap(pplayer, H_MAP);
1106 parameter.get_TB = autoworker_tile_behavior;
1107 pfm = pf_map_new(&parameter);
1109 }
1110
1111 if (ppath != nullptr && *ppath != nullptr) {
1112 bool alive;
1113
1115
1117 && punit->moves_left > 0) {
1119
1120 /* Reached destination and can start working immediately */
1123 action);
1124 } else {
1126 }
1127 send_unit_info(NULL, punit); /* FIXME: Probably duplicate */
1128
1130 "reached its worksite and started work");
1131 working = TRUE;
1132 } else if (alive) {
1134 "didn't start work yet; got to (%d, %d) with "
1135 "%d move frags left", TILE_XY(unit_tile(punit)),
1136 punit->moves_left);
1137 }
1139 *ppath = NULL;
1140 } else {
1142 "does not find path (%d, %d) -> (%d, %d)",
1144 }
1145
1146 if (pfm) {
1148 }
1149
1150 return working;
1151 }
1152
1153 return FALSE;
1154}
1155#undef LOG_WORKER
1156
1157/**********************************************************************/
1161 const struct player *pplayer, struct unit *punit,
1162 struct tile *ptile)
1163{
1164 unit_list_iterate(ptile->units, defender) {
1165 if (is_guard_unit(defender)) {
1166 return TRUE;
1167 }
1169
1170 if (is_square_threatened(nmap, pplayer, ptile,
1171 !has_handicap(pplayer, H_FOG))) {
1172 return FALSE;
1173 }
1174
1175 return TRUE;
1176}
1177
1178/**********************************************************************/
1182void auto_workers_player(struct player *pplayer)
1183{
1184 struct workermap *state;
1185 const struct civ_map *nmap = &(wld.map);
1186
1187 state = fc_calloc(MAP_INDEX_SIZE, sizeof(*state));
1188
1190 aw_timer != NULL ? NULL : "autoworkers");
1192
1193 if (is_ai(pplayer)) {
1194 /* Set up our city map. */
1195 citymap_turn_init(pplayer);
1196 }
1197
1198 whole_map_iterate(nmap, ptile) {
1199 state[tile_index(ptile)].enroute = -1;
1200 state[tile_index(ptile)].eta = FC_INFINITY;
1202
1203 /* Initialize the infrastructure cache, which is used shortly. */
1205
1206 /* An extra consideration for the benefit of cleaning up pollution/fallout.
1207 * This depends heavily on the calculations in update_environmental_upset.
1208 * Aside from that it's more or less a WAG that simply grows incredibly
1209 * large as an environmental disaster approaches. */
1210 pplayer->ai_common.warmth
1213 pplayer->ai_common.frost
1216
1217 log_debug("Warmth = %d, game.globalwarming=%d",
1219 log_debug("Frost = %d, game.nuclearwinter=%d",
1221
1222 /* Auto-work with a worker unit if it's under AI control (e.g. human
1223 * player autoworker mode) or if the player is an AI. But don't
1224 * autowork with a unit under orders even for an AI player - these come
1225 * from the human player and take precedence. */
1227 if ((punit->ssa_controller == SSA_AUTOWORKER || is_ai(pplayer))
1228 && (unit_type_get(punit)->adv.worker
1231 && punit->moves_left > 0) {
1232 log_debug("%s %s at (%d, %d) is controlled by server side agent %s.",
1237 if (punit->activity == ACTIVITY_SENTRY) {
1239 }
1240 if (punit->activity == ACTIVITY_GOTO && punit->moves_left > 0) {
1242 }
1243 if (punit->activity != ACTIVITY_IDLE) {
1244 if (!is_ai(pplayer)) {
1245 if (!adv_worker_safe_tile(nmap, pplayer, punit,
1246 unit_tile(punit))) {
1248 }
1249 } else {
1250 CALL_PLR_AI_FUNC(settler_cont, pplayer, pplayer, punit, state);
1251 }
1252 }
1253 if (punit->activity == ACTIVITY_IDLE) {
1254 if (!is_ai(pplayer)) {
1255 auto_worker_findwork(nmap, pplayer, punit, state, 0);
1256 } else {
1257 CALL_PLR_AI_FUNC(settler_run, pplayer, pplayer, punit, state);
1258 }
1259 }
1260 }
1262 /* Reset auto worker state for the next run. */
1263 if (is_ai(pplayer)) {
1264 CALL_PLR_AI_FUNC(settler_reset, pplayer, pplayer);
1265 }
1266
1267 if (timer_in_use(aw_timer)) {
1268
1269#ifdef LOG_TIMERS
1270 log_verbose("%s autoworkers consumed %g milliseconds.",
1272 1000.0 * timer_read_seconds(aw_timer));
1273#else
1274 log_verbose("%s autoworkers finished",
1276#endif
1277
1278 }
1279
1280 FC_FREE(state);
1281}
1282
1283/**********************************************************************/
1287 struct tile *ptile)
1288{
1289 if (punit->server.adv->task == task) {
1290 /* Already that task */
1291 return;
1292 }
1293
1294 punit->server.adv->task = task;
1295
1296 CALL_PLR_AI_FUNC(unit_task, unit_owner(punit), punit, task, ptile);
1297}
1298
1299/**********************************************************************/
1304 enum unit_activity activity,
1305 bool omniscient_cheat,
1306 struct extra_type *target,
1307 const struct tile *ptile)
1308{
1309 const struct civ_map *nmap = &(wld.map);
1310
1313 /* Not relevant. */
1314 continue;
1315 }
1316
1318 case ATK_CITY:
1320 nmap, paction->id,
1321 punit, unit_home(punit), ptile,
1323 tile_city(ptile)));
1324 case ATK_UNIT:
1326 FALSE);
1327 break;
1328 case ATK_STACK:
1330 nmap, paction->id,
1331 punit, unit_home(punit), ptile,
1333 ptile));
1334 case ATK_TILE:
1336 nmap, paction->id,
1337 punit, unit_home(punit), ptile,
1339 ptile, target));
1340 case ATK_EXTRAS:
1342 nmap, paction->id,
1343 punit, unit_home(punit), ptile,
1345 ptile, target));
1346 case ATK_SELF:
1348 nmap, paction->id,
1349 punit, unit_home(punit), ptile,
1351 case ATK_COUNT:
1353 FALSE);
1354 break;
1355 }
1357
1358 log_debug("No action found for activity %d", activity);
1359
1360 return FALSE;
1361}
struct act_prob action_speculate_unit_on_extras(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:5205
enum action_actor_kind action_get_actor_kind(const struct action *paction)
Definition actions.c:1119
bool action_prob_possible(const struct act_prob probability)
Definition actions.c:5317
struct act_prob action_speculate_unit_on_stack(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)
Definition actions.c:5138
struct act_prob action_speculate_unit_on_self(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)
Definition actions.c:5239
void action_array_add_all_by_result(action_id *act_array, int *position, enum action_result result)
Definition actions.c:6021
void action_array_end(action_id *act_array, int size)
Definition actions.c:6004
struct act_prob action_speculate_unit_on_city(const struct civ_map *nmap, const action_id act_id, const struct unit *actor, const struct city *actor_home, const struct tile *actor_tile, const bool omniscient_cheat, const struct city *target)
Definition actions.c:5070
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:5171
enum action_target_kind action_get_target_kind(const struct action *paction)
Definition actions.c:1129
#define action_by_activity_iterate(_paction_, _activity_)
Definition actions.h:253
static struct action * action_by_number(action_id act_id)
Definition actions.h:400
#define action_by_activity_iterate_end
Definition actions.h:257
#define MAX_NUM_ACTIONS
Definition actions.h:62
#define action_get_activity(_pact_)
Definition actions.h:464
#define action_id_get_activity(act_id)
Definition actions.h:466
#define ACTION_NONE
Definition actions.h:59
#define COOLING_FACTOR
Definition advbuilding.h:31
#define WARMING_FACTOR
Definition advbuilding.h:30
bool adv_follow_path(struct unit *punit, struct pf_path *path, struct tile *ptile)
Definition advgoto.c:47
adv_want amortize(adv_want benefit, int delay)
Definition advtools.c:29
#define ADV_WANTS_EQ(_w1, _w2)
Definition advtools.h:23
#define CALL_PLR_AI_FUNC(_func, _player,...)
Definition ai.h:377
void adv_unit_new_task(struct unit *punit, enum adv_unit_task task, struct tile *ptile)
struct city * worker_evaluate_city_requests(struct unit *punit, struct worker_task **best_task, struct pf_path **ppath, struct workermap *state)
static void consider_worker_action(const struct player *pplayer, enum unit_activity act, struct extra_type *target, adv_want extra, adv_want new_tile_value, adv_want old_tile_value, bool in_use, int delay, adv_want *best_value, adv_want *best_old_tile_value, int *best_extra, bool *improve_worked, int *best_delay, enum unit_activity *best_act, struct extra_type **best_target, struct tile **best_tile, struct tile *ptile)
static enum tile_behavior autoworker_tile_behavior(const struct tile *ptile, enum known_type known, const struct pf_parameter *param)
void auto_worker_findwork(const struct civ_map *nmap, struct player *pplayer, struct unit *punit, struct workermap *state, int recursion)
bool adv_worker_safe_tile(const struct civ_map *nmap, const struct player *pplayer, struct unit *punit, struct tile *ptile)
static struct timer * aw_timer
Definition autoworkers.c:81
void adv_workers_free(void)
Definition autoworkers.c:86
bool auto_worker_setup_work(const struct civ_map *nmap, struct player *pplayer, struct unit *punit, struct workermap *state, int recursion, struct pf_path **ppath, struct tile *best_tile, enum unit_activity best_act, struct extra_type **best_target, int completion_time)
action_id aw_actions_rmextra[MAX_NUM_ACTIONS]
Definition autoworkers.c:79
adv_want adv_workers_road_bonus(const struct civ_map *nmap, struct tile *ptile, struct road_type *proad)
adv_want worker_evaluate_improvements(const struct civ_map *nmap, struct unit *punit, enum unit_activity *best_act, struct extra_type **best_target, struct tile **best_tile, struct pf_path **ppath, struct workermap *state)
bool auto_workers_speculate_can_act_at(const struct unit *punit, enum unit_activity activity, bool omniscient_cheat, struct extra_type *target, const struct tile *ptile)
void auto_workers_player(struct player *pplayer)
action_id aw_actions_extra[MAX_NUM_ACTIONS]
Definition autoworkers.c:78
action_id aw_actions_transform[MAX_NUM_ACTIONS]
Definition autoworkers.c:77
void auto_workers_ruleset_init(void)
Definition autoworkers.c:95
#define WORKER_FACTOR
Definition autoworkers.c:70
#define MAX_DEP_ROADS
#define aw_extra_action_iterate(_act_)
Definition autoworkers.h:84
#define aw_transform_action_iterate(_act_)
Definition autoworkers.h:74
#define aw_rmextra_action_iterate_end
Definition autoworkers.h:98
#define aw_extra_action_iterate_end
Definition autoworkers.h:88
#define aw_transform_action_iterate_end
Definition autoworkers.h:78
#define aw_rmextra_action_iterate(_act_)
Definition autoworkers.h:94
int city_map_radius_sq_get(const struct city *pcity)
Definition city.c:137
bool city_can_work_tile(const struct city *pcity, const struct tile *ptile)
Definition city.c:1456
#define city_list_iterate(citylist, pcity)
Definition city.h:508
#define city_tile(_pcity_)
Definition city.h:564
#define city_tile_iterate_index(_nmap, _radius_sq, _city_tile, _tile, _index)
Definition city.h:199
#define city_tile_iterate_index_end
Definition city.h:207
#define city_list_iterate_end
Definition city.h:510
void citymap_turn_init(struct player *pplayer)
Definition citymap.c:61
void clear_worker_task(struct city *pcity, struct worker_task *ptask)
Definition citytools.c:3592
char * incite_cost
Definition comments.c:77
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:74
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 int const struct action *paction struct unit struct city * pcity
Definition dialogs_g.h:78
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:779
bool extra_has_flag(const struct extra_type *pextra, enum extra_flag_id flag)
Definition extras.c:875
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:804
enum extra_cause activity_to_extra_cause(enum unit_activity act)
Definition extras.c:1090
bool is_extra_caused_by_action(const struct extra_type *pextra, const struct action *paction)
Definition extras.c:1070
const char * extra_rule_name(const struct extra_type *pextra)
Definition extras.c:203
bool is_extra_removed_by_action(const struct extra_type *pextra, const struct action *paction)
Definition extras.c:1080
enum extra_rmcause activity_to_extra_rmcause(enum unit_activity act)
Definition extras.c:1111
#define extra_type_iterate(_p)
Definition extras.h:315
#define extra_deps_iterate(_reqs, _dep)
Definition extras.h:372
#define extra_type_iterate_end
Definition extras.h:321
#define is_extra_caused_by(e, c)
Definition extras.h:203
#define extra_deps_iterate_end
Definition extras.h:380
#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
float adv_want
Definition fc_types.h:1050
adv_unit_task
Definition fc_types.h:231
@ AUT_NONE
Definition fc_types.h:231
@ AUT_AUTO_WORKER
Definition fc_types.h:231
int action_id
Definition fc_types.h:250
#define EC_NONE
Definition fc_types.h:808
#define ERM_NONE
Definition fc_types.h:831
#define ADV_WANT_PRINTF
Definition fc_types.h:1051
struct civ_game game
Definition game.c:62
struct world wld
Definition game.c:63
struct city * owner
Definition citydlg.c:226
static struct tile * pos
Definition finddlg.c:53
bool has_handicap(const struct player *pplayer, enum handicap_type htype)
Definition handicaps.c:66
@ H_MAP
Definition handicaps.h:28
@ H_FOG
Definition handicaps.h:26
adv_want adv_city_worker_act_get(const struct city *pcity, int city_tile_index, enum unit_activity act_id)
Definition infracache.c:360
int adv_city_worker_extra_get(const struct city *pcity, int city_tile_index, const struct extra_type *pextra)
Definition infracache.c:430
void initialize_infrastructure_cache(struct player *pplayer)
Definition infracache.c:250
int adv_city_worker_rmextra_get(const struct city *pcity, int city_tile_index, const struct extra_type *pextra)
Definition infracache.c:447
adv_want city_tile_value(const struct city *pcity, const struct tile *ptile, int foodneed, int prodneed)
Definition infracache.c:303
#define fc_assert_ret(condition)
Definition log.h:192
#define log_warn(message,...)
Definition log.h:106
#define log_verbose(message,...)
Definition log.h:110
#define fc_assert(condition)
Definition log.h:177
#define fc_assert_ret_val(condition, val)
Definition log.h:195
#define log_debug(message,...)
Definition log.h:116
@ LOG_DEBUG
Definition log.h:35
struct tile * map_pos_to_tile(const struct civ_map *nmap, int map_x, int map_y)
Definition map.c:434
bool same_pos(const struct tile *tile1, const struct tile *tile2)
Definition map.c:1076
int real_map_distance(const struct tile *tile0, const struct tile *tile1)
Definition map.c:675
struct terrain_misc terrain_control
Definition map.c:68
#define current_topo_has_flag(flag)
Definition map.h:43
#define whole_map_iterate(_map, _tile)
Definition map.h:573
#define whole_map_iterate_end
Definition map.h:582
#define index_to_map_pos(pmap_x, pmap_y, mindex)
Definition map.h:229
#define fc_calloc(n, esz)
Definition mem.h:38
#define FC_FREE(ptr)
Definition mem.h:41
#define SINGLE_MOVE
Definition movement.h:26
const char * nation_rule_name(const struct nation_type *pnation)
Definition nation.c:138
struct nation_type * nation_of_player(const struct player *pplayer)
Definition nation.c:443
const struct pf_position * pf_path_last_position(const struct pf_path *path)
void pf_path_destroy(struct pf_path *path)
struct pf_map * pf_map_new(const struct pf_parameter *parameter)
struct pf_path * pf_map_path(struct pf_map *pfm, struct tile *ptile)
bool pf_map_position(struct pf_map *pfm, struct tile *ptile, struct pf_position *pos)
void pf_map_destroy(struct pf_map *pfm)
tile_behavior
@ TB_NORMAL
@ TB_IGNORE
void pft_fill_unit_parameter(struct pf_parameter *parameter, const struct civ_map *nmap, const struct unit *punit)
Definition pf_tools.c:843
struct unit * player_unit_by_number(const struct player *pplayer, int unit_id)
Definition player.c:1217
bool pplayers_allied(const struct player *pplayer, const struct player *pplayer2)
Definition player.c:1397
#define is_ai(plr)
Definition player.h:232
struct extra_type * road_extra_get(const struct road_type *proad)
Definition road.c:42
Road_type_id road_number(const struct road_type *proad)
Definition road.c:32
bool road_provides_move_bonus(const struct road_type *proad)
Definition road.c:505
#define road_deps_iterate(_reqs, _dep)
Definition road.h:155
#define road_deps_iterate_end
Definition road.h:164
#define FC_INFINITY
Definition shared.h:36
#define MAX(x, y)
Definition shared.h:54
struct sprite int int y
Definition sprite_g.h:31
struct sprite int x
Definition sprite_g.h:31
static int recursion[AIT_LAST]
Definition srv_log.c:45
#define UNIT_LOG(loglevel, punit, msg,...)
Definition srv_log.h:98
#define LOG_AI_TEST
Definition srv_log.h:38
@ AIT_WORKERS
Definition srv_log.h:45
@ TIMER_STOP
Definition srv_log.h:76
@ TIMER_START
Definition srv_log.h:76
#define TIMING_LOG(timer, activity)
Definition srv_log.h:125
Definition city.h:318
struct packet_game_info info
Definition game.h:89
struct requirement_vector reqs
Definition extras.h:106
enum tile_behavior(* get_TB)(const struct tile *ptile, enum known_type known, const struct pf_parameter *param)
const struct player * owner
int warmth
Definition player.h:121
int frost
Definition player.h:121
struct city_list * cities
Definition player.h:281
struct player_ai ai_common
Definition player.h:288
struct unit_list * units
Definition player.h:282
Definition tile.h:50
struct unit_list * units
Definition tile.h:58
Definition timing.c:81
enum adv_unit_task task
Definition unit.h:90
bool worker
Definition unittype.h:582
Definition unit.h:140
enum unit_activity activity
Definition unit.h:159
int moves_left
Definition unit.h:152
int id
Definition unit.h:147
struct unit::@84::@87 server
struct extra_type * activity_target
Definition unit.h:167
struct unit_adv * adv
Definition unit.h:239
struct tile * goto_tile
Definition unit.h:157
enum server_side_agent ssa_controller
Definition unit.h:175
struct tile * ptile
Definition workertask.h:22
struct civ_map map
#define TRUE
Definition support.h:46
#define FALSE
Definition support.h:47
int terrain_extra_build_time(const struct terrain *pterrain, enum unit_activity activity, const struct extra_type *tgt)
Definition terrain.c:702
bool tile_has_road(const struct tile *ptile, const struct road_type *proad)
Definition tile.c:845
struct city * tile_city(const struct tile *ptile)
Definition tile.c:83
#define tile_index(_pt_)
Definition tile.h:89
#define tile_worked(_tile)
Definition tile.h:119
known_type
Definition tile.h:35
#define tile_terrain(_tile)
Definition tile.h:115
#define TILE_XY(ptile)
Definition tile.h:43
#define tile_has_extra(ptile, pextra)
Definition tile.h:152
#define tile_owner(_tile)
Definition tile.h:97
bool timer_in_use(struct timer *t)
Definition timing.c:242
void timer_destroy(struct timer *t)
Definition timing.c:208
void timer_start(struct timer *t)
Definition timing.c:263
double timer_read_seconds(struct timer *t)
Definition timing.c:379
struct timer * timer_renew(struct timer *t, enum timer_timetype type, enum timer_use use, const char *name)
Definition timing.c:180
#define TIMER_DEBUG
Definition timing.h:61
@ TIMER_CPU
Definition timing.h:41
static int best_value(const void *a, const void *b)
int get_turns_for_activity_at(const struct unit *punit, enum unit_activity activity, const struct tile *ptile, struct extra_type *tgt)
Definition unit.c:585
bool unit_is_cityfounder(const struct unit *punit)
Definition unit.c:2745
enum gen_action activity_default_action(enum unit_activity act)
Definition unit.c:2964
const char * get_activity_text(enum unit_activity activity)
Definition unit.c:657
void set_unit_activity(struct unit *punit, enum unit_activity new_activity, enum gen_action trigger_action)
Definition unit.c:1141
bool is_square_threatened(const struct civ_map *nmap, const struct player *pplayer, const struct tile *ptile, bool omniscient)
Definition unit.c:431
bool is_guard_unit(const struct unit *punit)
Definition unit.c:359
bool unit_has_orders(const struct unit *punit)
Definition unit.c:221
bool activity_requires_target(enum unit_activity activity)
Definition unit.c:609
#define unit_tile(_pu)
Definition unit.h:407
#define CHECK_UNIT(punit)
Definition unit.h:273
#define unit_owner(_pu)
Definition unit.h:406
#define unit_home(_pu_)
Definition unit.h:404
bool unit_activity_handling_targeted(struct unit *punit, enum unit_activity new_activity, struct extra_type **new_target, enum gen_action trigger_action)
Definition unithand.c:6783
bool unit_activity_handling(struct unit *punit, enum unit_activity new_activity, enum gen_action trigger_action)
Definition unithand.c:6707
#define unit_list_iterate(unitlist, punit)
Definition unitlist.h:31
#define unit_list_iterate_safe(unitlist, _unit)
Definition unitlist.h:39
#define unit_list_iterate_end
Definition unitlist.h:33
#define unit_list_iterate_safe_end
Definition unitlist.h:61
void send_unit_info(struct conn_list *dest, struct unit *punit)
Definition unittools.c:2882
const struct unit_type * unit_type_get(const struct unit *punit)
Definition unittype.c:126
const char * unit_rule_name(const struct unit *punit)
Definition unittype.c:1613
bool unit_has_type_flag(const struct unit *punit, enum unit_type_flag_id flag)
Definition unittype.c:215
#define worker_task_list_iterate(tasklist, ptask)
Definition workertask.h:33
#define worker_task_list_iterate_end
Definition workertask.h:35
#define MAP_INDEX_SIZE