From eac4b59250432d5149c548a997598fe427928e9c Mon Sep 17 00:00:00 2001 From: Sveinung Kvilhaugsvik Date: Sat, 19 Jun 2021 10:39:33 +0200 Subject: [PATCH 4/5] Make can't bomb non war city hard req obligatory. The bombard actions can't bomb units in cities not owned by someone the actor player is at war with. Make this an obligatory hard requirement. See osdn #42552 --- common/actions.c | 30 +++++++++++++++--------- data/alien/game.ruleset | 20 ++++++++++++++-- data/civ2civ3/game.ruleset | 20 ++++++++++++++-- data/sandbox/game.ruleset | 41 +++++++++++++++++++++++++++++---- data/webperimental/game.ruleset | 19 ++++++++++++++- doc/README.actions | 4 ++-- server/unithand.c | 17 +------------- 7 files changed, 113 insertions(+), 38 deletions(-) diff --git a/common/actions.c b/common/actions.c index 32e4108bd0..bf7af7d9b6 100644 --- a/common/actions.c +++ b/common/actions.c @@ -453,6 +453,24 @@ static void hard_code_oblig_hard_reqs(void) ACTRES_WIPE_UNITS, ACTRES_NONE); + /* Why this is a hard requirement: assumed by the Freeciv code. */ + oblig_hard_req_reg(req_contradiction_or( + 2, + req_from_values(VUT_DIPLREL_TILE_O, + REQ_RANGE_LOCAL, + FALSE, FALSE, TRUE, DS_WAR), + TRUE, + req_from_values(VUT_CITYTILE, REQ_RANGE_LOCAL, + FALSE, TRUE, TRUE, + CITYT_CENTER), + TRUE), + N_("All action enablers for %s must require" + " that the actor is at war with the owner of the" + " target tile or that the target tile doesn't have" + " a city."), + ACTRES_BOMBARD, + ACTRES_NONE); + /* Why this is a hard requirement: Keep the old rules. Need to work * out corner cases. */ oblig_hard_req_register(req_from_values(VUT_DIPLREL, REQ_RANGE_LOCAL, @@ -4004,16 +4022,6 @@ is_action_possible(const action_id wanted_action, break; - case ACTRES_BOMBARD: - if (tile_city(target_tile) - && !pplayers_at_war(city_owner(tile_city(target_tile)), - actor_player)) { - return TRI_NO; - } - - break; - - case ACTRES_NUKE_UNITS: if (unit_attack_units_at_tile_result(actor_unit, paction, target_tile) != ATT_OK) { @@ -4600,6 +4608,7 @@ is_action_possible(const action_id wanted_action, case ACTRES_SPY_INCITE_CITY: case ACTRES_SPY_SABOTAGE_UNIT: case ACTRES_STEAL_MAPS: + case ACTRES_BOMBARD: case ACTRES_SPY_NUKE: case ACTRES_NUKE: case ACTRES_DESTROY_CITY: @@ -6071,7 +6080,6 @@ action_prob_vs_units_full(const struct unit* actor_unit, } if ((action_id_has_result_safe(act_id, ACTRES_ATTACK) - || action_id_has_result_safe(act_id, ACTRES_BOMBARD) || action_id_has_result_safe(act_id, ACTRES_WIPE_UNITS)) && tile_city(target_tile) != NULL && !pplayers_at_war(city_owner(tile_city(target_tile)), diff --git a/data/alien/game.ruleset b/data/alien/game.ruleset index 6fbae3890c..19c0732e25 100644 --- a/data/alien/game.ruleset +++ b/data/alien/game.ruleset @@ -726,7 +726,7 @@ target_reqs = "CityTile", "Center", "Local", FALSE } -[actionenabler_bombard] +[actionenabler_bombard_city] action = "Bombard" actor_reqs = { "type", "name", "range", "present" @@ -736,8 +736,24 @@ actor_reqs = "DiplRel", "War", "Local", TRUE } target_reqs = - { "type", "name", "range", "present" + { "type", "name", "range", "present" + "TerrainClass", "Oceanic", "Local", FALSE + "DiplRelTileOther", "War", "Local", TRUE + } + +[actionenabler_bombard_no_city] +action = "Bombard" +actor_reqs = + { "type", "name", "range", "present" + "UnitFlag", "Bombarder", "Local", TRUE + "UnitState", "Transported", "Local", FALSE + "MinMoveFrags", "1", "Local", TRUE + "DiplRel", "War", "Local", TRUE + } +target_reqs = + { "type", "name", "range", "present" "TerrainClass", "Oceanic", "Local", FALSE + "CityTile", "Center", "Local", FALSE } [actionenabler_build_city_pioneer] diff --git a/data/civ2civ3/game.ruleset b/data/civ2civ3/game.ruleset index de6fdfde6e..6548837c63 100644 --- a/data/civ2civ3/game.ruleset +++ b/data/civ2civ3/game.ruleset @@ -991,7 +991,7 @@ target_reqs = "CityTile", "Center", "Local", FALSE } -[actionenabler_bombard] +[actionenabler_bombard_city] action = "Bombard" actor_reqs = { "type", "name", "range", "present" @@ -1001,8 +1001,24 @@ actor_reqs = "DiplRel", "War", "Local", TRUE } target_reqs = - { "type", "name", "range", "present" + { "type", "name", "range", "present" + "TerrainClass", "Oceanic", "Local", FALSE + "DiplRelTileOther", "War", "Local", TRUE + } + +[actionenabler_bombard_no_city] +action = "Bombard" +actor_reqs = + { "type", "name", "range", "present" + "UnitFlag", "Bombarder", "Local", TRUE + "UnitState", "Transported", "Local", FALSE + "MinMoveFrags", "1", "Local", TRUE + "DiplRel", "War", "Local", TRUE + } +target_reqs = + { "type", "name", "range", "present" "TerrainClass", "Oceanic", "Local", FALSE + "CityTile", "Center", "Local", FALSE } [actionenabler_build_city_pioneer] diff --git a/data/sandbox/game.ruleset b/data/sandbox/game.ruleset index 60807122e0..18c1442b8b 100644 --- a/data/sandbox/game.ruleset +++ b/data/sandbox/game.ruleset @@ -1413,7 +1413,7 @@ target_reqs = "CityTile", "Center", "Local", FALSE } -[actionenabler_bombard] +[actionenabler_bombard_city] action = "Bombard" actor_reqs = { "type", "name", "range", "present" @@ -1424,11 +1424,27 @@ actor_reqs = "Building", "Treuga Dei", "World", FALSE } target_reqs = - { "type", "name", "range", "present" + { "type", "name", "range", "present" + "TerrainClass", "Oceanic", "Local", FALSE + "DiplRelTileOther", "War", "Local", TRUE + } + +[actionenabler_bombard_no_city] +action = "Bombard" +actor_reqs = + { "type", "name", "range", "present" + "UnitFlag", "Bombarder", "Local", TRUE + "UnitState", "Transported", "Local", FALSE + "MinMoveFrags", "1", "Local", TRUE + "DiplRel", "War", "Local", TRUE + } +target_reqs = + { "type", "name", "range", "present" "TerrainClass", "Oceanic", "Local", FALSE + "CityTile", "Center", "Local", FALSE } -[actionenabler_bombard_despite_treuga_dei] +[actionenabler_bombard_city_despite_treuga_dei] action = "Bombard" actor_reqs = { "type", "name", "range", "present", "survives" @@ -1439,8 +1455,25 @@ actor_reqs = "Tech", "Communism", "World", TRUE, TRUE } target_reqs = - { "type", "name", "range", "present" + { "type", "name", "range", "present" + "TerrainClass", "Oceanic", "Local", FALSE + "DiplRelTileOther", "War", "Local", TRUE + } + +[actionenabler_bombard_no_city_despite_treuga_dei] +action = "Bombard" +actor_reqs = + { "type", "name", "range", "present", "survives" + "UnitFlag", "Bombarder", "Local", TRUE, FALSE + "UnitState", "Transported", "Local", FALSE, FALSE + "MinMoveFrags", "1", "Local", TRUE, FALSE + "DiplRel", "War", "Local", TRUE, FALSE + "Tech", "Communism", "World", TRUE, TRUE + } +target_reqs = + { "type", "name", "range", "present" "TerrainClass", "Oceanic", "Local", FALSE + "CityTile", "Center", "Local", FALSE } [actionenabler_build_city_pioneer] diff --git a/data/webperimental/game.ruleset b/data/webperimental/game.ruleset index b2125e2f1d..e090de9dd6 100644 --- a/data/webperimental/game.ruleset +++ b/data/webperimental/game.ruleset @@ -1251,7 +1251,7 @@ target_reqs = "CityTile", "Center", "Local", FALSE } -[actionenabler_bombard] +[actionenabler_bombard_city] action = "Bombard" actor_reqs = { "type", "name", "range", "present" @@ -1259,6 +1259,23 @@ actor_reqs = "MinMoveFrags", "1", "Local", TRUE "DiplRel", "War", "Local", TRUE } +target_reqs = + { "type", "name", "range", "present" + "DiplRelTileOther", "War", "Local", TRUE + } + +[actionenabler_bombard_no_city] +action = "Bombard" +actor_reqs = + { "type", "name", "range", "present" + "UnitFlag", "Bombarder", "Local", TRUE + "MinMoveFrags", "1", "Local", TRUE + "DiplRel", "War", "Local", TRUE + } +target_reqs = + { "type", "name", "range", "present" + "CityTile", "Center", "Local", FALSE + } [actionenabler_attack_from_native] action = "Attack" diff --git a/doc/README.actions b/doc/README.actions index 2e36865a4f..662257e148 100644 --- a/doc/README.actions +++ b/doc/README.actions @@ -719,7 +719,7 @@ Actions done by a unit against all units at a tile * actor must have an attack > 0 * actor must be on a tile next to the target or, if bombard_max_range allows it, futher away. - * target can't be in a city the actor player isn't at war with. + * target can't be in a city the actor player isn't at war with. (!) * target owner must be at war with actor. (!) "Bombard 2" - bombard the units (and city) at the tile. @@ -748,7 +748,7 @@ Actions done by a unit against all units at a tile * actor must have an attack > 0 * actor must be on a tile next to the target or, if bombard_lethal_max_range allows it, futher away. - * target can't be in a city the actor player isn't at war with. + * target can't be in a city the actor player isn't at war with. (!) * target owner must be at war with actor. (!) "Attack" diff --git a/server/unithand.c b/server/unithand.c index f32243b143..ec13c16616 100644 --- a/server/unithand.c +++ b/server/unithand.c @@ -954,7 +954,6 @@ static struct player *need_war_player_hlp(const struct unit *actor, /* Look for hard coded war requirements without support for looking up in * an action enabler requirement. */ switch (paction->result) { - case ACTRES_BOMBARD: case ACTRES_ATTACK: case ACTRES_WIPE_UNITS: /* Target is a unit stack but a city can block it. */ @@ -1020,6 +1019,7 @@ static struct player *need_war_player_hlp(const struct unit *actor, case ACTRES_HEAL_UNIT: case ACTRES_STRIKE_BUILDING: case ACTRES_STRIKE_PRODUCTION: + case ACTRES_BOMBARD: case ACTRES_CONQUER_CITY: case ACTRES_TRANSFORM_TERRAIN: case ACTRES_CULTIVATE: @@ -4339,21 +4339,6 @@ static bool unit_bombard(struct unit *punit, struct tile *ptile, unit_rule_name(punit), TILE_XY(ptile)); unit_list_iterate_safe(ptile->units, pdefender) { - - /* Sanity checks */ - fc_assert_ret_val_msg(!pplayers_non_attack(unit_owner(punit), - unit_owner(pdefender)), - FALSE, - "Trying to attack a unit with which you have " - "peace or cease-fire at (%d, %d).", - TILE_XY(unit_tile(pdefender))); - fc_assert_ret_val_msg(!pplayers_allied(unit_owner(punit), - unit_owner(pdefender)), - FALSE, - "Trying to attack a unit with which you have " - "alliance at (%d, %d).", - TILE_XY(unit_tile(pdefender))); - if (is_unit_reachable_at(pdefender, punit, ptile)) { bool adj; enum direction8 facing; -- 2.30.2