From d66821241b7adb69456ccb2d1ce0cb7ba62ebc65 Mon Sep 17 00:00:00 2001 From: Sveinung Kvilhaugsvik Date: Tue, 11 May 2021 17:56:15 +0200 Subject: [PATCH 13/13] Support destroying a city with attack actions. Move the rule that attack actions like Attack and Bombard won't kill a city's last last citizen to the ruleset via the Unit_No_Lose_Pop effect. See osdn #42243 --- data/alien/effects.ruleset | 8 ++++++++ data/civ1/effects.ruleset | 8 ++++++++ data/civ2/effects.ruleset | 8 ++++++++ data/civ2civ3/effects.ruleset | 8 ++++++++ data/classic/effects.ruleset | 8 ++++++++ data/goldkeep/effects.ruleset | 8 ++++++++ data/multiplayer/effects.ruleset | 8 ++++++++ data/sandbox/effects.ruleset | 8 ++++++++ data/webperimental/effects.ruleset | 8 ++++++++ server/rscompat.c | 9 +++++++++ server/unithand.c | 24 ++++++++++++++++++++---- 11 files changed, 101 insertions(+), 4 deletions(-) diff --git a/data/alien/effects.ruleset b/data/alien/effects.ruleset index 647eb6697c..f5d625c899 100644 --- a/data/alien/effects.ruleset +++ b/data/alien/effects.ruleset @@ -955,6 +955,14 @@ reqs = "MaxUnitsOnTile", "0", "Local" } +[effect_attack_bombard_no_city_destruction] +type = "Unit_No_Lose_Pop" +value = 1 +reqs = + { "type", "name", "range", "present" + "MinSize", "2", "City", FALSE + } + [effect_unit_bribe_cost_settlers] type = "Unit_Bribe_Cost_Pct" value = -50 diff --git a/data/civ1/effects.ruleset b/data/civ1/effects.ruleset index a8d4d05fec..52949f4c97 100644 --- a/data/civ1/effects.ruleset +++ b/data/civ1/effects.ruleset @@ -1364,6 +1364,14 @@ reqs = "MaxUnitsOnTile", "0", "Local" } +[effect_attack_bombard_no_city_destruction] +type = "Unit_No_Lose_Pop" +value = 1 +reqs = + { "type", "name", "range", "present" + "MinSize", "2", "City", FALSE + } + [effect_unit_bribe_cost_settlers] type = "Unit_Bribe_Cost_Pct" value = -50 diff --git a/data/civ2/effects.ruleset b/data/civ2/effects.ruleset index b9d5ab6bae..a6d82d564d 100644 --- a/data/civ2/effects.ruleset +++ b/data/civ2/effects.ruleset @@ -2286,6 +2286,14 @@ reqs = "Extra", "Pollution", "Local" } +[effect_attack_bombard_no_city_destruction] +type = "Unit_No_Lose_Pop" +value = 1 +reqs = + { "type", "name", "range", "present" + "MinSize", "2", "City", FALSE + } + [effect_unit_bribe_cost_settlers] type = "Unit_Bribe_Cost_Pct" value = -50 diff --git a/data/civ2civ3/effects.ruleset b/data/civ2civ3/effects.ruleset index 5afab670ac..580577babb 100644 --- a/data/civ2civ3/effects.ruleset +++ b/data/civ2civ3/effects.ruleset @@ -4097,6 +4097,14 @@ reqs = "OutputType", "Science", "Local", FALSE, TRUE } +[effect_attack_bombard_no_city_destruction] +type = "Unit_No_Lose_Pop" +value = 1 +reqs = + { "type", "name", "range", "present" + "MinSize", "2", "City", FALSE + } + [effect_incident_caught_steal_tech] type = "Casus_Belli_Caught" value = 1 diff --git a/data/classic/effects.ruleset b/data/classic/effects.ruleset index 3cd229690e..04249886b6 100644 --- a/data/classic/effects.ruleset +++ b/data/classic/effects.ruleset @@ -2350,6 +2350,14 @@ reqs = "Extra", "Pollution", "Local" } +[effect_attack_bombard_no_city_destruction] +type = "Unit_No_Lose_Pop" +value = 1 +reqs = + { "type", "name", "range", "present" + "MinSize", "2", "City", FALSE + } + [effect_unit_bribe_cost_settlers] type = "Unit_Bribe_Cost_Pct" value = -50 diff --git a/data/goldkeep/effects.ruleset b/data/goldkeep/effects.ruleset index 7e3dbc2d25..efab91bb64 100644 --- a/data/goldkeep/effects.ruleset +++ b/data/goldkeep/effects.ruleset @@ -2733,6 +2733,14 @@ reqs = "Extra", "Pollution", "Local" } +[effect_attack_bombard_no_city_destruction] +type = "Unit_No_Lose_Pop" +value = 1 +reqs = + { "type", "name", "range", "present" + "MinSize", "2", "City", FALSE + } + [effect_unit_bribe_cost_settlers] type = "Unit_Bribe_Cost_Pct" value = -50 diff --git a/data/multiplayer/effects.ruleset b/data/multiplayer/effects.ruleset index 4309c336e4..260f585b98 100644 --- a/data/multiplayer/effects.ruleset +++ b/data/multiplayer/effects.ruleset @@ -2385,6 +2385,14 @@ reqs = "Extra", "Pollution", "Local" } +[effect_attack_bombard_no_city_destruction] +type = "Unit_No_Lose_Pop" +value = 1 +reqs = + { "type", "name", "range", "present" + "MinSize", "2", "City", FALSE + } + [effect_unit_bribe_cost_settlers] type = "Unit_Bribe_Cost_Pct" value = -50 diff --git a/data/sandbox/effects.ruleset b/data/sandbox/effects.ruleset index 7b812c6cb2..a83d0c4cae 100644 --- a/data/sandbox/effects.ruleset +++ b/data/sandbox/effects.ruleset @@ -4197,6 +4197,14 @@ reqs = "Action", "Steal Maps Escape", "Local", TRUE } +[effect_attack_bombard_no_city_destruction] +type = "Unit_No_Lose_Pop" +value = 1 +reqs = + { "type", "name", "range", "present" + "MinSize", "2", "City", FALSE + } + [effect_incident_caught_steal_tech] type = "Casus_Belli_Caught" value = 1 diff --git a/data/webperimental/effects.ruleset b/data/webperimental/effects.ruleset index 16aa2d0e82..7331807dc2 100644 --- a/data/webperimental/effects.ruleset +++ b/data/webperimental/effects.ruleset @@ -2376,6 +2376,14 @@ reqs = "Extra", "Pollution", "Local" } +[effect_attack_bombard_no_city_destruction] +type = "Unit_No_Lose_Pop" +value = 1 +reqs = + { "type", "name", "range", "present" + "MinSize", "2", "City", FALSE + } + [effect_unit_bribe_cost_settlers] type = "Unit_Bribe_Cost_Pct" value = -50 diff --git a/server/rscompat.c b/server/rscompat.c index 04a590bb8c..8f45ddca5d 100644 --- a/server/rscompat.c +++ b/server/rscompat.c @@ -339,6 +339,15 @@ void rscompat_postprocess(struct rscompat_info *info) FALSE, TRUE, FALSE, action_rule_name(paction))); } action_iterate_end; + + /* That Attack and Bombard can't destroy a city + * has moved to the ruleset. */ + peffect = effect_new(EFT_UNIT_NO_LOSE_POP, + effect_value_will_make_positive( + EFT_UNIT_NO_LOSE_POP), + NULL); + effect_req_append(peffect, req_from_str("MinSize", "City", FALSE, FALSE, + FALSE, "2")); } /* Make sure that all action enablers added or modified by the diff --git a/server/unithand.c b/server/unithand.c index 3343f61357..ed806fa615 100644 --- a/server/unithand.c +++ b/server/unithand.c @@ -4179,15 +4179,31 @@ static void unit_attack_civilian_casualties(const struct unit *punit, struct player *pplayer = unit_owner(punit); if (pcity - && city_size_get(pcity) > 1 && get_target_bonus_effects(NULL, city_owner(pcity), NULL, pcity, NULL, city_tile(pcity), NULL, NULL, NULL, NULL, paction, EFT_UNIT_NO_LOSE_POP) <= 0 && kills_citizen_after_attack(punit)) { - city_reduce_size(pcity, 1, pplayer, reason); - city_refresh(pcity); - send_city_info(NULL, pcity); + struct player *cplayer = city_owner(pcity); + struct tile *ctile = city_tile(pcity); + const char *clink = city_link(pcity); + + if (city_reduce_size(pcity, 1, pplayer, reason)) { + city_refresh(pcity); + send_city_info(NULL, pcity); + } else { + notify_player(pplayer, ctile, E_UNIT_ACTION_ACTOR_SUCCESS, ftc_server, + /* TRANS: Battleship ... Los Angeles ... Bombard */ + _("Your %s destroyed %s by doing %s."), + unit_link(punit), clink, + action_name_translation(paction)); + notify_player(cplayer, ctile, + E_UNIT_ACTION_TARGET_HOSTILE, ftc_server, + /* TRANS: Sigurd I Magnusson ... Alkasse ... Attack */ + _("%s destroyed %s by doing %s."), + player_name(pplayer), clink, + action_name_translation(paction)); + } } } -- 2.30.2