From a1ca8c4353d9c6298c19a786efe66a8d2fb1085c Mon Sep 17 00:00:00 2001 From: Marko Lindqvist Date: Wed, 11 Oct 2023 03:41:32 +0300 Subject: [PATCH 47/47] Allow attacks with or against flagless units always See osdn #48836 Signed-off-by: Marko Lindqvist --- common/combat.c | 22 ++++++++++++---------- common/oblig_reqs.c | 13 ------------- doc/README.actions | 6 +++--- server/unithand.c | 34 +++++++++++++++++++++++----------- server/unittools.c | 5 ++++- 5 files changed, 42 insertions(+), 38 deletions(-) diff --git a/common/combat.c b/common/combat.c index d52fa5c45e..a6552696a8 100644 --- a/common/combat.c +++ b/common/combat.c @@ -42,23 +42,24 @@ 3) the tile contains a non-enemy unit ***********************************************************************/ static bool can_player_attack_tile(const struct player *pplayer, - const struct tile *ptile) + const struct tile *ptile) { struct city *pcity = tile_city(ptile); - + /* 1. Is there anyone there at all? */ - if (!pcity && unit_list_size((ptile->units)) == 0) { + if (pcity == NULL && unit_list_size((ptile->units)) == 0) { return FALSE; } /* 2. If there is a city there, can we attack it? */ - if (pcity && !pplayers_at_war(city_owner(pcity), pplayer)) { + if (pcity != NULL && !pplayers_at_war(city_owner(pcity), pplayer)) { return FALSE; } /* 3. Are we allowed to attack _all_ units there? */ unit_list_iterate(ptile->units, aunit) { - if (!pplayers_at_war(unit_owner(aunit), pplayer)) { + if (!unit_has_type_flag(aunit, UTYF_FLAGLESS) + && !pplayers_at_war(unit_owner(aunit), pplayer)) { /* Enemy hiding behind a human/diplomatic shield */ return FALSE; } @@ -181,8 +182,8 @@ unit_attack_unit_at_tile_result(const struct unit *punit, /*******************************************************************//** When unreachable_protects setting is TRUE: - To attack a stack, unit must be able to attack every unit there (not - including transported units and UTYF_NEVER_PROTECTS units). + To attack a stack, unit must be able to attack every unit there + (not including transported units and UTYF_NEVER_PROTECTS units). ************************************************************************/ static enum unit_attack_result unit_attack_all_at_tile_result(const struct unit *punit, @@ -193,9 +194,9 @@ unit_attack_all_at_tile_result(const struct unit *punit, bool any_neverprotect_unit = FALSE; unit_list_iterate(ptile->units, aunit) { - /* HACK: we don't count transported units here. This prevents some + /* HACK: We don't count transported units here. This prevents some * bugs like a submarine carrying a cruise missile being invulnerable - * to other sea units. However from a gameplay perspective it's a hack, + * to other sea units. However from a gameplay perspective it's a hack, * since players can load and unload their units manually to protect * their transporters. */ if (!unit_transported(aunit)) { @@ -312,7 +313,8 @@ bool can_unit_attack_tile(const struct unit *punit, const struct action *paction, const struct tile *dest_tile) { - return (can_player_attack_tile(unit_owner(punit), dest_tile) + return ((unit_has_type_flag(punit, UTYF_FLAGLESS) + || can_player_attack_tile(unit_owner(punit), dest_tile)) && (unit_attack_units_at_tile_result(punit, paction, dest_tile) == ATT_OK)); } diff --git a/common/oblig_reqs.c b/common/oblig_reqs.c index 1a13e57f31..3e3f6ba086 100644 --- a/common/oblig_reqs.c +++ b/common/oblig_reqs.c @@ -330,19 +330,6 @@ void hard_code_oblig_hard_reqs(void) ACTRES_FORTIFY, ACTRES_NONE); - /* Why this is a hard requirement: there is a hard requirement that - * the actor player is at war with the owner of any city on the - * target tile. - * The Freeciv code assumes that ACTRES_ATTACK has this. */ - oblig_hard_req_register(req_from_values(VUT_DIPLREL, REQ_RANGE_LOCAL, - FALSE, FALSE, TRUE, DS_WAR), - FALSE, - N_("All action enablers for %s must require" - " that the actor is at war with the target."), - ACTRES_ATTACK, - ACTRES_WIPE_UNITS, - 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, diff --git a/doc/README.actions b/doc/README.actions index 5bb64152fa..c26c1eba87 100644 --- a/doc/README.actions +++ b/doc/README.actions @@ -834,7 +834,7 @@ Actions done by a unit against all units at a tile * the actor must be native to the target tile unless it has the "AttackNonNative" unit class flag and not the "Only_Native_Attack" unit type flag. - * the target tile has no non enemy units. (!) + * the target tile has no non enemy units, or actor is Flagless * the target tile has no non enemy city. * one or all (unreachableprotects) non transported units at the target tile must be reachable. A unit is reachable if any of the following is @@ -861,7 +861,7 @@ Actions done by a unit against all units at a tile * the actor must be native to the target tile unless it has the "AttackNonNative" unit class flag and not the "Only_Native_Attack" unit type flag. - * the target tile has no non enemy units. (!) + * the target tile has no non enemy units, or actor is Flagless * the target tile has no non enemy city. * one or all (unreachableprotects) non transported units at the target tile must be reachable. A unit is reachable if any of the following is @@ -887,7 +887,7 @@ Actions done by a unit against all units at a tile * the actor must be native to the target tile unless it has the "AttackNonNative" unit class flag and not the "Only_Native_Attack" unit type flag. - * the target tile has no non enemy units. (!) + * the target tile has no non enemy units, or actor is Flagless * the target tile has no non enemy city. * the target tile has no units with positive defense strength * all units at the target tile must be reachable. diff --git a/server/unithand.c b/server/unithand.c index 167ed68bdb..4740196ad1 100644 --- a/server/unithand.c +++ b/server/unithand.c @@ -1012,8 +1012,8 @@ static bool do_unit_make_homeless(struct unit *punit, Returns TRUE iff the player is able to change their diplomatic relationship to the other player to war. - Note that the player can't declare war on someone they already are at war - with. + Note that the player can't declare war on someone they already are + at war with. **************************************************************************/ static bool rel_may_become_war(const struct player *pplayer, const struct player *oplayer) @@ -1111,12 +1111,14 @@ static struct player *need_war_player_hlp(const struct unit *actor, /* Target is a unit stack but a city can block it. */ fc_assert_action(action_get_target_kind(paction) == ATK_UNITS, break); - if (target_tile) { - struct city *tcity; + if (!unit_has_type_flag(actor, UTYF_FLAGLESS)) { + if (target_tile != NULL) { + struct city *tcity; - if ((tcity = tile_city(target_tile)) - && rel_may_become_war(unit_owner(actor), city_owner(tcity))) { - return city_owner(tcity); + if ((tcity = tile_city(target_tile)) + && rel_may_become_war(unit_owner(actor), city_owner(tcity))) { + return city_owner(tcity); + } } } break; @@ -1220,6 +1222,11 @@ static struct player *need_war_player_hlp(const struct unit *actor, /* No target unit. */ return NULL; } + if (unit_has_type_flag(target_unit, UTYF_FLAGLESS)) { + /* Target unit is flagless anyway - no war needed */ + return NULL; + } + target_player = unit_owner(target_unit); break; case ATK_UNITS: @@ -1229,7 +1236,8 @@ static struct player *need_war_player_hlp(const struct unit *actor, } unit_list_iterate(target_tile->units, tunit) { - if (rel_may_become_war(actor_player, unit_owner(tunit))) { + if (!unit_has_type_flag(tunit, UTYF_FLAGLESS) + && rel_may_become_war(actor_player, unit_owner(tunit))) { target_player = unit_owner(tunit); break; } @@ -1706,7 +1714,7 @@ static struct ane_expl *expl_act_not_enabl(struct unit *punit, act_id, target_tile, target_city, - target_unit))) { + target_unit)) != NULL) { explnat->kind = ANEK_NO_WAR; explnat->no_war_with = must_war_player; } else if (action_mp_full_makes_legal(punit, act_id)) { @@ -4922,11 +4930,15 @@ static bool do_attack(struct unit *punit, struct tile *def_tile, /* Sanity checks */ fc_assert_ret_val_msg(!pplayers_non_attack(pplayer, - unit_owner(pdefender)), + unit_owner(pdefender)) + || unit_has_type_flag(punit, UTYF_FLAGLESS) + || unit_has_type_flag(pdefender, UTYF_FLAGLESS), FALSE, "Trying to attack a unit with which you have peace " "or cease-fire at (%d, %d).", TILE_XY(def_tile)); - fc_assert_ret_val_msg(!pplayers_allied(pplayer, unit_owner(pdefender)), + fc_assert_ret_val_msg(!pplayers_allied(pplayer, unit_owner(pdefender)) + || unit_has_type_flag(punit, UTYF_FLAGLESS) + || unit_has_type_flag(pdefender, UTYF_FLAGLESS), FALSE, "Trying to attack a unit with which you have " "alliance at (%d, %d).", TILE_XY(def_tile)); diff --git a/server/unittools.c b/server/unittools.c index 9e5189fe04..8ff0f6313c 100644 --- a/server/unittools.c +++ b/server/unittools.c @@ -2290,6 +2290,7 @@ void kill_unit(struct unit *pkiller, struct unit *punit, bool vet) struct tile *deftile = unit_tile(punit); int unitcount = 0; bool escaped; + bool flagless_attacker = unit_has_type_flag(pkiller, UTYF_FLAGLESS); sz_strlcpy(pkiller_link, unit_link(pkiller)); sz_strlcpy(punit_link, unit_tile_link(punit)); @@ -2298,7 +2299,9 @@ void kill_unit(struct unit *pkiller, struct unit *punit, bool vet) punit->server.dying = TRUE; unit_list_iterate(deftile->units, vunit) { - if (pplayers_at_war(pvictor, unit_owner(vunit)) + if ((flagless_attacker + || pplayers_at_war(pvictor, unit_owner(vunit)) + || unit_has_type_flag(vunit, UTYF_FLAGLESS)) && is_unit_reachable_at(vunit, pkiller, deftile)) { unitcount++; } -- 2.42.0