659
/**************************************************************************
660
Tries to find a boat for our unit. Requires warmap to be initialized
661
with respect to x, y. cap is the requested capacity on the transport.
662
Note that it may return a transport with less than cap capacity if this
663
transport has zero move cost to x, y.
665
The "virtual boats" code is not used. It is probably too unreliable,
666
since the AI switches its production back and forth continously.
668
FIXME: if there is a (free) boat in a city filled with units,
669
ground_unit_transporter_capacity will return negative.
670
TODO: Kill me. There is a reliable version of this, find_ferry.
671
**************************************************************************/
672
Unit_type_id find_boat(struct player *pplayer, struct tile **ptile, int cap)
674
int best = 22; /* arbitrary maximum distance, I will admit! */
676
unit_list_iterate(pplayer->units, aunit)
677
if (is_ground_units_transport(aunit)) {
678
if (WARMAP_COST(aunit->tile) < best &&
679
(WARMAP_COST(aunit->tile) == 0 ||
680
ground_unit_transporter_capacity(aunit->tile,
683
best = WARMAP_COST(aunit->tile);
684
*ptile = aunit->tile;
687
unit_list_iterate_end;
688
if (id != 0) return(id);
692
/**************************************************************************
693
Returns TRUE if there are (other) ground units than punit stacked on
695
**************************************************************************/
696
struct unit *other_passengers(struct unit *punit)
698
unit_list_iterate(punit->tile->units, aunit)
699
if (is_ground_unit(aunit) && aunit != punit) return aunit;
700
unit_list_iterate_end;
704
667
/****************************************************************************
705
Compares the best known tile improvement action with improving the tile
706
at (x,y) with activity act. Calculates the value of improving the tile
707
by discounting the total value by the time it would take to do the work
668
Compares the best known tile improvement action with improving ptile
669
with activity act. Calculates the value of improving the tile by
670
discounting the total value by the time it would take to do the work
708
671
and multiplying by some factor.
709
672
****************************************************************************/
710
static void consider_settler_action(struct player *pplayer,
673
static void consider_settler_action(const struct player *pplayer,
711
674
enum unit_activity act, int extra,
712
675
int new_tile_value, int old_tile_value,
713
bool in_use, int move_turns, int delay,
715
int *best_old_tile_value,
716
int *best_move_turns,
717
enum unit_activity *best_act,
718
struct tile **best_tile,
676
bool in_use, int delay,
678
int *best_old_tile_value,
679
enum unit_activity *best_act,
680
struct tile **best_tile,
719
681
struct tile *ptile)
819
792
if this array is NULL, workers are never displaced.
820
793
****************************************************************************/
821
794
static int evaluate_improvements(struct unit *punit,
822
enum unit_activity *best_act,
823
struct tile **best_tile,
825
struct settlermap *state)
795
enum unit_activity *best_act,
796
struct tile **best_tile,
797
struct pf_path **path,
798
struct settlermap *state)
827
struct city *mycity = tile_get_city(punit->tile);
828
struct player *pplayer = unit_owner(punit);
829
bool in_use; /* true if the target square is being used
830
by one of our cities */
831
Continent_id ucont = tile_get_continent(punit->tile);
832
int mv_rate = unit_type(punit)->move_rate;
833
int mv_turns; /* estimated turns to move to target square */
834
int oldv; /* current value of consideration tile */
835
int best_oldv = 9999; /* oldv of best target so far; compared if
836
newv==best_newv; not initialized to zero,
837
so that newv=0 activities are not chosen */
800
const struct player *pplayer = unit_owner(punit);
801
struct pf_parameter parameter;
803
struct pf_position pos;
804
int oldv; /* Current value of consideration tile. */
805
int best_oldv = 9999; /* oldv of best target so far; compared if
806
* newv == best_newv; not initialized to zero,
807
* so that newv = 0 activities are not chosen. */
838
808
bool can_rr = player_knows_techs_with_flag(pplayer, TF_RAILROAD);
840
809
int best_newv = 0;
842
811
/* closest worker, if any, headed towards target tile */
843
812
struct unit *enroute = NULL;
845
generate_warmap(mycity, punit);
814
pft_fill_unit_parameter(¶meter, punit);
815
parameter.can_invade_tile = autosettler_enter_territory;
816
pfm = pf_map_new(¶meter);
847
818
city_list_iterate(pplayer->cities, pcity) {
819
struct tile *pcenter = city_tile(pcity);
848
821
/* try to work near the city */
849
city_map_checked_iterate(pcity->tile, cx, cy, ptile) {
822
city_tile_iterate_cxy(pcenter, ptile, cx, cy) {
850
823
bool consider = TRUE;
824
bool in_use = (tile_worked(ptile) == pcity);
852
if (get_worker_city(pcity, cx, cy) == C_TILE_UNAVAILABLE
853
|| terrain_has_flag(pcity->tile->terrain, TER_UNSAFE)) {
854
/* Don't risk bothering with this tile. */
826
if (!in_use && !city_can_work_tile(pcity, ptile)) {
827
/* Don't risk bothering with this tile. */
858
/* do not go to tiles that already have workers there */
831
/* Do not go to tiles that already have workers there. */
859
832
unit_list_iterate(ptile->units, aunit) {
860
if (unit_owner(aunit) == pplayer
861
&& aunit->id != punit->id
862
&& unit_has_type_flag(aunit, F_SETTLERS)) {
833
if (unit_owner(aunit) == pplayer
834
&& aunit->id != punit->id
835
&& unit_has_type_flag(aunit, F_SETTLERS)) {
865
838
} unit_list_iterate_end;
867
in_use = (get_worker_city(pcity, cx, cy) == C_TILE_WORKER);
869
enroute = player_find_unit_by_id(pplayer,
870
state[ptile->index].enroute);
845
enroute = player_find_unit_by_id(pplayer,
846
state[tile_index(ptile)].enroute);
873
&& tile_get_continent(ptile) == ucont
874
&& WARMAP_COST(ptile) <= THRESHOLD * mv_rate) {
875
int eta = FC_INFINITY, inbound_distance = FC_INFINITY, time;
878
eta = state[ptile->index].eta;
879
inbound_distance = real_map_distance(ptile, enroute->tile);
881
mv_turns = WARMAP_COST(ptile) / mv_rate;
882
oldv = city_tile_value(pcity, cx, cy, 0, 0);
884
/* only consider this tile if we are closer in time and space to
885
* it than our other worker (if any) travelling to the site */
886
if ((enroute && enroute->id == punit->id)
889
&& (real_map_distance(ptile, punit->tile)
890
< inbound_distance))) {
893
UNIT_LOG(LOG_DEBUG, punit,
894
"Considering %d,%d because we're closer "
895
"(%d,%d) than %d (%d,%d)",
896
TILE_XY(ptile), mv_turns,
897
real_map_distance(ptile, punit->tile),
898
enroute->id, eta, inbound_distance);
901
/* now, consider various activities... */
902
activity_type_iterate(act) {
903
if (pcity->ai.act_value[act][cx][cy] >= 0
904
&& can_unit_do_activity_targeted_at(punit, act,
907
int base_value = pcity->ai.act_value[act][cx][cy];
909
time = mv_turns + get_turns_for_activity_at(punit, act, ptile);
911
if (act == ACTIVITY_ROAD) {
912
extra = road_bonus(ptile, S_ROAD) * 5;
914
/* if we can make railroads eventually, consider making
915
* road here, and set extras and time to to consider
916
* railroads in main consider_settler_action call */
917
consider_settler_action(pplayer, ACTIVITY_ROAD,
919
pcity->ai.act_value[ACTIVITY_ROAD][cx][cy],
920
oldv, in_use, mv_turns, time,
921
&best_newv, &best_oldv, travel_time,
926
= pcity->ai.act_value[ACTIVITY_RAILROAD][cx][cy];
928
/* Count road time plus rail time. */
929
time += get_turns_for_activity_at(punit, ACTIVITY_RAILROAD,
932
} else if (act == ACTIVITY_RAILROAD) {
933
extra = road_bonus(ptile, S_RAILROAD) * 3;
934
} else if (act == ACTIVITY_FALLOUT) {
935
extra = pplayer->ai.frost;
936
} else if (act == ACTIVITY_POLLUTION) {
937
extra = pplayer->ai.warmth;
940
consider_settler_action(pplayer, act,
945
&best_newv, &best_oldv, travel_time,
949
} /* endif: can the worker perform this action */
950
} activity_type_iterate_end;
951
} /* endif: can we finish sooner than current worker, if any? */
849
if (pf_map_get_position(pfm, ptile, &pos)) {
850
int eta = FC_INFINITY, inbound_distance = FC_INFINITY, time;
853
eta = state[tile_index(ptile)].eta;
854
inbound_distance = real_map_distance(ptile, unit_tile(enroute));
857
/* Only consider this tile if we are closer in time and space to
858
* it than our other worker (if any) travelling to the site. */
859
if ((enroute && enroute->id == punit->id)
862
&& (real_map_distance(ptile, unit_tile(punit))
863
< inbound_distance))) {
866
UNIT_LOG(LOG_DEBUG, punit,
867
"Considering (%d, %d) because we're closer "
868
"(%d, %d) than %d (%d, %d)",
869
TILE_XY(ptile), pos.turn,
870
real_map_distance(ptile, unit_tile(punit)),
871
enroute->id, eta, inbound_distance);
874
oldv = city_tile_value(pcity, ptile, 0, 0);
876
/* Now, consider various activities... */
877
activity_type_iterate(act) {
878
if (pcity->ai->act_value[act][cx][cy] >= 0
879
/* This needs separate implementation. */
880
&& act != ACTIVITY_BASE
881
&& can_unit_do_activity_targeted_at(punit, act, S_LAST,
884
int base_value = pcity->ai->act_value[act][cx][cy];
886
time = pos.turn + get_turns_for_activity_at(punit, act, ptile);
888
if (act == ACTIVITY_ROAD) {
889
extra = road_bonus(ptile, S_ROAD) * 5;
891
/* If we can make railroads eventually, consider making
892
* road here, and set extras and time to to consider
893
* railroads in main consider_settler_action call. */
894
consider_settler_action(pplayer, ACTIVITY_ROAD, extra,
895
pcity->ai->act_value[ACTIVITY_ROAD][cx][cy],
897
&best_newv, &best_oldv,
898
best_act, best_tile, ptile);
901
= pcity->ai->act_value[ACTIVITY_RAILROAD][cx][cy];
903
/* Count road time plus rail time. */
904
time += get_turns_for_activity_at(punit, ACTIVITY_RAILROAD,
907
} else if (act == ACTIVITY_RAILROAD) {
908
extra = road_bonus(ptile, S_RAILROAD) * 3;
909
} else if (act == ACTIVITY_FALLOUT) {
910
extra = pplayer->ai_data.frost;
911
} else if (act == ACTIVITY_POLLUTION) {
912
extra = pplayer->ai_data.warmth;
915
consider_settler_action(pplayer, act, extra, base_value,
917
&best_newv, &best_oldv,
918
best_act, best_tile, ptile);
920
} /* endif: can the worker perform this action */
921
} activity_type_iterate_end;
922
} /* endif: can we finish sooner than current worker, if any? */
952
923
} /* endif: are we travelling to a legal destination? */
953
} city_map_checked_iterate_end;
924
} city_tile_iterate_cxy_end;
954
925
} city_list_iterate_end;
956
927
best_newv /= WORKER_FACTOR;
1101
1094
/* Run the "autosettler" program */
1102
1095
if (punit->ai.ai_role == AIUNIT_AUTO_SETTLER) {
1096
struct pf_map *pfm = NULL;
1097
struct pf_parameter parameter;
1099
struct unit *displaced;
1102
UNIT_LOG(LOG_DEBUG, punit, "giving up trying to improve terrain");
1103
goto CLEANUP; /* We cannot do anything */
1103
1106
/* Mark the square as taken. */
1105
struct unit *displaced
1106
= player_find_unit_by_id(pplayer, state[best_tile->index].enroute);
1109
assert(state[best_tile->index].enroute == displaced->id);
1110
assert(state[best_tile->index].eta > completion_time
1111
|| (state[best_tile->index].eta == completion_time
1112
&& (real_map_distance(best_tile, punit->tile)
1113
< real_map_distance(best_tile, displaced->tile))));
1114
UNIT_LOG(LOG_DEBUG, punit,
1115
"%d (%d,%d) has displaced %d (%d,%d) on %d,%d",
1116
punit->id, completion_time,
1117
real_map_distance(best_tile, punit->tile),
1118
displaced->id, state[best_tile->index].eta,
1119
real_map_distance(best_tile, displaced->tile),
1120
TILE_XY(best_tile));
1123
state[best_tile->index].enroute = punit->id;
1124
state[best_tile->index].eta = completion_time;
1107
displaced = player_find_unit_by_id(pplayer, state[tile_index(best_tile)].enroute);
1110
assert(state[tile_index(best_tile)].enroute == displaced->id);
1111
assert(state[tile_index(best_tile)].eta > completion_time
1112
|| (state[tile_index(best_tile)].eta == completion_time
1113
&& (real_map_distance(best_tile, punit->tile)
1114
< real_map_distance(best_tile, displaced->tile))));
1115
UNIT_LOG(LOG_DEBUG, punit,
1116
"%d (%d,%d) has displaced %d (%d,%d) on %d,%d",
1117
punit->id, completion_time,
1118
real_map_distance(best_tile, punit->tile),
1119
displaced->id, state[tile_index(best_tile)].eta,
1120
real_map_distance(best_tile, displaced->tile),
1121
TILE_XY(best_tile));
1124
state[tile_index(best_tile)].enroute = punit->id;
1125
state[tile_index(best_tile)].eta = completion_time;
1127
int saved_id = punit->id;
1129
displaced->goto_tile = NULL;
1130
auto_settler_findwork(pplayer, displaced, state, recursion + 1);
1131
if (player_find_unit_by_id(pplayer, saved_id) == NULL) {
1132
/* Actions of the displaced settler somehow caused this settler
1133
* to die. (maybe by recursively giving control back to this unit)
1128
struct tile *goto_tile = punit->goto_tile;
1129
int saved_id = punit->id;
1131
displaced->goto_tile = NULL;
1132
auto_settler_findwork(pplayer, displaced, state, recursion + 1);
1133
if (player_find_unit_by_id(pplayer, saved_id) == NULL) {
1134
/* Actions of the displaced settler somehow caused this settler
1135
* to die. (maybe by recursively giving control back to this unit)
1139
if (goto_tile != punit->goto_tile) {
1140
/* Actions of the displaced settler somehow caused this settler
1141
* to get a new job. (A displaced B, B displaced C, C displaced A)
1143
UNIT_LOG(LOG_DEBUG, punit, "%d has changed goals from (%d, %d) "
1144
"to (%d, %d) due to recursion",
1145
punit->id, TILE_XY(goto_tile), TILE_XY(punit->goto_tile));
1151
pft_fill_unit_parameter(¶meter, punit);
1152
parameter.can_invade_tile = autosettler_enter_territory;
1153
pfm = pf_map_new(¶meter);
1154
path = pf_map_get_path(pfm, best_tile);
1160
alive = ai_follow_path(punit, path, best_tile);
1162
if (alive && same_pos(punit->tile, best_tile)
1163
&& punit->moves_left > 0) {
1164
/* Reached destination and can start working immediately */
1165
unit_activity_handling(punit, best_act);
1166
send_unit_info(NULL, punit); /* FIXME: probably duplicate */
1139
UNIT_LOG(LOG_DEBUG, punit, "giving up trying to improve terrain");
1140
return; /* We cannot do anything */
1142
punit->goto_tile = best_tile; /* TMP */
1143
if (do_unit_goto(punit, GOTO_MOVE_ANY, FALSE) == GR_DIED) {
1146
if (punit->moves_left > 0
1147
&& same_pos(best_tile, punit->tile)) {
1148
handle_unit_activity_request(punit, best_act);
1149
send_unit_info(NULL, punit);
1169
freelog(LOG_DEBUG, "Autosettler does not find path (%d,%d) -> (%d,%d)",
1170
punit->tile->x, punit->tile->y, best_tile->x, best_tile->y);
1174
pf_map_destroy(pfm);
1154
1180
/*** Recurse if we want to found a city ***/
1191
1224
void initialize_infrastructure_cache(struct player *pplayer)
1193
1226
city_list_iterate(pplayer->cities, pcity) {
1227
struct tile *pcenter = city_tile(pcity);
1194
1228
int best = best_worker_tile_value(pcity);
1196
1230
city_map_iterate(city_x, city_y) {
1197
1231
activity_type_iterate(act) {
1198
pcity->ai.act_value[act][city_x][city_y] = -1;
1232
pcity->ai->act_value[act][city_x][city_y] = -1;
1199
1233
} activity_type_iterate_end;
1200
1234
} city_map_iterate_end;
1202
city_map_checked_iterate(pcity->tile,
1203
city_x, city_y, ptile) {
1236
city_tile_iterate_cxy(pcenter, ptile, city_x, city_y) {
1205
struct terrain *old_terrain = ptile->terrain;
1238
struct terrain *old_terrain = tile_terrain(ptile);
1206
1239
bv_special old_special = ptile->special;
1209
pcity->ai.act_value[ACTIVITY_POLLUTION][city_x][city_y]
1210
= ai_calc_pollution(pcity, city_x, city_y, best, ptile);
1211
pcity->ai.act_value[ACTIVITY_FALLOUT][city_x][city_y]
1212
= ai_calc_fallout(pcity, pplayer, city_x, city_y, best, ptile);
1213
pcity->ai.act_value[ACTIVITY_MINE][city_x][city_y]
1214
= ai_calc_mine(pcity, city_x, city_y, ptile);
1215
pcity->ai.act_value[ACTIVITY_IRRIGATE][city_x][city_y]
1242
pcity->ai->act_value[ACTIVITY_POLLUTION][city_x][city_y]
1243
= ai_calc_pollution(pcity, city_x, city_y, best, ptile);
1244
pcity->ai->act_value[ACTIVITY_FALLOUT][city_x][city_y]
1245
= ai_calc_fallout(pcity, pplayer, city_x, city_y, best, ptile);
1246
pcity->ai->act_value[ACTIVITY_MINE][city_x][city_y]
1247
= ai_calc_mine(pcity, city_x, city_y, ptile);
1248
pcity->ai->act_value[ACTIVITY_IRRIGATE][city_x][city_y]
1216
1249
= ai_calc_irrigate(pcity, pplayer, city_x, city_y, ptile);
1217
pcity->ai.act_value[ACTIVITY_TRANSFORM][city_x][city_y]
1218
= ai_calc_transform(pcity, city_x, city_y, ptile);
1250
pcity->ai->act_value[ACTIVITY_TRANSFORM][city_x][city_y]
1251
= ai_calc_transform(pcity, city_x, city_y, ptile);
1220
1253
/* road_bonus() is handled dynamically later; it takes into
1221
1254
* account settlers that have already been assigned to building
1222
1255
* roads this turn. */
1223
pcity->ai.act_value[ACTIVITY_ROAD][city_x][city_y]
1224
= ai_calc_road(pcity, pplayer, city_x, city_y, ptile);
1225
pcity->ai.act_value[ACTIVITY_RAILROAD][city_x][city_y]
1226
= ai_calc_railroad(pcity, pplayer, city_x, city_y, ptile);
1256
pcity->ai->act_value[ACTIVITY_ROAD][city_x][city_y]
1257
= ai_calc_road(pcity, pplayer, city_x, city_y, ptile);
1258
pcity->ai->act_value[ACTIVITY_RAILROAD][city_x][city_y]
1259
= ai_calc_railroad(pcity, pplayer, city_x, city_y, ptile);
1228
1261
/* Make sure nothing was accidentally changed by these calculations. */
1229
assert(old_terrain == ptile->terrain
1262
assert(old_terrain == tile_terrain(ptile)
1230
1263
&& memcmp(&ptile->special, &old_special,
1231
1264
sizeof(old_special)) == 0);
1232
} city_map_checked_iterate_end;
1265
} city_tile_iterate_cxy_end;
1233
1266
} city_list_iterate_end;