From 3c15de9df7d52bcf8200a4833844192ee4ab4dae Mon Sep 17 00:00:00 2001 From: Marko Lindqvist Date: Fri, 5 Apr 2024 16:38:34 +0300 Subject: [PATCH 1/3] Update to Freeciv server freeciv/freeciv@5d3d7f1af1 Signed-off-by: Marko Lindqvist --- freeciv/version.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/freeciv/version.txt b/freeciv/version.txt index 487288869..e0eb39f4a 100644 --- a/freeciv/version.txt +++ b/freeciv/version.txt @@ -1,9 +1,9 @@ # The Git SHA hash for the commit to checkout from # https://github.com/freeciv/freeciv -FCREV=d19ae091673f8d49f9ca48c39c7c3c017ad19887 +FCREV=5d3d7f1af11bb6703784b957447017507df82774 -ORIGCAPSTR="+Freeciv.Devel-\${MAIN_VERSION}-2024.Feb.28" +ORIGCAPSTR="+Freeciv.Devel-\${MAIN_VERSION}-2024.Mar.08" # There's no need to bump this constantly as current freeciv-web # makes no connections to outside world - all connections are From 745f6d41a1dc35816830449132256ed4c4c82575 Mon Sep 17 00:00:00 2001 From: Marko Lindqvist Date: Sat, 6 Apr 2024 21:14:52 +0300 Subject: [PATCH 2/3] Server: Backport 0038-AI-Delay-war-declaration-until-really-revolted.patch Signed-off-by: Marko Lindqvist --- freeciv/apply_patches.sh | 4 + ...ar-declaration-until-really-revolted.patch | 258 ++++++++++++++++++ 2 files changed, 262 insertions(+) create mode 100644 freeciv/patches/backports/0038-AI-Delay-war-declaration-until-really-revolted.patch diff --git a/freeciv/apply_patches.sh b/freeciv/apply_patches.sh index 3f401e7b0..e07ff497b 100755 --- a/freeciv/apply_patches.sh +++ b/freeciv/apply_patches.sh @@ -21,6 +21,9 @@ # 0051-Adjust-nationality-of-remaining-units-after-player-r.patch # Fix to player removal # RM #383 +# 0038-AI-Delay-war-declaration-until-really-revolted.patch +# AI senate dismissal fix +# osdn #48018 # Not in the upstream Freeciv server # ---------------------------------- @@ -49,6 +52,7 @@ declare -a PATCHLIST=( "backports/0002-Fix-allied-victory-of-all-players" "backports/0041-Stop-sending-hidden-resources-to-the-client" "backports/0051-Adjust-nationality-of-remaining-units-after-player-r" + "backports/0038-AI-Delay-war-declaration-until-really-revolted" "RevertAmplio2ExtraUnits" "meson_webperimental" "metachange" diff --git a/freeciv/patches/backports/0038-AI-Delay-war-declaration-until-really-revolted.patch b/freeciv/patches/backports/0038-AI-Delay-war-declaration-until-really-revolted.patch new file mode 100644 index 000000000..7f5912773 --- /dev/null +++ b/freeciv/patches/backports/0038-AI-Delay-war-declaration-until-really-revolted.patch @@ -0,0 +1,258 @@ +From e6a03444059c7b1b0e2ab87c2bdf8c31379c9e73 Mon Sep 17 00:00:00 2001 +From: Marko Lindqvist +Date: Mon, 1 Apr 2024 04:05:55 +0300 +Subject: [PATCH 38/51] AI: Delay war declaration until really revolted + +If senate is blocking war declaration, don't try to +declare war as soon as have only decided to overthrow the senate. +Instead store the war target and wait until senate is +really overthrown before declaring the war + +See osdn #48018 + +Signed-off-by: Marko Lindqvist +--- + ai/classic/classicai.c | 12 +++++++ + ai/default/daidata.h | 7 ++-- + ai/default/daidiplomacy.c | 69 +++++++++++++++++++++++++++++---------- + ai/default/daidiplomacy.h | 3 ++ + ai/tex/texai.c | 11 +++++++ + common/ai.h | 3 ++ + server/plrhand.c | 2 ++ + 7 files changed, 87 insertions(+), 20 deletions(-) + +diff --git a/ai/classic/classicai.c b/ai/classic/classicai.c +index 7e11ee6206..6e47c6dded 100644 +--- a/ai/classic/classicai.c ++++ b/ai/classic/classicai.c +@@ -579,6 +579,16 @@ static void cai_consider_wonder_city(struct city *pcity, bool *result) + dai_consider_wonder_city(deftype, pcity, result); + } + ++/**********************************************************************//** ++ Call default ai with classic ai type as parameter. ++**************************************************************************/ ++static void cai_revolution_start(struct player *pplayer) ++{ ++ struct ai_type *deftype = classic_ai_get_self(); ++ ++ dai_revolution_start(deftype, pplayer); ++} ++ + /**********************************************************************//** + Setup player ai_funcs function pointers. + **************************************************************************/ +@@ -691,5 +701,7 @@ bool fc_ai_classic_setup(struct ai_type *ai) + /* ai->funcs.city_info = NULL; */ + /* ai->funcs.unit_info = NULL; */ + ++ ai->funcs.revolution_start = cai_revolution_start; ++ + return TRUE; + } +diff --git a/ai/default/daidata.h b/ai/default/daidata.h +index 756d526984..80b169bf9c 100644 +--- a/ai/default/daidata.h ++++ b/ai/default/daidata.h +@@ -75,11 +75,11 @@ struct ai_plr + int last_num_oceans; + + struct { +- int passengers; /* number of passengers waiting for boats */ ++ int passengers; /* Number of passengers waiting for boats */ + int boats; + int available_boats; + +- int *workers; /* cities to workers on continent */ ++ int *workers; /* Cities to workers on continent */ + int *ocean_workers; + + bv_id diplomat_reservations; +@@ -89,11 +89,12 @@ struct ai_plr + struct { + const struct ai_dip_intel **player_intel_slots; + enum winning_strategy strategy; +- int timer; /* pursue our goals with some stubbornness, in turns */ ++ int timer; /* Pursue our goals with some stubbornness, in turns */ + char love_coeff; /* Reduce love with this % each turn */ + char love_incr; /* Modify love with this fixed amount */ + int req_love_for_peace; + int req_love_for_alliance; ++ struct player *war_target; + } diplomacy; + + /* Cache map for AI settlers; defined in daisettler.c. */ +diff --git a/ai/default/daidiplomacy.c b/ai/default/daidiplomacy.c +index f28b6c9f23..6ac46a7fb8 100644 +--- a/ai/default/daidiplomacy.c ++++ b/ai/default/daidiplomacy.c +@@ -1299,6 +1299,41 @@ static void dai_share(struct ai_type *ait, struct player *pplayer, + } + } + ++/******************************************************************//** ++ AI to declare war. ++ ++ @param ait AI type of the player declaring war ++ @param pplayer Player declaring war ++ @param target Player to declare war to ++**********************************************************************/ ++static void dai_declare_war(struct ai_type *ait, struct player *pplayer, ++ struct player *target) ++{ ++ struct ai_dip_intel *adip = dai_diplomacy_get(ait, pplayer, target); ++ ++ /* This will take us straight to war. */ ++ while (player_diplstate_get(pplayer, target)->type != DS_WAR) { ++ if (pplayer_can_cancel_treaty(pplayer, target) != DIPL_OK) { ++ DIPLO_LOG(ait, LOG_ERROR, pplayer, target, ++ "Wanted to cancel treaty but was unable to."); ++ adip->countdown = -1; /* War declaration aborted */ ++ ++ return; ++ } ++ handle_diplomacy_cancel_pact(pplayer, player_number(target), clause_type_invalid()); ++ } ++ ++ /* Throw a tantrum */ ++ if (pplayer->ai_common.love[player_index(target)] > 0) { ++ pplayer->ai_common.love[player_index(target)] = -1; ++ } ++ pplayer->ai_common.love[player_index(target)] -= MAX_AI_LOVE / 8; ++ ++ fc_assert(!gives_shared_vision(pplayer, target)); ++ ++ DIPLO_LOG(ait, LOG_DIPL, pplayer, target, "war declared"); ++} ++ + /******************************************************************//** + Go to war. Explain to target why we did it, and set countdown to + some negative value to make us a bit stubborn to avoid immediate +@@ -1380,6 +1415,8 @@ static void dai_go_to_war(struct ai_type *ait, struct player *pplayer, + pplayer->government = real_gov; + handle_player_change_government(pplayer, + game.info.government_during_revolution_id); ++ def_ai_player_data(pplayer, ait)->diplomacy.war_target = target; ++ return; + } else { + /* There would be Senate even during revolution. Better not to revolt for nothing */ + pplayer->government = real_gov; +@@ -1392,26 +1429,24 @@ static void dai_go_to_war(struct ai_type *ait, struct player *pplayer, + } + } + +- /* This will take us straight to war. */ +- while (player_diplstate_get(pplayer, target)->type != DS_WAR) { +- if (pplayer_can_cancel_treaty(pplayer, target) != DIPL_OK) { +- DIPLO_LOG(ait, LOG_ERROR, pplayer, target, +- "Wanted to cancel treaty but was unable to."); +- adip->countdown = -1; /* War declaration aborted */ ++ dai_declare_war(ait, pplayer, target); ++} + +- return; +- } +- handle_diplomacy_cancel_pact(pplayer, player_number(target), clause_type_invalid()); +- } ++/******************************************************************//** ++ Revolution start callback for default AI. + +- /* Throw a tantrum */ +- if (pplayer->ai_common.love[player_index(target)] > 0) { +- pplayer->ai_common.love[player_index(target)] = -1; +- } +- pplayer->ai_common.love[player_index(target)] -= MAX_AI_LOVE / 8; ++ @param ait AI type of the player revolting ++ @param pplayer Player revolting ++**********************************************************************/ ++void dai_revolution_start(struct ai_type *ait, struct player *pplayer) ++{ ++ struct ai_plr *data = def_ai_player_data(pplayer, ait); + +- fc_assert(!gives_shared_vision(pplayer, target)); +- DIPLO_LOG(ait, LOG_DIPL, pplayer, target, "war declared"); ++ if (data->diplomacy.war_target != NULL) { ++ dai_declare_war(ait, pplayer, data->diplomacy.war_target); ++ ++ data->diplomacy.war_target = NULL; ++ } + } + + /******************************************************************//** +diff --git a/ai/default/daidiplomacy.h b/ai/default/daidiplomacy.h +index 77b5c76f45..74e4a10e39 100644 +--- a/ai/default/daidiplomacy.h ++++ b/ai/default/daidiplomacy.h +@@ -13,6 +13,7 @@ + #ifndef FC__DAIDIPLOMACY_H + #define FC__DAIDIPLOMACY_H + ++/* common */ + #include "fc_types.h" + + #include "ai.h" /* incident_type */ +@@ -40,4 +41,6 @@ bool dai_on_war_footing(struct ai_type *ait, struct player *pplayer); + void dai_diplomacy_first_contact(struct ai_type *ait, struct player *pplayer, + struct player *aplayer); + ++void dai_revolution_start(struct ai_type *ait, struct player *pplayer); ++ + #endif /* FC__DAIDIPLOMACY_H */ +diff --git a/ai/tex/texai.c b/ai/tex/texai.c +index e7f39c1ab2..e7aded9e8e 100644 +--- a/ai/tex/texai.c ++++ b/ai/tex/texai.c +@@ -566,6 +566,15 @@ static void texwai_refresh(struct player *pplayer) + TEXAI_TFUNC(texai_refresh, pplayer); + } + ++/**********************************************************************//** ++ Call default ai with tex ai type as parameter. ++**************************************************************************/ ++static void texwai_revolution_start(struct player *pplayer) ++{ ++ TEXAI_AIT; ++ TEXAI_TFUNC(dai_revolution_start, pplayer); ++} ++ + /**********************************************************************//** + Return module capability string + **************************************************************************/ +@@ -676,5 +685,7 @@ bool fc_ai_tex_setup(struct ai_type *ai) + ai->funcs.city_info = texai_city_changed; + ai->funcs.unit_info = texai_unit_changed; + ++ ai->funcs.revolution_start = texwai_revolution_start; ++ + return TRUE; + } +diff --git a/common/ai.h b/common/ai.h +index 5162d611e8..22c568dda3 100644 +--- a/common/ai.h ++++ b/common/ai.h +@@ -316,6 +316,9 @@ struct ai_type + */ + void (*unit_info)(struct unit *punit); + ++ /* Called for player AI when revolution starts. */ ++ void (*revolution_start)(struct player *pplayer); ++ + /* These are here reserving space for future optional callbacks. + * This way we don't need to change the mandatory capability of the AI module + * interface when adding such callbacks, but existing modules just have these +diff --git a/server/plrhand.c b/server/plrhand.c +index 8b796b3f43..2ce80c4366 100644 +--- a/server/plrhand.c ++++ b/server/plrhand.c +@@ -621,6 +621,8 @@ void handle_player_change_government(struct player *pplayer, + government_rule_name(pplayer->target_government), + pplayer->revolution_finishes, game.info.turn); + ++ CALL_PLR_AI_FUNC(revolution_start, pplayer, pplayer); ++ + /* Now see if the revolution is instantaneous. */ + if (turns <= 0 + && pplayer->target_government != game.government_during_revolution) { +-- +2.43.0 + From 9810e59d54367f7d8432852016b467e2a0e7501f Mon Sep 17 00:00:00 2001 From: Marko Lindqvist Date: Sun, 7 Apr 2024 01:41:02 +0300 Subject: [PATCH 3/3] Server: Backport 0053-AI-Fix-bad-city-spot-value-calculation-with-unknown-.patch Signed-off-by: Marko Lindqvist --- freeciv/apply_patches.sh | 4 ++ ...spot-value-calculation-with-unknown-.patch | 51 +++++++++++++++++++ 2 files changed, 55 insertions(+) create mode 100644 freeciv/patches/backports/0053-AI-Fix-bad-city-spot-value-calculation-with-unknown-.patch diff --git a/freeciv/apply_patches.sh b/freeciv/apply_patches.sh index e07ff497b..9a888596d 100755 --- a/freeciv/apply_patches.sh +++ b/freeciv/apply_patches.sh @@ -24,6 +24,9 @@ # 0038-AI-Delay-war-declaration-until-really-revolted.patch # AI senate dismissal fix # osdn #48018 +# 0053-AI-Fix-bad-city-spot-value-calculation-with-unknown-.patch +# AI city spot evaluation fix +# RM #408 # Not in the upstream Freeciv server # ---------------------------------- @@ -53,6 +56,7 @@ declare -a PATCHLIST=( "backports/0041-Stop-sending-hidden-resources-to-the-client" "backports/0051-Adjust-nationality-of-remaining-units-after-player-r" "backports/0038-AI-Delay-war-declaration-until-really-revolted" + "backports/0053-AI-Fix-bad-city-spot-value-calculation-with-unknown-" "RevertAmplio2ExtraUnits" "meson_webperimental" "metachange" diff --git a/freeciv/patches/backports/0053-AI-Fix-bad-city-spot-value-calculation-with-unknown-.patch b/freeciv/patches/backports/0053-AI-Fix-bad-city-spot-value-calculation-with-unknown-.patch new file mode 100644 index 000000000..2ca305856 --- /dev/null +++ b/freeciv/patches/backports/0053-AI-Fix-bad-city-spot-value-calculation-with-unknown-.patch @@ -0,0 +1,51 @@ +From 940ce754eba1d509a24b11427f715e8ef2306075 Mon Sep 17 00:00:00 2001 +From: Marko Lindqvist +Date: Sun, 7 Apr 2024 00:35:33 +0300 +Subject: [PATCH 53/53] AI: Fix bad city spot value calculation with unknown + tiles + +Unknown and already worked tiles counted as negative output value. +Now they count as 0, as they cannot produce anything for the city. + +See RM #408 + +Signed-off-by: Marko Lindqvist +--- + ai/default/daisettler.c | 15 ++++++++++----- + 1 file changed, 10 insertions(+), 5 deletions(-) + +diff --git a/ai/default/daisettler.c b/ai/default/daisettler.c +index 7372167d81..3395dfa9e8 100644 +--- a/ai/default/daisettler.c ++++ b/ai/default/daisettler.c +@@ -374,17 +374,22 @@ static struct cityresult *cityresult_fill(struct ai_type *ait, + result->best_other.tile = ptile; + result->best_other.cindex = cindex; + } else if (ptdc->sum > result->best_other.tdc->sum) { +- /* First add other other to remaining */ +- result->remaining += result->best_other.tdc->sum +- / GROWTH_POTENTIAL_DEEMPHASIS; ++ /* First add other other to remaining, unless it's unavailable (value < 0) tile. */ ++ if (result->best_other.tdc->sum > 0) { ++ result->remaining += result->best_other.tdc->sum ++ / GROWTH_POTENTIAL_DEEMPHASIS; ++ } + /* Then make new best other */ + result->best_other.tdc = ptdc; + result->best_other.tile = ptile; + result->best_other.cindex = cindex; + } else { + /* Save total remaining calculation, divided by crowdedness +- * of the area and the emphasis placed on space for growth. */ +- result->remaining += ptdc->sum / GROWTH_POTENTIAL_DEEMPHASIS; ++ * of the area and the emphasis placed on space for growth. ++ * Do not add unavailable (value < 0) tiles. */ ++ if (ptdc->sum > 0) { ++ result->remaining += ptdc->sum / GROWTH_POTENTIAL_DEEMPHASIS; ++ } + } + + tile_data_cache_hash_replace(result->tdc_hash, cindex, ptdc); +-- +2.43.0 +