Fix division by zero when unit activity rate is zero
[freeciv.git] / server / techtools.c
blob31f01173402b8d86583486a4686a17d911b9d113
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.
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
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"
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"
35 /* common/scriptcore */
36 #include "luascript_types.h"
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"
48 /* server/scripting */
49 #include "script_server.h"
51 #include "techtools.h"
53 /* Define this to add information about tech upkeep. */
54 #undef TECH_UPKEEP_DEBUGGING
56 static Tech_type_id
57 pick_random_tech_to_lose(const struct research *presearch);
58 static void research_tech_lost(struct research *presearch,
59 Tech_type_id tech);
60 static void forget_tech_transfered(struct player *pplayer, Tech_type_id tech);
62 /****************************************************************************
63 Apply a penalty to the research.
64 ****************************************************************************/
65 void research_apply_penalty(struct research *presearch, Tech_type_id tech,
66 int penalty_percent)
68 presearch->bulbs_researched -=
69 (research_total_bulbs_required(presearch, tech, FALSE)
70 * penalty_percent) / 100;
71 presearch->researching_saved = A_UNKNOWN;
74 /****************************************************************************
75 Emit script signal(s) for player/team learning new tech.
76 originating_plr is the player whose action caused this; may be NULL, and
77 is only used to order the emission of the signals.
78 ****************************************************************************/
79 void script_tech_learned(struct research *presearch,
80 struct player *originating_plr, struct advance *tech,
81 const char *reason)
83 /* Emit signal for individual player whose action triggered the
84 * tech first */
85 if (originating_plr) {
86 fc_assert(research_get(originating_plr) == presearch);
87 script_server_signal_emit("tech_researched", 3,
88 API_TYPE_TECH_TYPE, tech,
89 API_TYPE_PLAYER, originating_plr,
90 API_TYPE_STRING, reason);
93 /* Emit signal to remaining research teammates, if any */
94 research_players_iterate(presearch, member) {
95 if (member != originating_plr) {
96 script_server_signal_emit("tech_researched", 3,
97 API_TYPE_TECH_TYPE, tech,
98 API_TYPE_PLAYER, member,
99 API_TYPE_STRING, reason);
101 } research_players_iterate_end;
104 /****************************************************************************
105 Players have researched a new technology.
106 ****************************************************************************/
107 static void tech_researched(struct research *research)
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;
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));
122 /* Deduct tech cost. */
123 research->bulbs_researched -= research_total_bulbs_required(research, tech,
124 FALSE);
126 /* Do all the updates needed after finding new tech. */
127 found_new_tech(research, tech, TRUE, TRUE);
129 script_tech_learned(research, NULL, advance_by_number(tech), "researched");
132 /****************************************************************************
133 Give technologies to players with EFT_TECH_PARASITE (traditionally from
134 the Great Library).
135 ****************************************************************************/
136 void do_tech_parasite_effect(struct player *pplayer)
138 struct effect_list *plist = effect_list_new();
139 struct astring effects;
140 struct research *presearch;
141 char research_name[MAX_LEN_NAME * 2];
142 const char *advance_name;
143 Tech_type_id tech;
144 /* Note that two EFT_TECH_PARASITE effects will combine into a single,
145 * much worse effect. */
146 int mod = get_player_bonus_effects(plist, pplayer, EFT_TECH_PARASITE);
147 int num_players;
148 int num_techs;
150 if (mod <= 0) {
151 /* No effect. */
152 effect_list_destroy(plist);
153 return;
156 /* Pick a random technology. */
157 tech = A_UNSET;
158 num_techs = 0;
159 presearch = research_get(pplayer);
160 advance_index_iterate(A_FIRST, i) {
161 if (!research_invention_gettable(presearch, i,
162 game.info.tech_parasite_allow_holes)
163 || TECH_KNOWN == research_invention_state(presearch, i)) {
164 continue;
167 num_players = 0;
168 players_iterate(aplayer) {
169 if (TECH_KNOWN == research_invention_state(research_get(aplayer), i)) {
170 if (mod <= ++num_players) {
171 if (0 == fc_rand(++num_techs)) {
172 tech = i;
174 break;
177 } players_iterate_end;
178 } advance_index_iterate_end;
180 if (A_UNSET == tech) {
181 /* No tech found. */
182 effect_list_destroy(plist);
183 return;
186 /* Notify. */
187 research_pretty_name(presearch, research_name, sizeof(research_name));
188 advance_name = research_advance_name_translation(presearch, tech);
189 astr_init(&effects);
190 get_effect_list_req_text(plist, &effects);
192 notify_player(pplayer, NULL, E_TECH_GAIN, ftc_server,
193 /* TRANS: Tech from source of an effect
194 * (Great Library) */
195 Q_("?fromeffect:%s acquired from %s!"),
196 advance_name,
197 astr_str(&effects));
198 notify_research(presearch, pplayer, E_TECH_GAIN, ftc_server,
199 /* TRANS: Tech from source of an effect
200 * (Great Library) */
201 Q_("?fromeffect:%s acquired from %s's %s!"),
202 advance_name,
203 player_name(pplayer),
204 astr_str(&effects));
205 notify_research_embassies(presearch, NULL, E_TECH_EMBASSY, ftc_server,
206 /* TRANS: Tech from source of an effect
207 * (Great Library) */
208 Q_("?fromeffect:The %s have acquired %s from %s."),
209 research_name,
210 advance_name,
211 astr_str(&effects));
213 effect_list_destroy(plist);
214 astr_free(&effects);
216 /* Really get tech. */
217 research_apply_penalty(presearch, tech, game.server.freecost);
218 found_new_tech(presearch, tech, FALSE, TRUE);
220 research_players_iterate(presearch, member) {
221 script_server_signal_emit("tech_researched", 3,
222 API_TYPE_TECH_TYPE, advance_by_number(tech),
223 API_TYPE_PLAYER, member,
224 API_TYPE_STRING, "stolen");
225 } research_players_iterate_end;
228 /****************************************************************************
229 Fill packet fields. Helper for following functions.
230 ****************************************************************************/
231 static inline void
232 package_research_info(struct packet_research_info *packet,
233 const struct research *presearch)
235 packet->id = research_number(presearch);
236 packet->techs_researched = presearch->techs_researched;
237 packet->future_tech = presearch->future_tech;
238 packet->researching = presearch->researching;
239 packet->researching_cost =
240 (packet->researching != A_UNSET
241 ? research_total_bulbs_required(presearch, presearch->researching,
242 FALSE) : 0);
243 packet->bulbs_researched = presearch->bulbs_researched;
244 packet->tech_goal = presearch->tech_goal;
245 packet->total_bulbs_prod = 0;
246 research_players_iterate(presearch, pplayer) {
247 city_list_iterate(pplayer->cities, pcity) {
248 packet->total_bulbs_prod += pcity->surplus[O_SCIENCE];
249 } city_list_iterate_end;
250 } research_players_iterate_end;
251 advance_index_iterate(A_NONE, i) {
252 packet->inventions[i] = presearch->inventions[i].state + '0';
253 } advance_index_iterate_end;
254 packet->inventions[advance_count()] = '\0';
255 packet->tech_goal = presearch->tech_goal;
256 #ifdef DEBUG
257 log_verbose("Research nb %d inventions: %s",
258 research_number(presearch),
259 packet->inventions);
260 #endif
263 /****************************************************************************
264 Send research info for 'presearch' to 'dest'. 'dest' can be NULL to send
265 to all established connections.
266 ****************************************************************************/
267 void send_research_info(const struct research *presearch,
268 const struct conn_list *dest)
270 struct packet_research_info full_info, restricted_info;
271 const struct player *pplayer;
273 fc_assert_ret(NULL != presearch);
274 if (NULL == dest) {
275 dest = game.est_connections;
278 /* Packaging */
279 package_research_info(&full_info, presearch);
280 restricted_info = full_info;
281 restricted_info.tech_goal = A_UNSET;
282 restricted_info.total_bulbs_prod = 0;
284 conn_list_iterate(dest, pconn) {
285 pplayer = conn_get_player(pconn);
286 if (NULL != pplayer) {
287 if (presearch == research_get(pplayer)) {
288 /* Case research owner. */
289 send_packet_research_info(pconn, &full_info);
290 } else {
291 /* 'pplayer' may have an embassy for looking to 'presearch'. */
292 research_players_iterate(presearch, powner) {
293 if (player_has_embassy(pplayer, powner)) {
294 send_packet_research_info(pconn, &restricted_info);
295 break;
297 } research_players_iterate_end;
299 } else if (pconn->observer) {
300 /* Case global observer. */
301 send_packet_research_info(pconn, &full_info);
303 } conn_list_iterate_end;
306 /****************************************************************************
307 Players sharing the research have got a new technology (from somewhere).
308 'was_discovery' is passed on to upgrade_city_extras. Logging and
309 notification is not done here as it depends on how the tech came.
310 ****************************************************************************/
311 void found_new_tech(struct research *presearch, Tech_type_id tech_found,
312 bool was_discovery, bool saving_bulbs)
314 int had_embassies[player_slot_count()];
315 bool could_switch[player_slot_count()][government_count()];
316 bool was_first = FALSE;
317 bool bonus_tech_hack = FALSE;
318 int i;
319 const char *advance_name;
320 struct advance *vap = valid_advance_by_number(tech_found);
321 struct city *pcity;
323 if (!is_future_tech(tech_found)) {
325 #ifndef FREECIV_NDEBUG
326 fc_assert(NULL != vap);
327 fc_assert(TECH_KNOWN != research_invention_state(presearch, tech_found));
328 #endif /* FREECIV_NDEBUG */
330 was_first = (!game.info.global_advances[tech_found]);
333 /* Assign 'advance_name' before we increase the future tech counter. */
334 advance_name = research_advance_name_translation(presearch, tech_found);
336 if (was_first && vap) {
337 /* Alert the owners of any wonders that have been made obsolete */
338 improvement_iterate(pimprove) {
339 requirement_vector_iterate(&pimprove->obsolete_by, pobs) {
340 if (pobs->source.kind == VUT_ADVANCE
341 && pobs->source.value.advance == vap
342 && pobs->range >= REQ_RANGE_WORLD
343 && pobs->survives
344 && is_great_wonder(pimprove)
345 && (pcity = city_from_great_wonder(pimprove))) {
346 notify_player(city_owner(pcity), NULL, E_WONDER_OBSOLETE, ftc_server,
347 _("Discovery of %s OBSOLETES %s in %s!"),
348 research_advance_name_translation
349 (research_get(city_owner(pcity)), tech_found),
350 improvement_name_translation(pimprove),
351 city_link(pcity));
353 } requirement_vector_iterate_end;
354 } improvement_iterate_end;
357 if (was_first
358 && !is_future_tech(tech_found)
359 && advance_has_flag(tech_found, TF_BONUS_TECH)) {
360 bonus_tech_hack = TRUE;
363 /* Memorize some values before the tech is marked as researched.
364 * We will check what has changed later. */
365 players_iterate(aplayer) {
366 i = player_index(aplayer);
368 /* Count EFT_HAVE_EMBASSIES effect for each player. */
369 had_embassies[i] = get_player_bonus(aplayer, EFT_HAVE_EMBASSIES);
371 if (presearch != research_get(aplayer)) {
372 continue;
375 /* Memorize for the players sharing the research what government
376 * they could switch on. */
377 governments_iterate(pgov) {
378 could_switch[i][government_index(pgov)]
379 = can_change_to_government(aplayer, pgov);
380 } governments_iterate_end;
381 } players_iterate_end;
383 /* got_tech allows us to change research without applying techpenalty
384 * (without losing bulbs) */
385 if (tech_found == presearch->researching) {
386 presearch->got_tech = TRUE;
388 presearch->researching_saved = A_UNKNOWN;
389 presearch->techs_researched++;
391 /* Mark the tech as known in the research struct and update
392 * global_advances array. */
393 if (is_future_tech(tech_found)) {
394 presearch->future_tech++;
395 } else {
396 research_invention_set(presearch, tech_found, TECH_KNOWN);
397 research_update(presearch);
400 /* Inform players about their new tech. */
401 send_research_info(presearch, NULL);
403 if (was_first) {
404 /* Inform all players about new global advances to give them a
405 * chance for obsolete buildings. */
406 send_game_info(NULL);
409 /* Make proper changes for all players. Use shuffled order, in case
410 * a script would detect a signal. */
411 shuffled_players_iterate(aplayer) {
412 i = player_index(aplayer);
414 if (presearch == research_get(aplayer)) {
415 /* Only for players sharing the research. */
416 remove_obsolete_buildings(aplayer);
418 /* Give free infrastructure in every city */
419 if (tech_found != A_FUTURE) {
420 upgrade_all_city_extras(aplayer, was_discovery);
423 /* Enhance vision of units if a player-ranged effect has changed. Note
424 * that world-ranged effects will not be updated immediately. */
425 unit_list_refresh_vision(aplayer->units);
427 /* Notify a player about new governments available */
428 governments_iterate(pgov) {
429 if (!could_switch[i][government_index(pgov)]
430 && can_change_to_government(aplayer, pgov)) {
431 notify_player(aplayer, NULL, E_NEW_GOVERNMENT, ftc_server,
432 _("Discovery of %s makes the government form %s"
433 " available. You may want to start a revolution."),
434 advance_name,
435 government_name_translation(pgov));
437 } governments_iterate_end;
440 /* For any player. */
441 /* Update all cities in case the tech changed some effects. This is
442 * inefficient; it could be optimized if it's found to be a problem.
443 * But techs aren't researched that often. */
444 city_list_iterate(aplayer->cities, apcity) {
445 /* Refresh the city data; this also updates the squared city radius. */
446 city_refresh(apcity);
447 city_refresh_vision(apcity);
448 send_city_info(aplayer, apcity);
449 } city_list_iterate_end;
451 /* Send all player an updated info of the owner of the Marco Polo
452 * Wonder if this wonder has become obsolete. */
453 if (0 < had_embassies[i]
454 && 0 <= get_player_bonus(aplayer, EFT_HAVE_EMBASSIES)) {
455 send_player_all_c(aplayer, aplayer->connections);
456 players_iterate(pother_player) {
457 if (aplayer != pother_player) {
458 send_player_all_c(aplayer, pother_player->connections);
459 send_player_all_c(pother_player, aplayer->connections);
461 } players_iterate_end;
463 } shuffled_players_iterate_end;
465 if (tech_found == presearch->tech_goal) {
466 presearch->tech_goal = A_UNSET;
469 if (tech_found == presearch->researching) {
470 /* Try to pick new tech to research. */
471 Tech_type_id next_tech = research_goal_step(presearch,
472 presearch->tech_goal);
474 /* As this function can be recursive, we need to print the messages
475 * before really picking the new technology. */
476 if (A_UNSET != next_tech) {
477 notify_research(presearch, NULL, E_TECH_LEARNED, ftc_server,
478 _("Learned %s. Our scientists focus on %s; "
479 "goal is %s."),
480 advance_name,
481 research_advance_name_translation(presearch,
482 next_tech),
483 research_advance_name_translation
484 (presearch, presearch->tech_goal));
485 } else {
486 if (is_future_tech(tech_found)) {
487 /* Continue researching future tech. */
488 next_tech = A_FUTURE;
489 } else {
490 /* If there is at least one AI player still alive, then pick
491 * a random tech, else keep A_UNSET. */
492 research_players_iterate(presearch, aplayer) {
493 if (aplayer->ai_controlled) {
494 next_tech = pick_random_tech(presearch);
495 break;
497 } research_players_iterate_end;
500 if (A_UNSET == next_tech) {
501 notify_research(presearch, NULL, E_TECH_LEARNED, ftc_server,
502 _("Learned %s. Scientists "
503 "do not know what to research next."),
504 advance_name);
505 } else {
506 notify_research(presearch, NULL, E_TECH_LEARNED, ftc_server,
507 _("Learned %s. Scientists choose to research %s."),
508 advance_name,
509 research_advance_name_translation(presearch,
510 next_tech));
514 if (A_UNSET != next_tech) {
515 choose_tech(presearch, next_tech);
516 } else {
517 presearch->researching = A_UNSET;
521 if (!saving_bulbs && presearch->bulbs_researched > 0) {
522 presearch->bulbs_researched = 0;
525 if (bonus_tech_hack) {
526 Tech_type_id additional_tech;
527 char research_name[MAX_LEN_NAME * 2];
528 const char *radv_name;
530 research_pretty_name(presearch, research_name, sizeof(research_name));
532 additional_tech = give_immediate_free_tech(presearch);
534 radv_name = research_advance_name_translation(presearch, additional_tech);
536 if (advance_by_number(tech_found)->bonus_message != NULL
537 && additional_tech != A_UNSET) {
538 notify_research(presearch, NULL, E_TECH_GAIN, ftc_server,
539 _(advance_by_number(tech_found)->bonus_message),
540 radv_name);
541 } else if (additional_tech != A_UNSET) {
542 /* FIXME: "your" when it was just civilization of one of the players
543 * sharing the reseach. */
544 notify_research(presearch, NULL, E_TECH_GAIN, ftc_server,
545 _("Great scientists from all the "
546 "world join your civilization: you learn "
547 "%s immediately."), radv_name);
549 /* TODO: Ruleset should be able to customize this message too */
550 notify_research_embassies(presearch, NULL, E_TECH_EMBASSY, ftc_server,
551 _("%s acquire %s as a result of learning %s."),
552 research_name, radv_name, advance_name);
556 /****************************************************************************
557 Is player about to lose tech?
558 ****************************************************************************/
559 static bool lose_tech(struct research *research)
561 if (game.server.techloss_forgiveness < 0) {
562 /* Tech loss disabled */
563 return FALSE;
566 if (research->techs_researched == 0) {
567 /* No tech to lose */
568 fc_assert(research->future_tech == 0);
569 return FALSE;
572 if (research->bulbs_researched <
573 (-research_total_bulbs_required(research, research->researching, FALSE)
574 * game.server.techloss_forgiveness / 100)) {
575 return TRUE;
578 return FALSE;
581 /****************************************************************************
582 Adds the given number of bulbs into the player's tech and (if necessary and
583 'check_tech' is TRUE) completes the research. If the total number of bulbs
584 is negative due to tech upkeep, one (randomly chosen) tech is lost.
586 The caller is responsible for sending updated player information.
588 This is called from each city every turn, from caravan revenue, and at the
589 end of the phase.
590 ****************************************************************************/
591 void update_bulbs(struct player *pplayer, int bulbs, bool check_tech)
593 struct research *research = research_get(pplayer);
595 if (!pplayer->is_alive) {
596 /* Dead players do not produce research */
597 return;
600 /* count our research contribution this turn */
601 pplayer->server.bulbs_last_turn += bulbs;
602 research->bulbs_researched += bulbs;
604 do {
605 /* If we have a negative number of bulbs we do try to:
606 * - reduce the number of future techs;
607 * - or lose one random tech.
608 * After that the number of bulbs available is incresed based on the
609 * value of the lost tech. */
610 if (lose_tech(research)) {
611 Tech_type_id tech = (research->future_tech > 0
612 ? A_FUTURE : pick_random_tech_to_lose(research));
614 if (tech != A_NONE) {
615 if (game.server.techloss_restore >= 0) {
616 research->bulbs_researched +=
617 (research_total_bulbs_required(research, tech, TRUE)
618 * game.server.techloss_restore / 100);
619 } else {
620 research->bulbs_researched = 0;
622 research->researching_saved = A_UNKNOWN;
624 log_debug("%s: tech loss (%s)",
625 research_rule_name(research),
626 (is_future_tech(tech) ? "Future Tech"
627 : research_advance_rule_name(research, tech)));
628 research_tech_lost(research, tech);
629 /* Make notification after losing the research, in case it is
630 * a future tech (for getting the right tech number). */
631 notify_research(research, NULL, E_TECH_LOST, ftc_server,
632 _("Insufficient science output. We lost %s."),
633 research_advance_name_translation(research, tech));
637 /* Check for finished research. */
638 if (!check_tech
639 || research->researching == A_UNSET
640 || (research->bulbs_researched
641 < research_total_bulbs_required(research, research->researching,
642 FALSE))) {
643 break;
646 tech_researched(research);
647 } while (research->researching != A_UNSET);
650 /****************************************************************************
651 Choose a random tech for player to lose.
652 ****************************************************************************/
653 static Tech_type_id
654 pick_random_tech_to_lose(const struct research *presearch)
656 bv_techs eligible_techs;
657 /* A_NONE included in advance_count(). */
658 int eligible = advance_count() - 1;
659 int chosen;
661 BV_SET_ALL(eligible_techs);
663 advance_index_iterate(A_FIRST, i) {
664 if (research_invention_state(presearch, i) != TECH_KNOWN) {
665 if (BV_ISSET(eligible_techs, i)) {
666 eligible--;
667 BV_CLR(eligible_techs, i);
669 } else {
670 /* Knowing this tech may make others ineligible */
671 Tech_type_id root = advance_required(i, AR_ROOT);
672 /* Never lose techs that are root_req for a currently known tech
673 * (including self root_req) */
674 if (root != A_NONE && BV_ISSET(eligible_techs, root)) {
675 eligible--;
676 BV_CLR(eligible_techs, root);
678 if (!game.info.tech_loss_allow_holes) {
679 /* Ruleset can prevent this kind of tech loss from opening up
680 * holes in the tech tree */
681 Tech_type_id prereq;
682 prereq = advance_required(i, AR_ONE);
683 if (prereq != A_NONE && BV_ISSET(eligible_techs, prereq)) {
684 eligible--;
685 BV_CLR(eligible_techs, prereq);
687 prereq = advance_required(i, AR_TWO);
688 if (prereq != A_NONE && BV_ISSET(eligible_techs, prereq)) {
689 eligible--;
690 BV_CLR(eligible_techs, prereq);
694 } advance_index_iterate_end;
696 if (eligible == 0) {
697 /* no researched technology at all */
698 return A_NONE;
701 chosen = fc_rand(eligible) + 1;
703 advance_index_iterate(A_FIRST, i) {
704 if (BV_ISSET(eligible_techs, i)) {
705 chosen--;
706 if (chosen == 0) {
707 return i;
710 } advance_index_iterate_end;
712 /* should never be reached */
713 fc_assert_msg(chosen == 0, "internal error (eligible=%d, chosen=%d)",
714 eligible, chosen);
715 return A_NONE;
718 /****************************************************************************
719 Helper for research_tech_lost().
720 ****************************************************************************/
721 static inline struct government *
722 pick_random_government(struct player *pplayer)
724 struct government *picked = NULL;
725 int gov_nb = 0;
727 governments_iterate(pgov) {
728 if (can_change_to_government(pplayer, pgov) && 0 == fc_rand(++gov_nb)) {
729 picked = pgov;
731 } governments_iterate_end;
732 fc_assert(NULL != picked);
733 return picked;
736 /****************************************************************************
737 Remove one tech from the research.
738 ****************************************************************************/
739 static void research_tech_lost(struct research *presearch, Tech_type_id tech)
741 char research_name[MAX_LEN_NAME * 2];
742 /* Research members will be notified when new tech is chosen. */
744 research_pretty_name(presearch, research_name, sizeof(research_name));
746 presearch->techs_researched--;
747 if (is_future_tech(tech)) {
748 presearch->future_tech--;
749 research_update(presearch);
750 /* Notify after decreasing the future tech counter, to get the right
751 * tech number in the message. */
752 notify_research_embassies(presearch, NULL, E_TECH_EMBASSY, ftc_server,
753 _("The %s have lost %s."),
754 research_name,
755 research_advance_name_translation(presearch,
756 tech));
757 /* Inform players about their technology loss. */
758 send_research_info(presearch, NULL);
759 return;
762 fc_assert_ret(valid_advance_by_number(tech));
763 notify_research_embassies(presearch, NULL, E_TECH_EMBASSY, ftc_server,
764 /* TRANS: technology loss */
765 _("The %s have lost %s."),
766 research_name,
767 research_advance_name_translation(presearch,
768 tech));
770 /* Remove technology. */
771 research_invention_set(presearch, tech, TECH_UNKNOWN);
772 research_update(presearch);
773 log_debug("%s lost tech id %d (%s)", research_rule_name(presearch), tech,
774 advance_rule_name(advance_by_number(tech)));
776 /* Inform players about their technology loss. */
777 send_research_info(presearch, NULL);
779 research_players_iterate(presearch, pplayer) {
780 /* Check government. */
781 if (!can_change_to_government(pplayer, government_of_player(pplayer))) {
782 /* Lost the technology for the government; switch to random
783 * available government. */
784 struct government *pgov = pick_random_government(pplayer);
786 notify_player(pplayer, NULL, E_NEW_GOVERNMENT, ftc_server,
787 _("The required technology for our government '%s' "
788 "was lost. The citizens have started a "
789 "revolution into '%s'."),
790 government_name_translation(government_of_player
791 (pplayer)),
792 government_name_translation(pgov));
793 handle_player_change_government(pplayer, government_number(pgov));
794 send_player_info_c(pplayer, NULL);
795 } else if (NULL != pplayer->target_government
796 && !can_change_to_government(pplayer,
797 pplayer->target_government)) {
798 /* Lost the technology for the target government; use a random
799 * available government as new target government. */
800 struct government *pgov = pick_random_government(pplayer);
802 notify_player(pplayer, NULL, E_NEW_GOVERNMENT, ftc_server,
803 _("The required technology for our new government "
804 "'%s' was lost. The citizens chose '%s' as new "
805 "target government."),
806 government_name_translation(pplayer->target_government),
807 government_name_translation(pgov));
808 pplayer->target_government = pgov;
809 send_player_info_c(pplayer, pplayer->connections);
812 /* Check all units for valid activities. */
813 unit_list_iterate(pplayer->units, punit) {
814 if (!can_unit_continue_current_activity(punit)) {
815 log_debug("lost technology for activity of unit %s of %s (%d, %d)",
816 unit_name_translation(punit), player_name(pplayer),
817 TILE_XY(unit_tile(punit)));
818 set_unit_activity(punit, ACTIVITY_IDLE);
819 send_unit_info(NULL, punit);
821 } unit_list_iterate_end;
823 /* Check city production */
824 city_list_iterate(pplayer->cities, pcity) {
825 bool update = FALSE;
827 if (pcity->production.kind == VUT_UTYPE
828 && !can_city_build_unit_now(pcity, pcity->production.value.utype)) {
829 notify_player(pplayer, city_tile(pcity),
830 E_CITY_CANTBUILD, ftc_server,
831 _("%s can't build %s. The required technology was "
832 "lost."),
833 city_link(pcity),
834 utype_name_translation(pcity->production.value.utype));
835 choose_build_target(pplayer, pcity);
836 update = TRUE;
839 if (pcity->production.kind == VUT_IMPROVEMENT
840 && !can_city_build_improvement_now(pcity,
841 pcity->production.value.building)) {
842 notify_player(pplayer, city_tile(pcity),
843 E_CITY_CANTBUILD, ftc_server,
844 _("%s can't build %s. The required technology was "
845 "lost."),
846 city_link(pcity),
847 improvement_name_translation
848 (pcity->production.value.building));
849 choose_build_target(pplayer, pcity);
850 update = TRUE;
853 if (update) {
854 city_refresh(pcity);
855 send_city_info(pplayer, pcity);
857 } city_list_iterate_end;
858 } research_players_iterate_end;
861 /****************************************************************************
862 Returns random researchable tech or A_FUTURE. No side effects.
863 ****************************************************************************/
864 Tech_type_id pick_random_tech(const struct research *presearch)
866 Tech_type_id tech = A_FUTURE;
867 int num_techs = 0;
869 advance_index_iterate(A_FIRST, i) {
870 if (research_invention_state(presearch, i) == TECH_PREREQS_KNOWN) {
871 if (fc_rand(++num_techs) == 0) {
872 tech = i;
875 } advance_index_iterate_end;
876 return tech;
879 /****************************************************************************
880 Returns cheapest researchable tech, random among equal cost ones.
881 ****************************************************************************/
882 Tech_type_id pick_cheapest_tech(const struct research *presearch)
884 int cheapest_cost = -1;
885 int cheapest_amount = 0;
886 Tech_type_id cheapest = A_FUTURE; /* If no real tech is found to be missing */
888 advance_index_iterate(A_FIRST, i) {
889 if (research_invention_state(presearch, i) == TECH_PREREQS_KNOWN) {
890 int cost = research_total_bulbs_required(presearch, i, FALSE);
892 if (cost < cheapest_cost || cheapest_cost == -1) {
893 cheapest_cost = cost;
894 cheapest_amount = 1;
895 cheapest = i;
896 } else if (cost == cheapest_cost && fc_rand(++cheapest_amount) == 0) {
897 cheapest = i;
900 } advance_index_iterate_end;
902 return cheapest;
905 /****************************************************************************
906 Finds and chooses (sets) a random research target from among all those
907 available until presearch->researching != A_UNSET.
908 Players may research more than one tech in this function.
909 Possible reasons:
910 - techpenalty < 100;
911 - research.got_tech = TRUE and enough bulbs was saved;
912 - research.researching = A_UNSET and enough bulbs was saved.
913 ****************************************************************************/
914 void choose_random_tech(struct research *research)
916 do {
917 choose_tech(research, pick_random_tech(research));
918 } while (research->researching == A_UNSET);
921 /****************************************************************************
922 Called when a player chooses the tech he wants to research (or when
923 the server chooses it for him automatically).
925 This takes care of all side effects so the research target probably
926 shouldn't be changed outside of this function (doing so has been the
927 cause of several bugs).
928 ****************************************************************************/
929 void choose_tech(struct research *research, Tech_type_id tech)
931 if (is_future_tech(tech)) {
932 if (is_future_tech(research->researching)
933 && (research->bulbs_researched
934 >= research_total_bulbs_required(research, tech, FALSE))) {
935 tech_researched(research);
937 } else {
938 if (research->researching == tech) {
939 return;
941 if (research_invention_state(research, tech) != TECH_PREREQS_KNOWN) {
942 /* Can't research this. */
943 return;
946 if (!research->got_tech && research->researching_saved == A_UNKNOWN) {
947 research->bulbs_researching_saved = research->bulbs_researched;
948 research->researching_saved = research->researching;
949 /* Subtract a penalty because we changed subject. */
950 if (research->bulbs_researched > 0) {
951 research->bulbs_researched
952 -= ((research->bulbs_researched * game.server.techpenalty) / 100);
953 fc_assert(research->bulbs_researched >= 0);
955 } else if (tech == research->researching_saved) {
956 research->bulbs_researched = research->bulbs_researching_saved;
957 research->researching_saved = A_UNKNOWN;
959 research->researching = tech;
960 if (research->bulbs_researched
961 >= research_total_bulbs_required(research, tech, FALSE)) {
962 tech_researched(research);
966 /****************************************************************************
967 Called when a player chooses the tech goal he wants to research (or when
968 the server chooses it for him automatically).
969 ****************************************************************************/
970 void choose_tech_goal(struct research *presearch, Tech_type_id tech)
972 fc_assert_ret(presearch != NULL);
974 if (tech == presearch->tech_goal) {
975 return;
978 /* It's been suggested that if the research target is empty then
979 * choose_random_tech() should be called here. */
980 presearch->tech_goal = tech;
981 notify_research(presearch, NULL, E_TECH_GOAL, ftc_server,
982 _("Technology goal is %s."),
983 research_advance_name_translation(presearch, tech));
986 /****************************************************************************
987 Initializes tech data for the research.
988 ****************************************************************************/
989 void init_tech(struct research *research, bool update)
991 research_invention_set(research, A_NONE, TECH_KNOWN);
993 advance_index_iterate(A_FIRST, i) {
994 research_invention_set(research, i, TECH_UNKNOWN);
995 } advance_index_iterate_end;
997 #ifdef TECH_UPKEEP_DEBUGGING
998 /* Print a list of the needed upkeep if 'i' techs are researched.
999 * If the ruleset contains self-rooted techs this can not work! */
1001 bool global_state[A_LAST];
1002 Tech_type_id tech = A_LAST;
1004 /* Save the game research state. */
1005 advance_index_iterate(A_FIRST, i) {
1006 global_state[i] = game.info.global_advances[i];
1007 } advance_index_iterate_end;
1009 research->techs_researched = 1;
1010 research_update(presearch);
1012 /* Show research costs. */
1013 advance_index_iterate(A_NONE, i) {
1014 log_debug("[research %d] %-25s (ID: %3d) cost: %6d - reachable: %-3s "
1015 "(now) / %-3s (ever)", research_number(research),
1016 advance_rule_name(advance_by_number(i)), i,
1017 research_total_bulbs_required(research, i, FALSE),
1018 research_invention_gettable(research, i, FALSE)
1019 ? "yes" : "no",
1020 research_invention_reachable(research, i) ? "yes" : "no");
1021 } advance_index_iterate_end;
1023 /* Update step for step each tech as known and print the upkeep. */
1024 while (tech != A_NONE) {
1025 tech = A_NONE;
1026 advance_index_iterate(A_FIRST, i) {
1027 if (research_invention_state(research, i) == TECH_PREREQS_KNOWN) {
1028 /* Found a tech which can be researched. */
1029 tech = i;
1030 break;
1032 } advance_index_iterate_end;
1034 if (tech != A_NONE) {
1035 research->inventions[tech].state = TECH_KNOWN;
1036 research->techs_researched++;
1038 /* This will change the game state! */
1039 research_update(research);
1041 research_players_iterate(research, pplayer) {
1042 log_debug("[player %d] researched: %-25s (ID: %4d) techs: %3d "
1043 "upkeep: %4d", research_number(research),
1044 advance_rule_name(advance_by_number(tech)), tech,
1045 research->techs_researched, player_tech_upkeep(pplayer));
1046 } research_players_iterate_end;
1050 /* Reset the changes done. */
1051 advance_index_iterate(A_FIRST, i) {
1052 research_invention_set(research, i, TECH_UNKNOWN);
1053 game.info.global_advances[i] = global_state[i];
1054 } advance_index_iterate_end;
1056 #endif /* TECH_UPKEEP_DEBUGGING */
1058 research->techs_researched = 1;
1060 if (update) {
1061 Tech_type_id next_tech;
1063 /* Mark the reachable techs */
1064 research_update(research);
1066 next_tech = research_goal_step(research, research->tech_goal);
1067 if (A_UNSET != next_tech) {
1068 choose_tech(research, next_tech);
1069 } else {
1070 choose_random_tech(research);
1075 /****************************************************************************
1076 Gives global (read from the game ruleset file) and nation (read from the
1077 nation ruleset files) initial techs as specified in the ruleset, and
1078 random free technologies thanks to the techlevel setting.
1079 ****************************************************************************/
1080 void give_initial_techs(struct research *presearch, int num_random_techs)
1082 int i;
1084 /* Global techs. */
1085 for (i = 0; i < MAX_NUM_TECH_LIST; i++) {
1086 if (game.rgame.global_init_techs[i] == A_LAST) {
1087 break;
1089 /* Maybe the player already got this tech by an other way (e.g. team). */
1090 if (research_invention_state(presearch, game.rgame.global_init_techs[i])
1091 != TECH_KNOWN) {
1092 found_new_tech(presearch, game.rgame.global_init_techs[i],
1093 FALSE, TRUE);
1097 /* Nation techs. */
1098 research_players_iterate(presearch, pplayer) {
1099 const struct nation_type *pnation = nation_of_player(pplayer);
1101 for (i = 0; i < MAX_NUM_TECH_LIST; i++) {
1102 if (pnation->init_techs[i] == A_LAST) {
1103 break;
1105 /* Maybe the player already got this tech by an other way. */
1106 if (research_invention_state(presearch, pnation->init_techs[i])
1107 != TECH_KNOWN) {
1108 found_new_tech(presearch, pnation->init_techs[i], FALSE, TRUE);
1111 } research_players_iterate_end;
1113 /* Random free techs (N.B.: freecost penalty not applied). */
1114 for (i = 0; i < num_random_techs; i++) {
1115 found_new_tech(presearch, pick_random_tech(presearch), FALSE, TRUE);
1119 /****************************************************************************
1120 If victim has a tech which pplayer doesn't have, pplayer will get it.
1121 The clients will both be notified and the conquer cost
1122 penalty applied. Used for diplomats and city conquest.
1123 If preferred is A_UNSET one random tech will be chosen.
1124 Returns the stolen tech or A_NONE if no tech was found.
1125 ****************************************************************************/
1126 Tech_type_id steal_a_tech(struct player *pplayer, struct player *victim,
1127 Tech_type_id preferred)
1129 struct research *presearch, *vresearch;
1130 Tech_type_id stolen_tech = A_NONE;
1131 const char *advance_name;
1132 char research_name[MAX_LEN_NAME * 2];
1134 if (get_player_bonus(victim, EFT_NOT_TECH_SOURCE) > 0) {
1135 return A_NONE;
1138 presearch = research_get(pplayer);
1139 vresearch = research_get(victim);
1141 if (preferred == A_UNSET) {
1142 int j = 0;
1143 advance_index_iterate(A_FIRST, i) {
1144 if (research_invention_gettable(presearch, i,
1145 game.info.tech_steal_allow_holes)
1146 && research_invention_state(presearch, i) != TECH_KNOWN
1147 && research_invention_state(vresearch, i) == TECH_KNOWN) {
1148 j++;
1150 } advance_index_iterate_end;
1152 if (j == 0) {
1153 /* we've moved on to future tech */
1154 if (vresearch->future_tech > presearch->future_tech) {
1155 found_new_tech(presearch, A_FUTURE, FALSE, TRUE);
1156 stolen_tech = A_FUTURE;
1157 } else {
1158 return A_NONE;
1160 } else {
1161 /* pick random tech */
1162 j = fc_rand(j) + 1;
1163 stolen_tech = A_NONE; /* avoid compiler warning */
1164 advance_index_iterate(A_FIRST, i) {
1165 if (research_invention_gettable(presearch, i,
1166 game.info.tech_steal_allow_holes)
1167 && research_invention_state(presearch, i) != TECH_KNOWN
1168 && research_invention_state(vresearch, i) == TECH_KNOWN) {
1169 j--;
1171 if (j == 0) {
1172 stolen_tech = i;
1173 break;
1175 } advance_index_iterate_end;
1176 fc_assert(stolen_tech != A_NONE);
1178 } else { /* preferred != A_UNSET */
1179 #ifndef FREECIV_NDEBUG
1180 if (!is_future_tech(preferred)) {
1181 fc_assert(NULL != valid_advance_by_number(preferred));
1182 fc_assert(TECH_KNOWN == research_invention_state(vresearch,
1183 preferred));
1185 #endif /* FREECIV_NDEBUG */
1186 stolen_tech = preferred;
1189 advance_name = research_advance_name_translation(presearch, stolen_tech);
1190 research_pretty_name(presearch, research_name, sizeof(research_name));
1191 notify_player(pplayer, NULL, E_MY_DIPLOMAT_THEFT, ftc_server,
1192 _("You steal %s from the %s."),
1193 advance_name,
1194 nation_plural_for_player(victim));
1195 notify_research(presearch, pplayer, E_TECH_GAIN, ftc_server,
1196 _("The %s stole %s from the %s and shared it with you."),
1197 nation_plural_for_player(pplayer),
1198 advance_name,
1199 nation_plural_for_player(victim));
1201 notify_player(victim, NULL, E_ENEMY_DIPLOMAT_THEFT, ftc_server,
1202 _("The %s stole %s from you!"),
1203 nation_plural_for_player(pplayer),
1204 advance_name);
1206 notify_research_embassies(presearch, victim, E_TECH_EMBASSY, ftc_server,
1207 _("The %s have stolen %s from the %s."),
1208 research_name,
1209 advance_name,
1210 nation_plural_for_player(victim));
1212 if (tech_transfer(pplayer, victim, stolen_tech)) {
1213 research_apply_penalty(presearch, stolen_tech, game.server.conquercost);
1214 found_new_tech(presearch, stolen_tech, FALSE, TRUE);
1215 script_tech_learned(presearch, pplayer, advance_by_number(stolen_tech),
1216 "stolen");
1217 return stolen_tech;
1220 return A_NONE;
1223 /****************************************************************************
1224 Handle incoming research packet. Need to check correctness
1225 Set the player to be researching the given tech.
1227 If there are enough accumulated research points, the tech may be
1228 acquired immediately.
1229 ****************************************************************************/
1230 void handle_player_research(struct player *pplayer, int tech)
1232 struct research *research = research_get(pplayer);
1234 if (tech != A_FUTURE && !valid_advance_by_number(tech)) {
1235 return;
1238 if (tech != A_FUTURE
1239 && research_invention_state(research, tech) != TECH_PREREQS_KNOWN) {
1240 return;
1243 choose_tech(research, tech);
1245 /* Notify players sharing the same research. */
1246 send_research_info(research, NULL);
1249 /****************************************************************************
1250 Handle incoming player_tech_goal packet
1251 Called from the network or AI code to set the player's tech goal.
1252 ****************************************************************************/
1253 void handle_player_tech_goal(struct player *pplayer, int tech_goal)
1255 struct research *research = research_get(pplayer);
1257 /* Set the tech goal to a defined state if it is
1258 * - not a future tech and not a valid goal
1259 * - not a future tech and not a valid advance
1260 * - not defined
1261 * - known (i.e. due to EFT_GIVE_IMM_TECH). */
1262 if ((tech_goal != A_FUTURE
1263 && (!valid_advance_by_number(tech_goal)
1264 || !research_invention_reachable(research, tech_goal)))
1265 || (tech_goal == A_NONE)
1266 || (TECH_KNOWN == research_invention_state(research, tech_goal))) {
1267 tech_goal = A_UNSET;
1270 choose_tech_goal(research, tech_goal);
1272 /* Notify players sharing the same research. */
1273 send_research_info(research, NULL);
1276 /****************************************************************************
1277 Gives an immediate free tech. Applies freecost. Returns the tech.
1278 ****************************************************************************/
1279 Tech_type_id give_immediate_free_tech(struct research *presearch)
1281 Tech_type_id tech;
1283 if (game.info.free_tech_method == FTM_CHEAPEST) {
1284 tech = pick_cheapest_tech(presearch);
1285 } else if (presearch->researching == A_UNSET
1286 || game.info.free_tech_method == FTM_RANDOM) {
1287 tech = pick_random_tech(presearch);
1288 } else {
1289 tech = presearch->researching;
1291 research_apply_penalty(presearch, tech, game.server.freecost);
1292 found_new_tech(presearch, tech, FALSE, TRUE);
1293 return tech;
1296 /****************************************************************************
1297 Let the player forget one tech.
1298 ****************************************************************************/
1299 static void forget_tech_transfered(struct player *pplayer, Tech_type_id tech)
1301 struct research *presearch = research_get(pplayer);
1303 research_tech_lost(presearch, tech);
1304 /* Make notification after losing the research, in case it is a future
1305 * tech (for getting the right tech number). */
1306 notify_player(pplayer, NULL, E_TECH_LOST, ftc_server,
1307 _("Too bad! You made a mistake transferring the tech %s and "
1308 "lost it."),
1309 research_advance_name_translation(presearch, tech));
1310 notify_research(presearch, pplayer, E_TECH_LOST, ftc_server,
1311 _("Too bad! The %s made a mistake transferring the tech "
1312 "%s and lost it."),
1313 nation_plural_for_player(pplayer),
1314 research_advance_name_translation(presearch, tech));
1317 /****************************************************************************
1318 Check if the tech is lost by the donor or receiver. Returns if the
1319 receiver gets a new tech.
1320 ****************************************************************************/
1321 bool tech_transfer(struct player *plr_recv, struct player *plr_donor,
1322 Tech_type_id tech)
1324 if (game.server.techlost_donor > 0) {
1325 struct research *donor_research = research_get(plr_donor);
1326 bool donor_can_lose = TRUE;
1328 advance_index_iterate(A_FIRST, i) {
1329 /* Never let donor lose tech if it's root_req for some other known
1330 * tech */
1331 if (research_invention_state(donor_research, i) == TECH_KNOWN
1332 && (advance_required(i, AR_ROOT) == tech
1333 || (!game.info.tech_trade_loss_allow_holes
1334 && (advance_required(i, AR_ONE) == tech
1335 || advance_required(i, AR_TWO) == tech)))) {
1336 donor_can_lose = FALSE;
1337 break;
1339 } advance_index_iterate_end;
1340 if (donor_can_lose && fc_rand(100) < game.server.techlost_donor) {
1341 forget_tech_transfered(plr_donor, tech);
1345 if (fc_rand(100) < game.server.techlost_recv) {
1346 forget_tech_transfered(plr_recv, tech);
1347 return FALSE;
1350 return TRUE;