Freeciv21
Develop your civilization from humble roots to a global empire
research.cpp
Go to the documentation of this file.
1 /*
2 _ ._ Copyright (c) 1996-2021 Freeciv21 and Freeciv contributors.
3  \ | This file is part of Freeciv21. Freeciv21 is free software: you
4  \_| can redistribute it and/or modify it under the terms of the
5  .' '. GNU General Public License as published by the Free
6  :O O: Software Foundation, either version 3 of the License,
7  '/ \' or (at your option) any later version. You should have
8  :X: received a copy of the GNU General Public License along with
9  :X: Freeciv21. If not, see https://www.gnu.org/licenses/.
10  */
11 // utility
12 #include "fcintl.h"
13 #include "iterator.h"
14 #include "log.h"
15 #include "shared.h"
16 #include "support.h"
17 
18 // common
19 #include "fc_types.h"
20 #include "game.h"
21 #include "name_translation.h"
22 #include "nation.h"
23 #include "player.h"
24 #include "team.h"
25 #include "tech.h"
26 
27 #include "research.h"
28 // FIXME: Dont use extern, move inside some game running class eventually
29 std::vector<research> research_array(MAX_NUM_PLAYER_SLOTS);
30 
32  struct iterator vtable;
33  union {
34  struct player *pplayer;
35  struct player_list_link *plink;
36  };
37 };
38 #define RESEARCH_PLAYER_ITER(p) ((struct research_player_iter *) p)
39 
43 
44 Q_GLOBAL_STATIC(QVector<QString>, future_rule_name)
45 Q_GLOBAL_STATIC(QVector<QString>, future_name_translation);
46 
51 {
52  // Ensure we have enough space for players or teams.
55 
56  for (auto &research : research_array) {
61  research.inventions[A_NONE].state = TECH_KNOWN;
63  {
65  }
67  }
68 
69  game.info.global_advances[A_NONE] = true;
70 
71  // Set technology names.
72  // TRANS: "None" tech
73  name_set(&advance_unset_name, nullptr, N_("?tech:None"));
74  name_set(&advance_future_name, nullptr, N_("Future Tech."));
75  /* TRANS: "Unknown" advance/technology */
76  name_set(&advance_unknown_name, nullptr, N_("(Unknown)"));
77 }
78 
83 {
84  future_rule_name->clear();
85  future_name_translation->clear();
86 }
87 
91 int research_number(const research *presearch)
92 {
93  fc_assert_ret_val(nullptr != presearch, 0);
94  return presearch - &research_array[0];
95 }
96 
100 struct research *research_by_number(int number)
101 {
102  fc_assert_ret_val(0 <= number, nullptr);
103  fc_assert_ret_val(research_array.size() > number, nullptr);
104  return &research_array[number];
105 }
106 
110 struct research *research_get(const struct player *pplayer)
111 {
112  if (nullptr == pplayer) {
113  // Special case used at client side.
114  return nullptr;
115  } else if (game.info.team_pooled_research) {
116  return &research_array[team_number(pplayer->team)];
117  } else {
118  return &research_array[player_number(pplayer)];
119  }
120 }
121 
125 bool research_is_valid(const struct research &presearch)
126 {
127  if (game.info.team_pooled_research) {
128  return team_by_number(research_number(&presearch)) != nullptr;
129  } else {
130  return player_by_number(research_number(&presearch)) != nullptr;
131  }
132 }
133 
137 const char *research_rule_name(const struct research *presearch)
138 {
139  if (game.info.team_pooled_research) {
140  return team_rule_name(team_by_number(research_number(presearch)));
141  } else {
142  return player_name(player_by_number(research_number(presearch)));
143  }
144 }
145 
150 const char *research_name_translation(const struct research *presearch)
151 {
152  if (game.info.team_pooled_research) {
154  } else {
155  return player_name(player_by_number(research_number(presearch)));
156  }
157 }
158 
163 int research_pretty_name(const struct research *presearch, char *buf,
164  size_t buf_len)
165 {
166  const struct player *pplayer;
167 
168  if (game.info.team_pooled_research) {
169  const struct team *pteam = team_by_number(research_number(presearch));
170 
171  if (1 != player_list_size(team_members(pteam))) {
172  QString buf2;
173 
174  team_pretty_name(pteam, buf2);
175  /* TRANS: e.g. "members of team 1", or even "members of team Red".
176  * Used in many places where a nation plural might be used. */
177  return fc_snprintf(buf, buf_len, _("members of %s"),
178  qUtf8Printable(buf2));
179  } else {
180  pplayer = player_list_front(team_members(pteam));
181  }
182  } else {
183  pplayer = player_by_number(research_number(presearch));
184  }
185 
186  return fc_strlcpy(buf, nation_plural_for_player(pplayer), buf_len);
187 }
188 
193 static inline const struct name_translation *
195 {
196  if (A_UNSET == tech) {
197  return &advance_unset_name;
198  } else if (A_FUTURE == tech) {
199  return &advance_future_name;
200  } else if (A_UNKNOWN == tech) {
201  return &advance_unknown_name;
202  } else {
203  const struct advance *padvance = advance_by_number(tech);
204 
205  fc_assert_ret_val(nullptr != padvance, nullptr);
206  return &padvance->name;
207  }
208 }
209 
214 static const char *research_future_set_name(QVector<QString> *psv, int no,
215  const char *new_name)
216 {
217  if (psv->count() <= no) {
218  // Increase the size of the vector if needed.
219  psv->resize(no + 1);
220  }
221 
222  // Set in vector.
223  psv->replace(no, new_name);
224 
225  // Return duplicate of 'new_name'.
226  return qstrdup(qUtf8Printable(psv->at(no)));
227 }
228 
233 QString research_advance_rule_name(const struct research *presearch,
234  Tech_type_id tech)
235 {
236  if (A_FUTURE == tech && nullptr != presearch) {
237  const int no = presearch->future_tech;
238 
239  if (no >= future_rule_name->size()) {
240  char buffer[256];
241 
242  // NB: 'presearch->future_tech == 0' means "Future Tech. 1".
243  fc_snprintf(buffer, sizeof(buffer), "%s %d",
245  return research_future_set_name(future_rule_name, no, buffer);
246  }
247  return future_rule_name->at(no);
248  }
249 
250  return rule_name_get(research_advance_name(tech));
251 }
252 
257 QString research_advance_name_translation(const struct research *presearch,
258  Tech_type_id tech)
259 {
260  if (A_FUTURE == tech && nullptr != presearch) {
261  const int no = presearch->future_tech;
262  QString name;
263 
264  if (no < future_name_translation->count()) {
265  // FIXME remove check to read outside vector
266  name = future_name_translation->at(no);
267  }
268  if (name.isEmpty()) {
269  char buffer[256];
270 
271  // NB: 'presearch->future_tech == 0' means "Future Tech. 1".
272  fc_snprintf(buffer, sizeof(buffer), _("Future Tech. %d"), no + 1);
273  name = research_future_set_name(future_name_translation, no, buffer);
274  }
275 
276  fc_assert(!name.isEmpty());
277 
278  return name;
279  }
280 
282 }
283 
290 static bool reqs_may_activate(const struct player *target_player,
291  const struct player *other_player,
292  const struct city *target_city,
293  const struct impr_type *target_building,
294  const struct tile *target_tile,
295  const struct unit *target_unit,
296  const struct unit_type *target_unittype,
297  const struct output_type *target_output,
298  const struct specialist *target_specialist,
299  const struct action *target_action,
300  const struct requirement_vector *reqs,
301  const enum req_problem_type prob_type,
302  const enum vision_layer vision_layer,
303  const enum national_intelligence nintel)
304 {
306  {
307  if (is_req_unchanging(preq)
308  && !is_req_active(target_player, other_player, target_city,
309  target_building, target_tile, target_unit,
310  target_unittype, target_output, target_specialist,
311  target_action, preq, prob_type, vision_layer,
312  nintel)) {
313  return false;
314  }
315  }
317  return true;
318 }
319 
330 static bool research_allowed(
331  const struct research *presearch, Tech_type_id tech,
332  bool (*reqs_eval)(
333  const struct player *tplr, const struct player *oplr,
334  const struct city *tcity, const struct impr_type *tbld,
335  const struct tile *ttile, const struct unit *tunit,
336  const struct unit_type *tutype, const struct output_type *top,
337  const struct specialist *tspe, const struct action *tact,
338  const struct requirement_vector *reqs,
339  const enum req_problem_type ptype, const enum vision_layer vlayer,
340  const enum national_intelligence nintel))
341 {
342  struct advance *adv;
343 
344  adv = valid_advance_by_number(tech);
345 
346  if (adv == nullptr) {
347  // Not a valid advance.
348  return false;
349  }
350 
351  research_players_iterate(presearch, pplayer)
352  {
353  if (reqs_eval(pplayer, nullptr, nullptr, nullptr, nullptr, nullptr,
354  nullptr, nullptr, nullptr, nullptr, &(adv->research_reqs),
355  RPT_CERTAIN, V_COUNT, NI_COUNT)) {
356  /* It is enough that one player that shares research is allowed to
357  * research it.
358  * Reasoning: Imagine a tech with that requires a nation in the
359  * player range. If the requirement applies to all players sharing
360  * research it will be illegal in research sharing games. To require
361  * that the player that fulfills the requirement must order it to be
362  * researched creates unnecessary bureaucracy. */
363  return true;
364  }
365  }
367 
368  return false;
369 }
370 
377 static bool research_get_reachable_rreqs(const struct research *presearch,
378  Tech_type_id tech)
379 {
380  bv_techs done;
381  std::vector<Tech_type_id> techs{tech};
382  BV_CLR_ALL(done);
383  BV_SET(done, A_NONE);
384  BV_SET(done, tech);
385  /* Check that all recursive requirements have their research_reqs
386  * in order. */
387  while (!techs.empty()) { // Iterate till there is no-more techs to check
388  auto iter_tech = techs[techs.size() - 1]; // Last Element
389  techs.pop_back(); // Remove Last element
390  if (presearch->inventions[iter_tech].state == TECH_KNOWN) {
391  /* This tech is already reached. What is required to research it and
392  * the techs it depends on is therefore irrelevant. */
393  continue;
394  }
395 
396  if (!research_allowed(presearch, iter_tech, reqs_may_activate)) {
397  /* It will always be illegal to start researching this tech because
398  * of unchanging requirements. Since it isn't already known and can't
399  * be researched it must be unreachable. */
400  return false;
401  }
402 
403  // Check if required techs are research_reqs reachable.
404  for (int req = 0; req < AR_SIZE; req++) {
405  Tech_type_id req_tech = advance_required(iter_tech, tech_req(req));
406 
407  if (valid_advance_by_number(req_tech) == nullptr) {
408  return false;
409  } else if (!BV_ISSET(done, req_tech)) {
410  techs.push_back(req_tech);
411  BV_SET(done, req_tech);
412  }
413  }
414  }
415 
416  return true;
417 }
418 
425 static bool research_get_reachable(const struct research *presearch,
426  Tech_type_id tech)
427 {
428  if (valid_advance_by_number(tech) == nullptr) {
429  return false;
430  } else {
432  {
433  if (advance_requires(proot, AR_ROOT) == proot) {
434  /* This tech requires itself; it can only be reached by special
435  * means (init_techs, lua script, ...).
436  * If you already know it, you can "reach" it; if not, not. (This
437  * case is needed for descendants of this tech.) */
438  if (presearch->inventions[advance_number(proot)].state
439  != TECH_KNOWN) {
440  return false;
441  }
442  } else {
443  for (int req = 0; req < AR_SIZE; req++) {
444  if (valid_advance(advance_requires(proot, tech_req(req)))
445  == nullptr) {
446  return false;
447  }
448  }
449  }
450  }
452  }
453 
454  // Check research reqs reachability.
455  return research_get_reachable_rreqs(presearch, tech);
456 }
457 
465 static bool research_get_root_reqs_known(const struct research *presearch,
466  Tech_type_id tech)
467 {
469  {
470  if (presearch->inventions[advance_number(proot)].state != TECH_KNOWN) {
471  return false;
472  }
473  }
475 
476  return true;
477 }
478 
486 void research_update(struct research *presearch)
487 {
488  int techs_researched;
489 
491  {
492  enum tech_state state = presearch->inventions[i].state;
493  bool root_reqs_known = true;
494  bool reachable = research_get_reachable(presearch, i);
495 
496  /* Finding if the root reqs of an unreachable tech isn't redundant.
497  * A tech can be unreachable via research but have known root reqs
498  * because of unfilfilled research_reqs. Unfulfilled research_reqs
499  * doesn't prevent the player from aquiring the tech by other means. */
500  root_reqs_known = research_get_root_reqs_known(presearch, i);
501 
502  if (reachable) {
503  if (state != TECH_KNOWN) {
504  // Update state.
505  state =
506  (root_reqs_known
507  && (presearch->inventions[advance_required(i, AR_ONE)]
508  .state
509  == TECH_KNOWN)
510  && (presearch->inventions[advance_required(i, AR_TWO)]
511  .state
512  == TECH_KNOWN)
513  && research_allowed(presearch, i, are_reqs_active)
514  ? TECH_PREREQS_KNOWN
515  : TECH_UNKNOWN);
516  }
517  } else {
518  fc_assert(state == TECH_UNKNOWN);
519  }
520  presearch->inventions[i].state = state;
521  presearch->inventions[i].reachable = reachable;
522  presearch->inventions[i].root_reqs_known = root_reqs_known;
523 
524  // Updates required_techs, num_required_techs and bulbs_required.
525  BV_CLR_ALL(presearch->inventions[i].required_techs);
526  presearch->inventions[i].num_required_techs = 0;
527  presearch->inventions[i].bulbs_required = 0;
528 
529  if (!reachable || state == TECH_KNOWN) {
530  continue;
531  }
532 
533  techs_researched = presearch->techs_researched;
535  {
536  Tech_type_id j = advance_number(preq);
537 
538  if (TECH_KNOWN == research_invention_state(presearch, j)) {
539  continue;
540  }
541 
542  BV_SET(presearch->inventions[i].required_techs, j);
543  presearch->inventions[i].num_required_techs++;
544  presearch->inventions[i].bulbs_required +=
545  research_total_bulbs_required(presearch, j, false);
546  /* This is needed to get a correct result for the
547  * research_total_bulbs_required() call when
548  * game.info.game.info.tech_cost_style is TECH_COST_CIV1CIV2. */
549  presearch->techs_researched++;
550  }
552  presearch->techs_researched = techs_researched;
553  }
555 
556 #ifdef FREECIV_DEBUG
558  {
559  QByteArray buf;
560  buf.reserve(advance_count() + 1);
561 
563  {
564  if (BV_ISSET(presearch->inventions[i].required_techs, j)) {
565  buf.insert(j, '1');
566  } else {
567  buf.insert(j, '0');
568  }
569  }
571  buf.insert(advance_count(), '\0');
572 
573  log_debug("%s: [%3d] %-25s => %s%s%s", research_rule_name(presearch), i,
575  tech_state_name(research_invention_state(presearch, i)),
576  presearch->inventions[i].reachable ? "" : " [unrechable]",
577  presearch->inventions[i].root_reqs_known
578  ? ""
579  : " [root reqs aren't known]");
580  log_debug("%s: [%3d] %s", research_rule_name(presearch), i,
581  qUtf8Printable(buf));
582  }
584 #endif // FREECIV_DEBUG
585 
586  for (int flag = 0; flag <= tech_flag_id_max(); flag++) {
587  // Iterate over all possible tech flags (0..max).
588  presearch->num_known_tech_with_flag[flag] = 0;
589 
591  {
592  if (TECH_KNOWN == research_invention_state(presearch, i)
593  && advance_has_flag(i, tech_flag_id(flag))) {
594  presearch->num_known_tech_with_flag[flag]++;
595  }
596  }
598  }
599 }
600 
609 enum tech_state research_invention_state(const struct research *presearch,
610  Tech_type_id tech)
611 {
613  tech_state(-1));
614 
615  if (nullptr != presearch) {
616  return presearch->inventions[tech].state;
617  } else if (game.info.global_advances[tech]) {
618  return TECH_KNOWN;
619  } else {
620  return TECH_UNKNOWN;
621  }
622 }
623 
627 enum tech_state research_invention_set(struct research *presearch,
628  Tech_type_id tech,
629  enum tech_state value)
630 {
631  enum tech_state old;
632 
634  tech_state(-1));
635 
636  old = presearch->inventions[tech].state;
637  if (old == value) {
638  return old;
639  }
640  presearch->inventions[tech].state = value;
641 
642  if (value == TECH_KNOWN) {
643  if (!game.info.global_advances[tech]) {
644  game.info.global_advances[tech] = true;
645  game.info.global_advance_count++;
646  }
647  }
648 
649  return old;
650 }
651 
659 bool research_invention_reachable(const struct research *presearch,
660  const Tech_type_id tech)
661 {
662  if (valid_advance_by_number(tech) == nullptr) {
663  return false;
664  } else if (presearch != nullptr) {
665  return presearch->inventions[tech].reachable;
666  } else {
667  for (const auto &research_iter : research_array) {
668  if (research_is_valid(research_iter)) {
669  if (research_iter.inventions[tech].reachable) {
670  return true;
671  }
672  }
673  };
674 
675  return false;
676  }
677 }
678 
686 bool research_invention_gettable(const struct research *presearch,
687  const Tech_type_id tech, bool allow_holes)
688 {
689  if (valid_advance_by_number(tech) == nullptr) {
690  return false;
691  } else if (presearch != nullptr) {
692  return (allow_holes
693  ? presearch->inventions[tech].root_reqs_known
694  : presearch->inventions[tech].state == TECH_PREREQS_KNOWN);
695  } else {
696  for (const auto &research_iter : research_array) {
697  if (research_is_valid(research_iter)) {
698  if (allow_holes ? research_iter.inventions[tech].root_reqs_known
699  : research_iter.inventions[tech].state
700  == TECH_PREREQS_KNOWN) {
701  return true;
702  }
703  }
704  };
705 
706  return false;
707  }
708 }
709 
714 Tech_type_id research_goal_step(const struct research *presearch,
715  Tech_type_id goal)
716 {
717  const struct advance *pgoal = valid_advance_by_number(goal);
718 
719  if (nullptr == pgoal || !research_invention_reachable(presearch, goal)) {
720  return A_UNSET;
721  }
722 
723  advance_req_iterate(pgoal, preq)
724  {
725  switch (research_invention_state(presearch, advance_number(preq))) {
726  case TECH_PREREQS_KNOWN:
727  return advance_number(preq);
728  case TECH_KNOWN:
729  case TECH_UNKNOWN:
730  break;
731  };
732  }
734  return A_UNSET;
735 }
736 
745 int research_goal_unknown_techs(const struct research *presearch,
746  Tech_type_id goal)
747 {
748  const struct advance *pgoal = valid_advance_by_number(goal);
749 
750  if (nullptr == pgoal) {
751  return 0;
752  } else if (nullptr != presearch) {
753  return presearch->inventions[goal].num_required_techs;
754  } else {
755  return pgoal->num_reqs;
756  }
757 }
758 
767 int research_goal_bulbs_required(const struct research *presearch,
768  Tech_type_id goal)
769 {
770  const struct advance *pgoal = valid_advance_by_number(goal);
771 
772  if (nullptr == pgoal) {
773  return 0;
774  } else if (nullptr != presearch) {
775  return presearch->inventions[goal].bulbs_required;
776  } else if (game.info.tech_cost_style == TECH_COST_CIV1CIV2) {
777  return game.info.base_tech_cost * pgoal->num_reqs * (pgoal->num_reqs + 1)
778  / 2;
779  } else {
780  int bulbs_required = 0;
781 
782  advance_req_iterate(pgoal, preq) { bulbs_required += preq->cost; }
784  return bulbs_required;
785  }
786 }
787 
794 bool research_goal_tech_req(const struct research *presearch,
795  Tech_type_id goal, Tech_type_id tech)
796 {
797  const struct advance *pgoal, *ptech;
798 
799  if (tech == goal || nullptr == (pgoal = valid_advance_by_number(goal))
800  || nullptr == (ptech = valid_advance_by_number(tech))) {
801  return false;
802  } else if (nullptr != presearch) {
803  return BV_ISSET(presearch->inventions[goal].required_techs, tech);
804  } else {
805  advance_req_iterate(pgoal, preq)
806  {
807  if (preq == ptech) {
808  return true;
809  }
810  }
812  return false;
813  }
814 }
815 
855 int research_total_bulbs_required(const struct research *presearch,
856  Tech_type_id tech, bool loss_value)
857 {
858  enum tech_cost_style tech_cost_style = game.info.tech_cost_style;
859  int members;
860  double base_cost, total_cost;
861  double leak = 0.0;
862 
863  if (!loss_value && nullptr != presearch && !is_future_tech(tech)
864  && research_invention_state(presearch, tech) == TECH_KNOWN) {
865  // A non-future tech which is already known costs nothing.
866  return 0;
867  }
868 
869  if (is_future_tech(tech)) {
870  // Future techs use style TECH_COST_CIV1CIV2.
871  tech_cost_style = TECH_COST_CIV1CIV2;
872  }
873 
874  fc_assert_msg(tech_cost_style_is_valid(tech_cost_style),
875  "Invalid tech_cost_style %d", tech_cost_style);
876  base_cost = 0.0;
877  switch (tech_cost_style) {
878  case TECH_COST_CIV1CIV2:
879  if (nullptr != presearch) {
880  base_cost = game.info.base_tech_cost * presearch->techs_researched;
881  break;
882  }
883 
884  fc_assert(presearch != nullptr);
885  fc__fallthrough; // No break; Fallback to using preset cost.
886  case TECH_COST_CLASSIC:
887  case TECH_COST_CLASSIC_PRESET:
888  case TECH_COST_EXPERIMENTAL:
889  case TECH_COST_EXPERIMENTAL_PRESET:
890  case TECH_COST_LINEAR: {
891  const struct advance *padvance = valid_advance_by_number(tech);
892 
893  if (nullptr != padvance) {
894  base_cost = padvance->cost;
895  } else {
896  fc_assert(nullptr != padvance); // Always fails.
897  }
898  } break;
899  }
900 
901  total_cost = 0.0;
902  members = 0;
903  research_players_iterate(presearch, pplayer)
904  {
905  members++;
906  total_cost +=
907  (base_cost * get_player_bonus(pplayer, EFT_TECH_COST_FACTOR));
908  }
910  if (0 == members) {
911  /* There is no more alive players for this research, no need to apply
912  * complicated modifiers. */
913  return base_cost * static_cast<double>(game.info.sciencebox) / 100.0;
914  }
915  base_cost = total_cost / members;
916 
917  fc_assert_msg(tech_leakage_style_is_valid(game.info.tech_leakage),
918  "Invalid tech_leakage %d", game.info.tech_leakage);
919  switch (game.info.tech_leakage) {
920  case TECH_LEAKAGE_NONE:
921  // no change
922  break;
923 
924  case TECH_LEAKAGE_EMBASSIES: {
925  int players = 0, players_with_tech_and_embassy = 0;
926 
927  players_iterate_alive(aplayer)
928  {
929  const struct research *aresearch = research_get(aplayer);
930 
931  players++;
932  if (aresearch == presearch
933  || (A_FUTURE == tech
934  ? aresearch->future_tech <= presearch->future_tech
935  : TECH_KNOWN
936  != research_invention_state(aresearch, tech))) {
937  continue;
938  }
939 
940  research_players_iterate(presearch, pplayer)
941  {
942  if (player_has_embassy(pplayer, aplayer)) {
943  players_with_tech_and_embassy++;
944  break;
945  }
946  }
948  }
950 
951  fc_assert_ret_val(0 < players, base_cost);
952  fc_assert(players >= players_with_tech_and_embassy);
953  leak = base_cost * players_with_tech_and_embassy
954  * game.info.tech_leak_pct / players / 100;
955  } break;
956 
957  case TECH_LEAKAGE_PLAYERS: {
958  int players = 0, players_with_tech = 0;
959 
960  players_iterate_alive(aplayer)
961  {
962  players++;
963  if (A_FUTURE == tech
964  ? research_get(aplayer)->future_tech > presearch->future_tech
965  : TECH_KNOWN
967  tech)) {
968  players_with_tech++;
969  }
970  }
972 
973  fc_assert_ret_val(0 < players, base_cost);
974  fc_assert(players >= players_with_tech);
975  leak = base_cost * players_with_tech * game.info.tech_leak_pct / players
976  / 100;
977  } break;
978 
979  case TECH_LEAKAGE_NO_BARBS: {
980  int players = 0, players_with_tech = 0;
981 
982  players_iterate_alive(aplayer)
983  {
984  if (is_barbarian(aplayer)) {
985  continue;
986  }
987  players++;
988  if (A_FUTURE == tech
989  ? research_get(aplayer)->future_tech > presearch->future_tech
990  : TECH_KNOWN
992  tech)) {
993  players_with_tech++;
994  }
995  }
997 
998  fc_assert_ret_val(0 < players, base_cost);
999  fc_assert(players >= players_with_tech);
1000  leak = base_cost * players_with_tech * game.info.tech_leak_pct / players
1001  / 100;
1002  } break;
1003  }
1004 
1005  if (leak > base_cost) {
1006  base_cost = 0.0;
1007  } else {
1008  base_cost -= leak;
1009  }
1010 
1011  /* Assign a science penalty to the AI at easier skill levels. This code
1012  * can also be adopted to create an extra-hard AI skill level where the AI
1013  * gets science benefits. */
1014 
1015  total_cost = 0.0;
1016  research_players_iterate(presearch, pplayer)
1017  {
1018  if (is_ai(pplayer)) {
1019  fc_assert(0 < pplayer->ai_common.science_cost);
1020  total_cost += base_cost * pplayer->ai_common.science_cost / 100.0;
1021  } else {
1022  total_cost += base_cost;
1023  }
1024  }
1026  base_cost = total_cost / members;
1027 
1028  base_cost *= static_cast<double>(game.info.sciencebox) / 100.0;
1029 
1030  return MAX(base_cost, 1);
1031 }
1032 
1037 int player_tech_upkeep(const struct player *pplayer)
1038 {
1039  const struct research *presearch = research_get(pplayer);
1040  int f = presearch->future_tech, t = presearch->techs_researched;
1041  double tech_upkeep = 0.0;
1042  double total_research_factor;
1043  int members;
1044 
1045  if (TECH_UPKEEP_NONE == game.info.tech_upkeep_style) {
1046  return 0;
1047  }
1048 
1049  total_research_factor = 0.0;
1050  members = 0;
1051  research_players_iterate(presearch, contributor)
1052  {
1053  total_research_factor +=
1054  (get_player_bonus(contributor, EFT_TECH_COST_FACTOR)
1055  + (is_ai(contributor) ? contributor->ai_common.science_cost / 100.0
1056  : 1));
1057  members++;
1058  }
1060  if (0 == members) {
1061  // No player still alive.
1062  return 0;
1063  }
1064 
1065  // Upkeep cost for 'normal' techs (t).
1066  fc_assert_msg(tech_cost_style_is_valid(game.info.tech_cost_style),
1067  "Invalid tech_cost_style %d", game.info.tech_cost_style);
1068  switch (game.info.tech_cost_style) {
1069  case TECH_COST_CIV1CIV2:
1070  /* sum_1^t x = t * (t + 1) / 2 */
1071  tech_upkeep += game.info.base_tech_cost * t * (t + 1) / 2;
1072  break;
1073  case TECH_COST_CLASSIC:
1074  case TECH_COST_CLASSIC_PRESET:
1075  case TECH_COST_EXPERIMENTAL:
1076  case TECH_COST_EXPERIMENTAL_PRESET:
1077  case TECH_COST_LINEAR:
1078  advance_iterate(A_FIRST, padvance)
1079  {
1080  if (TECH_KNOWN
1081  == research_invention_state(presearch, advance_number(padvance))) {
1082  tech_upkeep += padvance->cost;
1083  }
1084  }
1086  if (0 < f) {
1087  /* Upkeep cost for future techs (f) are calculated using style 0:
1088  * sum_t^(t+f) x = (f * (2 * t + f + 1) + 2 * t) / 2 */
1089  tech_upkeep += static_cast<double>(
1090  game.info.base_tech_cost * (f * (2 * t + f + 1) + 2 * t) / 2);
1091  }
1092  break;
1093  }
1094 
1095  tech_upkeep *= total_research_factor / members;
1096  tech_upkeep *= static_cast<double>(game.info.sciencebox) / 100.0;
1097  /* We only want to calculate the upkeep part of one player, not the
1098  * whole team! */
1099  tech_upkeep /= members;
1100  tech_upkeep /= game.info.tech_upkeep_divider;
1101 
1102  switch (game.info.tech_upkeep_style) {
1103  case TECH_UPKEEP_BASIC:
1104  tech_upkeep -= get_player_bonus(pplayer, EFT_TECH_UPKEEP_FREE);
1105  break;
1106  case TECH_UPKEEP_PER_CITY:
1107  tech_upkeep -= get_player_bonus(pplayer, EFT_TECH_UPKEEP_FREE);
1108  tech_upkeep *= city_list_size(pplayer->cities);
1109  break;
1110  case TECH_UPKEEP_NONE:
1111  fc_assert(game.info.tech_upkeep_style != TECH_UPKEEP_NONE);
1112  tech_upkeep = 0.0;
1113  }
1114 
1115  if (0.0 > tech_upkeep) {
1116  tech_upkeep = 0.0;
1117  }
1118 
1119  log_debug("[%s (%d)] tech upkeep: %d", player_name(pplayer),
1120  player_number(pplayer), (int) tech_upkeep);
1121  return static_cast<int>(tech_upkeep);
1122 }
1123 
1128 {
1129  return sizeof(struct research_player_iter);
1130 }
1131 
1135 static inline bool research_player_iter_valid_state(struct iterator *it)
1136 {
1137  const player *pplayer = static_cast<const player *>(iterator_get(it));
1138 
1139  return (nullptr == pplayer || pplayer->is_alive);
1140 }
1141 
1145 static void *research_player_iter_pooled_get(const struct iterator *it)
1146 {
1147  return player_list_link_data(RESEARCH_PLAYER_ITER(it)->plink);
1148 }
1149 
1154 {
1155  struct research_player_iter *rpit = RESEARCH_PLAYER_ITER(it);
1156 
1157  do {
1158  rpit->plink = player_list_link_next(rpit->plink);
1159  } while (!research_player_iter_valid_state(it));
1160 }
1161 
1165 static bool research_player_iter_pooled_valid(const struct iterator *it)
1166 {
1167  return nullptr != RESEARCH_PLAYER_ITER(it)->plink;
1168 }
1169 
1173 static void *research_player_iter_not_pooled_get(const struct iterator *it)
1174 {
1175  return RESEARCH_PLAYER_ITER(it)->pplayer;
1176 }
1177 
1182 {
1183  RESEARCH_PLAYER_ITER(it)->pplayer = nullptr;
1184 }
1185 
1190 {
1191  return nullptr != RESEARCH_PLAYER_ITER(it)->pplayer;
1192 }
1193 
1198  const struct research *presearch)
1199 {
1200  struct iterator *base = ITERATOR(it);
1201 
1202  if (game.info.team_pooled_research && nullptr != presearch) {
1206  it->plink = player_list_head(
1208  } else {
1212  it->pplayer =
1213  (nullptr != presearch ? player_by_number(research_number(presearch))
1214  : nullptr);
1215  }
1216 
1217  // Ensure we have consistent data.
1220  }
1221 
1222  return base;
1223 }
#define BV_CLR_ALL(bv)
Definition: bitvector.h:62
#define BV_SET(bv, bit)
Definition: bitvector.h:44
bool BV_ISSET(const BV &bv, int bit)
Definition: bitvector.h:37
char * techs
Definition: comments.cpp:27
static void base(QVariant data1, QVariant data2)
Action "Build Base" for choice dialog.
Definition: dialogs.cpp:2393
struct @19::@20 reqs
int get_player_bonus(const struct player *pplayer, enum effect_type effect_type)
Returns the effect bonus for a player.
Definition: effects.cpp:673
int Tech_type_id
Definition: fc_types.h:294
req_problem_type
Definition: fc_types.h:566
@ RPT_CERTAIN
Definition: fc_types.h:568
#define MAX_NUM_PLAYER_SLOTS
Definition: fc_types.h:24
#define _(String)
Definition: fcintl.h:50
#define N_(String)
Definition: fcintl.h:52
struct civ_game game
Definition: game.cpp:47
const char * name
Definition: inputfile.cpp:118
#define ITERATOR(p)
Definition: iterator.h:26
static void * iterator_get(const struct iterator *it)
Definition: iterator.h:39
static void iterator_next(struct iterator *it)
Definition: iterator.h:31
#define fc_assert_msg(condition, message,...)
Definition: log.h:96
#define fc_assert(condition)
Definition: log.h:89
#define fc_assert_ret_val(condition, val)
Definition: log.h:114
#define log_debug(message,...)
Definition: log.h:65
#define NAME_INIT
static void name_set(struct name_translation *ptrans, const char *domain, const char *vernacular_name)
static const char * rule_name_get(const struct name_translation *ptrans)
static const char * name_translation_get(const struct name_translation *ptrans)
const char * nation_plural_for_player(const struct player *pplayer)
Return the (translated) plural noun of the given nation of a player.
Definition: nation.cpp:155
struct player * player_by_number(const int player_id)
Return struct player pointer for the given player index.
Definition: player.cpp:768
int player_number(const struct player *pplayer)
Return the player index/number/id.
Definition: player.cpp:756
const char * player_name(const struct player *pplayer)
Return the leader name of the player.
Definition: player.cpp:816
bool player_has_embassy(const struct player *pplayer, const struct player *pplayer2)
Check if pplayer has an embassy with pplayer2.
Definition: player.cpp:195
static bool is_barbarian(const struct player *pplayer)
Definition: player.h:474
#define is_ai(plr)
Definition: player.h:227
#define players_iterate_alive_end
Definition: player.h:532
#define players_iterate_alive(_pplayer)
Definition: player.h:526
bool is_req_active(const struct player *target_player, const struct player *other_player, const struct city *target_city, const struct impr_type *target_building, const struct tile *target_tile, const struct unit *target_unit, const struct unit_type *target_unittype, const struct output_type *target_output, const struct specialist *target_specialist, const struct action *target_action, const struct requirement *req, const enum req_problem_type prob_type, const enum vision_layer vision_layer, const enum national_intelligence nintel)
Checks the requirement to see if it is active on the given target.
bool is_req_unchanging(const struct requirement *req)
Return TRUE if this is an "unchanging" requirement.
bool are_reqs_active(const struct player *target_player, const struct player *other_player, const struct city *target_city, const struct impr_type *target_building, const struct tile *target_tile, const struct unit *target_unit, const struct unit_type *target_unittype, const struct output_type *target_output, const struct specialist *target_specialist, const struct action *target_action, const struct requirement_vector *reqs, const enum req_problem_type prob_type, const enum vision_layer vision_layer, const enum national_intelligence nintel)
Checks the requirement(s) to see if they are active on the given target.
#define requirement_vector_iterate_end
Definition: requirements.h:80
#define requirement_vector_iterate(req_vec, preq)
Definition: requirements.h:78
void researches_init()
Initializes all player research structure.
Definition: research.cpp:50
int research_goal_unknown_techs(const struct research *presearch, Tech_type_id goal)
Returns the number of technologies the player need to research to get the goal technology.
Definition: research.cpp:745
bool research_invention_reachable(const struct research *presearch, const Tech_type_id tech)
Returns TRUE iff the given tech is ever reachable via research by the players sharing the research by...
Definition: research.cpp:659
bool research_goal_tech_req(const struct research *presearch, Tech_type_id goal, Tech_type_id tech)
Returns if the given tech has to be researched to reach the goal.
Definition: research.cpp:794
static bool research_allowed(const struct research *presearch, Tech_type_id tech, bool(*reqs_eval)(const struct player *tplr, const struct player *oplr, const struct city *tcity, const struct impr_type *tbld, const struct tile *ttile, const struct unit *tunit, const struct unit_type *tutype, const struct output_type *top, const struct specialist *tspe, const struct action *tact, const struct requirement_vector *reqs, const enum req_problem_type ptype, const enum vision_layer vlayer, const enum national_intelligence nintel))
Evaluates the legality of starting to research this tech according to reqs_eval() and the tech's rese...
Definition: research.cpp:330
enum tech_state research_invention_set(struct research *presearch, Tech_type_id tech, enum tech_state value)
Set research knowledge about tech to given state.
Definition: research.cpp:627
static struct name_translation advance_unknown_name
Definition: research.cpp:42
int player_tech_upkeep(const struct player *pplayer)
Calculate the bulb upkeep needed for all techs of a player.
Definition: research.cpp:1037
struct research * research_get(const struct player *pplayer)
Returns the research structure associated with the player.
Definition: research.cpp:110
size_t research_player_iter_sizeof()
Returns the real size of the research player iterator.
Definition: research.cpp:1127
static struct name_translation advance_unset_name
Definition: research.cpp:40
static void research_player_iter_not_pooled_next(struct iterator *it)
Invalidate the iterator.
Definition: research.cpp:1181
Q_GLOBAL_STATIC(QVector< QString >, future_name_translation)
QString research_advance_name_translation(const struct research *presearch, Tech_type_id tech)
Store the translated name of the given tech (including A_FUTURE) in 'buf'.
Definition: research.cpp:257
const char * research_name_translation(const struct research *presearch)
Returns the name of the research owner: a player name or a team name.
Definition: research.cpp:150
static void research_player_iter_pooled_next(struct iterator *it)
Returns the next player sharing the research.
Definition: research.cpp:1153
QString research_advance_rule_name(const struct research *presearch, Tech_type_id tech)
Store the rule name of the given tech (including A_FUTURE) in 'buf'.
Definition: research.cpp:233
int research_number(const research *presearch)
Returns the index of the research in the array.
Definition: research.cpp:91
static struct name_translation advance_future_name
Definition: research.cpp:41
static bool research_get_root_reqs_known(const struct research *presearch, Tech_type_id tech)
Returns TRUE iff the players sharing 'presearch' already have got the knowledge of all root requireme...
Definition: research.cpp:465
static bool research_player_iter_valid_state(struct iterator *it)
Returns whether the iterator is currently at a valid state.
Definition: research.cpp:1135
int research_goal_bulbs_required(const struct research *presearch, Tech_type_id goal)
Function to determine cost (in bulbs) of reaching goal technology.
Definition: research.cpp:767
int research_total_bulbs_required(const struct research *presearch, Tech_type_id tech, bool loss_value)
Function to determine cost for technology.
Definition: research.cpp:855
static const struct name_translation * research_advance_name(Tech_type_id tech)
Return the name translation for 'tech'.
Definition: research.cpp:194
static bool research_get_reachable_rreqs(const struct research *presearch, Tech_type_id tech)
Returns TRUE iff the given tech is ever reachable by the players sharing the research as far as resea...
Definition: research.cpp:377
enum tech_state research_invention_state(const struct research *presearch, Tech_type_id tech)
Returns state of the tech for current research.
Definition: research.cpp:609
static bool research_get_reachable(const struct research *presearch, Tech_type_id tech)
Returns TRUE iff the given tech is ever reachable by the players sharing the research by checking tec...
Definition: research.cpp:425
struct research * research_by_number(int number)
Returns the research for the given index.
Definition: research.cpp:100
static bool research_player_iter_not_pooled_valid(const struct iterator *it)
Returns whether the iterate is valid.
Definition: research.cpp:1189
Tech_type_id research_goal_step(const struct research *presearch, Tech_type_id goal)
Return the next tech we should research to advance towards our goal.
Definition: research.cpp:714
static void * research_player_iter_not_pooled_get(const struct iterator *it)
Returns player of the iterator.
Definition: research.cpp:1173
bool research_invention_gettable(const struct research *presearch, const Tech_type_id tech, bool allow_holes)
Returns TRUE iff the given tech can be given to the players sharing the research immediately.
Definition: research.cpp:686
static bool research_player_iter_pooled_valid(const struct iterator *it)
Returns whether the iterate is valid.
Definition: research.cpp:1165
#define RESEARCH_PLAYER_ITER(p)
Definition: research.cpp:38
void researches_free()
Free all resources allocated for the research system.
Definition: research.cpp:82
struct iterator * research_player_iter_init(struct research_player_iter *it, const struct research *presearch)
Initializes a research player iterator.
Definition: research.cpp:1197
static bool reqs_may_activate(const struct player *target_player, const struct player *other_player, const struct city *target_city, const struct impr_type *target_building, const struct tile *target_tile, const struct unit *target_unit, const struct unit_type *target_unittype, const struct output_type *target_output, const struct specialist *target_specialist, const struct action *target_action, const struct requirement_vector *reqs, const enum req_problem_type prob_type, const enum vision_layer vision_layer, const enum national_intelligence nintel)
Returns TRUE iff the requirement vector may become active against the given target.
Definition: research.cpp:290
bool research_is_valid(const struct research &presearch)
Checks whether the research object is valid in the current game.
Definition: research.cpp:125
void research_update(struct research *presearch)
Mark as TECH_PREREQS_KNOWN each tech which is available, not known and which has all requirements ful...
Definition: research.cpp:486
static void * research_player_iter_pooled_get(const struct iterator *it)
Returns player of the iterator.
Definition: research.cpp:1145
static const char * research_future_set_name(QVector< QString > *psv, int no, const char *new_name)
Set a new future tech name in the string vector, and return the string duplicate stored inside the ve...
Definition: research.cpp:214
const char * research_rule_name(const struct research *presearch)
Returns the name of the research owner: a player name or a team name.
Definition: research.cpp:137
std::vector< research > research_array(MAX_NUM_PLAYER_SLOTS)
int research_pretty_name(const struct research *presearch, char *buf, size_t buf_len)
Set in 'buf' the name of the research owner.
Definition: research.cpp:163
#define research_players_iterate(_presearch, _pplayer)
Definition: research.h:151
#define research_players_iterate_end
Definition: research.h:155
#define MAX(x, y)
Definition: shared.h:48
Definition: tech.h:113
struct requirement_vector research_reqs
Definition: tech.h:125
double cost
Definition: tech.h:138
struct name_translation name
Definition: tech.h:115
int num_reqs
Definition: tech.h:144
Definition: city.h:291
struct packet_game_info info
Definition: game.h:80
Definition: player.h:231
struct city_list * cities
Definition: player.h:263
struct team * team
Definition: player.h:243
bool is_alive
Definition: player.h:250
enum tech_state state
Definition: research.h:66
struct iterator vtable
Definition: research.cpp:32
struct player * pplayer
Definition: research.cpp:34
struct player_list_link * plink
Definition: research.cpp:35
Tech_type_id researching
Definition: research.h:45
int future_tech
Definition: research.h:35
Tech_type_id tech_goal
Definition: research.h:78
Tech_type_id researching_saved
Definition: research.h:55
int techs_researched
Definition: research.h:35
struct research::research_invention inventions[A_LAST]
int num_known_tech_with_flag[TF_COUNT]
Definition: research.h:83
Definition: team.cpp:35
Definition: tile.h:42
Definition: unit.h:134
int fc_snprintf(char *str, size_t n, const char *format,...)
See also fc_utf8_snprintf_trunc(), fc_utf8_snprintf_rep().
Definition: support.cpp:537
size_t fc_strlcpy(char *dest, const char *src, size_t n)
fc_strlcpy() provides utf-8 version of (non-standard) function strlcpy() It is intended as more user-...
Definition: support.cpp:412
#define fc__fallthrough
Definition: support.h:49
struct team * team_by_number(const int team_id)
Return struct team pointer for the given team index.
Definition: team.cpp:373
const char * team_name_translation(const struct team *pteam)
Returns the name (translated) of the team.
Definition: team.cpp:393
const char * team_rule_name(const struct team *pteam)
Returns the name (untranslated) of the team.
Definition: team.cpp:383
int team_pretty_name(const struct team *pteam, QString &buf)
Set in 'buf' the name of the team 'pteam' in a format like "team <team_name>".
Definition: team.cpp:405
int team_number(const struct team *pteam)
Return the team index/number/id.
Definition: team.cpp:364
const struct player_list * team_members(const struct team *pteam)
Returns the member list of the team.
Definition: team.cpp:427
int team_slot_count()
Returns the total number of team slots (including used slots).
Definition: team.cpp:101
bool is_future_tech(Tech_type_id tech)
Is the given tech a future tech.
Definition: tech.cpp:268
bool advance_has_flag(Tech_type_id tech, enum tech_flag_id flag)
Return TRUE if the tech has this flag otherwise FALSE.
Definition: tech.cpp:198
struct advance * valid_advance(struct advance *padvance)
Returns pointer when the advance "exists" in this game, returns nullptr otherwise.
Definition: tech.cpp:138
struct advance * advance_requires(const struct advance *padvance, enum tech_req require)
Accessor for requirements.
Definition: tech.cpp:122
const char * advance_rule_name(const struct advance *padvance)
Return the (untranslated) rule name of the advance/technology.
Definition: tech.cpp:283
struct advance * advance_by_number(const Tech_type_id atype)
Return the advance for the given advance index.
Definition: tech.cpp:94
Tech_type_id advance_required(const Tech_type_id tech, enum tech_req require)
Accessor for requirements.
Definition: tech.cpp:108
struct advance * valid_advance_by_number(const Tech_type_id id)
Returns pointer when the advance "exists" in this game, returns nullptr otherwise.
Definition: tech.cpp:154
Tech_type_id advance_count()
Return the number of advances/technologies.
Definition: tech.cpp:68
Tech_type_id advance_number(const struct advance *padvance)
Return the advance index.
Definition: tech.cpp:85
#define A_FUTURE
Definition: tech.h:39
#define advance_index_iterate_end
Definition: tech.h:226
#define advance_req_iterate(_goal, _padvance)
Definition: tech.h:262
tech_req
Definition: tech.h:104
@ AR_TWO
Definition: tech.h:104
@ AR_ROOT
Definition: tech.h:104
@ AR_ONE
Definition: tech.h:104
@ AR_SIZE
Definition: tech.h:104
#define advance_iterate(_start, _p)
Definition: tech.h:232
#define advance_req_iterate_end
Definition: tech.h:266
#define A_FIRST
Definition: tech.h:37
#define A_NONE
Definition: tech.h:36
#define advance_root_req_iterate_end
Definition: tech.h:281
#define A_UNSET
Definition: tech.h:41
#define advance_iterate_end
Definition: tech.h:238
#define A_UNKNOWN
Definition: tech.h:42
#define advance_index_iterate(_start, _index)
Definition: tech.h:221
#define advance_root_req_iterate(_goal, _padvance)
Definition: tech.h:277