From c86197177a8091f6bd235229a057d3f3030bd388 Mon Sep 17 00:00:00 2001 From: Sveinung Kvilhaugsvik Date: Sat, 19 Jun 2021 10:39:33 +0200 Subject: [PATCH] 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 | 32 +++++++++++++++---------- data/alien/game.ruleset | 20 ++++++++++++++-- data/civ2civ3/game.ruleset | 20 ++++++++++++++-- data/sandbox/game.ruleset | 41 +++++++++++++++++++++++++++++---- data/webperimental/game.ruleset | 19 ++++++++++++++- doc/README.actions | 2 +- server/unithand.c | 17 +------------- 7 files changed, 113 insertions(+), 38 deletions(-) diff --git a/common/actions.c b/common/actions.c index 2a83a98156..516f325bbe 100644 --- a/common/actions.c +++ b/common/actions.c @@ -451,6 +451,24 @@ static void hard_code_oblig_hard_reqs(void) ACTRES_ATTACK, 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, @@ -3961,16 +3979,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) { @@ -4537,6 +4545,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: @@ -5993,8 +6002,7 @@ 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)) + if ((action_id_has_result_safe(act_id, ACTRES_ATTACK)) && tile_city(target_tile) != NULL && !pplayers_at_war(city_owner(tile_city(target_tile)), unit_owner(actor_unit))) { diff --git a/data/alien/game.ruleset b/data/alien/game.ruleset index b7ead7d65d..12f64898af 100644 --- a/data/alien/game.ruleset +++ b/data/alien/game.ruleset @@ -718,7 +718,7 @@ target_reqs = "CityTile", "Center", "Local", FALSE } -[actionenabler_bombard] +[actionenabler_bombard_city] action = "Bombard" actor_reqs = { "type", "name", "range", "present" @@ -728,8 +728,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 30b2428249..dd14be22ef 100644 --- a/data/civ2civ3/game.ruleset +++ b/data/civ2civ3/game.ruleset @@ -983,7 +983,7 @@ target_reqs = "CityTile", "Center", "Local", FALSE } -[actionenabler_bombard] +[actionenabler_bombard_city] action = "Bombard" actor_reqs = { "type", "name", "range", "present" @@ -993,8 +993,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 57c40e2690..6687c9d7df 100644 --- a/data/sandbox/game.ruleset +++ b/data/sandbox/game.ruleset @@ -1391,7 +1391,7 @@ target_reqs = "CityTile", "Center", "Local", FALSE } -[actionenabler_bombard] +[actionenabler_bombard_city] action = "Bombard" actor_reqs = { "type", "name", "range", "present" @@ -1402,11 +1402,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" @@ -1417,8 +1433,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 1a1e7fbe75..f9067d9d0d 100644 --- a/data/webperimental/game.ruleset +++ b/data/webperimental/game.ruleset @@ -1243,7 +1243,7 @@ target_reqs = "CityTile", "Center", "Local", FALSE } -[actionenabler_bombard] +[actionenabler_bombard_city] action = "Bombard" actor_reqs = { "type", "name", "range", "present" @@ -1251,6 +1251,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 ccd8f5b3b5..0d495b9032 100644 --- a/doc/README.actions +++ b/doc/README.actions @@ -709,7 +709,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 without killing them. diff --git a/server/unithand.c b/server/unithand.c index b09e7d3a45..ef5c7761a2 100644 --- a/server/unithand.c +++ b/server/unithand.c @@ -870,7 +870,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: /* Target is a unit stack but a city can block it. */ fc_assert_action(action_get_target_kind(paction) == ATK_UNITS, break); @@ -934,6 +933,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: @@ -4180,21 +4180,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