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)
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 ***********************************************************************/
15 #include <fc_config.h>
28 #include "workertask.h"
31 #include "citytools.h"
34 #include "advbuilding.h"
36 #include "autosettlers.h"
37 #include "infracache.h"
45 #include "texaicity.h"
47 /* Task Want Multiplier */
50 struct texai_worker_task_req
53 struct worker_task task
;
56 enum texai_worker_task_limitation
{
61 static bool texai_city_worker_task_select(struct ai_type
*ait
,
62 struct player
*pplayer
,
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
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
;
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
121 twant
/= MAX(1, dai
->stats
.workers
[place
] / (adv
->stats
.cities
[place
] + 1));
122 twant
-= dai
->stats
.workers
[place
];
124 /* TODO: Handle Oceans with cities sensibly */
127 twant
= MAX(twant
, 0);
129 if (twant
> maxwant
) {
133 } unit_type_iterate_end
;
135 cdata
->defai
.settler_want
= maxwant
/ 70;
136 cdata
->defai
.settler_type
= type
;
139 struct texai_tile_state
143 int orig_worst_worked
;
144 int old_worst_worked
;
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
)
160 bool potential_worst_worked
= FALSE
;
162 if (!city_can_work_tile(pcity
, ptile
)) {
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
) {
190 } unit_list_iterate_end
;
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
)) {
210 } unit_list_iterate_end
;
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
;
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
;
233 state
->worst_worked
= value
;
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
;
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
) {
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
)) {
266 } as_rmextra_activity_iterate_end
;
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
)) {
274 } as_extra_activity_iterate_end
;
276 } unit_list_iterate_end
;
278 if (act
!= ACTIVITY_LAST
) {
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
) {
292 } unit_list_iterate_end
;
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
)) {
304 int mc_multiplier
= 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
;
326 if (proad
->move_cost
== 0) {
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
;
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
;
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
;
364 state
->worst_worked
= value
;
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
;
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
;
407 case TWTL_CURRENT_UNITS
:
408 units
= pplayer
->units
;
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
;
422 city_tile_iterate_index(city_map_radius_sq_get(pcity
), city_tile(pcity
),
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
;
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
);
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
);
461 target
= selected
->tgt
;
464 task
->ptile
= selected
->ptile
;
465 task
->act
= selected
->act
;
467 task
->want
= selected
->want
;
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
;
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);
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
);
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
);