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)
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 ***********************************************************************/
14 #include <fc_config.h>
28 #include "government.h"
35 /* common/scriptcore */
36 #include "luascript_types.h"
39 #include "citytools.h"
41 #include "connecthand.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
57 pick_random_tech_to_lose(const struct research
*presearch
);
58 static void research_tech_lost(struct research
*presearch
,
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
,
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
,
83 /* Emit signal for individual player whose action triggered the
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."),
120 research_advance_name_translation(research
, tech
));
122 /* Deduct tech cost. */
123 research
->bulbs_researched
-= research_total_bulbs_required(research
, tech
,
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
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
;
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
);
152 effect_list_destroy(plist
);
156 /* Pick a random technology. */
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
)) {
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
)) {
177 } players_iterate_end
;
178 } advance_index_iterate_end
;
180 if (A_UNSET
== tech
) {
182 effect_list_destroy(plist
);
187 research_pretty_name(presearch
, research_name
, sizeof(research_name
));
188 advance_name
= research_advance_name_translation(presearch
, tech
);
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
195 Q_("?fromeffect:%s acquired from %s!"),
198 notify_research(presearch
, pplayer
, E_TECH_GAIN
, ftc_server
,
199 /* TRANS: Tech from source of an effect
201 Q_("?fromeffect:%s acquired from %s's %s!"),
203 player_name(pplayer
),
205 notify_research_embassies(presearch
, NULL
, E_TECH_EMBASSY
, ftc_server
,
206 /* TRANS: Tech from source of an effect
208 Q_("?fromeffect:The %s have acquired %s from %s."),
213 effect_list_destroy(plist
);
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 ****************************************************************************/
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
,
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
;
257 log_verbose("Research nb %d inventions: %s",
258 research_number(presearch
),
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
);
275 dest
= game
.est_connections
;
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
);
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
);
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
;
319 const char *advance_name
;
320 struct advance
*vap
= valid_advance_by_number(tech_found
);
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
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
),
353 } requirement_vector_iterate_end
;
354 } improvement_iterate_end
;
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
)) {
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
++;
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
);
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."),
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; "
481 research_advance_name_translation(presearch
,
483 research_advance_name_translation
484 (presearch
, presearch
->tech_goal
));
486 if (is_future_tech(tech_found
)) {
487 /* Continue researching future tech. */
488 next_tech
= A_FUTURE
;
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
);
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."),
506 notify_research(presearch
, NULL
, E_TECH_LEARNED
, ftc_server
,
507 _("Learned %s. Scientists choose to research %s."),
509 research_advance_name_translation(presearch
,
514 if (A_UNSET
!= next_tech
) {
515 choose_tech(presearch
, next_tech
);
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
),
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 */
566 if (research
->techs_researched
== 0) {
567 /* No tech to lose */
568 fc_assert(research
->future_tech
== 0);
572 if (research
->bulbs_researched
<
573 (-research_total_bulbs_required(research
, research
->researching
, FALSE
)
574 * game
.server
.techloss_forgiveness
/ 100)) {
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
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 */
600 /* count our research contribution this turn */
601 pplayer
->server
.bulbs_last_turn
+= bulbs
;
602 research
->bulbs_researched
+= bulbs
;
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);
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. */
639 || research
->researching
== A_UNSET
640 || (research
->bulbs_researched
641 < research_total_bulbs_required(research
, research
->researching
,
646 tech_researched(research
);
647 } while (research
->researching
!= A_UNSET
);
650 /****************************************************************************
651 Choose a random tech for player to lose.
652 ****************************************************************************/
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;
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
)) {
667 BV_CLR(eligible_techs
, i
);
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
)) {
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 */
682 prereq
= advance_required(i
, AR_ONE
);
683 if (prereq
!= A_NONE
&& BV_ISSET(eligible_techs
, prereq
)) {
685 BV_CLR(eligible_techs
, prereq
);
687 prereq
= advance_required(i
, AR_TWO
);
688 if (prereq
!= A_NONE
&& BV_ISSET(eligible_techs
, prereq
)) {
690 BV_CLR(eligible_techs
, prereq
);
694 } advance_index_iterate_end
;
697 /* no researched technology at all */
701 chosen
= fc_rand(eligible
) + 1;
703 advance_index_iterate(A_FIRST
, i
) {
704 if (BV_ISSET(eligible_techs
, i
)) {
710 } advance_index_iterate_end
;
712 /* should never be reached */
713 fc_assert_msg(chosen
== 0, "internal error (eligible=%d, chosen=%d)",
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
;
727 governments_iterate(pgov
) {
728 if (can_change_to_government(pplayer
, pgov
) && 0 == fc_rand(++gov_nb
)) {
731 } governments_iterate_end
;
732 fc_assert(NULL
!= 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."),
755 research_advance_name_translation(presearch
,
757 /* Inform players about their technology loss. */
758 send_research_info(presearch
, NULL
);
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."),
767 research_advance_name_translation(presearch
,
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
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
) {
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 "
834 utype_name_translation(pcity
->production
.value
.utype
));
835 choose_build_target(pplayer
, pcity
);
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 "
847 improvement_name_translation
848 (pcity
->production
.value
.building
));
849 choose_build_target(pplayer
, 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
;
869 advance_index_iterate(A_FIRST
, i
) {
870 if (research_invention_state(presearch
, i
) == TECH_PREREQS_KNOWN
) {
871 if (fc_rand(++num_techs
) == 0) {
875 } advance_index_iterate_end
;
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
;
896 } else if (cost
== cheapest_cost
&& fc_rand(++cheapest_amount
) == 0) {
900 } advance_index_iterate_end
;
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.
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
)
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
);
938 if (research
->researching
== tech
) {
941 if (research_invention_state(research
, tech
) != TECH_PREREQS_KNOWN
) {
942 /* Can't research this. */
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
) {
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
)
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
) {
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. */
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;
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
);
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
)
1085 for (i
= 0; i
< MAX_NUM_TECH_LIST
; i
++) {
1086 if (game
.rgame
.global_init_techs
[i
] == A_LAST
) {
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
])
1092 found_new_tech(presearch
, game
.rgame
.global_init_techs
[i
],
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
) {
1105 /* Maybe the player already got this tech by an other way. */
1106 if (research_invention_state(presearch
, pnation
->init_techs
[i
])
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) {
1138 presearch
= research_get(pplayer
);
1139 vresearch
= research_get(victim
);
1141 if (preferred
== A_UNSET
) {
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
) {
1150 } advance_index_iterate_end
;
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
;
1161 /* pick random tech */
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
) {
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
,
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."),
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
),
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
),
1206 notify_research_embassies(presearch
, victim
, E_TECH_EMBASSY
, ftc_server
,
1207 _("The %s have stolen %s from the %s."),
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
),
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
)) {
1238 if (tech
!= A_FUTURE
1239 && research_invention_state(research
, tech
) != TECH_PREREQS_KNOWN
) {
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
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
)
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
);
1289 tech
= presearch
->researching
;
1291 research_apply_penalty(presearch
, tech
, game
.server
.freecost
);
1292 found_new_tech(presearch
, tech
, FALSE
, TRUE
);
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 "
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 "
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
,
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
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
;
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
);