webperimental: enable restrictinfra by default...
[freeciv.git] / ai / threxpr / texaicity.c
blob674c69ee6e744271ada91a07ddd3536f8ef7ea46
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.
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 ***********************************************************************/
14 #ifdef HAVE_CONFIG_H
15 #include <fc_config.h>
16 #endif
18 /* utility */
19 #include "log.h"
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"
30 /* server */
31 #include "citytools.h"
33 /* server/advisors */
34 #include "advbuilding.h"
35 #include "advdata.h"
36 #include "autosettlers.h"
37 #include "infracache.h"
39 /* ai/default */
40 #include "aidata.h"
42 /* ai/threxpr */
43 #include "texaimsg.h"
45 #include "texaicity.h"
47 /* Task Want Multiplier */
48 #define TWMP 100
50 struct texai_worker_task_req
52 int city_id;
53 struct worker_task task;
56 enum texai_worker_task_limitation {
57 TWTL_CURRENT_UNITS,
58 TWTL_BUILDABLE_UNITS
61 static bool texai_city_worker_task_select(struct ai_type *ait,
62 struct player *pplayer,
63 struct city *pcity,
64 struct worker_task *task,
65 enum texai_worker_task_limitation limit);
67 /**************************************************************************
68 Create worker request for the city. Only tasks that existing units can
69 do are created.
70 **************************************************************************/
71 void texai_city_worker_requests_create(struct ai_type *ait,
72 struct player *pplayer, struct city *pcity)
74 struct worker_task task;
76 if (texai_city_worker_task_select(ait, pplayer, pcity, &task, TWTL_CURRENT_UNITS)) {
77 struct texai_worker_task_req *data = fc_malloc(sizeof(*data));
79 data->city_id = pcity->id;
80 data->task.ptile = task.ptile;
81 data->task.act = task.act;
82 data->task.tgt = task.tgt;
83 data->task.want = task.want;
85 texai_send_req(TEXAI_REQ_WORKER_TASK, pplayer, data);
89 /**************************************************************************
90 Set wants for worker-type units.
91 **************************************************************************/
92 void texai_city_worker_wants(struct ai_type *ait,
93 struct player *pplayer, struct city *pcity)
95 struct worker_task task;
96 struct texai_city *cdata = texai_city_data(ait, pcity);
97 int *wants = cdata->unit_wants;
98 int maxwant = 0;
99 struct unit_type *type = NULL;
100 Continent_id place = tile_continent(city_tile(pcity));
101 struct ai_plr *dai = dai_plr_data_get(ait, pplayer, NULL);
102 struct adv_data *adv = adv_data_get(pplayer, NULL);
104 unit_type_iterate(ptype) {
105 wants[utype_index(ptype)] = 0;
106 } unit_type_iterate_end;
108 texai_city_worker_task_select(ait, pplayer, pcity, &task, TWTL_BUILDABLE_UNITS);
110 unit_type_iterate(ptype) {
111 int twant = wants[utype_index(ptype)];
113 twant -= 20 * ptype->pop_cost;
114 twant -= ptype->build_cost;
115 twant -= ptype->upkeep[O_FOOD] * FOOD_WEIGHTING / 2;
117 /* Massage our desire based on available statistics to prevent
118 * overflooding with worker type units if they come cheap in
119 * the ruleset */
120 if (place >= 0) {
121 twant /= MAX(1, dai->stats.workers[place] / (adv->stats.cities[place] + 1));
122 twant -= dai->stats.workers[place];
123 } else {
124 /* TODO: Handle Oceans with cities sensibly */
127 twant = MAX(twant, 0);
129 if (twant > maxwant) {
130 maxwant = twant;
131 type = ptype;
133 } unit_type_iterate_end;
135 cdata->defai.settler_want = maxwant / 70;
136 cdata->defai.settler_type = type;
139 struct texai_tile_state
141 int uw_max;
142 int worst_worked;
143 int orig_worst_worked;
144 int old_worst_worked;
145 int *wants;
148 /**************************************************************************
149 Select worker task suitable for the tile.
150 **************************************************************************/
151 static void texai_tile_worker_task_select(struct player *pplayer,
152 struct city *pcity, struct tile *ptile,
153 int cindex, struct unit_list *units,
154 struct worker_task *worked,
155 struct worker_task *unworked,
156 struct texai_tile_state *state,
157 enum texai_worker_task_limitation limit)
159 int orig_value;
160 bool potential_worst_worked = FALSE;
162 if (!city_can_work_tile(pcity, ptile)) {
163 return;
166 orig_value = city_tile_value(pcity, ptile, 0, 0);
168 if (tile_worked(ptile) == pcity
169 && orig_value < state->worst_worked) {
170 state->worst_worked = orig_value;
171 state->orig_worst_worked = orig_value;
172 potential_worst_worked = TRUE;
175 as_transform_activity_iterate(act) {
176 bool consider = TRUE;
177 bool possible = FALSE;
178 enum extra_cause cause;
179 enum extra_rmcause rmcause;
180 struct extra_type *tgt = NULL;
182 /* Do not request activities that already are under way. */
183 unit_list_iterate(ptile->units, punit) {
184 if (unit_owner(punit) == pplayer
185 && unit_has_type_flag(punit, UTYF_SETTLERS)
186 && punit->activity == act) {
187 consider = FALSE;
188 break;
190 } unit_list_iterate_end;
192 if (!consider) {
193 continue;
196 cause = activity_to_extra_cause(act);
197 rmcause = activity_to_extra_rmcause(act);
199 unit_list_iterate(units, punit) {
200 if (cause != EC_NONE) {
201 tgt = next_extra_for_tile(ptile, cause, pplayer, punit);
202 } else if (rmcause != ERM_NONE) {
203 tgt = prev_extra_in_tile(ptile, rmcause, pplayer, punit);
206 if (can_unit_do_activity_targeted_at(punit, act, tgt, ptile)) {
207 possible = TRUE;
208 break;
210 } unit_list_iterate_end;
212 if (possible) {
213 int value = adv_city_worker_act_get(pcity, cindex, act);
215 if (tile_worked(ptile) == pcity) {
216 if ((value - orig_value) * TWMP > worked->want) {
217 worked->want = TWMP * (value - orig_value);
218 worked->ptile = ptile;
219 worked->act = act;
220 worked->tgt = NULL;
221 if (limit == TWTL_BUILDABLE_UNITS) {
222 unit_list_iterate(units, punit) {
223 if (can_unit_do_activity_targeted_at(punit, act, tgt, ptile)) {
224 state->wants[utype_index(unit_type_get(punit))] += worked->want;
226 } unit_list_iterate_end;
229 if (value > state->old_worst_worked) {
230 /* After improvement it would not be the worst */
231 potential_worst_worked = FALSE;
232 } else {
233 state->worst_worked = value;
235 } else {
236 if (value > orig_value && value > state->uw_max) {
237 state->uw_max = value;
238 unworked->want = TWMP * (value - orig_value);
239 unworked->ptile = ptile;
240 unworked->act = act;
241 unworked->tgt = NULL;
242 if (limit == TWTL_BUILDABLE_UNITS) {
243 unit_list_iterate(units, punit) {
244 if (can_unit_do_activity_targeted_at(punit, act, tgt, ptile)) {
245 state->wants[utype_index(unit_type_get(punit))] += unworked->want;
247 } unit_list_iterate_end;
252 } as_transform_activity_iterate_end;
254 extra_type_iterate(tgt) {
255 enum unit_activity act = ACTIVITY_LAST;
256 bool removing = tile_has_extra(ptile, tgt);
258 unit_list_iterate(units, punit) {
259 if (removing) {
260 as_rmextra_activity_iterate(try_act) {
261 if (is_extra_removed_by_action(tgt, try_act)
262 && can_unit_do_activity_targeted_at(punit, try_act, tgt, ptile)) {
263 act = try_act;
264 break;
266 } as_rmextra_activity_iterate_end;
267 } else {
268 as_extra_activity_iterate(try_act) {
269 if (is_extra_caused_by_action(tgt, try_act)
270 && can_unit_do_activity_targeted_at(punit, try_act, tgt, ptile)) {
271 act = try_act;
272 break;
274 } as_extra_activity_iterate_end;
276 } unit_list_iterate_end;
278 if (act != ACTIVITY_LAST) {
279 int value;
280 int extra;
281 bool consider = TRUE;
282 struct road_type *proad;
284 /* Do not request activities that already are under way. */
285 unit_list_iterate(ptile->units, punit) {
286 if (unit_owner(punit) == pplayer
287 && unit_has_type_flag(punit, UTYF_SETTLERS)
288 && punit->activity == act) {
289 consider = FALSE;
290 break;
292 } unit_list_iterate_end;
294 if (!consider) {
295 continue;
298 proad = extra_road_get(tgt);
300 value = adv_city_worker_extra_get(pcity, cindex, tgt);
302 if (proad != NULL && road_provides_move_bonus(proad)) {
303 int old_move_cost;
304 int mc_multiplier = 1;
305 int mc_divisor = 1;
307 /* Here 'old' means actually 'without the evaluated': In case of
308 * removal activity it's the value after the removal. */
309 old_move_cost = tile_terrain(ptile)->movement_cost * SINGLE_MOVE;
311 extra_type_by_cause_iterate(EC_ROAD, poe) {
312 struct road_type *pold = extra_road_get(poe);
314 if (tile_has_extra(ptile, poe) && poe != tgt) {
315 if (road_provides_move_bonus(pold)
316 && pold->move_cost < old_move_cost) {
317 old_move_cost = pold->move_cost;
320 } extra_type_by_cause_iterate_end;
322 if (proad->move_cost < old_move_cost) {
323 if (proad->move_cost >= terrain_control.move_fragments) {
324 mc_divisor = proad->move_cost / terrain_control.move_fragments;
325 } else {
326 if (proad->move_cost == 0) {
327 mc_multiplier = 2;
328 } else {
329 mc_multiplier = 1 - proad->move_cost;
331 mc_multiplier += old_move_cost;
335 extra = adv_settlers_road_bonus(ptile, proad) * mc_multiplier / mc_divisor;
337 if (removing) {
338 extra = -extra;
340 } else {
341 extra = 0;
344 value += extra;
346 if (tile_worked(ptile) == pcity) {
347 if ((value - orig_value) * TWMP > worked->want) {
348 worked->want = TWMP * (value - orig_value);
349 worked->ptile = ptile;
350 worked->act = act;
351 worked->tgt = tgt;
352 if (limit == TWTL_BUILDABLE_UNITS) {
353 unit_list_iterate(units, punit) {
354 if (can_unit_do_activity_targeted_at(punit, act, tgt, ptile)) {
355 state->wants[utype_index(unit_type_get(punit))] += worked->want;
357 } unit_list_iterate_end;
360 if (value > state->old_worst_worked) {
361 /* After improvement it would not be the worst */
362 potential_worst_worked = FALSE;
363 } else {
364 state->worst_worked = value;
366 } else {
367 if (value > orig_value && value > state->uw_max) {
368 state->uw_max = value;
369 unworked->want = TWMP * (value - orig_value);
370 unworked->ptile = ptile;
371 unworked->act = act;
372 unworked->tgt = tgt;
373 if (limit == TWTL_BUILDABLE_UNITS) {
374 unit_list_iterate(units, punit) {
375 if (can_unit_do_activity_targeted_at(punit, act, tgt, ptile)) {
376 state->wants[utype_index(unit_type_get(punit))] += unworked->want;
378 } unit_list_iterate_end;
383 } extra_type_iterate_end;
385 if (potential_worst_worked) {
386 /* Would still be worst worked even if we improved *it*. */
387 state->old_worst_worked = state->worst_worked;
391 /**************************************************************************
392 Select worker task suitable for the city.
393 **************************************************************************/
394 static bool texai_city_worker_task_select(struct ai_type *ait,
395 struct player *pplayer, struct city *pcity,
396 struct worker_task *task,
397 enum texai_worker_task_limitation limit)
399 struct worker_task *selected;
400 struct worker_task worked = { .ptile = NULL, .want = 0, .act = ACTIVITY_IDLE, .tgt = NULL };
401 struct worker_task unworked = { .ptile = NULL, .want = 0, .act = ACTIVITY_IDLE, .tgt = NULL };
402 struct texai_tile_state state = { .uw_max = 0, .worst_worked = FC_INFINITY,
403 .orig_worst_worked = 0, .old_worst_worked = FC_INFINITY };
404 struct unit_list *units = NULL;
406 switch (limit) {
407 case TWTL_CURRENT_UNITS:
408 units = pplayer->units;
409 state.wants = NULL;
410 break;
411 case TWTL_BUILDABLE_UNITS:
412 units = unit_list_new();
413 unit_type_iterate(ptype) {
414 if (can_city_build_unit_now(pcity, ptype)) {
415 unit_list_append(units, unit_virtual_create(pplayer, pcity, ptype, 0));
417 } unit_type_iterate_end;
418 state.wants = texai_city_data(ait, pcity)->unit_wants;
419 break;
422 city_tile_iterate_index(city_map_radius_sq_get(pcity), city_tile(pcity),
423 ptile, cindex) {
424 texai_tile_worker_task_select(pplayer, pcity, ptile, cindex, units,
425 &worked, &unworked, &state, limit);
426 } city_tile_iterate_end;
428 if (worked.ptile == NULL
429 || (state.old_worst_worked < state.uw_max
430 && (state.uw_max - state.orig_worst_worked) * TWMP > worked.want)) {
431 /* It's better to improve best yet unworked tile and take it to use after that,
432 than to improve already worked tile. */
433 selected = &unworked;
434 } else {
435 selected = &worked;
438 if (limit == TWTL_BUILDABLE_UNITS) {
439 unit_list_iterate(units, punit) {
440 unit_virtual_destroy(punit);
441 } unit_list_iterate_end;
442 unit_list_destroy(units);
445 if (selected->ptile != NULL) {
446 struct extra_type *target = NULL;
448 if (selected->tgt == NULL) {
449 enum extra_cause cause = activity_to_extra_cause(selected->act);
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);
456 if (rmcause != ERM_NONE) {
457 target = prev_extra_in_tile(selected->ptile, rmcause, pplayer, NULL);
460 } else {
461 target = selected->tgt;
464 task->ptile = selected->ptile;
465 task->act = selected->act;
466 task->tgt = target;
467 task->want = selected->want;
469 return TRUE;
472 return FALSE;
475 /**************************************************************************
476 Receive message from thread to main thread.
477 **************************************************************************/
478 void texai_req_worker_task_rcv(struct texai_req *req)
480 struct texai_worker_task_req *data = (struct texai_worker_task_req *)req->data;
481 struct city *pcity;
483 pcity = game_city_by_number(data->city_id);
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);
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);
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;
502 /* Send info to observers */
503 package_and_send_worker_tasks(pcity);
506 free(data);
509 /**************************************************************************
510 Initialize city for use with threxp AI.
511 **************************************************************************/
512 void texai_city_alloc(struct ai_type *ait, struct city *pcity)
514 struct texai_city *city_data = fc_calloc(1, sizeof(struct texai_city));
516 city_data->defai.building_wait = BUILDING_WAIT_MINIMUM;
517 adv_init_choice(&(city_data->defai.choice));
519 city_set_ai_data(pcity, ait, city_data);
522 /**************************************************************************
523 Free city from use with threxp AI.
524 **************************************************************************/
525 void texai_city_free(struct ai_type *ait, struct city *pcity)
527 struct texai_city *city_data = texai_city_data(ait, pcity);
529 if (city_data != NULL) {
530 adv_deinit_choice(&(city_data->defai.choice));
531 city_set_ai_data(pcity, ait, NULL);
532 FC_FREE(city_data);