diff -Nur -Xfreecivdiff.ignore freeciv-cvs/common/city.c freeciv-patched/common/city.c --- freeciv-cvs/common/city.c 2003-07-10 11:53:00.000000000 +0100 +++ freeciv-patched/common/city.c 2003-07-10 11:53:12.000000000 +0100 @@ -1713,6 +1713,33 @@ pcity->unlimit_impr = unlimit_impr; } +static void update_bonus(int bonus[4], int amount, struct eff_iter *iter, + bool add_bonus) +{ + int bonusind = 0; + + if (iter->imeff->outside) { + switch(iter->range) { + case EFR_ISLAND: + bonusind = 1; + break; + case EFR_PLAYER: + bonusind = 2; + break; + case EFR_WORLD: + bonusind = 3; + break; + default: + break; + } + } + if (add_bonus) { + bonus[bonusind] += amount; + } else { + bonus[bonusind] = bonus[bonusind] * amount / 100; + } +} + /************************************************************************** Updates the various modifiers and bonuses due to city improvements (should be called whenever city effects change - i.e. by @@ -1720,10 +1747,12 @@ **************************************************************************/ void update_city_bonuses(struct city *pcity) { - int tax_bonus = 100, science_bonus = 100, /* City bonuses */ - shield_bonus = 100, luxury_bonus = 100; - int tax_pct = 100, science_pct = 100, /* City bonus multipliers */ - shield_pct = 100, luxury_pct = 100; + int tax_bonus[4] = { 100, 100, 100, 100 }; + int science_bonus[4] = { 100, 100, 100, 100 }; + int shield_bonus = 100, luxury_bonus = 100; /* City bonuses */ + int tax_pct[4] = { 100, 100, 100, 100 }; + int science_pct[4] = { 100, 100, 100, 100 }; + int shield_pct = 100, luxury_pct = 100; /* City bonus multipliers */ int poppoladj = 100, prodpoladj = 100, /* Pollution adjustments */ poladj = 100; int poppolpct = 100, prodpolpct = 100, /* Pollution multipliers */ @@ -1810,17 +1839,21 @@ * amount / 100; break; case EFT_TAX_BONUS: - tax_bonus += amount; break; + update_bonus(tax_bonus, amount, &iter, TRUE); + break; case EFT_TAX_PCT: - tax_pct = tax_pct * amount / 100; break; + update_bonus(tax_pct, amount, &iter, FALSE); + break; case EFT_LUXURY_BONUS: luxury_bonus += amount; break; case EFT_LUXURY_PCT: luxury_pct = luxury_pct * amount / 100; break; case EFT_SCIENCE_BONUS: - science_bonus += amount; break; + update_bonus(science_bonus, amount, &iter, TRUE); + break; case EFT_SCIENCE_PCT: - science_pct = science_pct * amount / 100; break; + update_bonus(science_pct, amount, &iter, FALSE); + break; case EFT_PROD_BONUS: shield_bonus += amount; break; case EFT_PROD_PCT: @@ -1887,8 +1920,10 @@ /* Apply the multipliers to the bonuses (such that the bonuses are all summed first, and only then are the multipliers applied) */ - tax_bonus = tax_bonus * tax_pct / 100; - science_bonus = science_bonus * science_pct / 100; + for (i = 0; i < 4; ++i) { + tax_bonus[i] = tax_bonus[i] * tax_pct[i] / 100; + science_bonus[i] = science_bonus[i] * science_pct[i] / 100; + } shield_bonus = shield_bonus * shield_pct / 100; luxury_bonus = luxury_bonus * luxury_pct / 100; makecontent = makecontent * makecontentpct / 100; @@ -1906,11 +1941,17 @@ } if (government_has_flag(gov, G_REDUCED_RESEARCH)) { - science_bonus /= 2; + science_bonus[0] /= 2; } - pcity->tax_bonus = tax_bonus; - pcity->science_bonus = science_bonus; + pcity->tax_bonus = tax_bonus[0]; + pcity->science_bonus = science_bonus[0]; + /* FIXME: no handling of Island-range yet */ + pplayer->tax_bonus = tax_bonus[2]; + pplayer->science_bonus = science_bonus[2]; + game.tax_bonus = tax_bonus[3]; + game.science_bonus = science_bonus[3]; + pcity->shield_bonus = shield_bonus; pcity->shield_prod = pcity->shield_prod * shield_bonus / 100; pcity->makecontent = makecontent; diff -Nur -Xfreecivdiff.ignore freeciv-cvs/common/game.h freeciv-patched/common/game.h --- freeciv-cvs/common/game.h 2003-07-10 11:53:00.000000000 +0100 +++ freeciv-patched/common/game.h 2003-07-10 11:53:12.000000000 +0100 @@ -166,6 +166,9 @@ int watchtower_vision; int allowed_city_names; + /* Bonuses that affect all cities */ + int science_bonus, tax_bonus; + char rulesetdir[MAX_LEN_NAME]; int firepower_factor; /* See README.rulesets */ struct { diff -Nur -Xfreecivdiff.ignore freeciv-cvs/common/improvement.c freeciv-patched/common/improvement.c --- freeciv-cvs/common/improvement.c 2003-07-10 11:53:12.000000000 +0100 +++ freeciv-patched/common/improvement.c 2003-07-10 11:53:12.000000000 +0100 @@ -1214,7 +1214,8 @@ && iter->imeff->range == iter->range && (iter->imeff->range != EFR_LOCAL || effect->impr == iter->impr) - && is_city_affected(iter->imeff, iter->pcity)) { + && is_city_affected(iter->imeff, iter->pcity) + && is_effect_outside(iter->imeff, iter->pcity)) { return iter->imeff; } } @@ -1295,13 +1296,39 @@ Returns TRUE if the given effect should affect the given city (i.e. it has the building required for the effect to be active) **************************************************************************/ -int is_city_affected(struct impr_effect *imeff, struct city *pcity) +bool is_city_affected(struct impr_effect *imeff, struct city *pcity) { return (imeff->cond_bldg == B_LAST || (pcity && city_got_building(pcity, imeff->cond_bldg))); } /************************************************************************** + Returns TRUE if the given effect is in a city, or if it's in the field + and its "outside" flag is set, or if "outside" is ignored for this effect +**************************************************************************/ +bool is_effect_outside(struct impr_effect *imeff, struct city *pcity) +{ + if (!pcity && !imeff->outside) { + switch(imeff->type) { + case EFT_UNIT_DEFEND: + case EFT_UNIT_ATTACK: + case EFT_UNIT_DEFEND_FIREPOWER: + case EFT_UNIT_ATTACK_FIREPOWER: + case EFT_UNIT_RECOVER: + case EFT_UNIT_VET_COMBAT: + case EFT_UPGRADE_ONE_STEP: + case EFT_UPGRADE_ONE_LEAP: + case EFT_UPGRADE_ALL_STEP: + case EFT_UPGRADE_ALL_LEAP: + return FALSE; + default: + break; + } + } + return TRUE; +} + +/************************************************************************** Returns TRUE if the given effect should affect the given unit/terrain/special, by checking the relevant aff_xxx fields (Pass in NULL, T_UNKNOWN, and S_ALL respectively if you don't care diff -Nur -Xfreecivdiff.ignore freeciv-cvs/common/improvement.h freeciv-patched/common/improvement.h --- freeciv-cvs/common/improvement.h 2003-07-10 11:53:12.000000000 +0100 +++ freeciv-patched/common/improvement.h 2003-07-10 11:53:12.000000000 +0100 @@ -192,6 +192,9 @@ enum effect_range range; int amount; int survives; /* 1 = effect survives wonder destruction */ + int outside; /* 1 = effect influences units outside + * of cities, not just those in the + * center tile */ Impr_Type_id cond_bldg; /* B_LAST = unconditional */ int cond_gov; /* game.government_count = unconditional */ Tech_Type_id cond_adv; /* A_NONE = unconditional; A_LAST = never */ @@ -329,7 +332,8 @@ struct unit_classes *aff_unit, enum tile_terrain_type aff_terr, enum tile_special_type aff_spec); -int is_city_affected(struct impr_effect *imeff, struct city *pcity); +bool is_city_affected(struct impr_effect *imeff, struct city *pcity); +bool is_effect_outside(struct impr_effect *imeff, struct city *pcity); #define city_effects_iterate(EI_iter, pcity) \ { \ diff -Nur -Xfreecivdiff.ignore freeciv-cvs/common/packets.c freeciv-patched/common/packets.c --- freeciv-cvs/common/packets.c 2003-07-10 11:53:12.000000000 +0100 +++ freeciv-patched/common/packets.c 2003-07-10 11:53:12.000000000 +0100 @@ -179,8 +179,11 @@ } static void dio_put_effects(struct data_out *dout, + struct connection *pc, const struct impr_effect *effect); -static void dio_get_effects(struct data_in *din, struct impr_effect **peff); +static void dio_get_effects(struct data_in *din, + struct connection *pc, + struct impr_effect **peff); /************************************************************************** presult indicates if there is more packets in the cache. We return result @@ -2064,7 +2067,7 @@ dio_put_uint8(&dout, packet->pop_cost); if (has_capability("impr_gen", pc->capability)) { - dio_put_effects(&dout, packet->effect); + dio_put_effects(&dout, pc, packet->effect); } /* This must be last, so client can determine length: */ @@ -2128,7 +2131,7 @@ dio_get_uint8(&din, &packet->pop_cost); if (has_capability("impr_gen", pc->capability)) { - dio_get_effects(&din, &packet->effect); + dio_get_effects(&din, pc, &packet->effect); } else { packet->effect = fc_malloc(sizeof(struct impr_effect)); packet->effect[0].type = EFT_LAST; @@ -2220,6 +2223,7 @@ ... **************************************************************************/ static void dio_put_effects(struct data_out *dout, + struct connection *pc, const struct impr_effect *effect) { const struct impr_effect *eff; @@ -2237,6 +2241,9 @@ dio_put_uint8(dout, eff->range); dio_put_sint16(dout, eff->amount); dio_put_uint8(dout, eff->survives); + if (has_capability("impr_gen", pc->capability)) { + dio_put_uint8(dout, eff->outside); + } dio_put_uint8(dout, eff->cond_bldg); dio_put_uint8(dout, eff->cond_gov); dio_put_uint8(dout, eff->cond_adv); @@ -2276,7 +2283,7 @@ dio_put_uint16(&dout, packet->build_cost); dio_put_uint8(&dout, packet->upkeep); dio_put_uint8(&dout, packet->sabotage); - dio_put_effects(&dout, packet->effect); + dio_put_effects(&dout, pc, packet->effect); dio_put_uint8(&dout, packet->variant); /* FIXME: remove when gen-impr obsoletes */ dio_put_string(&dout, packet->name); @@ -2300,7 +2307,9 @@ /************************************************************************** ... **************************************************************************/ -static void dio_get_effects(struct data_in *din, struct impr_effect **peff) +static void dio_get_effects(struct data_in *din, + struct connection *pc, + struct impr_effect **peff) { int count, inx; struct impr_effect *effect; @@ -2312,6 +2321,9 @@ dio_get_uint8(din, (int *)&(effect[inx].range)); dio_get_sint16(din, &(effect[inx].amount)); dio_get_uint8(din, &(effect[inx].survives)); + if (has_capability("impr_gen", pc->capability)) { + dio_get_uint8(din, &(effect[inx].outside)); + } dio_get_uint8(din, &(effect[inx].cond_bldg)); dio_get_uint8(din, &(effect[inx].cond_gov)); dio_get_uint8(din, &(effect[inx].cond_adv)); @@ -2350,7 +2362,7 @@ dio_get_uint16(&din, &packet->build_cost); dio_get_uint8(&din, &packet->upkeep); dio_get_uint8(&din, &packet->sabotage); - dio_get_effects(&din, &packet->effect); + dio_get_effects(&din, pc, &packet->effect); dio_get_uint8(&din, &packet->variant); /* FIXME: remove when gen-impr obsoletes */ dio_get_string(&din, packet->name, sizeof(packet->name)); @@ -2634,7 +2646,7 @@ dio_put_string(&dout, packet->graphic_alt); if (has_capability("impr_gen", pc->capability)) { - dio_put_effects(&dout, packet->effect); + dio_put_effects(&dout, pc, packet->effect); } /* This must be last, so client can determine length: */ @@ -2731,7 +2743,7 @@ dio_get_string(&din, packet->graphic_alt, sizeof(packet->graphic_alt)); if (has_capability("impr_gen", pc->capability)) { - dio_get_effects(&din, &packet->effect); + dio_get_effects(&din, pc, &packet->effect); } else { packet->effect = fc_malloc(sizeof(struct impr_effect)); packet->effect[0].type = EFT_LAST; @@ -2788,7 +2800,7 @@ dio_put_uint8(&dout, packet->city_style); dio_put_tech_list(&dout, packet->init_techs); if (has_capability("impr_gen", pc->capability)) { - dio_put_effects(&dout, packet->effect); + dio_put_effects(&dout, pc, packet->effect); } if (has_capability("class_legend", pc->capability)) { dio_put_string(&dout, packet->class); @@ -2828,7 +2840,7 @@ dio_get_uint8(&din, &packet->city_style); dio_get_tech_list(&din, packet->init_techs); if (has_capability("impr_gen", pc->capability)) { - dio_get_effects(&din, &packet->effect); + dio_get_effects(&din, pc, &packet->effect); } if (has_capability("class_legend", pc->capability)) { dio_get_string(&din, packet->class, sizeof(packet->class)); diff -Nur -Xfreecivdiff.ignore freeciv-cvs/common/player.h freeciv-patched/common/player.h --- freeciv-cvs/common/player.h 2003-07-10 11:53:12.000000000 +0100 +++ freeciv-patched/common/player.h 2003-07-10 11:53:12.000000000 +0100 @@ -210,6 +210,9 @@ struct ceff_vector destroyed_effects;/* list of effects that have survived * building destruction */ + /* Bonuses that affect all cities */ + int science_bonus, tax_bonus; + struct { int length; void *data; diff -Nur -Xfreecivdiff.ignore freeciv-cvs/common/tech.c freeciv-patched/common/tech.c --- freeciv-cvs/common/tech.c 2003-07-10 11:49:12.000000000 +0100 +++ freeciv-patched/common/tech.c 2003-07-10 11:53:12.000000000 +0100 @@ -22,6 +22,7 @@ #include "fcintl.h" #include "game.h" +#include "log.h" #include "player.h" #include "shared.h" /* ARRAY_SIZE */ #include "support.h" @@ -327,18 +328,33 @@ } /************************************************************************** - Returns number of turns to advance (assuming current state of - civilization). + Returns the total number of bulbs the civilization produces every turn **************************************************************************/ -int tech_turns_to_advance(struct player *pplayer) +int total_science_output(struct player *pplayer) { - /* The number of bulbs the civilization produces every turn. */ int current_output = 0; city_list_iterate(pplayer->cities, pcity) { current_output += pcity->science_total; } city_list_iterate_end; + freelog(LOG_DEBUG, "Total science output: %d", current_output); + current_output = current_output * pplayer->science_bonus / 100; + current_output = current_output * game.science_bonus / 100; + freelog(LOG_DEBUG, "Player bonus %d; game bonus %d; total %d", + pplayer->science_bonus, game.science_bonus, current_output); + + return current_output; +} + +/************************************************************************** + Returns number of turns to advance (assuming current state of + civilization). +**************************************************************************/ +int tech_turns_to_advance(struct player *pplayer) +{ + int current_output = total_science_output(pplayer); + if (current_output <= 0) { return FC_INFINITY; } diff -Nur -Xfreecivdiff.ignore freeciv-cvs/common/tech.h freeciv-patched/common/tech.h --- freeciv-cvs/common/tech.h 2003-07-07 18:23:57.000000000 +0100 +++ freeciv-patched/common/tech.h 2003-07-10 11:53:12.000000000 +0100 @@ -119,6 +119,7 @@ enum tech_flag_id tech_flag_from_str(const char *s); Tech_Type_id find_tech_by_flag(int index, enum tech_flag_id flag); +int total_science_output(struct player *pplayer); int tech_turns_to_advance(struct player *pplayer); int total_bulbs_required(struct player *pplayer); diff -Nur -Xfreecivdiff.ignore freeciv-cvs/data/civ1/buildings.ruleset freeciv-patched/data/civ1/buildings.ruleset --- freeciv-cvs/data/civ1/buildings.ruleset 2003-07-10 11:53:00.000000000 +0100 +++ freeciv-patched/data/civ1/buildings.ruleset 2003-07-10 11:53:12.000000000 +0100 @@ -1793,9 +1793,9 @@ upkeep = 0 sabotage = 0 effect = - { "type", "range", "amount", "aff_unit" + { "type", "range", "amount", "aff_unit", "outside" + "Unit_Vet_Combat", "Player", 100, "Land", 1 "Unit_Veteran", "Player", 0, "Land" - "Unit_Vet_Combat", "Player", 100, "Land" } sound = "w_sun_tzus_war_academy" sound_alt = "w_generic" diff -Nur -Xfreecivdiff.ignore freeciv-cvs/data/civ2/buildings.ruleset freeciv-patched/data/civ2/buildings.ruleset --- freeciv-cvs/data/civ2/buildings.ruleset 2003-07-10 11:52:25.000000000 +0100 +++ freeciv-patched/data/civ2/buildings.ruleset 2003-07-10 11:53:12.000000000 +0100 @@ -1801,9 +1801,9 @@ upkeep = 0 sabotage = 0 effect = - { "type", "range", "amount", "aff_unit" + { "type", "range", "amount", "aff_unit", "outside" + "Unit_Vet_Combat", "Player", 100, "Land", 1 "Unit_Veteran", "Player", 0, "Land" - "Unit_Vet_Combat", "Player", 100, "Land" } sound = "w_sun_tzus_war_academy" sound_alt = "w_generic" diff -Nur -Xfreecivdiff.ignore freeciv-cvs/data/default/buildings.ruleset freeciv-patched/data/default/buildings.ruleset --- freeciv-cvs/data/default/buildings.ruleset 2003-07-10 11:53:00.000000000 +0100 +++ freeciv-patched/data/default/buildings.ruleset 2003-07-10 11:53:12.000000000 +0100 @@ -1999,9 +1999,9 @@ upkeep = 0 sabotage = 0 effect = - { "type", "range", "amount", "aff_unit" + { "type", "range", "amount", "aff_unit", "outside" + "Unit_Vet_Combat", "Player", 100, "Land", 1 "Unit_Veteran", "Player", 0, "Land" - "Unit_Vet_Combat", "Player", 100, "Land" } sound = "w_sun_tzus_war_academy" sound_alt = "w_generic" @@ -2028,12 +2028,12 @@ upkeep = 0 sabotage = 0 effect = - { "type", "range", "amount", "aff_unit" - "Unit_Recover", "Player", 2, "Air" - "Unit_Recover", "Player", 2, "Heli" - "Unit_Recover", "Player", 2, "Land" - "Unit_Recover", "Player", 2, "Missile" - "Unit_Recover", "Player", 2, "Sea" + { "type", "range", "amount", "aff_unit", "outside" + "Unit_Recover", "Player", 2, "Air", 1 + "Unit_Recover", "Player", 2, "Heli", 1 + "Unit_Recover", "Player", 2, "Land", 1 + "Unit_Recover", "Player", 2, "Missile", 1 + "Unit_Recover", "Player", 2, "Sea", 1 } sound = "w_united_nations" sound_alt = "w_generic" diff -Nur -Xfreecivdiff.ignore freeciv-cvs/doc/README.effects freeciv-patched/doc/README.effects --- freeciv-cvs/doc/README.effects 2003-07-10 11:53:00.000000000 +0100 +++ freeciv-patched/doc/README.effects 2003-07-10 11:53:12.000000000 +0100 @@ -270,6 +270,16 @@ (must be in the range -32767 to 32767) .survives = 1 if effect survives destruction (wonders only) (if unspecified, 0 (doesn't survive) is assumed) +.outside = 1 if, for effects at greater than City-range, the effect + is active in all tiles, not just the city center. For tax + and science city bonuses, this means that the TOTAL science + output of all cities affected is subject to the bonus, + rather than the output of each city individually. + Applicable effects: Science_Bonus, Science_Pct, + Tax_Bonus, Tax_Pct, Unit_Defend, Unit_Attack, + Unit_Attack_Firepower, Unit_Defend_Firepower, + Unit_Recover, Unit_Vet_Combat, Upgrade_* + (if unspecified, 0 (city center only) is assumed) .cond_bldg = effect is only active in cities that have this building (if unspecified, effect not conditional on building) .cond_nat = must be this nation for effect diff -Nur -Xfreecivdiff.ignore freeciv-cvs/server/cityturn.c freeciv-patched/server/cityturn.c --- freeciv-cvs/server/cityturn.c 2003-07-10 11:52:48.000000000 +0100 +++ freeciv-patched/server/cityturn.c 2003-07-10 11:53:12.000000000 +0100 @@ -400,16 +400,36 @@ } /************************************************************************** + N.B. We call update_tech for the total science output, rather than for + each city individually, to reduce rounding error when applying science + bonuses. +***************************************************************************/ +static void update_all_tech(struct player *pplayer) +{ + int current_output = total_science_output(pplayer); + + update_tech(pplayer, current_output); +} + +/************************************************************************** ... **************************************************************************/ void update_city_activities(struct player *pplayer) { - int gold; + int gold, goldmade; gold=pplayer->economic.gold; pplayer->got_tech = FALSE; city_list_iterate(pplayer->cities, pcity) update_city_activity(pplayer, pcity); city_list_iterate_end; + + /* Apply impr. gen. global tax bonuses */ + goldmade = pplayer->economic.gold - gold; + goldmade = goldmade * pplayer->tax_bonus / 100; + goldmade = goldmade * game.tax_bonus / 100; + pplayer->economic.gold = gold + goldmade; + + update_all_tech(pplayer); pplayer->ai.prev_gold = gold; /* This test include the cost of the units because pay_for_units is called * in update_city_activity */ @@ -1307,7 +1327,6 @@ pcity->did_sell=FALSE; pcity->did_buy = FALSE; - update_tech(pplayer, pcity->science_total); pplayer->economic.gold+=pcity->tax_total; pay_for_units(pplayer, pcity); pay_for_buildings(pplayer, pcity); diff -Nur -Xfreecivdiff.ignore freeciv-cvs/server/ruleset.c freeciv-patched/server/ruleset.c --- freeciv-cvs/server/ruleset.c 2003-07-10 11:53:12.000000000 +0100 +++ freeciv-patched/server/ruleset.c 2003-07-10 11:53:12.000000000 +0100 @@ -767,6 +767,8 @@ e->survives = secfile_lookup_int_default(file, 0, "%s.effect%d.survives", secname, j); } + e->outside = secfile_lookup_int_default(file, 0, "%s.effect%d.outside", + secname, j); item = secfile_lookup_str_default(file, "", "%s.effect%d.cond_bldg", secname, j); diff -Nur -Xfreecivdiff.ignore freeciv-cvs/server/unittools.c freeciv-patched/server/unittools.c --- freeciv-cvs/server/unittools.c 2003-07-10 11:53:00.000000000 +0100 +++ freeciv-patched/server/unittools.c 2003-07-10 11:53:12.000000000 +0100 @@ -245,14 +245,17 @@ unit_list_init(&candidates); unit_list_iterate(pplayer->units, punit) { + struct city *mapcity = map_get_city(punit->x, punit->y); + tile_t = map_get_terrain(punit->x, punit->y); spec_t = map_get_special(punit->x, punit->y); get_unit_classes(punit, &aff_unit); if (is_unit_terrain_affected(iter->imeff, &aff_unit, tile_t, spec_t) && + is_effect_outside(iter->imeff, mapcity) && (continent == -1 || continent == map_get_continent(punit->x, punit->y)) && - (!pcity || pcity == map_get_city(punit->x, punit->y)) && + (!pcity || pcity == mapcity) && (upgrade_type = can_upgrade_unittype(pplayer, punit->type, upgrade_leap)) != -1 && !upgrade_would_strand(punit, upgrade_type)) {