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