Freeciv-3.3: /fast/freeciv/nightly/main/server/techtools.c Source File

Freeciv-3.3

Loading...
Searching...
No Matches
techtools.c
Go to the documentation of this file.
1/***********************************************************************
2 Freeciv - Copyright (C) 2005 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 "astring.h"
19#include "fcintl.h"
20#include "log.h"
21#include "mem.h"
22#include "rand.h"
23#include "shared.h"
24#include "support.h"
25
26/* common */
27#include "game.h"
28#include "government.h"
29#include "movement.h"
30#include "player.h"
31#include "research.h"
32#include "tech.h"
33#include "unit.h"
34
35/* common/scriptcore */
36#include "luascript_types.h"
37
38/* server */
39#include "citytools.h"
40#include "cityturn.h"
41#include "connecthand.h"
42#include "gamehand.h"
43#include "maphand.h"
44#include "notify.h"
45#include "plrhand.h"
46#include "unittools.h"
47
48/* server/scripting */
49#include "script_server.h"
50
51#include "techtools.h"
52
53/* Define this to add information about tech upkeep. */
54#undef TECH_UPKEEP_DEBUGGING
55
56static Tech_type_id
57 pick_random_tech_to_lose(const struct research *presearch);
58static Tech_type_id pick_random_tech(const struct research *presearch);
59static Tech_type_id pick_cheapest_tech(const struct research *presearch);
60static void research_tech_lost(struct research *presearch,
61 Tech_type_id tech);
62static void forget_tech_transferred(struct player *pplayer, Tech_type_id tech);
63
64/************************************************************************/
67 void research_apply_penalty(struct research *presearch, Tech_type_id tech,
68 int penalty_percent)
69{
70 if (game.server.multiresearch) {
71 return;
72 }
73 presearch->bulbs_researched -=
74 (research_total_bulbs_required(presearch, tech, FALSE)
75 * penalty_percent) / 100;
76 presearch->researching_saved = A_UNKNOWN;
77}
78
79/************************************************************************/
84 void script_tech_learned(struct research *presearch,
85 struct player *originating_plr, struct advance *tech,
86 const char *reason)
87{
88 /* Emit signal for individual player whose action triggered the
89 * tech first */
90 if (originating_plr) {
91 fc_assert(research_get(originating_plr) == presearch);
92 script_server_signal_emit("tech_researched", tech, originating_plr,
93 reason);
94 }
95
96 /* Emit signal to remaining research teammates, if any */
97 research_players_iterate(presearch, member) {
98 if (member != originating_plr) {
99 script_server_signal_emit("tech_researched", tech, member, reason);
100 }
101 } research_players_iterate_end;
102}
103
104/************************************************************************/
107 static void tech_researched(struct research *research)
108{
109 char research_name[MAX_LEN_NAME * 2];
110 /* Cache researched technology for event signal, because found_new_tech()
111 * changes the research target. */
112 Tech_type_id tech = research->researching;
113
114 research_pretty_name(research, research_name, sizeof(research_name));
115 /* Players will be notified when new tech is chosen. */
116 notify_research_embassies
117 (research, NULL, E_TECH_EMBASSY, ftc_server,
118 _("The %s have researched %s."),
119 research_name,
120 research_advance_name_translation(research, tech));
121
122 /* Deduct tech cost. */
123 research->bulbs_researched -= research_total_bulbs_required(research, tech,
124 FALSE);
125 advance_index_iterate(A_FIRST, j) {
126 if (j == research->researching) {
127 research->inventions[j].bulbs_researched_saved
128 = research_total_bulbs_required(research, tech, FALSE);
129 }
130 } advance_index_iterate_end;
131
132
133 /* Do all the updates needed after finding new tech. */
134 found_new_tech(research, tech, TRUE, TRUE);
135
136 script_tech_learned(research, NULL, advance_by_number(tech), "researched");
137}
138
139/************************************************************************/
143 void do_tech_parasite_effects(struct player *pplayer)
144{
145 struct effect_list *plist_abs = effect_list_new();
146 struct effect_list *plist_pct = effect_list_new();
147 struct effect_list *plist;
148 struct astring effects;
149 struct research *plr_research;
150 char research_name[MAX_LEN_NAME * 2];
151 const char *advance_name;
152 Tech_type_id tech;
153 /* Note that two EFT_TECH_PARASITE* effects will combine into a single,
154 * much worse effect. */
155 int mod_abs;
156 int mod_pct;
157 int mod;
158 int num_techs;
159 int rcount = research_count();
160
161 mod_abs = get_player_bonus_effects(plist_abs, pplayer, EFT_TECH_PARASITE);
162 mod_pct = get_player_bonus_effects(plist_pct, pplayer, EFT_TECH_PARASITE_PCT_MAX);
163
164 mod = (rcount * mod_pct) / 100;
165
166 if (mod <= 0 && mod_abs <= 0) {
167 /* No effects. */
168 effect_list_destroy(plist_abs);
169 effect_list_destroy(plist_pct);
170 return;
171 }
172
173 if (mod > 0 && (mod_abs <= 0 || mod_abs > mod)) {
174 plist = plist_pct;
175 effect_list_destroy(plist_abs);
176 } else {
177 mod = mod_abs;
178 plist = plist_abs;
179 effect_list_destroy(plist_pct);
180 }
181
182 /* Pick a random technology. */
183 tech = A_UNSET;
184 num_techs = 0;
185 plr_research = research_get(pplayer);
186 advance_index_iterate(A_FIRST, i) {
187 int num_teams;
188
189 if (!research_invention_gettable(plr_research, i,
190 game.info.tech_parasite_allow_holes)
191 || TECH_KNOWN == research_invention_state(plr_research, i)) {
192 continue;
193 }
194
195 num_teams = 0;
196 researches_iterate(other_research) {
197 if (TECH_KNOWN == research_invention_state(other_research, i)) {
198 if (mod <= ++num_teams) {
199 if (0 == fc_rand(++num_techs)) {
200 tech = i;
201 }
202 break;
203 }
204 }
205 } researches_iterate_end;
206 } advance_index_iterate_end;
207
208 if (A_UNSET == tech) {
209 /* No tech found. */
210 effect_list_destroy(plist);
211 return;
212 }
213
214 /* Notify. */
215 research_pretty_name(plr_research, research_name, sizeof(research_name));
216 advance_name = research_advance_name_translation(plr_research, tech);
217 astr_init(&effects);
218 get_effect_list_req_text(plist, &effects);
219
220 notify_player(pplayer, NULL, E_TECH_GAIN, ftc_server,
221 /* TRANS: Tech from source of an effect
222 * (Great Library) */
223 Q_("?fromeffect:%s acquired from %s!"),
224 advance_name,
225 astr_str(&effects));
226 notify_research(plr_research, pplayer, E_TECH_GAIN, ftc_server,
227 /* TRANS: Tech from source of an effect
228 * (Great Library) */
229 Q_("?fromeffect:%s acquired from %s's %s!"),
230 advance_name,
231 player_name(pplayer),
232 astr_str(&effects));
233 notify_research_embassies(plr_research, NULL, E_TECH_EMBASSY, ftc_server,
234 /* TRANS: Tech from source of an effect
235 * (Great Library) */
236 Q_("?fromeffect:The %s have acquired %s from %s."),
237 research_name,
238 advance_name,
239 astr_str(&effects));
240
241 effect_list_destroy(plist);
242 astr_free(&effects);
243
244 /* Really get tech. */
245 research_apply_penalty(plr_research, tech, game.server.freecost);
246 found_new_tech(plr_research, tech, FALSE, TRUE);
247
248 research_players_iterate(plr_research, member) {
249 script_server_signal_emit("tech_researched", advance_by_number(tech),
250 member, "stolen");
251 } research_players_iterate_end;
252}
253
254/************************************************************************/
257static inline void
258package_research_info(struct packet_research_info *packet,
259 const struct research *presearch)
260{
261 packet->id = research_number(presearch);
262 packet->techs_researched = presearch->techs_researched;
263 packet->future_tech = presearch->future_tech;
264 packet->researching = presearch->researching;
265 packet->researching_cost =
266 (packet->researching != A_UNSET
267 ? research_total_bulbs_required(presearch, presearch->researching,
268 FALSE) : 0);
269 packet->bulbs_researched = presearch->bulbs_researched;
270 packet->tech_goal = presearch->tech_goal;
271 packet->total_bulbs_prod = 0;
272 research_players_iterate(presearch, pplayer) {
273 city_list_iterate(pplayer->cities, pcity) {
274 packet->total_bulbs_prod += pcity->surplus[O_SCIENCE];
275 } city_list_iterate_end;
276 } research_players_iterate_end;
277 advance_index_iterate(A_NONE, i) {
278 packet->inventions[i] = presearch->inventions[i].state + '0';
279 } advance_index_iterate_end;
280 packet->inventions[advance_count()] = '\0';
281 packet->tech_goal = presearch->tech_goal;
282#ifdef FREECIV_DEBUG
283 log_verbose("Research nb %d inventions: %s",
284 research_number(presearch),
285 packet->inventions);
286#endif /* FREECIV_DEBUG */
287}
288
289/************************************************************************/
293 void send_research_info(const struct research *presearch,
294 const struct conn_list *dest)
295{
296 struct packet_research_info full_info, restricted_info;
297 struct packet_unknown_research unknown_info;
298 const struct player *pplayer;
299
300 fc_assert_ret(NULL != presearch);
301 if (NULL == dest) {
302 dest = game.est_connections;
303 }
304
305 /* Packaging */
306 package_research_info(&full_info, presearch);
307 restricted_info = full_info;
308 restricted_info.tech_goal = A_UNSET;
309 restricted_info.total_bulbs_prod = 0;
310 unknown_info.id = research_number(presearch);
311
312 conn_list_iterate(dest, pconn) {
313 pplayer = conn_get_player(pconn);
314 if (NULL != pplayer) {
315 if (presearch == research_get(pplayer)) {
316 /* Case research owner. */
317 send_packet_research_info(pconn, &full_info);
318 } else {
319 /* 'pplayer' may have an embassy for looking to 'presearch'. */
320 bool embassy = FALSE;
321
322 research_players_iterate(presearch, powner) {
323 if (team_has_embassy(pplayer->team, powner)) {
324 embassy = TRUE;
325 break;
326 }
327 } research_players_iterate_end;
328
329 if (embassy) {
330 send_packet_research_info(pconn, &restricted_info);
331 } else {
332 send_packet_unknown_research(pconn, &unknown_info);
333 }
334 }
335 } else if (pconn->observer) {
336 /* Case global observer. */
337 send_packet_research_info(pconn, &full_info);
338 }
339 } conn_list_iterate_end;
340}
341
342/************************************************************************/
347 void found_new_tech(struct research *presearch, Tech_type_id tech_found,
348 bool was_discovery, bool saving_bulbs)
349{
350 int had_embassies[player_slot_count()];
351 struct cur_govs_data *could_switch;
352 bool was_first = FALSE;
353 bool bonus_tech_hack = FALSE;
354 int i;
355 const char *advance_name;
356 struct advance *vap = valid_advance_by_number(tech_found);
357 struct city *pcity;
358
359 if (!is_future_tech(tech_found)) {
360
361#ifndef FREECIV_NDEBUG
362 fc_assert(NULL != vap);
363 fc_assert(TECH_KNOWN != research_invention_state(presearch, tech_found));
364#endif /* FREECIV_NDEBUG */
365
366 was_first = (!game.info.global_advances[tech_found]);
367 }
368
369 /* Assign 'advance_name' before we increase the future tech counter. */
370 advance_name = research_advance_name_translation(presearch, tech_found);
371
372 if (was_first && vap) {
373 /* Alert the owners of any wonders that have been made obsolete */
374 improvement_iterate(pimprove) {
375 requirement_vector_iterate(&pimprove->obsolete_by, pobs) {
376 if (pobs->source.kind == VUT_ADVANCE
377 && pobs->source.value.advance == vap
378 && pobs->range >= REQ_RANGE_WORLD
379 && pobs->present
380 && pobs->survives
381 && is_great_wonder(pimprove)
382 && (pcity = city_from_great_wonder(pimprove))) {
383 notify_player(city_owner(pcity), NULL, E_WONDER_OBSOLETE, ftc_server,
384 _("Discovery of %s OBSOLETES %s in %s!"),
385 research_advance_name_translation
386 (research_get(city_owner(pcity)), tech_found),
387 improvement_name_translation(pimprove),
388 city_link(pcity));
389 }
390 } requirement_vector_iterate_end;
391 } improvement_iterate_end;
392 }
393
394 if (was_first
395 && !is_future_tech(tech_found)
396 && advance_has_flag(tech_found, TF_BONUS_TECH)) {
397 bonus_tech_hack = TRUE;
398 }
399
400 /* Memorize some values before the tech is marked as researched.
401 * We will check what has changed later. */
402 players_iterate(aplayer) {
403 i = player_index(aplayer);
404
405 /* Count EFT_HAVE_EMBASSIES effect for each player. */
406 had_embassies[i] = get_player_bonus(aplayer, EFT_HAVE_EMBASSIES);
407 } players_iterate_end;
408
409 could_switch = create_current_governments_data(presearch);
410
411 /* Getting tech allows us to change research without applying techpenalty
412 * (without losing bulbs) */
413 if (tech_found == presearch->researching) {
414 presearch->free_bulbs = presearch->bulbs_researched;
415 }
416 presearch->researching_saved = A_UNKNOWN;
417 presearch->techs_researched++;
418
419 /* Mark the tech as known in the research struct and update
420 * global_advances array. */
421 if (is_future_tech(tech_found)) {
422 presearch->future_tech++;
423 } else {
424 research_invention_set(presearch, tech_found, TECH_KNOWN);
425 research_update(presearch);
426 }
427
428 /* Inform players about their new tech. */
429 send_research_info(presearch, NULL);
430
431 if (was_first) {
432 /* Inform all players about new global advances to give them a
433 * chance for obsolete buildings. */
434 send_game_info(NULL);
435 }
436
437 /* Make proper changes for all players. Use shuffled order, in case
438 * a script would detect a signal. */
439 shuffled_players_iterate(aplayer) {
440 bool shares_research = (presearch == research_get(aplayer));
441 i = player_index(aplayer);
442
443 if (shares_research) {
444 char buf[250];
445
446 /* Only for players sharing the research. */
447 remove_obsolete_buildings(aplayer);
448
449 /* Give free infrastructure in every city */
450 if (tech_found != A_FUTURE) {
451 upgrade_all_city_extras(aplayer, was_discovery);
452
453 /* Revealing of extras with visibility_req */
454 whole_map_iterate(&(wld.map), ptile) {
455 if (map_is_known_and_seen(ptile, aplayer, V_MAIN)) {
456 if (update_player_tile_knowledge(aplayer, ptile)) {
457 send_tile_info(aplayer->connections, ptile, FALSE);
458 }
459 }
460 } whole_map_iterate_end;
461 }
462
463 /* Enhance vision of units if a player-ranged effect has changed. Note
464 * that world-ranged effects will not be updated immediately. */
465 unit_list_refresh_vision(aplayer->units);
466
467 if (shares_research) {
468 fc_snprintf(buf, sizeof(buf), _("Discovery of %s"), advance_name);
469
470 notify_new_government_options(aplayer, could_switch, buf);
471 }
472 }
473
474 /* For any player. */
475 /* Update all cities in case the tech changed some effects. This is
476 * inefficient; it could be optimized if it's found to be a problem.
477 * But techs aren't researched that often. */
478 city_list_iterate(aplayer->cities, apcity) {
479 /* Refresh the city data; this also updates the squared city radius. */
480 city_refresh(apcity);
481 city_refresh_vision(apcity);
482 send_city_info(aplayer, apcity);
483 } city_list_iterate_end;
484
485 /* Send all player an updated info of the owner of the Marco Polo
486 * Wonder if this wonder has become obsolete. */
487 if (0 < had_embassies[i]
488 && 0 <= get_player_bonus(aplayer, EFT_HAVE_EMBASSIES)) {
489 send_player_all_c(aplayer, aplayer->connections);
490 players_iterate(pother_player) {
491 if (aplayer != pother_player) {
492 send_player_all_c(aplayer, pother_player->connections);
493 send_player_all_c(pother_player, aplayer->connections);
494 }
495 } players_iterate_end;
496 }
497 } shuffled_players_iterate_end;
498
499 free_current_governments_data(could_switch);
500
501 if (tech_found == presearch->tech_goal) {
502 presearch->tech_goal = A_UNSET;
503 }
504
505 if (tech_found == presearch->researching) {
506 /* Try to pick new tech to research. */
507 Tech_type_id next_tech = research_goal_step(presearch,
508 presearch->tech_goal);
509
510 /* As this function can be recursive, we need to print the messages
511 * before really picking the new technology. */
512 if (A_UNSET != next_tech) {
513 notify_research(presearch, NULL, E_TECH_LEARNED, ftc_server,
514 _("Learned %s. Our scientists focus on %s; "
515 "goal is %s."),
516 advance_name,
517 research_advance_name_translation(presearch,
518 next_tech),
519 research_advance_name_translation
520 (presearch, presearch->tech_goal));
521 } else {
522 if (is_future_tech(tech_found)) {
523 /* Use pick_random_tech() to determine if there now is
524 * a regular tech to research, e.g., if one was lost
525 * due to tech upkeep since we started researching future techs. */
526 next_tech = pick_random_tech(presearch);
527
528 /* Continue researching future tech, if possible. */
529 if (next_tech != A_FUTURE) {
530 bool ai_found = FALSE;
531
532 /* Otherwise check if there's an AI player to support
533 * randomly selected tech (one that "made" the decision) */
534 research_players_iterate(presearch, aplayer) {
535 if (is_ai(aplayer)) {
536 ai_found = TRUE;
537 }
538 } research_players_iterate_end;
539
540 if (!ai_found) {
541 /* Decision is humans' to make */
542 next_tech = A_UNSET;
543 }
544 }
545 } else {
546 /* If there is at least one AI player still alive, then pick
547 * a random tech, else keep A_UNSET. */
548 research_players_iterate(presearch, aplayer) {
549 if (is_ai(aplayer)) {
550 next_tech = pick_random_tech(presearch);
551 break;
552 }
553 } research_players_iterate_end;
554 }
555
556 if (A_UNSET == next_tech) {
557 notify_research(presearch, NULL, E_TECH_LEARNED, ftc_server,
558 _("Learned %s. Scientists "
559 "do not know what to research next."),
560 advance_name);
561 } else {
562 notify_research(presearch, NULL, E_TECH_LEARNED, ftc_server,
563 _("Learned %s. Scientists choose to research %s."),
564 advance_name,
565 research_advance_name_translation(presearch,
566 next_tech));
567 }
568 }
569
570 if (A_UNSET != next_tech) {
571 choose_tech(presearch, next_tech);
572 } else {
573 presearch->researching = A_UNSET;
574 }
575 }
576
577 if (!saving_bulbs && presearch->bulbs_researched > 0) {
578 presearch->bulbs_researched = 0;
579 }
580
581 if (bonus_tech_hack) {
582 Tech_type_id additional_tech;
583 char research_name[MAX_LEN_NAME * 2];
584 const char *radv_name;
585
586 research_pretty_name(presearch, research_name, sizeof(research_name));
587
588 additional_tech = pick_free_tech(presearch);
589
590 radv_name = research_advance_name_translation(presearch, additional_tech);
591
592 give_immediate_free_tech(presearch, additional_tech);
593 if (advance_by_number(tech_found)->bonus_message != NULL
594 && additional_tech != A_UNSET) {
595 notify_research(presearch, NULL, E_TECH_GAIN, ftc_server,
596 _(advance_by_number(tech_found)->bonus_message),
597 radv_name);
598 } else if (additional_tech != A_UNSET) {
599 /* FIXME: "your" when it was just civilization of one of the players
600 * sharing the research. */
601 notify_research(presearch, NULL, E_TECH_GAIN, ftc_server,
602 _("Great scientists from all the "
603 "world join your civilization: you learn "
604 "%s immediately."), radv_name);
605 }
606 /* TODO: Ruleset should be able to customize this message too */
607 notify_research_embassies(presearch, NULL, E_TECH_EMBASSY, ftc_server,
608 _("%s acquire %s as a result of learning %s."),
609 research_name, radv_name, advance_name);
610 }
611}
612
613/************************************************************************/
616 static bool lose_tech(struct research *research)
617{
618 if (game.info.techloss_forgiveness < 0) {
619 /* Tech loss disabled */
620 return FALSE;
621 }
622
623 if (research->techs_researched == 0) {
624 /* No tech to lose */
625 fc_assert(research->future_tech == 0);
626 return FALSE;
627 }
628
629 /* First check is not for optimization only - it protects
630 * research_total_bulbs_required() from getting called before research
631 * has even been set to value other than A_UNSET. */
632 if (research->bulbs_researched < 0
633 && research->bulbs_researched <
634 (-research_total_bulbs_required(research, research->researching, FALSE)
635 * game.info.techloss_forgiveness / 100)) {
636 return TRUE;
637 }
638
639 return FALSE;
640}
641
642/************************************************************************/
654 void update_bulbs(struct player *pplayer, int bulbs, bool check_tech,
655 bool free_bulbs)
656{
657 struct research *research = research_get(pplayer);
658
659 if (!pplayer->is_alive) {
660 /* Dead players do not produce research */
661 return;
662 }
663 fc_assert_ret(research);
664
665 /* count our research contribution this turn */
666 pplayer->server.bulbs_last_turn += bulbs;
667 research->bulbs_researched += bulbs;
668 if (A_UNKNOWN != research->researching_saved) {
669 fc_assert(research->researching_saved != research->researching);
670 research->bulbs_researching_saved += bulbs;
671 }
672 if ((free_bulbs && !game.server.multiresearch)
673 || A_UNSET == research->researching) {
674 research->free_bulbs += bulbs;
675 }
676 advance_index_iterate(A_FIRST, j) {
677 if (j == research->researching) {
678 research->inventions[j].bulbs_researched_saved = research->bulbs_researched;
679 }
680 } advance_index_iterate_end;
681
682
683 do {
684 /* If we have a negative number of bulbs we do try to:
685 * - reduce the number of future techs;
686 * - or lose one random tech.
687 * After that the number of bulbs available is increased based on the
688 * value of the lost tech. */
689 if (lose_tech(research)) {
690 Tech_type_id tech = (research->future_tech > 0
691 ? A_FUTURE : pick_random_tech_to_lose(research));
692
693 if (tech != A_NONE) {
694 if (game.server.techloss_restore >= 0) {
695 research->bulbs_researched +=
696 (research_total_bulbs_required(research, tech, TRUE)
697 * game.server.techloss_restore / 100);
698 } else {
699 research->bulbs_researched = 0;
700 }
701 research->researching_saved = A_UNKNOWN;
702
703 log_debug("%s: tech loss (%s)",
704 research_rule_name(research),
705 (is_future_tech(tech) ? "Future Tech"
706 : research_advance_rule_name(research, tech)));
707 research_tech_lost(research, tech);
708 /* Make notification after losing the research, in case it is
709 * a future tech (for getting the right tech number). */
710 notify_research(research, NULL, E_TECH_LOST, ftc_server,
711 _("Insufficient science output. We lost %s."),
712 research_advance_name_translation(research, tech));
713 }
714 }
715
716 /* Check for finished research. */
717 if (!check_tech
718 || research->researching == A_UNSET
719 || (research->bulbs_researched
720 < research_total_bulbs_required(research, research->researching,
721 FALSE))) {
722 break;
723 }
724
725 tech_researched(research);
726 } while (research->researching != A_UNSET);
727}
728
729/************************************************************************/
732static Tech_type_id
733pick_random_tech_to_lose(const struct research *presearch)
734{
735 bv_techs eligible_techs;
736 Tech_type_id full_count = advance_count();
737 /* A_NONE included in advance_count(). */
738 int eligible = full_count - 1;
739 int chosen;
740
741 BV_SET_ALL(eligible_techs);
742
743 advance_index_iterate_max(A_FIRST, i, full_count) {
744 if (research_invention_state(presearch, i) != TECH_KNOWN) {
745 if (BV_ISSET(eligible_techs, i)) {
746 eligible--;
747 BV_CLR(eligible_techs, i);
748 }
749 } else {
750 /* Knowing this tech may make others ineligible */
751 Tech_type_id root = advance_required(i, AR_ROOT);
752
753 /* Never lose techs that are root_req for a currently known tech
754 * (including self root_req) */
755 if (root != A_NONE && BV_ISSET(eligible_techs, root)) {
756 eligible--;
757 BV_CLR(eligible_techs, root);
758 }
759 if (!game.info.tech_loss_allow_holes) {
760 /* Ruleset can prevent this kind of tech loss from opening up
761 * holes in the tech tree */
762 Tech_type_id prereq;
763
764 prereq = advance_required(i, AR_ONE);
765 if (prereq != A_NONE && BV_ISSET(eligible_techs, prereq)) {
766 eligible--;
767 BV_CLR(eligible_techs, prereq);
768 }
769 prereq = advance_required(i, AR_TWO);
770 if (prereq != A_NONE && BV_ISSET(eligible_techs, prereq)) {
771 eligible--;
772 BV_CLR(eligible_techs, prereq);
773 }
774 }
775 }
776 } advance_index_iterate_max_end;
777
778 if (eligible == 0) {
779 /* no researched technology at all */
780 return A_NONE;
781 }
782
783 chosen = fc_rand(eligible) + 1;
784
785 advance_index_iterate_max(A_FIRST, i, full_count) {
786 if (BV_ISSET(eligible_techs, i)) {
787 chosen--;
788 if (chosen == 0) {
789 return i;
790 }
791 }
792 } advance_index_iterate_max_end;
793
794 /* should never be reached */
795 fc_assert_msg(chosen == 0, "internal error (eligible=%d, chosen=%d)",
796 eligible, chosen);
797 return A_NONE;
798}
799
800/************************************************************************/
803static inline struct government *
804pick_random_government(struct player *pplayer)
805{
806 struct government *picked = NULL;
807 int gov_nb = 0;
808
809 governments_iterate(pgov) {
810 if (can_change_to_government(pplayer, pgov) && 0 == fc_rand(++gov_nb)) {
811 picked = pgov;
812 }
813 } governments_iterate_end;
814 fc_assert(NULL != picked);
815 return picked;
816}
817
818/************************************************************************/
821 static void research_tech_lost(struct research *presearch, Tech_type_id tech)
822{
823 char research_name[MAX_LEN_NAME * 2];
824 /* Research members will be notified when new tech is chosen. */
825
826 research_pretty_name(presearch, research_name, sizeof(research_name));
827
828 presearch->techs_researched--;
829 if (is_future_tech(tech)) {
830 presearch->future_tech--;
831 research_update(presearch);
832 /* Notify after decreasing the future tech counter, to get the right
833 * tech number in the message. */
834 notify_research_embassies(presearch, NULL, E_TECH_EMBASSY, ftc_server,
835 _("The %s have lost %s."),
836 research_name,
837 research_advance_name_translation(presearch,
838 tech));
839 /* Inform players about their technology loss. */
840 send_research_info(presearch, NULL);
841 return;
842 }
843
844 fc_assert_ret(valid_advance_by_number(tech));
845 notify_research_embassies(presearch, NULL, E_TECH_EMBASSY, ftc_server,
846 /* TRANS: technology loss */
847 _("The %s have lost %s."),
848 research_name,
849 research_advance_name_translation(presearch,
850 tech));
851
852 /* Remove technology. */
853 research_invention_set(presearch, tech, TECH_UNKNOWN);
854 research_update(presearch);
855 log_debug("%s lost tech id %d (%s)", research_rule_name(presearch), tech,
856 advance_rule_name(advance_by_number(tech)));
857
858 /* Inform players about their technology loss. */
859 send_research_info(presearch, NULL);
860
861 research_players_iterate(presearch, pplayer) {
862 /* Check government. */
863 if (!can_change_to_government(pplayer, government_of_player(pplayer))) {
864 /* Lost the technology for the government; switch to random
865 * available government. */
866 struct government *pgov = pick_random_government(pplayer);
867
868 notify_player(pplayer, NULL, E_NEW_GOVERNMENT, ftc_server,
869 _("The required technology for our government '%s' "
870 "was lost. The citizens have started a "
871 "revolution into '%s'."),
872 government_name_translation(government_of_player
873 (pplayer)),
874 government_name_translation(pgov));
875 handle_player_change_government(pplayer, government_number(pgov));
876 send_player_info_c(pplayer, NULL);
877 } else if (NULL != pplayer->target_government
878 && !can_change_to_government(pplayer,
879 pplayer->target_government)) {
880 /* Lost the technology for the target government; use a random
881 * available government as new target government. */
882 struct government *pgov = pick_random_government(pplayer);
883
884 notify_player(pplayer, NULL, E_NEW_GOVERNMENT, ftc_server,
885 _("The required technology for our new government "
886 "'%s' was lost. The citizens chose '%s' as new "
887 "target government."),
888 government_name_translation(pplayer->target_government),
889 government_name_translation(pgov));
890 pplayer->target_government = pgov;
891 send_player_info_c(pplayer, pplayer->connections);
892 }
893
894 /* Check all units for valid activities. */
895 unit_activities_cancel_all_illegal_plr(pplayer);
896
897 /* Check city production */
898 city_list_iterate(pplayer->cities, pcity) {
899 bool update = FALSE;
900
901 if (pcity->production.kind == VUT_UTYPE
902 && !can_city_build_unit_now(pcity, pcity->production.value.utype)) {
903 notify_player(pplayer, city_tile(pcity),
904 E_CITY_CANTBUILD, ftc_server,
905 _("%s can't build %s. The required technology was "
906 "lost."),
907 city_link(pcity),
908 utype_name_translation(pcity->production.value.utype));
909 choose_build_target(pplayer, pcity);
910 update = TRUE;
911 }
912
913 if (pcity->production.kind == VUT_IMPROVEMENT
914 && !can_city_build_improvement_now(pcity,
915 pcity->production.value.building)) {
916 notify_player(pplayer, city_tile(pcity),
917 E_CITY_CANTBUILD, ftc_server,
918 _("%s can't build %s. The required technology was "
919 "lost."),
920 city_link(pcity),
921 improvement_name_translation
922 (pcity->production.value.building));
923 choose_build_target(pplayer, pcity);
924 update = TRUE;
925 }
926
927 if (update) {
928 city_refresh(pcity);
929 send_city_info(pplayer, pcity);
930 }
931 } city_list_iterate_end;
932 } research_players_iterate_end;
933}
934
935/************************************************************************/
938 static Tech_type_id pick_random_tech(const struct research *presearch)
939{
940 Tech_type_id tech = A_FUTURE;
941 int num_techs = 0;
942
943 advance_index_iterate(A_FIRST, i) {
944 if (research_invention_state(presearch, i) == TECH_PREREQS_KNOWN) {
945 if (fc_rand(++num_techs) == 0) {
946 tech = i;
947 }
948 }
949 } advance_index_iterate_end;
950
951 return tech;
952}
953
954/************************************************************************/
957 static Tech_type_id pick_cheapest_tech(const struct research *presearch)
958{
959 int cheapest_cost = -1;
960 int cheapest_amount = 0;
961 Tech_type_id cheapest = A_FUTURE; /* If no real tech is found to be missing */
962
963 advance_index_iterate(A_FIRST, i) {
964 if (research_invention_state(presearch, i) == TECH_PREREQS_KNOWN) {
965 int cost = research_total_bulbs_required(presearch, i, FALSE);
966
967 if (cost < cheapest_cost || cheapest_cost == -1) {
968 cheapest_cost = cost;
969 cheapest_amount = 1;
970 cheapest = i;
971 } else if (cost == cheapest_cost && fc_rand(++cheapest_amount) == 0) {
972 cheapest = i;
973 }
974 }
975 } advance_index_iterate_end;
976
977 return cheapest;
978}
979
980/************************************************************************/
989 void choose_random_tech(struct research *research)
990{
991 do {
992 choose_tech(research, pick_random_tech(research));
993 } while (research->researching == A_UNSET);
994}
995
996/************************************************************************/
1004 void choose_tech(struct research *research, Tech_type_id tech)
1005{
1006 int bulbs_res = 0;
1007
1008 if (is_future_tech(tech)) {
1009 if (is_future_tech(research->researching)
1010 && (research->bulbs_researched
1011 >= research_total_bulbs_required(research, tech, FALSE))) {
1012 tech_researched(research);
1013 }
1014 } else {
1015 if (research->researching == tech) {
1016 return;
1017 }
1018 if (research_invention_state(research, tech) != TECH_PREREQS_KNOWN) {
1019 /* Can't research this. */
1020 return;
1021 }
1022 }
1023
1024 if (game.server.multiresearch) {
1025 advance_index_iterate(A_FIRST, j) {
1026 /* Save old tech research */
1027 if (j == research->researching) {
1028 research->inventions[j].bulbs_researched_saved = research->bulbs_researched;
1029 }
1030 /* New tech*/
1031 if (j == tech) {
1032 bulbs_res = research->inventions[j].bulbs_researched_saved;
1033 }
1034 } advance_index_iterate_end;
1035 research->researching = tech;
1036 research->bulbs_researched = research->free_bulbs + bulbs_res;
1037 research->free_bulbs = 0;
1038 if (research->bulbs_researched
1039 >= research_total_bulbs_required(research, tech, FALSE)) {
1040 tech_researched(research);
1041 }
1042 return;
1043 }
1044
1045 /* The first check implies we have NOT recently got a technology
1046 * and are changing from one we were researching at tc. */
1047 if (research->bulbs_researched - research->free_bulbs > 0
1048 && research->researching_saved == A_UNKNOWN) {
1049 research->bulbs_researching_saved = research->bulbs_researched;
1050 research->researching_saved = research->researching;
1051 /* Subtract a penalty because we changed subject. */
1052 if (research->bulbs_researched > 0) {
1053 research->bulbs_researched
1054 -= ((research->bulbs_researched - research->free_bulbs)
1055 * game.server.techpenalty) / 100;
1056 /* If free_bulbs were for some reason negative... */
1057 research->bulbs_researched = MAX(research->bulbs_researched, 0);
1058 }
1059 } else if (tech == research->researching_saved) {
1060 research->bulbs_researched = research->bulbs_researching_saved;
1061 research->researching_saved = A_UNKNOWN;
1062 }
1063 research->researching = tech;
1064 if (research->bulbs_researched
1065 >= research_total_bulbs_required(research, tech, FALSE)) {
1066 tech_researched(research);
1067 }
1068}
1069
1070/************************************************************************/
1074 void choose_tech_goal(struct research *presearch, Tech_type_id tech)
1075{
1076 fc_assert_ret(presearch != NULL);
1077
1078 if (tech == presearch->tech_goal) {
1079 return;
1080 }
1081
1082 /* It's been suggested that if the research target is empty then
1083 * choose_random_tech() should be called here. */
1084 presearch->tech_goal = tech;
1085 notify_research(presearch, NULL, E_TECH_GOAL, ftc_server,
1086 _("Technology goal is %s."),
1087 research_advance_name_translation(presearch, tech));
1088}
1089
1090/************************************************************************/
1093 void init_tech(struct research *research, bool update)
1094{
1095 Tech_type_id ac = advance_count();
1096
1097 research_invention_set(research, A_NONE, TECH_KNOWN);
1098
1099 advance_index_iterate_max(A_FIRST, i, ac) {
1100 research_invention_set(research, i, TECH_UNKNOWN);
1101 } advance_index_iterate_max_end;
1102
1103#ifdef TECH_UPKEEP_DEBUGGING
1104 /* Print a list of the needed upkeep if 'i' techs are researched.
1105 * If the ruleset contains self-rooted techs this can not work! */
1106 {
1107 bool global_state[A_LAST];
1108 Tech_type_id tech = A_LAST;
1109
1110 /* Save the game research state. */
1111 advance_index_iterate_max(A_FIRST, i, ac) {
1112 global_state[i] = game.info.global_advances[i];
1113 } advance_index_iterate_max_end;
1114
1115 research->techs_researched = 1;
1116 research_update(presearch);
1117
1118 /* Show research costs. */
1119 advance_index_iterate_max(A_NONE, i, ac) {
1120 log_debug("[research %d] %-25s (ID: %3d) cost: %6d - reachable: %-3s "
1121 "(now) / %-3s (ever)", research_number(research),
1122 advance_rule_name(advance_by_number(i)), i,
1123 research_total_bulbs_required(research, i, FALSE),
1124 research_invention_gettable(research, i, FALSE)
1125 ? "yes" : "no",
1126 research_invention_reachable(research, i) ? "yes" : "no");
1127 } advance_index_iterate_max_end;
1128
1129 /* Update step for step each tech as known and print the upkeep. */
1130 while (tech != A_NONE) {
1131 tech = A_NONE;
1132 advance_index_iterate_max(A_FIRST, i, ac) {
1133 if (valid_advance_by_number(i) != NULL
1134 && research_invention_state(research, i) == TECH_PREREQS_KNOWN) {
1135 /* Found a tech which can be researched. */
1136 tech = i;
1137 break;
1138 }
1139 } advance_index_iterate_max_end;
1140
1141 if (tech != A_NONE) {
1142 research->inventions[tech].state = TECH_KNOWN;
1143 research->techs_researched++;
1144
1145 /* This will change the game state! */
1146 research_update(research);
1147
1148 research_players_iterate(research, pplayer) {
1149 log_debug("[player %d] researched: %-25s (ID: %4d) techs: %3d "
1150 "upkeep: %4d", research_number(research),
1151 advance_rule_name(advance_by_number(tech)), tech,
1152 research->techs_researched, player_tech_upkeep(pplayer));
1153 } research_players_iterate_end;
1154 }
1155 }
1156
1157 /* Reset the changes done. */
1158 advance_index_iterate_max(A_FIRST, i, ac) {
1159 research_invention_set(research, i, TECH_UNKNOWN);
1160 game.info.global_advances[i] = global_state[i];
1161 } advance_index_iterate_max_end;
1162 }
1163#endif /* TECH_UPKEEP_DEBUGGING */
1164
1165 research->techs_researched = 1;
1166
1167 if (update) {
1168 Tech_type_id next_tech;
1169
1170 /* Mark the reachable techs */
1171 research_update(research);
1172
1173 next_tech = research_goal_step(research, research->tech_goal);
1174 if (A_UNSET != next_tech) {
1175 choose_tech(research, next_tech);
1176 } else {
1177 choose_random_tech(research);
1178 }
1179 }
1180}
1181
1182/************************************************************************/
1187 void give_initial_techs(struct research *presearch, int num_random_techs)
1188{
1189 int i;
1190
1191 /* Global techs. */
1192 for (i = 0; i < MAX_NUM_TECH_LIST; i++) {
1193 if (game.rgame.global_init_techs[i] == A_LAST) {
1194 break;
1195 }
1196 /* Maybe the player already got this tech by an other way (e.g. team). */
1197 if (research_invention_state(presearch, game.rgame.global_init_techs[i])
1198 != TECH_KNOWN) {
1199 found_new_tech(presearch, game.rgame.global_init_techs[i],
1200 FALSE, TRUE);
1201 }
1202 }
1203
1204 /* Nation techs. */
1205 research_players_iterate(presearch, pplayer) {
1206 const struct nation_type *pnation = nation_of_player(pplayer);
1207
1208 for (i = 0; i < MAX_NUM_TECH_LIST; i++) {
1209 if (pnation->init_techs[i] == A_LAST) {
1210 break;
1211 }
1212 /* Maybe the player already got this tech by an other way. */
1213 if (research_invention_state(presearch, pnation->init_techs[i])
1214 != TECH_KNOWN) {
1215 found_new_tech(presearch, pnation->init_techs[i], FALSE, TRUE);
1216 }
1217 }
1218 } research_players_iterate_end;
1219
1220 /* Random free techs (N.B.: freecost penalty not applied). */
1221 for (i = 0; i < num_random_techs; i++) {
1222 found_new_tech(presearch, pick_random_tech(presearch), FALSE, TRUE);
1223 }
1224}
1225
1226/************************************************************************/
1233 Tech_type_id steal_a_tech(struct player *pplayer, struct player *victim,
1234 Tech_type_id preferred)
1235{
1236 struct research *presearch, *vresearch;
1237 Tech_type_id stolen_tech = A_NONE;
1238 const char *advance_name;
1239 char research_name[MAX_LEN_NAME * 2];
1240
1241 if (get_player_bonus(victim, EFT_NOT_TECH_SOURCE) > 0) {
1242 return A_NONE;
1243 }
1244
1245 presearch = research_get(pplayer);
1246 vresearch = research_get(victim);
1247
1248 if (preferred == A_UNSET) {
1249 int j = 0;
1250 Tech_type_id ac = advance_count();
1251
1252 advance_index_iterate_max(A_FIRST, i, ac) {
1253 if (research_invention_gettable(presearch, i,
1254 game.info.tech_steal_allow_holes)
1255 && research_invention_state(presearch, i) != TECH_KNOWN
1256 && research_invention_state(vresearch, i) == TECH_KNOWN) {
1257 j++;
1258 }
1259 } advance_index_iterate_max_end;
1260
1261 if (j == 0) {
1262 /* We've moved on to future tech */
1263 if (vresearch->future_tech > presearch->future_tech) {
1264 stolen_tech = A_FUTURE;
1265 } else {
1266 return A_NONE;
1267 }
1268 } else {
1269 /* Pick random tech */
1270 j = fc_rand(j) + 1;
1271 stolen_tech = A_NONE; /* Avoid compiler warning */
1272 advance_index_iterate_max(A_FIRST, i, ac) {
1273 if (research_invention_gettable(presearch, i,
1274 game.info.tech_steal_allow_holes)
1275 && research_invention_state(presearch, i) != TECH_KNOWN
1276 && research_invention_state(vresearch, i) == TECH_KNOWN) {
1277 j--;
1278 }
1279 if (j == 0) {
1280 stolen_tech = i;
1281 break;
1282 }
1283 } advance_index_iterate_max_end;
1284 fc_assert(stolen_tech != A_NONE);
1285 }
1286 } else { /* preferred != A_UNSET */
1287#ifndef FREECIV_NDEBUG
1288 if (!is_future_tech(preferred)) {
1289 fc_assert(NULL != valid_advance_by_number(preferred));
1290 fc_assert(TECH_KNOWN == research_invention_state(vresearch,
1291 preferred));
1292 }
1293#endif /* FREECIV_NDEBUG */
1294 stolen_tech = preferred;
1295 }
1296
1297 advance_name = research_advance_name_translation(presearch, stolen_tech);
1298 research_pretty_name(presearch, research_name, sizeof(research_name));
1299 notify_player(pplayer, NULL, E_MY_DIPLOMAT_THEFT, ftc_server,
1300 _("You steal %s from the %s."),
1301 advance_name,
1302 nation_plural_for_player(victim));
1303 notify_research(presearch, pplayer, E_TECH_GAIN, ftc_server,
1304 _("The %s stole %s from the %s and shared it with you."),
1305 nation_plural_for_player(pplayer),
1306 advance_name,
1307 nation_plural_for_player(victim));
1308
1309 notify_player(victim, NULL, E_ENEMY_DIPLOMAT_THEFT, ftc_server,
1310 _("The %s stole %s from you!"),
1311 nation_plural_for_player(pplayer),
1312 advance_name);
1313
1314 notify_research_embassies(presearch, victim, E_TECH_EMBASSY, ftc_server,
1315 _("The %s have stolen %s from the %s."),
1316 research_name,
1317 advance_name,
1318 nation_plural_for_player(victim));
1319
1320 if (tech_transfer(pplayer, victim, stolen_tech)) {
1321 research_apply_penalty(presearch, stolen_tech, game.server.conquercost);
1322 found_new_tech(presearch, stolen_tech, FALSE, TRUE);
1323 script_tech_learned(presearch, pplayer, advance_by_number(stolen_tech),
1324 "stolen");
1325 return stolen_tech;
1326 }
1327
1328 return A_NONE;
1329}
1330
1331/************************************************************************/
1338 void handle_player_research(struct player *pplayer, int tech)
1339{
1340 struct research *research = research_get(pplayer);
1341
1342 if (tech != A_FUTURE && !valid_advance_by_number(tech)) {
1343 return;
1344 }
1345
1346 if (tech != A_FUTURE
1347 && research_invention_state(research, tech) != TECH_PREREQS_KNOWN) {
1348 return;
1349 }
1350
1351 choose_tech(research, tech);
1352
1353 /* Notify players sharing the same research. */
1354 send_research_info(research, NULL);
1355}
1356
1357/************************************************************************/
1361 void handle_player_tech_goal(struct player *pplayer, int tech_goal)
1362{
1363 struct research *research = research_get(pplayer);
1364
1365 /* Set the tech goal to a defined state if it is
1366 * - not a future tech and not a valid goal
1367 * - not a future tech and not a valid advance
1368 * - not defined
1369 * - known (i.e. due to EFT_GIVE_IMM_TECH). */
1370 if ((tech_goal != A_FUTURE
1371 && (!valid_advance_by_number(tech_goal)
1372 || !research_invention_reachable(research, tech_goal)))
1373 || (tech_goal == A_NONE)
1374 || (TECH_KNOWN == research_invention_state(research, tech_goal))) {
1375 tech_goal = A_UNSET;
1376 }
1377
1378 choose_tech_goal(research, tech_goal);
1379
1380 /* Notify players sharing the same research. */
1381 send_research_info(research, NULL);
1382}
1383
1384/************************************************************************/
1387 Tech_type_id pick_free_tech(struct research *presearch)
1388{
1389 Tech_type_id tech;
1390
1391 if (game.info.free_tech_method == FTM_CHEAPEST) {
1392 tech = pick_cheapest_tech(presearch);
1393 } else if (presearch->researching == A_UNSET
1394 || game.info.free_tech_method == FTM_RANDOM) {
1395 tech = pick_random_tech(presearch);
1396 } else {
1397 tech = presearch->researching;
1398 }
1399 return tech;
1400}
1401
1402/************************************************************************/
1406 void give_immediate_free_tech(struct research *presearch, Tech_type_id tech)
1407{
1408 research_apply_penalty(presearch, tech, game.server.freecost);
1409 found_new_tech(presearch, tech, FALSE, TRUE);
1410}
1411
1412/************************************************************************/
1415 static void forget_tech_transferred(struct player *pplayer, Tech_type_id tech)
1416{
1417 struct research *presearch = research_get(pplayer);
1418
1419 research_tech_lost(presearch, tech);
1420 /* Make notification after losing the research, in case it is a future
1421 * tech (for getting the right tech number). */
1422 notify_player(pplayer, NULL, E_TECH_LOST, ftc_server,
1423 _("Too bad! You made a mistake transferring the tech %s and "
1424 "lost it."),
1425 research_advance_name_translation(presearch, tech));
1426 notify_research(presearch, pplayer, E_TECH_LOST, ftc_server,
1427 _("Too bad! The %s made a mistake transferring the tech "
1428 "%s and lost it."),
1429 nation_plural_for_player(pplayer),
1430 research_advance_name_translation(presearch, tech));
1431}
1432
1433/************************************************************************/
1437 bool tech_transfer(struct player *plr_recv, struct player *plr_donor,
1438 Tech_type_id tech)
1439{
1440 if (game.server.techlost_donor > 0) {
1441 struct research *donor_research = research_get(plr_donor);
1442 bool donor_can_lose = TRUE;
1443
1444 advance_index_iterate(A_FIRST, i) {
1445 /* Never let donor lose tech if it's root_req for some other known
1446 * tech */
1447 if (research_invention_state(donor_research, i) == TECH_KNOWN
1448 && (advance_required(i, AR_ROOT) == tech
1449 || (!game.info.tech_trade_loss_allow_holes
1450 && (advance_required(i, AR_ONE) == tech
1451 || advance_required(i, AR_TWO) == tech)))) {
1452 donor_can_lose = FALSE;
1453 break;
1454 }
1455 } advance_index_iterate_end;
1456 if (donor_can_lose && fc_rand(100) < game.server.techlost_donor) {
1457 forget_tech_transferred(plr_donor, tech);
1458 }
1459 }
1460
1461 if (fc_rand(100) < game.server.techlost_recv) {
1462 struct research *presearch = research_get(plr_recv);
1463
1464 /* We've not received the tech yet, and never will.
1465 * Do not call forget_tech_transferred() that would handle it
1466 * as something we had and now lose.
1467 * (e.g. subtracting techs_researched counter) */
1468 notify_player(plr_recv, NULL, E_TECH_LOST, ftc_server,
1469 _("Too bad! You made a mistake transferring the tech %s and "
1470 "didn't get it."),
1471 research_advance_name_translation(presearch, tech));
1472 notify_research(presearch, plr_recv, E_TECH_LOST, ftc_server,
1473 _("Too bad! The %s made a mistake transferring the tech "
1474 "%s and didn't get it."),
1475 nation_plural_for_player(plr_recv),
1476 research_advance_name_translation(presearch, tech));
1477 return FALSE;
1478 }
1479
1480 return TRUE;
1481}
1482
1483/************************************************************************/
1489 struct cur_govs_data *create_current_governments_data(struct research *presearch)
1490{
1491 struct cur_govs_data *data = fc_malloc(sizeof(struct cur_govs_data));
1492
1493 data->players = fc_malloc(sizeof(*data->players) * player_slot_count());
1494
1495 players_iterate(pplayer) {
1496 data->players[player_index(pplayer)].govs = fc_malloc(sizeof(bool) * government_count());
1497 } players_iterate_end;
1498
1499 research_players_iterate(presearch, pplayer) {
1500 /* Memorize for the players sharing the research what government
1501 * they could switch on. */
1502 governments_iterate(pgov) {
1503 data->players[player_index(pplayer)].govs[government_index(pgov)]
1504 = can_change_to_government(pplayer, pgov);
1505 } governments_iterate_end;
1506 } research_players_iterate_end;
1507
1508 return data;
1509}
1510
1511/************************************************************************/
1517 struct cur_govs_data *create_current_governments_data_all(void)
1518{
1519 struct cur_govs_data *data = fc_malloc(sizeof(struct cur_govs_data));
1520
1521 data->players = fc_malloc(sizeof(*data->players) * player_slot_count());
1522
1523 players_iterate(pplayer) {
1524 data->players[player_index(pplayer)].govs = fc_malloc(sizeof(bool) * government_count());
1525 governments_iterate(pgov) {
1526 data->players[player_index(pplayer)].govs[government_index(pgov)]
1527 = can_change_to_government(pplayer, pgov);
1528 } governments_iterate_end;
1529 } players_iterate_end;
1530
1531 return data;
1532}
1533
1534/************************************************************************/
1537 void free_current_governments_data(struct cur_govs_data *data)
1538{
1539 players_iterate(pplayer) {
1540 free(data->players[player_index(pplayer)].govs);
1541 } players_iterate_end;
1542
1543 free(data->players);
1544 free(data);
1545}
1546
1547/************************************************************************/
1551 void notify_new_government_options(struct player *pplayer,
1552 struct cur_govs_data *data,
1553 const char *reason)
1554{
1555 struct government *available = NULL;
1556
1557 governments_iterate(pgov) {
1558 if (!data->players[player_index(pplayer)].govs[government_index(pgov)]
1559 && can_change_to_government(pplayer, pgov)) {
1560 if (available != NULL) {
1561 notify_player(pplayer, NULL, E_NEW_GOVERNMENT, ftc_server,
1562 /* TRANS: "Discovery of <tech>" */
1563 _("%s makes several new government forms"
1564 " available. You may want to start a revolution."),
1565 reason);
1566 return;
1567 }
1568
1569 available = pgov;
1570 }
1571 } governments_iterate_end;
1572
1573 if (available != NULL) {
1574 notify_player(pplayer, NULL, E_NEW_GOVERNMENT, ftc_server,
1575 /* TRANS: "Discovery of <tech>" */
1576 _("%s makes the government form %s"
1577 " available. You may want to start a revolution."),
1578 reason,
1579 government_name_translation(available));
1580 }
1581}
astr_free
void astr_free(struct astring *astr)
Definition astring.c:148
astr_init
void astr_init(struct astring *astr)
Definition astring.c:139
astring.h
astr_str
static const char * astr_str(const struct astring *astr) fc__attribute((nonnull(1)))
Definition astring.h:93
BV_SET_ALL
#define BV_SET_ALL(bv)
Definition bitvector.h:99
BV_ISSET
#define BV_ISSET(bv, bit)
Definition bitvector.h:78
BV_CLR
#define BV_CLR(bv, bit)
Definition bitvector.h:86
can_city_build_improvement_now
bool can_city_build_improvement_now(const struct city *pcity, const struct impr_type *pimprove)
Definition city.c:853
can_city_build_unit_now
bool can_city_build_unit_now(const struct city *pcity, const struct unit_type *punittype)
Definition city.c:945
city_list_iterate
#define city_list_iterate(citylist, pcity)
Definition city.h:508
city_tile
#define city_tile(_pcity_)
Definition city.h:564
city_owner
#define city_owner(_pcity_)
Definition city.h:563
city_list_iterate_end
#define city_list_iterate_end
Definition city.h:510
send_city_info
void send_city_info(struct player *dest, struct city *pcity)
Definition citytools.c:2344
city_refresh_vision
void city_refresh_vision(struct city *pcity)
Definition citytools.c:3419
citytools.h
remove_obsolete_buildings
void remove_obsolete_buildings(struct player *pplayer)
Definition cityturn.c:269
choose_build_target
void choose_build_target(struct player *pplayer, struct city *pcity)
Definition cityturn.c:2398
city_refresh
bool city_refresh(struct city *pcity)
Definition cityturn.c:158
cityturn.h
incite_cost
char * incite_cost
Definition comments.c:74
connecthand.h
conn_get_player
struct player * conn_get_player(const struct connection *pconn)
Definition connection.c:763
conn_list_iterate
#define conn_list_iterate(connlist, pconn)
Definition connection.h:108
conn_list_iterate_end
#define conn_list_iterate_end
Definition connection.h:110
cost
struct unit struct city struct unit struct tile struct extra_type const struct act_prob *act_probs int actor_unit_id struct unit struct unit int cost
Definition dialogs_g.h:74
effects
struct effect_list * effects[EFT_COUNT]
Definition effects.c:127
govs
struct effect_list * govs[G_LAST]
Definition effects.c:133
get_player_bonus_effects
int get_player_bonus_effects(struct effect_list *plist, const struct player *pplayer, enum effect_type effect_type)
Definition effects.c:1130
get_player_bonus
int get_player_bonus(const struct player *pplayer, enum effect_type effect_type)
Definition effects.c:828
get_effect_list_req_text
void get_effect_list_req_text(const struct effect_list *plist, struct astring *astr)
Definition effects.c:1303
Tech_type_id
int Tech_type_id
Definition fc_types.h:381
MAX_LEN_NAME
#define MAX_LEN_NAME
Definition fc_types.h:66
MAX_NUM_TECH_LIST
#define MAX_NUM_TECH_LIST
Definition fc_types.h:44
O_SCIENCE
@ O_SCIENCE
Definition fc_types.h:101
fcintl.h
Q_
#define Q_(String)
Definition fcintl.h:70
_
#define _(String)
Definition fcintl.h:67
ftc_server
const struct ft_color ftc_server
Definition featured_text.c:77
city_link
const char * city_link(const struct city *pcity)
Definition featured_text.c:1076
game
struct civ_game game
Definition game.c:62
wld
struct world wld
Definition game.c:63
game.h
send_game_info
void send_game_info(struct conn_list *dest)
Definition gamehand.c:910
gamehand.h
government_name_translation
const char * government_name_translation(const struct government *pgovern)
Definition government.c:143
government_count
Government_type_id government_count(void)
Definition government.c:71
government_of_player
struct government * government_of_player(const struct player *pplayer)
Definition government.c:114
can_change_to_government
bool can_change_to_government(struct player *pplayer, const struct government *gov)
Definition government.c:166
government_number
Government_type_id government_number(const struct government *pgovern)
Definition government.c:91
government_index
Government_type_id government_index(const struct government *pgovern)
Definition government.c:82
government.h
governments_iterate
#define governments_iterate(NAME_pgov)
Definition government.h:120
governments_iterate_end
#define governments_iterate_end
Definition government.h:123
handle_player_change_government
void handle_player_change_government(struct player *pplayer, Government_type_id government)
Definition plrhand.c:565
is_great_wonder
bool is_great_wonder(const struct impr_type *pimprove)
Definition improvement.c:772
improvement_name_translation
const char * improvement_name_translation(const struct impr_type *pimprove)
Definition improvement.c:243
city_from_great_wonder
struct city * city_from_great_wonder(const struct impr_type *pimprove)
Definition improvement.c:1016
improvement_iterate_end
#define improvement_iterate_end
Definition improvement.h:205
improvement_iterate
#define improvement_iterate(_p)
Definition improvement.h:199
log.h
fc_assert_msg
#define fc_assert_msg(condition, message,...)
Definition log.h:181
fc_assert_ret
#define fc_assert_ret(condition)
Definition log.h:191
log_verbose
#define log_verbose(message,...)
Definition log.h:109
fc_assert
#define fc_assert(condition)
Definition log.h:176
log_debug
#define log_debug(message,...)
Definition log.h:115
luascript_types.h
whole_map_iterate
#define whole_map_iterate(_map, _tile)
Definition map.h:531
whole_map_iterate_end
#define whole_map_iterate_end
Definition map.h:540
send_tile_info
void send_tile_info(struct conn_list *dest, struct tile *ptile, bool send_unknown)
Definition maphand.c:491
update_player_tile_knowledge
bool update_player_tile_knowledge(struct player *pplayer, struct tile *ptile)
Definition maphand.c:1402
upgrade_all_city_extras
void upgrade_all_city_extras(struct player *pplayer, bool discovery)
Definition maphand.c:276
map_is_known_and_seen
bool map_is_known_and_seen(const struct tile *ptile, const struct player *pplayer, enum vision_layer vlayer)
Definition maphand.c:927
maphand.h
mem.h
fc_malloc
#define fc_malloc(sz)
Definition mem.h:34
movement.h
nation_of_player
struct nation_type * nation_of_player(const struct player *pplayer)
Definition nation.c:444
nation_plural_for_player
const char * nation_plural_for_player(const struct player *pplayer)
Definition nation.c:178
notify_research
void notify_research(const struct research *presearch, const struct player *exclude, enum event_type event, const struct ft_color color, const char *format,...)
Definition notify.c:394
notify_player
void notify_player(const struct player *pplayer, const struct tile *ptile, enum event_type event, const struct ft_color color, const char *format,...)
Definition notify.c:292
notify_research_embassies
void notify_research_embassies(const struct research *presearch, const struct player *exclude, enum event_type event, const struct ft_color color, const char *format,...)
Definition notify.c:434
notify.h
send_packet_unknown_research
int send_packet_unknown_research(struct connection *pc, const struct packet_unknown_research *packet)
Definition packets_gen.c:27687
send_packet_research_info
int send_packet_research_info(struct connection *pc, const struct packet_research_info *packet)
Definition packets_gen.c:27485
player_slot_count
int player_slot_count(void)
Definition player.c:418
player_name
const char * player_name(const struct player *pplayer)
Definition player.c:895
team_has_embassy
bool team_has_embassy(const struct team *pteam, const struct player *tgt_player)
Definition player.c:220
player_index
int player_index(const struct player *pplayer)
Definition player.c:829
player.h
players_iterate_end
#define players_iterate_end
Definition player.h:539
players_iterate
#define players_iterate(_pplayer)
Definition player.h:534
is_ai
#define is_ai(plr)
Definition player.h:232
send_player_all_c
void send_player_all_c(struct player *src, struct conn_list *dest)
Definition plrhand.c:1129
send_player_info_c
void send_player_info_c(struct player *src, struct conn_list *dest)
Definition plrhand.c:1146
plrhand.h
shuffled_players_iterate_end
#define shuffled_players_iterate_end
Definition plrhand.h:108
shuffled_players_iterate
#define shuffled_players_iterate(NAME_pplayer)
Definition plrhand.h:98
rand.h
fc_rand
#define fc_rand(_size)
Definition rand.h:56
requirement_vector_iterate_end
#define requirement_vector_iterate_end
Definition requirements.h:94
requirement_vector_iterate
#define requirement_vector_iterate(req_vec, preq)
Definition requirements.h:92
research_invention_reachable
bool research_invention_reachable(const struct research *presearch, const Tech_type_id tech)
Definition research.c:668
research_invention_set
enum tech_state research_invention_set(struct research *presearch, Tech_type_id tech, enum tech_state value)
Definition research.c:637
research_advance_rule_name
const char * research_advance_rule_name(const struct research *presearch, Tech_type_id tech)
Definition research.c:240
player_tech_upkeep
int player_tech_upkeep(const struct player *pplayer)
Definition research.c:1058
research_count
int research_count(void)
Definition research.c:1336
research_number
int research_number(const struct research *presearch)
Definition research.c:109
research_advance_name_translation
const char * research_advance_name_translation(const struct research *presearch, Tech_type_id tech)
Definition research.c:273
research_total_bulbs_required
int research_total_bulbs_required(const struct research *presearch, Tech_type_id tech, bool loss_value)
Definition research.c:868
research_rule_name
const char * research_rule_name(const struct research *presearch)
Definition research.c:143
research_get
struct research * research_get(const struct player *pplayer)
Definition research.c:128
research_invention_state
enum tech_state research_invention_state(const struct research *presearch, Tech_type_id tech)
Definition research.c:619
research_goal_step
Tech_type_id research_goal_step(const struct research *presearch, Tech_type_id goal)
Definition research.c:720
research_invention_gettable
bool research_invention_gettable(const struct research *presearch, const Tech_type_id tech, bool allow_holes)
Definition research.c:693
research_update
void research_update(struct research *presearch)
Definition research.c:501
research_pretty_name
int research_pretty_name(const struct research *presearch, char *buf, size_t buf_len)
Definition research.c:169
research.h
research_players_iterate
#define research_players_iterate(_presearch, _pplayer)
Definition research.h:166
researches_iterate
#define researches_iterate(_presearch)
Definition research.h:155
research_players_iterate_end
#define research_players_iterate_end
Definition research.h:170
researches_iterate_end
#define researches_iterate_end
Definition research.h:158
script_server_signal_emit
void script_server_signal_emit(const char *signal_name,...)
Definition script_server.c:408
script_server.h
shared.h
MAX
#define MAX(x, y)
Definition shared.h:54
advance
Definition tech.h:124
astring
Definition astring.h:36
city
Definition city.h:320
civ_game::multiresearch
bool multiresearch
Definition game.h:163
civ_game::techlost_recv
int techlost_recv
Definition game.h:194
civ_game::est_connections
struct conn_list * est_connections
Definition game.h:97
civ_game::global_init_techs
int global_init_techs[MAX_NUM_TECH_LIST]
Definition game.h:108
civ_game::info
struct packet_game_info info
Definition game.h:89
civ_game::conquercost
int conquercost
Definition game.h:136
civ_game::techloss_restore
int techloss_restore
Definition game.h:192
civ_game::freecost
int freecost
Definition game.h:148
civ_game::server
struct civ_game::@31::@35 server
civ_game::rgame
struct civ_game::@30 rgame
civ_game::techlost_donor
int techlost_donor
Definition game.h:193
civ_game::techpenalty
int techpenalty
Definition game.h:196
cur_govs_data
Definition techtools.h:23
cur_govs_data::govs
bool * govs
Definition techtools.h:25
cur_govs_data::players
struct cur_govs_data::@123 * players
government
Definition government.h:52
nation_type
Definition nation.h:98
nation_type::init_techs
int init_techs[MAX_NUM_TECH_LIST]
Definition nation.h:122
packet_game_info::tech_steal_allow_holes
bool tech_steal_allow_holes
Definition packets_gen.h:217
packet_game_info::techloss_forgiveness
int techloss_forgiveness
Definition packets_gen.h:236
packet_game_info::tech_trade_loss_allow_holes
bool tech_trade_loss_allow_holes
Definition packets_gen.h:219
packet_game_info::free_tech_method
enum free_tech_method free_tech_method
Definition packets_gen.h:237
packet_game_info::global_advances
bool global_advances[A_LAST]
Definition packets_gen.h:168
packet_game_info::tech_loss_allow_holes
bool tech_loss_allow_holes
Definition packets_gen.h:221
packet_game_info::tech_parasite_allow_holes
bool tech_parasite_allow_holes
Definition packets_gen.h:220
packet_research_info
Definition packets_gen.h:611
packet_research_info::tech_goal
int tech_goal
Definition packets_gen.h:618
packet_research_info::researching
int researching
Definition packets_gen.h:615
packet_research_info::inventions
char inventions[A_LAST+1]
Definition packets_gen.h:620
packet_research_info::techs_researched
int techs_researched
Definition packets_gen.h:613
packet_research_info::id
int id
Definition packets_gen.h:612
packet_research_info::future_tech
int future_tech
Definition packets_gen.h:614
packet_research_info::bulbs_researched
int bulbs_researched
Definition packets_gen.h:617
packet_research_info::researching_cost
int researching_cost
Definition packets_gen.h:616
packet_research_info::total_bulbs_prod
int total_bulbs_prod
Definition packets_gen.h:619
packet_unknown_research
Definition packets_gen.h:623
player
Definition player.h:249
player::bulbs_last_turn
int bulbs_last_turn
Definition player.h:351
player::team
struct team * team
Definition player.h:261
player::is_alive
bool is_alive
Definition player.h:268
player::server
struct player::@70::@72 server
research::research_invention::bulbs_researched_saved
int bulbs_researched_saved
Definition research.h:78
research::research_invention::state
enum tech_state state
Definition research.h:71
research
Definition research.h:39
research::researching
Tech_type_id researching
Definition research.h:52
research::future_tech
int future_tech
Definition research.h:42
research::tech_goal
Tech_type_id tech_goal
Definition research.h:83
research::bulbs_researching_saved
int bulbs_researching_saved
Definition research.h:63
research::inventions
struct research::research_invention inventions[A_ARRAY_SIZE]
research::researching_saved
Tech_type_id researching_saved
Definition research.h:62
research::techs_researched
int techs_researched
Definition research.h:42
research::bulbs_researched
int bulbs_researched
Definition research.h:53
research::free_bulbs
int free_bulbs
Definition research.h:67
world::map
struct civ_map map
Definition world_object.h:38
fc_snprintf
int fc_snprintf(char *str, size_t n, const char *format,...)
Definition support.c:960
support.h
TRUE
#define TRUE
Definition support.h:46
FALSE
#define FALSE
Definition support.h:47
advance_by_number
struct advance * advance_by_number(const Tech_type_id atype)
Definition tech.c:107
is_future_tech
bool is_future_tech(Tech_type_id tech)
Definition tech.c:281
advance_has_flag
bool advance_has_flag(Tech_type_id tech, enum tech_flag_id flag)
Definition tech.c:216
valid_advance_by_number
struct advance * valid_advance_by_number(const Tech_type_id id)
Definition tech.c:176
advance_required
Tech_type_id advance_required(const Tech_type_id tech, enum tech_req require)
Definition tech.c:121
advance_rule_name
const char * advance_rule_name(const struct advance *padvance)
Definition tech.c:309
tech.h
A_FUTURE
#define A_FUTURE
Definition tech.h:46
advance_index_iterate_max
#define advance_index_iterate_max(_start, _index, _max)
Definition tech.h:253
advance_index_iterate_end
#define advance_index_iterate_end
Definition tech.h:249
AR_TWO
@ AR_TWO
Definition tech.h:112
AR_ROOT
@ AR_ROOT
Definition tech.h:113
AR_ONE
@ AR_ONE
Definition tech.h:111
advance_index_iterate_max_end
#define advance_index_iterate_max_end
Definition tech.h:259
advance_count
static Tech_type_id advance_count(void)
Definition tech.h:170
A_FIRST
#define A_FIRST
Definition tech.h:44
A_NONE
#define A_NONE
Definition tech.h:43
A_UNSET
#define A_UNSET
Definition tech.h:48
A_UNKNOWN
#define A_UNKNOWN
Definition tech.h:49
A_LAST
#define A_LAST
Definition tech.h:45
advance_index_iterate
#define advance_index_iterate(_start, _index)
Definition tech.h:245
pick_cheapest_tech
static Tech_type_id pick_cheapest_tech(const struct research *presearch)
Definition techtools.c:957
handle_player_tech_goal
void handle_player_tech_goal(struct player *pplayer, int tech_goal)
Definition techtools.c:1361
init_tech
void init_tech(struct research *research, bool update)
Definition techtools.c:1093
pick_random_government
static struct government * pick_random_government(struct player *pplayer)
Definition techtools.c:804
found_new_tech
void found_new_tech(struct research *presearch, Tech_type_id tech_found, bool was_discovery, bool saving_bulbs)
Definition techtools.c:347
free_current_governments_data
void free_current_governments_data(struct cur_govs_data *data)
Definition techtools.c:1537
lose_tech
static bool lose_tech(struct research *research)
Definition techtools.c:616
choose_tech_goal
void choose_tech_goal(struct research *presearch, Tech_type_id tech)
Definition techtools.c:1074
research_apply_penalty
void research_apply_penalty(struct research *presearch, Tech_type_id tech, int penalty_percent)
Definition techtools.c:67
tech_researched
static void tech_researched(struct research *research)
Definition techtools.c:107
choose_tech
void choose_tech(struct research *research, Tech_type_id tech)
Definition techtools.c:1004
pick_random_tech_to_lose
static Tech_type_id pick_random_tech_to_lose(const struct research *presearch)
Definition techtools.c:733
package_research_info
static void package_research_info(struct packet_research_info *packet, const struct research *presearch)
Definition techtools.c:258
forget_tech_transferred
static void forget_tech_transferred(struct player *pplayer, Tech_type_id tech)
Definition techtools.c:1415
steal_a_tech
Tech_type_id steal_a_tech(struct player *pplayer, struct player *victim, Tech_type_id preferred)
Definition techtools.c:1233
notify_new_government_options
void notify_new_government_options(struct player *pplayer, struct cur_govs_data *data, const char *reason)
Definition techtools.c:1551
handle_player_research
void handle_player_research(struct player *pplayer, int tech)
Definition techtools.c:1338
pick_free_tech
Tech_type_id pick_free_tech(struct research *presearch)
Definition techtools.c:1387
give_immediate_free_tech
void give_immediate_free_tech(struct research *presearch, Tech_type_id tech)
Definition techtools.c:1406
create_current_governments_data
struct cur_govs_data * create_current_governments_data(struct research *presearch)
Definition techtools.c:1489
send_research_info
void send_research_info(const struct research *presearch, const struct conn_list *dest)
Definition techtools.c:293
choose_random_tech
void choose_random_tech(struct research *research)
Definition techtools.c:989
create_current_governments_data_all
struct cur_govs_data * create_current_governments_data_all(void)
Definition techtools.c:1517
research_tech_lost
static void research_tech_lost(struct research *presearch, Tech_type_id tech)
Definition techtools.c:821
script_tech_learned
void script_tech_learned(struct research *presearch, struct player *originating_plr, struct advance *tech, const char *reason)
Definition techtools.c:84
give_initial_techs
void give_initial_techs(struct research *presearch, int num_random_techs)
Definition techtools.c:1187
tech_transfer
bool tech_transfer(struct player *plr_recv, struct player *plr_donor, Tech_type_id tech)
Definition techtools.c:1437
pick_random_tech
static Tech_type_id pick_random_tech(const struct research *presearch)
Definition techtools.c:938
do_tech_parasite_effects
void do_tech_parasite_effects(struct player *pplayer)
Definition techtools.c:143
update_bulbs
void update_bulbs(struct player *pplayer, int bulbs, bool check_tech, bool free_bulbs)
Definition techtools.c:654
techtools.h
unit.h
unit_activities_cancel_all_illegal_plr
void unit_activities_cancel_all_illegal_plr(const struct player *pplayer)
Definition unittools.c:818
unit_list_refresh_vision
void unit_list_refresh_vision(struct unit_list *punitlist)
Definition unittools.c:5011
unittools.h
utype_name_translation
const char * utype_name_translation(const struct unit_type *punittype)
Definition unittype.c:1560