diff -Nur -Xfreecivdiff.ignore freeciv-cvs/common/city.c freeciv-patched/common/city.c --- freeciv-cvs/common/city.c 2003-07-24 17:02:26.000000000 +0100 +++ freeciv-patched/common/city.c 2003-07-24 17:02:27.000000000 +0100 @@ -1822,6 +1822,7 @@ polpct = 100; int makecontent = 0, makehappy = 0, /* Happiness modifiers */ forcecontent = 0, forcehappy = 0; + int defensepct[UCL_LAST]; /* Defense multipliers */ int makecontentpct = 100, forcecontentpct = 100; int makecontentmil = 0, makecontentmilper = 0; int corruptadj = 0, corruptpct = 100; @@ -1834,13 +1835,17 @@ enum tile_special_type tile_spec[CITY_MAP_SIZE][CITY_MAP_SIZE]; enum tile_terrain_type tile_terr[CITY_MAP_SIZE][CITY_MAP_SIZE]; - int amount; + int amount, i; struct player *pplayer; struct government *gov; pplayer = city_owner(pcity); gov = get_gov_pcity(pcity); + for (i = 0; i < UCL_LAST; i++) { + defensepct[i] = 100; + } + city_init_tile_mods(pcity); pcity->airlift = FALSE; @@ -1877,6 +1882,17 @@ && is_unit_terrain_affected(iter.imeff, UCL_LAST, terr, spec)) { amount = iter.imeff->amount; switch(iter.imeff->type) { + case EFT_UNIT_DEFEND: + if (iter.imeff->aff_unit == UCL_LAST) { + for (i = 0; i < UCL_LAST; i++) { + defensepct[i] = defensepct[i] * amount / 100; + } + } else { + i = iter.imeff->aff_unit; + assert(i >= 0 && i < UCL_LAST); + defensepct[i] = defensepct[i] * amount / 100; + } + break; case EFT_TAX_BONUS: tax_bonus += amount; break; case EFT_TAX_PCT: @@ -1990,6 +2006,10 @@ pcity->poladj = poladj; pcity->poppoladj = poppoladj; pcity->prodpoladj = prodpoladj; + + for (i = 0; i < UCL_LAST; i++) { + pcity->defensepct[i] = defensepct[i]; + } } /************************************************************************** diff -Nur -Xfreecivdiff.ignore freeciv-cvs/common/city.h freeciv-patched/common/city.h --- freeciv-cvs/common/city.h 2003-07-24 17:02:26.000000000 +0100 +++ freeciv-patched/common/city.h 2003-07-24 17:02:27.000000000 +0100 @@ -250,6 +250,9 @@ struct tile_mod tile_add[CITY_MAP_SIZE][CITY_MAP_SIZE]; struct tile_mod tile_pct[CITY_MAP_SIZE][CITY_MAP_SIZE]; + /* defense multiplier for each type of attacker */ + int defensepct[UCL_LAST]; + /* corruption modifiers from city improvements */ int corruptadj, corruptpct; diff -Nur -Xfreecivdiff.ignore freeciv-cvs/common/combat.c freeciv-patched/common/combat.c --- freeciv-cvs/common/combat.c 2003-07-24 17:02:26.000000000 +0100 +++ freeciv-patched/common/combat.c 2003-07-24 17:02:27.000000000 +0100 @@ -295,20 +295,6 @@ } /************************************************************************** - a wrapper function that returns whether or not the unit is on a citysquare - with citywalls -**************************************************************************/ -bool unit_behind_walls(struct unit *punit) -{ - struct city *pcity; - - if((pcity=map_get_city(punit->x, punit->y))) - return city_got_citywalls(pcity); - - return FALSE; -} - -/************************************************************************** a wrapper function returns 1 if the unit is on a square with fortress **************************************************************************/ bool unit_on_fortress(struct unit *punit) @@ -317,39 +303,6 @@ } /************************************************************************** - a wrapper function returns 1 if the unit is on a square with coastal defense -**************************************************************************/ -bool unit_behind_coastal(struct unit *punit) -{ - struct city *pcity; - if((pcity=map_get_city(punit->x, punit->y))) - return city_got_building(pcity, B_COASTAL); - return FALSE; -} - -/************************************************************************** - a wrapper function returns 1 if the unit is on a square with sam site -**************************************************************************/ -bool unit_behind_sam(struct unit *punit) -{ - struct city *pcity; - if((pcity=map_get_city(punit->x, punit->y))) - return city_got_building(pcity, B_SAM); - return FALSE; -} - -/************************************************************************** - a wrapper function returns 1 if the unit is on a square with sdi defense -**************************************************************************/ -bool unit_behind_sdi(struct unit *punit) -{ - struct city *pcity; - if((pcity=map_get_city(punit->x, punit->y))) - return city_got_building(pcity, B_SDI); - return FALSE; -} - -/************************************************************************** a wrapper function returns 1 if there is a sdi-defense close to the square **************************************************************************/ struct city *sdi_defense_close(struct player *owner, int x, int y) @@ -449,9 +402,11 @@ **************************************************************************/ static int defence_multiplication(Unit_Type_id att_type, Unit_Type_id def_type, int x, int y, - int defensepower, bool fortified) + int defensepower, bool fortified, + struct player *def_player) { struct city *pcity = map_get_city(x, y); + int defensepct = 100; if (unit_type_exists(att_type)) { if (unit_type_flag(def_type, F_PIKEMEN) @@ -464,26 +419,24 @@ 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; + /* Effects from generalised improvements; if we're in a city, use + * the city's cached defense bonus. Only consider effects if the + * attacker does not "ignore" defenses */ + if (!unit_type_flag(att_type, F_IGWALL)) { + if (pcity) { + defensepct = pcity->defensepct[get_unittype_class(att_type)]; + } else { + struct map_position mappos; + + mappos.x = x; mappos.y = y; + unittype_effects_iterate(iter, att_type, def_player, &mappos) { + if (iter.imeff->type == EFT_UNIT_DEFEND) { + defensepct = defensepct * iter.imeff->amount / 100; + } + } unittype_effects_iterate_end; } - } 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; } + defensepower = defensepower * defensepct / 100; if (unit_type_flag(att_type, F_FIGHTER) && is_heli_unittype(def_type)) { defensepower /= 2; @@ -528,8 +481,10 @@ defensepower = (defensepower * 3) / 2; } + /* FIXME: we don't know the player, so can't consider Player-range + * Unit_Defend improvement effects... */ return defence_multiplication(att_type, def_type, x, y, defensepower, - fortified); + fortified, NULL); } /*************************************************************************** @@ -542,7 +497,8 @@ return defence_multiplication(attacker->type, defender->type, defender->x, defender->y, get_defense_power(defender), - defender->activity == ACTIVITY_FORTIFIED); + defender->activity == ACTIVITY_FORTIFIED, + unit_owner(defender)); } /************************************************************************** diff -Nur -Xfreecivdiff.ignore freeciv-cvs/common/combat.h freeciv-patched/common/combat.h --- freeciv-cvs/common/combat.h 2003-07-10 11:53:38.000000000 +0100 +++ freeciv-patched/common/combat.h 2003-07-24 17:02:27.000000000 +0100 @@ -38,11 +38,7 @@ double unit_win_chance(struct unit *attacker, struct unit *defender); bool unit_really_ignores_citywalls(struct unit *punit); -bool unit_behind_walls(struct unit *punit); bool unit_on_fortress(struct unit *punit); -bool unit_behind_coastal(struct unit *punit); -bool unit_behind_sam(struct unit *punit); -bool unit_behind_sdi(struct unit *punit); struct city *sdi_defense_close(struct player *owner, int x, int y); int get_attack_power(struct unit *punit); diff -Nur -Xfreecivdiff.ignore freeciv-cvs/common/improvement.h freeciv-patched/common/improvement.h --- freeciv-cvs/common/improvement.h 2003-07-24 16:59:50.000000000 +0100 +++ freeciv-patched/common/improvement.h 2003-07-24 17:02:27.000000000 +0100 @@ -365,6 +365,16 @@ } \ } +#define unittype_effects_iterate(EI_iter, utype, pplayer, mappos) \ + { \ + struct eff_iter EI_iter; \ + eff_iterator_unit_init(&iter, utype, pplayer, mappos); \ + while (eff_iterator_next(&EI_iter)) { + +#define unittype_effects_iterate_end \ + } \ + } + /* improvement functions */ void improvements_free(void); struct impr_type *get_improvement_type(Impr_Type_id id); diff -Nur -Xfreecivdiff.ignore freeciv-cvs/doc/README.effects freeciv-patched/doc/README.effects --- freeciv-cvs/doc/README.effects 2003-07-24 16:59:50.000000000 +0100 +++ freeciv-patched/doc/README.effects 2003-07-24 17:02:27.000000000 +0100 @@ -211,7 +211,8 @@ "Trade_Route_Pct"- increases trade from trade routes by AMOUNT percent "Unit_Defend" - multiplies defense by AMOUNT percent against units - of class .aff_unit + of class .aff_unit (multiple effects are + multiplicative) "Unit_Move" - adds AMOUNT of movement points to units of class .aff_unit diff -Nur -Xfreecivdiff.ignore freeciv-cvs/server/unithand.c freeciv-patched/server/unithand.c --- freeciv-cvs/server/unithand.c 2003-07-24 17:02:27.000000000 +0100 +++ freeciv-patched/server/unithand.c 2003-07-24 17:02:27.000000000 +0100 @@ -727,7 +727,7 @@ if (punit->hp && (pcity=map_get_city(def_x, def_y)) && pcity->size>1 && - !city_got_citywalls(pcity) && + !is_under_effect(B_LAST,pcity,NULL,EFT_UNIT_NO_LOSE_POP) && kills_citizen_after_attack(punit)) { city_reduce_size(pcity,1); city_refresh(pcity);