From 8b1755caba74ac5970610dd3f89258bc75f506c1 Mon Sep 17 00:00:00 2001 From: Marko Lindqvist Date: Wed, 24 May 2023 00:43:29 +0300 Subject: [PATCH 10/10] Make combat.c functions to take map as parameter They were hardcoded to use the main map. See osdn #47949 Signed-off-by: Marko Lindqvist --- ai/default/aiair.c | 6 +- ai/default/aihunt.c | 5 +- ai/default/aiparatrooper.c | 32 +++++---- ai/default/daimilitary.c | 17 +++-- ai/default/daiunit.c | 48 +++++++------ client/gui-sdl2/dialogs.c | 38 +++++----- common/actions.c | 13 ++-- common/clientutils.c | 6 +- common/combat.c | 137 +++++++++++++++++++------------------ common/combat.h | 24 ++++--- server/unithand.c | 10 +-- server/unittools.c | 21 +++--- 12 files changed, 202 insertions(+), 155 deletions(-) diff --git a/ai/default/aiair.c b/ai/default/aiair.c index 391a0b6cf1..dc6c516bbc 100644 --- a/ai/default/aiair.c +++ b/ai/default/aiair.c @@ -172,10 +172,12 @@ static adv_want dai_evaluate_tile_for_air_attack(struct unit *punit, adv_want profit; /* time spent in the air */ int sortie_time; + struct civ_map *nmap = &(wld.map); + #define PROB_MULTIPLIER 100 /* should unify with those in combat.c */ if (!can_unit_attack_tile(punit, NULL, dst_tile) - || !(pdefender = get_defender(punit, dst_tile, NULL))) { + || !(pdefender = get_defender(nmap, punit, dst_tile, NULL))) { return 0; } @@ -200,7 +202,7 @@ static adv_want dai_evaluate_tile_for_air_attack(struct unit *punit, } unit_attack = (int) (PROB_MULTIPLIER - * unit_win_chance(punit, pdefender, NULL)); + * unit_win_chance(nmap, punit, pdefender, NULL)); victim_defense = PROB_MULTIPLIER - unit_attack; diff --git a/ai/default/aihunt.c b/ai/default/aihunt.c index fdd2df7f1d..acfdd44ad6 100644 --- a/ai/default/aihunt.c +++ b/ai/default/aihunt.c @@ -439,6 +439,7 @@ int dai_hunter_manage(struct ai_type *ait, struct player *pplayer, struct unit_ai *unit_data = def_ai_unit_data(punit, ait); struct unit *original_target = game_unit_by_number(unit_data->target); unsigned original_threat = 0, original_cost = 0; + struct civ_map *nmap = &(wld.map); fc_assert_ret_val(!is_barbarian(pplayer), 0); fc_assert_ret_val(pplayer->is_alive, 0); @@ -530,9 +531,9 @@ int dai_hunter_manage(struct ai_type *ait, struct player *pplayer, /* Calculate juiciness of target, compare with existing target, * if any. */ dai_hunter_juiciness(pplayer, punit, target, &stackthreat, &stackcost); - defender = get_defender(punit, target_tile, NULL); + defender = get_defender(nmap, punit, target_tile, NULL); if (defender != NULL) { - stackcost *= unit_win_chance(punit, defender, NULL); + stackcost *= unit_win_chance(nmap, punit, defender, NULL); } if (stackcost < unit_build_shield_cost_base(punit)) { UNIT_LOG(LOGLEVEL_HUNT, punit, "%d is too expensive (it %d vs us %d)", diff --git a/ai/default/aiparatrooper.c b/ai/default/aiparatrooper.c index f5b9e3b339..7f2ffc1895 100644 --- a/ai/default/aiparatrooper.c +++ b/ai/default/aiparatrooper.c @@ -69,9 +69,10 @@ static struct tile *find_best_tile_to_paradrop_to(struct ai_type *ait, int range = unit_type_get(punit)->paratroopers_range; struct city* acity; struct player* pplayer = unit_owner(punit); + struct civ_map *nmap = &(wld.map); /* First, we search for undefended cities in danger */ - square_iterate(&(wld.map), unit_tile(punit), range, ptile) { + square_iterate(nmap, unit_tile(punit), range, ptile) { if (!map_is_known(ptile, pplayer)) { continue; } @@ -97,7 +98,7 @@ static struct tile *find_best_tile_to_paradrop_to(struct ai_type *ait, } /* Second, we search for undefended enemy cities */ - square_iterate(&(wld.map), unit_tile(punit), range, ptile) { + square_iterate(nmap, unit_tile(punit), range, ptile) { acity = tile_city(ptile); if (acity && pplayers_at_war(unit_owner(punit), city_owner(acity)) && (unit_list_size(ptile->units) == 0)) { @@ -124,7 +125,7 @@ static struct tile *find_best_tile_to_paradrop_to(struct ai_type *ait, } /* Jump to kill adjacent units */ - square_iterate(&(wld.map), unit_tile(punit), range, ptile) { + square_iterate(nmap, unit_tile(punit), range, ptile) { struct terrain *pterrain = tile_terrain(ptile); if (is_ocean(pterrain)) { continue; @@ -145,8 +146,9 @@ static struct tile *find_best_tile_to_paradrop_to(struct ai_type *ait, if (!acity && unit_list_size(ptile->units) > 0) { continue; } + /* Iterate over adjacent tile to find good victim */ - adjc_iterate(&(wld.map), ptile, target) { + adjc_iterate(nmap, ptile, target) { if (unit_list_size(target->units) == 0 || !can_unit_attack_tile(punit, NULL, target) || is_ocean_tile(target) @@ -166,9 +168,10 @@ static struct tile *find_best_tile_to_paradrop_to(struct ai_type *ait, } } unit_list_iterate_end; } else { - val += get_defender(punit, target, NULL)->hp * 100; + val += get_defender(nmap, punit, target, NULL)->hp * 100; } - val *= unit_win_chance(punit, get_defender(punit, target, NULL), + val *= unit_win_chance(nmap, punit, + get_defender(nmap, punit, target, NULL), NULL); val += pterrain->defense_bonus / 10; val -= punit->hp * 100; @@ -313,15 +316,16 @@ static int calculate_want_for_paratrooper(struct unit *punit, int profit = 0; struct player* pplayer = unit_owner(punit); int total, total_cities; + struct civ_map *nmap = &(wld.map); profit += u_type->defense_strength + u_type->move_rate + u_type->attack_strength; - - square_iterate(&(wld.map), ptile_city, range, ptile) { + + square_iterate(nmap, ptile_city, range, ptile) { int multiplier; struct city *pcity = tile_city(ptile); - + if (!pcity) { continue; } @@ -330,9 +334,9 @@ static int calculate_want_for_paratrooper(struct unit *punit, continue; } - /* We prefer jumping to other continents. On the same continent we + /* We prefer jumping to other continents. On the same continent we * can fight traditionally. - * FIXME: Handle ocean cities we can attack. */ + * FIXME: Handle ocean cities we can attack. */ if (!is_ocean_tile(ptile) && tile_continent(ptile_city) != tile_continent(ptile)) { if (get_continent_size(tile_continent(ptile)) < 3) { @@ -344,12 +348,12 @@ static int calculate_want_for_paratrooper(struct unit *punit, } else { multiplier = 1; } - + /* There are lots of units, the city will be safe against paratroopers. */ if (unit_list_size(ptile->units) > 2) { continue; } - + /* Prefer long jumps. * If a city is near we can take/protect it with normal units */ if (pplayers_allied(pplayer, city_owner(pcity))) { @@ -383,7 +387,7 @@ void dai_choose_paratrooper(struct ai_type *ait, int profit; struct ai_plr *plr_data = def_ai_player_data(pplayer, ait); - /* military_advisor_choose_build does something idiotic, + /* military_advisor_choose_build() does something idiotic, * this function should not be called if there is danger... */ if (choice->want >= 100 && choice->type != CT_ATTACKER) { return; diff --git a/ai/default/daimilitary.c b/ai/default/daimilitary.c index 9fdc3f24be..db5ddd8ac6 100644 --- a/ai/default/daimilitary.c +++ b/ai/default/daimilitary.c @@ -88,6 +88,7 @@ struct unit_type *dai_choose_defender_versus(struct city *pcity, double best = 0; int best_cost = FC_INFINITY; struct player *pplayer = city_owner(pcity); + struct civ_map *nmap = &(wld.map); simple_ai_unit_type_iterate(punittype) { if (can_city_build_unit_now(pcity, punittype)) { @@ -101,7 +102,7 @@ struct unit_type *dai_choose_defender_versus(struct city *pcity, defender = unit_virtual_create(pplayer, pcity, punittype, veteran); defense = get_total_defense_power(attacker, defender); attack = get_total_attack_power(attacker, defender, NULL); - get_modified_firepower(attacker, defender, &fpatt, &fpdef); + get_modified_firepower(nmap, attacker, defender, &fpatt, &fpdef); /* Greg's algorithm. loss is the average number of health lost by * defender. If loss > attacker's hp then we should win the fight, @@ -134,8 +135,10 @@ struct unit_type *dai_choose_defender_versus(struct city *pcity, desirability without regard to cost, unless costs are equal. This is very wrong. FIXME, use amortize on time to build. **************************************************************************/ -static struct unit_type *dai_choose_attacker(struct ai_type *ait, struct city *pcity, - enum terrain_class tc, bool allow_gold_upkeep) +static struct unit_type *dai_choose_attacker(struct ai_type *ait, + struct city *pcity, + enum terrain_class tc, + bool allow_gold_upkeep) { struct unit_type *bestid = NULL; int best = -1; @@ -519,6 +522,7 @@ static unsigned int assess_danger_unit(const struct city *pcity, const struct unit *ferry; unsigned int danger; int amod = -99, dmod; + struct civ_map *nmap = &(wld.map); bool attack_danger = FALSE; *move_time = PF_IMPOSSIBLE_MC; @@ -555,7 +559,7 @@ static unsigned int assess_danger_unit(const struct city *pcity, && !can_attack_non_native(punittype)) { return 0; } - if (!is_native_near_tile(&(wld.map), unit_class_get(punit), ptile)) { + if (!is_native_near_tile(nmap, unit_class_get(punit), ptile)) { return 0; } @@ -1513,6 +1517,7 @@ static struct adv_choice *kill_something_with(struct ai_type *ait, struct adv_choice *best_choice; struct ai_city *city_data = def_ai_city_data(pcity, ait); struct ai_city *acity_data; + struct civ_map *nmap = &(wld.map); best_choice = adv_new_choice(); best_choice->value.utype = unit_type_get(myunit); @@ -1573,7 +1578,7 @@ static struct adv_choice *kill_something_with(struct ai_type *ait, def_vet = 0; } - pdef = get_defender(myunit, ptile, NULL); + pdef = get_defender(nmap, myunit, ptile, NULL); if (pdef) { int m = unittype_def_rating_squared(unit_type_get(myunit), unit_type_get(pdef), city_owner(acity), ptile, FALSE, @@ -1605,7 +1610,7 @@ static struct adv_choice *kill_something_with(struct ai_type *ait, ferry_map = NULL; } - pdef = get_defender(myunit, ptile, NULL); + pdef = get_defender(nmap, myunit, ptile, NULL); if (!pdef) { /* Nobody to attack! */ goto cleanup; diff --git a/ai/default/daiunit.c b/ai/default/daiunit.c index dae9f14297..26dd0fc9fe 100644 --- a/ai/default/daiunit.c +++ b/ai/default/daiunit.c @@ -297,7 +297,7 @@ static int unit_def_rating_squared(const struct unit *attacker, /**********************************************************************//** Defense rating of def_type unit against att_type unit, squared. - See get_virtual_defense_power for the arguments att_type, def_type, + See get_virtual_defense_power() for the arguments att_type, def_type, x, y, fortified and veteran. **************************************************************************/ int unittype_def_rating_squared(const struct unit_type *att_type, @@ -306,8 +306,9 @@ int unittype_def_rating_squared(const struct unit_type *att_type, struct tile *ptile, bool fortified, int veteran) { - int v = get_virtual_defense_power(att_type, def_type, def_player, ptile, - fortified, veteran) + struct civ_map *nmap = &(wld.map); + int v = get_virtual_defense_power(nmap, att_type, def_type, def_player, + ptile, fortified, veteran) * def_type->hp * def_type->firepower / POWER_DIVIDER; return v * v; @@ -397,45 +398,48 @@ static void reinforcements_cost_and_value(struct unit *punit, **************************************************************************/ static bool is_my_turn(struct unit *punit, struct unit *pdef) { - int val = unit_att_rating_now(punit), cur, d; + int val = unit_att_rating_now(punit); + int cur, d; + const struct unit_type *def_type = unit_type_get(pdef); + struct tile *def_tile = unit_tile(pdef); + struct civ_map *nmap = &(wld.map); CHECK_UNIT(punit); - square_iterate(&(wld.map), unit_tile(pdef), 1, ptile) { + square_iterate(nmap, def_tile, 1, ptile) { unit_list_iterate(ptile->units, aunit) { if (aunit == punit || unit_owner(aunit) != unit_owner(punit)) { continue; } - if ((unit_attack_units_at_tile_result(aunit, NULL, unit_tile(pdef)) + if ((unit_attack_units_at_tile_result(aunit, NULL, def_tile) != ATT_OK) || (unit_attack_unit_at_tile_result(aunit, NULL, - pdef, unit_tile(pdef)) + pdef, def_tile) != ATT_OK)) { continue; } - d = get_virtual_defense_power(unit_type_get(aunit), unit_type_get(pdef), - unit_owner(pdef), unit_tile(pdef), + d = get_virtual_defense_power(nmap, unit_type_get(aunit), def_type, + unit_owner(pdef), def_tile, FALSE, 0); if (d == 0) { return TRUE; /* Thanks, Markus -- Syela */ } cur = unit_att_rating_now(aunit) * - get_virtual_defense_power(unit_type_get(punit), unit_type_get(pdef), - unit_owner(pdef), unit_tile(pdef), - FALSE, 0) / d; + get_virtual_defense_power(nmap, unit_type_get(punit), def_type, + unit_owner(pdef), def_tile, + FALSE, 0) / d; if (cur > val && ai_fuzzy(unit_owner(punit), TRUE)) { return FALSE; } - } - unit_list_iterate_end; - } - square_iterate_end; + } unit_list_iterate_end; + } square_iterate_end; + return TRUE; } /**********************************************************************//** This function appraises the location (x, y) for a quick hit-n-run - operation. We do not take into account reinforcements: rampage is for + operation. We do not take into account reinforcements: rampage is for loners. Returns value as follows: @@ -453,11 +457,12 @@ static int dai_rampage_want(struct unit *punit, struct tile *ptile) { struct player *pplayer = unit_owner(punit); struct unit *pdef; + struct civ_map *nmap = &(wld.map); CHECK_UNIT(punit); if (can_unit_attack_tile(punit, NULL, ptile) - && (pdef = get_defender(punit, ptile, NULL))) { + && (pdef = get_defender(nmap, punit, ptile, NULL))) { /* See description of kill_desire() about these variables. */ int attack = unit_att_rating_now(punit); int benefit = stack_cost(punit, pdef); @@ -477,7 +482,7 @@ static int dai_rampage_want(struct unit *punit, struct tile *ptile) /* If we have non-zero attack rating... */ if (attack > 0 && is_my_turn(punit, pdef)) { - double chance = unit_win_chance(punit, pdef, NULL); + double chance = unit_win_chance(nmap, punit, pdef, NULL); int desire = avg_benefit(benefit, loss, chance); /* No need to amortize, our operation takes one turn. */ @@ -1163,6 +1168,7 @@ adv_want find_something_to_kill(struct ai_type *ait, struct player *pplayer, adv_want best = 0; /* Best of all wants. */ struct tile *goto_dest_tile = NULL; bool can_occupy; + struct civ_map *nmap = &(wld.map); /* Very preliminary checks. */ *pdest_tile = punit_tile; @@ -1374,7 +1380,7 @@ adv_want find_something_to_kill(struct ai_type *ait, struct player *pplayer, } if (can_unit_attack_tile(punit, NULL, city_tile(acity)) - && (pdefender = get_defender(punit, city_tile(acity), NULL))) { + && (pdefender = get_defender(nmap, punit, city_tile(acity), NULL))) { vulnerability = unit_def_rating_squared(punit, pdefender); benefit = unit_build_shield_cost_base(pdefender); } else { @@ -1545,7 +1551,7 @@ adv_want find_something_to_kill(struct ai_type *ait, struct player *pplayer, * We cannot use can_player_attack_tile, because we might not * be at war with aplayer yet */ if (!can_unit_attack_tile(punit, NULL, atile) - || aunit != get_defender(punit, atile, NULL)) { + || aunit != get_defender(nmap, punit, atile, NULL)) { /* We cannot attack it, or it is not the main defender. */ continue; } diff --git a/client/gui-sdl2/dialogs.c b/client/gui-sdl2/dialogs.c index 979822dc7e..278ea86a96 100644 --- a/client/gui-sdl2/dialogs.c +++ b/client/gui-sdl2/dialogs.c @@ -184,22 +184,25 @@ void popdown_all_game_dialogs(void) /* ======================================================================= */ /**********************************************************************//** - Find the my unit's (focus) chance of success at attacking/defending the - given enemy unit. Return FALSE if the values cannot be determined (e.g., no + Find my unit's (focus) chance of success at attacking/defending the + given enemy unit. Return FALSE if the values cannot be determined (e.g., no units given). **************************************************************************/ static bool sdl_get_chance_to_win(int *att_chance, int *def_chance, - struct unit *enemy_unit, struct unit *my_unit) -{ + struct unit *enemy_unit, + struct unit *my_unit) +{ if (!my_unit || !enemy_unit) { return FALSE; } - /* chance to win when active unit is attacking the selected unit */ - *att_chance = unit_win_chance(my_unit, enemy_unit, NULL) * 100; + /* Chance to win when active unit is attacking the selected unit */ + *att_chance = unit_win_chance(&(wld.map), my_unit, + enemy_unit, NULL) * 100; - /* chance to win when selected unit is attacking the active unit */ - *def_chance = (1.0 - unit_win_chance(enemy_unit, my_unit, NULL)) * 100; + /* Chance to win when selected unit is attacking the active unit */ + *def_chance = (1.0 - unit_win_chance(&(wld.map), enemy_unit, + my_unit, NULL)) * 100; return TRUE; } @@ -1680,7 +1683,8 @@ static int unit_help_callback(struct widget *pwidget) Popup a generic dialog to display some generic information about terrain : tile, units , cities, etc. **************************************************************************/ -void popup_advanced_terrain_dialog(struct tile *ptile, Uint16 pos_x, Uint16 pos_y) +void popup_advanced_terrain_dialog(struct tile *ptile, + Uint16 pos_x, Uint16 pos_y) { struct widget *pwindow = NULL, *buf = NULL; struct city *pcity; @@ -1729,7 +1733,7 @@ void popup_advanced_terrain_dialog(struct tile *ptile, Uint16 pos_x, Uint16 pos_ area = pwindow->area; /* ---------- */ - /* exit button */ + /* Exit button */ buf = create_themeicon(current_theme->small_cancel_icon, pwindow->dst, WF_WIDGET_HAS_INFO_LABEL | WF_RESTORE_BACKGROUND); buf->info_label = create_utf8_from_char(_("Close Dialog (Esc)"), @@ -1762,7 +1766,7 @@ void popup_advanced_terrain_dialog(struct tile *ptile, Uint16 pos_x, Uint16 pos_ /* ---------- */ if (pcity && city_owner(pcity) == client.conn.playing) { - /* separator */ + /* Separator */ buf = create_iconlabel(NULL, pwindow->dst, NULL, WF_FREE_THEME); add_to_gui_list(ID_SEPARATOR, buf); @@ -1821,7 +1825,7 @@ void popup_advanced_terrain_dialog(struct tile *ptile, Uint16 pos_x, Uint16 pos_ if (focus_unit && (tile_index(unit_tile(focus_unit)) != tile_index(ptile))) { - /* separator */ + /* Separator */ buf = create_iconlabel(NULL, pwindow->dst, NULL, WF_FREE_THEME); add_to_gui_list(ID_SEPARATOR, buf); @@ -1892,7 +1896,8 @@ void popup_advanced_terrain_dialog(struct tile *ptile, Uint16 pos_x, Uint16 pos_ const struct unit_type *punittype = NULL; units_h = 0; - /* separator */ + + /* Separator */ buf = create_iconlabel(NULL, pwindow->dst, NULL, WF_FREE_THEME); add_to_gui_list(ID_SEPARATOR, buf); @@ -1907,9 +1912,10 @@ void popup_advanced_terrain_dialog(struct tile *ptile, Uint16 pos_x, Uint16 pos_ #define ADV_NUM_SEEN 15 - defender = (focus_unit ? get_defender(focus_unit, ptile, NULL) - : NULL); - attacker = (focus_unit ? get_attacker(focus_unit, ptile) : NULL); + defender = (focus_unit ? get_defender(&(wld.map), focus_unit, ptile, NULL) + : NULL); + attacker = (focus_unit ? get_attacker(&(wld.map), focus_unit, ptile) + : NULL); for (i = 0; i < n; i++) { punit = unit_list_get(ptile->units, i); if (punit == focus_unit) { diff --git a/common/actions.c b/common/actions.c index 75f2753b35..8122e03a96 100644 --- a/common/actions.c +++ b/common/actions.c @@ -3681,6 +3681,7 @@ is_action_possible(const action_id wanted_action, enum fc_tristate out; struct action *paction = action_by_number(wanted_action); enum action_target_kind tkind = action_get_target_kind(paction); + struct civ_map *nmap = &(wld.map); if (actor == NULL) { actor = req_context_empty(); @@ -3791,7 +3792,7 @@ is_action_possible(const action_id wanted_action, /* Reason: Keep the old rules. Be merciful. */ /* Info leak: The player sees the target tile. */ - if (!can_unit_exist_at_tile(&(wld.map), actor->unit, target->tile) + if (!can_unit_exist_at_tile(nmap, actor->unit, target->tile) && (!BV_ISSET(paction->sub_results, ACT_SUB_RES_MAY_EMBARK) || !unit_could_load_at(actor->unit, target->tile))) { return TRI_NO; @@ -4678,8 +4679,8 @@ action_prob(const action_id wanted_action, { int known; struct act_prob chance; - const struct action *paction = action_by_number(wanted_action); + struct civ_map *nmap = &(wld.map); if (actor == NULL) { actor = req_context_empty(); @@ -4859,12 +4860,12 @@ action_prob(const action_id wanted_action, break; case ACTRES_ATTACK: { - struct unit *defender_unit = get_defender(actor->unit, target->tile, - paction); + struct unit *defender_unit = get_defender(nmap, actor->unit, + target->tile, paction); if (can_player_see_unit(actor->player, defender_unit)) { - double unconverted = unit_win_chance(actor->unit, defender_unit, - paction); + double unconverted = unit_win_chance(nmap, actor->unit, + defender_unit, paction); chance.min = MAX(ACTPROB_VAL_MIN, floor((double)ACTPROB_VAL_MAX * unconverted)); diff --git a/common/clientutils.c b/common/clientutils.c index abde999a95..7b9c62f479 100644 --- a/common/clientutils.c +++ b/common/clientutils.c @@ -24,6 +24,7 @@ #include "fc_types.h" #include "game.h" /* FIXME it's extra_type_iterate that needs this really */ #include "tile.h" +#include "world_object.h" #include "clientutils.h" @@ -353,6 +354,7 @@ void combat_odds_to_astr(struct astring *str, struct unit_list *punits, const char *pct_str) { const struct unit_type *ptype = unit_type_get(punit); + struct civ_map *nmap = &(wld.map); unit_list_iterate(punits, pfocus) { int att_chance = FC_INFINITY, def_chance = FC_INFINITY; @@ -360,8 +362,8 @@ void combat_odds_to_astr(struct astring *str, struct unit_list *punits, unit_list_iterate(ptile->units, tile_unit) { if (unit_owner(tile_unit) != unit_owner(pfocus)) { - int att = unit_win_chance(pfocus, tile_unit, NULL) * 100; - int def = (1.0 - unit_win_chance(tile_unit, pfocus, + int att = unit_win_chance(nmap, pfocus, tile_unit, NULL) * 100; + int def = (1.0 - unit_win_chance(nmap, tile_unit, pfocus, NULL)) * 100; found = TRUE; diff --git a/common/combat.c b/common/combat.c index 950a76ed63..d52fa5c45e 100644 --- a/common/combat.c +++ b/common/combat.c @@ -318,16 +318,16 @@ bool can_unit_attack_tile(const struct unit *punit, } /*******************************************************************//** -Returns the chance of the attacker winning, a number between 0 and 1. -If you want the chance that the defender wins just use 1-chance(...) + Returns the chance of the attacker winning, a number between 0 and 1. + If you want the chance that the defender wins just use 1-chance(...) -NOTE: this number can be _very_ small, fx in a battle between an -ironclad and a battleship the ironclad has less than 1/100000 chance of -winning. + NOTE: this number can be _very_ small, fx in a battle between an + ironclad and a battleship the ironclad has less than 1/100000 chance of + winning. -The algoritm calculates the probability of each possible number of HP's -the attacker has left. Maybe that info should be preserved for use in -the AI. + The algoritm calculates the probability of each possible number of HP's + the attacker has left. Maybe that info should be preserved for use in + the AI. ***********************************************************************/ double win_chance(int as, int ahp, int afp, int ds, int dhp, int dfp) { @@ -406,7 +406,8 @@ double win_chance(int as, int ahp, int afp, int ds, int dhp, int dfp) /*******************************************************************//** A unit's effective firepower depend on the situation. ***********************************************************************/ -void get_modified_firepower(const struct unit *attacker, +void get_modified_firepower(const struct civ_map *nmap, + const struct unit *attacker, const struct unit *defender, int *att_fp, int *def_fp) { @@ -463,8 +464,7 @@ void get_modified_firepower(const struct unit *attacker, * or from a tile where attacker is despite non-native terrain (city, transport) */ if (utype_has_class_flag(def_type, UCF_NONNAT_BOMBARD_TGT) && !is_native_tile(att_type, unit_tile(defender)) - && (!can_exist_at_tile(&(wld.map), - def_type, att_tile) + && (!can_exist_at_tile(nmap, def_type, att_tile) || !is_native_tile(att_type, att_tile))) { *att_fp = MIN(*att_fp, game.info.low_firepower_nonnat_bombard); *def_fp = MIN(*def_fp, game.info.low_firepower_nonnat_bombard); @@ -472,20 +472,20 @@ void get_modified_firepower(const struct unit *attacker, } /*******************************************************************//** -Returns a double in the range [0;1] indicating the attackers chance of -winning. The calculation takes all factors into account. + Returns a double in the range [0;1] indicating the attackers chance of + winning. The calculation takes all factors into account. ***********************************************************************/ -double unit_win_chance(const struct unit *attacker, +double unit_win_chance(const struct civ_map *nmap, + const struct unit *attacker, const struct unit *defender, const struct action *paction) { int def_power = get_total_defense_power(attacker, defender); int att_power = get_total_attack_power(attacker, defender, paction); - double chance; - int def_fp, att_fp; - get_modified_firepower(attacker, defender, &att_fp, &def_fp); + + get_modified_firepower(nmap, attacker, defender, &att_fp, &def_fp); chance = win_chance(att_power, attacker->hp, att_fp, def_power, defender->hp, def_fp); @@ -498,10 +498,11 @@ double unit_win_chance(const struct unit *attacker, had enough luck and EFT_NUKE_PROOF. If the attack was successful return NULL. ***********************************************************************/ -struct city *sdi_try_defend(const struct player *owner, +struct city *sdi_try_defend(const struct civ_map *nmap, + const struct player *owner, const struct tile *ptile) { - square_iterate(&(wld.map), ptile, 2, ptile1) { + square_iterate(nmap, ptile, 2, ptile1) { struct city *pcity = tile_city(ptile1); if (pcity @@ -521,7 +522,7 @@ struct city *sdi_try_defend(const struct player *owner, } /*******************************************************************//** - Returns if the attack is going to be a tired attack + Returns if the attack is going to be a tired attack ***********************************************************************/ bool is_tired_attack(int moves_left) { @@ -529,7 +530,7 @@ bool is_tired_attack(int moves_left) } /*******************************************************************//** - Convenience wrapper for base_get_attack_power. + Convenience wrapper for base_get_attack_power(). ***********************************************************************/ int get_attack_power(const struct unit *punit) { @@ -630,14 +631,14 @@ int get_total_attack_power(const struct unit *attacker, } /*******************************************************************//** - Return an increased defensepower. Effects which increase the - defensepower are: - - unit type effects (horse vs pikemen for example) - - defender in a fortress - - fortified defender - -May be called with a non-existing att_type to avoid any unit type -effects. + Return an increased defensepower. Effects which increase the + defensepower are: + - unit type effects (horse vs pikemen for example) + - defender in a fortress + - fortified defender + + May be called with a non-existing att_type to avoid any unit type + effects. ***********************************************************************/ static int defense_multiplication(const struct unit_type *att_type, const struct unit *def, @@ -706,7 +707,8 @@ static int defense_multiplication(const struct unit_type *att_type, May be called with a non-existing att_type to avoid any effects which depend on the attacker. ***********************************************************************/ -int get_virtual_defense_power(const struct unit_type *att_type, +int get_virtual_defense_power(const struct civ_map *nmap, + const struct unit_type *att_type, const struct unit_type *def_type, struct player *def_player, struct tile *ptile, @@ -721,7 +723,7 @@ int get_virtual_defense_power(const struct unit_type *att_type, fc_assert_ret_val(def_type != NULL, 0); - if (!can_exist_at_tile(&(wld.map), def_type, ptile)) { + if (!can_exist_at_tile(nmap, def_type, ptile)) { /* Ground units on ship doesn't defend. */ return 0; } @@ -803,17 +805,18 @@ int get_fortified_defense_power(const struct unit *attacker, } /*******************************************************************//** -A number indicating the defense strength. -Unlike the one got from win chance this doesn't potentially get insanely -small if the units are unevenly matched, unlike win_chance. + A number indicating the defense strength. + Unlike the one got from win chance this doesn't potentially get + insanely small if the units are unevenly matched, unlike win_chance(). ***********************************************************************/ -static int get_defense_rating(const struct unit *attacker, +static int get_defense_rating(const struct civ_map *nmap, + const struct unit *attacker, const struct unit *defender) { int afp, dfp; - int rating = get_total_defense_power(attacker, defender); - get_modified_firepower(attacker, defender, &afp, &dfp); + + get_modified_firepower(nmap, attacker, defender, &afp, &dfp); /* How many rounds the defender will last */ rating *= (defender->hp + afp-1)/afp; @@ -824,22 +827,23 @@ static int get_defense_rating(const struct unit *attacker, } /*******************************************************************//** - Finds the best defender on the tile, given an attacker. The diplomatic + Finds the best defender on the tile, given an attacker. The diplomatic relationship of attacker and defender is ignored; the caller should check this. ***********************************************************************/ -struct unit *get_defender(const struct unit *attacker, +struct unit *get_defender(const struct civ_map *nmap, + const struct unit *attacker, const struct tile *ptile, const struct action *paction) { struct unit *bestdef = NULL; int bestvalue = -99, best_cost = 0, rating_of_best = 0; - /* Simply call win_chance with all the possible defenders in turn, and - * take the best one. It currently uses build cost as a tiebreaker in + /* Simply call unit_win_chance() with all the possible defenders in turn, and + * take the best one. It currently uses build cost as a tiebreaker in * case 2 units are identical, but this is crude as build cost does not - * necessarily have anything to do with the value of a unit. This function - * could be improved to take the value of the unit into account. It would + * necessarily have anything to do with the value of a unit. This function + * could be improved to take the value of the unit into account. It would * also be nice if the function was a bit more fuzzy about prioritizing, * making it able to fx choose a 1a/9d unit over a 10a/10d unit. It should * also be able to spare units without full hp's to some extent, as these @@ -847,42 +851,43 @@ struct unit *get_defender(const struct unit *attacker, unit_list_iterate(ptile->units, defender) { /* We used to skip over allied units, but the logic for that is * complicated and is now handled elsewhere. */ - if (unit_can_defend_here(&(wld.map), defender) + if (unit_can_defend_here(nmap, defender) && (unit_attack_unit_at_tile_result(attacker, NULL, defender, ptile) == ATT_OK)) { bool change = FALSE; int build_cost = unit_build_shield_cost_base(defender); - int defense_rating = get_defense_rating(attacker, defender); + int defense_rating = get_defense_rating(nmap, attacker, defender); /* This will make units roughly evenly good defenders look alike. */ - int unit_def - = (int) (100000 * (1 - unit_win_chance(attacker, defender, paction))); + int unit_def + = (int) (100000 * (1 - unit_win_chance(nmap, attacker, + defender, paction))); fc_assert_action(0 <= unit_def, continue); if (unit_has_type_flag(defender, UTYF_GAMELOSS) && !is_stack_vulnerable(unit_tile(defender))) { - unit_def = -1; /* then always use leader as last defender. */ - /* FIXME: multiple gameloss units with varying defense value - * not handled. */ + unit_def = -1; /* Then always use leader as last defender. */ + /* FIXME: Multiple gameloss units with varying defense value + * not handled. */ } if (unit_def > bestvalue) { - change = TRUE; + change = TRUE; } else if (unit_def == bestvalue) { - if (build_cost < best_cost) { - change = TRUE; - } else if (build_cost == best_cost) { - if (rating_of_best < defense_rating) { - change = TRUE; - } - } + if (build_cost < best_cost) { + change = TRUE; + } else if (build_cost == best_cost) { + if (rating_of_best < defense_rating) { + change = TRUE; + } + } } if (change) { - bestvalue = unit_def; - bestdef = defender; - best_cost = build_cost; - rating_of_best = defense_rating; + bestvalue = unit_def; + bestdef = defender; + best_cost = build_cost; + rating_of_best = defense_rating; } } } unit_list_iterate_end; @@ -893,10 +898,11 @@ struct unit *get_defender(const struct unit *attacker, /*******************************************************************//** Get unit at (x, y) that wants to kill defender. - Works like get_defender; see comment there. + Works like get_defender(); see comment there. This function is mostly used by the AI. ***********************************************************************/ -struct unit *get_attacker(const struct unit *defender, +struct unit *get_attacker(const struct civ_map *nmap, + const struct unit *defender, const struct tile *ptile) { struct unit *bestatt = 0; @@ -908,7 +914,8 @@ struct unit *get_attacker(const struct unit *defender, if (pplayers_allied(unit_owner(defender), unit_owner(attacker))) { return NULL; } - unit_a = (int) (100000 * (unit_win_chance(attacker, defender, NULL))); + unit_a = (int) (100000 * (unit_win_chance(nmap, attacker, + defender, NULL))); if (unit_a > bestvalue || (unit_a == bestvalue && build_cost < best_cost)) { bestvalue = unit_a; diff --git a/common/combat.h b/common/combat.h index e1ed5eb2b1..e4dac384d0 100644 --- a/common/combat.h +++ b/common/combat.h @@ -21,13 +21,15 @@ extern "C" { #include "fc_types.h" #include "unittype.h" +struct civ_map; + /* * attack_strength and defense_strength are multiplied by POWER_FACTOR * to yield the base of attack_power and defense_power. * - * The constant may be changed since it isn't externally visible used. + * The constant may be changed since it isn't externally visibly used. */ -#define POWER_FACTOR 10 +#define POWER_FACTOR 10 enum unit_attack_result { ATT_OK, @@ -59,15 +61,18 @@ bool can_unit_attack_tile(const struct unit *punit, double win_chance(int as, int ahp, int afp, int ds, int dhp, int dfp); -void get_modified_firepower(const struct unit *attacker, +void get_modified_firepower(const struct civ_map *nmap, + const struct unit *attacker, const struct unit *defender, int *att_fp, int *def_fp); -double unit_win_chance(const struct unit *attacker, +double unit_win_chance(const struct civ_map *nmap, + const struct unit *attacker, const struct unit *defender, const struct action *paction); bool unit_really_ignores_citywalls(const struct unit *punit); -struct city *sdi_try_defend(const struct player *owner, +struct city *sdi_try_defend(const struct civ_map *nmap, + const struct player *owner, const struct tile *ptile); bool is_tired_attack(int moves_left); @@ -79,7 +84,8 @@ int get_total_defense_power(const struct unit *attacker, const struct unit *defender); int get_fortified_defense_power(const struct unit *attacker, struct unit *defender); -int get_virtual_defense_power(const struct unit_type *attacker, +int get_virtual_defense_power(const struct civ_map *nmap, + const struct unit_type *attacker, const struct unit_type *defender, struct player *defending_player, struct tile *ptile, @@ -88,10 +94,12 @@ int get_total_attack_power(const struct unit *attacker, const struct unit *defender, const struct action *paction); -struct unit *get_defender(const struct unit *attacker, +struct unit *get_defender(const struct civ_map *nmap, + const struct unit *attacker, const struct tile *ptile, const struct action *paction); -struct unit *get_attacker(const struct unit *defender, +struct unit *get_attacker(const struct civ_map *nmap, + const struct unit *defender, const struct tile *ptile); struct unit *get_diplomatic_defender(const struct unit *act_unit, diff --git a/server/unithand.c b/server/unithand.c index 50f0b3e469..a299513033 100644 --- a/server/unithand.c +++ b/server/unithand.c @@ -4630,6 +4630,7 @@ static bool unit_nuke(struct player *pplayer, struct unit *punit, { struct city *pcity; const struct unit_type *act_utype; + struct civ_map *nmap = &(wld.map); /* Sanity check: The actor still exists. */ fc_assert_ret_val(pplayer, FALSE); @@ -4642,7 +4643,7 @@ static bool unit_nuke(struct player *pplayer, struct unit *punit, unit_rule_name(punit), TILE_XY(def_tile)); - if ((pcity = sdi_try_defend(pplayer, def_tile))) { + if ((pcity = sdi_try_defend(nmap, pplayer, def_tile))) { /* FIXME: Remove the hard coded reference to SDI defense. */ notify_player(pplayer, unit_tile(punit), E_UNIT_LOST_ATT, ftc_server, _("Your %s was shot down by " @@ -4887,18 +4888,19 @@ static bool do_attack(struct unit *punit, struct tile *def_tile, int att_vet, def_vet; struct unit *pdefender; const struct unit_type *act_utype = unit_type_get(punit); + struct civ_map *nmap = &(wld.map); bool powerless; - if (!(pdefender = get_defender(punit, def_tile, paction))) { + if (!(pdefender = get_defender(nmap, punit, def_tile, paction))) { /* Can't fight air... */ return FALSE; } - + att_hp_start = punit->hp; def_hp_start = pdefender->hp; def_power = get_total_defense_power(punit, pdefender); att_power = get_total_attack_power(punit, pdefender, paction); - get_modified_firepower(punit, pdefender, &att_fp, &def_fp); + get_modified_firepower(nmap, punit, pdefender, &att_fp, &def_fp); log_debug("Start attack: %s %s against %s %s.", nation_rule_name(nation_of_player(pplayer)), diff --git a/server/unittools.c b/server/unittools.c index 6c699fc19a..477e32a972 100644 --- a/server/unittools.c +++ b/server/unittools.c @@ -293,6 +293,7 @@ bool unit_versus_unit(struct unit *attacker, struct unit *defender, int attack_firepower, defense_firepower; struct player *plr1 = unit_owner(attacker); struct player *plr2 = unit_owner(defender); + struct civ_map *nmap = &(wld.map); int max_rounds; int rounds; int att_strength; @@ -300,7 +301,7 @@ bool unit_versus_unit(struct unit *attacker, struct unit *defender, *att_hp = attacker->hp; *def_hp = defender->hp; - get_modified_firepower(attacker, defender, + get_modified_firepower(nmap, attacker, defender, &attack_firepower, &defense_firepower); log_verbose("attack:%d, defense:%d, attack firepower:%d, " @@ -356,16 +357,16 @@ void unit_bombs_unit(struct unit *attacker, struct unit *defender, { int i; int rate = unit_bombard_rate(attacker); - int attackpower = get_total_attack_power(attacker, defender, paction); int defensepower = get_total_defense_power(attacker, defender); int attack_firepower, defense_firepower; struct player *plr1 = unit_owner(attacker); struct player *plr2 = unit_owner(defender); + struct civ_map *nmap = &(wld.map); *att_hp = attacker->hp; *def_hp = defender->hp; - get_modified_firepower(attacker, defender, + get_modified_firepower(nmap, attacker, defender, &attack_firepower, &defense_firepower); log_verbose("attack:%d, defense:%d, attack firepower:%d, " @@ -1177,9 +1178,10 @@ static bool find_a_good_partisan_spot(struct tile *pcenter, struct tile **dst_tile) { int bestvalue = 0; + struct civ_map *nmap = &(wld.map); /* coords of best tile in arg pointers */ - circle_iterate(&(wld.map), pcenter, sq_radius, ptile) { + circle_iterate(nmap, pcenter, sq_radius, ptile) { int value; if (!is_native_tile(u_type, ptile)) { @@ -1195,8 +1197,8 @@ static bool find_a_good_partisan_spot(struct tile *pcenter, } /* City may not have changed hands yet; see place_partisans(). */ - value = get_virtual_defense_power(NULL, u_type, powner, - ptile, FALSE, 0); + value = get_virtual_defense_power(nmap, NULL, u_type, powner, + ptile, FALSE, 0); value *= 10; if (tile_continent(ptile) != tile_continent(pcenter)) { @@ -3348,6 +3350,7 @@ static bool unit_survive_autoattack(struct unit *punit) struct autoattack_prob_list *autoattack; int moves = punit->moves_left; int sanity1 = punit->id; + struct civ_map *nmap = &(wld.map); if (!game.server.autoattack) { return TRUE; @@ -3358,7 +3361,7 @@ static bool unit_survive_autoattack(struct unit *punit) /* Kludge to prevent attack power from dropping to zero during calc */ punit->moves_left = MAX(punit->moves_left, 1); - adjc_iterate(&(wld.map), unit_tile(punit), ptile) { + adjc_iterate(nmap, unit_tile(punit), ptile) { /* First add all eligible units to a autoattack list */ unit_list_iterate(ptile->units, penemy) { struct autoattack_prob *probability = fc_malloc(sizeof(*probability)); @@ -3390,7 +3393,7 @@ static bool unit_survive_autoattack(struct unit *punit) autoattack_prob_list_iterate_safe(autoattack, peprob, penemy) { int sanity2 = penemy->id; struct tile *ptile = unit_tile(penemy); - struct unit *enemy_defender = get_defender(punit, ptile, NULL); + struct unit *enemy_defender = get_defender(nmap, punit, ptile, NULL); double punitwin, penemywin; double threshold = 0.25; struct tile *tgt_tile = unit_tile(punit); @@ -3403,7 +3406,7 @@ static bool unit_survive_autoattack(struct unit *punit) } if (NULL != enemy_defender) { - punitwin = unit_win_chance(punit, enemy_defender, NULL); + punitwin = unit_win_chance(nmap, punit, enemy_defender, NULL); } else { /* 'penemy' can attack 'punit' but it may be not reciproque. */ punitwin = 1.0; -- 2.39.2