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 #ifndef FREECIV_NDEBUG
324 if (!is_future_tech(tech_found
)) {
325 fc_assert(NULL
!= vap
);
326 fc_assert(TECH_KNOWN
!= research_invention_state(presearch
, tech_found
));
328 #endif /* FREECIV_NDEBUG */
330 was_first
= (!game
.info
.global_advances
[tech_found
]);
331 /* Assign 'advance_name' before we increase the future tech counter. */
332 advance_name
= research_advance_name_translation(presearch
, tech_found
);
334 if (was_first
&& vap
) {
335 /* Alert the owners of any wonders that have been made obsolete */
336 improvement_iterate(pimprove
) {
337 requirement_vector_iterate(&pimprove
->obsolete_by
, pobs
) {
338 if (pobs
->source
.kind
== VUT_ADVANCE
339 && pobs
->source
.value
.advance
== vap
340 && pobs
->range
>= REQ_RANGE_WORLD
342 && is_great_wonder(pimprove
)
343 && (pcity
= city_from_great_wonder(pimprove
))) {
344 notify_player(city_owner(pcity
), NULL
, E_WONDER_OBSOLETE
, ftc_server
,
345 _("Discovery of %s OBSOLETES %s in %s!"),
346 research_advance_name_translation
347 (research_get(city_owner(pcity
)), tech_found
),
348 improvement_name_translation(pimprove
),
351 } requirement_vector_iterate_end
;
352 } improvement_iterate_end
;
356 && !is_future_tech(tech_found
)
357 && advance_has_flag(tech_found
, TF_BONUS_TECH
)) {
358 bonus_tech_hack
= TRUE
;
361 /* Memorize some values before the tech is marked as researched.
362 * We will check what has changed later. */
363 players_iterate(aplayer
) {
364 i
= player_index(aplayer
);
366 /* Count EFT_HAVE_EMBASSIES effect for each player. */
367 had_embassies
[i
] = get_player_bonus(aplayer
, EFT_HAVE_EMBASSIES
);
369 if (presearch
!= research_get(aplayer
)) {
373 /* Memorize for the players sharing the research what government
374 * they could switch on. */
375 governments_iterate(pgov
) {
376 could_switch
[i
][government_index(pgov
)]
377 = can_change_to_government(aplayer
, pgov
);
378 } governments_iterate_end
;
379 } players_iterate_end
;
381 /* got_tech allows us to change research without applying techpenalty
382 * (without losing bulbs) */
383 if (tech_found
== presearch
->researching
) {
384 presearch
->got_tech
= TRUE
;
386 presearch
->researching_saved
= A_UNKNOWN
;
387 presearch
->techs_researched
++;
389 /* Mark the tech as known in the research struct and update
390 * global_advances array. */
391 if (is_future_tech(tech_found
)) {
392 presearch
->future_tech
++;
394 research_invention_set(presearch
, tech_found
, TECH_KNOWN
);
395 research_update(presearch
);
398 /* Inform players about their new tech. */
399 send_research_info(presearch
, NULL
);
402 /* Inform all players about new global advances to give them a
403 * chance for obsolete buildings. */
404 send_game_info(NULL
);
407 /* Make proper changes for all players. Use shuffled order, in case
408 * a script would detect a signal. */
409 shuffled_players_iterate(aplayer
) {
410 i
= player_index(aplayer
);
412 if (presearch
== research_get(aplayer
)) {
413 /* Only for players sharing the research. */
414 remove_obsolete_buildings(aplayer
);
416 /* Give free infrastructure in every city */
417 if (tech_found
!= A_FUTURE
) {
418 upgrade_all_city_extras(aplayer
, was_discovery
);
421 /* Enhance vision of units if a player-ranged effect has changed. Note
422 * that world-ranged effects will not be updated immediately. */
423 unit_list_refresh_vision(aplayer
->units
);
425 /* Notify a player about new governments available */
426 governments_iterate(pgov
) {
427 if (!could_switch
[i
][government_index(pgov
)]
428 && can_change_to_government(aplayer
, pgov
)) {
429 notify_player(aplayer
, NULL
, E_NEW_GOVERNMENT
, ftc_server
,
430 _("Discovery of %s makes the government form %s"
431 " available. You may want to start a revolution."),
433 government_name_translation(pgov
));
435 } governments_iterate_end
;
438 /* For any player. */
439 /* Update all cities in case the tech changed some effects. This is
440 * inefficient; it could be optimized if it's found to be a problem.
441 * But techs aren't researched that often. */
442 city_list_iterate(aplayer
->cities
, apcity
) {
443 /* Refresh the city data; this also updates the squared city radius. */
444 city_refresh(apcity
);
445 city_refresh_vision(apcity
);
446 send_city_info(aplayer
, apcity
);
447 } city_list_iterate_end
;
449 /* Send all player an updated info of the owner of the Marco Polo
450 * Wonder if this wonder has become obsolete. */
451 if (0 < had_embassies
[i
]
452 && 0 <= get_player_bonus(aplayer
, EFT_HAVE_EMBASSIES
)) {
453 send_player_all_c(aplayer
, aplayer
->connections
);
454 players_iterate(pother_player
) {
455 if (aplayer
!= pother_player
) {
456 send_player_all_c(aplayer
, pother_player
->connections
);
457 send_player_all_c(pother_player
, aplayer
->connections
);
459 } players_iterate_end
;
461 } shuffled_players_iterate_end
;
463 if (tech_found
== presearch
->tech_goal
) {
464 presearch
->tech_goal
= A_UNSET
;
467 if (tech_found
== presearch
->researching
) {
468 /* Try to pick new tech to research. */
469 Tech_type_id next_tech
= research_goal_step(presearch
,
470 presearch
->tech_goal
);
472 /* As this function can be recursive, we need to print the messages
473 * before really picking the new technology. */
474 if (A_UNSET
!= next_tech
) {
475 notify_research(presearch
, NULL
, E_TECH_LEARNED
, ftc_server
,
476 _("Learned %s. Our scientists focus on %s; "
479 research_advance_name_translation(presearch
,
481 research_advance_name_translation
482 (presearch
, presearch
->tech_goal
));
484 if (is_future_tech(tech_found
)) {
485 /* Continue researching future tech. */
486 next_tech
= A_FUTURE
;
488 /* If there is at least one AI player still alive, then pick
489 * a random tech, else keep A_UNSET. */
490 research_players_iterate(presearch
, aplayer
) {
491 if (aplayer
->ai_controlled
) {
492 next_tech
= pick_random_tech(presearch
);
495 } research_players_iterate_end
;
498 if (A_UNSET
== next_tech
) {
499 notify_research(presearch
, NULL
, E_TECH_LEARNED
, ftc_server
,
500 _("Learned %s. Scientists "
501 "do not know what to research next."),
504 notify_research(presearch
, NULL
, E_TECH_LEARNED
, ftc_server
,
505 _("Learned %s. Scientists choose to research %s."),
507 research_advance_name_translation(presearch
,
512 if (A_UNSET
!= next_tech
) {
513 choose_tech(presearch
, next_tech
);
515 presearch
->researching
= A_UNSET
;
519 if (!saving_bulbs
&& presearch
->bulbs_researched
> 0) {
520 presearch
->bulbs_researched
= 0;
523 if (bonus_tech_hack
) {
524 Tech_type_id additional_tech
;
525 char research_name
[MAX_LEN_NAME
* 2];
526 const char *radv_name
;
528 research_pretty_name(presearch
, research_name
, sizeof(research_name
));
530 additional_tech
= give_immediate_free_tech(presearch
);
532 radv_name
= research_advance_name_translation(presearch
, additional_tech
);
534 if (advance_by_number(tech_found
)->bonus_message
!= NULL
535 && additional_tech
!= A_UNSET
) {
536 notify_research(presearch
, NULL
, E_TECH_GAIN
, ftc_server
,
537 _(advance_by_number(tech_found
)->bonus_message
),
539 } else if (additional_tech
!= A_UNSET
) {
540 /* FIXME: "your" when it was just civilization of one of the players
541 * sharing the reseach. */
542 notify_research(presearch
, NULL
, E_TECH_GAIN
, ftc_server
,
543 _("Great scientists from all the "
544 "world join your civilization: you learn "
545 "%s immediately."), radv_name
);
547 /* TODO: Ruleset should be able to customize this message too */
548 notify_research_embassies(presearch
, NULL
, E_TECH_EMBASSY
, ftc_server
,
549 _("%s acquire %s as a result of learning %s."),
550 research_name
, radv_name
, advance_name
);
554 /****************************************************************************
555 Is player about to lose tech?
556 ****************************************************************************/
557 static bool lose_tech(struct research
*research
)
559 if (game
.server
.techloss_forgiveness
< 0) {
560 /* Tech loss disabled */
564 if (research
->techs_researched
== 0) {
565 /* No tech to lose */
566 fc_assert(research
->future_tech
== 0);
570 if (research
->bulbs_researched
<
571 (-research_total_bulbs_required(research
, research
->researching
, FALSE
)
572 * game
.server
.techloss_forgiveness
/ 100)) {
579 /****************************************************************************
580 Adds the given number of bulbs into the player's tech and (if necessary and
581 'check_tech' is TRUE) completes the research. If the total number of bulbs
582 is negative due to tech upkeep, one (randomly chosen) tech is lost.
584 The caller is responsible for sending updated player information.
586 This is called from each city every turn, from caravan revenue, and at the
588 ****************************************************************************/
589 void update_bulbs(struct player
*pplayer
, int bulbs
, bool check_tech
)
591 struct research
*research
= research_get(pplayer
);
593 if (!pplayer
->is_alive
) {
594 /* Dead players do not produce research */
598 /* count our research contribution this turn */
599 pplayer
->server
.bulbs_last_turn
+= bulbs
;
600 research
->bulbs_researched
+= bulbs
;
603 /* If we have a negative number of bulbs we do try to:
604 * - reduce the number of future techs;
605 * - or lose one random tech.
606 * After that the number of bulbs available is incresed based on the
607 * value of the lost tech. */
608 if (lose_tech(research
)) {
609 Tech_type_id tech
= (research
->future_tech
> 0
610 ? A_FUTURE
: pick_random_tech_to_lose(research
));
612 if (tech
!= A_NONE
) {
613 if (game
.server
.techloss_restore
>= 0) {
614 research
->bulbs_researched
+=
615 (research_total_bulbs_required(research
, tech
, TRUE
)
616 * game
.server
.techloss_restore
/ 100);
618 research
->bulbs_researched
= 0;
620 research
->researching_saved
= A_UNKNOWN
;
622 log_debug("%s: tech loss (%s)",
623 research_rule_name(research
),
624 (is_future_tech(tech
) ? "Future Tech"
625 : research_advance_rule_name(research
, tech
)));
626 research_tech_lost(research
, tech
);
627 /* Make notification after losing the research, in case it is
628 * a future tech (for getting the right tech number). */
629 notify_research(research
, NULL
, E_TECH_LOST
, ftc_server
,
630 _("Insufficient science output. We lost %s."),
631 research_advance_name_translation(research
, tech
));
635 /* Check for finished research. */
637 || research
->researching
== A_UNSET
638 || (research
->bulbs_researched
639 < research_total_bulbs_required(research
, research
->researching
,
644 tech_researched(research
);
645 } while (research
->researching
!= A_UNSET
);
648 /****************************************************************************
649 Choose a random tech for player to lose.
650 ****************************************************************************/
652 pick_random_tech_to_lose(const struct research
*presearch
)
654 bv_techs eligible_techs
;
655 /* A_NONE included in advance_count(). */
656 int eligible
= advance_count() - 1;
659 BV_SET_ALL(eligible_techs
);
661 advance_index_iterate(A_FIRST
, i
) {
662 if (research_invention_state(presearch
, i
) != TECH_KNOWN
) {
663 if (BV_ISSET(eligible_techs
, i
)) {
665 BV_CLR(eligible_techs
, i
);
668 /* Knowing this tech may make others ineligible */
669 Tech_type_id root
= advance_required(i
, AR_ROOT
);
670 /* Never lose techs that are root_req for a currently known tech
671 * (including self root_req) */
672 if (root
!= A_NONE
&& BV_ISSET(eligible_techs
, root
)) {
674 BV_CLR(eligible_techs
, root
);
676 if (!game
.info
.tech_loss_allow_holes
) {
677 /* Ruleset can prevent this kind of tech loss from opening up
678 * holes in the tech tree */
680 prereq
= advance_required(i
, AR_ONE
);
681 if (prereq
!= A_NONE
&& BV_ISSET(eligible_techs
, prereq
)) {
683 BV_CLR(eligible_techs
, prereq
);
685 prereq
= advance_required(i
, AR_TWO
);
686 if (prereq
!= A_NONE
&& BV_ISSET(eligible_techs
, prereq
)) {
688 BV_CLR(eligible_techs
, prereq
);
692 } advance_index_iterate_end
;
695 /* no researched technology at all */
699 chosen
= fc_rand(eligible
) + 1;
701 advance_index_iterate(A_FIRST
, i
) {
702 if (BV_ISSET(eligible_techs
, i
)) {
708 } advance_index_iterate_end
;
710 /* should never be reached */
711 fc_assert_msg(chosen
== 0, "internal error (eligible=%d, chosen=%d)",
716 /****************************************************************************
717 Helper for research_tech_lost().
718 ****************************************************************************/
719 static inline struct government
*
720 pick_random_government(struct player
*pplayer
)
722 struct government
*picked
= NULL
;
725 governments_iterate(pgov
) {
726 if (can_change_to_government(pplayer
, pgov
) && 0 == fc_rand(++gov_nb
)) {
729 } governments_iterate_end
;
730 fc_assert(NULL
!= picked
);
734 /****************************************************************************
735 Remove one tech from the research.
736 ****************************************************************************/
737 static void research_tech_lost(struct research
*presearch
, Tech_type_id tech
)
739 char research_name
[MAX_LEN_NAME
* 2];
740 /* Research members will be notified when new tech is chosen. */
742 research_pretty_name(presearch
, research_name
, sizeof(research_name
));
744 presearch
->techs_researched
--;
745 if (is_future_tech(tech
)) {
746 presearch
->future_tech
--;
747 research_update(presearch
);
748 /* Notify after decreasing the future tech counter, to get the right
749 * tech number in the message. */
750 notify_research_embassies(presearch
, NULL
, E_TECH_EMBASSY
, ftc_server
,
751 _("The %s have lost %s."),
753 research_advance_name_translation(presearch
,
755 /* Inform players about their technology loss. */
756 send_research_info(presearch
, NULL
);
760 fc_assert_ret(valid_advance_by_number(tech
));
761 notify_research_embassies(presearch
, NULL
, E_TECH_EMBASSY
, ftc_server
,
762 /* TRANS: technology loss */
763 _("The %s have lost %s."),
765 research_advance_name_translation(presearch
,
768 /* Remove technology. */
769 research_invention_set(presearch
, tech
, TECH_UNKNOWN
);
770 research_update(presearch
);
771 log_debug("%s lost tech id %d (%s)", research_rule_name(presearch
), tech
,
772 advance_rule_name(advance_by_number(tech
)));
774 /* Inform players about their technology loss. */
775 send_research_info(presearch
, NULL
);
777 research_players_iterate(presearch
, pplayer
) {
778 /* Check government. */
779 if (!can_change_to_government(pplayer
, government_of_player(pplayer
))) {
780 /* Lost the technology for the government; switch to random
781 * available government. */
782 struct government
*pgov
= pick_random_government(pplayer
);
784 notify_player(pplayer
, NULL
, E_NEW_GOVERNMENT
, ftc_server
,
785 _("The required technology for our government '%s' "
786 "was lost. The citizens have started a "
787 "revolution into '%s'."),
788 government_name_translation(government_of_player
790 government_name_translation(pgov
));
791 handle_player_change_government(pplayer
, government_number(pgov
));
792 send_player_info_c(pplayer
, NULL
);
793 } else if (NULL
!= pplayer
->target_government
794 && !can_change_to_government(pplayer
,
795 pplayer
->target_government
)) {
796 /* Lost the technology for the target government; use a random
797 * available government as new target government. */
798 struct government
*pgov
= pick_random_government(pplayer
);
800 notify_player(pplayer
, NULL
, E_NEW_GOVERNMENT
, ftc_server
,
801 _("The required technology for our new government "
802 "'%s' was lost. The citizens chose '%s' as new "
803 "target government."),
804 government_name_translation(pplayer
->target_government
),
805 government_name_translation(pgov
));
806 pplayer
->target_government
= pgov
;
807 send_player_info_c(pplayer
, pplayer
->connections
);
810 /* Check all units for valid activities. */
811 unit_list_iterate(pplayer
->units
, punit
) {
812 if (!can_unit_continue_current_activity(punit
)) {
813 log_debug("lost technology for activity of unit %s of %s (%d, %d)",
814 unit_name_translation(punit
), player_name(pplayer
),
815 TILE_XY(unit_tile(punit
)));
816 set_unit_activity(punit
, ACTIVITY_IDLE
);
817 send_unit_info(NULL
, punit
);
819 } unit_list_iterate_end
;
821 /* Check city production */
822 city_list_iterate(pplayer
->cities
, pcity
) {
825 if (pcity
->production
.kind
== VUT_UTYPE
826 && !can_city_build_unit_now(pcity
, pcity
->production
.value
.utype
)) {
827 notify_player(pplayer
, city_tile(pcity
),
828 E_CITY_CANTBUILD
, ftc_server
,
829 _("%s can't build %s. The required technology was "
832 utype_name_translation(pcity
->production
.value
.utype
));
833 choose_build_target(pplayer
, pcity
);
837 if (pcity
->production
.kind
== VUT_IMPROVEMENT
838 && !can_city_build_improvement_now(pcity
,
839 pcity
->production
.value
.building
)) {
840 notify_player(pplayer
, city_tile(pcity
),
841 E_CITY_CANTBUILD
, ftc_server
,
842 _("%s can't build %s. The required technology was "
845 improvement_name_translation
846 (pcity
->production
.value
.building
));
847 choose_build_target(pplayer
, pcity
);
853 send_city_info(pplayer
, pcity
);
855 } city_list_iterate_end
;
856 } research_players_iterate_end
;
859 /****************************************************************************
860 Returns random researchable tech or A_FUTURE. No side effects.
861 ****************************************************************************/
862 Tech_type_id
pick_random_tech(const struct research
*presearch
)
864 Tech_type_id tech
= A_FUTURE
;
867 advance_index_iterate(A_FIRST
, i
) {
868 if (research_invention_state(presearch
, i
) == TECH_PREREQS_KNOWN
) {
869 if (fc_rand(++num_techs
) == 0) {
873 } advance_index_iterate_end
;
877 /****************************************************************************
878 Returns cheapest researchable tech, random among equal cost ones.
879 ****************************************************************************/
880 Tech_type_id
pick_cheapest_tech(const struct research
*presearch
)
882 int cheapest_cost
= -1;
883 int cheapest_amount
= 0;
884 Tech_type_id cheapest
= A_FUTURE
; /* If no real tech is found to be missing */
886 advance_index_iterate(A_FIRST
, i
) {
887 if (research_invention_state(presearch
, i
) == TECH_PREREQS_KNOWN
) {
888 int cost
= research_total_bulbs_required(presearch
, i
, FALSE
);
890 if (cost
< cheapest_cost
|| cheapest_cost
== -1) {
891 cheapest_cost
= cost
;
894 } else if (cost
== cheapest_cost
&& fc_rand(++cheapest_amount
) == 0) {
898 } advance_index_iterate_end
;
903 /****************************************************************************
904 Finds and chooses (sets) a random research target from among all those
905 available until presearch->researching != A_UNSET.
906 Players may research more than one tech in this function.
909 - research.got_tech = TRUE and enough bulbs was saved;
910 - research.researching = A_UNSET and enough bulbs was saved.
911 ****************************************************************************/
912 void choose_random_tech(struct research
*research
)
915 choose_tech(research
, pick_random_tech(research
));
916 } while (research
->researching
== A_UNSET
);
919 /****************************************************************************
920 Called when a player chooses the tech he wants to research (or when
921 the server chooses it for him automatically).
923 This takes care of all side effects so the research target probably
924 shouldn't be changed outside of this function (doing so has been the
925 cause of several bugs).
926 ****************************************************************************/
927 void choose_tech(struct research
*research
, Tech_type_id tech
)
929 if (is_future_tech(tech
)) {
930 if (is_future_tech(research
->researching
)
931 && (research
->bulbs_researched
932 >= research_total_bulbs_required(research
, tech
, FALSE
))) {
933 tech_researched(research
);
936 if (research
->researching
== tech
) {
939 if (research_invention_state(research
, tech
) != TECH_PREREQS_KNOWN
) {
940 /* Can't research this. */
944 if (!research
->got_tech
&& research
->researching_saved
== A_UNKNOWN
) {
945 research
->bulbs_researching_saved
= research
->bulbs_researched
;
946 research
->researching_saved
= research
->researching
;
947 /* Subtract a penalty because we changed subject. */
948 if (research
->bulbs_researched
> 0) {
949 research
->bulbs_researched
950 -= ((research
->bulbs_researched
* game
.server
.techpenalty
) / 100);
951 fc_assert(research
->bulbs_researched
>= 0);
953 } else if (tech
== research
->researching_saved
) {
954 research
->bulbs_researched
= research
->bulbs_researching_saved
;
955 research
->researching_saved
= A_UNKNOWN
;
957 research
->researching
= tech
;
958 if (research
->bulbs_researched
959 >= research_total_bulbs_required(research
, tech
, FALSE
)) {
960 tech_researched(research
);
964 /****************************************************************************
965 Called when a player chooses the tech goal he wants to research (or when
966 the server chooses it for him automatically).
967 ****************************************************************************/
968 void choose_tech_goal(struct research
*presearch
, Tech_type_id tech
)
970 fc_assert_ret(presearch
!= NULL
);
972 if (tech
== presearch
->tech_goal
) {
976 /* It's been suggested that if the research target is empty then
977 * choose_random_tech() should be called here. */
978 presearch
->tech_goal
= tech
;
979 notify_research(presearch
, NULL
, E_TECH_GOAL
, ftc_server
,
980 _("Technology goal is %s."),
981 research_advance_name_translation(presearch
, tech
));
984 /****************************************************************************
985 Initializes tech data for the research.
986 ****************************************************************************/
987 void init_tech(struct research
*research
, bool update
)
989 research_invention_set(research
, A_NONE
, TECH_KNOWN
);
991 advance_index_iterate(A_FIRST
, i
) {
992 research_invention_set(research
, i
, TECH_UNKNOWN
);
993 } advance_index_iterate_end
;
995 #ifdef TECH_UPKEEP_DEBUGGING
996 /* Print a list of the needed upkeep if 'i' techs are researched.
997 * If the ruleset contains self-rooted techs this can not work! */
999 bool global_state
[A_LAST
];
1000 Tech_type_id tech
= A_LAST
;
1002 /* Save the game research state. */
1003 advance_index_iterate(A_FIRST
, i
) {
1004 global_state
[i
] = game
.info
.global_advances
[i
];
1005 } advance_index_iterate_end
;
1007 research
->techs_researched
= 1;
1008 research_update(presearch
);
1010 /* Show research costs. */
1011 advance_index_iterate(A_NONE
, i
) {
1012 log_debug("[research %d] %-25s (ID: %3d) cost: %6d - reachable: %-3s "
1013 "(now) / %-3s (ever)", research_number(research
),
1014 advance_rule_name(advance_by_number(i
)), i
,
1015 research_total_bulbs_required(research
, i
, FALSE
),
1016 research_invention_gettable(research
, i
, FALSE
)
1018 research_invention_reachable(research
, i
) ? "yes" : "no");
1019 } advance_index_iterate_end
;
1021 /* Update step for step each tech as known and print the upkeep. */
1022 while (tech
!= A_NONE
) {
1024 advance_index_iterate(A_FIRST
, i
) {
1025 if (research_invention_state(research
, i
) == TECH_PREREQS_KNOWN
) {
1026 /* Found a tech which can be researched. */
1030 } advance_index_iterate_end
;
1032 if (tech
!= A_NONE
) {
1033 research
->inventions
[tech
].state
= TECH_KNOWN
;
1034 research
->techs_researched
++;
1036 /* This will change the game state! */
1037 research_update(research
);
1039 research_players_iterate(research
, pplayer
) {
1040 log_debug("[player %d] researched: %-25s (ID: %4d) techs: %3d "
1041 "upkeep: %4d", research_number(research
),
1042 advance_rule_name(advance_by_number(tech
)), tech
,
1043 research
->techs_researched
, player_tech_upkeep(pplayer
));
1044 } research_players_iterate_end
;
1048 /* Reset the changes done. */
1049 advance_index_iterate(A_FIRST
, i
) {
1050 research_invention_set(research
, i
, TECH_UNKNOWN
);
1051 game
.info
.global_advances
[i
] = global_state
[i
];
1052 } advance_index_iterate_end
;
1054 #endif /* TECH_UPKEEP_DEBUGGING */
1056 research
->techs_researched
= 1;
1059 Tech_type_id next_tech
;
1061 /* Mark the reachable techs */
1062 research_update(research
);
1064 next_tech
= research_goal_step(research
, research
->tech_goal
);
1065 if (A_UNSET
!= next_tech
) {
1066 choose_tech(research
, next_tech
);
1068 choose_random_tech(research
);
1073 /****************************************************************************
1074 Gives global (read from the game ruleset file) and nation (read from the
1075 nation ruleset files) initial techs as specified in the ruleset, and
1076 random free technologies thanks to the techlevel setting.
1077 ****************************************************************************/
1078 void give_initial_techs(struct research
*presearch
, int num_random_techs
)
1083 for (i
= 0; i
< MAX_NUM_TECH_LIST
; i
++) {
1084 if (game
.rgame
.global_init_techs
[i
] == A_LAST
) {
1087 /* Maybe the player already got this tech by an other way (e.g. team). */
1088 if (research_invention_state(presearch
, game
.rgame
.global_init_techs
[i
])
1090 found_new_tech(presearch
, game
.rgame
.global_init_techs
[i
],
1096 research_players_iterate(presearch
, pplayer
) {
1097 const struct nation_type
*pnation
= nation_of_player(pplayer
);
1099 for (i
= 0; i
< MAX_NUM_TECH_LIST
; i
++) {
1100 if (pnation
->init_techs
[i
] == A_LAST
) {
1103 /* Maybe the player already got this tech by an other way. */
1104 if (research_invention_state(presearch
, pnation
->init_techs
[i
])
1106 found_new_tech(presearch
, pnation
->init_techs
[i
], FALSE
, TRUE
);
1109 } research_players_iterate_end
;
1111 /* Random free techs (N.B.: freecost penalty not applied). */
1112 for (i
= 0; i
< num_random_techs
; i
++) {
1113 found_new_tech(presearch
, pick_random_tech(presearch
), FALSE
, TRUE
);
1117 /****************************************************************************
1118 If victim has a tech which pplayer doesn't have, pplayer will get it.
1119 The clients will both be notified and the conquer cost
1120 penalty applied. Used for diplomats and city conquest.
1121 If preferred is A_UNSET one random tech will be chosen.
1122 Returns the stolen tech or A_NONE if no tech was found.
1123 ****************************************************************************/
1124 Tech_type_id
steal_a_tech(struct player
*pplayer
, struct player
*victim
,
1125 Tech_type_id preferred
)
1127 struct research
*presearch
, *vresearch
;
1128 Tech_type_id stolen_tech
= A_NONE
;
1129 const char *advance_name
;
1130 char research_name
[MAX_LEN_NAME
* 2];
1132 if (get_player_bonus(victim
, EFT_NOT_TECH_SOURCE
) > 0) {
1136 presearch
= research_get(pplayer
);
1137 vresearch
= research_get(victim
);
1139 if (preferred
== A_UNSET
) {
1141 advance_index_iterate(A_FIRST
, i
) {
1142 if (research_invention_gettable(presearch
, i
,
1143 game
.info
.tech_steal_allow_holes
)
1144 && research_invention_state(presearch
, i
) != TECH_KNOWN
1145 && research_invention_state(vresearch
, i
) == TECH_KNOWN
) {
1148 } advance_index_iterate_end
;
1151 /* we've moved on to future tech */
1152 if (vresearch
->future_tech
> presearch
->future_tech
) {
1153 found_new_tech(presearch
, A_FUTURE
, FALSE
, TRUE
);
1154 stolen_tech
= A_FUTURE
;
1159 /* pick random tech */
1161 stolen_tech
= A_NONE
; /* avoid compiler warning */
1162 advance_index_iterate(A_FIRST
, i
) {
1163 if (research_invention_gettable(presearch
, i
,
1164 game
.info
.tech_steal_allow_holes
)
1165 && research_invention_state(presearch
, i
) != TECH_KNOWN
1166 && research_invention_state(vresearch
, i
) == TECH_KNOWN
) {
1173 } advance_index_iterate_end
;
1174 fc_assert(stolen_tech
!= A_NONE
);
1176 } else { /* preferred != A_UNSET */
1177 #ifndef FREECIV_NDEBUG
1178 if (!is_future_tech(preferred
)) {
1179 fc_assert(NULL
!= valid_advance_by_number(preferred
));
1180 fc_assert(TECH_KNOWN
== research_invention_state(vresearch
,
1183 #endif /* FREECIV_NDEBUG */
1184 stolen_tech
= preferred
;
1187 advance_name
= research_advance_name_translation(presearch
, stolen_tech
);
1188 research_pretty_name(presearch
, research_name
, sizeof(research_name
));
1189 notify_player(pplayer
, NULL
, E_MY_DIPLOMAT_THEFT
, ftc_server
,
1190 _("You steal %s from the %s."),
1192 nation_plural_for_player(victim
));
1193 notify_research(presearch
, pplayer
, E_TECH_GAIN
, ftc_server
,
1194 _("The %s stole %s from the %s and shared it with you."),
1195 nation_plural_for_player(pplayer
),
1197 nation_plural_for_player(victim
));
1199 notify_player(victim
, NULL
, E_ENEMY_DIPLOMAT_THEFT
, ftc_server
,
1200 _("The %s stole %s from you!"),
1201 nation_plural_for_player(pplayer
),
1204 notify_research_embassies(presearch
, victim
, E_TECH_EMBASSY
, ftc_server
,
1205 _("The %s have stolen %s from the %s."),
1208 nation_plural_for_player(victim
));
1210 if (tech_transfer(pplayer
, victim
, stolen_tech
)) {
1211 research_apply_penalty(presearch
, stolen_tech
, game
.server
.conquercost
);
1212 found_new_tech(presearch
, stolen_tech
, FALSE
, TRUE
);
1213 script_tech_learned(presearch
, pplayer
, advance_by_number(stolen_tech
),
1221 /****************************************************************************
1222 Handle incoming research packet. Need to check correctness
1223 Set the player to be researching the given tech.
1225 If there are enough accumulated research points, the tech may be
1226 acquired immediately.
1227 ****************************************************************************/
1228 void handle_player_research(struct player
*pplayer
, int tech
)
1230 struct research
*research
= research_get(pplayer
);
1232 if (tech
!= A_FUTURE
&& !valid_advance_by_number(tech
)) {
1236 if (tech
!= A_FUTURE
1237 && research_invention_state(research
, tech
) != TECH_PREREQS_KNOWN
) {
1241 choose_tech(research
, tech
);
1243 /* Notify players sharing the same research. */
1244 send_research_info(research
, NULL
);
1247 /****************************************************************************
1248 Handle incoming player_tech_goal packet
1249 Called from the network or AI code to set the player's tech goal.
1250 ****************************************************************************/
1251 void handle_player_tech_goal(struct player
*pplayer
, int tech_goal
)
1253 struct research
*research
= research_get(pplayer
);
1255 /* Set the tech goal to a defined state if it is
1256 * - not a future tech and not a valid goal
1257 * - not a future tech and not a valid advance
1259 * - known (i.e. due to EFT_GIVE_IMM_TECH). */
1260 if ((tech_goal
!= A_FUTURE
1261 && (!valid_advance_by_number(tech_goal
)
1262 || !research_invention_reachable(research
, tech_goal
)))
1263 || (tech_goal
== A_NONE
)
1264 || (TECH_KNOWN
== research_invention_state(research
, tech_goal
))) {
1265 tech_goal
= A_UNSET
;
1268 choose_tech_goal(research
, tech_goal
);
1270 /* Notify players sharing the same research. */
1271 send_research_info(research
, NULL
);
1274 /****************************************************************************
1275 Gives an immediate free tech. Applies freecost. Returns the tech.
1276 ****************************************************************************/
1277 Tech_type_id
give_immediate_free_tech(struct research
*presearch
)
1281 if (game
.info
.free_tech_method
== FTM_CHEAPEST
) {
1282 tech
= pick_cheapest_tech(presearch
);
1283 } else if (presearch
->researching
== A_UNSET
1284 || game
.info
.free_tech_method
== FTM_RANDOM
) {
1285 tech
= pick_random_tech(presearch
);
1287 tech
= presearch
->researching
;
1289 research_apply_penalty(presearch
, tech
, game
.server
.freecost
);
1290 found_new_tech(presearch
, tech
, FALSE
, TRUE
);
1294 /****************************************************************************
1295 Let the player forget one tech.
1296 ****************************************************************************/
1297 static void forget_tech_transfered(struct player
*pplayer
, Tech_type_id tech
)
1299 struct research
*presearch
= research_get(pplayer
);
1301 research_tech_lost(presearch
, tech
);
1302 /* Make notification after losing the research, in case it is a future
1303 * tech (for getting the right tech number). */
1304 notify_player(pplayer
, NULL
, E_TECH_LOST
, ftc_server
,
1305 _("Too bad! You made a mistake transferring the tech %s and "
1307 research_advance_name_translation(presearch
, tech
));
1308 notify_research(presearch
, pplayer
, E_TECH_LOST
, ftc_server
,
1309 _("Too bad! The %s made a mistake transferring the tech "
1311 nation_plural_for_player(pplayer
),
1312 research_advance_name_translation(presearch
, tech
));
1315 /****************************************************************************
1316 Check if the tech is lost by the donor or receiver. Returns if the
1317 receiver gets a new tech.
1318 ****************************************************************************/
1319 bool tech_transfer(struct player
*plr_recv
, struct player
*plr_donor
,
1322 if (game
.server
.techlost_donor
> 0) {
1323 struct research
*donor_research
= research_get(plr_donor
);
1324 bool donor_can_lose
= TRUE
;
1326 advance_index_iterate(A_FIRST
, i
) {
1327 /* Never let donor lose tech if it's root_req for some other known
1329 if (research_invention_state(donor_research
, i
) == TECH_KNOWN
1330 && (advance_required(i
, AR_ROOT
) == tech
1331 || (!game
.info
.tech_trade_loss_allow_holes
1332 && (advance_required(i
, AR_ONE
) == tech
1333 || advance_required(i
, AR_TWO
) == tech
)))) {
1334 donor_can_lose
= FALSE
;
1337 } advance_index_iterate_end
;
1338 if (donor_can_lose
&& fc_rand(100) < game
.server
.techlost_donor
) {
1339 forget_tech_transfered(plr_donor
, tech
);
1343 if (fc_rand(100) < game
.server
.techlost_recv
) {
1344 forget_tech_transfered(plr_recv
, tech
);