From 09953bd51e85604206696edb67423cd2775ee59b Mon Sep 17 00:00:00 2001 From: Ihnatus <ignatus31oct@mail.ru> Date: Tue, 27 Sep 2022 01:12:03 +0300 Subject: [PATCH] Split researched bulbs on free and bound This abandons got_tech flags. Caravan or Lua bonuses now go to free bulbs and are not lost or penalized on switch between saved and new researched tech. See OSDN#45685 Signed-off-by: Ihnatus <ignatus31oct@mail.ru> --- ai/default/aitech.c | 4 ++- common/research.h | 8 ++--- server/cityturn.c | 2 +- server/plrhand.c | 2 +- server/savegame/savegame2.c | 6 +++- server/savegame/savegame3.c | 20 +++++++++---- server/scripting/api_server_edit.c | 2 +- server/scripting/api_server_game_methods.c | 23 +++++++------- server/scripting/api_server_game_methods.h | 2 +- server/scripting/tolua_server.pkg | 4 +-- server/srv_main.c | 7 ++--- server/techtools.c | 35 ++++++++++++++-------- server/techtools.h | 3 +- server/unithand.c | 2 +- 14 files changed, 72 insertions(+), 48 deletions(-) diff --git a/ai/default/aitech.c b/ai/default/aitech.c index 305b464604..0eec7d64a4 100644 --- a/ai/default/aitech.c +++ b/ai/default/aitech.c @@ -330,7 +330,9 @@ void dai_manage_tech(struct ai_type *ait, struct player *pplayer) struct ai_tech_choice choice, goal; struct research *research = research_get(pplayer); /* Penalty for switching research */ - int penalty = (research->got_tech ? 0 : research->bulbs_researched); + /* FIXME: get real penalty with game.server.techpenalty and multiresearch */ + int penalty = research->bulbs_researched - research->free_bulbs; + penalty = MAX(penalty, 0); /* Even when we let human to do the final decision, we keep our * wants correctly calculated. Add effect values in */ diff --git a/common/research.h b/common/research.h index 718f843031..f0faba3377 100644 --- a/common/research.h +++ b/common/research.h @@ -62,11 +62,9 @@ struct research { Tech_type_id researching_saved; int bulbs_researching_saved; - /* If the player completed a research this turn, this value is turned on - * and changing targets may be done without penalty. */ - bool got_tech; - /* The same as got_tech but flipped back in choose_tech() */ - bool got_tech_multi; + /* For this amount of bulbs, changing targets this turn + * may be done without penalty. */ + int free_bulbs; struct research_invention { /* One of TECH_UNKNOWN, TECH_KNOWN or TECH_PREREQS_KNOWN. */ diff --git a/server/cityturn.c b/server/cityturn.c index 94d5be36e5..3d75bf3cae 100644 --- a/server/cityturn.c +++ b/server/cityturn.c @@ -3347,7 +3347,7 @@ static void update_city_activity(struct city *pcity) pcity->did_sell = FALSE; pcity->did_buy = FALSE; pcity->airlift = city_airlift_max(pcity); - update_bulbs(pplayer, pcity->prod[O_SCIENCE], FALSE); + update_bulbs(pplayer, pcity->prod[O_SCIENCE], FALSE, FALSE); pplayer->economic.infra_points += get_city_bonus(pcity, EFT_INFRA_POINTS); diff --git a/server/plrhand.c b/server/plrhand.c index 514f3da58e..dff2154f0d 100644 --- a/server/plrhand.c +++ b/server/plrhand.c @@ -3458,5 +3458,5 @@ void update_national_activities(struct player *pplayer, int old_gold) research_get(pplayer)->researching_saved = A_UNKNOWN; /* Reduce the number of bulbs by the amount needed for tech upkeep and * check for finished research */ - update_bulbs(pplayer, -player_tech_upkeep(pplayer), TRUE); + update_bulbs(pplayer, -player_tech_upkeep(pplayer), TRUE, FALSE); } diff --git a/server/savegame/savegame2.c b/server/savegame/savegame2.c index 769c538696..53f5202642 100644 --- a/server/savegame/savegame2.c +++ b/server/savegame/savegame2.c @@ -4921,6 +4921,7 @@ static void sg_load_researches(struct loaddata *loading) int number; const char *str; int i, j; + bool got_tech; /* Check status and return if not OK (sg_success FALSE). */ sg_check_ret(); @@ -4964,9 +4965,12 @@ static void sg_load_researches(struct loaddata *loading) presearch->researching = technology_load(loading->file, "research.r%d.now", i); sg_failure_ret(secfile_lookup_bool(loading->file, - &presearch->got_tech, + &got_tech, "research.r%d.got_tech", i), "%s", secfile_error()); + if (got_tech) { + presearch->free_bulbs = presearch->bulbs_researched; + } str = secfile_lookup_str(loading->file, "research.r%d.done", i); sg_failure_ret(str != NULL, "%s", secfile_error()); diff --git a/server/savegame/savegame3.c b/server/savegame/savegame3.c index f98d6f8647..4df6956c8b 100644 --- a/server/savegame/savegame3.c +++ b/server/savegame/savegame3.c @@ -7205,6 +7205,7 @@ static void sg_load_researches(struct loaddata *loading) const char *str; int i, j; int *vlist_research; + bool got_tech, got_tech_multi; vlist_research = NULL; /* Check status and return if not OK (sg_success FALSE). */ @@ -7248,13 +7249,22 @@ static void sg_load_researches(struct loaddata *loading) "research.r%d.saved", i); presearch->researching = technology_load(loading->file, "research.r%d.now", i); + sg_failure_ret(secfile_lookup_int(loading->file, + &presearch->free_bulbs, + "research.r%d.free_bulbs", i), + "%s", secfile_error()); + + /* 3.0...3.1 datafile format */ sg_failure_ret(secfile_lookup_bool(loading->file, - &presearch->got_tech, + &got_tech, "research.r%d.got_tech", i), "%s", secfile_error()); - sg_failure_ret(secfile_lookup_bool(loading->file, &presearch->got_tech_multi, + sg_failure_ret(secfile_lookup_bool(loading->file, &got_tech_multi, "research.r%d.got_tech_multi", i), "%s", secfile_error()); + if (got_tech || got_tech_multi) { + presearch->free_bulbs = presearch->bulbs_researched; + } str = secfile_lookup_str(loading->file, "research.r%d.done", i); sg_failure_ret(str != NULL, "%s", secfile_error()); @@ -7346,10 +7356,8 @@ static void sg_save_researches(struct savedata *saving) "research.r%d.bulbs", i); technology_save(saving->file, "research.r%d.now", i, presearch->researching); - secfile_insert_bool(saving->file, presearch->got_tech, - "research.r%d.got_tech", i); - secfile_insert_bool(saving->file, presearch->got_tech_multi, - "research.r%d.got_tech_multi", i); + secfile_insert_int(saving->file, presearch->free_bulbs, + "research.r%d.free_bulbs", i); /* Save technology lists as bytevector. Note that technology order is * saved in savefile.technology.order */ advance_index_iterate(A_NONE, tech_id) { diff --git a/server/scripting/api_server_edit.c b/server/scripting/api_server_edit.c index 49c6a67eb6..623a72ce39 100644 --- a/server/scripting/api_server_edit.c +++ b/server/scripting/api_server_edit.c @@ -1094,7 +1094,7 @@ void api_edit_player_give_bulbs(lua_State *L, Player *pplayer, int amount) LUASCRIPT_CHECK_STATE(L); LUASCRIPT_CHECK_SELF(L, pplayer); - update_bulbs(pplayer, amount, TRUE); + update_bulbs(pplayer, amount, TRUE, TRUE); send_research_info(research_get(pplayer), NULL); } diff --git a/server/scripting/api_server_game_methods.c b/server/scripting/api_server_game_methods.c index cfc562de68..895b521687 100644 --- a/server/scripting/api_server_game_methods.c +++ b/server/scripting/api_server_game_methods.c @@ -191,9 +191,17 @@ int api_methods_player_tech_bulbs(lua_State *L, Player *pplayer, if (presearch->researching_saved == tn) { return presearch->bulbs_researching_saved - presearch->bulbs_researched; - } else if (!presearch->got_tech && tn != presearch->researching + } else if (tn != presearch->researching && presearch->bulbs_researched > 0) { - return -presearch->bulbs_researched * game.server.techpenalty / 100; + int bound_bulbs = presearch->bulbs_researched - presearch->free_bulbs; + int penalty; + + if (bound_bulbs <= 0) { + return 0; + } + penalty = bound_bulbs * game.server.techpenalty / 100; + + return -MIN(penalty, presearch->bulbs_researched); } else { return 0; } @@ -201,10 +209,9 @@ int api_methods_player_tech_bulbs(lua_State *L, Player *pplayer, } /**********************************************************************//** - Returns whether pplayer is in "got tech" state and can invest their - remaining rsearched bulbs freely. + Returns bulbs that can be freely transferred to a new research target. **************************************************************************/ -bool api_methods_player_got_tech(lua_State *L, Player *pplayer) +int api_methods_player_free_bulbs(lua_State *L, Player *pplayer) { const struct research *presearch; @@ -213,9 +220,5 @@ bool api_methods_player_got_tech(lua_State *L, Player *pplayer) presearch = research_get(pplayer); LUASCRIPT_CHECK(L, presearch, "player's research not set", 0); - if (game.server.multiresearch) { - return presearch->got_tech_multi; - } else { - return presearch->got_tech; - } + return presearch->free_bulbs; } diff --git a/server/scripting/api_server_game_methods.h b/server/scripting/api_server_game_methods.h index c74a0bd61b..4a6e3d5148 100644 --- a/server/scripting/api_server_game_methods.h +++ b/server/scripting/api_server_game_methods.h @@ -39,6 +39,6 @@ int api_methods_nation_trait_default(lua_State *L, Nation_Type *pnation, const char *tname); int api_methods_player_tech_bulbs(lua_State *L, Player *pplayer, Tech_Type *tech); -bool api_methods_player_got_tech(lua_State *L, Player *pplayer); +int api_methods_player_free_bulbs(lua_State *L, Player *pplayer); #endif /* FC__API_SERVER_GAME_METHODS_H */ diff --git a/server/scripting/tolua_server.pkg b/server/scripting/tolua_server.pkg index ac62a1a426..204c82aeff 100644 --- a/server/scripting/tolua_server.pkg +++ b/server/scripting/tolua_server.pkg @@ -498,8 +498,8 @@ $] /* Additions to common Player module. */ module Player { module properties { - bool api_methods_player_got_tech - @ got_tech (lua_State *L, Player *pplayer); + int api_methods_player_free_bulbs + @ free_bulbs (lua_State *L, Player *pplayer); } int api_methods_player_trait @ trait (lua_State *L, Player *pplayer, const char *tname); diff --git a/server/srv_main.c b/server/srv_main.c index 3c18dca1e2..a741a838db 100644 --- a/server/srv_main.c +++ b/server/srv_main.c @@ -1418,7 +1418,7 @@ static void end_phase(void) } /* Add the researched bulbs to the pool; do *NOT* check for finished * research */ - update_bulbs(pplayer, 0, FALSE); + update_bulbs(pplayer, 0, FALSE, FALSE); } } phase_players_iterate_end; @@ -1440,8 +1440,7 @@ static void end_phase(void) /* Refresh cities */ phase_players_iterate(pplayer) { - research_get(pplayer)->got_tech = FALSE; - research_get(pplayer)->got_tech_multi = FALSE; + research_get(pplayer)->free_bulbs = 0; } phase_players_iterate_end; alive_phase_players_iterate(pplayer) { @@ -3384,7 +3383,7 @@ static void srv_ready(void) players_iterate(pplayer) { /* Check for finished research. */ - update_bulbs(pplayer, 0, TRUE); + update_bulbs(pplayer, 0, TRUE, FALSE); } players_iterate_end; } diff --git a/server/techtools.c b/server/techtools.c index 3a145b2b42..cf0e5b059d 100644 --- a/server/techtools.c +++ b/server/techtools.c @@ -378,11 +378,10 @@ void found_new_tech(struct research *presearch, Tech_type_id tech_found, could_switch = create_current_governments_data(presearch); - /* got_tech allows us to change research without applying techpenalty + /* getting tech allows us to change research without applying techpenalty * (without losing bulbs) */ if (tech_found == presearch->researching) { - presearch->got_tech = TRUE; - presearch->got_tech_multi = TRUE; + presearch->free_bulbs += presearch->bulbs_researched; } presearch->researching_saved = A_UNKNOWN; presearch->techs_researched++; @@ -617,7 +616,8 @@ static bool lose_tech(struct research *research) This is called from each city every turn, from caravan revenue, at the end of the phase, and from lua API. ****************************************************************************/ -void update_bulbs(struct player *pplayer, int bulbs, bool check_tech) +void update_bulbs(struct player *pplayer, int bulbs, bool check_tech, + bool free_bulbs) { struct research *research = research_get(pplayer); @@ -629,6 +629,13 @@ void update_bulbs(struct player *pplayer, int bulbs, bool check_tech) /* count our research contribution this turn */ pplayer->server.bulbs_last_turn += bulbs; research->bulbs_researched += bulbs; + if (A_UNKNOWN != research->researching_saved) { + fc_assert(research->researching_saved != research->researching); + research->bulbs_researching_saved += bulbs; + } + if (free_bulbs) { + research->free_bulbs += bulbs; + } advance_index_iterate(A_FIRST, j) { if (j == research->researching) { research->inventions[j].bulbs_researched_saved = research->bulbs_researched; @@ -640,7 +647,7 @@ void update_bulbs(struct player *pplayer, int bulbs, bool check_tech) /* If we have a negative number of bulbs we do try to: * - reduce the number of future techs; * - or lose one random tech. - * After that the number of bulbs available is incresed based on the + * After that the number of bulbs available is increased based on the * value of the lost tech. */ if (lose_tech(research)) { Tech_type_id tech = (research->future_tech > 0 @@ -985,11 +992,8 @@ void choose_tech(struct research *research, Tech_type_id tech) } } advance_index_iterate_end; research->researching = tech; - if (!research->got_tech_multi) { - research->bulbs_researched = 0; - } - research->bulbs_researched = research->bulbs_researched + bulbs_res; - research->got_tech_multi = FALSE; + research->bulbs_researched = research->free_bulbs + bulbs_res; + research->free_bulbs = 0; if (research->bulbs_researched >= research_total_bulbs_required(research, tech, FALSE)) { tech_researched(research); @@ -997,14 +1001,19 @@ void choose_tech(struct research *research, Tech_type_id tech) return; } - if (!research->got_tech && research->researching_saved == A_UNKNOWN) { + /* The first check implies we have NOT recently got a technology + * and are changing from one we were researching at tc. */ + if (research->bulbs_researched - research->free_bulbs > 0 + && research->researching_saved == A_UNKNOWN) { research->bulbs_researching_saved = research->bulbs_researched; research->researching_saved = research->researching; /* Subtract a penalty because we changed subject. */ if (research->bulbs_researched > 0) { research->bulbs_researched - -= ((research->bulbs_researched * game.server.techpenalty) / 100); - fc_assert(research->bulbs_researched >= 0); + -= ((research->bulbs_researched - research->free_bulbs) + * game.server.techpenalty) / 100; + /* If free_bulbs were for some reason negative... */ + research->bulbs_researched = MAX(research->bulbs_researched, 0); } } else if (tech == research->researching_saved) { research->bulbs_researched = research->bulbs_researching_saved; diff --git a/server/techtools.h b/server/techtools.h index 9fd4130cc5..2a6b385bd9 100644 --- a/server/techtools.h +++ b/server/techtools.h @@ -38,7 +38,8 @@ void script_tech_learned(struct research *presearch, const char *reason); void found_new_tech(struct research *presearch, Tech_type_id tech_found, bool was_discovery, bool saving_bulbs); -void update_bulbs(struct player *pplayer, int bulbs, bool check_tech); +void update_bulbs(struct player *pplayer, int bulbs, bool check_tech, + bool free_bulbs); void init_tech(struct research *presearch, bool update); void choose_tech(struct research *presearch, Tech_type_id tech); void choose_random_tech(struct research *presearch); diff --git a/server/unithand.c b/server/unithand.c index 981fffb773..5a1f6cbb36 100644 --- a/server/unithand.c +++ b/server/unithand.c @@ -5970,7 +5970,7 @@ static bool do_unit_establish_trade(struct player *pplayer, if (bonus_type == TBONUS_SCIENCE || bonus_type == TBONUS_BOTH) { /* add bulbs and check for finished research */ - update_bulbs(pplayer, revenue, TRUE); + update_bulbs(pplayer, revenue, TRUE, TRUE); /* Inform everyone about tech changes */ send_research_info(research_get(pplayer), NULL); -- 2.34.1