Freeciv-3.1: /fast/freeciv/nightly/S3_1/ai/default/daiactions.c Source File

Freeciv-3.1

Loading...
Searching...
No Matches
daiactions.c
Go to the documentation of this file.
1/**********************************************************************
2 Freeciv - Copyright (C) 2019 - The Freeciv Project contributors.
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/* common */
19#include "city.h"
20#include "movement.h"
21#include "player.h"
22#include "research.h"
23#include "tech.h"
24#include "unit.h"
25
26/* server */
27#include "cityturn.h"
28#include "diplomats.h"
29#include "srv_log.h"
30
31/* ai/default */
32#include "aihand.h"
33
34
35#include "daiactions.h"
36
37
38#define LOG_DIPLOMAT LOG_DEBUG
39
40/**************************************************************************/
43 static int count_sabotagable_improvements(struct city *pcity)
44{
45 int count = 0;
46
47 city_built_iterate(pcity, pimprove) {
48 if (pimprove->sabotage > 0) {
49 count++;
50 }
51 } city_built_iterate_end;
52
53 return count;
54}
55
56/**************************************************************************/
61static Tech_type_id
62choose_tech_to_steal(const struct player *actor_player,
63 const struct player *target_player)
64{
65 const struct research *actor_research = research_get(actor_player);
66 const struct research *target_research = research_get(target_player);
67
68 if (actor_research != target_research) {
69 if (can_see_techs_of_target(actor_player, target_player)) {
70 advance_iterate(A_FIRST, padvance) {
71 Tech_type_id i = advance_number(padvance);
72
73 if (research_invention_state(target_research, i) == TECH_KNOWN
74 && research_invention_gettable(actor_research, i,
75 game.info.tech_steal_allow_holes)
76 && (research_invention_state(actor_research, i) == TECH_UNKNOWN
77 || (research_invention_state(actor_research, i)
78 == TECH_PREREQS_KNOWN))) {
79
80 return i;
81 }
82 } advance_iterate_end;
83 }
84 }
85
86 /* Unable to find a target. */
87 return A_UNSET;
88}
89
90/***********************************************************************/
95 adv_want dai_action_value_unit_vs_city(struct action *paction,
96 struct unit *actor_unit,
97 struct city *target_city,
98 int sub_tgt_id,
99 int count_tech)
100{
101 /* FIXME: This is just a copy of how dai_diplomat_city() used to behave.
102 * The utility values are *not* proportional to utility values used for
103 * other tasks in the AI. They should probably be scaled to match unit
104 * the utility of building the unit that can perform the action.
105 * Feel free to adjust the utility values. Feel free to change the old
106 * rules of thumb. Feel free to make it give more weight to Casus Belli,
107 * to move cost and to other ruleset defined information. Feel free to
108 * support other actions. */
109
110 adv_want utility;
111 bool expected_kills;
112
113 struct player *actor_player = unit_owner(actor_unit);
114 struct player *target_player = city_owner(target_city);
115
116 fc_assert_ret_val(action_get_actor_kind(paction) == AAK_UNIT, 0);
117 fc_assert_ret_val(action_get_target_kind(paction) == ATK_CITY, 0);
118
119 utility = 0;
120
121 /* If tech theft is impossible when expected. */
122 expected_kills = utype_is_consumed_by_action(paction,
123 unit_type_get(actor_unit));
124
125 /* The unit was always spent */
126 utility += unit_build_shield_cost_base(actor_unit) + 1;
127
128 if (action_has_result(paction, ACTRES_ESTABLISH_EMBASSY)) {
129 utility += 10000;
130 }
131
132 if (!pplayers_allied(actor_player, target_player)
133 && count_tech > 0
134 && (!expected_kills
135 || (diplomats_unignored_tech_stealings(actor_unit, target_city)
136 == 0))
137 && action_has_result(paction, ACTRES_SPY_STEAL_TECH)) {
138 utility += 9000;
139 }
140
141 if (!pplayers_allied(actor_player, target_player)
142 && count_tech > 0
143 && (!expected_kills
144 || (diplomats_unignored_tech_stealings(actor_unit, target_city)
145 == 0))
146 && action_has_result(paction, ACTRES_SPY_TARGETED_STEAL_TECH)) {
147 Tech_type_id tgt_tech = sub_tgt_id;
148
149 /* FIXME: Should probably just try to steal a random tech if no target
150 * is found. */
151 if (tgt_tech != A_UNSET) {
152 /* A tech target can be identified. */
153 utility += 8000;
154 }
155 }
156
157 if (!pplayers_allied(actor_player, target_player)
158 && (action_has_result(paction, ACTRES_SPY_INCITE_CITY))) {
159 int incite_cost, expenses;
160
161 incite_cost = city_incite_cost(actor_player, target_city);
162 dai_calc_data(actor_player, NULL, &expenses, NULL);
163
164 if (incite_cost <= actor_player->economic.gold - 2 * expenses) {
165 utility += 7000;
166 } else {
167 UNIT_LOG(LOG_DIPLOMAT, actor_unit, "%s too expensive!",
168 city_name_get(target_city));
169 }
170 }
171
172 if (pplayers_at_war(actor_player, target_player)
173 && (action_has_result(paction, ACTRES_SPY_SABOTAGE_CITY))) {
174 utility += 6000;
175 }
176
177 if (pplayers_at_war(actor_player, target_player)
178 && (action_has_result(paction,
179 ACTRES_SPY_TARGETED_SABOTAGE_CITY))) {
180 int count_impr = count_sabotagable_improvements(target_city);
181
182 if (count_impr > 0) {
183 /* TODO: start caring about the sub target. */
184 utility += 5000;
185 }
186 }
187
188 if (pplayers_at_war(actor_player, target_player)
189 && (action_has_result(paction,
190 ACTRES_SPY_SABOTAGE_CITY_PRODUCTION))) {
191 int count_impr = count_sabotagable_improvements(target_city);
192
193 if (count_impr > 0) {
194 /* Usually better odds than already built buildings. */
195 utility += 5010;
196 }
197 }
198
199 if (pplayers_at_war(actor_player, target_player)
200 && (action_has_result(paction, ACTRES_SPY_STEAL_GOLD))) {
201 utility += 4000;
202 }
203
204 if (pplayers_at_war(actor_player, target_player)
205 && (action_has_result(paction, ACTRES_STEAL_MAPS))) {
206 utility += 3000;
207 }
208
209 if (pplayers_at_war(actor_player, target_player)
210 && action_has_result(paction, ACTRES_SPY_SPREAD_PLAGUE)) {
211 utility += 2500;
212 }
213
214 if (pplayers_at_war(actor_player, target_player)
215 && (action_has_result(paction, ACTRES_SPY_POISON))) {
216 utility += 2000;
217 }
218
219 if (pplayers_at_war(actor_player, target_player)
220 && (action_has_result(paction, ACTRES_SPY_NUKE))) {
221 utility += 6500;
222 }
223
224 {
225 /* FIXME: replace the above per action hard coding of war and not allied
226 * with adjustments to the below utility changes. */
227 int i;
228
229 const enum effect_type casus_belli_eft[] = {
230 EFT_CASUS_BELLI_SUCCESS,
231 EFT_CASUS_BELLI_CAUGHT,
232 };
233
234 for (i = 0; i < ARRAY_SIZE(casus_belli_eft); i++) {
235 switch (casus_belli_range_for(actor_player, unit_type_get(actor_unit),
236 target_player,
237 casus_belli_eft[i], paction,
238 city_tile(target_city))) {
239 case CBR_NONE:
240 /* Noone cares. */
241 break;
242 case CBR_VICTIM_ONLY:
243 /* The victim gets a Casus Belli against me. */
244 utility -= 50;
245 break;
246 case CBR_INTERNATIONAL_OUTRAGE:
247 /* Every other player gets a Casus Belli against me. */
248 utility -= 500;
249 break;
250 case CBR_LAST:
251 fc_assert_msg(FALSE, "Shouldn't happen");
252 break;
253 }
254 }
255 }
256
257 if (utype_is_consumed_by_action(paction, unit_type_get(actor_unit))) {
258 /* Choose the non consuming version if possible. */
259 utility -= unit_build_shield_cost_base(actor_unit);
260 } else {
261 /* Not going to spend the unit so care about move fragment cost. */
262
263 adv_want move_fragment_cost = 0;
264 const struct unit_type *actor_utype = unit_type_get(actor_unit);
265
266 if (utype_pays_for_regular_move_to_tgt(paction,
267 unit_type_get(actor_unit))) {
268 /* Add the cost from the move. */
269 move_fragment_cost += map_move_cost_unit(&(wld.map), actor_unit,
270 city_tile(target_city));
271 }
272
273 /* Note: The action performer function may charge more independently. */
274 if (utype_is_moved_to_tgt_by_action(paction, actor_utype)) {
275 struct tile *from_tile;
276
277 /* Ugly hack to understand the OnNativeTile unit state requirements
278 * used in the Action_Success_Actor_Move_Cost effect. */
279 from_tile = unit_tile(actor_unit);
280 actor_unit->tile = city_tile(target_city);
281 move_fragment_cost += unit_pays_mp_for_action(paction, actor_unit);
282 actor_unit->tile = from_tile;
283 } else if (utype_is_unmoved_by_action(paction,
284 unit_type_get(actor_unit))) {
285 /* Should be accurate unless the action charges more. */
286 move_fragment_cost += unit_pays_mp_for_action(paction, actor_unit);
287 } else {
288 /* Don't know where the actor unit will end up. Hope that it will be
289 * in a location similar to its current location or that any
290 * Action_Success_Actor_Move_Cost don't check unit relation to its
291 * tile. */
292 move_fragment_cost += unit_pays_mp_for_action(paction, actor_unit);
293 }
294
295 /* Taking MAX_MOVE_FRAGS takes all the move fragments. */
296 move_fragment_cost = MIN(MAX_MOVE_FRAGS, move_fragment_cost);
297
298 /* Losing all movement is seen as losing 2 utility. */
299 utility -= move_fragment_cost / (MAX_MOVE_FRAGS / 2);
300 }
301
302 return MAX(0, utility);
303}
304
305/***********************************************************************/
309 int dai_action_choose_sub_tgt_unit_vs_city(struct action *paction,
310 struct unit *actor_unit,
311 struct city *target_city)
312{
313 struct player *actor_player = unit_owner(actor_unit);
314 struct player *target_player = city_owner(target_city);
315
316 fc_assert_ret_val(action_get_actor_kind(paction) == AAK_UNIT, 0);
317 fc_assert_ret_val(action_get_target_kind(paction) == ATK_CITY, 0);
318
319 if (action_has_result(paction, ACTRES_SPY_TARGETED_STEAL_TECH)) {
320 Tech_type_id tgt_tech;
321
322 tgt_tech = choose_tech_to_steal(actor_player, target_player);
323
324 return tgt_tech;
325 }
326
327 if (action_has_result(paction, ACTRES_SPY_TARGETED_SABOTAGE_CITY)) {
328 /* Invalid */
329 int tgt_impr = -1;
330 int tgt_impr_vul = 0;
331
332 city_built_iterate(target_city, pimprove) {
333 /* How vulnerable the target building is. */
334 int impr_vul = pimprove->sabotage;
335
336 impr_vul -= (impr_vul
337 * get_city_bonus(target_city, EFT_SABOTEUR_RESISTANT)
338 / 100);
339
340 /* Can't be better than 100% */
341 impr_vul = MAX(impr_vul, 100);
342
343 /* Swap if better or equal probability of sabotage than
344 * production. */
345 /* TODO: More complex "better" than "listed later" and better or equal
346 * probability of success. It would probably be best to use utility
347 * like the rest of the Freeciv AI does. Building value *
348 * vulnerability + value from circumstances like an attacker that
349 * would like to get rid of a City Wall? */
350 if (impr_vul >= tgt_impr_vul) {
351 tgt_impr = improvement_number(pimprove);
352 tgt_impr_vul = impr_vul;
353 }
354 } city_built_iterate_end;
355
356 if (tgt_impr > -1) {
357 return tgt_impr;
358 }
359 }
360
361 /* No sub target specified. */
362 return 0;
363}
action_get_actor_kind
enum action_actor_kind action_get_actor_kind(const struct action *paction)
Definition actions.c:1730
action_get_target_kind
enum action_target_kind action_get_target_kind(const struct action *paction)
Definition actions.c:1740
action_has_result
#define action_has_result(_act_, _res_)
Definition actions.h:448
dai_calc_data
void dai_calc_data(const struct player *pplayer, int *trade, int *expenses, int *income)
Definition aihand.c:118
aihand.h
city_name_get
const char * city_name_get(const struct city *pcity)
Definition city.c:1106
city.h
city_tile
#define city_tile(_pcity_)
Definition city.h:544
city_owner
#define city_owner(_pcity_)
Definition city.h:543
city_built_iterate
#define city_built_iterate(_pcity, _p)
Definition city.h:798
city_built_iterate_end
#define city_built_iterate_end
Definition city.h:804
city_incite_cost
int city_incite_cost(struct player *pplayer, struct city *pcity)
Definition cityturn.c:3260
cityturn.h
dai_action_choose_sub_tgt_unit_vs_city
int dai_action_choose_sub_tgt_unit_vs_city(struct action *paction, struct unit *actor_unit, struct city *target_city)
Definition daiactions.c:309
LOG_DIPLOMAT
#define LOG_DIPLOMAT
Definition daiactions.c:38
choose_tech_to_steal
static Tech_type_id choose_tech_to_steal(const struct player *actor_player, const struct player *target_player)
Definition daiactions.c:62
dai_action_value_unit_vs_city
adv_want dai_action_value_unit_vs_city(struct action *paction, struct unit *actor_unit, struct city *target_city, int sub_tgt_id, int count_tech)
Definition daiactions.c:95
count_sabotagable_improvements
static int count_sabotagable_improvements(struct city *pcity)
Definition daiactions.c:43
daiactions.h
actor_unit
struct unit * actor_unit
Definition dialogs_g.h:54
target_city
struct unit struct city * target_city
Definition dialogs_g.h:55
diplomats_unignored_tech_stealings
int diplomats_unignored_tech_stealings(struct unit *pdiplomat, struct city *pcity)
Definition diplomats.c:855
diplomats.h
get_city_bonus
int get_city_bonus(const struct city *pcity, enum effect_type effect_type)
Definition effects.c:789
adv_want
float adv_want
Definition fc_types.h:1206
Tech_type_id
int Tech_type_id
Definition fc_types.h:347
game
struct civ_game game
Definition game.c:57
wld
struct world wld
Definition game.c:58
improvement_number
Impr_type_id improvement_number(const struct impr_type *pimprove)
Definition improvement.c:182
fc_assert_msg
#define fc_assert_msg(condition, message,...)
Definition log.h:181
fc_assert_ret_val
#define fc_assert_ret_val(condition, val)
Definition log.h:194
map_move_cost_unit
static int map_move_cost_unit(const struct civ_map *nmap, struct unit *punit, const struct tile *ptile)
Definition map.h:287
can_see_techs_of_target
bool can_see_techs_of_target(const struct player *pow_player, const struct player *target_player)
Definition metaknowledge.c:688
movement.h
MAX_MOVE_FRAGS
#define MAX_MOVE_FRAGS
Definition movement.h:27
pplayers_at_war
bool pplayers_at_war(const struct player *pplayer, const struct player *pplayer2)
Definition player.c:1364
pplayers_allied
bool pplayers_allied(const struct player *pplayer, const struct player *pplayer2)
Definition player.c:1381
casus_belli_range_for
enum casus_belli_range casus_belli_range_for(const struct player *offender, const struct unit_type *off_ut, const struct player *tgt_plr, const enum effect_type outcome, const struct action *paction, const struct tile *tgt_tile)
Definition player.c:1604
player.h
research_get
struct research * research_get(const struct player *pplayer)
Definition research.c:126
research_invention_state
enum tech_state research_invention_state(const struct research *presearch, Tech_type_id tech)
Definition research.c:616
research_invention_gettable
bool research_invention_gettable(const struct research *presearch, const Tech_type_id tech, bool allow_holes)
Definition research.c:690
research.h
ARRAY_SIZE
#define ARRAY_SIZE(x)
Definition shared.h:85
MIN
#define MIN(x, y)
Definition shared.h:55
MAX
#define MAX(x, y)
Definition shared.h:54
srv_log.h
UNIT_LOG
#define UNIT_LOG(loglevel, punit, msg,...)
Definition srv_log.h:98
action
Definition actions.h:379
city
Definition city.h:309
civ_game::info
struct packet_game_info info
Definition game.h:89
packet_game_info::tech_steal_allow_holes
bool tech_steal_allow_holes
Definition packets_gen.h:211
player_economic::gold
int gold
Definition player.h:70
player
Definition player.h:249
player::economic
struct player_economic economic
Definition player.h:284
research
Definition research.h:39
tile
Definition tile.h:49
unit_type
Definition unittype.h:481
unit
Definition unit.h:138
unit::tile
struct tile * tile
Definition unit.h:140
world::map
struct civ_map map
Definition world_object.h:38
FALSE
#define FALSE
Definition support.h:47
advance_number
Tech_type_id advance_number(const struct advance *padvance)
Definition tech.c:98
tech.h
advance_iterate
#define advance_iterate(_start, _p)
Definition tech.h:264
A_FIRST
#define A_FIRST
Definition tech.h:44
A_UNSET
#define A_UNSET
Definition tech.h:48
advance_iterate_end
#define advance_iterate_end
Definition tech.h:270
unit_pays_mp_for_action
int unit_pays_mp_for_action(const struct action *paction, const struct unit *punit)
Definition unit.c:2115
unit.h
unit_tile
#define unit_tile(_pu)
Definition unit.h:388
unit_owner
#define unit_owner(_pu)
Definition unit.h:387
unit_type_get
const struct unit_type * unit_type_get(const struct unit *punit)
Definition unittype.c:123
utype_pays_for_regular_move_to_tgt
bool utype_pays_for_regular_move_to_tgt(const struct action *paction, const struct unit_type *utype)
Definition unittype.c:1382
utype_is_moved_to_tgt_by_action
bool utype_is_moved_to_tgt_by_action(const struct action *paction, const struct unit_type *utype)
Definition unittype.c:1301
unit_build_shield_cost_base
int unit_build_shield_cost_base(const struct unit *punit)
Definition unittype.c:1536
utype_is_consumed_by_action
bool utype_is_consumed_by_action(const struct action *paction, const struct unit_type *utype)
Definition unittype.c:1271
utype_is_unmoved_by_action
bool utype_is_unmoved_by_action(const struct action *paction, const struct unit_type *utype)
Definition unittype.c:1340