1 /****************************************************************************
2 Freeciv - Copyright (C) 2004 - The Freeciv Team
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 #ifdef HAVE_CONFIG_H
14 #include <fc_config.h>
15 #endif
16
17 /* utility */
18 #include "iterator.h"
19 #include "log.h"
20 #include "shared.h"
21 #include "string_vector.h"
22 #include "support.h"
23
24 /* common */
25 #include "fc_types.h"
26 #include "game.h"
27 #include "player.h"
28 #include "name_translation.h"
29 #include "team.h"
30 #include "tech.h"
31
32 #include "research.h"
33
34
35 struct research_iter {
36 struct iterator vtable;
37 int index;
38 };
39 #define RESEARCH_ITER(p) ((struct research_iter *) p)
40
41 struct research_player_iter {
42 struct iterator vtable;
43 union {
44 struct player *pplayer;
45 struct player_list_link *plink;
46 };
47 };
48 #define RESEARCH_PLAYER_ITER(p) ((struct research_player_iter *) p)
49
50 static struct research research_array[MAX_NUM_PLAYER_SLOTS];
51
52 static struct name_translation advance_unset_name = NAME_INIT;
53 static struct name_translation advance_future_name = NAME_INIT;
54 static struct name_translation advance_unknown_name = NAME_INIT;
55
56 static struct strvec *future_rule_name;
57 static struct strvec *future_name_translation;
58
59 /****************************************************************************
60 Initializes all player research structure.
61 ****************************************************************************/
researches_init(void)62 void researches_init(void)
63 {
64 int i;
65
66 /* Ensure we have enough space for players or teams. */
67 fc_assert(ARRAY_SIZE(research_array) >= team_slot_count());
68 fc_assert(ARRAY_SIZE(research_array) >= player_slot_count());
69
70 memset(research_array, 0, sizeof(research_array));
71 for (i = 0; i < ARRAY_SIZE(research_array); i++) {
72 research_array[i].tech_goal = A_UNSET;
73 research_array[i].researching = A_UNSET;
74 research_array[i].researching_saved = A_UNKNOWN;
75 research_array[i].future_tech = 0;
76 research_array[i].inventions[A_NONE].state = TECH_KNOWN;
77 }
78
79 game.info.global_advances[A_NONE] = TRUE;
80
81 /* Set technology names. */
82 /* TRANS: "None" tech */
83 name_set(&advance_unset_name, NULL, N_("?tech:None"));
84 name_set(&advance_future_name, NULL, N_("Future Tech."));
85 /* TRANS: "Unknown" advance/technology */
86 name_set(&advance_unknown_name, NULL, N_("(Unknown)"));
87
88 future_rule_name = strvec_new();
89 future_name_translation = strvec_new();
90 }
91
92 /****************************************************************************
93 Free all resources allocated for the research system
94 ****************************************************************************/
researches_free(void)95 void researches_free(void)
96 {
97 strvec_destroy(future_rule_name);
98 strvec_destroy(future_name_translation);
99 }
100
101 /****************************************************************************
102 Returns the index of the research in the array.
103 ****************************************************************************/
research_number(const struct research * presearch)104 int research_number(const struct research *presearch)
105 {
106 fc_assert_ret_val(NULL != presearch, -1);
107 return presearch - research_array;
108 }
109
110 /****************************************************************************
111 Returns the research for the given index.
112 ****************************************************************************/
research_by_number(int number)113 struct research *research_by_number(int number)
114 {
115 fc_assert_ret_val(0 <= number, NULL);
116 fc_assert_ret_val(ARRAY_SIZE(research_array) > number, NULL);
117 return &research_array[number];
118 }
119
120 /****************************************************************************
121 Returns the research structure associated with the player.
122 ****************************************************************************/
research_get(const struct player * pplayer)123 struct research *research_get(const struct player *pplayer)
124 {
125 if (NULL == pplayer) {
126 /* Special case used at client side. */
127 return NULL;
128 } else if (game.info.team_pooled_research) {
129 return &research_array[team_number(pplayer->team)];
130 } else {
131 return &research_array[player_number(pplayer)];
132 }
133 }
134
135 /****************************************************************************
136 Returns the name of the research owner: a player name or a team name.
137 ****************************************************************************/
research_rule_name(const struct research * presearch)138 const char *research_rule_name(const struct research *presearch)
139 {
140 if (game.info.team_pooled_research) {
141 return team_rule_name(team_by_number(research_number(presearch)));
142 } else {
143 return player_name(player_by_number(research_number(presearch)));
144 }
145 }
146
147 /****************************************************************************
148 Returns the name of the research owner: a player name or a team name.
149 For most uses you probably want research_pretty_name() instead.
150 ****************************************************************************/
research_name_translation(const struct research * presearch)151 const char *research_name_translation(const struct research *presearch)
152 {
153 if (game.info.team_pooled_research) {
154 return team_name_translation(team_by_number(research_number(presearch)));
155 } else {
156 return player_name(player_by_number(research_number(presearch)));
157 }
158 }
159
160 /****************************************************************************
161 Set in 'buf' the name of the research owner. It may be either a nation
162 plural name, or something like "members of team Red".
163 ****************************************************************************/
research_pretty_name(const struct research * presearch,char * buf,size_t buf_len)164 int research_pretty_name(const struct research *presearch, char *buf,
165 size_t buf_len)
166 {
167 const struct player *pplayer;
168
169 if (game.info.team_pooled_research) {
170 const struct team *pteam = team_by_number(research_number(presearch));
171
172 if (1 != player_list_size(team_members(pteam))) {
173 char buf2[buf_len];
174
175 team_pretty_name(pteam, buf2, sizeof(buf2));
176 /* TRANS: e.g. "members of team 1", or even "members of team Red".
177 * Used in many places where a nation plural might be used. */
178 return fc_snprintf(buf, buf_len, _("members of %s"), 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
189 /****************************************************************************
190 Return the name translation for 'tech'. Utility for
191 research_advance_rule_name() and research_advance_translated_name().
192 ****************************************************************************/
193 static inline const struct name_translation *
research_advance_name(Tech_type_id tech)194 research_advance_name(Tech_type_id tech)
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(NULL != padvance, NULL);
206 return &padvance->name;
207 }
208 }
209
210 /****************************************************************************
211 Set a new future tech name in the string vector, and return the string
212 duplicate stored inside the vector.
213 ****************************************************************************/
research_future_set_name(struct strvec * psv,int no,const char * new_name)214 static const char *research_future_set_name(struct strvec *psv, int no,
215 const char *new_name)
216 {
217 if (strvec_size(psv) <= no) {
218 /* Increase the size of the vector if needed. */
219 strvec_reserve(psv, no + 1);
220 }
221
222 /* Set in vector. */
223 strvec_set(psv, no, new_name);
224
225 /* Return duplicate of 'new_name'. */
226 return strvec_get(psv, no);
227 }
228
229 /****************************************************************************
230 Store the rule name of the given tech (including A_FUTURE) in 'buf'.
231 'presearch' may be NULL.
232 We don't return a static buffer because that would break anything that
233 needed to work with more than one name at a time.
234 ****************************************************************************/
research_advance_rule_name(const struct research * presearch,Tech_type_id tech)235 const char *research_advance_rule_name(const struct research *presearch,
236 Tech_type_id tech)
237 {
238 if (A_FUTURE == tech && NULL != presearch) {
239 const int no = presearch->future_tech;
240 const char *name;
241
242 name = strvec_get(future_rule_name, no);
243 if (name == NULL) {
244 char buffer[256];
245
246 /* NB: 'presearch->future_tech == 0' means "Future Tech. 1". */
247 fc_snprintf(buffer, sizeof(buffer), "%s %d",
248 rule_name_get(&advance_future_name),
249 no + 1);
250 name = research_future_set_name(future_rule_name, no, buffer);
251 }
252
253 fc_assert(name != NULL);
254
255 return name;
256 }
257
258 return rule_name_get(research_advance_name(tech));
259 }
260
261 /****************************************************************************
262 Store the translated name of the given tech (including A_FUTURE) in 'buf'.
263 'presearch' may be NULL.
264 We don't return a static buffer because that would break anything that
265 needed to work with more than one name at a time.
266 ****************************************************************************/
267 const char *
research_advance_name_translation(const struct research * presearch,Tech_type_id tech)268 research_advance_name_translation(const struct research *presearch,
269 Tech_type_id tech)
270 {
271 if (A_FUTURE == tech && NULL != presearch) {
272 const int no = presearch->future_tech;
273 const char *name;
274
275 name = strvec_get(future_name_translation, no);
276 if (name == NULL) {
277 char buffer[256];
278
279 /* NB: 'presearch->future_tech == 0' means "Future Tech. 1". */
280 fc_snprintf(buffer, sizeof(buffer), _("Future Tech. %d"), no + 1);
281 name = research_future_set_name(future_name_translation, no, buffer);
282 }
283
284 fc_assert(name != NULL);
285
286 return name;
287 }
288
289 return name_translation_get(research_advance_name(tech));
290 }
291
292 /****************************************************************************
293 Returns TRUE iff the given tech is ever reachable by the players sharing
294 the research by checking tech tree limitations.
295
296 Helper for research_update().
297 ****************************************************************************/
research_get_reachable(const struct research * presearch,Tech_type_id tech)298 static bool research_get_reachable(const struct research *presearch,
299 Tech_type_id tech)
300 {
301 if (valid_advance_by_number(tech) == NULL) {
302 return FALSE;
303 } else {
304 advance_root_req_iterate(advance_by_number(tech), proot) {
305 if (advance_requires(proot, AR_ROOT) == proot) {
306 /* This tech requires itself; it can only be reached by special
307 * means (init_techs, lua script, ...).
308 * If you already know it, you can "reach" it; if not, not. (This
309 * case is needed for descendants of this tech.) */
310 if (presearch->inventions[advance_number(proot)].state != TECH_KNOWN) {
311 return FALSE;
312 }
313 } else {
314 enum tech_req req;
315
316 for (req = 0; req < AR_SIZE; req++) {
317 if (valid_advance(advance_requires(proot, req)) == NULL) {
318 return FALSE;
319 }
320 }
321 }
322 } advance_root_req_iterate_end;
323 }
324
325 return TRUE;
326 }
327
328 /****************************************************************************
329 Returns TRUE iff the players sharing 'presearch' already have got the
330 knowledge of all root requirement technologies for 'tech' (without which
331 it's impossible to gain 'tech').
332
333 Helper for research_update().
334 ****************************************************************************/
research_get_root_reqs_known(const struct research * presearch,Tech_type_id tech)335 static bool research_get_root_reqs_known(const struct research *presearch,
336 Tech_type_id tech)
337 {
338 advance_root_req_iterate(advance_by_number(tech), proot) {
339 if (presearch->inventions[advance_number(proot)].state != TECH_KNOWN) {
340 return FALSE;
341 }
342 } advance_root_req_iterate_end;
343
344 return TRUE;
345 }
346
347 /****************************************************************************
348 Mark as TECH_PREREQS_KNOWN each tech which is available, not known and
349 which has all requirements fullfiled.
350
351 Recalculate presearch->num_known_tech_with_flag
352 Should always be called after research_invention_set().
353 ****************************************************************************/
research_update(struct research * presearch)354 void research_update(struct research *presearch)
355 {
356 enum tech_flag_id flag;
357 int techs_researched;
358
359 advance_index_iterate(A_FIRST, i) {
360 enum tech_state state = presearch->inventions[i].state;
361 bool root_reqs_known = TRUE;
362 bool reachable = research_get_reachable(presearch, i);
363
364 if (reachable) {
365 root_reqs_known = research_get_root_reqs_known(presearch, i);
366 if (state != TECH_KNOWN) {
367 /* Update state. */
368 state = (root_reqs_known
369 && (presearch->inventions[advance_required(i, AR_ONE)].state
370 == TECH_KNOWN)
371 && (presearch->inventions[advance_required(i, AR_TWO)].state
372 == TECH_KNOWN)
373 ? TECH_PREREQS_KNOWN : TECH_UNKNOWN);
374 }
375 } else {
376 fc_assert(state == TECH_UNKNOWN);
377 root_reqs_known = FALSE;
378 }
379 presearch->inventions[i].state = state;
380 presearch->inventions[i].reachable = reachable;
381 presearch->inventions[i].root_reqs_known = root_reqs_known;
382
383 /* Updates required_techs, num_required_techs and bulbs_required. */
384 BV_CLR_ALL(presearch->inventions[i].required_techs);
385 presearch->inventions[i].num_required_techs = 0;
386 presearch->inventions[i].bulbs_required = 0;
387
388 if (!reachable || state == TECH_KNOWN) {
389 continue;
390 }
391
392 techs_researched = presearch->techs_researched;
393 advance_req_iterate(valid_advance_by_number(i), preq) {
394 Tech_type_id j = advance_number(preq);
395
396 if (TECH_KNOWN == research_invention_state(presearch, j)) {
397 continue;
398 }
399
400 BV_SET(presearch->inventions[i].required_techs, j);
401 presearch->inventions[i].num_required_techs++;
402 presearch->inventions[i].bulbs_required +=
403 research_total_bulbs_required(presearch, j, FALSE);
404 /* This is needed to get a correct result for the
405 * research_total_bulbs_required() call when
406 * game.info.game.info.tech_cost_style is TECH_COST_CIV1CIV2. */
407 presearch->techs_researched++;
408 } advance_req_iterate_end;
409 presearch->techs_researched = techs_researched;
410 } advance_index_iterate_end;
411
412 #ifdef FREECIV_DEBUG
413 advance_index_iterate(A_FIRST, i) {
414 char buf[advance_count() + 1];
415
416 advance_index_iterate(A_NONE, j) {
417 if (BV_ISSET(presearch->inventions[i].required_techs, j)) {
418 buf[j] = '1';
419 } else {
420 buf[j] = '0';
421 }
422 } advance_index_iterate_end;
423 buf[advance_count()] = '\0';
424
425 log_debug("%s: [%3d] %-25s => %s%s%s",
426 research_rule_name(presearch),
427 i,
428 advance_rule_name(advance_by_number(i)),
429 tech_state_name(research_invention_state(presearch, i)),
430 presearch->inventions[i].reachable ? "" : " [unrechable]",
431 presearch->inventions[i].root_reqs_known
432 ? "" : " [root reqs aren't known]");
433 log_debug("%s: [%3d] %s", research_rule_name(presearch), i, buf);
434 } advance_index_iterate_end;
435 #endif /* FREECIV_DEBUG */
436
437 for (flag = 0; flag <= tech_flag_id_max(); flag++) {
438 /* Iterate over all possible tech flags (0..max). */
439 presearch->num_known_tech_with_flag[flag] = 0;
440
441 advance_index_iterate(A_NONE, i) {
442 if (TECH_KNOWN == research_invention_state(presearch, i)
443 && advance_has_flag(i, flag)) {
444 presearch->num_known_tech_with_flag[flag]++;
445 }
446 } advance_index_iterate_end;
447 }
448 }
449
450 /****************************************************************************
451 Returns state of the tech for current research.
452 This can be: TECH_KNOWN, TECH_UNKNOWN, or TECH_PREREQS_KNOWN
453 Should be called with existing techs.
454
455 If 'presearch' is NULL this checks whether any player knows the tech
456 (used by the client).
457 ****************************************************************************/
research_invention_state(const struct research * presearch,Tech_type_id tech)458 enum tech_state research_invention_state(const struct research *presearch,
459 Tech_type_id tech)
460 {
461 fc_assert_ret_val(NULL != valid_advance_by_number(tech), -1);
462
463 if (NULL != presearch) {
464 return presearch->inventions[tech].state;
465 } else if (game.info.global_advances[tech]) {
466 return TECH_KNOWN;
467 } else {
468 return TECH_UNKNOWN;
469 }
470 }
471
472 /****************************************************************************
473 Set research knowledge about tech to given state.
474 ****************************************************************************/
research_invention_set(struct research * presearch,Tech_type_id tech,enum tech_state value)475 enum tech_state research_invention_set(struct research *presearch,
476 Tech_type_id tech,
477 enum tech_state value)
478 {
479 enum tech_state old;
480
481 fc_assert_ret_val(NULL != valid_advance_by_number(tech), -1);
482
483 old = presearch->inventions[tech].state;
484 if (old == value) {
485 return old;
486 }
487 presearch->inventions[tech].state = value;
488
489 if (value == TECH_KNOWN) {
490 game.info.global_advances[tech] = TRUE;
491 }
492 return old;
493 }
494
495 /****************************************************************************
496 Returns TRUE iff the given tech is ever reachable by the players sharing
497 the research by checking tech tree limitations.
498
499 'presearch' may be NULL in which case a simplified result is returned
500 (used by the client).
501 ****************************************************************************/
research_invention_reachable(const struct research * presearch,const Tech_type_id tech)502 bool research_invention_reachable(const struct research *presearch,
503 const Tech_type_id tech)
504 {
505 if (valid_advance_by_number(tech) == NULL) {
506 return FALSE;
507 } else if (presearch != NULL) {
508 return presearch->inventions[tech].reachable;
509 } else {
510 researches_iterate(research_iter) {
511 if (research_iter->inventions[tech].reachable) {
512 return TRUE;
513 }
514 } researches_iterate_end;
515
516 return FALSE;
517 }
518 }
519
520 /****************************************************************************
521 Returns TRUE iff the given tech can be given to the players sharing the
522 research immediately.
523
524 If allow_holes is TRUE, any reachable tech is ok. If it's FALSE,
525 getting the tech must not leave holes to the known techs tree.
526 ****************************************************************************/
research_invention_gettable(const struct research * presearch,const Tech_type_id tech,bool allow_holes)527 bool research_invention_gettable(const struct research *presearch,
528 const Tech_type_id tech,
529 bool allow_holes)
530 {
531 if (valid_advance_by_number(tech) == NULL) {
532 return FALSE;
533 } else if (presearch != NULL) {
534 return (allow_holes
535 ? presearch->inventions[tech].root_reqs_known
536 : presearch->inventions[tech].state == TECH_PREREQS_KNOWN);
537 } else {
538 researches_iterate(research_iter) {
539 if (allow_holes
540 ? research_iter->inventions[tech].root_reqs_known
541 : research_iter->inventions[tech].state == TECH_PREREQS_KNOWN) {
542 return TRUE;
543 }
544 } researches_iterate_end;
545
546 return FALSE;
547 }
548 }
549
550 /****************************************************************************
551 Return the next tech we should research to advance towards our goal.
552 Returns A_UNSET if nothing is available or the goal is already known.
553 ****************************************************************************/
research_goal_step(const struct research * presearch,Tech_type_id goal)554 Tech_type_id research_goal_step(const struct research *presearch,
555 Tech_type_id goal)
556 {
557 const struct advance *pgoal = valid_advance_by_number(goal);
558
559 if (NULL == pgoal
560 || !research_invention_reachable(presearch, goal)) {
561 return A_UNSET;
562 }
563
564 advance_req_iterate(pgoal, preq) {
565 switch (research_invention_state(presearch, advance_number(preq))) {
566 case TECH_PREREQS_KNOWN:
567 return advance_number(preq);
568 case TECH_KNOWN:
569 case TECH_UNKNOWN:
570 break;
571 };
572 } advance_req_iterate_end;
573 return A_UNSET;
574 }
575
576 /****************************************************************************
577 Returns the number of technologies the player need to research to get
578 the goal technology. This includes the goal technology. Technologies
579 are only counted once.
580
581 'presearch' may be NULL in which case it will returns the total number
582 of technologies needed for reaching the goal.
583 ****************************************************************************/
research_goal_unknown_techs(const struct research * presearch,Tech_type_id goal)584 int research_goal_unknown_techs(const struct research *presearch,
585 Tech_type_id goal)
586 {
587 const struct advance *pgoal = valid_advance_by_number(goal);
588
589 if (NULL == pgoal) {
590 return 0;
591 } else if (NULL != presearch) {
592 return presearch->inventions[goal].num_required_techs;
593 } else {
594 return pgoal->num_reqs;
595 }
596 }
597
598 /****************************************************************************
599 Function to determine cost (in bulbs) of reaching goal technology.
600 These costs _include_ the cost for researching the goal technology
601 itself.
602
603 'presearch' may be NULL in which case it will returns the total number
604 of bulbs needed for reaching the goal.
605 ****************************************************************************/
research_goal_bulbs_required(const struct research * presearch,Tech_type_id goal)606 int research_goal_bulbs_required(const struct research *presearch,
607 Tech_type_id goal)
608 {
609 const struct advance *pgoal = valid_advance_by_number(goal);
610
611 if (NULL == pgoal) {
612 return 0;
613 } else if (NULL != presearch) {
614 return presearch->inventions[goal].bulbs_required;
615 } else if (game.info.tech_cost_style == TECH_COST_CIV1CIV2) {
616 return game.info.base_tech_cost * pgoal->num_reqs
617 * (pgoal->num_reqs + 1) / 2;
618 } else {
619 int bulbs_required = 0;
620
621 advance_req_iterate(pgoal, preq) {
622 bulbs_required += preq->cost;
623 } advance_req_iterate_end;
624 return bulbs_required;
625 }
626 }
627
628 /****************************************************************************
629 Returns if the given tech has to be researched to reach the goal. The
630 goal itself isn't a requirement of itself.
631
632 'presearch' may be NULL.
633 ****************************************************************************/
research_goal_tech_req(const struct research * presearch,Tech_type_id goal,Tech_type_id tech)634 bool research_goal_tech_req(const struct research *presearch,
635 Tech_type_id goal, Tech_type_id tech)
636 {
637 const struct advance *pgoal, *ptech;
638
639 if (tech == goal
640 || NULL == (pgoal = valid_advance_by_number(goal))
641 || NULL == (ptech = valid_advance_by_number(tech))) {
642 return FALSE;
643 } else if (NULL != presearch) {
644 return BV_ISSET(presearch->inventions[goal].required_techs, tech);
645 } else {
646 advance_req_iterate(pgoal, preq) {
647 if (preq == ptech) {
648 return TRUE;
649 }
650 } advance_req_iterate_end;
651 return FALSE;
652 }
653 }
654
655 /****************************************************************************
656 Function to determine cost for technology. The equation is determined
657 from game.info.tech_cost_style and game.info.tech_leakage.
658
659 tech_cost_style:
660 TECH_COST_CIV1CIV2: Civ (I|II) style. Every new tech add base_tech_cost to
661 cost of next tech.
662 TECH_COST_CLASSIC: Cost of technology is:
663 base_tech_cost * (1 + reqs) * sqrt(1 + reqs) / 2
664 where reqs == number of requirement for tech, counted
665 recursively.
666 TECH_COST_CLASSIC_PRESET: Cost are read from tech.ruleset. Missing costs
667 are generated by style "Classic".
668 TECH_COST_EXPERIMENTAL: Cost of technology is:
669 base_tech_cost * (reqs^2
670 / (1 + sqrt(sqrt(reqs + 1)))
671 - 0.5)
672 where reqs == number of requirement for tech,
673 counted recursively.
674 TECH_COST_EXPERIMENTAL_PRESET: Cost are read from tech.ruleset. Missing
675 costs are generated by style "Experimental".
676
677 tech_leakage:
678 TECH_LEAKAGE_NONE: No reduction of the technology cost.
679 TECH_LEAKAGE_EMBASSIES: Technology cost is reduced depending on the number
680 of players which already know the tech and you have
681 an embassy with.
682 TECH_LEAKAGE_PLAYERS: Technology cost is reduced depending on the number of
683 all players (human, AI and barbarians) which already
684 know the tech.
685 TECH_LEAKAGE_NO_BARBS: Technology cost is reduced depending on the number
686 of normal players (human and AI) which already know
687 the tech.
688
689 At the end we multiply by the sciencebox value, as a percentage. The
690 cost can never be less than 1.
691
692 'presearch' may be NULL in which case a simplified result is returned
693 (used by client and manual code).
694 ****************************************************************************/
research_total_bulbs_required(const struct research * presearch,Tech_type_id tech,bool loss_value)695 int research_total_bulbs_required(const struct research *presearch,
696 Tech_type_id tech, bool loss_value)
697 {
698 enum tech_cost_style tech_cost_style = game.info.tech_cost_style;
699 int members;
700 double base_cost, total_cost;
701
702 if (!loss_value
703 && NULL != presearch
704 && !is_future_tech(tech)
705 && research_invention_state(presearch, tech) == TECH_KNOWN) {
706 /* A non-future tech which is already known costs nothing. */
707 return 0;
708 }
709
710 if (is_future_tech(tech)) {
711 /* Future techs use style TECH_COST_CIV1CIV2. */
712 tech_cost_style = TECH_COST_CIV1CIV2;
713 }
714
715 fc_assert_msg(tech_cost_style_is_valid(tech_cost_style),
716 "Invalid tech_cost_style %d", tech_cost_style);
717 base_cost = 0.0;
718 switch (tech_cost_style) {
719 case TECH_COST_CIV1CIV2:
720 if (NULL != presearch) {
721 base_cost = game.info.base_tech_cost * presearch->techs_researched;
722 break;
723 }
724
725 fc_assert(presearch != NULL);
726 fc__fallthrough; /* No break; Fallback to using preset cost. */
727 case TECH_COST_CLASSIC:
728 case TECH_COST_CLASSIC_PRESET:
729 case TECH_COST_EXPERIMENTAL:
730 case TECH_COST_EXPERIMENTAL_PRESET:
731 {
732 const struct advance *padvance = valid_advance_by_number(tech);
733
734 if (NULL != padvance) {
735 base_cost = padvance->cost;
736 } else {
737 fc_assert(NULL != padvance); /* Always fails. */
738 }
739 }
740 break;
741 }
742
743 total_cost = 0.0;
744 members = 0;
745 research_players_iterate(presearch, pplayer) {
746 members++;
747 total_cost += (base_cost
748 * get_player_bonus(pplayer, EFT_TECH_COST_FACTOR));
749 } research_players_iterate_end;
750 if (0 == members) {
751 /* There is no more alive players for this research, no need to apply
752 * complicated modifiers. */
753 return base_cost * (double) game.info.sciencebox / 100.0;
754 }
755 base_cost = total_cost / members;
756
757 fc_assert_msg(tech_leakage_style_is_valid(game.info.tech_leakage),
758 "Invalid tech_leakage %d", game.info.tech_leakage);
759 switch (game.info.tech_leakage) {
760 case TECH_LEAKAGE_NONE:
761 /* no change */
762 break;
763
764 case TECH_LEAKAGE_EMBASSIES:
765 {
766 int players = 0, players_with_tech_and_embassy = 0;
767
768 players_iterate_alive(aplayer) {
769 const struct research *aresearch = research_get(aplayer);
770
771 players++;
772 if (aresearch == presearch
773 || (A_FUTURE == tech
774 ? aresearch->future_tech <= presearch->future_tech
775 : TECH_KNOWN != research_invention_state(aresearch, tech))) {
776 continue;
777 }
778
779 research_players_iterate(presearch, pplayer) {
780 if (player_has_embassy(pplayer, aplayer)) {
781 players_with_tech_and_embassy++;
782 break;
783 }
784 } research_players_iterate_end;
785 } players_iterate_alive_end;
786
787 fc_assert_ret_val(0 < players, base_cost);
788 fc_assert(players >= players_with_tech_and_embassy);
789 base_cost *= (double) (players - players_with_tech_and_embassy);
790 base_cost /= (double) players;
791 }
792 break;
793
794 case TECH_LEAKAGE_PLAYERS:
795 {
796 int players = 0, players_with_tech = 0;
797
798 players_iterate_alive(aplayer) {
799 players++;
800 if (A_FUTURE == tech
801 ? research_get(aplayer)->future_tech > presearch->future_tech
802 : TECH_KNOWN == research_invention_state(research_get(aplayer),
803 tech)) {
804 players_with_tech++;
805 }
806 } players_iterate_alive_end;
807
808 fc_assert_ret_val(0 < players, base_cost);
809 fc_assert(players >= players_with_tech);
810 base_cost *= (double) (players - players_with_tech);
811 base_cost /= (double) players;
812 }
813 break;
814
815 case TECH_LEAKAGE_NO_BARBS:
816 {
817 int players = 0, players_with_tech = 0;
818
819 players_iterate_alive(aplayer) {
820 if (is_barbarian(aplayer)) {
821 continue;
822 }
823 players++;
824 if (A_FUTURE == tech
825 ? research_get(aplayer)->future_tech > presearch->future_tech
826 : TECH_KNOWN == research_invention_state(research_get(aplayer),
827 tech)) {
828 players_with_tech++;
829 }
830 } players_iterate_alive_end;
831
832 fc_assert_ret_val(0 < players, base_cost);
833 fc_assert(players >= players_with_tech);
834 base_cost *= (double) (players - players_with_tech);
835 base_cost /= (double) players;
836 }
837 break;
838 }
839
840 /* Assign a science penalty to the AI at easier skill levels. This code
841 * can also be adopted to create an extra-hard AI skill level where the AI
842 * gets science benefits. */
843
844 total_cost = 0.0;
845 research_players_iterate(presearch, pplayer) {
846 if (pplayer->ai_controlled) {
847 fc_assert(0 < pplayer->ai_common.science_cost);
848 total_cost += base_cost * pplayer->ai_common.science_cost / 100.0;
849 } else {
850 total_cost += base_cost;
851 }
852 } research_players_iterate_end;
853 base_cost = total_cost / members;
854
855 base_cost *= (double) game.info.sciencebox / 100.0;
856
857 return MAX(base_cost, 1);
858 }
859
860
861 /****************************************************************************
862 Calculate the bulb upkeep needed for all techs of a player. See also
863 research_total_bulbs_required().
864 ****************************************************************************/
player_tech_upkeep(const struct player * pplayer)865 int player_tech_upkeep(const struct player *pplayer)
866 {
867 const struct research *presearch = research_get(pplayer);
868 int f = presearch->future_tech, t = presearch->techs_researched;
869 double tech_upkeep = 0.0;
870 double total_research_factor;
871 int members;
872
873 if (TECH_UPKEEP_NONE == game.info.tech_upkeep_style) {
874 return 0;
875 }
876
877 total_research_factor = 0.0;
878 members = 0;
879 research_players_iterate(presearch, contributor) {
880 total_research_factor += (get_player_bonus(contributor, EFT_TECH_COST_FACTOR)
881 + (contributor->ai_controlled
882 ? contributor->ai_common.science_cost / 100.0
883 : 1));
884 members++;
885 } research_players_iterate_end;
886 if (0 == members) {
887 /* No player still alive. */
888 return 0;
889 }
890
891 /* Upkeep cost for 'normal' techs (t). */
892 fc_assert_msg(tech_cost_style_is_valid(game.info.tech_cost_style),
893 "Invalid tech_cost_style %d", game.info.tech_cost_style);
894 switch (game.info.tech_cost_style) {
895 case TECH_COST_CIV1CIV2:
896 /* sum_1^t x = t * (t + 1) / 2 */
897 tech_upkeep += game.info.base_tech_cost * t * (t + 1) / 2;
898 break;
899 case TECH_COST_CLASSIC:
900 case TECH_COST_CLASSIC_PRESET:
901 case TECH_COST_EXPERIMENTAL:
902 case TECH_COST_EXPERIMENTAL_PRESET:
903 advance_iterate(A_FIRST, padvance) {
904 if (TECH_KNOWN == research_invention_state(presearch,
905 advance_number(padvance))) {
906 tech_upkeep += padvance->cost;
907 }
908 } advance_iterate_end;
909 if (0 < f) {
910 /* Upkeep cost for future techs (f) are calculated using style 0:
911 * sum_t^(t+f) x = (f * (2 * t + f + 1) + 2 * t) / 2 */
912 tech_upkeep += (double) (game.info.base_tech_cost
913 * (f * (2 * t + f + 1) + 2 * t) / 2);
914 }
915 break;
916 }
917
918 tech_upkeep *= total_research_factor / members;
919 tech_upkeep *= (double) game.info.sciencebox / 100.0;
920 /* We only want to calculate the upkeep part of one player, not the
921 * whole team! */
922 tech_upkeep /= members;
923 tech_upkeep /= game.info.tech_upkeep_divider;
924
925 switch (game.info.tech_upkeep_style) {
926 case TECH_UPKEEP_BASIC:
927 tech_upkeep -= get_player_bonus(pplayer, EFT_TECH_UPKEEP_FREE);
928 break;
929 case TECH_UPKEEP_PER_CITY:
930 tech_upkeep -= get_player_bonus(pplayer, EFT_TECH_UPKEEP_FREE);
931 tech_upkeep *= city_list_size(pplayer->cities);
932 break;
933 case TECH_UPKEEP_NONE:
934 fc_assert(game.info.tech_upkeep_style != TECH_UPKEEP_NONE);
935 tech_upkeep = 0.0;
936 }
937
938 if (0.0 > tech_upkeep) {
939 tech_upkeep = 0.0;
940 }
941
942 log_debug("[%s (%d)] tech upkeep: %d", player_name(pplayer),
943 player_number(pplayer), (int) tech_upkeep);
944 return (int) tech_upkeep;
945 }
946
947
948 /****************************************************************************
949 Returns the real size of the player research iterator.
950 ****************************************************************************/
research_iter_sizeof(void)951 size_t research_iter_sizeof(void)
952 {
953 return sizeof(struct research_iter);
954 }
955
956 /****************************************************************************
957 Returns the research structure pointed by the iterator.
958 ****************************************************************************/
research_iter_get(const struct iterator * it)959 static void *research_iter_get(const struct iterator *it)
960 {
961 return &research_array[RESEARCH_ITER(it)->index];
962 }
963
964 /****************************************************************************
965 Jump to next team research structure.
966 ****************************************************************************/
research_iter_team_next(struct iterator * it)967 static void research_iter_team_next(struct iterator *it)
968 {
969 struct research_iter *rit = RESEARCH_ITER(it);
970
971 if (team_slots_initialised()) {
972 do {
973 rit->index++;
974 } while (rit->index < ARRAY_SIZE(research_array) && !it->valid(it));
975 }
976 }
977
978 /****************************************************************************
979 Returns FALSE if there is no valid team at current index.
980 ****************************************************************************/
research_iter_team_valid(const struct iterator * it)981 static bool research_iter_team_valid(const struct iterator *it)
982 {
983 struct research_iter *rit = RESEARCH_ITER(it);
984
985 return (0 <= rit->index
986 && ARRAY_SIZE(research_array) > rit->index
987 && NULL != team_by_number(rit->index));
988 }
989
990 /****************************************************************************
991 Jump to next player research structure.
992 ****************************************************************************/
research_iter_player_next(struct iterator * it)993 static void research_iter_player_next(struct iterator *it)
994 {
995 struct research_iter *rit = RESEARCH_ITER(it);
996
997 if (player_slots_initialised()) {
998 do {
999 rit->index++;
1000 } while (rit->index < ARRAY_SIZE(research_array) && !it->valid(it));
1001 }
1002 }
1003
1004 /****************************************************************************
1005 Returns FALSE if there is no valid player at current index.
1006 ****************************************************************************/
research_iter_player_valid(const struct iterator * it)1007 static bool research_iter_player_valid(const struct iterator *it)
1008 {
1009 struct research_iter *rit = RESEARCH_ITER(it);
1010
1011 return (0 <= rit->index
1012 && ARRAY_SIZE(research_array) > rit->index
1013 && NULL != player_by_number(rit->index));
1014 }
1015
1016 /****************************************************************************
1017 Initializes a player research iterator.
1018 ****************************************************************************/
research_iter_init(struct research_iter * it)1019 struct iterator *research_iter_init(struct research_iter *it)
1020 {
1021 struct iterator *base = ITERATOR(it);
1022
1023 base->get = research_iter_get;
1024 it->index = -1;
1025
1026 if (game.info.team_pooled_research) {
1027 base->next = research_iter_team_next;
1028 base->valid = research_iter_team_valid;
1029 } else {
1030 base->next = research_iter_player_next;
1031 base->valid = research_iter_player_valid;
1032 }
1033
1034 base->next(base);
1035 return base;
1036 }
1037
1038 /****************************************************************************
1039 Returns the real size of the research player iterator.
1040 ****************************************************************************/
research_player_iter_sizeof(void)1041 size_t research_player_iter_sizeof(void)
1042 {
1043 return sizeof(struct research_player_iter);
1044 }
1045
1046 /****************************************************************************
1047 Returns whether the iterator is currently at a valid state.
1048 ****************************************************************************/
research_player_iter_valid_state(struct iterator * it)1049 static inline bool research_player_iter_valid_state(struct iterator *it)
1050 {
1051 const struct player *pplayer = iterator_get(it);
1052
1053 return (NULL == pplayer || pplayer->is_alive);
1054 }
1055
1056 /****************************************************************************
1057 Returns player of the iterator.
1058 ****************************************************************************/
research_player_iter_pooled_get(const struct iterator * it)1059 static void *research_player_iter_pooled_get(const struct iterator *it)
1060 {
1061 return player_list_link_data(RESEARCH_PLAYER_ITER(it)->plink);
1062 }
1063
1064 /****************************************************************************
1065 Returns the next player sharing the research.
1066 ****************************************************************************/
research_player_iter_pooled_next(struct iterator * it)1067 static void research_player_iter_pooled_next(struct iterator *it)
1068 {
1069 struct research_player_iter *rpit = RESEARCH_PLAYER_ITER(it);
1070
1071 do {
1072 rpit->plink = player_list_link_next(rpit->plink);
1073 } while (!research_player_iter_valid_state(it));
1074 }
1075
1076 /****************************************************************************
1077 Returns whether the iterate is valid.
1078 ****************************************************************************/
research_player_iter_pooled_valid(const struct iterator * it)1079 static bool research_player_iter_pooled_valid(const struct iterator *it)
1080 {
1081 return NULL != RESEARCH_PLAYER_ITER(it)->plink;
1082 }
1083
1084 /****************************************************************************
1085 Returns player of the iterator.
1086 ****************************************************************************/
research_player_iter_not_pooled_get(const struct iterator * it)1087 static void *research_player_iter_not_pooled_get(const struct iterator *it)
1088 {
1089 return RESEARCH_PLAYER_ITER(it)->pplayer;
1090 }
1091
1092 /****************************************************************************
1093 Invalidate the iterator.
1094 ****************************************************************************/
research_player_iter_not_pooled_next(struct iterator * it)1095 static void research_player_iter_not_pooled_next(struct iterator *it)
1096 {
1097 RESEARCH_PLAYER_ITER(it)->pplayer = NULL;
1098 }
1099
1100 /****************************************************************************
1101 Returns whether the iterate is valid.
1102 ****************************************************************************/
research_player_iter_not_pooled_valid(const struct iterator * it)1103 static bool research_player_iter_not_pooled_valid(const struct iterator *it)
1104 {
1105 return NULL != RESEARCH_PLAYER_ITER(it)->pplayer;
1106 }
1107
1108 /****************************************************************************
1109 Initializes a research player iterator.
1110 ****************************************************************************/
research_player_iter_init(struct research_player_iter * it,const struct research * presearch)1111 struct iterator *research_player_iter_init(struct research_player_iter *it,
1112 const struct research *presearch)
1113 {
1114 struct iterator *base = ITERATOR(it);
1115
1116 if (game.info.team_pooled_research && NULL != presearch) {
1117 base->get = research_player_iter_pooled_get;
1118 base->next = research_player_iter_pooled_next;
1119 base->valid = research_player_iter_pooled_valid;
1120 it->plink = player_list_head(team_members(team_by_number(research_number
1121 (presearch))));
1122 } else {
1123 base->get = research_player_iter_not_pooled_get;
1124 base->next = research_player_iter_not_pooled_next;
1125 base->valid = research_player_iter_not_pooled_valid;
1126 it->pplayer = (NULL != presearch
1127 ? player_by_number(research_number(presearch)) : NULL);
1128 }
1129
1130 /* Ensure we have consistent data. */
1131 if (!research_player_iter_valid_state(base)) {
1132 iterator_next(base);
1133 }
1134
1135 return base;
1136 }
1137