Index: ai/advmilitary.c =================================================================== RCS file: /home/freeciv/CVS/freeciv/ai/advmilitary.c,v retrieving revision 1.97 diff -u -r1.97 advmilitary.c --- ai/advmilitary.c 2002/03/06 10:05:31 1.97 +++ ai/advmilitary.c 2002/03/06 14:44:12 @@ -593,12 +593,7 @@ } else if (real_map_distance(pcity->x, pcity->y, x, y) * SINGLE_MOVE <= m) c = 1; else c = real_map_distance(pcity->x, pcity->y, x, y) * SINGLE_MOVE * q / m; - m = get_virtual_defense_power(i, n, x, y); - m *= unit_types[n].hp * unit_types[n].firepower; - if (vet) m *= 1.5; - m /= 30; - m *= m; - d = m; + d = unit_vulnerability_virtual2(i, n, x, y, FALSE, vet, FALSE, 0); if (unit_types[i].move_type == LAND_MOVING && acity && c > (player_knows_improvement_tech(city_owner(acity), @@ -733,12 +728,10 @@ else c = real_map_distance(myunit->x, myunit->y, acity->x, acity->y) * SINGLE_MOVE / m; n = ai_choose_defender_versus(acity, v); - m = get_virtual_defense_power(v, n, x, y); - m *= unit_types[n].hp * unit_types[n].firepower; - if (do_make_unit_veteran(acity, n)) m *= 1.5; - m /= 30; if (c > 1) { - d = m * m; + d = unit_vulnerability_virtual2(v, n, x, y, FALSE, + do_make_unit_veteran(acity, n), + FALSE, 0); b = unit_types[n].build_cost + 40; vet = do_make_unit_veteran(acity, n); } else { @@ -751,14 +744,10 @@ Yet, somehow, this line existed, and remained here for months, bugging the AI tech progression beyond all description. Only when adding the override code did I realize the magnitude of my transgression. How despicable. -- Syela */ - m = get_virtual_defense_power(v, pdef->type, x, y); - if (pdef->veteran) m *= 1.5; /* with real defenders, this must be before * hp -- Syela */ - m *= (myunit->id != 0 ? pdef->hp : unit_type(pdef)->hp) * - unit_type(pdef)->firepower; -/* m /= (pdef->veteran ? 20 : 30); -- led to rounding errors. Duh! -- Syela */ - m /= 30; - if (d < m * m) { - d = m * m; + m = unit_vulnerability_virtual2(v, pdef->type, x, y, FALSE, + pdef->veteran, myunit->id, pdef->hp); + if (d < m) { + d = m; b = unit_type(pdef)->build_cost + 40; vet = pdef->veteran; n = pdef->type; /* and not before, or heinous things occur!! */ @@ -793,17 +782,9 @@ c = ((dist + m - 1) / m); n = pdef->type; - m = get_virtual_defense_power(v, n, x, y); - if (pdef->veteran) m += m / 2; - if (pdef->activity == ACTIVITY_FORTIFIED) m += m / 2; -/* attempting to recreate the rounding errors in get_total_defense_power -- Syela */ - - m *= (myunit->id != 0 ? pdef->hp : unit_types[n].hp) * unit_types[n].firepower; -/* let this be the LAST discrepancy! How horribly many there have been! -- Syela */ -/* m /= (pdef->veteran ? 20 : 30);*/ - m /= 30; - m *= m; - d = m; + d = unit_vulnerability_virtual2(v, n, x, y, + pdef->activity == ACTIVITY_FORTIFIED, + pdef->veteran, myunit->id, pdef->hp); vet = pdef->veteran; } /* end dealing with units */ Index: ai/aicity.c =================================================================== RCS file: /home/freeciv/CVS/freeciv/ai/aicity.c,v retrieving revision 1.107 diff -u -r1.107 aicity.c --- ai/aicity.c 2002/03/06 10:05:31 1.107 +++ ai/aicity.c 2002/03/06 14:44:13 @@ -305,12 +305,11 @@ static int ai_city_defender_value(struct city *pcity, Unit_Type_id a_type, Unit_Type_id d_type) { - int m; - m = get_virtual_defense_power(a_type, d_type, pcity->x, pcity->y); - if (do_make_unit_veteran(pcity, d_type)) m *= 1.5; - m *= unit_types[d_type].hp * unit_types[d_type].firepower; - m /= 30; - return (m * m); + int m = unit_vulnerability_virtual2(a_type, d_type, pcity->x, + pcity->y, FALSE, + do_make_unit_veteran(pcity, d_type), + FALSE, 0); + return m; } #endif @@ -632,7 +631,7 @@ if (!is_ai_simple_military(i)) continue; m = unit_types[i].move_type; if (can_build_unit(pcity, i) && (m == LAND_MOVING || m == SEA_MOVING)) { - j = get_virtual_defense_power(v, i, pcity->x, pcity->y); + j = get_virtual_defense_power(v, i, pcity->x, pcity->y, FALSE, FALSE); if (j > best || (j == best && get_unit_type(i)->build_cost <= get_unit_type(bestid)->build_cost)) { best = j; Index: ai/aiunit.c =================================================================== RCS file: /home/freeciv/CVS/freeciv/ai/aiunit.c,v retrieving revision 1.185 diff -u -r1.185 aiunit.c --- ai/aiunit.c 2002/03/06 05:28:19 1.185 +++ ai/aiunit.c 2002/03/06 14:44:15 @@ -588,21 +588,33 @@ int unit_vulnerability_basic(struct unit *punit, struct unit *pdef) { - int v; - - v = get_total_defense_power(punit, pdef) * - (punit->id != 0 ? pdef->hp : unit_type(pdef)->hp) * - unit_type(pdef)->firepower / 30; - - return(v); + return (get_total_defense_power(punit, pdef) * + (punit->id != 0 ? pdef->hp : unit_type(pdef)->hp) * + unit_type(pdef)->firepower / POWER_DIVIDER); } int unit_vulnerability_virtual(struct unit *punit) { - int v; - v = unit_type(punit)->defense_strength * - (punit->veteran ? 15 : 10) * punit->hp / 30; - return(v * v); + int v = base_get_defense_power(punit) * punit->hp / POWER_DIVIDER; + + return v * v; +} + +/************************************************************************** + See get_virtual_defense_power for the arguments att_type, def_type, + x, y, fortified and veteran. If use_alternative_hp is FALSE the + (maximum) hps of the given unit type is used. If use_alternative_hp + is TRUE the given alternative_hp value is used. +**************************************************************************/ +int unit_vulnerability_virtual2(Unit_Type_id att_type, Unit_Type_id def_type, + int x, int y, bool fortified, bool veteran, + bool use_alternative_hp, int alternative_hp) +{ + int v = (get_virtual_defense_power(att_type, def_type, x, y, fortified, + veteran) * + (use_alternative_hp ? alternative_hp : unit_types[def_type]. + hp) * unit_types[def_type].firepower / POWER_DIVIDER); + return v * v; } int unit_vulnerability(struct unit *punit, struct unit *pdef) @@ -790,14 +802,13 @@ continue; if (!can_unit_attack_unit_at_tile(aunit, pdef, pdef->x, pdef->y)) continue; - d = - get_virtual_defense_power(aunit->type, pdef->type, pdef->x, - pdef->y); + d = get_virtual_defense_power(aunit->type, pdef->type, pdef->x, + pdef->y, FALSE, FALSE); if (d == 0) return TRUE; /* Thanks, Markus -- Syela */ cur = unit_belligerence_primitive(aunit) * get_virtual_defense_power(punit->type, pdef->type, pdef->x, - pdef->y) / d; + pdef->y, FALSE, FALSE) / d; if (cur > val && ai_fuzzy(unit_owner(punit), TRUE)) return FALSE; } @@ -1109,11 +1120,9 @@ freelog(LOG_DEBUG, "%s@(%d,%d) looking for bodyguard, d_val=%d, my_val=%d", unit_type(punit)->name, punit->x, punit->y, d_val, - (punit->hp * (punit->veteran ? 15 : 10) - * unit_type(punit)->defense_strength)); + (punit->hp * base_get_defense_power(punit))); ptile = map_get_tile(punit->x, punit->y); - if (d_val >= punit->hp * (punit->veteran ? 15 : 10) * - unit_type(punit)->defense_strength) { + if (d_val >= punit->hp * base_get_defense_power(punit)) { /* if (!unit_list_find(&pplayer->units, punit->ai.bodyguard)) Ugggggh */ if (!unit_list_find(&ptile->units, punit->ai.bodyguard)) punit->ai.bodyguard = -1; @@ -1553,10 +1562,11 @@ * SINGLE_MOVE) / m; if (c > 1) { n = ai_choose_defender_versus(acity, punit->type); - v = get_virtual_defense_power(punit->type, n, acity->x, acity->y) * - unit_types[n].hp * unit_types[n].firepower * - (do_make_unit_veteran(acity, n) ? 1.5 : 1.0) / 30; - if (v * v >= d) { d = v * v; b = unit_types[n].build_cost + 40; } + v = unit_vulnerability_virtual2(punit->type, n, acity->x, + acity->y, FALSE, + do_make_unit_veteran(acity, n), + FALSE, 0); + if (v >= d) { d = v; b = unit_types[n].build_cost + 40; } } /* let's hope this works! */ if (!is_ground_unit(punit) && !is_heli_unit(punit) && !TEST_BIT(acity->ai.invasion, 0)) b -= 40; /* boats can't conquer cities */ Index: ai/aiunit.h =================================================================== RCS file: /home/freeciv/CVS/freeciv/ai/aiunit.h,v retrieving revision 1.32 diff -u -r1.32 aiunit.h --- ai/aiunit.h 2002/03/01 14:07:29 1.32 +++ ai/aiunit.h 2002/03/06 14:44:15 @@ -48,6 +48,9 @@ int unit_belligerence(struct unit *punit); int unit_vulnerability_basic(struct unit *punit, struct unit *pdef); int unit_vulnerability_virtual(struct unit *punit); +int unit_vulnerability_virtual2(Unit_Type_id att_type, Unit_Type_id def_type, + int x, int y, bool fortified, bool veteran, + bool use_alternative_hp, int alternative_hp); int unit_vulnerability(struct unit *punit, struct unit *pdef); int kill_desire(int benefit, int attack, int loss, int vuln, int attack_count); int military_amortize(int value, int delay, int build_cost); Index: common/combat.c =================================================================== RCS file: /home/freeciv/CVS/freeciv/common/combat.c,v retrieving revision 1.20 diff -u -r1.20 combat.c --- common/combat.c 2002/03/01 14:07:30 1.20 +++ common/combat.c 2002/03/06 14:44:19 @@ -266,27 +266,29 @@ } /************************************************************************** - returns the defense power, modified by terrain and veteran status + Returns the defense power, modified by veteran status. **************************************************************************/ -int get_defense_power(struct unit *punit) +int base_get_defense_power(struct unit *punit) { - int power; - enum tile_terrain_type terra; - int db; - - if (!punit || punit->type<0 || punit->type>=U_LAST - || punit->type>=game.num_unit_types) - abort(); - power = unit_type(punit)->defense_strength * POWER_FACTOR; + int power = unit_type(punit)->defense_strength * POWER_FACTOR; if (punit->veteran) { - power *= 3; - power /= 2; + power = (power * 3) / 2; } - terra=map_get_terrain(punit->x, punit->y); - db = get_tile_type(terra)->defense_bonus; - if (map_has_special(punit->x, punit->y, S_RIVER)) + return power; +} + +/************************************************************************** + Returns the defense power, modified by terrain and veteran status. +**************************************************************************/ +int get_defense_power(struct unit *punit) +{ + int db, power = base_get_defense_power(punit); + + db = get_tile_type(map_get_terrain(punit->x, punit->y))->defense_bonus; + if (map_has_special(punit->x, punit->y, S_RIVER)) { db += (db * terrain_control.river_defense_bonus) / 100; - power=(power*db)/10; + } + power = (power * db) / 10; return power; } @@ -302,81 +304,95 @@ return attackpower; } -/*************************************************************************** - Like get_virtual_defense_power, but don't include most of the modifications. - (For calls which used to be g_v_d_p(U_HOWITZER,...)) - Specifically, include: - unit def, terrain effect, fortress effect, ground unit in city effect -***************************************************************************/ -int get_simple_defense_power(Unit_Type_id d_type, int x, int y) +/************************************************************************** + 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 defence_multiplication(Unit_Type_id att_type, + Unit_Type_id def_type, int x, int y, + int defensepower, bool fortified) { - int defensepower=unit_types[d_type].defense_strength; struct city *pcity = map_get_city(x, y); - enum tile_terrain_type t = map_get_terrain(x, y); - int db; - if (unit_types[d_type].move_type == LAND_MOVING && t == T_OCEAN) return 0; -/* I had this dorky bug where transports with mech inf aboard would go next -to enemy ships thinking the mech inf would defend them adequately. -- Syela */ + if (unit_type_exists(att_type)) { + if (unit_type_flag(def_type, F_PIKEMEN) + && unit_type_flag(att_type, F_HORSE)) { + defensepower *= 2; + } + + if (unit_type_flag(def_type, F_AEGIS) && + (is_air_unittype(att_type) || is_heli_unittype(att_type))) { + defensepower *= 5; + } + + if (is_air_unittype(att_type) && pcity) { + if (city_got_building(pcity, B_SAM)) { + defensepower *= 2; + } + if (city_got_building(pcity, B_SDI) + && unit_type_flag(att_type, F_MISSILE)) { + defensepower *= 2; + } + } else if (is_water_unit(att_type) && pcity) { + if (city_got_building(pcity, B_COASTAL)) { + defensepower *= 2; + } + } + if (!unit_type_flag(att_type, F_IGWALL) + && (is_ground_unittype(att_type) || is_heli_unittype(att_type) + || (improvement_variant(B_CITY) == 1 + && is_water_unit(att_type))) && pcity + && city_got_citywalls(pcity)) { + defensepower *= 3; + } + } - db = get_tile_type(t)->defense_bonus; - if (map_has_special(x, y, S_RIVER)) - db += (db * terrain_control.river_defense_bonus) / 100; - defensepower *= db; + if (map_has_special(x, y, S_FORTRESS) && !pcity) { + defensepower += + (defensepower * terrain_control.fortress_defense_bonus) / 100; + } - if (map_has_special(x, y, S_FORTRESS) && !pcity) - defensepower+=(defensepower*terrain_control.fortress_defense_bonus)/100; - if (pcity && unit_types[d_type].move_type == LAND_MOVING) - defensepower*=1.5; + if ((pcity || fortified) && is_ground_unittype(def_type)) { + defensepower = (defensepower * 3) / 2; + } return defensepower; } /************************************************************************** -... + May be called with a non-existing att_type to avoid any effects which + depend on the attacker. **************************************************************************/ -int get_virtual_defense_power(Unit_Type_id a_type, Unit_Type_id d_type, int x, int y) +int get_virtual_defense_power(Unit_Type_id att_type, Unit_Type_id def_type, + int x, int y, bool fortified, bool veteran) { - int defensepower=unit_types[d_type].defense_strength; - enum unit_move_type m_type = unit_types[a_type].move_type; - struct city *pcity = map_get_city(x, y); + int defensepower = unit_types[def_type].defense_strength; enum tile_terrain_type t = map_get_terrain(x, y); int db; - if (unit_types[d_type].move_type == LAND_MOVING && t == T_OCEAN) return 0; -/* I had this dorky bug where transports with mech inf aboard would go next -to enemy ships thinking the mech inf would defend them adequately. -- Syela */ + if (unit_types[def_type].move_type == LAND_MOVING && t == T_OCEAN) { + /* Ground units on ship doesn't defend. */ + return 0; + } db = get_tile_type(t)->defense_bonus; - if (map_has_special(x, y, S_RIVER)) + if (map_has_special(x, y, S_RIVER)) { db += (db * terrain_control.river_defense_bonus) / 100; + } defensepower *= db; - if (unit_type_flag(d_type, F_PIKEMEN) && unit_type_flag(a_type, F_HORSE)) - defensepower*=2; - if (unit_type_flag(d_type, F_AEGIS) && - (m_type == AIR_MOVING || m_type == HELI_MOVING)) defensepower*=5; - if (m_type == AIR_MOVING && pcity) { - if (city_got_building(pcity, B_SAM)) - defensepower*=2; - if (city_got_building(pcity, B_SDI) && unit_type_flag(a_type, F_MISSILE)) - defensepower*=2; - } else if (m_type == SEA_MOVING && pcity) { - if (city_got_building(pcity, B_COASTAL)) - defensepower*=2; - } - if (!unit_type_flag(a_type, F_IGWALL) - && (m_type == LAND_MOVING || m_type == HELI_MOVING - || (improvement_variant(B_CITY)==1 && m_type == SEA_MOVING)) - && pcity && city_got_citywalls(pcity)) { - defensepower*=3; - } - if (map_has_special(x, y, S_FORTRESS) && !pcity) - defensepower+=(defensepower*terrain_control.fortress_defense_bonus)/100; - if (pcity && unit_types[d_type].move_type == LAND_MOVING) - defensepower*=1.5; + if (veteran) { + defensepower = (defensepower * 3) / 2; + } - return defensepower; + return defence_multiplication(att_type, def_type, x, y, defensepower, + fortified); } /*************************************************************************** @@ -386,33 +402,10 @@ ***************************************************************************/ int get_total_defense_power(struct unit *attacker, struct unit *defender) { - int defensepower=get_defense_power(defender); - if (unit_flag(defender, F_PIKEMEN) && unit_flag(attacker, F_HORSE)) - defensepower*=2; - if (unit_flag(defender, F_AEGIS) - && (is_air_unit(attacker) || is_heli_unit(attacker))) - defensepower *= 5; - if (is_air_unit(attacker)) { - if (unit_behind_sam(defender)) - defensepower*=2; - if (unit_behind_sdi(defender) && unit_flag(attacker, F_MISSILE)) - defensepower*=2; - } else if (is_sailing_unit(attacker)) { - if (unit_behind_coastal(defender)) - defensepower*=2; - } - if (!unit_really_ignores_citywalls(attacker) - && unit_behind_walls(defender)) - defensepower*=3; - if (unit_on_fortress(defender) && - !map_get_city(defender->x, defender->y)) - defensepower*=2; - if ((defender->activity == ACTIVITY_FORTIFIED || - map_get_city(defender->x, defender->y)) && - is_ground_unit(defender)) - defensepower*=1.5; - - return defensepower; + return defence_multiplication(attacker->type, defender->type, + defender->x, defender->y, + get_defense_power(defender), + defender->activity == ACTIVITY_FORTIFIED); } /************************************************************************** Index: common/combat.h =================================================================== RCS file: /home/freeciv/CVS/freeciv/common/combat.h,v retrieving revision 1.5 diff -u -r1.5 combat.h --- common/combat.h 2002/03/01 14:07:31 1.5 +++ common/combat.h 2002/03/06 14:44:19 @@ -43,10 +43,11 @@ int get_attack_power(struct unit *punit); int base_get_attack_power(Unit_Type_id type, bool veteran, int moves_left); +int base_get_defense_power(struct unit *punit); int get_defense_power(struct unit *punit); int get_total_defense_power(struct unit *attacker, struct unit *defender); -int get_simple_defense_power(Unit_Type_id d_type, int x, int y); -int get_virtual_defense_power(Unit_Type_id a_type, Unit_Type_id d_type, int x, int y); +int get_virtual_defense_power(Unit_Type_id att_type, Unit_Type_id def_type, + int x, int y, bool fortified, bool veteran); int get_total_attack_power(struct unit *attacker, struct unit *defender); struct unit *get_defender(struct unit *attacker, int x, int y); Index: server/gotohand.c =================================================================== RCS file: /home/freeciv/CVS/freeciv/server/gotohand.c,v retrieving revision 1.141 diff -u -r1.141 gotohand.c --- server/gotohand.c 2002/02/27 11:12:50 1.141 +++ server/gotohand.c 2002/03/06 14:44:21 @@ -888,7 +888,7 @@ const int dest_x, const int dest_y) { #define UNIT_DEFENSE(punit, x, y, defence_multiplier) \ - ((get_simple_defense_power((punit)->type, (x), (y)) * \ + ((get_virtual_defense_power(U_LAST, (punit)->type, (x), (y), FALSE, FALSE) *\ (defence_multiplier)) / 2) #define UNIT_RATING(punit, x, y, defence_multiplier) \ Index: server/unittools.c =================================================================== RCS file: /home/freeciv/CVS/freeciv/server/unittools.c,v retrieving revision 1.165 diff -u -r1.165 unittools.c --- server/unittools.c 2002/03/05 15:46:28 1.165 +++ server/unittools.c 2002/03/06 14:44:23 @@ -1276,7 +1276,7 @@ continue; if (unit_list_size(&ptile->units) > 0) continue; - value = get_simple_defense_power(u_type, x1, y1); + value = get_virtual_defense_power(U_LAST, u_type, x1, y1, FALSE, FALSE); value *= 10; if (ptile->continent != map_get_continent(pcity->x, pcity->y))