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_NONE
;
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
;
902 /****************************************************************************
903 Finds and chooses (sets) a random research target from among all those
904 available until presearch->researching != A_UNSET.
905 Players may research more than one tech in this function.
908 - research.got_tech = TRUE and enough bulbs was saved;
909 - research.researching = A_UNSET and enough bulbs was saved.
910 ****************************************************************************/
911 void choose_random_tech(struct research
*research
)
914 choose_tech(research
, pick_random_tech(research
));
915 } while (research
->researching
== A_UNSET
);
918 /****************************************************************************
919 Called when a player chooses the tech he wants to research (or when
920 the server chooses it for him automatically).
922 This takes care of all side effects so the research target probably
923 shouldn't be changed outside of this function (doing so has been the
924 cause of several bugs).
925 ****************************************************************************/
926 void choose_tech(struct research
*research
, Tech_type_id tech
)
928 if (is_future_tech(tech
)) {
929 if (is_future_tech(research
->researching
)
930 && (research
->bulbs_researched
931 >= research_total_bulbs_required(research
, tech
, FALSE
))) {
932 tech_researched(research
);
935 if (research
->researching
== tech
) {
938 if (research_invention_state(research
, tech
) != TECH_PREREQS_KNOWN
) {
939 /* Can't research this. */
943 if (!research
->got_tech
&& research
->researching_saved
== A_UNKNOWN
) {
944 research
->bulbs_researching_saved
= research
->bulbs_researched
;
945 research
->researching_saved
= research
->researching
;
946 /* Subtract a penalty because we changed subject. */
947 if (research
->bulbs_researched
> 0) {
948 research
->bulbs_researched
949 -= ((research
->bulbs_researched
* game
.server
.techpenalty
) / 100);
950 fc_assert(research
->bulbs_researched
>= 0);
952 } else if (tech
== research
->researching_saved
) {
953 research
->bulbs_researched
= research
->bulbs_researching_saved
;
954 research
->researching_saved
= A_UNKNOWN
;
956 research
->researching
= tech
;
957 if (research
->bulbs_researched
958 >= research_total_bulbs_required(research
, tech
, FALSE
)) {
959 tech_researched(research
);
963 /****************************************************************************
964 Called when a player chooses the tech goal he wants to research (or when
965 the server chooses it for him automatically).
966 ****************************************************************************/
967 void choose_tech_goal(struct research
*presearch
, Tech_type_id tech
)
969 fc_assert_ret(presearch
!= NULL
);
971 if (tech
== presearch
->tech_goal
) {
975 /* It's been suggested that if the research target is empty then
976 * choose_random_tech() should be called here. */
977 presearch
->tech_goal
= tech
;
978 notify_research(presearch
, NULL
, E_TECH_GOAL
, ftc_server
,
979 _("Technology goal is %s."),
980 research_advance_name_translation(presearch
, tech
));
983 /****************************************************************************
984 Initializes tech data for the research.
985 ****************************************************************************/
986 void init_tech(struct research
*research
, bool update
)
988 research_invention_set(research
, A_NONE
, TECH_KNOWN
);
990 advance_index_iterate(A_FIRST
, i
) {
991 research_invention_set(research
, i
, TECH_UNKNOWN
);
992 } advance_index_iterate_end
;
994 #ifdef TECH_UPKEEP_DEBUGGING
995 /* Print a list of the needed upkeep if 'i' techs are researched.
996 * If the ruleset contains self-rooted techs this can not work! */
998 bool global_state
[A_LAST
];
999 Tech_type_id tech
= A_LAST
;
1001 /* Save the game research state. */
1002 advance_index_iterate(A_FIRST
, i
) {
1003 global_state
[i
] = game
.info
.global_advances
[i
];
1004 } advance_index_iterate_end
;
1006 research
->techs_researched
= 1;
1007 research_update(presearch
);
1009 /* Show research costs. */
1010 advance_index_iterate(A_NONE
, i
) {
1011 log_debug("[research %d] %-25s (ID: %3d) cost: %6d - reachable: %-3s "
1012 "(now) / %-3s (ever)", research_number(research
),
1013 advance_rule_name(advance_by_number(i
)), i
,
1014 research_total_bulbs_required(research
, i
, FALSE
),
1015 research_invention_gettable(research
, i
, FALSE
)
1017 research_invention_reachable(research
, i
) ? "yes" : "no");
1018 } advance_index_iterate_end
;
1020 /* Update step for step each tech as known and print the upkeep. */
1021 while (tech
!= A_NONE
) {
1023 advance_index_iterate(A_FIRST
, i
) {
1024 if (research_invention_state(research
, i
) == TECH_PREREQS_KNOWN
) {
1025 /* Found a tech which can be researched. */
1029 } advance_index_iterate_end
;
1031 if (tech
!= A_NONE
) {
1032 research
->inventions
[tech
].state
= TECH_KNOWN
;
1033 research
->techs_researched
++;
1035 /* This will change the game state! */
1036 research_update(research
);
1038 research_players_iterate(research
, pplayer
) {
1039 log_debug("[player %d] researched: %-25s (ID: %4d) techs: %3d "
1040 "upkeep: %4d", research_number(research
),
1041 advance_rule_name(advance_by_number(tech
)), tech
,
1042 research
->techs_researched
, player_tech_upkeep(pplayer
));
1043 } research_players_iterate_end
;
1047 /* Reset the changes done. */
1048 advance_index_iterate(A_FIRST
, i
) {
1049 research_invention_set(research
, i
, TECH_UNKNOWN
);
1050 game
.info
.global_advances
[i
] = global_state
[i
];
1051 } advance_index_iterate_end
;
1053 #endif /* TECH_UPKEEP_DEBUGGING */
1055 research
->techs_researched
= 1;
1058 Tech_type_id next_tech
;
1060 /* Mark the reachable techs */
1061 research_update(research
);
1063 next_tech
= research_goal_step(research
, research
->tech_goal
);
1064 if (A_UNSET
!= next_tech
) {
1065 choose_tech(research
, next_tech
);
1067 choose_random_tech(research
);
1072 /****************************************************************************
1073 Gives global (read from the game ruleset file) and nation (read from the
1074 nation ruleset files) initial techs as specified in the ruleset, and
1075 random free technologies thanks to the techlevel setting.
1076 ****************************************************************************/
1077 void give_initial_techs(struct research
*presearch
, int num_random_techs
)
1082 for (i
= 0; i
< MAX_NUM_TECH_LIST
; i
++) {
1083 if (game
.rgame
.global_init_techs
[i
] == A_LAST
) {
1086 /* Maybe the player already got this tech by an other way (e.g. team). */
1087 if (research_invention_state(presearch
, game
.rgame
.global_init_techs
[i
])
1089 found_new_tech(presearch
, game
.rgame
.global_init_techs
[i
],
1095 research_players_iterate(presearch
, pplayer
) {
1096 const struct nation_type
*pnation
= nation_of_player(pplayer
);
1098 for (i
= 0; i
< MAX_NUM_TECH_LIST
; i
++) {
1099 if (pnation
->init_techs
[i
] == A_LAST
) {
1102 /* Maybe the player already got this tech by an other way. */
1103 if (research_invention_state(presearch
, pnation
->init_techs
[i
])
1105 found_new_tech(presearch
, pnation
->init_techs
[i
], FALSE
, TRUE
);
1108 } research_players_iterate_end
;
1110 /* Random free techs (N.B.: freecost penalty not applied). */
1111 for (i
= 0; i
< num_random_techs
; i
++) {
1112 found_new_tech(presearch
, pick_random_tech(presearch
), FALSE
, TRUE
);
1116 /****************************************************************************
1117 If victim has a tech which pplayer doesn't have, pplayer will get it.
1118 The clients will both be notified and the conquer cost
1119 penalty applied. Used for diplomats and city conquest.
1120 If preferred is A_UNSET one random tech will be chosen.
1121 Returns the stolen tech or A_NONE if no tech was found.
1122 ****************************************************************************/
1123 Tech_type_id
steal_a_tech(struct player
*pplayer
, struct player
*victim
,
1124 Tech_type_id preferred
)
1126 struct research
*presearch
, *vresearch
;
1127 Tech_type_id stolen_tech
= A_NONE
;
1128 const char *advance_name
;
1129 char research_name
[MAX_LEN_NAME
* 2];
1131 if (get_player_bonus(victim
, EFT_NOT_TECH_SOURCE
) > 0) {
1135 presearch
= research_get(pplayer
);
1136 vresearch
= research_get(victim
);
1138 if (preferred
== A_UNSET
) {
1140 advance_index_iterate(A_FIRST
, i
) {
1141 if (research_invention_gettable(presearch
, i
,
1142 game
.info
.tech_steal_allow_holes
)
1143 && research_invention_state(presearch
, i
) != TECH_KNOWN
1144 && research_invention_state(vresearch
, i
) == TECH_KNOWN
) {
1147 } advance_index_iterate_end
;
1150 /* we've moved on to future tech */
1151 if (vresearch
->future_tech
> presearch
->future_tech
) {
1152 found_new_tech(presearch
, A_FUTURE
, FALSE
, TRUE
);
1153 stolen_tech
= A_FUTURE
;
1158 /* pick random tech */
1160 stolen_tech
= A_NONE
; /* avoid compiler warning */
1161 advance_index_iterate(A_FIRST
, i
) {
1162 if (research_invention_gettable(presearch
, i
,
1163 game
.info
.tech_steal_allow_holes
)
1164 && research_invention_state(presearch
, i
) != TECH_KNOWN
1165 && research_invention_state(vresearch
, i
) == TECH_KNOWN
) {
1172 } advance_index_iterate_end
;
1173 fc_assert(stolen_tech
!= A_NONE
);
1175 } else { /* preferred != A_UNSET */
1176 #ifndef FREECIV_NDEBUG
1177 if (!is_future_tech(preferred
)) {
1178 fc_assert(NULL
!= valid_advance_by_number(preferred
));
1179 fc_assert(TECH_KNOWN
== research_invention_state(vresearch
,
1182 #endif /* FREECIV_NDEBUG */
1183 stolen_tech
= preferred
;
1186 advance_name
= research_advance_name_translation(presearch
, stolen_tech
);
1187 research_pretty_name(presearch
, research_name
, sizeof(research_name
));
1188 notify_player(pplayer
, NULL
, E_MY_DIPLOMAT_THEFT
, ftc_server
,
1189 _("You steal %s from the %s."),
1191 nation_plural_for_player(victim
));
1192 notify_research(presearch
, pplayer
, E_TECH_GAIN
, ftc_server
,
1193 _("The %s stole %s from the %s and shared it with you."),
1194 nation_plural_for_player(pplayer
),
1196 nation_plural_for_player(victim
));
1198 notify_player(victim
, NULL
, E_ENEMY_DIPLOMAT_THEFT
, ftc_server
,
1199 _("The %s stole %s from you!"),
1200 nation_plural_for_player(pplayer
),
1203 notify_research_embassies(presearch
, victim
, E_TECH_EMBASSY
, ftc_server
,
1204 _("The %s have stolen %s from the %s."),
1207 nation_plural_for_player(victim
));
1209 if (tech_transfer(pplayer
, victim
, stolen_tech
)) {
1210 research_apply_penalty(presearch
, stolen_tech
, game
.server
.conquercost
);
1211 found_new_tech(presearch
, stolen_tech
, FALSE
, TRUE
);
1212 script_tech_learned(presearch
, pplayer
, advance_by_number(stolen_tech
),
1220 /****************************************************************************
1221 Handle incoming research packet. Need to check correctness
1222 Set the player to be researching the given tech.
1224 If there are enough accumulated research points, the tech may be
1225 acquired immediately.
1226 ****************************************************************************/
1227 void handle_player_research(struct player
*pplayer
, int tech
)
1229 struct research
*research
= research_get(pplayer
);
1231 if (tech
!= A_FUTURE
&& !valid_advance_by_number(tech
)) {
1235 if (tech
!= A_FUTURE
1236 && research_invention_state(research
, tech
) != TECH_PREREQS_KNOWN
) {
1240 choose_tech(research
, tech
);
1242 /* Notify players sharing the same research. */
1243 send_research_info(research
, NULL
);
1246 /****************************************************************************
1247 Handle incoming player_tech_goal packet
1248 Called from the network or AI code to set the player's tech goal.
1249 ****************************************************************************/
1250 void handle_player_tech_goal(struct player
*pplayer
, int tech_goal
)
1252 struct research
*research
= research_get(pplayer
);
1254 /* Set the tech goal to a defined state if it is
1255 * - not a future tech and not a valid goal
1256 * - not a future tech and not a valid advance
1258 * - known (i.e. due to EFT_GIVE_IMM_TECH). */
1259 if ((tech_goal
!= A_FUTURE
1260 && (!valid_advance_by_number(tech_goal
)
1261 || !research_invention_reachable(research
, tech_goal
)))
1262 || (tech_goal
== A_NONE
)
1263 || (TECH_KNOWN
== research_invention_state(research
, tech_goal
))) {
1264 tech_goal
= A_UNSET
;
1267 choose_tech_goal(research
, tech_goal
);
1269 /* Notify players sharing the same research. */
1270 send_research_info(research
, NULL
);
1273 /****************************************************************************
1274 Gives an immediate free tech. Applies freecost. Returns the tech.
1275 ****************************************************************************/
1276 Tech_type_id
give_immediate_free_tech(struct research
*presearch
)
1280 if (game
.info
.free_tech_method
== FTM_CHEAPEST
) {
1281 tech
= pick_cheapest_tech(presearch
);
1282 } else if (presearch
->researching
== A_UNSET
1283 || game
.info
.free_tech_method
== FTM_RANDOM
) {
1284 tech
= pick_random_tech(presearch
);
1286 tech
= presearch
->researching
;
1288 research_apply_penalty(presearch
, tech
, game
.server
.freecost
);
1289 found_new_tech(presearch
, tech
, FALSE
, TRUE
);
1293 /****************************************************************************
1294 Let the player forget one tech.
1295 ****************************************************************************/
1296 static void forget_tech_transfered(struct player
*pplayer
, Tech_type_id tech
)
1298 struct research
*presearch
= research_get(pplayer
);
1300 research_tech_lost(presearch
, tech
);
1301 /* Make notification after losing the research, in case it is a future
1302 * tech (for getting the right tech number). */
1303 notify_player(pplayer
, NULL
, E_TECH_LOST
, ftc_server
,
1304 _("Too bad! You made a mistake transferring the tech %s and "
1306 research_advance_name_translation(presearch
, tech
));
1307 notify_research(presearch
, pplayer
, E_TECH_LOST
, ftc_server
,
1308 _("Too bad! The %s made a mistake transferring the tech "
1310 nation_plural_for_player(pplayer
),
1311 research_advance_name_translation(presearch
, tech
));
1314 /****************************************************************************
1315 Check if the tech is lost by the donor or receiver. Returns if the
1316 receiver gets a new tech.
1317 ****************************************************************************/
1318 bool tech_transfer(struct player
*plr_recv
, struct player
*plr_donor
,
1321 if (game
.server
.techlost_donor
> 0) {
1322 struct research
*donor_research
= research_get(plr_donor
);
1323 bool donor_can_lose
= TRUE
;
1325 advance_index_iterate(A_FIRST
, i
) {
1326 /* Never let donor lose tech if it's root_req for some other known
1328 if (research_invention_state(donor_research
, i
) == TECH_KNOWN
1329 && (advance_required(i
, AR_ROOT
) == tech
1330 || (!game
.info
.tech_trade_loss_allow_holes
1331 && (advance_required(i
, AR_ONE
) == tech
1332 || advance_required(i
, AR_TWO
) == tech
)))) {
1333 donor_can_lose
= FALSE
;
1336 } advance_index_iterate_end
;
1337 if (donor_can_lose
&& fc_rand(100) < game
.server
.techlost_donor
) {
1338 forget_tech_transfered(plr_donor
, tech
);
1342 if (fc_rand(100) < game
.server
.techlost_recv
) {
1343 forget_tech_transfered(plr_recv
, tech
);