From be7c9d27f9f1ed6c62a81992b0c7393c6c27e22d Mon Sep 17 00:00:00 2001 From: Sveinung Kvilhaugsvik Date: Thu, 15 Apr 2021 12:08:16 +0200 Subject: [PATCH] unit_attack_unit_at_tile_result(): action param. Take what attack action is being checked as a parameter to unit_attack_unit_at_tile_result(). Stop checking the rules for other actions when it is specified. See osdn #42007 --- ai/default/aiair.c | 4 +-- ai/default/aihunt.c | 4 +-- ai/default/aiparatrooper.c | 6 ++-- ai/default/aitools.c | 7 +++-- ai/default/aiunit.c | 21 ++++++++------ ai/default/daimilitary.c | 2 +- client/control.c | 2 +- common/actions.c | 5 ++-- common/combat.c | 56 ++++++++++++++++++++++++++++---------- common/combat.h | 5 +++- server/advisors/advgoto.c | 6 ++-- server/unithand.c | 6 ++-- 12 files changed, 84 insertions(+), 40 deletions(-) diff --git a/ai/default/aiair.c b/ai/default/aiair.c index 7af34be75d..dfb5052061 100644 --- a/ai/default/aiair.c +++ b/ai/default/aiair.c @@ -130,7 +130,7 @@ static int dai_evaluate_tile_for_air_attack(struct unit *punit, int sortie_time; #define PROB_MULTIPLIER 100 /* should unify with those in combat.c */ - if (!can_unit_attack_tile(punit, dst_tile) + if (!can_unit_attack_tile(punit, NULL, dst_tile) || !(pdefender = get_defender(punit, dst_tile))) { return 0; } @@ -224,7 +224,7 @@ static int find_something_to_bomb(struct ai_type *ait, struct unit *punit, if (is_enemy_unit_tile(ptile, pplayer) && dai_should_we_air_attack_tile(ait, punit, ptile) - && can_unit_attack_tile(punit, ptile)) { + && can_unit_attack_tile(punit, NULL, ptile)) { int new_best = dai_evaluate_tile_for_air_attack(punit, ptile); if (new_best > best) { diff --git a/ai/default/aihunt.c b/ai/default/aihunt.c index 6f7ac1895f..dd3083acc2 100644 --- a/ai/default/aihunt.c +++ b/ai/default/aihunt.c @@ -333,7 +333,7 @@ static void dai_hunter_try_launch(struct ai_type *ait, break; } if (tile_city(ptile) - || !can_unit_attack_tile(punit, ptile)) { + || !can_unit_attack_tile(punit, NULL, ptile)) { continue; } unit_list_iterate(ptile->units, victim) { @@ -461,7 +461,7 @@ int dai_hunter_manage(struct ai_type *ait, struct player *pplayer, } if (tile_city(ptile) - || !can_unit_attack_tile(punit, ptile)) { + || !can_unit_attack_tile(punit, NULL, ptile)) { continue; } diff --git a/ai/default/aiparatrooper.c b/ai/default/aiparatrooper.c index 9b5e7c0b58..4b1bb05d07 100644 --- a/ai/default/aiparatrooper.c +++ b/ai/default/aiparatrooper.c @@ -143,7 +143,7 @@ static struct tile *find_best_tile_to_paradrop_to(struct ai_type *ait, /* Iterate over adjacent tile to find good victim */ adjc_iterate(ptile, target) { if (unit_list_size(target->units) == 0 - || !can_unit_attack_tile(punit, target) + || !can_unit_attack_tile(punit, NULL, target) || is_ocean_tile(target) || (has_handicap(pplayer, H_FOG) && !map_is_known_and_seen(target, pplayer, V_MAIN))) { @@ -154,7 +154,9 @@ static struct tile *find_best_tile_to_paradrop_to(struct ai_type *ait, unit_list_iterate(target->units, victim) { if ((!has_handicap(pplayer, H_FOG) || can_player_see_unit(pplayer, victim)) - && (unit_attack_unit_at_tile_result(punit, victim, target) == ATT_OK)) { + && (unit_attack_unit_at_tile_result(punit, NULL, + victim, target) + == ATT_OK)) { val += victim->hp * 100; } } unit_list_iterate_end; diff --git a/ai/default/aitools.c b/ai/default/aitools.c index 45cfb450de..29d966efc7 100644 --- a/ai/default/aitools.c +++ b/ai/default/aitools.c @@ -990,11 +990,14 @@ int stack_cost(struct unit *pattacker, struct unit *pdefender) if (is_stack_vulnerable(ptile)) { /* lotsa people die */ unit_list_iterate(ptile->units, aunit) { - if (unit_attack_unit_at_tile_result(pattacker, aunit, ptile) == ATT_OK) { + if (unit_attack_unit_at_tile_result(pattacker, NULL, aunit, ptile) + == ATT_OK) { victim_cost += unit_build_shield_cost(aunit); } } unit_list_iterate_end; - } else if (unit_attack_unit_at_tile_result(pattacker, pdefender, ptile) == ATT_OK) { + } else if (unit_attack_unit_at_tile_result(pattacker, NULL, + pdefender, ptile) + == ATT_OK) { /* Only one unit dies if attack is successful */ victim_cost = unit_build_shield_cost(pdefender); } diff --git a/ai/default/aiunit.c b/ai/default/aiunit.c index 2ff4278818..cee556691a 100644 --- a/ai/default/aiunit.c +++ b/ai/default/aiunit.c @@ -403,8 +403,11 @@ static bool is_my_turn(struct unit *punit, struct unit *pdef) if (aunit == punit || unit_owner(aunit) != unit_owner(punit)) { continue; } - if (unit_attack_units_at_tile_result(aunit, unit_tile(pdef)) != ATT_OK - || unit_attack_unit_at_tile_result(aunit, pdef, unit_tile(pdef)) != ATT_OK) { + if ((unit_attack_units_at_tile_result(aunit, NULL, unit_tile(pdef)) + != ATT_OK) + || (unit_attack_unit_at_tile_result(aunit, NULL, + pdef, unit_tile(pdef)) + != ATT_OK)) { continue; } d = get_virtual_defense_power(unit_type_get(aunit), unit_type_get(pdef), @@ -450,7 +453,7 @@ static int dai_rampage_want(struct unit *punit, struct tile *ptile) CHECK_UNIT(punit); - if (can_unit_attack_tile(punit, ptile) + if (can_unit_attack_tile(punit, NULL, ptile) && (pdef = get_defender(punit, ptile))) { /* See description of kill_desire() about these variables. */ int attack = unit_att_rating_now(punit); @@ -1345,7 +1348,7 @@ int find_something_to_kill(struct ai_type *ait, struct player *pplayer, go_by_boat = TRUE; } - if (can_unit_attack_tile(punit, city_tile(acity)) + if (can_unit_attack_tile(punit, NULL, city_tile(acity)) && (pdefender = get_defender(punit, city_tile(acity)))) { vulnerability = unit_def_rating_squared(punit, pdefender); benefit = unit_build_shield_cost(pdefender); @@ -1514,7 +1517,7 @@ int find_something_to_kill(struct ai_type *ait, struct player *pplayer, /* We have to assume the attack is diplomatically ok. * We cannot use can_player_attack_tile, because we might not * be at war with aplayer yet */ - if (!can_unit_attack_tile(punit, atile) + if (!can_unit_attack_tile(punit, NULL, atile) || aunit != get_defender(punit, atile)) { /* We cannot attack it, or it is not the main defender. */ continue; @@ -1742,7 +1745,7 @@ static void dai_military_attack(struct ai_type *ait, struct player *pplayer, NULL, &ferryboat, NULL, NULL); if (!same_pos(unit_tile(punit), dest_tile)) { if (!is_tiles_adjacent(unit_tile(punit), dest_tile) - || !can_unit_attack_tile(punit, dest_tile)) { + || !can_unit_attack_tile(punit, NULL, dest_tile)) { /* Adjacent and can't attack usually means we are not marines * and on a ferry. This fixes the problem (usually). */ @@ -2989,8 +2992,10 @@ void dai_consider_tile_dangerous(struct ai_type *ait, struct tile *ptile, } unit_list_iterate(ptile1->units, enemy) { if (pplayers_at_war(unit_owner(enemy), unit_owner(punit)) - && unit_attack_unit_at_tile_result(enemy, punit, ptile) == ATT_OK - && unit_attack_units_at_tile_result(enemy, ptile) == ATT_OK) { + && (unit_attack_unit_at_tile_result(enemy, NULL, punit, ptile) + == ATT_OK) + && (unit_attack_units_at_tile_result(enemy, NULL, ptile) + == ATT_OK)) { a += adv_unit_att_rating(enemy); if ((a * a * 10) >= d) { /* The enemies combined strength is too big! */ diff --git a/ai/default/daimilitary.c b/ai/default/daimilitary.c index cf0e638765..16e34ed953 100644 --- a/ai/default/daimilitary.c +++ b/ai/default/daimilitary.c @@ -1196,7 +1196,7 @@ static struct adv_choice *kill_something_with(struct ai_type *ait, struct player &boattype, &move_time); if (NULL == ptile || ptile == unit_tile(myunit) - || !can_unit_attack_tile(myunit, ptile)) { + || !can_unit_attack_tile(myunit, NULL, ptile)) { goto cleanup; } diff --git a/client/control.c b/client/control.c index 7924601420..5281046ac7 100644 --- a/client/control.c +++ b/client/control.c @@ -1164,7 +1164,7 @@ static bool can_units_attack_at(struct unit_list *punits, { unit_list_iterate(punits, punit) { if (is_attack_unit(punit) - && can_unit_attack_tile(punit, ptile)) { + && can_unit_attack_tile(punit, NULL, ptile)) { return TRUE; } } unit_list_iterate_end; diff --git a/common/actions.c b/common/actions.c index 2c8b01ca0c..c2a6420c8d 100644 --- a/common/actions.c +++ b/common/actions.c @@ -2439,7 +2439,8 @@ is_action_possible(const action_id wanted_action, } if (!tcity - && (unit_attack_units_at_tile_result(actor_unit, target_tile) + && (unit_attack_units_at_tile_result(actor_unit, paction, + target_tile) != ATT_OK)) { return TRI_NO; } @@ -2554,7 +2555,7 @@ is_action_possible(const action_id wanted_action, case ACTION_ATTACK: /* Reason: Keep the old rules. */ - if (!can_unit_attack_tile(actor_unit, target_tile)) { + if (!can_unit_attack_tile(actor_unit, paction, target_tile)) { return TRI_NO; } break; diff --git a/common/combat.c b/common/combat.c index 6ed6b5fe16..11a88f161e 100644 --- a/common/combat.c +++ b/common/combat.c @@ -120,15 +120,22 @@ bool is_unit_reachable_at(const struct unit *defender, ***********************************************************************/ enum unit_attack_result unit_attack_unit_at_tile_result(const struct unit *punit, + const struct action *paction, const struct unit *pdefender, const struct tile *dest_tile) { /* 1. Can we attack _anything_ ? */ - if (!(utype_can_do_action(unit_type_get(punit), ACTION_ATTACK) - /* Needed because ACTION_NUKE uses this when evaluating its hard - * requirements. */ - || utype_can_do_action(unit_type_get(punit), ACTION_NUKE))) { - return ATT_NON_ATTACK; + if (paction == NULL) { + if (!(utype_can_do_action(unit_type_get(punit), ACTION_ATTACK) + /* Needed because ACTION_NUKE uses this when evaluating its hard + * requirements. */ + || utype_can_do_action(unit_type_get(punit), ACTION_NUKE))) { + return ATT_NON_ATTACK; + } + } else { + if (!utype_can_do_action(unit_type_get(punit), paction->id)) { + return ATT_NON_ATTACK; + } } /* 2. Only fighters can attack planes, except in city or airbase attacks */ @@ -137,10 +144,20 @@ unit_attack_unit_at_tile_result(const struct unit *punit, } /* 3. Can't attack with ground unit from ocean, except for marines */ - if (!is_native_tile(unit_type_get(punit), unit_tile(punit)) - && !utype_can_do_act_when_ustate(unit_type_get(punit), ACTION_ATTACK, - USP_NATIVE_TILE, FALSE)) { - return ATT_NONNATIVE_SRC; + if (paction == NULL) { + if (!is_native_tile(unit_type_get(punit), unit_tile(punit)) + && !utype_can_do_act_when_ustate(unit_type_get(punit), + ACTION_ATTACK, + USP_NATIVE_TILE, FALSE)) { + return ATT_NONNATIVE_SRC; + } + } else { + if (!is_native_tile(unit_type_get(punit), unit_tile(punit)) + && !utype_can_do_act_when_ustate(unit_type_get(punit), + paction->id, + USP_NATIVE_TILE, FALSE)) { + return ATT_NONNATIVE_SRC; + } } /* 4. Most units can not attack non-native terrain. @@ -160,6 +177,7 @@ unit_attack_unit_at_tile_result(const struct unit *punit, ************************************************************************/ static enum unit_attack_result unit_attack_all_at_tile_result(const struct unit *punit, + const struct action *paction, const struct tile *ptile) { unit_list_iterate(ptile->units, aunit) { @@ -171,7 +189,8 @@ unit_attack_all_at_tile_result(const struct unit *punit, if (!unit_transported(aunit)) { enum unit_attack_result result; - result = unit_attack_unit_at_tile_result(punit, aunit, ptile); + result = unit_attack_unit_at_tile_result(punit, paction, + aunit, ptile); if (result != ATT_OK) { return result; } @@ -188,6 +207,7 @@ unit_attack_all_at_tile_result(const struct unit *punit, ************************************************************************/ static enum unit_attack_result unit_attack_any_at_tile_result(const struct unit *punit, + const struct action *paction, const struct tile *ptile) { enum unit_attack_result result = ATT_OK; @@ -196,7 +216,8 @@ unit_attack_any_at_tile_result(const struct unit *punit, /* HACK: we don't count transported units here. This prevents some * bugs like a cargoplane carrying a land unit being vulnerable. */ if (!unit_transported(aunit)) { - result = unit_attack_unit_at_tile_result(punit, aunit, ptile); + result = unit_attack_unit_at_tile_result(punit, paction, + aunit, ptile); if (result == ATT_OK) { return result; } @@ -213,12 +234,13 @@ unit_attack_any_at_tile_result(const struct unit *punit, ***********************************************************************/ enum unit_attack_result unit_attack_units_at_tile_result(const struct unit *punit, + const struct action *paction, const struct tile *ptile) { if (game.info.unreachable_protects) { - return unit_attack_all_at_tile_result(punit, ptile); + return unit_attack_all_at_tile_result(punit, paction, ptile); } else { - return unit_attack_any_at_tile_result(punit, ptile); + return unit_attack_any_at_tile_result(punit, paction, ptile); } } @@ -227,10 +249,12 @@ unit_attack_units_at_tile_result(const struct unit *punit, to do so? ***********************************************************************/ 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) - && unit_attack_units_at_tile_result(punit, dest_tile) == ATT_OK); + && (unit_attack_units_at_tile_result(punit, paction, dest_tile) + == ATT_OK)); } /*********************************************************************** @@ -686,7 +710,9 @@ struct unit *get_defender(const struct unit *attacker, /* We used to skip over allied units, but the logic for that is * complicated and is now handled elsewhere. */ if (unit_can_defend_here(defender) - && unit_attack_unit_at_tile_result(attacker, defender, ptile) == ATT_OK) { + && (unit_attack_unit_at_tile_result(attacker, NULL, + defender, ptile) + == ATT_OK)) { bool change = FALSE; int build_cost = unit_build_shield_cost(defender); int defense_rating = get_defense_rating(attacker, defender); diff --git a/common/combat.h b/common/combat.h index 03c88dc5b9..0fe69b7b70 100644 --- a/common/combat.h +++ b/common/combat.h @@ -41,13 +41,16 @@ bool is_unit_reachable_at(const struct unit *defender, const struct tile *location); enum unit_attack_result unit_attack_unit_at_tile_result(const struct unit *punit, + const struct action *paction, const struct unit *pdefender, const struct tile *dest_tile); enum unit_attack_result unit_attack_units_at_tile_result(const struct unit *punit, + const struct action *paction, const struct tile *ptile); bool can_unit_attack_tile(const struct unit *punit, - const struct tile *ptile); + const struct action *paction, + const struct tile *ptile); double win_chance(int as, int ahp, int afp, int ds, int dhp, int dfp); diff --git a/server/advisors/advgoto.c b/server/advisors/advgoto.c index ce83f28b70..a82d9940a7 100644 --- a/server/advisors/advgoto.c +++ b/server/advisors/advgoto.c @@ -316,8 +316,10 @@ bool adv_danger_at(struct unit *punit, struct tile *ptile) } unit_list_iterate(ptile1->units, enemy) { if (pplayers_at_war(unit_owner(enemy), unit_owner(punit)) - && unit_attack_unit_at_tile_result(enemy, punit, ptile) == ATT_OK - && unit_attack_units_at_tile_result(enemy, ptile) == ATT_OK) { + && (unit_attack_unit_at_tile_result(enemy, NULL, punit, ptile) + == ATT_OK) + && (unit_attack_units_at_tile_result(enemy, NULL, ptile) + == ATT_OK)) { a += adv_unit_att_rating(enemy); if ((a * a * 10) >= d) { /* The enemies combined strength is too big! */ diff --git a/server/unithand.c b/server/unithand.c index 34aeb688c0..adc768434c 100644 --- a/server/unithand.c +++ b/server/unithand.c @@ -1101,13 +1101,15 @@ static struct ane_expl *expl_act_not_enabl(struct unit *punit, case ACTION_NUKE: if (target_tile != unit_tile(punit)) { /* unit_attack_units_at_tile_result() matters for neighbor tiles. */ - action_custom = unit_attack_units_at_tile_result(punit, target_tile); + action_custom = unit_attack_units_at_tile_result(punit, paction, + target_tile); } else { action_custom = ATT_OK; } break; case ACTION_ATTACK: - action_custom = unit_attack_units_at_tile_result(punit, target_tile); + action_custom = unit_attack_units_at_tile_result(punit, paction, + target_tile); break; case ACTION_CONQUER_CITY: if (target_city) { -- 2.30.2