From 9b82ac5852275d61035ec1435ac1a3092c798add Mon Sep 17 00:00:00 2001 From: Marko Lindqvist Date: Mon, 1 Apr 2024 04:05:55 +0300 Subject: [PATCH 50/50] 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