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 <string.h>
19
20 /* utility */
21 #include "log.h"
22
23 /* common */
24 #include "game.h"
25 #include "government.h"
26 #include "player.h"
27 #include "research.h"
28 #include "tech.h"
29
30 /* server */
31 #include "plrhand.h"
32 #include "srv_log.h"
33 #include "techtools.h"
34
35 /* server/advisors */
36 #include "advdata.h"
37
38 /* ai/default */
39 #include "aidata.h"
40 #include "ailog.h"
41 #include "aiplayer.h"
42 #include "aitools.h"
43 #include "daieffects.h"
44
45 #include "aitech.h"
46
47 struct ai_tech_choice {
48 Tech_type_id choice; /* The id of the most needed tech */
49 adv_want want; /* Want of the most needed tech */
50 adv_want current_want; /* Want of the tech which is currently researched
51 * or is our current goal */
52 };
53
54 /**************************************************************************
55 Massage the numbers provided to us by ai.tech_want into unrecognizable
56 pulp.
57
58 TODO: Write a transparent formula.
59
60 Notes: 1. research_goal_unknown_techs returns 0 for known techs, 1 if tech
61 is immediately available etc.
62 2. A tech is reachable means we can research it now; tech is available
63 means it's on our tech tree (different nations can have different techs).
64 3. ai.tech_want is usually upped by each city, so it is divided by number
65 of cities here.
66 4. A tech isn't a requirement of itself.
67 **************************************************************************/
dai_select_tech(struct ai_type * ait,struct player * pplayer,struct ai_tech_choice * choice,struct ai_tech_choice * goal)68 static void dai_select_tech(struct ai_type *ait,
69 struct player *pplayer,
70 struct ai_tech_choice *choice,
71 struct ai_tech_choice *goal)
72 {
73 struct research *presearch = research_get(pplayer);
74 Tech_type_id newtech, newgoal;
75 int num_cities_nonzero = MAX(1, city_list_size(pplayer->cities));
76 int values[MAX(A_LAST, A_UNSET + 1)];
77 int goal_values[MAX(A_LAST, A_UNSET + 1)];
78 struct ai_plr *plr_data = def_ai_player_data(pplayer, ait);
79
80 memset(values, 0, sizeof(values));
81 values[A_UNSET] = -1;
82 values[A_NONE] = -1;
83 goal_values[A_UNSET] = -1;
84 goal_values[A_NONE] = -1;
85
86 /* if we are researching future techs, then simply continue with that.
87 * we don't need to do anything below. */
88 if (is_future_tech(presearch->researching)) {
89 if (choice) {
90 choice->choice = presearch->researching;
91 choice->want = 1;
92 choice->current_want = 1;
93 }
94 if (goal) {
95 goal->choice = A_UNSET;
96 goal->want = 1;
97 goal->current_want = 1;
98 }
99 return;
100 }
101
102 /* Fill in values for the techs: want of the tech
103 * + average want of those we will discover en route */
104 advance_index_iterate(A_FIRST, i) {
105 if (valid_advance_by_number(i)) {
106 int steps = research_goal_unknown_techs(presearch, i);
107
108 /* We only want it if we haven't got it (so AI is human after all) */
109 if (steps > 0) {
110 values[i] += plr_data->tech_want[i];
111 advance_index_iterate(A_FIRST, k) {
112 if (research_goal_tech_req(presearch, i, k)) {
113 values[k] += plr_data->tech_want[i] / steps;
114 }
115 } advance_index_iterate_end;
116 }
117 }
118 } advance_index_iterate_end;
119
120 /* Fill in the values for the tech goals */
121 advance_index_iterate(A_FIRST, i) {
122 if (valid_advance_by_number(i)) {
123 int steps = research_goal_unknown_techs(presearch, i);
124
125 if (steps == 0) {
126 /* Can't be set as a goal any more */
127 goal_values[i] = -1;
128 continue;
129 }
130
131 goal_values[i] = values[i];
132 advance_index_iterate(A_FIRST, k) {
133 if (research_goal_tech_req(presearch, i, k)) {
134 goal_values[i] += values[k];
135 }
136 } advance_index_iterate_end;
137
138 /* This is the best I could do. It still sometimes does freaky stuff
139 * like setting goal to Republic and learning Monarchy, but that's what
140 * it's supposed to be doing; it just looks strange. -- Syela */
141 goal_values[i] /= steps;
142 if (steps < 6) {
143 log_debug("%s: want = " ADV_WANT_PRINTF ", value = %d, goal_value = %d",
144 advance_rule_name(advance_by_number(i)),
145 plr_data->tech_want[i],
146 values[i], goal_values[i]);
147 }
148 }
149 } advance_index_iterate_end;
150
151 newtech = A_UNSET;
152 newgoal = A_UNSET;
153 advance_index_iterate(A_FIRST, i) {
154 if (valid_advance_by_number(i)) {
155 if (values[i] > values[newtech]
156 && research_invention_gettable(presearch, i, TRUE)) {
157 newtech = i;
158 }
159 if (goal_values[i] > goal_values[newgoal]
160 && research_invention_reachable(presearch, i)) {
161 newgoal = i;
162 }
163 }
164 } advance_index_iterate_end;
165 #ifdef REALLY_DEBUG_THIS
166 advance_index_iterate(A_FIRST, id) {
167 if (values[id] > 0
168 && research_invention_state(presearch, id) == TECH_PREREQS_KNOWN) {
169 TECH_LOG(ait, LOG_DEBUG, pplayer, advance_by_number(id),
170 "turn end want: %d", values[id]);
171 }
172 } advance_index_iterate_end;
173 #endif /* REALLY_DEBUG_THIS */
174 if (choice) {
175 choice->choice = newtech;
176 choice->want = values[newtech] / num_cities_nonzero;
177 choice->current_want = (values[presearch->researching]
178 / num_cities_nonzero);
179 }
180
181 if (goal) {
182 goal->choice = newgoal;
183 goal->want = goal_values[newgoal] / num_cities_nonzero;
184 goal->current_want = (goal_values[presearch->tech_goal]
185 / num_cities_nonzero);
186 log_debug("Goal->choice = %s, goal->want = " ADV_WANT_PRINTF ", goal_value = %d, "
187 "num_cities_nonzero = %d",
188 research_advance_rule_name(presearch, goal->choice),
189 goal->want,
190 goal_values[newgoal],
191 num_cities_nonzero);
192 }
193
194 /* we can't have this, which will happen in the circumstance
195 * where all ai.tech_wants are negative */
196 if (choice && choice->choice == A_UNSET) {
197 choice->choice = presearch->researching;
198 }
199
200 return;
201 }
202
203 /**************************************************************************
204 Calculates want for some techs by actually adding the tech and
205 measuring the effect.
206 **************************************************************************/
dai_tech_base_want(struct ai_type * ait,struct player * pplayer,struct city * pcity,struct advance * padv)207 static adv_want dai_tech_base_want(struct ai_type *ait, struct player *pplayer,
208 struct city *pcity, struct advance *padv)
209 {
210 struct research *pres = research_get(pplayer);
211 Tech_type_id tech = advance_number(padv);
212 enum tech_state old_state = research_invention_state(pres, tech);
213 struct adv_data *adv = adv_data_get(pplayer, NULL);
214 adv_want orig_want = dai_city_want(pplayer, pcity, adv, NULL);
215 adv_want final_want;
216 bool world_knew = game.info.global_advances[tech];
217
218 research_invention_set(pres, tech, TECH_KNOWN);
219
220 final_want = dai_city_want(pplayer, pcity, adv, NULL);
221
222 research_invention_set(pres, tech, old_state);
223 game.info.global_advances[tech] = world_knew;
224
225 return final_want - orig_want;
226 }
227
228 /**************************************************************************
229 Add effect values in to tech wants.
230 **************************************************************************/
dai_tech_effect_values(struct ai_type * ait,struct player * pplayer)231 static void dai_tech_effect_values(struct ai_type *ait, struct player *pplayer)
232 {
233 /* TODO: Currently this duplicates code from aicity.c improvement effect
234 * evaluating almost verbose - refactor so that they can share code. */
235 struct government *gov = government_of_player(pplayer);
236 struct adv_data *adv = adv_data_get(pplayer, NULL);
237 struct ai_plr *aip = def_ai_player_data(pplayer, ait);
238 int turns = 9999; /* TODO: Set to correct value */
239 int nplayers = normal_player_count();
240
241 /* Remove team members from the equation */
242 players_iterate(aplayer) {
243 if (aplayer->team
244 && aplayer->team == pplayer->team
245 && aplayer != pplayer) {
246 nplayers--;
247 }
248 } players_iterate_end;
249
250 advance_iterate(A_FIRST, padv) {
251 if (research_invention_state(research_get(pplayer), advance_number(padv))
252 != TECH_KNOWN) {
253 struct universal source = { .kind = VUT_ADVANCE, .value.advance = padv };
254
255 city_list_iterate(pplayer->cities, pcity) {
256 adv_want v;
257 adv_want tech_want;
258 bool capital;
259
260 v = dai_tech_base_want(ait, pplayer, pcity, padv);
261 capital = is_capital(pcity);
262
263 effect_list_iterate(get_req_source_effects(&source), peffect) {
264 bool present = TRUE;
265 bool active = TRUE;
266
267 requirement_vector_iterate(&peffect->reqs, preq) {
268 /* Check if all the requirements for the currently evaluated effect
269 * are met, except for having the tech that we are evaluating.
270 * TODO: Consider requirements that could be met later. */
271 if (VUT_ADVANCE == preq->source.kind
272 && preq->source.value.advance == padv) {
273 present = preq->present;
274 continue;
275 }
276 if (!is_req_active(pplayer, NULL, pcity, NULL, NULL, NULL, NULL,
277 NULL, NULL, preq, RPT_POSSIBLE)) {
278 active = FALSE;
279 break; /* presence doesn't matter for inactive effects. */
280
281 }
282 } requirement_vector_iterate_end;
283
284 if (active) {
285 adv_want v1;
286
287 v1 = dai_effect_value(pplayer, gov, adv, pcity, capital,
288 turns, peffect, 1,
289 nplayers);
290
291 if (!present) {
292 /* Tech removes the effect */
293 v -= v1;
294 } else {
295 v += v1;
296 }
297 }
298 } effect_list_iterate_end;
299
300 /* Same conversion factor as in want_tech_for_improvement_effect() */
301 tech_want = v * 14 / 8;
302
303 aip->tech_want[advance_index(padv)] += tech_want;
304 } city_list_iterate_end;
305 }
306 } advance_iterate_end;
307 }
308
309 /**************************************************************************
310 Key AI research function. Disable if we are in a team with human team
311 mates in a research pool.
312 **************************************************************************/
dai_manage_tech(struct ai_type * ait,struct player * pplayer)313 void dai_manage_tech(struct ai_type *ait, struct player *pplayer)
314 {
315 struct ai_tech_choice choice, goal;
316 struct research *research = research_get(pplayer);
317 /* Penalty for switching research */
318 int penalty = (research->got_tech ? 0 : research->bulbs_researched);
319
320 /* Even when we let human to do the final decision, we keep our
321 * wants correctly calculated. Add effect values in */
322 dai_tech_effect_values(ait, pplayer);
323
324 /* If there are humans in our team, they will choose the techs */
325 players_iterate(aplayer) {
326 const struct player_diplstate *ds = player_diplstate_get(pplayer, aplayer);
327
328 if (ds->type == DS_TEAM) {
329 return;
330 }
331 } players_iterate_end;
332
333 dai_select_tech(ait, pplayer, &choice, &goal);
334 if (choice.choice != research->researching) {
335 /* changing */
336 if (choice.want - choice.current_want > penalty
337 && (penalty + research->bulbs_researched
338 <= research_total_bulbs_required(research, research->researching,
339 FALSE))) {
340 TECH_LOG(ait, LOG_DEBUG, pplayer, advance_by_number(choice.choice),
341 "new research, was %s, penalty was %d",
342 research_advance_rule_name(research, research->researching),
343 penalty);
344 choose_tech(research, choice.choice);
345 }
346 }
347
348 /* crossing my fingers on this one! -- Syela (seems to have worked!) */
349 /* It worked, in particular, because the value it sets (research->tech_goal)
350 * is practically never used, see the comment for ai_next_tech_goal */
351 if (goal.choice != research->tech_goal) {
352 log_debug("%s change goal from %s (want=" ADV_WANT_PRINTF
353 ") to %s (want=" ADV_WANT_PRINTF ")",
354 player_name(pplayer),
355 research_advance_rule_name(research, research->tech_goal),
356 goal.current_want,
357 research_advance_rule_name(research, goal.choice),
358 goal.want);
359 choose_tech_goal(research, goal.choice);
360 }
361 }
362
363 /**************************************************************************
364 Returns the best defense multiplier unit we can build, or NULL if none.
365 Assigns tech wants for techs to get better units, but only for the
366 cheapest to research.
367 **************************************************************************/
dai_wants_defender_against(struct ai_type * ait,struct player * pplayer,struct city * pcity,struct unit_type * att,int want)368 struct unit_type *dai_wants_defender_against(struct ai_type *ait,
369 struct player *pplayer,
370 struct city *pcity,
371 struct unit_type *att, int want)
372 {
373 struct research *presearch = research_get(pplayer);
374 int best_avl_def = 0;
375 struct unit_type *best_avl = NULL;
376 int best_cost = FC_INFINITY;
377 struct advance *best_tech = A_NEVER;
378 struct unit_type *best_unit = NULL;
379 int def_values[U_LAST];
380 int att_idx = utype_index(att);
381
382 unit_type_iterate(deftype) {
383 int mp = deftype->cache.defense_mp_bonuses[att_idx] + 1;
384 int div_bonus = combat_bonus_against(att->bonuses, deftype, CBONUS_DEFENSE_DIVIDER) + 1;
385 int def = deftype->defense_strength * mp / div_bonus;
386
387 def_values[utype_index(deftype)] = def;
388
389 if (can_city_build_unit_now(pcity, deftype)) {
390 if (def > best_avl_def) {
391 best_avl_def = def;
392 best_avl = deftype;
393 }
394 }
395 } unit_type_iterate_end;
396
397 unit_type_iterate(deftype) {
398 if (def_values[utype_index(deftype)] > best_avl_def
399 && !can_city_build_unit_now(pcity, deftype)
400 && can_city_build_unit_later(pcity, deftype)) {
401 /* It would be better than current best. Consider researching tech */
402 int cost = 0;
403 struct advance *itech = deftype->require_advance;
404 bool impossible_to_get = FALSE;
405
406 if (A_NEVER != itech
407 && research_invention_state(presearch,
408 advance_number(itech)) != TECH_KNOWN) {
409 /* See if we want to invent this. */
410 cost = research_goal_bulbs_required(presearch,
411 advance_number(itech));
412 }
413 if (deftype->need_improvement
414 && !can_player_build_improvement_direct(pplayer, deftype->need_improvement)) {
415 struct impr_type *building = deftype->need_improvement;
416
417 requirement_vector_iterate(&building->reqs, preq) {
418 if (!is_req_active(pplayer, NULL, pcity, building, city_tile(pcity),
419 NULL, deftype, NULL, NULL, preq, RPT_CERTAIN)) {
420
421 if (VUT_ADVANCE == preq->source.kind && preq->present) {
422 int iimprtech = advance_number(preq->source.value.advance);
423 int imprcost = research_goal_bulbs_required(presearch,
424 iimprtech);
425
426 if (imprcost < cost || cost == 0) {
427 /* If we already have the primary tech (cost == 0),
428 * or the building's tech is cheaper,
429 * go for the building's required tech. */
430 itech = preq->source.value.advance;
431 cost = 0;
432 }
433 cost += imprcost;
434 } else if (!dai_can_requirement_be_met_in_city(preq, pplayer,
435 pcity)) {
436 impossible_to_get = TRUE;
437 }
438 }
439 } requirement_vector_iterate_end;
440 }
441
442 if (cost < best_cost && !impossible_to_get
443 && research_invention_reachable(presearch, advance_number(itech))) {
444 best_tech = itech;
445 best_cost = cost;
446 best_unit = deftype;
447 }
448 }
449 } unit_type_iterate_end;
450
451 if (A_NEVER != best_tech) {
452 struct ai_plr *plr_data = def_ai_player_data(pplayer, ait);
453
454 /* Crank up chosen tech want */
455 if (best_avl != NULL
456 && def_values[utype_index(best_unit)] <= 1.5 * best_avl_def) {
457 /* We already have almost as good unit suitable for defending against this attacker */
458 want /= 2;
459 }
460
461 plr_data->tech_want[advance_index(best_tech)] += want;
462 TECH_LOG(ait, LOG_DEBUG, pplayer, best_tech,
463 "+ %d for %s by role",
464 want,
465 utype_rule_name(best_unit));
466 }
467
468 return best_avl;
469 }
470
471 /**************************************************************************
472 Returns the best unit we can build, or NULL if none. "Best" here
473 means last in the unit list as defined in the ruleset. Assigns tech
474 wants for techs to get better units with given role, but only for the
475 cheapest to research "next" unit up the "chain".
476 **************************************************************************/
dai_wants_role_unit(struct ai_type * ait,struct player * pplayer,struct city * pcity,int role,int want)477 struct unit_type *dai_wants_role_unit(struct ai_type *ait, struct player *pplayer,
478 struct city *pcity, int role, int want)
479 {
480 struct research *presearch = research_get(pplayer);
481 int i, n;
482 int best_cost = FC_INFINITY;
483 struct advance *best_tech = A_NEVER;
484 struct unit_type *best_unit = NULL;
485 struct unit_type *build_unit = NULL;
486
487 n = num_role_units(role);
488 for (i = n - 1; i >= 0; i--) {
489 struct unit_type *iunit = get_role_unit(role, i);
490 struct advance *itech = iunit->require_advance;
491
492 if (can_city_build_unit_now(pcity, iunit)) {
493 build_unit = iunit;
494 break;
495 } else if (can_city_build_unit_later(pcity, iunit)) {
496 int cost = 0;
497
498 if (A_NEVER != itech
499 && research_invention_state(presearch,
500 advance_number(itech)) != TECH_KNOWN) {
501 /* See if we want to invent this. */
502 cost = research_goal_bulbs_required(presearch,
503 advance_number(itech));
504 }
505 if (iunit->need_improvement
506 && !can_player_build_improvement_direct(pplayer, iunit->need_improvement)) {
507 struct impr_type *building = iunit->need_improvement;
508
509 requirement_vector_iterate(&building->reqs, preq) {
510 if (VUT_ADVANCE == preq->source.kind && preq->present) {
511 int iimprtech = advance_number(preq->source.value.advance);
512
513 if (TECH_KNOWN != research_invention_state(presearch,
514 iimprtech)) {
515 int imprcost = research_goal_bulbs_required(presearch,
516 iimprtech);
517
518 if (imprcost < cost || cost == 0) {
519 /* If we already have the primary tech (cost==0),
520 * or the building's tech is cheaper,
521 * go for the building's required tech. */
522 itech = preq->source.value.advance;
523 cost = 0;
524 }
525 cost += imprcost;
526 }
527 }
528 } requirement_vector_iterate_end;
529 }
530
531 if (cost < best_cost
532 && research_invention_reachable(presearch, advance_number(itech))) {
533 best_tech = itech;
534 best_cost = cost;
535 best_unit = iunit;
536 }
537 }
538 }
539
540 if (A_NEVER != best_tech) {
541 struct ai_plr *plr_data = def_ai_player_data(pplayer, ait);
542
543 /* Crank up chosen tech want */
544 if (build_unit != NULL) {
545 /* We already have a role unit of this kind */
546 want /= 2;
547 }
548 plr_data->tech_want[advance_index(best_tech)] += want;
549 TECH_LOG(ait, LOG_DEBUG, pplayer, best_tech,
550 "+ %d for %s by role",
551 want,
552 utype_rule_name(best_unit));
553 }
554 return build_unit;
555 }
556
557 /**************************************************************************
558 Zero player tech wants
559 **************************************************************************/
dai_clear_tech_wants(struct ai_type * ait,struct player * pplayer)560 void dai_clear_tech_wants(struct ai_type *ait, struct player *pplayer)
561 {
562 struct ai_plr *plr_data = def_ai_player_data(pplayer, ait);
563
564 advance_index_iterate(A_FIRST, i) {
565 plr_data->tech_want[i] = 0;
566 } advance_index_iterate_end;
567 }
568