Complete.Org:
Mailing Lists:
Archives:
freeciv-dev:
September 2004: [Freeciv-Dev] (PR#9961) Re: effects |
![]() |
[Freeciv-Dev] (PR#9961) Re: effects[Date Prev][Date Next][Thread Prev][Thread Next][Date Index] [Thread Index]
<URL: http://rt.freeciv.org/Ticket/Display.html?id=9961 > Mike Kaufman wrote: > in find_source_building() why do you check for !is_wonder(*pbldg) ? > I think this is wrong. I should look for non-wonder buildings first, but after > that search the wonders. This shouldn't cost much. Maybe. The problem is this is really an AI function, it just has to be in effects.c because it accesses static data. I renamed it ai_find_source_building (nobody else should use it!) and left it at that. > "Returns the number buildings of a certain type in a continent" > s/in/on/ Yes. > rename targets_in_range() I renamed it to count_targets_in_range. But I don't think that's exactly what it does? > I can stand no longer. in eff_redundant(): > s/group that exists wins/group that exists takes precedence/ > same for the comments in the rulesets. OK. But I found no such comments in the rulesets. > The comment for eff_reqs_active() should read: > "Check the requirements for the effect to see if it is active." OK. > in the comment of eff_eventually_active() > s/deps/reqs/ OK. > rename eff_eventually_active() to is_eff_active_for_target()? > maybe, in any case 'eventually' needs to be removed as it communicates > future time rather than lack of range check. I renamed it as is_effect_useful(). > rename eff_active() -> is_eff_active() OK. I also booleanized some other boolean functions. > in get_effect_value(), rename the parameter 'eff' to 'type' or something. effect_type > eff_redundant(), eff_reqs_active(), eff_eventually_active() and > eff_active() rename parameter 'id' to 'building' as you did in > targets_in_range() I also renamed "eff" as "peffect". And added explanations of the parameters. > in aicity.c:adjust_building_want_by_effects(), > cities[EFR_LAST] is cached in ai_data. Use that instead. > > in aicity.c:108 > add a comment there saying something like: iterate over each > effect for the building type, etc > > in the header to ai_manage_buildings() a TODO: RECALC_SPEED should be > configurable to ai difficulty > > aicity.c:893 > - && i != B_CITY /* selling city walls is really, really dumb -- Syela > */ > - && (wonder_replacement(pcity, i) || > building_unwanted(city_owner(pcity), i))) { > + && !building_has_effect(i, EFT_LAND_DEFEND) > + /* selling city walls is really, really dumb -- Syela */ > + && (building_replaced(pcity, i) > + || building_unwanted(city_owner(pcity), i))) { > > don't like this. If it's obsolete, then it has no effect and never will. > $$ is better. Are there other assumptions (or lack thereof) made here? AI stuff: I didn't touch this. But Per changed a lot of the AI code so they may be obsolete. > city.c:can_build_improvement() > The comment is wrong. We aren't talking about units here. Fixed. > can_build_improvement() and can_eventually_build_improvement() return FALSE > rather than 0. Change comment No doubt a holdover from before we had booleans. > can_build_improvement_direct(), can_build_improvement(), > can_eventually_build_improvement() should be in improvement.c Probably, but the effect patch doesn't need to move it. > in improvement_upkeep() > > if (improvement_types[i].upkeep <= > get_city_bonus(pcity, EFT_UPKEEP_FREE)) > > can go on one line. No it can't. It's one character too long ;-). > city.c:563 > the government comment here makes less sense now. Rewritten (it still mentions government). > base_get_shields_tile(): > get_city_tile_bonus(pcity, ptile, EFT_PROD_PER_TILE); is missing. Yep. I also moved EFT_FOOD_PER_TILE in get_city_food_bonus so it follows the sames tructure as the other two (previously FOOD_PER_TILE was applied earlier). > city.c:set_pollution(). This is wrong. How so? If you have recycling center and hydro/hoover/nuclear, you only get /5 to your pollution instead of /6. This is hard or impossible to fix, and probably isn't a big deal. I did make a minor fix in case EFT_POLLU_POP_PCT was > 100%. We don't want mod to be negative in that case. > city.c:2516 > pcity->luxury_bonus = 100; > pcity->tax_bonus = 100; > + pcity->luxury_bonus = 100; > pcity->science_bonus = 100; > redundant Yes. There's another duplicate luxury calc below that I also removed. > combat.c:305,306, indent properly OK. > game.c:372 initialize spaceshipparts in the declaration This code has changed; the complaint is obsolete. > improvement.c:130 this is dangerous. what happens if the building has > multiple effects. This must be noted in the documentation. I wrote about it in README.effects. (In fact the space parts weren't documented here at all since I changed them.) > improvement.c:556 > s/N.B. Unlike effects, we do not have/N.B. We do not need/ Sure... > improvement.h: why do you have stuff aboe the #includes? Removed. > player.c:407 README.effects needs to note that a "value" for this effect > does nothing (or alter this to reflect what it _does_ say in README.effects > which would be better) Modified README.effects. I agree that the value should be made a percentage. But I didn't do this. > unit.c:57 line wrapping... I couldn't find anything. > rulesets: "eff" should be replaced by "name" I agree. Done. > there needs to to commentary for the effect groups. Vasco, can you make some? > Also, what happens if I put a -2 instead of 4 for Size_Adj. Correct behavior? I assume it reduces the max size of the city. This is correct. In SMAC one of the nations has this effect. > I'm not happy that you make *_Defend a multiplier rather than a percentage. > That's too coarse-grained. I agree. Done (but I didn't edit the ai code). > ditto for Growth Food Also done. This was just a little uglier. Someone should check the logic. > ditto for Pollu_Prod_Pct, which makes even less sense considering the name. > review all Pollu_Prod_Pct. I didn't change this one. I think it needs to be renamed. We can't make it a percentage. Recycle reduces pollution by 66% and clean power by 50%. But these don't combine to 116% as they would if we made it a "normal" percentage. The way it is now recycle gets a value of 2 and clean power a value of 5. Each of them works fine individually. But if you combine them you'll get /= 5 instead of /= 6. Not too big a problem. > The mass_transit number for Pollu_Pop_Pct is incongruous. 100%? Why? > is this intentional: > - "Unit_Vet_Combat", "Player", 100, "Land" > + { "eff", "range", "value" > + "Land_Veteran", "Player" > + "Land_Regen", "Player" > + "Land_Vet_Combat", "Player", 50 I removed Land_Regen from Sun Tzu's in history/default/civ2 rulesets. It seems to be clearly wrong. The logic for Land_Vet_Combat seems to be a bit backwards. I think the Land_Vet_Combat value is correct for the current rules. But the value in civ2 ruleset was wrong. > citytools.c:642 > pcity->improvements[game.palace_building] = I_NONE; > ^ ^ ok... > cityturn.c:310 probably should be: > get_current_construction_bonus(pcity, EFT_GROWTH_FOOD) >= 100 The check is && get_current_construction_bonus(pcity, EFT_GROWTH_FOOD) > 0 which I think is correct. If we are building granary (bonus=50) then we (may) want to throttle. > cityturn.c:443 should be: > } else if (find_source_building(powner, EFT_SIZE_ADJ) > || find_source_building(powner, EFT_SIZE_UNLIMIT)) { > notify_player_ex(powner, pcity->x, pcity->y, E_CITY_AQUEDUCT, > _("Game: %s needs an improvement to grow any > further."), > pcity->name); > } else { > notify_player_ex(powner, pcity->x, pcity->y, E_CITY_AQUEDUCT, > _("Game: %s can grow no further."), pcity->name); > } This code shouldn't use find_source_building. It does need to be better before we can have fully generalized rulesets. But it should be okay for now. Note that [ai_]find_source_building doesn't return a boolean so your code is quite wrong. > and then cityturn.c:460,461 is wrong. > same issue for cityturn.c:530 and 540 I have no idea what code you mean. Line numbers change you know. > cityturn.c:751 the variable 'id' really isn't needed. fold into notify. OK. I renamed id2 as upgrades_to > cityturn.c:759 extra space before comma Yah. > overarching comment you use get_current_construction_bonus() in conditionals > and the answer might be negative, which as I recall is not defined. All checks now do a direct comparison > 0. > cityturn.c:943 mod can share the line with .name Picky, aren't we? > diplomats.c:759 comment makes no sense anymore. Is "subvertable" a word? > diplomats.c:1034 I don't like this at all. We should be able to specify a > percentage. > diplomats.c:1122 ditto For EFT_SPY_RESISTANT, yes. This bonus is given defensively in diplomatic combat as well as to protect buildings. The former should be a different effect (EFT_SPY_DEFEND) but I didn't make that. > gotohand.c:989 see above on multipliers vs. percentages. Yep. > plrhand.c:do_tech_parasite_effect() why aren't we naming the building? Because we don't know what building it is. We can find out but it will take some work. > plrhand.c:903 is this right? I assume you mean this on line 935: - if (player_owns_active_govchange_wonder(pplayer)) { + if (get_player_bonus(pplayer, EFT_NO_ANARCHY) > 0) { why wouldn't it be right? > ruleset.c:load_ruleset_buildings() some lines wrapping issues. Some fixed (there may be more). > settlers.c:877 see EFT_GROWTH_FOOD above. Yes. > unittools.c:do_upgrade_effects() > there are problems here as you assign an int to a bool. > I see you choose to ignore the AMOUNT spec... > you are missing the upgrade step effects. > int candidate_to_upgrade=-1; spacing > i=0 spacing, or initialize it in the declaration. > for the ALL_LEAP, you need not go through the candidate selection process. This is ugly. But I solved it ;-). I removed all four effects and replaced them with one EFT_UNIT_UPGRADE. The amount specifies the number to be ugpraded. Really, even having an amount here is unnecessary for the current level of generalization. > unittools.c:496 line wrap. ? > doc/README.effects needs to be updated. I fixed the problems I noticed (and the ones I changed above). Someone will have to review it eventually. In addition to the above changes, Per made a bunch of improvements to the AI code. These are merged in with my patch. They include changes to the prototypes of city_pollution and city_gold_surplus. The patch is about 100k bigger now because of all the AI changes. I will guarantee there are bugs. jason ? data/diff Index: ai/advdomestic.c =================================================================== RCS file: /home/freeciv/CVS/freeciv/ai/advdomestic.c,v retrieving revision 1.118 diff -u -r1.118 advdomestic.c --- ai/advdomestic.c 31 Aug 2004 15:52:46 -0000 1.118 +++ ai/advdomestic.c 6 Sep 2004 01:11:02 -0000 @@ -39,883 +39,6 @@ #include "advdomestic.h" -/************************************************************************** - Calculate desire for land defense. First look for potentially hostile - cities on our continent, indicating danger of being attacked by land. - Then check if we are on the shoreline because we want to stop invasions - too - but only if a non-allied player has started using sea units yet. - If they are slow to go on the offensive, we should expand or attack. - - Returns a base value of desire for land defense building. - - FIXME: We should have a concept of "oceans" just like we do for - continents. Too many times I've seen the AI build destroyers and - coastal defences in inlands cities with a small pond adjacent. - Per -**************************************************************************/ -static int ai_eval_threat_land(struct player *pplayer, struct city *pcity) -{ - struct ai_data *ai = ai_data_get(pplayer); - Continent_id continent; - bool vulnerable; - - /* make easy AI dumb */ - if (ai_handicap(pplayer, H_DEFENSIVE)) { - return 40; - } - - continent = map_get_continent(pcity->x, pcity->y); - vulnerable = ai->threats.continent[continent] - || city_got_building(pcity, B_PALACE) - || (ai->threats.invasions - && is_water_adjacent_to_tile(pcity->x, pcity->y)); - - return vulnerable ? TRADE_WEIGHTING + 2 : 1; /* trump coinage, and sam */ -} - -/************************************************************************** - Calculate desire for coastal defence building. -**************************************************************************/ -static int ai_eval_threat_sea(struct player *pplayer, struct city *pcity) -{ - struct ai_data *ai = ai_data_get(pplayer); - - /* make easy AI stay dumb */ - if (ai_handicap(pplayer, H_DEFENSIVE)) { - return 40; - } - - /* trump coinage, and wall, and sam */ - if (is_ocean(map_get_terrain(pcity->x, pcity->y))) { - return ai->threats.ocean[-map_get_continent(pcity->x, pcity->y)] - ? TRADE_WEIGHTING + 3 : 1; - } else { - adjc_iterate(pcity->x, pcity->y, x2, y2) { - if (is_ocean(map_get_terrain(x2, y2))) { - Continent_id ocean_number = map_get_continent(x2, y2); - - if (ai->threats.ocean[-ocean_number]) { - return TRADE_WEIGHTING + 3; - } - } - } adjc_iterate_end; - } - return 1; -} - -/************************************************************************** - Calculate desire for air defence building. -**************************************************************************/ -static int ai_eval_threat_air(struct player *pplayer, struct city *pcity) -{ - struct ai_data *ai = ai_data_get(pplayer); - Continent_id continent; - bool vulnerable; - - /* make easy AI dumber */ - if (ai_handicap(pplayer, H_DEFENSIVE)) { - return 50; - } - - continent = map_get_continent(pcity->x, pcity->y); - vulnerable = ai->threats.air - && (ai->threats.continent[continent] - || is_water_adjacent_to_tile(pcity->x, pcity->y) - || city_got_building(pcity, B_PALACE)); - - return vulnerable ? TRADE_WEIGHTING + 1 : 1; /* trump coinage */ -} - -/************************************************************************** - Calculate need for nuclear defence. Look for players capable of building - nuclear weapons. Capable of building, not has, because at this stage in - the game we can get nukes and use nukes faster than we can manage to - build SDIs. We also look if players _have_ nukes, and increase our - want for SDIs correspondingly. Lastly, we check if we are in a strategic - position (ie near water or on a continent with non-allied cities). -**************************************************************************/ -static int ai_eval_threat_nuclear(struct player *pplayer, struct city *pcity) -{ - struct ai_data *ai = ai_data_get(pplayer); - Continent_id continent; - int vulnerable = 1; - - /* make easy AI really dumb, like it was before */ - if (ai_handicap(pplayer, H_DEFENSIVE)) { - return 50; - } - - /* No non-allied player has nuclear capability yet. */ - if (ai->threats.nuclear == 0) { return 0; } - - continent = map_get_continent(pcity->x, pcity->y); - if (ai->threats.continent[continent] - || is_water_adjacent_to_tile(pcity->x, pcity->y) - || city_got_building(pcity, B_PALACE)) { - vulnerable++; - } - - /* 15 is just a new magic number, which will be +15 if we are - in a vulnerable spot, and +15 if someone we are not allied - with really have built nukes. This might be overkill, but - at least it is not as bad as it used to be. */ - return ((ai->threats.nuclear + vulnerable) * 15); -} - -/************************************************************************** - Calculate desire for missile defence. -**************************************************************************/ -static int ai_eval_threat_missile(struct player *pplayer, struct city *pcity) -{ - struct ai_data *ai = ai_data_get(pplayer); - Continent_id continent = map_get_continent(pcity->x, pcity->y); - bool vulnerable = is_water_adjacent_to_tile(pcity->x, pcity->y) - || ai->threats.continent[continent] - || city_got_building(pcity, B_PALACE); - - /* Only build missile defence if opponent builds them, and we are in - a vulnerable spot. Trump coinage but not wall or coastal. */ - return (ai->threats.missile && vulnerable) ? TRADE_WEIGHTING + 1 : 1; -} - -/************************************************************************** -Returns the value (desire to build it) of the improvement for keeping -of order in the city. - -Improvements which increase happiness have two benefits. They can prevent -cities from falling into disorder, and free the population changed into elvis -specialists (so you can work tiles with value like tileval with them). Happy -is number of people the improvement would make happy. - -This function lets you decide if the happiness improvement such as the Temple, -Cathedral or WoW is worth the cost of the elvises keeping your citizens content -or the cost of the potential disorder (basically how much citizens would be -unhappy * SADVAL). - -Note that an elvis citizen is a parasite. The fewer you have, the more -food/prod/trade your city produces. -**************************************************************************/ -static int impr_happy_val(struct city *pcity, int happy, int tileval) -{ - /* How much one rebeling citizen counts - 16 is debatable value */ -#define SADVAL 16 - /* Number of elvises in the city */ - int elvis = pcity->specialists[SP_ELVIS]; - /* Raw number of unhappy people */ - int sad = pcity->ppl_unhappy[0]; - /* Final number of content people */ - int content = pcity->ppl_content[4]; - /* Resulting value */ - int value = 0; - - /* Count people made happy by luxury as content. */ - if (pcity->ppl_content[1] < pcity->ppl_content[0]) - content += pcity->ppl_content[0] - pcity->ppl_content[1]; - - /* If units are making us unhappy, count that too. */ - sad += pcity->ppl_unhappy[3] - pcity->ppl_unhappy[2]; - /* Angry citizens have to be counted double, as you have to first make them - * unhappy and then content. */ - sad += pcity->ppl_angry[0] * 2; - - freelog(LOG_DEBUG, "In %s, unh[0] = %d, unh[4] = %d, sad = %d", - pcity->name, pcity->ppl_unhappy[0], pcity->ppl_unhappy[4], sad); - - /* The cost of the elvises. */ - while (happy > 0 && elvis > 0) { happy--; elvis--; value += tileval; } - /* The cost of the rebels. */ - while (happy > 0 && sad > 0) { happy--; sad--; value += SADVAL; } - - /* Desperately seeking Colosseum - we need happy improvements urgently. */ - if (city_unhappy(pcity)) - value += SADVAL * (sad + content); - - /* Usage of (happy && content) led to a lack of foresight, especially - * re: Chapel -- Syela */ - while (happy > 0) { happy--; value += SADVAL; } - - freelog(LOG_DEBUG, "%s: %d elvis %d sad %d content %d size %d val", - pcity->name, pcity->specialists[SP_ELVIS], pcity->ppl_unhappy[4], - pcity->ppl_content[4], pcity->size, value); - - return value; -#undef SADVAL -} - -/************************************************************************** -Return a weighted value for a city's Ocean tiles -(i.e. based on the total number and number actively worked). -**************************************************************************/ -static int ocean_workers(struct city *pcity) -{ - int i = 0; - - city_map_checked_iterate(pcity->x, pcity->y, cx, cy, mx, my) { - if (is_ocean(map_get_terrain(mx, my))) { - /* This is a kluge; wasn't getting enough harbors because often - * everyone was stuck farming grassland. */ - i++; - - if (is_worker_here(pcity, cx, cy)) - i++; - } - } city_map_checked_iterate_end; - - return i / 2; -} - -/************************************************************************** -Number of road tiles actively worked. -**************************************************************************/ -static int road_trade(struct city *pcity) -{ - int i = 0; - - city_map_checked_iterate(pcity->x, pcity->y, cx, cy, mx, my) { - if (map_has_special(mx, my, S_ROAD) - && is_worker_here(pcity, cx, cy)) - i++; - } city_map_checked_iterate_end; - - return i; -} - -/************************************************************************** -Number of farmland tiles actively worked. -**************************************************************************/ -static int farmland_food(struct city *pcity) -{ - int i = 0; - - city_map_checked_iterate(pcity->x, pcity->y, cx, cy, mx, my) { - if (map_has_special(mx, my, S_FARMLAND) - && is_worker_here(pcity, cx, cy)) - i++; - } city_map_checked_iterate_end; - - return i; -} - -/************************************************************************** -Pollution benefit or cost of given improvement. - -Positive return value: less pollution if this improvement would be built -Negative return value: more pollution if this improvement would be built -Bigger absolute value means greater effect, naturally. -**************************************************************************/ -static int pollution_benefit(struct player *pplayer, struct city *pcity, - Impr_Type_id impr_type) -{ - /* Generated pollution */ - int pollution = 0; - /* Production bonus of improvement */ - int prodbonus = 0; - /* How seriously we should take it */ - int weight; - /* Pollution cost */ - int cost = 0; - - /* Count total production of worked tiles, that's base of pollution value. */ - city_map_iterate(x, y) { - if (get_worker_city(pcity, x, y) == C_TILE_WORKER) { - pollution += city_get_shields_tile(x, y, pcity); - } - } city_map_iterate_end; - - /* Count production bonuses generated by various buildings. */ - if (city_got_building(pcity, B_FACTORY) || impr_type == B_FACTORY) { - prodbonus += 50; - if (city_got_building(pcity, B_MFG) || impr_type == B_MFG) { - prodbonus *= 2; - } - } - - /* Count bonuses for that production bonuses ;-). */ - if (city_affected_by_wonder(pcity, B_HOOVER) || impr_type == B_HOOVER || - city_got_building(pcity, B_POWER) || impr_type == B_POWER || - city_got_building(pcity, B_HYDRO) || impr_type == B_HYDRO || - city_got_building(pcity, B_NUCLEAR) || impr_type == B_NUCLEAR) { - prodbonus = (prodbonus * 3) / 2; - } - - /* And now apply the bonuses. */ - pollution = pollution * (prodbonus + 100) / 100; - - /* Count buildings which reduce the pollution. */ - if (city_got_building(pcity, B_RECYCLING) || impr_type == B_RECYCLING) - pollution /= 3; - - else if (city_got_building(pcity, B_HYDRO) || impr_type == B_HYDRO || - city_affected_by_wonder(pcity, B_HOOVER) || impr_type == B_HOOVER || - city_got_building(pcity, B_NUCLEAR) || impr_type == B_NUCLEAR) - pollution /= 2; - - /* Count technologies which affect the pollution. */ - if (! city_got_building(pcity, B_MASS) && impr_type != B_MASS) { - pollution += (num_known_tech_with_flag(pplayer, - TF_POPULATION_POLLUTION_INC) * - pcity->size) / 4; - } - - /* Heuristic? */ - pollution -= 20; - if (pollution < 0) pollution = 0; - - weight = (POLLUTION_WEIGHTING + pplayer->ai.warmth) * 64; - - /* Base is cost of actual pollution. */ - - if (pcity->pollution > 0) { - int amortized = amortize(weight, 100 / pcity->pollution); - - cost = ((amortized * weight) / (MAX(1, weight - amortized))) / 64; - - freelog(LOG_DEBUG, "City: %s, Pollu: %d, cost: %d, Id: %d, P: %d", - pcity->name, pcity->pollution, cost, impr_type, pollution); - } - - /* Subtract cost of future pollution. */ - - if (pollution > 0) { - int amortized = amortize(weight, 100 / pollution); - - cost -= ((amortized * weight) / (MAX(1, weight - amortized))) / 64; - } - - return cost; -} - -/**************************************************************************** - Return TRUE if the given wonder is already being built by pcity owner in - another city (if so we probably don't want to build it here, although - we may want to start building it and switch later). -****************************************************************************/ -static bool built_elsewhere(struct city *pcity, Impr_Type_id wonder) -{ - city_list_iterate(city_owner(pcity)->cities, acity) { - if (pcity != acity && !acity->is_building_unit - && pcity->currently_building == wonder) { - return TRUE; - } - } city_list_iterate_end; - - return FALSE; -} - -/************************************************************************** - Returns the city_tile_value of the worst tile worked by pcity - (not including the city center). Returns 0 if no tiles are worked. -**************************************************************************/ -static int worst_worker_tile_value(struct city *pcity) -{ - int worst = 0; - - city_map_iterate(x, y) { - if (is_city_center(x, y)) { - continue; - } - if (get_worker_city(pcity, x, y) == C_TILE_WORKER) { - int tmp = city_tile_value(pcity, x, y, 0, 0); - - if (tmp < worst || worst == 0) { - worst = tmp; - } - } - } city_map_iterate_end; - - return worst; -} - -/************************************************************************** - Get city_tile_value of best unused tile available to pcity. Returns - 0 if no tiles are available. -**************************************************************************/ -static int best_free_tile_value(struct city *pcity) -{ - int best = 0; - - city_map_iterate(x, y) { - if (get_worker_city(pcity, x, y) == C_TILE_EMPTY) { - int tmp = city_tile_value(pcity, x, y, 0, 0); - - if (tmp > best) { - best = tmp; - } - } - } city_map_iterate_end; - - return best; -} - -/************************************************************************** - Returns the amount of food consumed by pcity's units. -**************************************************************************/ -static int settler_eats(struct city *pcity) -{ - struct government *gov = get_gov_pcity(pcity); - int free_food = citygov_free_food(pcity, gov); - int eat = 0; - - unit_list_iterate(pcity->units_supported, this_unit) { - int food_cost = utype_food_cost(unit_type(this_unit), gov); - - adjust_city_free_cost(&free_food, &food_cost); - if (food_cost > 0) { - eat += food_cost; - } - } unit_list_iterate_end; - - return eat; -} - -/************************************************************************** - Evaluate the current desirability of all city improvements for the given - city to update pcity->ai.building_want. -**************************************************************************/ -void ai_eval_buildings(struct city *pcity) -{ - struct government *g = get_gov_pcity(pcity); - struct player *pplayer = city_owner(pcity); - int bar, est_food, food, grana, hunger, needpower; - int tprod, prod, sci, tax, t, val, wwtv; - int j, k; - int values[B_LAST]; - int nplayers = game.nplayers - - team_count_members_alive(pplayer->team); - - /* --- initialize control parameters --- */ - t = pcity->ai.trade_want; /* trade_weighting */ - sci = (pcity->trade_prod * pplayer->economic.science + 50) / 100; - tax = pcity->trade_prod - sci; - - /* better might be a longterm weighted average, this is a quick-n-dirty fix - -- Syela */ - sci = ((sci + pcity->trade_prod) * t)/2; - tax = ((tax + pcity->trade_prod) * t)/2; - /* don't need libraries!! */ - if (ai_wants_no_science(pplayer)) { - sci = 0; - } - - est_food = (2 * pcity->specialists[SP_SCIENTIST] - + 2 * pcity->specialists[SP_TAXMAN] - + pcity->food_surplus); - prod = - (pcity->shield_prod * SHIELD_WEIGHTING * 100) / city_shield_bonus(pcity); - needpower = (city_got_building(pcity, B_MFG) ? 2 : - (city_got_building(pcity, B_FACTORY) ? 1 : 0)); - val = best_free_tile_value(pcity); - wwtv = worst_worker_tile_value(pcity); - - /* because the benefit doesn't come immediately, and to stop stupidity */ - /* the AI used to really love granaries for nascent cities, which is OK */ - /* as long as they aren't rated above Settlers and Laws is above Pottery */ - /* -- Syela */ - grana = MAX(2, pcity->size); - food = food_weighting(grana); - grana = food_weighting(grana + 1); - hunger = 1; - j = (pcity->size * 2) + settler_eats(pcity) - pcity->food_prod; - if (j >= 0 - && pcity->specialists[SP_SCIENTIST] <= 0 - && pcity->specialists[SP_TAXMAN] <= 0) { - hunger += j + 1; - } - - /* rationale: barracks effectively doubles prod if building military units */ - /* if half our production is military, effective gain is 1/2 city prod */ - bar = ((!pcity->is_building_unit && pcity->currently_building == B_SUNTZU) - || built_elsewhere(pcity, B_SUNTZU)) ? 1 : 0; - j = 0; k = 0, tprod = 0; - city_list_iterate(pplayer->cities, acity) { - k++; - tprod += acity->shield_prod; - if (acity->is_building_unit) { - if (!unit_type_flag(acity->currently_building, F_NONMIL) - && unit_types[acity->currently_building].move_type == LAND_MOVING) - j += prod; - else - if (unit_type_flag(acity->currently_building, F_HELP_WONDER) && bar != 0) - j += prod; /* this also stops flip-flops */ - } else - if (acity->currently_building == B_BARRACKS /* this stops flip-flops */ - || acity->currently_building == B_BARRACKS2 - || acity->currently_building == B_BARRACKS3 - || acity->currently_building == B_SUNTZU) - j += prod; - } city_list_iterate_end; - bar = j > 0 ? j / k : 0; - - /* --- clear to initialize values ... and go --- */ - memset(values, 0, sizeof(values)); - - /* Buildings first, values are used in Wonder section next */ - impr_type_iterate(id) { - if ( is_wonder(id) - || !can_build_improvement(pcity, id)) - continue; - - switch (id) { - - /* food/growth production */ - case B_AQUEDUCT: - case B_SEWER: - /* Aqueducts and Sewers are similar */ - k = (id == B_AQUEDUCT ? game.aqueduct_size : game.sewer_size); - if (pcity->size >= k-1 && est_food > 0) { - /* need it to grow, but don't force */ - j = ((city_happy(pcity) || pcity->size > k) ? -100 : -66); - } - else { - /* how long (== how much food) till we grow big enough? - * j = num_pop_rollover * biggest_granary_size - current_food */ - j = (k+1) - MIN(k, pcity->size); - j *= city_granary_size(MAX(k, pcity->size)); - j-= pcity->food_stock; - - /* value = some odd factors / food_required */ - j = (k+1) * food * est_food * game.foodbox / MAX(1, j); - } - values[id] = j; - break; - case B_GRANARY: - if (improvement_variant(B_PYRAMIDS) != 0 - || !built_elsewhere(pcity, B_PYRAMIDS)) - values[id] = grana * pcity->food_surplus; - break; - case B_HARBOUR: - values[id] = ocean_workers(pcity) * food * hunger; - break; - case B_SUPERMARKET: - if (player_knows_techs_with_flag(pplayer, TF_FARMLAND)) - values[id] = farmland_food(pcity) * food * hunger; - break; - - /* science production */ - case B_RESEARCH: - if (built_elsewhere(pcity, B_SETI)) - break; - case B_UNIVERSITY: - case B_LIBRARY: - values[id] = sci/2; - break; - - /* happiness generation - trade production */ - case B_MARKETPLACE: - case B_BANK: - case B_STOCK: - values[id] = (tax + 3 * pcity->specialists[SP_TAXMAN] - + pcity->specialists[SP_ELVIS] * wwtv) / 2; - break; - case B_SUPERHIGHWAYS: - values[id] = road_trade(pcity) * t; - break; - case B_CAPITAL: - values[id] = TRADE_WEIGHTING; /* a kind of default */ - break; - - /* unhappiness relief */ - case B_TEMPLE: - values[id] = impr_happy_val(pcity, get_temple_power(pcity), val); - break; - case B_CATHEDRAL: - if (improvement_variant(B_MICHELANGELO) == 1 - || !built_elsewhere(pcity, B_MICHELANGELO)) - values[id]= impr_happy_val(pcity, get_cathedral_power(pcity), val); - else - if (tech_exists(game.rtech.cathedral_plus) - && get_invention(pplayer, game.rtech.cathedral_plus) != TECH_KNOWN) - values[id]= impr_happy_val(pcity, 4, val) - impr_happy_val(pcity, 3, val); - break; - case B_COLOSSEUM: - values[id] = impr_happy_val(pcity, get_colosseum_power(pcity), val); - break; - case B_COURTHOUSE: - if (g->corruption_level == 0) { - values[id] += impr_happy_val(pcity, 1, val); - } else { - /* The use of TRADE_WEIGHTING here is deliberate, since - * t is corruption modified. */ - values[id] = (pcity->corruption * TRADE_WEIGHTING) / 2; - } - break; - - /* shield production and pollution */ - case B_OFFSHORE: /* ignoring pollu. FIX? */ - values[B_OFFSHORE] = ocean_workers(pcity) * SHIELD_WEIGHTING; - break; - case B_FACTORY: - case B_MFG: - values[id] = - (( city_got_building(pcity, B_HYDRO) - || city_got_building(pcity, B_NUCLEAR) - || city_got_building(pcity, B_POWER) - || city_affected_by_wonder(pcity, B_HOOVER)) - ? (prod * 3)/4 : prod/2) - + pollution_benefit(pplayer, pcity, id); - break; - case B_HYDRO: - case B_NUCLEAR: - case B_POWER: - if ( !city_got_building(pcity, B_HYDRO) - && !city_got_building(pcity, B_NUCLEAR) - && !city_got_building(pcity, B_POWER) - && !city_affected_by_wonder(pcity, B_HOOVER)) - values[id] = (needpower*prod)/4 + pollution_benefit(pplayer, pcity, id); - break; - case B_MASS: - case B_RECYCLING: - values[id] = pollution_benefit(pplayer, pcity, id); - break; - - /* defense/protection */ - case B_BARRACKS: - case B_BARRACKS2: - case B_BARRACKS3: - if (!built_elsewhere(pcity, B_SUNTZU)) - values[id] = bar; - break; - - /* military advisor will deal with CITY and PORT */ - - /* old wall code depended on danger, was a CPU hog and didn't really work - * anyway. It was so stupid, AI wouldn't start building walls until it was - * in danger and it would have no chance to finish them before it was too - * late */ - case B_CITY: - /* if (!built_elsewhere(pcity, B_WALL)) was counterproductive -- Syela */ - values[id] = ai_eval_threat_land(pplayer, pcity); - break; - case B_COASTAL: - values[id] = ai_eval_threat_sea(pplayer, pcity); - break; - case B_SAM: - values[id] = ai_eval_threat_air(pplayer, pcity); - break; - case B_SDI: - values[B_SDI] = MAX(ai_eval_threat_nuclear(pplayer, pcity), - ai_eval_threat_missile(pplayer, pcity)); - break; - - /* spaceship production */ - case B_SCOMP: - if ((game.spacerace) - && pplayer->spaceship.components < NUM_SS_COMPONENTS) - values[id] = -90; - break; - case B_SMODULE: - if ((game.spacerace) - && pplayer->spaceship.modules < NUM_SS_MODULES) - values[id] = -90; - break; - case B_SSTRUCTURAL: - if ((game.spacerace) - && pplayer->spaceship.structurals < NUM_SS_STRUCTURALS) - values[id] = -80; - break; - default: - /* ignored: AIRPORT, PALACE, and POLICE and the rest. -- Syela*/ - break; - } /* end switch */ - } impr_type_iterate_end; - - /* Miscellaneous building values */ - if ( values[B_COLOSSEUM] == 0 - && tech_exists(game.rtech.colosseum_plus) - && get_invention(pplayer, game.rtech.colosseum_plus) != TECH_KNOWN) - values[B_COLOSSEUM] = - impr_happy_val(pcity, 4, val) - impr_happy_val(pcity, 3, val); - - /* Wonders */ - impr_type_iterate(id) { - if (!is_wonder(id) - || !can_build_improvement(pcity, id) - || wonder_obsolete(id) - || !is_wonder_useful(id)) - continue; - - switch (id) { - case B_ASMITHS: - impr_type_iterate(id2) { - if (city_got_building(pcity, id2) - && improvement_upkeep(pcity, id2) == 1) - values[id] += t; - } impr_type_iterate_end; - break; - case B_COLLOSSUS: - /* probably underestimates the value */ - values[id] = (pcity->size + 1) * t; - break; - case B_COPERNICUS: - values[id] = sci/2; - break; - case B_CURE: - values[id] = impr_happy_val(pcity, 1, val); - break; - case B_DARWIN: - /* this is a one-time boost, not constant */ - values[id] = ((total_bulbs_required(pplayer) * 2 + game.researchcost) * t - - pplayer->research.bulbs_researched * t) / MORT; - break; - case B_GREAT: - /* basically (100 - freecost)% of a free tech per 2 turns */ - values[id] = (total_bulbs_required(pplayer) * (100 - game.freecost) * t - * (nplayers - 2)) / (nplayers * 2 * 100); - break; - case B_WALL: - if (!city_got_citywalls(pcity)) { - /* allowing B_CITY when B_WALL exists, - * don't like B_WALL when B_CITY exists. */ - /* was 40, which led to the AI building WALL, not being able to build - * CITY, someone learning Metallurgy, and the AI collapsing. - * I hate the WALL. -- Syela */ - values[B_WALL] = 1; /* WAG */ - } - break; - case B_HANGING: - /* will add the global effect to this. */ - values[id] = impr_happy_val(pcity, 3, val) - - impr_happy_val(pcity, 1, val); - break; - case B_HOOVER: - if (!city_got_building(pcity, B_HYDRO) - && !city_got_building(pcity, B_NUCLEAR)) { - values[id] = (city_got_building(pcity, B_POWER) ? 0 : - (needpower * prod)/4) + pollution_benefit(pplayer, pcity, B_HOOVER); - } - break; - case B_ISAAC: - values[id] = sci; - break; - case B_LEONARDO: - unit_list_iterate(pcity->units_supported, punit) { - Unit_Type_id unit_id = can_upgrade_unittype(pplayer, punit->type); - if (unit_id >= 0) { - /* this is probably wrong -- Syela */ - j = 8 * unit_upgrade_price(pplayer, punit->type, unit_id); - values[id] = MAX(values[id], j); - } - } unit_list_iterate_end; - break; - case B_BACH: - values[id] = impr_happy_val(pcity, 2, val); - break; - case B_RICHARDS: - /* ignoring pollu, I don't think it matters here -- Syela */ - values[id] = (pcity->size + 1) * SHIELD_WEIGHTING; - break; - case B_MICHELANGELO: - /* Note: Mich not built, so get_cathedral_power() doesn't include - * its effect. */ - if (improvement_variant(B_MICHELANGELO) == 0 - && !city_got_building(pcity, B_CATHEDRAL)) { - /* Assumes Mich will act as the Cath that is not in this city. */ - values[id] = impr_happy_val(pcity, get_cathedral_power(pcity), val); - } - else - if (improvement_variant(B_MICHELANGELO)==1 - && city_got_building(pcity, B_CATHEDRAL)) { - /* Assumes Mich doubles the power of the Cath that is in this city. */ - values[id] = impr_happy_val(pcity, get_cathedral_power(pcity), val); - } - break; - case B_ORACLE: - /* The following is probably wrong if B_ORACLE req is - * not the same as game.rtech.temple_plus (was A_MYSTICISM) --dwp */ - if (!city_got_building(pcity, B_TEMPLE)) { - if (get_invention(pplayer, game.rtech.temple_plus) != TECH_KNOWN) { - /* The += has nothing to do with oracle, - * just the tech_Want of mysticism! */ - values[id] = impr_happy_val(pcity, 2, val) - - impr_happy_val(pcity, 1, val); - values[id]+= impr_happy_val(pcity, 2, val) - - impr_happy_val(pcity, 1, val); - } - } else { - if (get_invention(pplayer, game.rtech.temple_plus) != TECH_KNOWN) { - /* The += has nothing to do with oracle, - * just the tech_Want of mysticism! */ - values[id] = impr_happy_val(pcity, 4, val) - - impr_happy_val(pcity, 1, val); - values[id]+= impr_happy_val(pcity, 2, val) - - impr_happy_val(pcity, 1, val); - } - else - values[id] = impr_happy_val(pcity, 2, val); - } - break; - case B_PYRAMIDS: - if (improvement_variant(B_PYRAMIDS)==0 - && !city_got_building(pcity, B_GRANARY)) { - /* different tech req's */ - values[id] = food * pcity->food_surplus; - } - break; - case B_SETI: - if (!city_got_building(pcity, B_RESEARCH)) - values[id] = sci/2; - break; - case B_SHAKESPEARE: - values[id] = impr_happy_val(pcity, pcity->size, val); - break; - case B_SUNTZU: - values[id] = bar; - break; - case B_WOMENS: - unit_list_iterate(pcity->units_supported, punit) { - if (punit->unhappiness != 0) { - values[id] += t * 2; - } - } unit_list_iterate_end; - break; - case B_APOLLO: - if (game.spacerace) { - values[id] = values[B_CAPITAL] + 1; /* trump coinage and defenses */ - } - break; - case B_UNITED: - values[id] = values[B_CAPITAL] + 4; /* trump coinage and defenses */ - break; - case B_LIGHTHOUSE: - values[id] = values[B_CAPITAL] + 4; /* trump coinage and defenses */ - break; - case B_MAGELLAN: - values[id] = values[B_CAPITAL] + 4; /* trump coinage and defenses */ - break; - default: - /* also, MAGELLAN is special cased in ai_manage_buildings() */ - /* ignoring MANHATTAN and STATUE */ - break; - } /* end switch */ - } impr_type_iterate_end; - - /* Final massage */ - impr_type_iterate(id) { - if (values[id] >= 0) { - if (!is_wonder(id)) { - /* trying to buy fewer improvements */ - values[id]-= improvement_upkeep(pcity, id) * t; - values[id] = (values[id] <= 0 - ? 0 : (values[id] * SHIELD_WEIGHTING * 100) / MORT); - } else { - /* bias against wonders when total production is small */ - values[id] *= (tprod < 50 ? 100/(50-tprod): 100); - } - - /* handle H_PROD here? -- Syela */ - j = impr_build_shield_cost(id); - pcity->ai.building_want[id] = values[id] / j; - } else { - pcity->ai.building_want[id] = -values[id]; - } - - if (values[id] != 0) - CITY_LOG(LOG_DEBUG, pcity, "ai_eval_buildings: wants %s with desire %d.", - get_improvement_name(id), pcity->ai.building_want[id]); - } impr_type_iterate_end; - - return; -} - /*************************************************************************** * Evaluate the need for units (like caravans) that aid wonder construction. * If another city is building wonder and needs help but pplayer is not Index: ai/advdomestic.h =================================================================== RCS file: /home/freeciv/CVS/freeciv/ai/advdomestic.h,v retrieving revision 1.7 diff -u -r1.7 advdomestic.h --- ai/advdomestic.h 3 Sep 2004 04:22:36 -0000 1.7 +++ ai/advdomestic.h 6 Sep 2004 01:11:02 -0000 @@ -21,6 +21,5 @@ void ai_eval_threat_done(struct player *pplayer); void domestic_advisor_choose_build(struct player *pplayer, struct city *pcity, struct ai_choice *choice); -void ai_eval_buildings(struct city *pcity); #endif /* FC__ADVDOMESTIC_H */ Index: ai/advmilitary.c =================================================================== RCS file: /home/freeciv/CVS/freeciv/ai/advmilitary.c,v retrieving revision 1.172 diff -u -r1.172 advmilitary.c --- ai/advmilitary.c 2 Sep 2004 14:53:08 -0000 1.172 +++ ai/advmilitary.c 6 Sep 2004 01:11:02 -0000 @@ -323,8 +323,12 @@ } danger = unit_att_rating(punit); - if (sailing && city_got_building(pcity, B_COASTAL)) danger /= 2; - if (is_air_unit(punit) && city_got_building(pcity, B_SAM)) danger /= 2; + if (sailing && get_city_bonus(pcity, EFT_SEA_DEFEND) > 0) { + danger /= 2; + } + if (is_air_unit(punit) && get_city_bonus(pcity, EFT_AIR_DEFEND) > 0) { + danger /= 2; + } return danger; } @@ -437,7 +441,7 @@ static unsigned int assess_danger(struct city *pcity) { int i; - unsigned int danger[5]; + int danger[5], defender[4]; struct player *pplayer = city_owner(pcity); bool pikemen = FALSE; unsigned int urgency = 0; @@ -547,17 +551,32 @@ urgency += 10; } - ai_reevaluate_building(pcity, &pcity->ai.building_want[B_CITY], - urgency, danger[1], assess_defense(pcity)); - ai_reevaluate_building(pcity, &pcity->ai.building_want[B_COASTAL], - urgency, danger[2], - assess_defense_igwall(pcity)); - ai_reevaluate_building(pcity, &pcity->ai.building_want[B_SAM], - urgency, danger[3], - assess_defense_igwall(pcity)); - ai_reevaluate_building(pcity, &pcity->ai.building_want[B_SDI], - urgency, danger[4], - assess_defense_igwall(pcity)); + /* HACK: This needs changing if multiple improvements provide + * this effect. */ + defender[0] = ai_find_source_building(pplayer, EFT_LAND_DEFEND); + defender[1] = ai_find_source_building(pplayer, EFT_SEA_DEFEND); + defender[2] = ai_find_source_building(pplayer, EFT_AIR_DEFEND); + defender[3] = ai_find_source_building(pplayer, EFT_MISSILE_DEFEND); + + if (defender[0] != B_LAST) { + ai_reevaluate_building(pcity, &pcity->ai.building_want[defender[0]], + urgency, danger[1], assess_defense(pcity)); + } + if (defender[1] != B_LAST) { + ai_reevaluate_building(pcity, &pcity->ai.building_want[defender[1]], + urgency, danger[2], + assess_defense_igwall(pcity)); + } + if (defender[2] != B_LAST) { + ai_reevaluate_building(pcity, &pcity->ai.building_want[defender[2]], + urgency, danger[3], + assess_defense_igwall(pcity)); + } + if (defender[3] != B_LAST) { + ai_reevaluate_building(pcity, &pcity->ai.building_want[defender[3]], + urgency, danger[4], + assess_defense_igwall(pcity)); + } pcity->ai.danger = danger[0]; pcity->ai.urgency = urgency; @@ -799,9 +818,9 @@ !can_build_unit_direct(pcity, unit_types[unit_type].obsoleted_by)) && unit_types[unit_type].attack_strength > 0 /* or we'll get SIGFPE */ && move_type == orig_move_type) { - /* TODO: Case for B_AIRPORT. -- Raahul */ + /* TODO: Case for Airport. -- Raahul */ int will_be_veteran = (move_type == LAND_MOVING - || player_knows_improvement_tech(pplayer, B_PORT)); + || ai_find_source_building(pplayer, EFT_SEA_VETERAN) != B_LAST); /* Cost (shield equivalent) of gaining these techs. */ /* FIXME? Katvrr advises that this should be weighted more heavily in big * danger. */ @@ -1148,6 +1167,7 @@ { enum unit_move_type move_type; struct player *pplayer = city_owner(pcity); + Impr_Type_id id; /* Sanity */ if (!is_unit_choice_type(choice->choice)) return; @@ -1155,36 +1175,25 @@ if (do_make_unit_veteran(pcity, choice->choice)) return; move_type = get_unit_type(choice->choice)->move_type; - if (improvement_variant(B_BARRACKS)==1) { - /* Barracks will work for all units! */ - move_type = LAND_MOVING; - } - switch(move_type) { case LAND_MOVING: - if (player_knows_improvement_tech(pplayer, B_BARRACKS3)) { - choice->choice = B_BARRACKS3; - choice->type = CT_BUILDING; - } else if (player_knows_improvement_tech(pplayer, B_BARRACKS2)) { - choice->choice = B_BARRACKS2; - choice->type = CT_BUILDING; - } else if (player_knows_improvement_tech(pplayer, B_BARRACKS)) { - choice->choice = B_BARRACKS; + if ((id = ai_find_source_building(pplayer, EFT_LAND_VETERAN)) != B_LAST) { + choice->choice = id; choice->type = CT_BUILDING; } break; case SEA_MOVING: - if (player_knows_improvement_tech(pplayer, B_PORT)) { - choice->choice = B_PORT; + if ((id = ai_find_source_building(pplayer, EFT_SEA_VETERAN)) != B_LAST) { + choice->choice = id; choice->type = CT_BUILDING; } break; case HELI_MOVING: case AIR_MOVING: - if (player_knows_improvement_tech(pplayer, B_AIRPORT) - && pcity->shield_surplus > impr_build_shield_cost(B_AIRPORT) / 10) { + if ((id = ai_find_source_building(pplayer, EFT_AIR_VETERAN)) != B_LAST + && pcity->shield_surplus > impr_build_shield_cost(id) / 10) { /* Only build this if we have really high production */ - choice->choice = B_AIRPORT; + choice->choice = id; choice->type = CT_BUILDING; } break; @@ -1223,6 +1232,7 @@ /* Otherwise no need to defend yet */ if (pcity->ai.danger != 0) { int num_defenders = unit_list_size(&ptile->units); + int land_id, sea_id, air_id; /* First determine the danger. It is measured in percents of our * defensive strength, capped at 200 + urgency */ @@ -1248,40 +1258,50 @@ * 2. (80 - pcity->shield_stock) * 2 below is hardcoded price of walls */ /* We will build walls if we can and want and (have "enough" defenders or * can just buy the walls straight away) */ - if (pcity->ai.building_want[B_CITY] != 0 && our_def != 0 - && can_build_improvement(pcity, B_CITY) + + /* HACK: This needs changing if multiple improvements provide + * this effect. */ + land_id = ai_find_source_building(pplayer, EFT_LAND_DEFEND); + sea_id = ai_find_source_building(pplayer, EFT_SEA_DEFEND); + air_id = ai_find_source_building(pplayer, EFT_AIR_DEFEND); + + if (land_id != B_LAST + && pcity->ai.building_want[land_id] != 0 && our_def != 0 + && can_build_improvement(pcity, land_id) && (danger < 101 || num_defenders > 1 || (pcity->ai.grave_danger == 0 && pplayer->economic.gold > (80 - pcity->shield_stock) * 2)) && ai_fuzzy(pplayer, TRUE)) { /* NB: great wall is under domestic */ - choice->choice = B_CITY; + choice->choice = land_id; /* building_want is hacked by assess_danger */ - choice->want = pcity->ai.building_want[B_CITY]; + choice->want = pcity->ai.building_want[land_id]; if (urgency == 0 && choice->want > 100) { choice->want = 100; } choice->type = CT_BUILDING; - } else if (pcity->ai.building_want[B_COASTAL] != 0 && our_def != 0 - && can_build_improvement(pcity, B_COASTAL) + } else if (sea_id != B_LAST + && pcity->ai.building_want[sea_id] != 0 && our_def != 0 + && can_build_improvement(pcity, sea_id) && (danger < 101 || num_defenders > 1) && ai_fuzzy(pplayer, TRUE)) { - choice->choice = B_COASTAL; + choice->choice = sea_id; /* building_want is hacked by assess_danger */ - choice->want = pcity->ai.building_want[B_COASTAL]; + choice->want = pcity->ai.building_want[sea_id]; if (urgency == 0 && choice->want > 100) { choice->want = 100; } choice->type = CT_BUILDING; - } else if (pcity->ai.building_want[B_SAM] != 0 && our_def != 0 - && can_build_improvement(pcity, B_SAM) + } else if (air_id != B_LAST + && pcity->ai.building_want[air_id] != 0 && our_def != 0 + && can_build_improvement(pcity, air_id) && (danger < 101 || num_defenders > 1) && ai_fuzzy(pplayer, TRUE)) { - choice->choice = B_SAM; + choice->choice = air_id; /* building_want is hacked by assess_danger */ - choice->want = pcity->ai.building_want[B_SAM]; + choice->want = pcity->ai.building_want[air_id]; if (urgency == 0 && choice->want > 100) { choice->want = 100; } @@ -1291,7 +1311,7 @@ /* Consider building defensive units units */ process_defender_want(pplayer, pcity, danger, choice); if (urgency == 0 && unit_types[choice->choice].defense_strength == 1) { - if (city_got_barracks(pcity)) { + if (get_city_bonus(pcity, EFT_LAND_REGEN) > 0) { /* unlikely */ choice->want = MIN(49, danger); } else { Index: ai/aicity.c =================================================================== RCS file: /home/freeciv/CVS/freeciv/ai/aicity.c,v retrieving revision 1.162 diff -u -r1.162 aicity.c --- ai/aicity.c 4 Sep 2004 19:28:18 -0000 1.162 +++ ai/aicity.c 6 Sep 2004 01:11:03 -0000 @@ -20,6 +20,7 @@ #include "city.h" #include "combat.h" +#include "effects.h" #include "events.h" #include "fcintl.h" #include "game.h" @@ -28,6 +29,7 @@ #include "map.h" #include "packets.h" #include "player.h" +#include "rand.h" #include "shared.h" #include "support.h" #include "unit.h" @@ -75,7 +77,7 @@ - pcity->ppl_unhappy[4] * ai->unhappy_priority - pcity->ppl_angry[4] * ai->angry_priority - pcity->pollution * ai->pollution_priority); - + if (pcity->food_surplus < 0 || pcity->shield_surplus < 0) { /* The city is unmaintainable, it can't be good */ i = MIN(i, 0); @@ -83,90 +85,434 @@ return i; } - + +/************************************************************************** + Calculates want for some buildings by actually adding the building and + measuring the effect. +**************************************************************************/ +static int base_want(struct player *pplayer, struct city *pcity, + Impr_Type_id id) +{ + struct ai_data *ai = ai_data_get(pplayer); + int final_want = 0; + Continent_id continent = map_get_continent(pcity->x, pcity->y); + struct city *capital = find_palace(pplayer); + + if (ai->impr_calc[id] == AI_IMPR_ESTIMATE) { + return 0; /* Nothing to calculate here. */ + } + + /* First calculate current worth */ + city_list_iterate(pplayer->cities, acity) { + if ((ai->impr_range[id] == EFR_CITY && acity == pcity) + || (ai->impr_range[id] == EFR_LOCAL && acity == pcity) + || (ai->impr_range[id] == EFR_CONTINENT + && map_get_continent(acity->x, acity->y) == continent) + || (ai->impr_range[id] == EFR_PLAYER)) { + int food, trade, shields, lux, sci, tax, want = 0; + + get_food_trade_shields(acity, &food, &trade, &shields); + get_tax_income(pplayer, trade, &sci, &lux, &tax); + + want += food * ai->food_priority; + want += ((shields * get_city_shield_bonus(acity)) / 100) + * ai->shield_priority; + want -= city_pollution(acity, shields) * ai->pollution_priority; + want += ((lux * get_city_luxury_bonus(acity)) / 100) + * ai->luxury_priority; + want += ((sci * get_city_science_bonus(acity)) / 100) + * ai->science_priority; + want += ((city_gold_surplus(acity, tax) + * get_city_tax_bonus(acity)) / 100) + * ai->gold_priority; + acity->ai.worth = want; + } + } city_list_iterate_end; + + /* Add the improvement */ + city_add_improvement(pcity, id); + + /* Stir, then compare notes */ + city_list_iterate(pplayer->cities, acity) { + if ((ai->impr_range[id] == EFR_CITY && acity == pcity) + || (ai->impr_range[id] == EFR_LOCAL && acity == pcity) + || (ai->impr_range[id] == EFR_CONTINENT + && map_get_continent(acity->x, acity->y) == continent) + || (ai->impr_range[id] == EFR_PLAYER)) { + int food, trade, shields, lux, sci, tax, want = 0; + + get_food_trade_shields(acity, &food, &trade, &shields); + get_tax_income(pplayer, trade, &sci, &lux, &tax); + want += food * ai->food_priority; + want += ((shields * get_city_shield_bonus(acity)) / 100) + * ai->shield_priority; + want -= city_pollution(acity, shields) * ai->pollution_priority; + want += ((lux * get_city_luxury_bonus(acity)) / 100) + * ai->luxury_priority; + want += ((sci * get_city_science_bonus(acity)) / 100) + * ai->science_priority; + want += ((city_gold_surplus(acity, tax) + * get_city_tax_bonus(acity)) / 100) + * ai->gold_priority; + final_want += want - acity->ai.worth; + } + } city_list_iterate_end; + + /* Restore */ + city_remove_improvement(pcity, id); + + /* Ensure that we didn't inadvertantly move our palace */ + if (find_palace(pplayer) != capital) { + city_add_improvement(capital, get_building_for_effect(EFT_CAPITAL_CITY)); + } + + return final_want; +} + /************************************************************************** -... + Calculate effects. A few base variables: + c - number of cities we have in current range + u - units we have of currently affected type + v - the want for the improvement we are considering + + This function contains a whole lot of WAGs. We ignore cond_* for now, + thinking that one day we may fulfill the cond_s anyway. In general, we + first add bonus for city improvements, then for wonders. + + IDEA: Calculate per-continent aggregates of various data, and use this + for wonders below for better wonder placements. +**************************************************************************/ +static void adjust_building_want_by_effects(struct city *pcity, + Impr_Type_id id) +{ + struct player *pplayer = city_owner(pcity); + struct impr_type *pimpr = get_improvement_type(id); + int v = 0; + int cities[EFR_LAST]; + int nplayers = game.nplayers + - team_count_members_alive(pplayer->team); + struct ai_data *ai = ai_data_get(pplayer); + struct tile *ptile = map_get_tile(pcity->x, pcity->y); + bool capital = is_capital(pcity); + struct government *gov = get_gov_pplayer(pplayer); + + /* Base want is calculated above using a more direct approach. */ + v += base_want(pplayer, pcity, id); + if (v != 0) { + CITY_LOG(LOG_DEBUG, pcity, "%s base_want is %d (range=%d, calc=%d)", + get_improvement_name(id), v, ai->impr_range[id], ai->impr_calc[id]); + } + + /* Find number of cities per range. */ + cities[EFR_PLAYER] = city_list_size(&pplayer->cities); + cities[EFR_WORLD] = cities[EFR_PLAYER]; /* kludge. */ + + cities[EFR_CONTINENT] = 0; + city_list_iterate(pplayer->cities, acity) { + if (map_get_tile(acity->x, acity->y)->continent == ptile->continent) + cities[EFR_CONTINENT]++; + } city_list_iterate_end; + + cities[EFR_CITY] = 1; + cities[EFR_LOCAL] = 0; + + /* Calculate desire value. */ + effect_type_vector_iterate(get_building_effect_types(id), ptype) { + effect_list_iterate(*get_building_effects(id, *ptype), peff) { + if (is_effect_useful(TARGET_BUILDING, pplayer, pcity, id, + NULL, id, peff)) { + int amount = peff->value, c = cities[peff->range]; + + switch (*ptype) { + /* TODO */ + case EFT_INCITE_DIST_ADJ: + case EFT_INCITE_DIST_PCT: + case EFT_MAKE_CONTENT_MIL_PER: + case EFT_MAKE_HAPPY: + case EFT_UNIT_RECOVER: + case EFT_FORCE_CONTENT_PCT: + case EFT_MAKE_CONTENT_PCT: + case EFT_SEA_VET_COMBAT: + case EFT_AIR_VET_COMBAT: + break; + + /* These have already been evaluated in base_want() */ + case EFT_LUXURY_PCT: + case EFT_SCIENCE_PCT: + case EFT_TAX_PCT: + case EFT_CAPITAL_CITY: + case EFT_UPKEEP_FREE: + case EFT_POLLU_POP_PCT: + case EFT_POLLU_PROD_PCT: + case EFT_TRADE_PER_TILE: + case EFT_PROD_TO_GOLD: + case EFT_TRADE_INC_TILE: + case EFT_FOOD_BONUS: + case EFT_FOOD_PCT: + case EFT_FOOD_INC_TILE: + case EFT_POLLU_ADJ: + case EFT_POLLU_PCT: + case EFT_POLLU_POP_ADJ: + case EFT_POLLU_PROD_ADJ: + case EFT_TRADE_ADD_TILE: + case EFT_TRADE_BONUS: + case EFT_TRADE_PCT: + case EFT_NO_UPKEEP: + case EFT_PROD_PCT: + case EFT_PROD_INC_TILE: + case EFT_PROD_PER_TILE: + case EFT_PROD_ADD_TILE: + case EFT_FOOD_PER_TILE: + case EFT_FOOD_ADD_TILE: + case EFT_PROD_BONUS: + case EFT_TAX_BONUS: + case EFT_SCIENCE_BONUS: + case EFT_LUXURY_BONUS: + case EFT_CORRUPT_PCT: + case EFT_WASTE_PCT: + break; + + /* WAG evaluated effects */ + case EFT_NO_UNHAPPY: + v += (pcity->specialists[SP_ELVIS] + pcity->ppl_unhappy[0]) * 3; + break; + case EFT_FORCE_CONTENT: + if (!government_has_flag(gov, G_NO_UNHAPPY_CITIZENS)) { + v += (pcity->ppl_unhappy[0] + pcity->specialists[SP_ELVIS]) * 3; + v += 5 * c; + } + break; + case EFT_MAKE_CONTENT: + if (!government_has_flag(gov, G_NO_UNHAPPY_CITIZENS)) { + v += pcity->ppl_unhappy[0] * amount; + v += amount * c; + } + break; + case EFT_MAKE_CONTENT_MIL: + if (!government_has_flag(gov, G_NO_UNHAPPY_CITIZENS)) { + v += pcity->ppl_unhappy[4] * amount + * MAX(unit_list_size(&pcity->units_supported) + - gov->free_happy, 0) * 2; + v += c * MAX(amount + 2 - gov->free_happy, 1); + } + break; + case EFT_TECH_PARASITE: + v += (total_bulbs_required(pplayer) * (100 - game.freecost) + * (nplayers - amount)) / (nplayers * amount * 100); + break; + case EFT_GROWTH_FOOD: + v += c * 4 + 25; + break; + case EFT_AIRLIFT: + v += c + ai->stats.units[UCL_LAND]; + break; + case EFT_ANY_GOVERNMENT: + if (!can_change_to_government(pplayer, ai->goal.govt.idx)) { + v += MIN(MIN(ai->goal.govt.val, 65), + num_unknown_techs_for_goal(pplayer, ai->goal.govt.req) * 10); + } + break; + case EFT_ENABLE_NUKE: + /* Treat nuke as a Cruise Missile upgrade */ + v += 20 + ai->stats.units[UCL_MISSILE] * 5; + break; + case EFT_ENABLE_SPACE: + if (game.spacerace) { + v += 50; + } + break; + case EFT_GIVE_IMM_TECH: + v += ((total_bulbs_required(pplayer) * amount + + game.researchcost) + * TRADE_WEIGHTING - pplayer->research.bulbs_researched + * TRADE_WEIGHTING) / MORT; + break; + case EFT_HAVE_EMBASSIES: + v += 5 * nplayers; + break; + case EFT_REVEAL_CITIES: + case EFT_NO_ANARCHY: + break; /* Useless for AI */ + case EFT_NO_SINK_DEEP: + v += 15 + ai->stats.triremes * 5; + break; + case EFT_NUKE_PROOF: + if (ai->threats.nuclear) { + v += pcity->size * unit_list_size(&ptile->units) * (capital + 1); + } + break; + case EFT_REVEAL_MAP: + if (!ai->explore.land_done || !ai->explore.sea_done) { + v += 10; + } + break; + case EFT_SIZE_UNLIMIT: + amount = 20; /* really big city */ + /* there not being a break here is deliberate, mind you */ + case EFT_SIZE_ADJ: + if (city_can_grow_to(pcity, pcity->size + 1)) { + v += pcity->food_surplus * ai->food_priority * amount / 10; + } + v += c * amount / game.aqueduct_size; + break; + case EFT_SS_STRUCTURAL: + case EFT_SS_COMPONENT: + case EFT_SS_MODULE: + if (game.spacerace && ai->diplomacy.strategy == WIN_SPACE) { + v += 95; + } + break; + case EFT_SPY_RESISTANT: + /* Uhm, problem: City Wall has -50% here!! */ + break; + case EFT_SEA_MOVE: + v += ai->stats.units[UCL_SEA] * 8 * amount; + break; + case EFT_UNIT_NO_LOSE_POP: + v += unit_list_size(&(ptile->units)) * 2; + break; + case EFT_LAND_REGEN: + v += 15 * c + ai->stats.units[UCL_LAND] * 3; + break; + case EFT_SEA_REGEN: + v += 15 * c + ai->stats.units[UCL_SEA] * 3; + break; + case EFT_AIR_REGEN: + v += 15 * c + ai->stats.units[UCL_AIR] * 3; + break; + case EFT_LAND_VET_COMBAT: + v += 2 * c + ai->stats.units[UCL_LAND] * 2; + break; + case EFT_LAND_VETERAN: + v += 5 * c + ai->stats.units[UCL_LAND]; + break; + case EFT_SEA_VETERAN: + v += 5 * c + ai->stats.units[UCL_SEA]; + break; + case EFT_AIR_VETERAN: + v += 5 * c + ai->stats.units[UCL_AIR]; + break; + case EFT_UPGRADE_UNIT: + v += ai->stats.units[UCL_LAST]; + if (amount == 1) { + v *= 2; + } else if (amount == 2) { + v *= 3; + } else { + v *= 4; + } + break; + case EFT_SEA_DEFEND: + if (ai_handicap(pplayer, H_DEFENSIVE)) { + v += amount * 10; /* make AI slow */ + } + if (is_ocean(map_get_terrain(pcity->x, pcity->y))) { + v += ai->threats.ocean[-map_get_continent(pcity->x, pcity->y)] + ? amount * 8 : amount; + } else { + adjc_iterate(pcity->x, pcity->y, x2, y2) { + if (is_ocean(map_get_terrain(x2, y2))) { + if (ai->threats.ocean[-map_get_continent(x2, y2)]) { + v += 8 * amount; + } + } + } adjc_iterate_end; + } + v += (amount + ai->threats.invasions - 1) * c; /* for wonder */ + if (capital && ai->threats.invasions) { + v += amount * 10; /* defend capital! */ + } + break; + case EFT_AIR_DEFEND: + if (ai_handicap(pplayer, H_DEFENSIVE)) { + v += amount * 15; /* make AI slow */ + } + v += (ai->threats.air && ai->threats.continent[ptile->continent]) + ? amount * 5 + amount * c : c; + break; + case EFT_MISSILE_DEFEND: + if (ai->threats.missile + && (ai->threats.continent[ptile->continent] || capital)) { + v += amount * 5 + (amount - 1) * c; + } + break; + case EFT_LAND_DEFEND: + if (ai_handicap(pplayer, H_DEFENSIVE)) { + v += amount * 10; /* make AI slow */ + } + if (ai->threats.continent[ptile->continent] + || capital + || (ai->threats.invasions + && is_water_adjacent_to_tile(pcity->x, pcity->y))) { + v += !ai->threats.igwall ? 15 + (capital * amount * 5) : 10; + } + v += (1 + ai->threats.invasions + !ai->threats.igwall) * c; + break; + case EFT_NO_INCITE: + if (!government_has_flag(gov, G_UNBRIBABLE)) { + v += MAX((game.diplchance * 2 - game.incite_cost.total_factor) / 2 + - game.incite_cost.improvement_factor * 5 + - game.incite_cost.unit_factor * 5, 0); + } + break; + case EFT_LAST: + freelog(LOG_ERROR, "Bad effect type."); + break; + } + } + } effect_list_iterate_end; + } effect_type_vector_iterate_end; + + /* Reduce want if building gets obsoleted soon */ + if (tech_exists(pimpr->obsolete_by)) { + v -= v / MAX(1, num_unknown_techs_for_goal(pplayer, pimpr->obsolete_by)); + } + + /* Adjust by building cost */ + v -= pimpr->build_cost / (pcity->shield_surplus * 10 + 1); + + /* Set */ + pcity->ai.building_want[id] = v; +} + +/************************************************************************** + Prime pcity->ai.building_want[] **************************************************************************/ static void ai_manage_buildings(struct player *pplayer) -{ /* we have just managed all our cities but not chosen build for them yet */ - struct government *g = get_gov_pplayer(pplayer); - Tech_Type_id j; - int values[B_LAST], leon = 0; - bool palace = FALSE; - int corr = 0; - memset(values, 0, sizeof(values)); - memset(pplayer->ai.tech_want, 0, sizeof(pplayer->ai.tech_want)); - - if (find_palace(pplayer) || g->corruption_level == 0) palace = TRUE; - city_list_iterate(pplayer->cities, pcity) - ai_eval_buildings(pcity); - if (!palace) corr += pcity->corruption * 8; - impr_type_iterate(i) { - if (pcity->ai.building_want[i] > 0) values[i] += pcity->ai.building_want[i]; - } impr_type_iterate_end; - - if (pcity->ai.building_want[B_LEONARDO] > leon) - leon = pcity->ai.building_want[B_LEONARDO]; - city_list_iterate_end; - -/* this is a weird place to iterate a units list! */ - unit_list_iterate(pplayer->units, punit) - if (is_sailing_unit(punit)) - values[B_MAGELLAN] += - unit_build_shield_cost(punit->type) * 2 * SINGLE_MOVE / - unit_type(punit)->move_rate; - unit_list_iterate_end; - values[B_MAGELLAN] *= 100 * SHIELD_WEIGHTING; - values[B_MAGELLAN] /= (MORT * impr_build_shield_cost(B_MAGELLAN)); - - /* This is a weird place to put tech advice */ - /* This was: > G_DESPOTISM; should maybe remove test, depending - * on new government evaluation etc, but used for now for - * regression testing --dwp */ - if (g->index != game.default_government - && g->index != game.government_when_anarchy) { - impr_type_iterate(i) { - j = improvement_types[i].tech_req; - if (get_invention(pplayer, j) != TECH_KNOWN) - pplayer->ai.tech_want[j] += values[i]; - /* if it is a bonus tech double it's value since it give a free - tech */ - if (game.global_advances[j] == 0 && tech_flag(j, TF_BONUS_TECH)) - pplayer->ai.tech_want[j] *= 2; - /* this probably isn't right -- Syela */ - /* since it assumes that the next tech is as valuable as the - current -- JJCogliati */ - } impr_type_iterate_end; - } /* tired of researching pottery when we need to learn Republic!! -- Syela */ - - - city_list_iterate(pplayer->cities, pcity) - pcity->ai.building_want[B_MAGELLAN] = values[B_MAGELLAN]; - pcity->ai.building_want[B_ASMITHS] = values[B_ASMITHS]; - pcity->ai.building_want[B_CURE] = values[B_CURE]; - pcity->ai.building_want[B_HANGING] += values[B_CURE]; - pcity->ai.building_want[B_WALL] = values[B_WALL]; - pcity->ai.building_want[B_HOOVER] = values[B_HOOVER]; - pcity->ai.building_want[B_BACH] = values[B_BACH]; -/* yes, I know that HOOVER and BACH should be continent-only not global */ - pcity->ai.building_want[B_MICHELANGELO] = values[B_MICHELANGELO]; - pcity->ai.building_want[B_ORACLE] = values[B_ORACLE]; - pcity->ai.building_want[B_PYRAMIDS] = values[B_PYRAMIDS]; - pcity->ai.building_want[B_SETI] = values[B_SETI]; - pcity->ai.building_want[B_SUNTZU] = values[B_SUNTZU]; - pcity->ai.building_want[B_WOMENS] = values[B_WOMENS]; - pcity->ai.building_want[B_LEONARDO] = leon; /* hopefully will fix */ - pcity->ai.building_want[B_PALACE] = corr; /* urgent enough? */ - city_list_iterate_end; - - city_list_iterate(pplayer->cities, pcity) /* wonder-kluge */ - impr_type_iterate(i) { - if (!pcity->is_building_unit && is_wonder(i) && - is_wonder(pcity->currently_building)) - /* this should encourage completion of wonders, I hope! -- Syela */ - pcity->ai.building_want[i] += pcity->shield_stock / 2; - } impr_type_iterate_end; - city_list_iterate_end; +/* TODO: RECALC_SPEED should be configurable to ai difficulty. -kauf */ +#define RECALC_SPEED 5 +{ + impr_type_iterate(id) { + if (!can_player_build_improvement(pplayer, id) + || improvement_obsolete(pplayer, id)) { + continue; + } + city_list_iterate(pplayer->cities, pcity) { + if (pcity->ai.next_recalc > game.turn) { + continue; /* do not recalc yet */ + } else { + pcity->ai.building_want[id] = 0; /* do recalc */ + } + if (city_got_building(pcity, id) + || pcity->shield_surplus == 0 + || !can_build_improvement(pcity, id) + || improvement_redundant(pplayer, pcity, id, FALSE)) { + continue; /* Don't build redundant buildings */ + } + adjust_building_want_by_effects(pcity, id); + CITY_LOG(LOG_DEBUG, pcity, "want to build %s with %d", + get_improvement_name(id), pcity->ai.building_want[id]); + } city_list_iterate_end; + } impr_type_iterate_end; + + /* Reset recalc counter */ + city_list_iterate(pplayer->cities, pcity) { + if (pcity->ai.next_recalc <= game.turn) { + /* This will spread recalcs out so that no one turn end is + * much longer than others */ + pcity->ai.next_recalc = game.turn + myrand(RECALC_SPEED) + RECALC_SPEED; + } + } city_list_iterate_end; } /*************************************************************************** @@ -296,8 +642,8 @@ if (best_role_unit(pcity, F_TRADE_ROUTE) != U_LAST) { pcity->ai.choice.choice = best_role_unit(pcity, F_TRADE_ROUTE); pcity->ai.choice.type = CT_NONMIL; - } else if (can_build_improvement(pcity, B_CAPITAL)) { - pcity->ai.choice.choice = B_CAPITAL; + } else if (can_build_improvement(pcity, game.default_building)) { + pcity->ai.choice.choice = game.default_building; pcity->ai.choice.type = CT_BUILDING; } else if (best_role_unit(pcity, F_SETTLERS) != U_LAST) { pcity->ai.choice.choice = best_role_unit(pcity, F_SETTLERS); @@ -355,7 +701,8 @@ static void try_to_sell_stuff(struct player *pplayer, struct city *pcity) { impr_type_iterate(id) { - if (can_sell_building(pcity, id) && id != B_CITY) { + if (can_sell_building(pcity, id) + && !building_has_effect(id, EFT_LAND_DEFEND)) { /* selling walls to buy defenders is counterproductive -- Syela */ really_handle_city_sell(pplayer, pcity, id); break; @@ -488,7 +835,7 @@ if (bestchoice.type != CT_BUILDING && unit_type_flag(bestchoice.choice, F_CITIES)) { - if (!city_got_effect(pcity, B_GRANARY) + if (get_city_bonus(pcity, EFT_GROWTH_FOOD) == 0 && pcity->size == 1 && city_granary_size(pcity->size) > pcity->food_stock + pcity->food_surplus) { @@ -607,7 +954,7 @@ static bool building_unwanted(struct player *plr, Impr_Type_id i) { return (ai_wants_no_science(plr) - && (i == B_LIBRARY || i == B_UNIVERSITY || i == B_RESEARCH)); + && building_has_effect(i, EFT_SCIENCE_BONUS)); } /************************************************************************** @@ -619,9 +966,10 @@ built_impr_iterate(pcity, i) { if(!is_wonder(i) - && i != B_CITY /* selling city walls is really, really dumb -- Syela */ + && !building_has_effect(i, EFT_LAND_DEFEND) + /* selling city walls is really, really dumb -- Syela */ && (building_replaced(pcity, i) - || building_unwanted(city_owner(pcity), i))) { + || building_unwanted(city_owner(pcity), i))) { do_sell_building(pplayer, pcity, i); notify_player_ex(pplayer, pcity->x, pcity->y, E_IMP_SOLD, _("Game: %s is selling %s (not needed) for %d."), Index: ai/aicity.h =================================================================== RCS file: /home/freeciv/CVS/freeciv/ai/aicity.h,v retrieving revision 1.24 diff -u -r1.24 aicity.h --- ai/aicity.h 3 Sep 2004 04:22:36 -0000 1.24 +++ ai/aicity.h 6 Sep 2004 01:11:03 -0000 @@ -15,15 +15,14 @@ #include "fc_types.h" #include "unit.h" /* enum unit_move_type */ +#include "city.h" +#include "aidata.h" struct ai_choice; -struct ai_data; - -int ai_eval_calc_city(struct city *pcity, struct ai_data *ai); void ai_manage_cities(struct player *pplayer); -enum ai_city_task { AICITY_NONE, AICITY_TECH, AICITY_TAX, AICITY_PROD}; -/* These are not used (well, except AICITY_NONE) --dwp */ +Unit_Type_id ai_choose_defender_versus(struct city *pcity, Unit_Type_id v); +int ai_eval_calc_city(struct city *pcity, struct ai_data *ai); #endif /* FC__AICITY_H */ Index: ai/aidata.c =================================================================== RCS file: /home/freeciv/CVS/freeciv/ai/aidata.c,v retrieving revision 1.37 diff -u -r1.37 aidata.c --- ai/aidata.c 2 Sep 2004 20:51:48 -0000 1.37 +++ ai/aidata.c 6 Sep 2004 01:11:03 -0000 @@ -1,389 +1,484 @@ -/********************************************************************** - Freeciv - Copyright (C) 2002 - The Freeciv Project - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2, or (at your option) - any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. -***********************************************************************/ - -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif - -#include "aisupport.h" -#include "city.h" -#include "game.h" -#include "government.h" -#include "log.h" -#include "map.h" -#include "mem.h" -#include "unit.h" - -#include "citytools.h" -#include "diplhand.h" -#include "maphand.h" -#include "settlers.h" -#include "unittools.h" - -#include "advdiplomacy.h" -#include "advmilitary.h" -#include "aicity.h" -#include "aiferry.h" -#include "aihand.h" -#include "ailog.h" -#include "aitools.h" -#include "aiunit.h" - -#include "aidata.h" - -static struct ai_data aidata[MAX_NUM_PLAYERS + MAX_NUM_BARBARIANS]; - -/************************************************************************** - Make and cache lots of calculations needed for other functions. - - Note: We use map.num_continents here rather than pplayer->num_continents - because we are omniscient and don't care about such trivialities as who - can see what. - - FIXME: We should try to find the lowest common defence strength of our - defending units, and ignore enemy units that are incapable of harming - us, instead of just checking attack strength > 1. -**************************************************************************/ -void ai_data_turn_init(struct player *pplayer) -{ - struct ai_data *ai = &aidata[pplayer->player_no]; - int i, nuke_units = num_role_units(F_NUCLEAR); - bool danger_of_nukes = FALSE; - int ally_strength = -1; - struct player *ally_strongest = NULL; - - /*** Threats ***/ - - ai->num_continents = map.num_continents; - ai->num_oceans = map.num_oceans; - ai->threats.continent = fc_calloc(ai->num_continents + 1, sizeof(bool)); - ai->threats.invasions = FALSE; - ai->threats.air = FALSE; - ai->threats.nuclear = 0; /* none */ - ai->threats.ocean = fc_calloc(ai->num_oceans + 1, sizeof(bool)); - - players_iterate(aplayer) { - if (!is_player_dangerous(pplayer, aplayer)) { - continue; - } - - /* The idea is that if there aren't any hostile cities on - * our continent, the danger of land attacks is not big - * enough to warrant city walls. Concentrate instead on - * coastal fortresses and hunting down enemy transports. */ - city_list_iterate(aplayer->cities, acity) { - Continent_id continent = map_get_continent(acity->x, acity->y); - ai->threats.continent[continent] = TRUE; - } city_list_iterate_end; - - unit_list_iterate(aplayer->units, punit) { - if (is_sailing_unit(punit)) { - /* If the enemy has not started sailing yet, or we have total - * control over the seas, don't worry, keep attacking. */ - if (is_ground_units_transport(punit)) { - ai->threats.invasions = TRUE; - } - - /* The idea is that while our enemies don't have any offensive - * seaborne units, we don't have to worry. Go on the offensive! */ - if (unit_type(punit)->attack_strength > 1) { - if (is_ocean(map_get_terrain(punit->x, punit->y))) { - Continent_id continent = map_get_continent(punit->x, punit->y); - ai->threats.ocean[-continent] = TRUE; - } else { - adjc_iterate(punit->x, punit->y, x2, y2) { - if (is_ocean(map_get_terrain(x2, y2))) { - Continent_id continent = map_get_continent(x2, y2); - ai->threats.ocean[-continent] = TRUE; - } - } adjc_iterate_end; - } - } - continue; - } - - /* The next idea is that if our enemies don't have any offensive - * airborne units, we don't have to worry. Go on the offensive! */ - if ((is_air_unit(punit) || is_heli_unit(punit)) - && unit_type(punit)->attack_strength > 1) { - ai->threats.air = TRUE; - } - - /* If our enemy builds missiles, worry about missile defence. */ - if (unit_flag(punit, F_MISSILE) - && unit_type(punit)->attack_strength > 1) { - ai->threats.missile = TRUE; - } - - /* If he builds nukes, worry a lot. */ - if (unit_flag(punit, F_NUCLEAR)) { - danger_of_nukes = TRUE; - } - } unit_list_iterate_end; - - /* Check for nuke capability */ - for (i = 0; i < nuke_units; i++) { - Unit_Type_id nuke = get_role_unit(F_NUCLEAR, i); - if (can_player_build_unit_direct(aplayer, nuke)) { - ai->threats.nuclear = 1; - } - } - } players_iterate_end; - - /* Increase from fear to terror if opponent actually has nukes */ - if (danger_of_nukes) ai->threats.nuclear++; /* sum of both fears */ - - /*** Exploration ***/ - - ai->explore.land_done = TRUE; - ai->explore.sea_done = TRUE; - ai->explore.continent = fc_calloc(ai->num_continents + 1, sizeof(bool)); - ai->explore.ocean = fc_calloc(ai->num_oceans + 1, sizeof(bool)); - whole_map_iterate(x, y) { - struct tile *ptile = map_get_tile(x, y); - Continent_id continent = map_get_continent(x, y); - - if (is_ocean(ptile->terrain)) { - if (ai->explore.sea_done && ai_handicap(pplayer, H_TARGETS) - && !map_is_known(x, y, pplayer)) { - /* We're not done there. */ - ai->explore.sea_done = FALSE; - ai->explore.ocean[-continent] = TRUE; - } - /* skip rest, which is land only */ - continue; - } - if (ai->explore.continent[ptile->continent]) { - /* we don't need more explaining, we got the point */ - continue; - } - if (map_has_special(x, y, S_HUT) - && (!ai_handicap(pplayer, H_HUTS) - || map_is_known(x, y, pplayer))) { - ai->explore.land_done = FALSE; - ai->explore.continent[continent] = TRUE; - continue; - } - if (ai_handicap(pplayer, H_TARGETS) && !map_is_known(x, y, pplayer)) { - /* this AI must explore */ - ai->explore.land_done = FALSE; - ai->explore.continent[continent] = TRUE; - } - } whole_map_iterate_end; - - /*** Statistics ***/ - - ai->stats.workers = fc_calloc(ai->num_continents + 1, sizeof(int)); - ai->stats.cities = fc_calloc(ai->num_continents + 1, sizeof(int)); - ai->stats.average_production = 0; - city_list_iterate(pplayer->cities, pcity) { - ai->stats.cities[(int)map_get_continent(pcity->x, pcity->y)]++; - ai->stats.average_production += pcity->shield_surplus; - } city_list_iterate_end; - ai->stats.average_production /= MAX(1, city_list_size(&pplayer->cities)); - BV_CLR_ALL(ai->stats.diplomat_reservations); - unit_list_iterate(pplayer->units, punit) { - struct tile *ptile = map_get_tile(punit->x, punit->y); - - if (!is_ocean(ptile->terrain) && unit_flag(punit, F_SETTLERS)) { - ai->stats.workers[(int)map_get_continent(punit->x, punit->y)]++; - } - if (unit_flag(punit, F_DIPLOMAT) && punit->ai.ai_role == AIUNIT_ATTACK) { - /* Heading somewhere on a mission, reserve target. */ - struct city *pcity = map_get_city(goto_dest_x(punit), - goto_dest_y(punit));; - if (pcity) { - BV_SET(ai->stats.diplomat_reservations, pcity->id); - } - } - } unit_list_iterate_end; - aiferry_init_stats(pplayer); - - /*** Diplomacy ***/ - - if (pplayer->ai.control && !is_barbarian(pplayer)) { - ai_diplomacy_calculate(pplayer, ai); - } - - /* Question: What can we accept as the reputation of a player before - * we start taking action to prevent us from being suckered? - * Answer: Very little. */ - ai->diplomacy.acceptable_reputation = - GAME_DEFAULT_REPUTATION - - GAME_DEFAULT_REPUTATION / 4; - - /* Set per-player variables. We must set all players, since players - * can be created during a turn, and we don't want those to have - * invalid values. */ - for (i = 0; i < MAX_NUM_PLAYERS + MAX_NUM_BARBARIANS; i++) { - struct player *aplayer = get_player(i); - - ai->diplomacy.player_intel[i].is_allied_with_enemy = NULL; - ai->diplomacy.player_intel[i].at_war_with_ally = NULL; - ai->diplomacy.player_intel[i].is_allied_with_ally = NULL; - - /* Determine who is the leader of our alliance. That is, - * whoever has the more cities. */ - if (pplayers_allied(pplayer, aplayer) - && city_list_size(&aplayer->cities) > ally_strength) { - ally_strength = city_list_size(&aplayer->cities); - ally_strongest = aplayer; - } - - players_iterate(check_pl) { - if (check_pl == pplayer - || check_pl == aplayer - || !check_pl->is_alive) { - continue; - } - if (pplayers_allied(aplayer, check_pl) - && pplayer_get_diplstate(pplayer, check_pl)->type == DS_WAR) { - ai->diplomacy.player_intel[i].is_allied_with_enemy = check_pl; - } - if (pplayers_allied(pplayer, check_pl) - && pplayer_get_diplstate(aplayer, check_pl)->type == DS_WAR) { - ai->diplomacy.player_intel[i].at_war_with_ally = check_pl; - } - if (pplayers_allied(aplayer, check_pl) - && pplayers_allied(pplayer, check_pl)) { - ai->diplomacy.player_intel[i].is_allied_with_ally = check_pl; - } - } players_iterate_end; - } - if (ally_strongest != ai->diplomacy.alliance_leader) { - ai->diplomacy.alliance_leader = ally_strongest; - } - ai->diplomacy.spacerace_leader = player_leading_spacerace(); - - /*** Priorities ***/ - - /* NEVER set these to zero! Weight values are usually multiplied by - * these values, so be careful with them. They are used in city - * and government calculations, and food and shields should be - * slightly bigger because we only look at surpluses there. They - * are all WAGs. */ - ai->food_priority = FOOD_WEIGHTING; - ai->shield_priority = SHIELD_WEIGHTING; - if (ai_wants_no_science(pplayer)) { - ai->luxury_priority = TRADE_WEIGHTING; - ai->science_priority = 1; - } else { - ai->luxury_priority = 1; - ai->science_priority = TRADE_WEIGHTING; - } - ai->gold_priority = TRADE_WEIGHTING; - ai->happy_priority = 1; - ai->unhappy_priority = TRADE_WEIGHTING; /* danger */ - ai->angry_priority = TRADE_WEIGHTING * 3; /* grave danger */ - ai->pollution_priority = POLLUTION_WEIGHTING; - - ai_best_government(pplayer); - - /*** Interception engine ***/ - - /* We are tracking a unit if punit->ai.cur_pos is not NULL. If we - * are not tracking, start tracking by setting cur_pos. If we are, - * fill prev_pos with previous cur_pos. This way we get the - * necessary coordinates to calculate a probably trajectory. */ - players_iterate(aplayer) { - if (!aplayer->is_alive || aplayer == pplayer) { - continue; - } - unit_list_iterate(aplayer->units, punit) { - if (!punit->ai.cur_pos) { - /* Start tracking */ - punit->ai.cur_pos = &punit->ai.cur_struct; - punit->ai.prev_pos = NULL; - } else { - punit->ai.prev_struct = punit->ai.cur_struct; - punit->ai.prev_pos = &punit->ai.prev_struct; - } - punit->ai.cur_pos->x = punit->x; - punit->ai.cur_pos->y = punit->y; - } unit_list_iterate_end; - } players_iterate_end; -} - -/************************************************************************** - Clean up our mess. -**************************************************************************/ -void ai_data_turn_done(struct player *pplayer) -{ - struct ai_data *ai = &aidata[pplayer->player_no]; - - free(ai->explore.ocean); ai->explore.ocean = NULL; - free(ai->explore.continent); ai->explore.continent = NULL; - free(ai->threats.continent); ai->threats.continent = NULL; - free(ai->stats.workers); ai->stats.workers = NULL; - free(ai->stats.cities); ai->stats.cities = NULL; -} - -/************************************************************************** - Return a pointer to our data -**************************************************************************/ -struct ai_data *ai_data_get(struct player *pplayer) -{ - struct ai_data *ai = &aidata[pplayer->player_no]; - - if (ai->num_continents != map.num_continents - || ai->num_oceans != map.num_oceans) { - /* we discovered more continents, recalculate! */ - ai_data_turn_done(pplayer); - ai_data_turn_init(pplayer); - } - return ai; -} - -/************************************************************************** - Initialize with sane values. -**************************************************************************/ -void ai_data_init(struct player *pplayer) -{ - struct ai_data *ai = &aidata[pplayer->player_no]; - int i; - - ai->govt_reeval = 0; - ai->government_want = fc_calloc(game.government_count + 1, sizeof(int)); - - ai->diplomacy.target = NULL; - ai->diplomacy.strategy = WIN_OPEN; - ai->diplomacy.timer = 0; - ai->diplomacy.countdown = 0; - ai->diplomacy.love_coeff = 4; /* 4% */ - ai->diplomacy.love_incr = 4; - ai->diplomacy.req_love_for_peace = 8; - ai->diplomacy.req_love_for_alliance = 16; - ai->diplomacy.req_love_for_ceasefire = 0; - ai->diplomacy.alliance_leader = pplayer; - - for (i = 0; i < MAX_NUM_PLAYERS + MAX_NUM_BARBARIANS; i++) { - ai->diplomacy.player_intel[i].spam = i % 5; /* pseudorandom */ - ai->diplomacy.player_intel[i].distance = 1; - ai->diplomacy.player_intel[i].ally_patience = 0; - pplayer->ai.love[i] = 1; - ai->diplomacy.player_intel[i].asked_about_peace = 0; - ai->diplomacy.player_intel[i].asked_about_alliance = 0; - ai->diplomacy.player_intel[i].asked_about_ceasefire = 0; - ai->diplomacy.player_intel[i].warned_about_space = 0; - } -} - -/************************************************************************** - Deinitialize data -**************************************************************************/ -void ai_data_done(struct player *pplayer) -{ - struct ai_data *ai = &aidata[pplayer->player_no]; - - free(ai->government_want); -} +/********************************************************************** + Freeciv - Copyright (C) 2002 - The Freeciv Project + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include "aisupport.h" +#include "city.h" +#include "effects.h" +#include "game.h" +#include "government.h" +#include "log.h" +#include "map.h" +#include "mem.h" +#include "unit.h" + +#include "citytools.h" +#include "diplhand.h" +#include "maphand.h" +#include "settlers.h" +#include "unittools.h" + +#include "advdiplomacy.h" +#include "advmilitary.h" +#include "aicity.h" +#include "aiferry.h" +#include "aihand.h" +#include "ailog.h" +#include "aitools.h" +#include "aiunit.h" + +#include "aidata.h" + +static struct ai_data aidata[MAX_NUM_PLAYERS + MAX_NUM_BARBARIANS]; + +/************************************************************************** + Precalculates some important data about the improvements in the game + that we use later in ai/aicity.c. We mark improvements as 'calculate' + if we want to run a full test on them, as 'estimate' if we just want + to do some guesses on them, or as 'unused' is they are useless to us. + Then we find the largest range of calculatable effects in the + improvement and record it for later use. +**************************************************************************/ +static void ai_data_city_impr_calc(struct player *pplayer, struct ai_data *ai) +{ + int count[AI_IMPR_LAST]; + + memset(count, 0, sizeof(count)); + + impr_type_iterate(id) { + ai->impr_calc[id] = AI_IMPR_ESTIMATE; + + /* Find largest extension */ + effect_type_vector_iterate(get_building_effect_types(id), ptype) { + switch (*ptype) { +#if 0 + /* TODO */ + case EFT_FORCE_CONTENT: + case EFT_FORCE_CONTENT_PCT: + case EFT_MAKE_CONTENT: + case EFT_MAKE_CONTENT_MIL: + case EFT_MAKE_CONTENT_MIL_PER: + case EFT_MAKE_CONTENT_PCT: + case EFT_MAKE_HAPPY: +#endif + case EFT_LUXURY_BONUS: + case EFT_LUXURY_PCT: + case EFT_SCIENCE_BONUS: + case EFT_SCIENCE_PCT: + case EFT_TAX_BONUS: + case EFT_TAX_PCT: + case EFT_CAPITAL_CITY: + case EFT_CORRUPT_PCT: + case EFT_FOOD_ADD_TILE: + case EFT_FOOD_BONUS: + case EFT_FOOD_PCT: + case EFT_FOOD_INC_TILE: + case EFT_FOOD_PER_TILE: + case EFT_POLLU_ADJ: + case EFT_POLLU_PCT: + case EFT_POLLU_POP_ADJ: + case EFT_POLLU_POP_PCT: + case EFT_POLLU_PROD_ADJ: + case EFT_POLLU_PROD_PCT: + case EFT_PROD_ADD_TILE: + case EFT_PROD_BONUS: + case EFT_PROD_PCT: + case EFT_PROD_INC_TILE: + case EFT_PROD_PER_TILE: + case EFT_TRADE_ADD_TILE: + case EFT_TRADE_BONUS: + case EFT_TRADE_PCT: + case EFT_TRADE_INC_TILE: + case EFT_TRADE_PER_TILE: + case EFT_UPKEEP_FREE: + effect_list_iterate(*get_building_effects(id, *ptype), peff) { + ai->impr_calc[id] = AI_IMPR_CALCULATE; + if (peff->range > ai->impr_range[id]) { + ai->impr_range[id] = peff->range; + } + } effect_list_iterate_end; + break; + default: + /* Nothing! */ + break; + } + } effect_type_vector_iterate_end; + + } impr_type_iterate_end; +} + +/************************************************************************** + Analyze rulesets. Must be run after rulesets after loaded, unlike + _init, which must be run before savegames are loaded, which is usually + before rulesets. +**************************************************************************/ +void ai_data_analyze_rulesets(struct player *pplayer) +{ + struct ai_data *ai = &aidata[pplayer->player_no]; + +freelog(LOG_NORMAL, "yep, ran"); + ai_data_city_impr_calc(pplayer, ai); +} + +/************************************************************************** + Make and cache lots of calculations needed for other functions. + + Note: We use map.num_continents here rather than pplayer->num_continents + because we are omniscient and don't care about such trivialities as who + can see what. + + FIXME: We should try to find the lowest common defence strength of our + defending units, and ignore enemy units that are incapable of harming + us, instead of just checking attack strength > 1. +**************************************************************************/ +void ai_data_turn_init(struct player *pplayer) +{ + struct ai_data *ai = &aidata[pplayer->player_no]; + int i, nuke_units = num_role_units(F_NUCLEAR); + bool danger_of_nukes = FALSE; + int ally_strength = -1; + struct player *ally_strongest = NULL; + + /*** Threats ***/ + + ai->num_continents = map.num_continents; + ai->num_oceans = map.num_oceans; + ai->threats.continent = fc_calloc(ai->num_continents + 1, sizeof(bool)); + ai->threats.invasions = FALSE; + ai->threats.air = FALSE; + ai->threats.nuclear = 0; /* none */ + ai->threats.ocean = fc_calloc(ai->num_oceans + 1, sizeof(bool)); + ai->threats.igwall = FALSE; + + players_iterate(aplayer) { + if (!is_player_dangerous(pplayer, aplayer)) { + continue; + } + + /* The idea is that if there aren't any hostile cities on + * our continent, the danger of land attacks is not big + * enough to warrant city walls. Concentrate instead on + * coastal fortresses and hunting down enemy transports. */ + city_list_iterate(aplayer->cities, acity) { + Continent_id continent = map_get_continent(acity->x, acity->y); + ai->threats.continent[continent] = TRUE; + } city_list_iterate_end; + + unit_list_iterate(aplayer->units, punit) { + if (unit_flag(punit, F_IGWALL)) { + ai->threats.igwall = TRUE; + } + + if (is_sailing_unit(punit)) { + /* If the enemy has not started sailing yet, or we have total + * control over the seas, don't worry, keep attacking. */ + if (is_ground_units_transport(punit)) { + ai->threats.invasions = TRUE; + } + + /* The idea is that while our enemies don't have any offensive + * seaborne units, we don't have to worry. Go on the offensive! */ + if (unit_type(punit)->attack_strength > 1) { + if (is_ocean(map_get_terrain(punit->x, punit->y))) { + Continent_id continent = map_get_continent(punit->x, punit->y); + ai->threats.ocean[-continent] = TRUE; + } else { + adjc_iterate(punit->x, punit->y, x2, y2) { + if (is_ocean(map_get_terrain(x2, y2))) { + Continent_id continent = map_get_continent(x2, y2); + ai->threats.ocean[-continent] = TRUE; + } + } adjc_iterate_end; + } + } + continue; + } + + /* The next idea is that if our enemies don't have any offensive + * airborne units, we don't have to worry. Go on the offensive! */ + if ((is_air_unit(punit) || is_heli_unit(punit)) + && unit_type(punit)->attack_strength > 1) { + ai->threats.air = TRUE; + } + + /* If our enemy builds missiles, worry about missile defence. */ + if (unit_flag(punit, F_MISSILE) + && unit_type(punit)->attack_strength > 1) { + ai->threats.missile = TRUE; + } + + /* If he builds nukes, worry a lot. */ + if (unit_flag(punit, F_NUCLEAR)) { + danger_of_nukes = TRUE; + } + } unit_list_iterate_end; + + /* Check for nuke capability */ + for (i = 0; i < nuke_units; i++) { + Unit_Type_id nuke = get_role_unit(F_NUCLEAR, i); + if (can_player_build_unit_direct(aplayer, nuke)) { + ai->threats.nuclear = 1; + } + } + } players_iterate_end; + + /* Increase from fear to terror if opponent actually has nukes */ + if (danger_of_nukes) ai->threats.nuclear++; /* sum of both fears */ + + /*** Exploration ***/ + + ai->explore.land_done = TRUE; + ai->explore.sea_done = TRUE; + ai->explore.continent = fc_calloc(ai->num_continents + 1, sizeof(bool)); + ai->explore.ocean = fc_calloc(ai->num_oceans + 1, sizeof(bool)); + whole_map_iterate(x, y) { + struct tile *ptile = map_get_tile(x, y); + Continent_id continent = map_get_continent(x, y); + + if (is_ocean(ptile->terrain)) { + if (ai->explore.sea_done && ai_handicap(pplayer, H_TARGETS) + && !map_is_known(x, y, pplayer)) { + /* We're not done there. */ + ai->explore.sea_done = FALSE; + ai->explore.ocean[-continent] = TRUE; + } + /* skip rest, which is land only */ + continue; + } + if (ai->explore.continent[ptile->continent]) { + /* we don't need more explaining, we got the point */ + continue; + } + if (map_has_special(x, y, S_HUT) + && (!ai_handicap(pplayer, H_HUTS) + || map_is_known(x, y, pplayer))) { + ai->explore.land_done = FALSE; + ai->explore.continent[continent] = TRUE; + continue; + } + if (ai_handicap(pplayer, H_TARGETS) && !map_is_known(x, y, pplayer)) { + /* this AI must explore */ + ai->explore.land_done = FALSE; + ai->explore.continent[continent] = TRUE; + } + } whole_map_iterate_end; + + /*** Statistics ***/ + + ai->stats.workers = fc_calloc(ai->num_continents + 1, sizeof(int)); + ai->stats.cities = fc_calloc(ai->num_continents + 1, sizeof(int)); + ai->stats.average_production = 0; + city_list_iterate(pplayer->cities, pcity) { + ai->stats.cities[(int)map_get_continent(pcity->x, pcity->y)]++; + ai->stats.average_production += pcity->shield_surplus; + } city_list_iterate_end; + ai->stats.average_production /= MAX(1, city_list_size(&pplayer->cities)); + BV_CLR_ALL(ai->stats.diplomat_reservations); + unit_list_iterate(pplayer->units, punit) { + struct tile *ptile = map_get_tile(punit->x, punit->y); + + if (!is_ocean(ptile->terrain) && unit_flag(punit, F_SETTLERS)) { + ai->stats.workers[(int)map_get_continent(punit->x, punit->y)]++; + } + if (unit_flag(punit, F_DIPLOMAT) && punit->ai.ai_role == AIUNIT_ATTACK) { + /* Heading somewhere on a mission, reserve target. */ + struct city *pcity = map_get_city(goto_dest_x(punit), + goto_dest_y(punit));; + if (pcity) { + BV_SET(ai->stats.diplomat_reservations, pcity->id); + } + } + } unit_list_iterate_end; + aiferry_init_stats(pplayer); + + /*** Diplomacy ***/ + + if (pplayer->ai.control && !is_barbarian(pplayer)) { + ai_diplomacy_calculate(pplayer, ai); + } + + /* Question: What can we accept as the reputation of a player before + * we start taking action to prevent us from being suckered? + * Answer: Very little. */ + ai->diplomacy.acceptable_reputation = + GAME_DEFAULT_REPUTATION - + GAME_DEFAULT_REPUTATION / 4; + + /* Set per-player variables. We must set all players, since players + * can be created during a turn, and we don't want those to have + * invalid values. */ + for (i = 0; i < MAX_NUM_PLAYERS + MAX_NUM_BARBARIANS; i++) { + struct player *aplayer = get_player(i); + + ai->diplomacy.player_intel[i].is_allied_with_enemy = NULL; + ai->diplomacy.player_intel[i].at_war_with_ally = NULL; + ai->diplomacy.player_intel[i].is_allied_with_ally = NULL; + + /* Determine who is the leader of our alliance. That is, + * whoever has the more cities. */ + if (pplayers_allied(pplayer, aplayer) + && city_list_size(&aplayer->cities) > ally_strength) { + ally_strength = city_list_size(&aplayer->cities); + ally_strongest = aplayer; + } + + players_iterate(check_pl) { + if (check_pl == pplayer + || check_pl == aplayer + || !check_pl->is_alive) { + continue; + } + if (pplayers_allied(aplayer, check_pl) + && pplayer_get_diplstate(pplayer, check_pl)->type == DS_WAR) { + ai->diplomacy.player_intel[i].is_allied_with_enemy = check_pl; + } + if (pplayers_allied(pplayer, check_pl) + && pplayer_get_diplstate(aplayer, check_pl)->type == DS_WAR) { + ai->diplomacy.player_intel[i].at_war_with_ally = check_pl; + } + if (pplayers_allied(aplayer, check_pl) + && pplayers_allied(pplayer, check_pl)) { + ai->diplomacy.player_intel[i].is_allied_with_ally = check_pl; + } + } players_iterate_end; + } + if (ally_strongest != ai->diplomacy.alliance_leader) { + ai->diplomacy.alliance_leader = ally_strongest; + } + ai->diplomacy.spacerace_leader = player_leading_spacerace(); + + /*** Priorities ***/ + + /* NEVER set these to zero! Weight values are usually multiplied by + * these values, so be careful with them. They are used in city + * and government calculations, and food and shields should be + * slightly bigger because we only look at surpluses there. They + * are all WAGs. */ + ai->food_priority = FOOD_WEIGHTING; + ai->shield_priority = SHIELD_WEIGHTING; + if (ai_wants_no_science(pplayer)) { + ai->luxury_priority = TRADE_WEIGHTING; + ai->science_priority = 1; + } else { + ai->luxury_priority = 1; + ai->science_priority = TRADE_WEIGHTING; + } + ai->gold_priority = TRADE_WEIGHTING; + ai->happy_priority = 1; + ai->unhappy_priority = TRADE_WEIGHTING; /* danger */ + ai->angry_priority = TRADE_WEIGHTING * 3; /* grave danger */ + ai->pollution_priority = POLLUTION_WEIGHTING; + + ai_best_government(pplayer); + + /*** Interception engine ***/ + + /* We are tracking a unit if punit->ai.cur_pos is not NULL. If we + * are not tracking, start tracking by setting cur_pos. If we are, + * fill prev_pos with previous cur_pos. This way we get the + * necessary coordinates to calculate a probably trajectory. */ + players_iterate(aplayer) { + if (!aplayer->is_alive || aplayer == pplayer) { + continue; + } + unit_list_iterate(aplayer->units, punit) { + if (!punit->ai.cur_pos) { + /* Start tracking */ + punit->ai.cur_pos = &punit->ai.cur_struct; + punit->ai.prev_pos = NULL; + } else { + punit->ai.prev_struct = punit->ai.cur_struct; + punit->ai.prev_pos = &punit->ai.prev_struct; + } + punit->ai.cur_pos->x = punit->x; + punit->ai.cur_pos->y = punit->y; + } unit_list_iterate_end; + } players_iterate_end; +} + +/************************************************************************** + Clean up our mess. +**************************************************************************/ +void ai_data_turn_done(struct player *pplayer) +{ + struct ai_data *ai = &aidata[pplayer->player_no]; + + free(ai->explore.ocean); ai->explore.ocean = NULL; + free(ai->explore.continent); ai->explore.continent = NULL; + free(ai->threats.continent); ai->threats.continent = NULL; + free(ai->stats.workers); ai->stats.workers = NULL; + free(ai->stats.cities); ai->stats.cities = NULL; +} + +/************************************************************************** + Return a pointer to our data +**************************************************************************/ +struct ai_data *ai_data_get(struct player *pplayer) +{ + struct ai_data *ai = &aidata[pplayer->player_no]; + + if (ai->num_continents != map.num_continents + || ai->num_oceans != map.num_oceans) { + /* we discovered more continents, recalculate! */ + ai_data_turn_done(pplayer); + ai_data_turn_init(pplayer); + } + return ai; +} + +/************************************************************************** + Initialize with sane values. +**************************************************************************/ +void ai_data_init(struct player *pplayer) +{ + struct ai_data *ai = &aidata[pplayer->player_no]; + int i; + + ai->govt_reeval = 0; + ai->government_want = fc_calloc(game.government_count + 1, sizeof(int)); + + ai->diplomacy.target = NULL; + ai->diplomacy.strategy = WIN_OPEN; + ai->diplomacy.timer = 0; + ai->diplomacy.countdown = 0; + ai->diplomacy.love_coeff = 4; /* 4% */ + ai->diplomacy.love_incr = 4; + ai->diplomacy.req_love_for_peace = 8; + ai->diplomacy.req_love_for_alliance = 16; + ai->diplomacy.req_love_for_ceasefire = 0; + ai->diplomacy.alliance_leader = pplayer; + + for (i = 0; i < MAX_NUM_PLAYERS + MAX_NUM_BARBARIANS; i++) { + ai->diplomacy.player_intel[i].spam = i % 5; /* pseudorandom */ + ai->diplomacy.player_intel[i].distance = 1; + ai->diplomacy.player_intel[i].ally_patience = 0; + pplayer->ai.love[i] = 1; + ai->diplomacy.player_intel[i].asked_about_peace = 0; + ai->diplomacy.player_intel[i].asked_about_alliance = 0; + ai->diplomacy.player_intel[i].asked_about_ceasefire = 0; + ai->diplomacy.player_intel[i].warned_about_space = 0; + } +} + +/************************************************************************** + Deinitialize data +**************************************************************************/ +void ai_data_done(struct player *pplayer) +{ + struct ai_data *ai = &aidata[pplayer->player_no]; + + free(ai->government_want); +} Index: ai/aidata.h =================================================================== RCS file: /home/freeciv/CVS/freeciv/ai/aidata.h,v retrieving revision 1.16 diff -u -r1.16 aidata.h --- ai/aidata.h 3 Sep 2004 04:22:36 -0000 1.16 +++ ai/aidata.h 6 Sep 2004 01:11:03 -0000 @@ -26,6 +26,12 @@ * start of every turn. */ +enum ai_improvement_status { + AI_IMPR_CALCULATE, /* Calculate exactly its effect */ + AI_IMPR_ESTIMATE, /* Estimate its effect using wild guesses */ + AI_IMPR_LAST +}; + enum winning_strategy { WIN_OPEN, /* still undetermined */ WIN_WAR, /* we have no other choice than to crush all opposition */ @@ -50,6 +56,10 @@ BV_DEFINE(bv_id, MAX_NUM_ID); struct ai_data { + /* Precalculated info about city improvements */ + enum ai_improvement_status impr_calc[MAX_NUM_ITEMS]; + enum effect_range impr_range[MAX_NUM_ITEMS]; + /* AI diplomacy and opinions on other players */ struct { int acceptable_reputation; @@ -75,6 +85,7 @@ bool air; /* check for non-allied offensive aircraft */ bool missile; /* check for non-allied missiles */ int nuclear; /* nuke check: 0=no, 1=capability, 2=built */ + bool igwall; /* enemies have igwall units */ } threats; /* Keeps track of which continents are fully explored already */ @@ -88,6 +99,8 @@ /* This struct is used for statistical unit building, eg to ensure * that we don't build too few or too many units of a given type. */ struct { + int triremes; + int units[UCL_LAST + 1]; /* no. units by class */ int *workers; /* cities to workers on continent*/ int *cities; /* number of cities on continent */ int passengers; /* number of passengers waiting for boats */ @@ -132,8 +145,8 @@ void ai_data_init(struct player *pplayer); void ai_data_done(struct player *pplayer); +void ai_data_analyze_rulesets(struct player *pplayer); struct ai_data *ai_data_get(struct player *pplayer); - #endif Index: ai/aidiplomat.c =================================================================== RCS file: /home/freeciv/CVS/freeciv/ai/aidiplomat.c,v retrieving revision 1.38 diff -u -r1.38 aidiplomat.c --- ai/aidiplomat.c 29 Aug 2004 17:54:13 -0000 1.38 +++ ai/aidiplomat.c 6 Sep 2004 01:11:03 -0000 @@ -173,11 +173,8 @@ } incite_cost = city_incite_cost(pplayer, acity); if (HOSTILE_PLAYER(pplayer, ai, city_owner(acity)) - && !city_got_building(acity, B_PALACE) - && !government_has_flag(get_gov_pplayer(city_owner(acity)), - G_UNBRIBABLE) - && (incite_cost < - pplayer->economic.gold - pplayer->ai.est_upkeep)) { + && (incite_cost < INCITE_IMPOSSIBLE_COST) + && (incite_cost < pplayer->economic.gold - pplayer->ai.est_upkeep)) { /* incite gain (FIXME: we should count wonders too but need to cache that somehow to avoid CPU hog -- Per) */ gain_incite = acity->food_prod * FOOD_WEIGHTING @@ -345,11 +342,9 @@ continue; } - can_incite = !(city_got_building(acity, B_PALACE) - || government_has_flag(get_gov_pplayer(aplayer), - G_UNBRIBABLE)); - incite_cost = city_incite_cost(pplayer, acity); + can_incite = (incite_cost < INCITE_IMPOSSIBLE_COST); + dipldef = (count_diplomats_on_tile(acity->x, acity->y) > 0); /* Three actions to consider: * 1. establishing embassy OR Index: ai/aiexplorer.c =================================================================== RCS file: /home/freeciv/CVS/freeciv/ai/aiexplorer.c,v retrieving revision 1.3 diff -u -r1.3 aiexplorer.c --- ai/aiexplorer.c 26 Aug 2004 22:22:03 -0000 1.3 +++ ai/aiexplorer.c 6 Sep 2004 01:11:04 -0000 @@ -110,7 +110,7 @@ */ if ((likely_ocean(x, y, pplayer) < 50) || is_likely_coastline(x, y, pplayer) || - (player_owns_active_wonder(pplayer, B_LIGHTHOUSE))) { + get_player_bonus(pplayer, EFT_NO_SINK_DEEP) > 0) { return FALSE; } else { return TRUE; Index: ai/aitools.c =================================================================== RCS file: /home/freeciv/CVS/freeciv/ai/aitools.c,v retrieving revision 1.122 diff -u -r1.122 aitools.c --- ai/aitools.c 2 Sep 2004 14:58:23 -0000 1.122 +++ ai/aitools.c 6 Sep 2004 01:11:04 -0000 @@ -793,8 +793,6 @@ struct government *g) { int free_happy; - bool have_police; - int variant; int unhap = 0; /* bail out now if happy_cost is 0 */ @@ -803,14 +801,10 @@ } free_happy = citygov_free_happy(pcity, g); - have_police = city_got_effect(pcity, B_POLICE); - variant = improvement_variant(B_WOMENS); - if (variant == 0 && have_police) { - /* ?? This does the right thing for normal Republic and Democ -- dwp */ - free_happy += g->unit_happy_cost_factor; - } - + /* ?? This does the right thing for normal Republic and Democ -- dwp */ + free_happy += get_city_bonus(pcity, EFT_MAKE_CONTENT_MIL); + unit_list_iterate(pcity->units_supported, punit) { int happy_cost = utype_happy_cost(unit_type(punit), g); @@ -830,7 +824,7 @@ continue; } - if (variant == 1 && have_police) { + if (get_city_bonus(pcity, EFT_MAKE_CONTENT_MIL_PER) > 0) { happy_cost--; } adjust_city_free_cost(&free_happy, &happy_cost); Index: ai/aiunit.c =================================================================== RCS file: /home/freeciv/CVS/freeciv/ai/aiunit.c,v retrieving revision 1.334 diff -u -r1.334 aiunit.c --- ai/aiunit.c 1 Sep 2004 11:47:25 -0000 1.334 +++ ai/aiunit.c 6 Sep 2004 01:11:04 -0000 @@ -1734,14 +1734,12 @@ city_list_iterate(aplayer->cities, pcity) { if (ground) { cur = WARMAP_COST(pcity->x, pcity->y); - if (city_got_building(pcity, B_BARRACKS) - || city_got_building(pcity, B_BARRACKS2) - || city_got_building(pcity, B_BARRACKS3)) { + if (get_city_bonus(pcity, EFT_LAND_REGEN) > 0) { cur /= 3; } } else { cur = WARMAP_SEACOST(pcity->x, pcity->y); - if (city_got_building(pcity, B_PORT)) { + if (get_city_bonus(pcity, EFT_SEA_REGEN) > 0) { cur /= 3; } } Index: client/cityrepdata.c =================================================================== RCS file: /home/freeciv/CVS/freeciv/client/cityrepdata.c,v retrieving revision 1.35 diff -u -r1.35 cityrepdata.c --- client/cityrepdata.c 4 Sep 2004 18:39:38 -0000 1.35 +++ client/cityrepdata.c 6 Sep 2004 01:11:04 -0000 @@ -274,7 +274,7 @@ static char buf[32]; int goldie; - goldie = city_gold_surplus(pcity); + goldie = city_gold_surplus(pcity, pcity->tax_total); my_snprintf(buf, sizeof(buf), "%s%d/%d/%d", (goldie < 0) ? "-" : (goldie > 0) ? "+" : "", (goldie < 0) ? (-goldie) : goldie, @@ -286,11 +286,11 @@ static const char *cr_entry_gold(const struct city *pcity) { static char buf[8]; - int income = city_gold_surplus(pcity); + int income = city_gold_surplus(pcity, pcity->tax_total); if (income > 0) { my_snprintf(buf, sizeof(buf), "+%d", income); } else { - my_snprintf(buf, sizeof(buf), "%3d", city_gold_surplus(pcity)); + my_snprintf(buf, sizeof(buf), "%3d", city_gold_surplus(pcity, pcity->tax_total)); } return buf; } Index: client/climisc.c =================================================================== RCS file: /home/freeciv/CVS/freeciv/client/climisc.c,v retrieving revision 1.138 diff -u -r1.138 climisc.c --- client/climisc.c 3 Sep 2004 01:21:03 -0000 1.138 +++ client/climisc.c 6 Sep 2004 01:11:04 -0000 @@ -713,7 +713,7 @@ impr_type_iterate(id) { bool can_build = can_player_build_improvement(game.player_ptr, id); bool can_eventually_build = - could_player_eventually_build_improvement(game.player_ptr, id); + can_player_eventually_build_improvement(game.player_ptr, id); /* If there's a city, can the city build the improvement? */ if (pcity) { Index: client/helpdata.c =================================================================== RCS file: /home/freeciv/CVS/freeciv/client/helpdata.c,v retrieving revision 1.74 diff -u -r1.74 helpdata.c --- client/helpdata.c 4 Sep 2004 21:11:46 -0000 1.74 +++ client/helpdata.c 6 Sep 2004 01:11:04 -0000 @@ -507,7 +507,8 @@ assert(buf); buf[0] = '\0'; - if (which == B_MANHATTEN && num_role_units(F_NUCLEAR) > 0) { + if (building_has_effect(which, EFT_ENABLE_NUKE) + && num_role_units(F_NUCLEAR) > 0) { Unit_Type_id u; Tech_Type_id t; Index: client/packhand.c =================================================================== RCS file: /home/freeciv/CVS/freeciv/client/packhand.c,v retrieving revision 1.400 diff -u -r1.400 packhand.c --- client/packhand.c 31 Aug 2004 04:40:48 -0000 1.400 +++ client/packhand.c 6 Sep 2004 01:11:05 -0000 @@ -699,10 +699,10 @@ ARRAY_SIZE(pcity->improvements)); } - update_improvement_from_packet(pcity, B_PALACE, packet->capital, - &need_effect_update); - update_improvement_from_packet(pcity, B_CITY, packet->walls, - &need_effect_update); + update_improvement_from_packet(pcity, game.palace_building, + packet->capital, &need_effect_update); + update_improvement_from_packet(pcity, game.land_defend_building, + packet->walls, &need_effect_update); if (city_is_new) { init_worklist(&pcity->worklist); @@ -1367,6 +1367,20 @@ game.nuclearwinter=pinfo->nuclearwinter; game.cooling=pinfo->cooling; if (!can_client_change_view()) { + /* + * Hack to allow code that explicitly checks for Palace or City Walls + * to work. + */ + game.palace_building = get_building_for_effect(EFT_CAPITAL_CITY); + if (game.palace_building == B_LAST) { + freelog(LOG_FATAL, "Cannot find any palace building"); + } + + game.land_defend_building = get_building_for_effect(EFT_LAND_DEFEND); + if (game.land_defend_building == B_LAST) { + freelog(LOG_FATAL, "Cannot find any land defend building"); + } + improvement_status_init(game.improvements, ARRAY_SIZE(game.improvements)); @@ -2155,6 +2169,8 @@ tilespec_free_city_tiles(game.styles_count); ruleset_data_free(); + ruleset_cache_init(); + game.aqueduct_size = packet->aqueduct_size; game.sewer_size = packet->sewer_size; game.add_to_size_limit = packet->add_to_size_limit; @@ -2194,6 +2210,8 @@ mystrlcpy(team_get_by_id(i)->name, packet->team_name[i], MAX_LEN_NAME); } + + game.default_building = packet->default_building; } /************************************************************************** @@ -2328,12 +2346,6 @@ T(equiv_repl, equiv_repl_count, B_LAST); #undef T - b->effect = fc_malloc(sizeof(*b->effect) * (p->effect_count + 1)); - for (i = 0; i < p->effect_count; i++) { - b->effect[i] = p->effect[i]; - } - b->effect[p->effect_count].type = EFT_LAST; - #ifdef DEBUG if(p->id == game.num_impr_types-1) { impr_type_iterate(id) { @@ -2384,75 +2396,6 @@ freelog(LOG_DEBUG, " upkeep %2d", b->upkeep); freelog(LOG_DEBUG, " sabotage %3d", b->sabotage); freelog(LOG_DEBUG, " effect..."); - for (inx = 0; b->effect[inx].type != EFT_LAST; inx++) { - char buf[1024], *ptr; - ptr = buf; - my_snprintf(ptr, sizeof(buf)-(ptr-buf), " %d/%s", - b->effect[inx].type, - effect_type_name(b->effect[inx].type)); - ptr = strchr(ptr, '\0'); - my_snprintf(ptr, sizeof(buf)-(ptr-buf), " range=%d/%s", - b->effect[inx].range, - effect_range_name(b->effect[inx].range)); - ptr = strchr(ptr, '\0'); - my_snprintf(ptr, sizeof(buf)-(ptr-buf), " amount=%d", - b->effect[inx].amount); - ptr = strchr(ptr, '\0'); - my_snprintf(ptr, sizeof(buf)-(ptr-buf), " survives=%d", - b->effect[inx].survives); - ptr = strchr(ptr, '\0'); - freelog(LOG_DEBUG, " %2d. %s", inx, buf); - ptr = buf; - my_snprintf(ptr, sizeof(buf)-(ptr-buf), " cond_bldg=%d/%s", - b->effect[inx].cond_bldg, - (b->effect[inx].cond_bldg == B_LAST) ? - "Uncond." : - improvement_types[b->effect[inx].cond_bldg].name); - ptr = strchr(ptr, '\0'); - my_snprintf(ptr, sizeof(buf)-(ptr-buf), " cond_gov=%d/%s", - b->effect[inx].cond_gov, - (b->effect[inx].cond_gov == game.government_count) ? - "Uncond." : - get_government_name(b->effect[inx].cond_gov)); - ptr = strchr(ptr, '\0'); - my_snprintf(ptr, sizeof(buf)-(ptr-buf), " cond_adv=%d/%s", - b->effect[inx].cond_adv, - (b->effect[inx].cond_adv == A_NONE) ? - "Uncond." : - (b->effect[inx].cond_adv == A_LAST) ? - "Never" : - advances[b->effect[inx].cond_adv].name); - ptr = strchr(ptr, '\0'); - my_snprintf(ptr, sizeof(buf)-(ptr-buf), " cond_eff=%d/%s", - b->effect[inx].cond_eff, - (b->effect[inx].cond_eff == EFT_LAST) ? - "Uncond." : - effect_type_name(b->effect[inx].cond_eff)); - ptr = strchr(ptr, '\0'); - freelog(LOG_DEBUG, " %s", buf); - ptr = buf; - my_snprintf(ptr, sizeof(buf)-(ptr-buf), " aff_unit=%d/%s", - b->effect[inx].aff_unit, - (b->effect[inx].aff_unit == UCL_LAST) ? - "All" : - unit_class_name(b->effect[inx].aff_unit)); - ptr = strchr(ptr, '\0'); - my_snprintf(ptr, sizeof(buf)-(ptr-buf), " aff_terr=%d/%s", - b->effect[inx].aff_terr, - (b->effect[inx].aff_terr == T_NONE) ? "None" - : ((b->effect[inx].aff_terr == T_UNKNOWN) ? "All" - : get_terrain_name(b->effect[inx].aff_terr))); - ptr = strchr(ptr, '\0'); - my_snprintf(ptr, sizeof(buf)-(ptr-buf), " aff_spec=%04X/%s", - b->effect[inx].aff_spec, - (b->effect[inx].aff_spec == 0) ? - "None" : - (b->effect[inx].aff_spec == S_ALL) ? - "All" : - get_special_name(b->effect[inx].aff_spec)); - ptr = strchr(ptr, '\0'); - freelog(LOG_DEBUG, " %s", buf); - } freelog(LOG_DEBUG, " variant %2d", b->variant); /* FIXME: remove when gen-impr obsoletes */ freelog(LOG_DEBUG, " helptext %s", b->helptext); } impr_type_iterate_end; @@ -2975,3 +2918,30 @@ { freelog(LOG_VERBOSE, "server shutdown"); } + +/************************************************************************** + Add group data to ruleset cache. +**************************************************************************/ +void handle_ruleset_cache_group(struct packet_ruleset_cache_group *packet) +{ + struct effect_group *pgroup; + int i; + + pgroup = effect_group_new(packet->name); + + for (i = 0; i < packet->num_elements; i++) { + effect_group_add(pgroup, packet->improvements[i], + packet->ranges[i], packet->survives[i]); + } +} + +/************************************************************************** + Add effect data to ruleset cache. +**************************************************************************/ +void handle_ruleset_cache_effect(struct packet_ruleset_cache_effect *packet) +{ + ruleset_cache_add(packet->id, packet->eff, packet->range, packet->survives, + packet->value, packet->req, packet->arg, + packet->group); +} + Index: client/text.c =================================================================== RCS file: /home/freeciv/CVS/freeciv/client/text.c,v retrieving revision 1.9 diff -u -r1.9 text.c --- client/text.c 13 Aug 2004 15:26:50 -0000 1.9 +++ client/text.c 6 Sep 2004 01:11:06 -0000 @@ -711,34 +711,18 @@ const char *get_happiness_buildings(const struct city *pcity) { int faces = 0; - struct government *g = get_gov_pcity(pcity); + struct building_vector sources; INIT; add_line(_("Buildings: ")); - if (city_got_building(pcity, B_TEMPLE)) { - faces++; - add(_("%s. "), get_improvement_name(B_TEMPLE)); - } - if (city_got_building(pcity, B_COURTHOUSE) && g->corruption_level == 0) { - faces++; - add(_("%s. "), get_improvement_name(B_COURTHOUSE)); - } - if (city_got_building(pcity, B_COLOSSEUM)) { - faces++; - add(_("%s. "), get_improvement_name(B_COLOSSEUM)); - } - if (faces > 2) { - /* Hack to get wrapping right. */ - add(_("\n ")); - } - if (city_got_effect(pcity, B_CATHEDRAL)) { + + sources = get_city_bonus_sources(pcity, EFT_MAKE_CONTENT); + building_vector_iterate(&sources, pbldg) { faces++; - add("%s", get_improvement_name(B_CATHEDRAL)); - if (!city_got_building(pcity, B_CATHEDRAL)) { - add(_("(%s)"), get_improvement_name(B_MICHELANGELO)); - } - add(_(". ")); - } + add(_("%s. "), get_improvement_name(*pbldg)); + } building_vector_iterate_end; + building_vector_free(&sources); + if (faces == 0) { add(_("None. ")); } @@ -752,31 +736,31 @@ const char *get_happiness_wonders(const struct city *pcity) { int faces = 0; + struct building_vector sources; INIT; add_line(_("Wonders: ")); - if (city_affected_by_wonder(pcity, B_HANGING)) { - faces++; - add(_("%s. "), get_improvement_name(B_HANGING)); - } - if (city_affected_by_wonder(pcity, B_BACH)) { + sources = get_city_bonus_sources(pcity, EFT_MAKE_HAPPY); + building_vector_iterate(&sources, pbldg) { faces++; - add(_("%s. "), get_improvement_name(B_BACH)); - } - /* hack for eliminating gtk_set_line_wrap() -mck */ - if (faces > 1) { - /* sizeof("Wonders: ") */ - add(_("\n ")); - } - if (city_affected_by_wonder(pcity, B_SHAKESPEARE)) { - faces++; - add(_("%s. "), get_improvement_name(B_SHAKESPEARE)); - } - if (city_affected_by_wonder(pcity, B_CURE)) { - faces++; - add(_("%s. "), get_improvement_name(B_CURE)); - } + add(_("%s. "), get_improvement_name(*pbldg)); + } building_vector_iterate_end; + building_vector_free(&sources); + + sources = get_city_bonus_sources(pcity, EFT_FORCE_CONTENT); + building_vector_iterate(&sources, pbldg) { + faces++; + add(_("%s. "), get_improvement_name(*pbldg)); + } building_vector_iterate_end; + building_vector_free(&sources); + + sources = get_city_bonus_sources(pcity, EFT_NO_UNHAPPY); + building_vector_iterate(&sources, pbldg) { + faces++; + add(_("%s. "), get_improvement_name(*pbldg)); + } building_vector_iterate_end; + building_vector_free(&sources); if (faces == 0) { add(_("None. ")); Index: client/gui-gtk/citydlg.c =================================================================== RCS file: /home/freeciv/CVS/freeciv/client/gui-gtk/citydlg.c,v retrieving revision 1.185 diff -u -r1.185 citydlg.c --- client/gui-gtk/citydlg.c 17 Jul 2004 05:53:20 -0000 1.185 +++ client/gui-gtk/citydlg.c 6 Sep 2004 01:11:06 -0000 @@ -1696,7 +1696,7 @@ my_snprintf(buf[TRADE], sizeof(buf[TRADE]), "%2d (%+2d)", pcity->trade_prod + pcity->corruption, pcity->trade_prod); my_snprintf(buf[GOLD], sizeof(buf[GOLD]), "%2d (%+2d)", - pcity->tax_total, city_gold_surplus(pcity)); + pcity->tax_total, city_gold_surplus(pcity, pcity->tax_total)); my_snprintf(buf[LUXURY], sizeof(buf[LUXURY]), "%2d ", pcity->luxury_total); Index: client/gui-gtk-2.0/citydlg.c =================================================================== RCS file: /home/freeciv/CVS/freeciv/client/gui-gtk-2.0/citydlg.c,v retrieving revision 1.90 diff -u -r1.90 citydlg.c --- client/gui-gtk-2.0/citydlg.c 17 Jul 2004 05:53:20 -0000 1.90 +++ client/gui-gtk-2.0/citydlg.c 6 Sep 2004 01:11:06 -0000 @@ -1318,7 +1318,7 @@ my_snprintf(buf[TRADE], sizeof(buf[TRADE]), "%2d (%+2d)", pcity->trade_prod + pcity->corruption, pcity->trade_prod); my_snprintf(buf[GOLD], sizeof(buf[GOLD]), "%2d (%+2d)", - pcity->tax_total, city_gold_surplus(pcity)); + pcity->tax_total, city_gold_surplus(pcity, pcity->tax_total)); my_snprintf(buf[LUXURY], sizeof(buf[LUXURY]), "%2d ", pcity->luxury_total); Index: client/gui-mui/citydlg.c =================================================================== RCS file: /home/freeciv/CVS/freeciv/client/gui-mui/citydlg.c,v retrieving revision 1.80 diff -u -r1.80 citydlg.c --- client/gui-mui/citydlg.c 20 Jul 2004 16:27:07 -0000 1.80 +++ client/gui-mui/citydlg.c 6 Sep 2004 01:11:07 -0000 @@ -1810,7 +1810,7 @@ settextf(info->food_text, "%2d (%+2d)", pcity->food_prod, pcity->food_surplus); settextf(info->shield_text, "%2d (%+2d)", pcity->shield_prod + pcity->shield_waste, pcity->shield_surplus); settextf(info->trade_text, "%2d (%+2d)", pcity->trade_prod + pcity->corruption, pcity->trade_prod); - settextf(info->gold_text, "%2d (%+2d)", pcity->tax_total, city_gold_surplus(pcity)); + settextf(info->gold_text, "%2d (%+2d)", pcity->tax_total, city_gold_surplus(pcity, pcity->tax_total)); settextf(info->luxury_text, "%2d", pcity->luxury_total); settextf(info->science_text, "%2d", pcity->science_total); Index: client/gui-sdl/citydlg.c =================================================================== RCS file: /home/freeciv/CVS/freeciv/client/gui-sdl/citydlg.c,v retrieving revision 1.44 diff -u -r1.44 citydlg.c --- client/gui-sdl/citydlg.c 23 Jun 2004 23:08:55 -0000 1.44 +++ client/gui-sdl/citydlg.c 6 Sep 2004 01:11:07 -0000 @@ -2965,7 +2965,7 @@ /* ================================================================= */ /* gold label */ my_snprintf(cBuf, sizeof(cBuf), _("Gold: %d (%d) per turn"), - city_gold_surplus(pCity), pCity->tax_total); + city_gold_surplus(pCity, pcity->tax_total), pCity->tax_total); copy_chars_to_string16(pStr, cBuf); pStr->fgcol = *get_game_colorRGB(COLOR_STD_CITY_GOLD); @@ -2980,7 +2980,7 @@ FREESURFACE(pBuf); /* draw coins */ - count = city_gold_surplus(pCity); + count = city_gold_surplus(pCity, pcity->tax_total); if (count) { if (count > 0) { @@ -3012,7 +3012,7 @@ /* upkeep label */ my_snprintf(cBuf, sizeof(cBuf), _("Upkeep : %d"), pCity->tax_total - - city_gold_surplus(pCity)); + city_gold_surplus(pCity, pcity->tax_total)); copy_chars_to_string16(pStr, cBuf); pStr->fgcol = *get_game_colorRGB(COLOR_STD_CITY_UNKEEP); @@ -3027,7 +3027,7 @@ FREESURFACE(pBuf); /* draw upkeep */ - count = city_gold_surplus(pCity); + count = city_gold_surplus(pCity, pcity->tax_total); if (pCity->tax_total - count) { dest.x = pWindow->size.x + 423; Index: client/gui-sdl/cityrep.c =================================================================== RCS file: /home/freeciv/CVS/freeciv/client/gui-sdl/cityrep.c,v retrieving revision 1.14 diff -u -r1.14 cityrep.c --- client/gui-sdl/cityrep.c 25 Feb 2004 20:09:51 -0000 1.14 +++ client/gui-sdl/cityrep.c 6 Sep 2004 01:11:07 -0000 @@ -386,7 +386,7 @@ add_to_gui_list(MAX_ID - pCity->id, pBuf); /* ----------- */ - my_snprintf(cBuf, sizeof(cBuf), "%d", city_gold_surplus(pCity)); + my_snprintf(cBuf, sizeof(cBuf), "%d", city_gold_surplus(pCity, pcity->tax_total)); pStr = create_str16_from_char(cBuf, 10); pStr->style |= SF_CENTER; pStr->fgcol = *get_game_colorRGB(COLOR_STD_CITY_GOLD); @@ -974,7 +974,7 @@ /* gold surplus */ pWidget = pWidget->prev; - my_snprintf(cBuf, sizeof(cBuf), "%d", city_gold_surplus(pCity)); + my_snprintf(cBuf, sizeof(cBuf), "%d", city_gold_surplus(pCity, pcity->tax_total)); copy_chars_to_string16(pWidget->string16, cBuf); /* science income */ Index: client/gui-win32/citydlg.c =================================================================== RCS file: /home/freeciv/CVS/freeciv/client/gui-win32/citydlg.c,v retrieving revision 1.81 diff -u -r1.81 citydlg.c --- client/gui-win32/citydlg.c 18 Jul 2004 04:50:23 -0000 1.81 +++ client/gui-win32/citydlg.c 6 Sep 2004 01:11:08 -0000 @@ -459,7 +459,7 @@ struct city *pcity=pdialog->pcity; my_snprintf(buf, sizeof(buf), _("Gold: %2d (%+2d)\nLuxury: %2d\nScience: %2d"), - pcity->tax_total, city_gold_surplus(pcity), + pcity->tax_total, city_gold_surplus(pcity, pcity->tax_total), pcity->luxury_total, pcity->science_total); SetWindowText(pdialog->output_area[0],buf); Index: client/gui-xaw/citydlg.c =================================================================== RCS file: /home/freeciv/CVS/freeciv/client/gui-xaw/citydlg.c,v retrieving revision 1.120 diff -u -r1.120 citydlg.c --- client/gui-xaw/citydlg.c 27 Jul 2004 17:53:37 -0000 1.120 +++ client/gui-xaw/citydlg.c 6 Sep 2004 01:11:08 -0000 @@ -271,7 +271,7 @@ if (pdialog) { pcity=pdialog->pcity; goldtotal=pcity->tax_total; - goldsurplus=city_gold_surplus(pcity); + goldsurplus=city_gold_surplus(pcity, pcity->tax_total); luxtotal=pcity->luxury_total; scitotal=pcity->science_total; } Index: common/city.c =================================================================== RCS file: /home/freeciv/CVS/freeciv/common/city.c,v retrieving revision 1.241 diff -u -r1.241 city.c --- common/city.c 4 Sep 2004 19:28:19 -0000 1.241 +++ common/city.c 6 Sep 2004 01:11:09 -0000 @@ -263,54 +263,6 @@ } /************************************************************************** - Returns TRUE if a building is replaced. To be replaced, all its effects - must be redundant. -**************************************************************************/ -bool building_replaced(const struct city *pcity, Impr_Type_id id) -{ - if(is_wonder(id)) return FALSE; - switch (id) { - case B_BARRACKS: - case B_BARRACKS2: - case B_BARRACKS3: - if (city_affected_by_wonder(pcity, B_SUNTZU)) - return TRUE; - break; - case B_GRANARY: - if (improvement_variant(B_PYRAMIDS)==0 - && city_affected_by_wonder(pcity, B_PYRAMIDS)) - return TRUE; - break; - case B_CATHEDRAL: - if (improvement_variant(B_MICHELANGELO)==0 - && city_affected_by_wonder(pcity, B_MICHELANGELO)) - return TRUE; - break; - case B_CITY: - if (city_affected_by_wonder(pcity, B_WALL)) - return TRUE; - break; - case B_HYDRO: - case B_POWER: - case B_NUCLEAR: - if (city_affected_by_wonder(pcity, B_HOOVER)) - return TRUE; - break; - case B_POLICE: - if (city_affected_by_wonder(pcity, B_WOMENS)) - return TRUE; - break; - case B_RESEARCH: - if (city_affected_by_wonder(pcity, B_SETI)) - return TRUE; - break; - default: - break; - } - return FALSE; -} - -/************************************************************************** Return the extended name of the building. **************************************************************************/ const char *get_impr_name_ex(const struct city *pcity, Impr_Type_id id) @@ -399,13 +351,12 @@ } /************************************************************************** - Will this city ever be able to build this improvement? - Doesn't check for building prereqs + Return whether given city can build given improvement, ignoring whether + improvement is obsolete. **************************************************************************/ -bool can_eventually_build_improvement(const struct city *pcity, Impr_Type_id id) +bool can_build_improvement_direct(const struct city *pcity, Impr_Type_id id) { - /* also does an improvement_exists() */ - if (!could_player_eventually_build_improvement(city_owner(pcity),id)) { + if (!can_player_build_improvement_direct(city_owner(pcity), id)) { return FALSE; } @@ -413,7 +364,7 @@ return FALSE; } - if (!city_has_terr_spec_gate(pcity,id)) { + if (!city_has_terr_spec_gate(pcity, id)) { return FALSE; } @@ -421,29 +372,34 @@ } /************************************************************************** - Can this improvement get built in this city by the player who owns it? + Return whether given city can build given building; returns FALSE if + the building is obsolete. **************************************************************************/ bool can_build_improvement(const struct city *pcity, Impr_Type_id id) -{ - struct player *p = city_owner(pcity); - struct impr_type *impr = get_improvement_type(id); - - if (!improvement_exists(id)) { +{ + if (!can_build_improvement_direct(pcity, id)) { return FALSE; } - if (!player_knows_improvement_tech(p, id)) { + if (improvement_obsolete(city_owner(pcity), id)) { return FALSE; } + return TRUE; +} - if (!can_eventually_build_improvement(pcity, id)) { +/************************************************************************** + Return whether player can eventually build given improvement in the city; + returns 0 if improvement can never possibly be built in this city. +**************************************************************************/ +bool can_eventually_build_improvement(const struct city *pcity, + Impr_Type_id id) +{ + /* Can the _player_ ever build this improvement? */ + if (!can_player_eventually_build_improvement(city_owner(pcity), id)) { return FALSE; } - /* The building pre req */ - if (impr->bldg_req != B_LAST) { - if (!city_got_building(pcity, impr->bldg_req)) { - return FALSE; - } + if (!city_has_terr_spec_gate(pcity, id)) { + return FALSE; } return TRUE; @@ -552,11 +508,11 @@ return 0; if (is_wonder(i)) return 0; - if (improvement_types[i].upkeep == 1 && - city_affected_by_wonder(pcity, B_ASMITHS)) + if (improvement_types[i].upkeep + <= get_city_bonus(pcity, EFT_UPKEEP_FREE)) { return 0; - if (government_has_flag(get_gov_pcity(pcity), G_CONVERT_TITHES_TO_MONEY) - && (i == B_TEMPLE || i == B_COLOSSEUM || i == B_CATHEDRAL)) { + } + if (get_building_bonus(pcity, i, EFT_NO_UPKEEP) > 0) { return 0; } @@ -574,6 +530,7 @@ { enum tile_special_type spec_t = map_get_special(map_x, map_y); Terrain_type_id tile_t = map_get_terrain(map_x, map_y); + struct tile *ptile = map_get_tile(map_x, map_y); int s; if (contains_special(spec_t, S_SPECIAL_1)) { @@ -597,17 +554,16 @@ int before_penalty = (is_celebrating ? g->celeb_shields_before_penalty : g->shields_before_penalty); - if (city_affected_by_wonder(pcity, B_RICHARDS)) { - s++; - } - if (is_ocean(tile_t) && city_got_building(pcity, B_OFFSHORE)) { - s++; - } + s += get_city_tile_bonus(pcity, ptile, EFT_PROD_ADD_TILE); - /* government shield bonus & penalty */ + /* Government & effect shield bonus/penalty. */ if (s > 0) { s += (is_celebrating ? g->celeb_shield_bonus : g->shield_bonus); + s += get_city_tile_bonus(pcity, ptile, EFT_PROD_INC_TILE); } + + s += (s * get_city_tile_bonus(pcity, ptile, EFT_PROD_PER_TILE)) / 100; + if (before_penalty > 0 && s > before_penalty) { s--; } @@ -679,6 +635,7 @@ { enum tile_special_type spec_t = map_get_special(map_x, map_y); Terrain_type_id tile_t = map_get_terrain(map_x, map_y); + struct tile *ptile = map_get_tile(map_x, map_y); int t; if (contains_special(spec_t, S_SPECIAL_1)) { @@ -692,50 +649,46 @@ if (contains_special(spec_t, S_RIVER) && !is_ocean(tile_t)) { t += terrain_control.river_trade_incr; } + if (contains_special(spec_t, S_ROAD)) { t += get_tile_type(tile_t)->road_trade_incr; } - if (t > 0) { - if (contains_special(spec_t, S_RAILROAD)) { - t += (t * terrain_control.rail_trade_bonus) / 100; - } - - /* Civ1 specifically documents that Railroad trade increase is before - * Democracy/Republic [government in general now -- SKi] bonus -AJS */ - if (pcity) { - struct government *g = get_gov_pcity(pcity); - int before_penalty = (is_celebrating ? g->celeb_trade_before_penalty - : g->trade_before_penalty); - if (t > 0) { - t += (is_celebrating ? g->celeb_trade_bonus : g->trade_bonus); - } + if (contains_special(spec_t, S_RAILROAD)) { + t += (t * terrain_control.rail_trade_bonus) / 100; + } - if (city_affected_by_wonder(pcity, B_COLLOSSUS)) { - t++; - } + /* Civ1 specifically documents that Railroad trade increase is before + * Democracy/Republic [government in general now -- SKi] bonus -AJS */ + if (pcity) { + struct government *g = get_gov_pcity(pcity); + int before_penalty = (is_celebrating ? g->celeb_trade_before_penalty + : g->trade_before_penalty); - if (contains_special(spec_t, S_ROAD) - && city_got_building(pcity, B_SUPERHIGHWAYS)) { - t += (t * terrain_control.road_superhighway_trade_bonus) / 100; - } + t += get_city_tile_bonus(pcity, ptile, EFT_TRADE_ADD_TILE); - /* government trade penalty -- SKi */ - if (before_penalty > 0 && t > before_penalty) { - t--; - } + if (t > 0) { + t += (is_celebrating ? g->celeb_trade_bonus : g->trade_bonus); + t += get_city_bonus(pcity, EFT_TRADE_INC_TILE); } - if (contains_special(spec_t, S_POLLUTION)) { - /* The trade here is dirty */ - t -= (t * terrain_control.pollution_trade_penalty) / 100; - } + t += (t * get_city_tile_bonus(pcity, ptile, EFT_TRADE_PER_TILE)) / 100; - if (contains_special(spec_t, S_FALLOUT)) { - t -= (t * terrain_control.fallout_trade_penalty) / 100; + /* government trade penalty -- SKi */ + if (before_penalty > 0 && t > before_penalty) { + t--; } } + if (contains_special(spec_t, S_POLLUTION)) { + /* The trade here is dirty */ + t -= (t * terrain_control.pollution_trade_penalty) / 100; + } + + if (contains_special(spec_t, S_FALLOUT)) { + t -= (t * terrain_control.fallout_trade_penalty) / 100; + } + if (pcity && is_city_center(city_x, city_y)) { t = MAX(t, game.rgame.min_city_center_trade); } @@ -793,36 +746,38 @@ const enum tile_special_type spec_t = map_get_special(map_x, map_y); const Terrain_type_id tile_t = map_get_terrain(map_x, map_y); struct tile_type *type = get_tile_type(tile_t); + struct tile tile; int f; const bool auto_water = (pcity && is_city_center(city_x, city_y) && tile_t == type->irrigation_result && terrain_control.may_irrigate); - if (contains_special(spec_t, S_SPECIAL_1)) { - f = get_tile_type(tile_t)->food_special_1; - } else if (contains_special(spec_t, S_SPECIAL_2)) { - f = get_tile_type(tile_t)->food_special_2; - } else { - f = get_tile_type(tile_t)->food; - } + /* create dummy tile which has the city center bonuses. */ + tile.terrain = tile_t; + tile.special = spec_t; - if (contains_special(spec_t, S_IRRIGATION) || auto_water) { + if (auto_water) { /* The center tile is auto-irrigated. */ - f += type->irrigation_food_incr; + tile.special |= S_IRRIGATION; - /* Farmland only affects cities with supermarkets. The center tile is - * auto-irrigated. */ - if (pcity - && (contains_special(spec_t, S_FARMLAND) - || (auto_water - && player_knows_techs_with_flag(city_owner(pcity), - TF_FARMLAND))) - && city_got_building(pcity, B_SUPERMARKET)) { - f += (f * terrain_control.farmland_supermarket_food_bonus) / 100; + if (player_knows_techs_with_flag(city_owner(pcity), TF_FARMLAND)) { + tile.special |= S_FARMLAND; } } - if (contains_special(spec_t, S_RAILROAD)) { + if (contains_special(tile.special, S_SPECIAL_1)) { + f = type->food_special_1; + } else if (contains_special(tile.special, S_SPECIAL_2)) { + f = type->food_special_2; + } else { + f = type->food; + } + + if (contains_special(tile.special, S_IRRIGATION)) { + f += type->irrigation_food_incr; + } + + if (contains_special(tile.special, S_RAILROAD)) { f += (f * terrain_control.rail_food_bonus) / 100; } @@ -831,23 +786,25 @@ int before_penalty = (is_celebrating ? g->celeb_food_before_penalty : g->food_before_penalty); - if (is_ocean(tile_t) && city_got_building(pcity, B_HARBOUR)) { - f++; - } + f += get_city_tile_bonus(pcity, &tile, EFT_FOOD_ADD_TILE); if (f > 0) { f += (is_celebrating ? g->celeb_food_bonus : g->food_bonus); + f += get_city_bonus(pcity, EFT_FOOD_INC_TILE); } + + f += (f * get_city_tile_bonus(pcity, &tile, EFT_FOOD_PER_TILE) / 100); + if (before_penalty > 0 && f > before_penalty) { f--; } } - if (contains_special(spec_t, S_POLLUTION)) { + if (contains_special(tile.special, S_POLLUTION)) { /* The food here is yucky */ f -= (f * terrain_control.pollution_food_penalty) / 100; } - if (contains_special(spec_t, S_FALLOUT)) { + if (contains_special(tile.special, S_FALLOUT)) { f -= (f * terrain_control.fallout_food_penalty) / 100; } @@ -1094,7 +1051,7 @@ Calculate amount of gold remaining in city after paying for buildings and units. *************************************************************************/ -int city_gold_surplus(const struct city *pcity) +int city_gold_surplus(const struct city *pcity, int tax_total) { int cost = 0; @@ -1106,17 +1063,7 @@ cost += punit->upkeep_gold; } unit_list_iterate_end; - return pcity->tax_total-cost; -} - -/************************************************************************** - Whether a city has an improvement, or the same effect via a wonder. - (The Impr_Type_id should be an improvement, not a wonder.) - Note also: city_got_citywalls(), and server/citytools:city_got_barracks() -**************************************************************************/ -bool city_got_effect(const struct city *pcity, Impr_Type_id id) -{ - return city_got_building(pcity, id) || building_replaced(pcity, id); + return tax_total - cost; } /************************************************************************** @@ -1125,7 +1072,7 @@ **************************************************************************/ bool is_capital(const struct city *pcity) { - return city_got_building(pcity, B_PALACE); + return (get_city_bonus(pcity, EFT_CAPITAL_CITY) != 0); } /************************************************************************** @@ -1133,80 +1080,7 @@ **************************************************************************/ bool city_got_citywalls(const struct city *pcity) { - if (city_got_building(pcity, B_CITY)) - return TRUE; - return (city_affected_by_wonder(pcity, B_WALL)); -} - -/************************************************************************** - Return TRUE if the wonder's effect applies to this city. This is only - used for some wonder checks; others are done manually. -**************************************************************************/ -bool city_affected_by_wonder(const struct city *pcity, Impr_Type_id id) -{ - struct city *tmp; - if (!improvement_exists(id)) - return FALSE; - if (!is_wonder(id) || wonder_obsolete(id)) - return FALSE; - if (city_got_building(pcity, id)) - return TRUE; - - /* For Manhatten it can be owned by anyone, and it doesn't matter - * whether it is destroyed or not. - * - * (The same goes for Apollo, with respect to building spaceship parts, - * but not for getting the map effect. This function only returns true - * for Apollo for the owner of a non-destroyed Apollo; for building - * spaceship parts just check (game.global_wonders[id] != 0). - * (Actually, this function is not currently used for either Manhatten - * or Apollo.)) - * - * Otherwise the player who owns the city needs to have it to - * get the effect. - */ - if (id==B_MANHATTEN) - return (game.global_wonders[id] != 0); - - tmp = player_find_city_by_id(city_owner(pcity), game.global_wonders[id]); - if (!tmp) - return FALSE; - switch (id) { - case B_ASMITHS: - case B_APOLLO: - case B_CURE: - case B_GREAT: - case B_WALL: - case B_HANGING: - case B_ORACLE: - case B_UNITED: - case B_WOMENS: - case B_DARWIN: - case B_LIGHTHOUSE: - case B_MAGELLAN: - case B_MICHELANGELO: - case B_SETI: - case B_PYRAMIDS: - case B_LIBERTY: - case B_SUNTZU: - return TRUE; - case B_ISAAC: - case B_COPERNICUS: - case B_SHAKESPEARE: - case B_COLLOSSUS: - case B_RICHARDS: - return FALSE; - case B_HOOVER: - case B_BACH: - if (improvement_variant(id)==1) { - return (map_get_continent(tmp->x, tmp->y) == - map_get_continent(pcity->x, pcity->y)); - } else { - return TRUE; - } - default: - return FALSE; - } + return (get_city_bonus(pcity, EFT_LAND_DEFEND) > 0); } /************************************************************************** @@ -1547,10 +1421,14 @@ ****************************************************************************/ bool city_can_grow_to(const struct city *pcity, int pop_size) { - return (pop_size <= game.aqueduct_size - || (pop_size <= game.sewer_size - && city_got_building(pcity, B_AQUEDUCT)) - || city_got_building(pcity, B_SEWER)); + if (get_city_bonus(pcity, EFT_SIZE_UNLIMIT) > 0) { + return TRUE; + } else { + int max_size; + + max_size = game.aqueduct_size + get_city_bonus(pcity, EFT_SIZE_ADJ); + return (pop_size <= max_size); + } } /************************************************************************** @@ -1693,23 +1571,7 @@ **************************************************************************/ int get_city_shield_bonus(const struct city *pcity) { - int shield_bonus = 100; - - if (city_got_building(pcity, B_FACTORY)) { - shield_bonus += 50; - if (city_got_building(pcity, B_MFG)) { - shield_bonus += 50; - } - - if (city_affected_by_wonder(pcity, B_HOOVER) || - city_got_building(pcity, B_POWER) || - city_got_building(pcity, B_HYDRO) || - city_got_building(pcity, B_NUCLEAR)) { - shield_bonus = 100 + (3 * (shield_bonus - 100)) / 2; - } - } - - return shield_bonus; + return (100 + get_city_bonus(pcity, EFT_PROD_BONUS)); } /************************************************************************** @@ -1717,19 +1579,7 @@ **************************************************************************/ int get_city_tax_bonus(const struct city *pcity) { - int tax_bonus = 100; - - if (city_got_building(pcity, B_MARKETPLACE)) { - tax_bonus += 50; - if (city_got_building(pcity, B_BANK)) { - tax_bonus += 50; - if (city_got_building(pcity, B_STOCK)) { - tax_bonus += 50; - } - } - } - - return tax_bonus; + return (100 + get_city_bonus(pcity, EFT_TAX_BONUS)); } /************************************************************************** @@ -1737,8 +1587,7 @@ **************************************************************************/ int get_city_luxury_bonus(const struct city *pcity) { - /* Currently the luxury bonus is equivalent to the tax bonus. */ - return get_city_tax_bonus(pcity); + return (100 + get_city_bonus(pcity, EFT_LUXURY_BONUS)); } /************************************************************************** @@ -1754,16 +1603,8 @@ return 0; } - if (city_got_building(pcity, B_TEMPLE)) - tithes_bonus += get_temple_power(pcity); - if (city_got_building(pcity, B_COLOSSEUM)) - tithes_bonus += get_colosseum_power(pcity); - if (city_got_effect(pcity, B_CATHEDRAL)) - tithes_bonus += get_cathedral_power(pcity); - if (city_affected_by_wonder(pcity, B_BACH)) - tithes_bonus += 2; - if (city_affected_by_wonder(pcity, B_CURE)) - tithes_bonus += 1; + tithes_bonus += get_city_bonus(pcity, EFT_MAKE_CONTENT); + tithes_bonus += get_city_bonus(pcity, EFT_FORCE_CONTENT); return tithes_bonus; } @@ -1773,23 +1614,10 @@ **************************************************************************/ int get_city_science_bonus(const struct city *pcity) { - int science_bonus = 100; + int science_bonus; + + science_bonus = 100 + get_city_bonus(pcity, EFT_SCIENCE_BONUS); - if (city_got_building(pcity, B_LIBRARY)) { - science_bonus += 50; - if (city_got_building(pcity, B_UNIVERSITY)) { - science_bonus += 50; - } - if (city_got_effect(pcity, B_RESEARCH)) { - science_bonus += 50; - } - } - if (city_affected_by_wonder(pcity, B_COPERNICUS)) { - science_bonus += 50; - } - if (city_affected_by_wonder(pcity, B_ISAAC)) { - science_bonus += 100; - } if (government_has_flag(get_gov_pcity(pcity), G_REDUCED_RESEARCH)) { science_bonus /= 2; } @@ -1861,12 +1689,14 @@ /************************************************************************** Modify the incomes according to various buildings. + + Note this does not set trade. That's been done already. **************************************************************************/ static void add_buildings_effect(struct city *pcity) { /* this is the place to set them */ - pcity->luxury_bonus = get_city_luxury_bonus(pcity); pcity->tax_bonus = get_city_tax_bonus(pcity); + pcity->luxury_bonus = get_city_luxury_bonus(pcity); pcity->science_bonus = get_city_science_bonus(pcity); pcity->shield_bonus = get_city_shield_bonus(pcity); @@ -1999,21 +1829,11 @@ **************************************************************************/ static inline void citizen_content_buildings(struct city *pcity) { - struct government *g = get_gov_pcity(pcity); int faces = 0; happy_copy(pcity, 1); - if (city_got_building(pcity, B_TEMPLE)) { - faces += get_temple_power(pcity); - } - if (city_got_building(pcity, B_COURTHOUSE) && g->corruption_level == 0) { - faces++; - } + faces += get_city_bonus(pcity, EFT_MAKE_CONTENT); - if (city_got_building(pcity, B_COLOSSEUM)) - faces += get_colosseum_power(pcity); - if (city_got_effect(pcity, B_CATHEDRAL)) - faces += get_cathedral_power(pcity); /* make people content (but not happy): get rid of angry first, then make unhappy content. */ while (faces > 0 && pcity->ppl_angry[2] > 0) { @@ -2033,14 +1853,13 @@ **************************************************************************/ static inline void citizen_happy_wonders(struct city *pcity) { - int bonus = 0; + int bonus = 0, mod; happy_copy(pcity, 3); - if (city_affected_by_wonder(pcity, B_HANGING)) { - bonus += 1; - if (city_got_building(pcity, B_HANGING)) - bonus += 2; + if ((mod = get_city_bonus(pcity, EFT_MAKE_HAPPY)) > 0) { + bonus += mod; + while (bonus > 0 && pcity->ppl_content[4] > 0) { pcity->ppl_content[4]--; pcity->ppl_happy[4]++; @@ -2049,10 +1868,9 @@ will let it make unhappy content */ } } - if (city_affected_by_wonder(pcity, B_BACH)) - bonus += 2; - if (city_affected_by_wonder(pcity, B_CURE)) - bonus += 1; + + bonus += get_city_bonus(pcity, EFT_FORCE_CONTENT); + /* get rid of angry first, then make unhappy content */ while (bonus > 0 && pcity->ppl_angry[4] > 0) { pcity->ppl_angry[4]--; @@ -2065,7 +1883,7 @@ bonus--; } - if (city_affected_by_wonder(pcity, B_SHAKESPEARE)) { + if (get_city_bonus(pcity, EFT_NO_UNHAPPY) > 0) { pcity->ppl_content[4] += pcity->ppl_unhappy[4] + pcity->ppl_angry[4]; pcity->ppl_unhappy[4] = 0; pcity->ppl_angry[4] = 0; @@ -2092,28 +1910,25 @@ } /************************************************************************** - Calculate pollution. + Calculate pollution for the city. The shield_total must be passed in + (most callers will want to pass pcity->shield_prod). **************************************************************************/ -static inline void set_pollution(struct city *pcity) +int city_pollution(struct city *pcity, int shield_total) { struct player *pplayer = city_owner(pcity); + int mod, pollution = shield_total; - pcity->pollution = pcity->shield_prod; - if (city_got_building(pcity, B_RECYCLING)) { - pcity->pollution /= 3; - } else if (city_got_building(pcity, B_HYDRO) || - city_affected_by_wonder(pcity, B_HOOVER) || - city_got_building(pcity, B_NUCLEAR)) { - pcity->pollution /= 2; - } - - if (!city_got_building(pcity, B_MASS)) { - pcity->pollution += (pcity->size * - num_known_tech_with_flag - (pplayer, TF_POPULATION_POLLUTION_INC)) / 4; - } + mod = get_city_bonus(pcity, EFT_POLLU_PROD_PCT); + if (mod > 0) { + pollution /= mod; + } + mod = (pcity->size * + num_known_tech_with_flag(pplayer, TF_POPULATION_POLLUTION_INC)) / 4; + mod -= mod * get_city_bonus(pcity, EFT_POLLU_POP_PCT) / 100; + pollution += MAX(mod, 0); + pollution = MAX(0, pollution - 20); - pcity->pollution = MAX(0, pcity->pollution - 20); + return pollution; } /************************************************************************** @@ -2174,18 +1989,13 @@ { struct government *g = get_gov_pcity(pcity); - bool have_police = city_got_effect(pcity, B_POLICE); - int variant = improvement_variant(B_WOMENS); - int free_happy = citygov_free_happy(pcity, g); int free_shield = citygov_free_shield(pcity, g); int free_food = citygov_free_food(pcity, g); int free_gold = citygov_free_gold(pcity, g); - if (variant == 0 && have_police) { - /* ?? This does the right thing for normal Republic and Democ -- dwp */ - free_happy += g->unit_happy_cost_factor; - } + /* ?? This does the right thing for normal Republic and Democ -- dwp */ + free_happy += get_city_bonus(pcity, EFT_MAKE_CONTENT_MIL); happy_copy(pcity, 2); @@ -2257,7 +2067,8 @@ happy_cost = 0; } } - if (happy_cost > 0 && variant == 1 && have_police) { + if (happy_cost > 0 + && get_city_bonus(pcity, EFT_MAKE_CONTENT_MIL_PER) > 0) { happy_cost--; } @@ -2317,7 +2128,7 @@ citizen_happy_size(pcity); set_tax_income(pcity); /* calc base luxury, tax & bulbs */ add_buildings_effect(pcity); /* marketplace, library wonders.. */ - set_pollution(pcity); + pcity->pollution = city_pollution(pcity, pcity->shield_prod); citizen_happy_luxury(pcity); /* with our new found luxuries */ citizen_content_buildings(pcity); /* temple cathedral colosseum */ city_support(pcity, send_unit_info); /* manage settlers, and units */ @@ -2402,10 +2213,7 @@ /* Now calculate the final corruption. Ordered to reduce integer * roundoff errors. */ val = trade * MAX(dist, 1) * g->corruption_level; - if (city_got_building(pcity, B_COURTHOUSE) || - city_got_building(pcity, B_PALACE)) { - val /= 2; - } + val -= (val * get_city_bonus(pcity, EFT_CORRUPT_PCT)) / 100; val /= 100 * 100; /* Level is a % multiplied by 100 */ val = CLIP(trade_penalty, val, trade); return val; @@ -2441,10 +2249,8 @@ val = shields * MAX(dist, 1) * g->waste_level; val /= 100 * 100; /* Level is a % multiplied by 100 */ - if (city_got_building(pcity, B_COURTHOUSE) - || city_got_building(pcity, B_PALACE)) { - val /= 2; - } + val -= (val * get_city_bonus(pcity, EFT_WASTE_PCT)) / 100; + val = CLIP(shield_penalty, val, shields); return val; } @@ -2464,49 +2270,6 @@ } /************************************************************************** - Return the power (pacifying effect) of temples in the city. -**************************************************************************/ -int get_temple_power(const struct city *pcity) -{ - struct player *p = city_owner(pcity); - int power = 1; - if (get_invention(p, game.rtech.temple_plus) == TECH_KNOWN) - power = 2; - if (city_affected_by_wonder(pcity, B_ORACLE)) - power *= 2; - return power; -} - -/************************************************************************** - Return the power (pacifying effect) of cathedrals in the city. -**************************************************************************/ -int get_cathedral_power(const struct city *pcity) -{ - struct player *p = city_owner(pcity); - int power = 3; - if (get_invention(p, game.rtech.cathedral_minus /*A_COMMUNISM */ ) == - TECH_KNOWN) power--; - if (get_invention(p, game.rtech.cathedral_plus /*A_THEOLOGY */ ) == - TECH_KNOWN) power++; - if (improvement_variant(B_MICHELANGELO) == 1 - && city_affected_by_wonder(pcity, B_MICHELANGELO)) - power *= 2; - return power; -} - -/************************************************************************** - Return the power (pacifying effect) of colosseums in the city. -**************************************************************************/ -int get_colosseum_power(const struct city *pcity) -{ - struct player *p = city_owner(pcity); - int power = 3; - if (get_invention(p, game.rtech.colosseum_plus /*A_ELECTRICITY */ ) == - TECH_KNOWN) power++; - return power; -} - -/************************************************************************** Adds an improvement (and its effects) to a city, and sets the global arrays if the improvement has effects and/or an equiv_range that extend outside of the city. @@ -2644,7 +2407,7 @@ pcity->currently_building = u; } else { pcity->is_building_unit = FALSE; - pcity->currently_building = B_CAPITAL; + pcity->currently_building = game.default_building; } } pcity->turn_founded = game.turn; @@ -2673,6 +2436,7 @@ pcity->ai.invasion = 0; pcity->ai.bcost = 0; pcity->ai.attack = 0; + pcity->ai.next_recalc = 0; pcity->corruption = 0; pcity->shield_waste = 0; Index: common/city.h =================================================================== RCS file: /home/freeciv/CVS/freeciv/common/city.h,v retrieving revision 1.159 diff -u -r1.159 city.h --- common/city.h 4 Sep 2004 19:28:19 -0000 1.159 +++ common/city.h 6 Sep 2004 01:11:09 -0000 @@ -206,6 +206,9 @@ int invasion; /* who's coming to kill us, for attack co-ordination */ int attack, bcost; /* This is also for invasion - total power and value of * all units coming to kill us. */ + + int worth; /* Cache city worth here, sum of all weighted incomes */ + int next_recalc; /* Only recalc every Nth turn */ }; struct city { @@ -254,7 +257,7 @@ int currently_building; Impr_Status improvements[B_LAST]; - + struct worklist worklist; enum city_tile_type city_map[CITY_MAP_SIZE][CITY_MAP_SIZE]; @@ -346,7 +349,7 @@ struct player *city_owner(const struct city *pcity); int city_population(const struct city *pcity); -int city_gold_surplus(const struct city *pcity); +int city_gold_surplus(const struct city *pcity, int tax_total); int city_buy_cost(const struct city *pcity); bool city_happy(const struct city *pcity); /* generally use celebrating instead */ bool city_unhappy(const struct city *pcity); /* anarchy??? */ @@ -358,15 +361,15 @@ bool city_has_terr_spec_gate(const struct city *pcity, Impr_Type_id id); int improvement_upkeep(const struct city *pcity, Impr_Type_id i); +bool can_build_improvement_direct(const struct city *pcity, Impr_Type_id id); bool can_build_improvement(const struct city *pcity, Impr_Type_id id); -bool can_eventually_build_improvement(const struct city *pcity, Impr_Type_id id); +bool can_eventually_build_improvement(const struct city *pcity, + Impr_Type_id id); bool can_build_unit(const struct city *pcity, Unit_Type_id id); bool can_build_unit_direct(const struct city *pcity, Unit_Type_id id); bool can_eventually_build_unit(const struct city *pcity, Unit_Type_id id); bool city_can_use_specialist(const struct city *pcity, enum specialist_type type); bool city_got_building(const struct city *pcity, Impr_Type_id id); -bool city_affected_by_wonder(const struct city *pcity, Impr_Type_id id); -bool city_got_effect(const struct city *pcity, Impr_Type_id id); bool is_capital(const struct city *pcity); bool city_got_citywalls(const struct city *pcity); bool building_replaced(const struct city *pcity, Impr_Type_id id); @@ -483,9 +486,6 @@ int city_corruption(const struct city *pcity, int trade); int city_waste(const struct city *pcity, int shields); int city_specialists(const struct city *pcity); /* elv+tax+scie */ -int get_temple_power(const struct city *pcity); -int get_cathedral_power(const struct city *pcity); -int get_colosseum_power(const struct city *pcity); int get_city_tax_bonus(const struct city *pcity); int get_city_luxury_bonus(const struct city *pcity); int get_city_shield_bonus(const struct city *pcity); @@ -507,6 +507,7 @@ void get_tax_income(struct player *pplayer, int trade, int *sci, int *lux, int *tax); int get_city_tithes_bonus(const struct city *pcity); +int city_pollution(struct city *pcity, int shield_total); /* * Iterates over all improvements which are built in the given city. Index: common/combat.c =================================================================== RCS file: /home/freeciv/CVS/freeciv/common/combat.c,v retrieving revision 1.45 diff -u -r1.45 combat.c --- common/combat.c 25 Aug 2004 18:24:19 -0000 1.45 +++ common/combat.c 6 Sep 2004 01:11:09 -0000 @@ -301,9 +301,9 @@ **************************************************************************/ bool unit_really_ignores_citywalls(struct unit *punit) { - return unit_ignores_citywalls(punit) - || is_air_unit(punit) - || (is_sailing_unit(punit) && !(improvement_variant(B_CITY)==1)); + return (unit_ignores_citywalls(punit) + || is_air_unit(punit) + || is_sailing_unit(punit)); } /************************************************************************** @@ -322,7 +322,9 @@ square_iterate(x, y, 2, x1, y1) { struct city *pcity = map_get_city(x1, y1); if (pcity && (!pplayers_allied(city_owner(pcity), owner)) - && city_got_building(pcity, B_SDI)) return pcity; + && get_city_bonus(pcity, EFT_NUKE_PROOF) > 0) { + return pcity; + } } square_iterate_end; return NULL; @@ -406,6 +408,7 @@ int defensepower, bool fortified) { struct city *pcity = map_get_city(x, y); + int mod; if (unit_type_exists(att_type)) { if (unit_type_flag(def_type, F_PIKEMEN) @@ -419,24 +422,23 @@ } if (is_air_unittype(att_type) && pcity) { - if (city_got_building(pcity, B_SAM)) { - defensepower *= 2; + if ((mod = get_city_bonus(pcity, EFT_AIR_DEFEND)) > 0) { + defensepower = defensepower * (100 + mod) / 100; } - if (city_got_building(pcity, B_SDI) + if ((mod = get_city_bonus(pcity, EFT_MISSILE_DEFEND)) > 0 && unit_type_flag(att_type, F_MISSILE)) { - defensepower *= 2; + defensepower = defensepower * (100 + mod) / 100; } } else if (is_water_unit(att_type) && pcity) { - if (city_got_building(pcity, B_COASTAL)) { - defensepower *= 2; + if ((mod = get_city_bonus(pcity, EFT_SEA_DEFEND)) > 0) { + defensepower = defensepower * (100 + mod) / 100; } } 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; + && (is_ground_unittype(att_type) || is_heli_unittype(att_type)) + && pcity + && (mod = get_city_bonus(pcity, EFT_LAND_DEFEND)) > 0) { + defensepower = defensepower * (100 + mod) / 100; } if (unit_type_flag(att_type, F_FIGHTER) && is_heli_unittype(def_type)) { Index: common/dataio.c =================================================================== RCS file: /home/freeciv/CVS/freeciv/common/dataio.c,v retrieving revision 1.12 diff -u -r1.12 dataio.c --- common/dataio.c 2 Sep 2004 22:01:51 -0000 1.12 +++ common/dataio.c 6 Sep 2004 01:11:09 -0000 @@ -711,33 +711,3 @@ dio_put_uint16(dout, pds->contact_turns_left); dio_put_uint8(dout, pds->has_reason_to_cancel); } - -void dio_get_effect(struct data_in *din, struct impr_effect *peffect) -{ - dio_get_uint8(din, (int *) &(peffect->type)); - dio_get_uint8(din, (int *) &(peffect->range)); - dio_get_sint16(din, &peffect->amount); - dio_get_uint8(din, &peffect->survives); - dio_get_uint8(din, (int *) &peffect->cond_bldg); - dio_get_uint8(din, &peffect->cond_gov); - dio_get_uint8(din, &peffect->cond_adv); - dio_get_uint8(din, (int *) &(peffect->cond_eff)); - dio_get_uint8(din, (int *) &(peffect->aff_unit)); - dio_get_sint16(din, (int *) &(peffect->aff_terr)); - dio_get_uint16(din, (int *) &(peffect->aff_spec)); -} - -void dio_put_effect(struct data_out *dout, const struct impr_effect *peffect) -{ - dio_put_uint8(dout, peffect->type); - dio_put_uint8(dout, peffect->range); - dio_put_sint16(dout, peffect->amount); - dio_put_uint8(dout, peffect->survives); - dio_put_uint8(dout, peffect->cond_bldg); - dio_put_uint8(dout, peffect->cond_gov); - dio_put_uint8(dout, peffect->cond_adv); - dio_put_uint8(dout, peffect->cond_eff); - dio_put_uint8(dout, peffect->aff_unit); - dio_put_sint16(dout, peffect->aff_terr); - dio_put_uint16(dout, peffect->aff_spec); -} Index: common/dataio.h =================================================================== RCS file: /home/freeciv/CVS/freeciv/common/dataio.h,v retrieving revision 1.6 diff -u -r1.6 dataio.h --- common/dataio.h 2 Jun 2004 19:47:41 -0000 1.6 +++ common/dataio.h 6 Sep 2004 01:11:09 -0000 @@ -17,7 +17,6 @@ struct worklist; struct player_diplstate; -struct impr_effect; struct data_in { const void *src; @@ -71,7 +70,6 @@ void dio_get_tech_list(struct data_in *din, int *dest); void dio_get_worklist(struct data_in *din, struct worklist *pwl); void dio_get_diplstate(struct data_in *din, struct player_diplstate *pds); -void dio_get_effect(struct data_in *din, struct impr_effect *peffect); void dio_get_uint8_vec8(struct data_in *din, int **values, int stop_value); void dio_get_uint16_vec8(struct data_in *din, int **values, int stop_value); @@ -100,8 +98,6 @@ void dio_put_worklist(struct data_out *dout, const struct worklist *pwl); void dio_put_diplstate(struct data_out *dout, const struct player_diplstate *pds); -void dio_put_effect(struct data_out *dout, - const struct impr_effect *peffect); void dio_put_uint8_vec8(struct data_out *dout, int *values, int stop_value); void dio_put_uint16_vec8(struct data_out *dout, int *values, int stop_value); Index: common/effects.c =================================================================== RCS file: /home/freeciv/CVS/freeciv/common/effects.c,v retrieving revision 1.8 diff -u -r1.8 effects.c --- common/effects.c 4 Sep 2004 20:19:51 -0000 1.8 +++ common/effects.c 6 Sep 2004 01:11:09 -0000 @@ -1,5 +1,5 @@ /********************************************************************** - Freeciv - Copyright (C) 1996 - A Kjeldberg, L Gregersen, P Unold + Freeciv - Copyright (C) 2004 - The Freeciv Team This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) @@ -15,25 +15,30 @@ #endif #include <assert.h> +#include <ctype.h> +#include <string.h> +#include "city.h" #include "effects.h" #include "game.h" #include "government.h" #include "improvement.h" +#include "log.h" #include "map.h" #include "mem.h" +#include "packets.h" +#include "player.h" #include "support.h" #include "tech.h" #include "shared.h" /* ARRAY_SIZE */ - - + /* Names of effect ranges. * (These must correspond to enum effect_range_id in effects.h.) * do not change these unless you know what you're doing! */ static const char *effect_range_names[] = { "Local", "City", - "Island", + "Continent", "Player", "World" }; @@ -41,20 +46,14 @@ /* Names of effect types. * (These must correspond to enum effect_type_id in effects.h.) */ static const char *effect_type_names[] = { - "Adv_Parasite", + "Tech_Parasite", "Airlift", "Any_Government", - "Barb_Attack", - "Barb_Defend", - "Building_Cost", - "Building_Cost_Pct", "Capital_City", - "Capital_Exists", - "Corrupt_Adj", "Corrupt_Pct", + "Waste_Pct", "Enable_Nuke", "Enable_Space", - "Enemy_Peaceful", "Food_Add_Tile", "Food_Bonus", "Food_Pct", @@ -62,10 +61,9 @@ "Food_Per_Tile", "Force_Content", "Force_Content_Pct", - "Give_Imm_Adv", + "Give_Imm_Tech", "Growth_Food", "Have_Embassies", - "Improve_Rep", "Luxury_Bonus", "Luxury_Pct", "Make_Content", @@ -73,7 +71,6 @@ "Make_Content_Mil_Per", "Make_Content_Pct", "Make_Happy", - "May_Declare_War", "No_Anarchy", "No_Sink_Deep", "Nuke_Proof", @@ -91,13 +88,11 @@ "Prod_To_Gold", "Reveal_Cities", "Reveal_Map", - "Revolt_Dist_Adj", - "Revolt_Dist_Pct", + "Incite_Dist_Adj", + "Incite_Dist_Pct", "Science_Bonus", "Science_Pct", "Size_Unlimit", - "Slow_Nuke_Winter", - "Slow_Global_Warm", "SS_Structural", "SS_Component", "SS_Module", @@ -109,24 +104,28 @@ "Trade_Pct", "Trade_Inc_Tile", "Trade_Per_Tile", - "Trade_Route_Pct", - "Unit_Attack", - "Unit_Attack_Firepower", - "Unit_Cost", - "Unit_Cost_Pct", - "Unit_Defend", - "Unit_Defend_Firepower", - "Unit_Move", + "Sea_Move", "Unit_No_Lose_Pop", "Unit_Recover", - "Unit_Repair", - "Unit_Vet_Combat", - "Unit_Veteran", - "Upgrade_One_Step", - "Upgrade_One_Leap", - "Upgrade_All_Step", - "Upgrade_All_Leap", - "Upkeep_Free" + "Upgrade_Unit", + "Upkeep_Free", + "No_Unhappy", + "Land_Veteran", + "Sea_Veteran", + "Air_Veteran", + "Land_Vet_Combat", + "Sea_Vet_Combat", + "Air_Vet_Combat", + "Land_Regen", + "Sea_Regen", + "Air_Regen", + "Land_Defend", + "Sea_Defend", + "Air_Defend", + "Missile_Defend", + "Size_Adj", + "No_Upkeep", + "No_Incite" }; /************************************************************************** @@ -187,33 +186,505 @@ const char *effect_type_name(enum effect_type id) { assert(ARRAY_SIZE(effect_type_names) == EFT_LAST); + assert(id >= 0 && id < EFT_LAST); + return effect_type_names[id]; +} + +/************************************************************************** + The code creates a ruleset cache on ruleset load. This constant cache + is used to speed up effects queries. There is no further memory + allocation or de-allocation by any of the code after cache creation. + + Since the cache is constant, the server only needs to send effects data to + the client upon connect. It also means that an AI can do fast searches in + the effects space by trying the possible combinations of addition or + removal of buildings with the effects it cares about, like is done in the + existing code. + + + To know how much a target is being affected, simply use the convenience + functions: + + * get_player_bonus + * get_city_bonus + * get_city_tile_bonus + * get_building_bonus + + These functions require as arguments the target and the effect type to be + queried. + + Source buildings are unique and at a well known place in the + data structures. This allows lots of optimizations in the code. + + + === Future extensions: + The uniqueness aspect of a source is not as important as it being in a + well known place. Since a wonder is in a well known place, i.e. + game.global_wonders[], it is easy to find out if something is affected by + it or not. + + This could easily be extended by generalizing it to these arrays: + game.impr[], pplayer->impr[], pisland->impr[], pcity->impr[]. + + Which would store the number of buildings of that type present by game, + player, island or city. A similar, game wide only array would be kept + for surviving effects. + + This should enable basic support for small wonders and satellites. + + Since this means one always knows where to look for a source, we + can have very fast queries on effects that will scale well with complex + effects. +**************************************************************************/ + +static const char *req_type_names[] = { + "None", + "Tech", + "Gov", + "Building", + "Special", + "Terrain" +}; + +struct effect_group_element { + Impr_Type_id improvement; + enum effect_range range; + bool survives; +}; + +#define SPECLIST_TAG effect_group_element +#define SPECLIST_TYPE struct effect_group_element +#include "speclist.h" + +#define effect_group_element_list_iterate(list, elt) \ + TYPED_LIST_ITERATE(struct effect_group_element, list, elt) +#define effect_group_element_list_iterate_end LIST_ITERATE_END + +struct effect_group { + char *name; + int id; + struct effect_group_element_list elements; +}; + +#define SPECLIST_TAG effect_group +#define SPECLIST_TYPE struct effect_group +#include "speclist.h" + +#define effect_group_list_iterate(list, pgroup) \ + TYPED_LIST_ITERATE(struct effect_group, list, pgroup) +#define effect_group_list_iterate_end LIST_ITERATE_END + +/************************************************************************** + Ruleset cache. The cache is created during ruleset loading and the data + is organized to enable fast queries. +**************************************************************************/ +static struct { + struct { + /* This cache shows for each effect, which buildings provide it. */ + struct building_vector buildings; + + /* This array provides a full list of the effects of this type provided + * by each building. (It's not really a cache, it's the real data.) */ + struct effect_list buckets[B_LAST]; + } effects[EFT_LAST]; + + /* This cache shows for each building, which effect types it provides. */ + struct { + struct effect_type_vector types; + } buildings[B_LAST]; +} ruleset_cache; + +static struct effect_group_list groups; +static int next_group_id; + + +/************************************************************************** + Get a vector of buildings which grant the effect type. +**************************************************************************/ +static struct building_vector *get_buildings_with_effect(enum effect_type e) +{ + return &ruleset_cache.effects[e].buildings; +} + +/************************************************************************** + Get a list of effects of a type granted by a building. +**************************************************************************/ +struct effect_list *get_building_effects(Impr_Type_id building, + enum effect_type effect) +{ + return &ruleset_cache.effects[effect].buckets[building]; +} + +/************************************************************************** + Get a vector of effects types granted by a building. +**************************************************************************/ +struct effect_type_vector *get_building_effect_types(Impr_Type_id id) +{ + return &ruleset_cache.buildings[id].types; +} + + +/************************************************************************** + Get requirements type from string. +**************************************************************************/ +enum req_type req_type_from_str(const char *str) +{ + enum req_type id; + + for (id = 1; id < ARRAY_SIZE(req_type_names); id++) { + if (0 == mystrcasecmp(req_type_names[id], str)) { + return id; + } + } + + return REQ_LAST; +} + +/************************************************************************** + Create a new effects group. +**************************************************************************/ +struct effect_group *effect_group_new(const char *name) +{ + struct effect_group *group; + + group = fc_malloc(sizeof(*group)); + group->name = mystrdup(name); + group->id = next_group_id++; + effect_group_element_list_init(&group->elements); + + effect_group_list_insert_back(&groups, group); + return group; +} + +/************************************************************************** + Add a new building to an existing effects group. +**************************************************************************/ +void effect_group_add(struct effect_group *group, Impr_Type_id id, + enum effect_range range, bool survives) +{ + struct effect_group_element *elt; + + elt = fc_malloc(sizeof(*elt)); + elt->improvement = id; + elt->range = range; + elt->survives = survives; + + effect_group_element_list_insert_back(&group->elements, elt); +} + +/************************************************************************** + Find the id of an effects group by name. +**************************************************************************/ +int find_effect_group(const char *name) +{ + int i = 0; + + effect_group_list_iterate(groups, pgroup) { + if (0 == mystrcasecmp(pgroup->name, name)) { + return i; + } + i++; + } effect_group_list_iterate_end; + + return -1; +} + +/************************************************************************** + Initialize ruleset cache. +**************************************************************************/ +void ruleset_cache_init(void) +{ + int i, j; + + assert(ARRAY_SIZE(req_type_names) == REQ_LAST); - if (id < EFT_LAST) { - return effect_type_names[id]; + effect_group_list_init(&groups); + next_group_id = 0; + + for (i = 0; i < ARRAY_SIZE(ruleset_cache.buildings); i++) { + effect_type_vector_init(get_building_effect_types(i)); + } + + for (i = 0; i < ARRAY_SIZE(ruleset_cache.effects); i++) { + building_vector_init(get_buildings_with_effect(i)); + + for (j = 0; j < ARRAY_SIZE(ruleset_cache.effects[i].buckets); j++) { + effect_list_init(get_building_effects(j, i)); + } + } +} + +/************************************************************************** + Free the ruleset cache. +**************************************************************************/ +void ruleset_cache_free(void) +{ + int i, j; + + for (i = 0; i < ARRAY_SIZE(ruleset_cache.buildings); i++) { + effect_type_vector_free(get_building_effect_types(i)); + } + + for (i = 0; i < ARRAY_SIZE(ruleset_cache.effects); i++) { + building_vector_free(get_buildings_with_effect(i)); + + for (j = 0; j < ARRAY_SIZE(ruleset_cache.effects[i].buckets); j++) { + effect_list_unlink_all(get_building_effects(j, i)); + } + } +} + +/************************************************************************** + Parse effect requirement. +**************************************************************************/ +int parse_effect_requirement(Impr_Type_id id, enum req_type type, + const char *arg) +{ + bool problem; + int data; + struct government *pgov; + + switch (type) { + case REQ_NONE: + problem = FALSE; + data = 0; + break; + case REQ_TECH: + problem = (A_LAST == (data = find_tech_by_name(arg))); + break; + case REQ_GOV: + if (!(pgov = find_government_by_name(arg))) { + problem = TRUE; + } else { + problem = FALSE; + data = pgov->index; + } + break; + case REQ_BUILDING: + problem = (B_LAST == (data = find_improvement_by_name(arg))); + break; + case REQ_SPECIAL: + problem = (S_NO_SPECIAL == (data = get_special_by_name(arg))); + break; + case REQ_TERRAIN: + problem = (T_UNKNOWN == (data = get_terrain_by_name(arg))); + break; + default: + freelog(LOG_ERROR, "for %s: unimplemented requirement type '%d'", + get_improvement_name(id), type); + return -1; + } + + if (problem) { + freelog(LOG_ERROR, "for %s: bad requirement data '%s'", + get_improvement_name(id), arg); + return -1; } else { - return NULL; + return data; + } +} + +/************************************************************************** + Add effect to ruleset cache. +**************************************************************************/ +void ruleset_cache_add(Impr_Type_id id, enum effect_type eff, + enum effect_range range, bool survives, + int value, + enum req_type req, int arg, int group) +{ + struct effect *peff; + + peff = fc_malloc(sizeof(*peff)); + + peff->range = range; + peff->survives = survives; + peff->value = value; + + peff->req.type = req; + + switch (req) { + case REQ_NONE: + break; + case REQ_TECH: + peff->req.value.tech = arg; + break; + case REQ_GOV: + peff->req.value.gov = arg; + break; + case REQ_BUILDING: + peff->req.value.building = arg; + break; + case REQ_SPECIAL: + peff->req.value.special = arg; + break; + case REQ_TERRAIN: + peff->req.value.terrain = arg; + break; + case REQ_LAST: + assert(0); + break; + } + + effect_list_insert_back(get_building_effects(id, eff), peff); + + if (group >= 0) { + peff->group = effect_group_list_get(&groups, group); + } else { + peff->group = NULL; + } + + /* Add improvement type to the effect's buildings vector. */ + { + struct building_vector *vec; + Impr_Type_id *pbldg; + + vec = get_buildings_with_effect(eff); + + if (!(pbldg = building_vector_get(vec, -1)) || *pbldg != id) { + building_vector_append(vec, &id); + } + } + + /* Add effect type to the building's effect types vector. */ + { + struct effect_type_vector *vec; + bool exists = FALSE; + + vec = get_building_effect_types(id); + + effect_type_vector_iterate(vec, ptype) { + if (*ptype == eff) { + exists = TRUE; + break; + } + } effect_type_vector_iterate_end; + + if (!exists) { + effect_type_vector_append(vec, &eff); + } } } /************************************************************************** - Return TRUE iff the two effects are equal. + Send the ruleset cache groups data. **************************************************************************/ -bool are_effects_equal(const struct impr_effect *const peff1, - const struct impr_effect *const peff2) +static void send_ruleset_cache_groups(struct conn_list *dest) { -#define T(name) if(peff1->name!=peff2->name) return FALSE; - T(type); - T(range); - T(amount); - T(survives); - T(cond_bldg); - T(cond_gov); - T(cond_adv); - T(cond_eff); - T(aff_unit); - T(aff_terr); - T(aff_spec); - return TRUE; + struct packet_ruleset_cache_group packet; + int i; + + effect_group_list_iterate(groups, pgroup) { + sz_strlcpy(packet.name, pgroup->name); + + packet.num_elements = effect_group_element_list_size(&pgroup->elements); + for (i = 0; i < packet.num_elements; i++) { + struct effect_group_element *elt; + + elt = effect_group_element_list_get(&pgroup->elements, i); + packet.improvements[i] = elt->improvement; + packet.ranges[i] = elt->range; + packet.survives[i] = elt->survives; + } + + lsend_packet_ruleset_cache_group(dest, &packet); + } effect_group_list_iterate_end; +} + +/************************************************************************** + Send the ruleset cache effects data. +**************************************************************************/ +static void send_ruleset_cache_effects(struct conn_list *dest) +{ + struct packet_ruleset_cache_effect packet; + enum effect_type eff; + + for (eff = 0; eff < EFT_LAST; eff++) { + packet.eff = eff; + + building_vector_iterate(get_buildings_with_effect(eff), id) { + packet.id = *id; + + effect_list_iterate(*get_building_effects(*id, eff), peff) { + packet.range = peff->range; + packet.survives = peff->survives; + packet.value = peff->value; + packet.req = peff->req.type; + + if (peff->group) { + packet.group = peff->group->id; + } else { + packet.group = -1; + } + + switch (packet.req) { + case REQ_NONE: + packet.arg = 0; + break; + case REQ_TECH: + packet.arg = peff->req.value.tech; + break; + case REQ_GOV: + packet.arg = peff->req.value.gov; + break; + case REQ_BUILDING: + packet.arg = peff->req.value.building; + break; + case REQ_SPECIAL: + packet.arg = peff->req.value.special; + break; + case REQ_TERRAIN: + packet.arg = peff->req.value.terrain; + break; + case REQ_LAST: + assert(0); + break; + } + + lsend_packet_ruleset_cache_effect(dest, &packet); + } effect_list_iterate_end; + } building_vector_iterate_end; + } +} + +/************************************************************************** + Send the ruleset cache data over the network. +**************************************************************************/ +void send_ruleset_cache(struct conn_list *dest) +{ + send_ruleset_cache_groups(dest); + send_ruleset_cache_effects(dest); +} + +/************************************************************************** + Returns a buildable, non-obsolete building that can provide the effect. + + Note: this function is an inefficient hack to be used by the old AI. It + will never find wonders, since that's not what the AI wants. +**************************************************************************/ +Impr_Type_id ai_find_source_building(struct player *plr, + enum effect_type effect_type) +{ + /* FIXME: this just returns the first building. it should return the best + * building instead. */ + building_vector_iterate(get_buildings_with_effect(effect_type), pbldg) { + if (can_player_build_improvement(plr, *pbldg) + && !improvement_obsolete(plr, *pbldg) + && !is_wonder(*pbldg)) { + return *pbldg; + } + } building_vector_iterate_end; + return B_LAST; +} + +/************************************************************************** + Get a building which grants this effect. Returns B_LAST if there is none. +**************************************************************************/ +Impr_Type_id get_building_for_effect(enum effect_type eff) +{ + building_vector_iterate(get_buildings_with_effect(eff), pbldg) { + return *pbldg; + } building_vector_iterate_end; + return B_LAST; } /************************************************************************** @@ -223,62 +694,430 @@ giving the exact bonus. Finding the exact bonus requires knowing the effect range and may take longer. This function should only be used in situations where the range doesn't matter. +**************************************************************************/ +bool building_has_effect(Impr_Type_id id, enum effect_type effect) +{ + return (effect_list_size(get_building_effects(id, effect)) > 0); +} + +/************************************************************************** + Returns the number of total world buildings (this includes buildings + that have been destroyed). +**************************************************************************/ +static int num_world_buildings_total(Impr_Type_id id) +{ + if (is_wonder(id) && game.global_wonders[id] != 0) { + return 1; + } else { + return 0; + } +} + +/************************************************************************** + Returns the number of buildings of a certain type in the world. +**************************************************************************/ +static int num_world_buildings(Impr_Type_id id) +{ + if (is_wonder(id) && find_city_by_id(game.global_wonders[id])) { + return 1; + } else { + return 0; + } +} + +/************************************************************************** + Returns the number of buildings of a certain type owned by plr. +**************************************************************************/ +static int num_player_buildings(const struct player *plr, Impr_Type_id id) +{ + if (is_wonder(id) && player_find_city_by_id(plr, game.global_wonders[id])) { + return 1; + } else { + return 0; + } +} + +/************************************************************************** + Returns the number of buildings of a certain type on a continent. +**************************************************************************/ +static int num_continent_buildings(const struct player *plr, int continent, + Impr_Type_id id) +{ + if (is_wonder(id)) { + struct city *tmp; - TODO: - 1. This function does not access the effect data directly; instead - it just associates the effect with a building. - 2. Only a few effects are supported. -**************************************************************************/ -bool building_has_effect(Impr_Type_id building, enum effect_type effect) -{ - switch (effect) { - case EFT_PROD_TO_GOLD: - return building == B_CAPITAL; - case EFT_SS_STRUCTURAL: - return building == B_SSTRUCTURAL; - case EFT_SS_COMPONENT: - return building == B_SCOMP; - case EFT_SS_MODULE: - return building == B_SMODULE; - default: - break; + tmp = player_find_city_by_id(plr, game.global_wonders[id]); + if (tmp && map_get_continent(tmp->x, tmp->y) == continent) { + return 1; + } + } + return 0; +} + +/************************************************************************** + Returns the number of buildings of a certain type in a city. +**************************************************************************/ +static int num_city_buildings(const struct city *pcity, Impr_Type_id id) +{ + return (city_got_building(pcity, id) ? 1 : 0); +} + +/************************************************************************** + Is this target possible for the range involved? + e.g. you can only affect a player target with something of at least + player range. +**************************************************************************/ +static bool is_target_possible(enum target_type target, + enum effect_range range) +{ + switch (target) { + case TARGET_PLAYER: + return (range >= EFR_PLAYER); + case TARGET_CITY: + return (range >= EFR_CITY); + case TARGET_BUILDING: + return (range >= EFR_LOCAL); } assert(0); return FALSE; } /************************************************************************** + How many targets (player, city, building) are in range of the source + building? +**************************************************************************/ +static int count_targets_in_range(enum target_type target, + const struct player *plr, + const struct city *pcity, + Impr_Type_id building, + enum effect_range range, bool survives, + Impr_Type_id source) +{ + if (!is_target_possible(target, range)) { + return 0; + } + + if (improvement_obsolete(plr, source)) { + return 0; + } + + if (survives) { + if (range == EFR_WORLD) { + return num_world_buildings_total(source); + } else { + return 0; + } + } + + switch (range) { + case EFR_WORLD: + return num_world_buildings(source); + case EFR_PLAYER: + return num_player_buildings(plr, source); + case EFR_CONTINENT: + { + int continent; + + continent = map_get_continent(pcity->x, pcity->y); + + return num_continent_buildings(plr, continent, source); + } + case EFR_CITY: + return num_city_buildings(pcity, source); + case EFR_LOCAL: + if (building == source) { + return num_city_buildings(pcity, source); + } else { + return 0; + } + default: + return 0; + } +} + +/************************************************************************** + Is the effect from the source building redundant on the given target + (i.e. are its effects replaced by other sources in the group)? + + target gives the type of the target + (plr,pcity,building) gives the exact target + source is the source of the effect + peffect is the exact effect +**************************************************************************/ +static bool is_effect_redundant(enum target_type target, + const struct player *plr, + const struct city *pcity, + Impr_Type_id building, + Impr_Type_id source, + const struct effect *peffect) +{ + if (peffect->group) { + /* If there is more than one building in the same effects "group", then + * only the first one that exists can be active. */ + effect_group_element_list_iterate(peffect->group->elements, elt) { + if (elt->improvement == source) { + return FALSE; + } else { + if (count_targets_in_range(target, plr, pcity, building, elt->range, + elt->survives, elt->improvement) > 0) { + return TRUE; + } + } + } effect_group_element_list_iterate_end; + } + return FALSE; +} + +/************************************************************************** + Checks the requirements of the effect to see if it is active on the + given target. (If the requirements are not met the effect should be + ignored.) + + target gives the type of the target + (plr,pcity,building,ptile) give the exact target + source gives the source of the effect + peffect gives the exact effect value +**************************************************************************/ +static bool are_effect_reqs_active(enum target_type target, + const struct player *plr, + const struct city *pcity, + Impr_Type_id building, + const struct tile *ptile, + Impr_Type_id source, + const struct effect *peffect) +{ + bool active = FALSE; + + switch (peffect->req.type) { + case REQ_NONE: + active = TRUE; + break; + case REQ_TECH: + active = plr && (get_invention(plr, peffect->req.value.tech) + == TECH_KNOWN); + break; + case REQ_GOV: + active = plr && (plr->government == peffect->req.value.gov); + break; + case REQ_BUILDING: + active = (count_targets_in_range(target, plr, pcity, building, + EFR_CITY, FALSE, + peffect->req.value.building) > 0); + break; + case REQ_SPECIAL: + active = ptile && tile_has_special(ptile, peffect->req.value.special); + break; + case REQ_TERRAIN: + active = ptile && (ptile->terrain == peffect->req.value.terrain); + break; + case REQ_LAST: + assert(0); + break; + } + + return active; +} + +/************************************************************************** + Can the effect from the source building be active at a certain target + (player, city or building)? + + Don't do range checks for the actual source being tested, only for + requirements. + + target gives the type of the target + (plr,pcity,building,ptile) give the exact target + source gives the source of the effect + peffect gives the exact effect value +**************************************************************************/ +bool is_effect_useful(enum target_type target, const struct player *plr, + const struct city *pcity, Impr_Type_id building, + const struct tile *ptile, Impr_Type_id source, + const struct effect *peffect) +{ + if (is_effect_redundant(target, plr, pcity, building, source, peffect)) { + return FALSE; + } + return are_effect_reqs_active(target, plr, pcity, building, + ptile, source, peffect); +} + +/************************************************************************** + Is the effect from the source building active at a certain target (player, + city or building)? + + target gives the type of the target + (plr,pcity,building,ptile) give the exact target + source gives the source of the effect + peffect gives the exact effect value +**************************************************************************/ +static bool is_effect_active(enum target_type target, + const struct player *plr, + const struct city *pcity, + Impr_Type_id building, + const struct tile *ptile, + Impr_Type_id source, + const struct effect *peffect) +{ + if (count_targets_in_range(target, plr, pcity, building, peffect->range, + peffect->survives, source) == 0) { + return FALSE; + } + return is_effect_useful(target, plr, pcity, building, + ptile, source, peffect); +} + +/************************************************************************** + Returns TRUE if a building is replaced. To be replaced, all its effects + must be redundant. +**************************************************************************/ +bool building_replaced(const struct city *pcity, Impr_Type_id id) +{ + bool equivs_present = FALSE; + + effect_type_vector_iterate(get_building_effect_types(id), ptype) { + effect_list_iterate(*get_building_effects(id, *ptype), peff) { + if (!is_effect_redundant(TARGET_BUILDING, city_owner(pcity), pcity, id, + id, peff)) { + return FALSE; + } + if (peff->group) { + equivs_present = TRUE; + } + } effect_list_iterate_end; + } effect_type_vector_iterate_end; + return equivs_present; +} + +/************************************************************************** + Get the total value of one source building's effect type. This is + necessary since one building may have multiple effects of one type. +**************************************************************************/ +static int get_effect_value(enum target_type target, + const struct player *plr, + const struct city *pcity, + Impr_Type_id id, + const struct tile *ptile, + Impr_Type_id source, + enum effect_type effect_type) +{ + int value = 0; + + effect_list_iterate(*get_building_effects(source, effect_type), peffect) { + if (is_effect_active(target, plr, pcity, id, ptile, source, peffect)) { + value += peffect->value; + } + } effect_list_iterate_end; + + return value; +} + +/************************************************************************** + Returns the effect bonus for any target. + + The target type is given by 'target'. The effect type is given by + 'effect'. The other parameters give information about the target. +**************************************************************************/ +static int get_target_bonus(enum target_type target, + enum effect_type effect, + const struct player *pplayer, + const struct city *pcity, + Impr_Type_id building, + const struct tile *ptile) +{ + int bonus = 0; + + building_vector_iterate(get_buildings_with_effect(effect), pbldg) { + bonus += get_effect_value(target, pplayer, pcity, building, ptile, + *pbldg, effect); + } building_vector_iterate_end; + + return bonus; +} + +/************************************************************************** + Returns the effect bonus for a player. +**************************************************************************/ +int get_player_bonus(const struct player *pplayer, enum effect_type effect) +{ + return get_target_bonus(TARGET_PLAYER, effect, + pplayer, NULL, B_LAST, NULL); +} + +/************************************************************************** + Returns the effect bonus at a city. +**************************************************************************/ +int get_city_bonus(const struct city *pcity, enum effect_type effect) +{ + return get_target_bonus(TARGET_CITY, effect, + city_owner(pcity), pcity, B_LAST, NULL); +} + +/************************************************************************** + Returns the effect bonus at a city tile. +**************************************************************************/ +int get_city_tile_bonus(const struct city *pcity, const struct tile *ptile, + enum effect_type effect) +{ + return get_target_bonus(TARGET_CITY, effect, + city_owner(pcity), pcity, B_LAST, ptile); +} + +/************************************************************************** + Returns the effect bonus at a building. +**************************************************************************/ +int get_building_bonus(const struct city *pcity, Impr_Type_id id, + enum effect_type effect) +{ + return get_target_bonus(TARGET_BUILDING, effect, + city_owner(pcity), pcity, id, NULL); +} + +/************************************************************************** + Returns the effect sources of this type currently active at the city. +**************************************************************************/ +struct building_vector get_city_bonus_sources(const struct city *pcity, + enum effect_type effect) +{ + struct player *plr = city_owner(pcity); + struct building_vector res; + + building_vector_init(&res); + + building_vector_iterate(get_buildings_with_effect(effect), pbldg) { + if (get_effect_value(TARGET_CITY, plr, pcity, + B_LAST, NULL, *pbldg, effect) > 0) { + building_vector_append(&res, pbldg); + } + } building_vector_iterate_end; + + return res; +} + +/************************************************************************** Returns the effect bonus the currently-in-construction-item will provide. Note this is not called get_current_production_bonus because that would be confused with EFT_PROD_BONUS. - - TODO: - 1. This function does not access the effect data directly; instead - it just associates the effect with a building. - 2. Only a few effects are supported. **************************************************************************/ int get_current_construction_bonus(const struct city *pcity, enum effect_type effect) { - if (pcity->is_building_unit) { - return 0; /* No effects for units. */ - } + if (!pcity->is_building_unit) { + Impr_Type_id id; + int power = 0; + + id = pcity->currently_building; + + effect_list_iterate(*get_building_effects(id, effect), peffect) { + if (is_effect_useful(TARGET_BUILDING, city_owner(pcity), + pcity, id, NULL, id, peffect)) { + power += peffect->value; + } + } effect_list_iterate_end; - switch (effect) { - case EFT_PROD_TO_GOLD: - return (pcity->currently_building == B_CAPITAL) ? 1 : 0; - case EFT_SS_STRUCTURAL: - return (pcity->currently_building == B_SSTRUCTURAL) ? 1 : 0; - case EFT_SS_COMPONENT: - return (pcity->currently_building == B_SCOMP) ? 1 : 0; - case EFT_SS_MODULE: - return (pcity->currently_building == B_SMODULE) ? 1 : 0; - default: - /* All others unsupported. */ - break; + return power; } - assert(0); return 0; } Index: common/effects.h =================================================================== RCS file: /home/freeciv/CVS/freeciv/common/effects.h,v retrieving revision 1.6 diff -u -r1.6 effects.h --- common/effects.h 4 Sep 2004 20:19:51 -0000 1.6 +++ common/effects.h 6 Sep 2004 01:11:09 -0000 @@ -13,11 +13,10 @@ #ifndef FC__EFFECTS_H #define FC__EFFECTS_H -struct impr_effect; - #include "shared.h" /* bool */ #include "fc_types.h" +#include "tech.h" #include "terrain.h" /* Range of effects (used in equiv_range and effect.range fields) @@ -25,7 +24,7 @@ enum effect_range { EFR_LOCAL, EFR_CITY, - EFR_ISLAND, + EFR_CONTINENT, EFR_PLAYER, EFR_WORLD, EFR_LAST /* keep this last */ @@ -34,20 +33,14 @@ /* Type of effects. (Used in effect.type field) * These must correspond to effect_type_names[] in effects.c. */ enum effect_type { - EFT_ADV_PARASITE, + EFT_TECH_PARASITE, EFT_AIRLIFT, EFT_ANY_GOVERNMENT, - EFT_BARB_ATTACK, - EFT_BARB_DEFEND, - EFT_BUILDING_COST, - EFT_BUILDING_COST_PCT, EFT_CAPITAL_CITY, - EFT_CAPITAL_EXISTS, - EFT_CORRUPT_ADJ, EFT_CORRUPT_PCT, + EFT_WASTE_PCT, EFT_ENABLE_NUKE, EFT_ENABLE_SPACE, - EFT_ENEMY_PEACEFUL, EFT_FOOD_ADD_TILE, EFT_FOOD_BONUS, EFT_FOOD_PCT, @@ -55,10 +48,9 @@ EFT_FOOD_PER_TILE, EFT_FORCE_CONTENT, EFT_FORCE_CONTENT_PCT, - EFT_GIVE_IMM_ADV, + EFT_GIVE_IMM_TECH, EFT_GROWTH_FOOD, EFT_HAVE_EMBASSIES, - EFT_IMPROVE_REP, EFT_LUXURY_BONUS, EFT_LUXURY_PCT, EFT_MAKE_CONTENT, @@ -66,7 +58,6 @@ EFT_MAKE_CONTENT_MIL_PER, EFT_MAKE_CONTENT_PCT, EFT_MAKE_HAPPY, - EFT_MAY_DECLARE_WAR, EFT_NO_ANARCHY, EFT_NO_SINK_DEEP, EFT_NUKE_PROOF, @@ -84,13 +75,11 @@ EFT_PROD_TO_GOLD, EFT_REVEAL_CITIES, EFT_REVEAL_MAP, - EFT_REVOLT_DIST_ADJ, - EFT_REVOLT_DIST_Pct, + EFT_INCITE_DIST_ADJ, + EFT_INCITE_DIST_PCT, EFT_SCIENCE_BONUS, EFT_SCIENCE_PCT, EFT_SIZE_UNLIMIT, - EFT_SLOW_NUKE_WINTER, - EFT_SLOW_GLOBAL_WARM, EFT_SS_STRUCTURAL, EFT_SS_COMPONENT, EFT_SS_MODULE, @@ -102,40 +91,158 @@ EFT_TRADE_PCT, EFT_TRADE_INC_TILE, EFT_TRADE_PER_TILE, - EFT_TRADE_ROUTE_PCT, - EFT_UNIT_ATTACK, - EFT_UNIT_ATTACK_FIREPOWER, - EFT_UNIT_COST, - EFT_UNIT_COST_PCT, - EFT_UNIT_DEFEND, - EFT_UNIT_DEFEND_FIREPOWER, - EFT_UNIT_MOVE, + EFT_SEA_MOVE, EFT_UNIT_NO_LOSE_POP, EFT_UNIT_RECOVER, - EFT_UNIT_REPAIR, - EFT_UNIT_VET_COMBAT, - EFT_UNIT_VETERAN, - EFT_UPGRADE_ONE_STEP, - EFT_UPGRADE_ONE_LEAP, - EFT_UPGRADE_ALL_STEP, - EFT_UPGRADE_ALL_LEAP, + EFT_UPGRADE_UNIT, EFT_UPKEEP_FREE, + EFT_NO_UNHAPPY, + EFT_LAND_VETERAN, + EFT_SEA_VETERAN, + EFT_AIR_VETERAN, + EFT_LAND_VET_COMBAT, + EFT_SEA_VET_COMBAT, + EFT_AIR_VET_COMBAT, + EFT_LAND_REGEN, + EFT_SEA_REGEN, + EFT_AIR_REGEN, + EFT_LAND_DEFEND, + EFT_SEA_DEFEND, + EFT_AIR_DEFEND, + EFT_MISSILE_DEFEND, + EFT_SIZE_ADJ, + EFT_NO_UPKEEP, + EFT_NO_INCITE, EFT_LAST /* keep this last */ }; -#define EFT_ALL EFT_LAST - /* lookups */ enum effect_range effect_range_from_str(const char *str); const char *effect_range_name(enum effect_range id); enum effect_type effect_type_from_str(const char *str); const char *effect_type_name(enum effect_type id); -bool are_effects_equal(const struct impr_effect *const peff1, - const struct impr_effect *const peff2); +/* Typedefs. */ +#define effect_list_iterate(list, peff) \ + TYPED_LIST_ITERATE(struct effect, list, peff) +#define effect_list_iterate_end LIST_ITERATE_END + +#define SPECVEC_TAG building +#define SPECVEC_TYPE Impr_Type_id +#include "specvec.h" + +#define building_vector_iterate(vector, pbldg) \ + TYPED_VECTOR_ITERATE(Impr_Type_id, vector, pbldg) +#define building_vector_iterate_end VECTOR_ITERATE_END + +#define SPECVEC_TAG effect_type +#define SPECVEC_TYPE enum effect_type +#include "specvec.h" + +#define effect_type_vector_iterate(vector, ptype) \ + TYPED_VECTOR_ITERATE(enum effect_type, vector, ptype) +#define effect_type_vector_iterate_end VECTOR_ITERATE_END + +/* Effect requirement type. */ +enum req_type { + REQ_NONE, + REQ_TECH, + REQ_GOV, + REQ_BUILDING, + REQ_SPECIAL, + REQ_TERRAIN, + REQ_LAST +}; + +struct effect_group; + +struct effect { + enum effect_range range; /* effect range */ + + int value; /* effect modifier value */ + + struct effect_group *group; /* effect group */ + bool survives; /* does this effect survive? */ + + struct { + enum req_type type; /* requirement type */ + + union { + Tech_Type_id tech; /* requirement tech */ + int gov; /* requirement government */ + Impr_Type_id building; /* requirement building */ + enum tile_special_type special; /* requirement special */ + enum tile_terrain_type terrain; /* requirement terrain type */ + } value; /* requirement value */ + } req; +}; + +#define SPECLIST_TAG effect +#define SPECLIST_TYPE struct effect +#include "speclist.h" + +struct conn_list; + +struct city; +struct player; +struct tile; + +/* ruleset cache creation and communication functions */ +void ruleset_cache_init(void); +void ruleset_cache_free(void); +void ruleset_cache_add(Impr_Type_id id, enum effect_type eff, + enum effect_range range, bool survives, + int value, enum req_type req, int arg, int equiv); +void send_ruleset_cache(struct conn_list *dest); + +/* equivalent effect group */ +struct effect_group *effect_group_new(const char *name); +void effect_group_add(struct effect_group *group, Impr_Type_id id, + enum effect_range range, bool survives); +int find_effect_group(const char *name); + +/* name string to value functions */ +enum req_type req_type_from_str(const char *str); +int parse_effect_requirement(Impr_Type_id id, enum req_type req, + const char *arg); + +/* effect presence tests */ +enum target_type { + TARGET_PLAYER, + TARGET_CITY, + TARGET_BUILDING +}; + +bool is_effect_useful(enum target_type target, const struct player *plr, + const struct city *pcity, Impr_Type_id id, + const struct tile *ptile, Impr_Type_id source, + const struct effect *eff); + +bool building_replaced(const struct city *pcity, Impr_Type_id id); + +/* functions to know the bonuses a certain effect is granting */ +int get_player_bonus(const struct player *plr, enum effect_type eff); +int get_city_bonus(const struct city *pcity, enum effect_type eff); +int get_city_tile_bonus(const struct city *city, const struct tile *ptile, + enum effect_type eff); +int get_building_bonus(const struct city *pcity, Impr_Type_id id, + enum effect_type eff); + +/* miscellaneous auxiliary effects functions */ +struct effect_list *get_building_effects(Impr_Type_id id, + enum effect_type eff); +struct effect_type_vector *get_building_effect_types(Impr_Type_id id); + +struct building_vector get_city_bonus_sources(const struct city *pcity, + enum effect_type eff); bool building_has_effect(Impr_Type_id building, enum effect_type effect); int get_current_construction_bonus(const struct city *pcity, enum effect_type effect); +Impr_Type_id ai_find_source_building(struct player *plr, + enum effect_type effect); +Impr_Type_id get_building_for_effect(enum effect_type effect); + #endif /* FC__EFFECTS_H */ + Index: common/fc_types.h =================================================================== RCS file: /home/freeciv/CVS/freeciv/common/fc_types.h,v retrieving revision 1.5 diff -u -r1.5 fc_types.h --- common/fc_types.h 3 Sep 2004 04:22:37 -0000 1.5 +++ common/fc_types.h 6 Sep 2004 01:11:09 -0000 @@ -20,25 +20,7 @@ typedef signed short Continent_id; typedef enum tile_terrain_type Terrain_type_id; - -/* TODO: Remove this enum and make this an integer when gen-eff is done. */ -typedef enum { - B_AIRPORT=0, B_AQUEDUCT, B_BANK, B_BARRACKS, B_BARRACKS2, B_BARRACKS3, - B_CATHEDRAL, B_CITY, B_COASTAL, B_COLOSSEUM, B_COURTHOUSE, B_FACTORY, - B_GRANARY, B_HARBOUR, B_HYDRO, B_LIBRARY, B_MARKETPLACE, B_MASS, B_MFG, - B_NUCLEAR, B_OFFSHORE, B_PALACE, B_POLICE, B_PORT, B_POWER, - B_RECYCLING, B_RESEARCH, B_SAM, B_SDI, B_SEWER, B_SOLAR, B_SCOMP, - B_SMODULE, B_SSTRUCTURAL, B_STOCK, B_SUPERHIGHWAYS, B_SUPERMARKET, B_TEMPLE, - B_UNIVERSITY, - - B_APOLLO, B_ASMITHS, B_COLLOSSUS, B_COPERNICUS, B_CURE, B_DARWIN, B_EIFFEL, - B_GREAT, B_WALL, B_HANGING, B_HOOVER, B_ISAAC, B_BACH, B_RICHARDS, - B_LEONARDO, B_LIGHTHOUSE, B_MAGELLAN, B_MANHATTEN, B_MARCO, B_MICHELANGELO, - B_ORACLE, B_PYRAMIDS, B_SETI, B_SHAKESPEARE, B_LIBERTY, B_SUNTZU, - B_UNITED, B_WOMENS, - B_CAPITAL, B_LAST_ENUM -} Impr_Type_id; - +typedef int Impr_Type_id; struct city; struct government; Index: common/game.c =================================================================== RCS file: /home/freeciv/CVS/freeciv/common/game.c,v retrieving revision 1.184 diff -u -r1.184 game.c --- common/game.c 4 Sep 2004 20:19:51 -0000 1.184 +++ common/game.c 6 Sep 2004 01:11:10 -0000 @@ -278,6 +278,10 @@ game.government_when_anarchy = G_MAGIC; /* flag */ game.ai_goal_government = G_MAGIC; /* flag */ + game.default_building = B_LAST; + game.palace_building = B_LAST; + game.land_defend_building = B_LAST; + sz_strlcpy(game.demography, GAME_DEFAULT_DEMOGRAPHY); sz_strlcpy(game.allow_take, GAME_DEFAULT_ALLOW_TAKE); Index: common/game.h =================================================================== RCS file: /home/freeciv/CVS/freeciv/common/game.h,v retrieving revision 1.149 diff -u -r1.149 game.h --- common/game.h 3 Sep 2004 04:22:37 -0000 1.149 +++ common/game.h 6 Sep 2004 01:11:10 -0000 @@ -168,6 +168,10 @@ char rulesetdir[MAX_LEN_NAME]; int firepower_factor; /* See README.rulesets */ + Impr_Type_id default_building; + Impr_Type_id palace_building; + Impr_Type_id land_defend_building; + struct { int cathedral_plus; /* eg Theology */ int cathedral_minus; /* eg Communism */ Index: common/government.c =================================================================== RCS file: /home/freeciv/CVS/freeciv/common/government.c,v retrieving revision 1.45 diff -u -r1.45 government.c --- common/government.c 18 Aug 2004 18:11:05 -0000 1.45 +++ common/government.c 6 Sep 2004 01:11:10 -0000 @@ -237,7 +237,7 @@ return FALSE; } else { return (get_invention(pplayer, req) == TECH_KNOWN - || player_owns_active_govchange_wonder(pplayer)); + || get_player_bonus(pplayer, EFT_ANY_GOVERNMENT) > 0); } } Index: common/improvement.c =================================================================== RCS file: /home/freeciv/CVS/freeciv/common/improvement.c,v retrieving revision 1.45 diff -u -r1.45 improvement.c --- common/improvement.c 4 Sep 2004 20:19:51 -0000 1.45 +++ common/improvement.c 6 Sep 2004 01:11:10 -0000 @@ -99,9 +99,6 @@ free(p->equiv_repl); p->equiv_repl = NULL; - free(p->effect); - p->effect = NULL; - free(p->helptext); p->helptext = NULL; } @@ -355,15 +352,6 @@ } /************************************************************************** -Barbarians don't get enough knowledges to be counted as normal players. -**************************************************************************/ -bool is_wonder_useful(Impr_Type_id id) -{ - if ((id == B_GREAT) && (get_num_human_and_ai_players () < 3)) return FALSE; - return TRUE; -} - -/************************************************************************** Clears a list of improvements - sets them all to I_NONE **************************************************************************/ void improvement_status_init(Impr_Status * improvements, size_t elements) @@ -380,18 +368,22 @@ } /************************************************************************** - Whether player could build this improvement, assuming they had - the tech req, and assuming a city with the right pre-reqs etc. + Whether player can build given improvement somewhere, + ignoring whether improvement is obsolete. **************************************************************************/ -bool could_player_eventually_build_improvement(struct player *p, - Impr_Type_id id) +bool can_player_build_improvement_direct(struct player *p, Impr_Type_id id) { struct impr_type *impr; bool space_part = FALSE; /* This also checks if tech req is Never */ - if (!improvement_exists(id)) + if (!improvement_exists(id)) { return FALSE; + } + + if (!player_knows_improvement_tech(p, id)) { + return FALSE; + } impr = get_improvement_type(id); @@ -415,46 +407,50 @@ return FALSE; } } - if (space_part && (game.global_wonders[B_APOLLO] == 0 - || p->spaceship.state >= SSHIP_LAUNCHED)) { + if (space_part && + (!get_player_bonus(p, EFT_ENABLE_SPACE) > 0 + || p->spaceship.state >= SSHIP_LAUNCHED)) { return FALSE; } if (is_wonder(id)) { /* Can't build wonder if already built */ if (game.global_wonders[id] != 0) return FALSE; - } else { - /* Can't build if obsolette */ - if (improvement_obsolete(p, id)) return FALSE; } + return TRUE; } /************************************************************************** -... + Whether player can _eventually_ build given improvement somewhere -- ie, + returns 1 if improvement is available with current tech OR will be available + with future tech. returns 0 if improvement is obsolete. **************************************************************************/ -static bool could_player_build_improvement(struct player *p, Impr_Type_id id) +bool can_player_build_improvement(struct player *p, Impr_Type_id id) { - if (!could_player_eventually_build_improvement(p, id)) + if (!can_player_build_improvement_direct(p, id)) { return FALSE; - - /* Make sure we have the tech /now/.*/ - if (get_invention(p, improvement_types[id].tech_req) == TECH_KNOWN) - return TRUE; - return FALSE; + } + if (improvement_obsolete(p, id)) { + return FALSE; + } + return TRUE; } - + /************************************************************************** - Can a player build this improvement somewhere? Ignores the fact that - player may not have a city with appropriate prereqs. + Whether player can _eventually_ build given improvement somewhere -- ie, + returns 1 if improvement is available with current tech OR will be available + with future tech. returns 0 if unit is obsolete. **************************************************************************/ -bool can_player_build_improvement(struct player *p, Impr_Type_id id) +bool can_player_eventually_build_improvement(struct player *p, Impr_Type_id id) { - if (!improvement_exists(id)) + if (!improvement_exists(id)) { return FALSE; - if (!player_knows_improvement_tech(p,id)) + } + if (improvement_obsolete(p, id)) { return FALSE; - return(could_player_build_improvement(p, id)); + } + return TRUE; } /************************************************************************** @@ -564,7 +560,7 @@ We only check improvements within the equiv_range range. - N.B. Unlike effects, we do not have to do multiple iterations: an + N.B. We do not need to do multiple iterations: an improvement making another improvement redundant does not depend on whether it itself it redundant or not. having been built is all that counts. Index: common/improvement.h =================================================================== RCS file: /home/freeciv/CVS/freeciv/common/improvement.h,v retrieving revision 1.32 diff -u -r1.32 improvement.h --- common/improvement.h 3 Sep 2004 04:22:37 -0000 1.32 +++ common/improvement.h 6 Sep 2004 01:11:10 -0000 @@ -23,6 +23,12 @@ #include "terrain.h" /* Terrain_type_id etc */ #include "unittype.h" /* Unit_Class_id, Unit_Type_id */ +/* B_LAST is a value which is guaranteed to be larger than all + * actual Impr_Type_id values. It is used as a flag value; + * it can also be used for fixed allocations to ensure ability + * to hold full number of improvement types. */ +#define B_LAST MAX_NUM_ITEMS + /* Improvement status (for cities' lists of improvements) * An enum or bitfield would be neater here, but we use a typedef for * a) less memory usage and b) compatibility with old behaviour */ @@ -50,25 +56,6 @@ IR_LAST /* keep this last */ }; -/* An effect conferred by an improvement. */ -struct impr_effect { - enum effect_type type; - enum effect_range range; - int amount; - int survives; /* 1 = effect survives wonder destruction */ - 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 */ - enum effect_type cond_eff; /* EFT_LAST = unconditional */ - Unit_Class_id aff_unit; /* UCL_LAST = all */ - Terrain_type_id aff_terr; /* T_UNKNOWN = all; T_NONE = none */ - enum tile_special_type aff_spec; /* S_* bit mask of specials affected */ -}; - -/* Maximum number of effects per improvement - * (this should not be more than the number of bits in the Eff_Status type) */ -#define MAX_EFFECTS 16 - /* Type of improvement. (Read from buildings.ruleset file.) */ struct impr_type { char name[MAX_LEN_NAME]; @@ -83,11 +70,11 @@ Impr_Type_id *equiv_dupl; /* list; B_LAST terminated */ Impr_Type_id *equiv_repl; /* list; B_LAST terminated */ Tech_Type_id obsolete_by; /* A_LAST = never obsolete */ + Impr_Type_id replaced_by; /* B_LAST = never replaced */ bool is_wonder; int build_cost; /* Use wrappers to access this. */ int upkeep; int sabotage; /* Base chance of diplomat sabotage succeeding. */ - struct impr_effect *effect; /* list; .type==EFT_LAST terminated */ int variant; /* FIXME: remove when gen-impr obsoletes */ struct Sprite *sprite; /* icon of the improvement */ char *helptext; @@ -122,15 +109,15 @@ bool improvement_redundant(struct player *pplayer, const struct city *pcity, Impr_Type_id id, bool want_to_build); bool wonder_obsolete(Impr_Type_id id); -bool is_wonder_useful(Impr_Type_id id); Impr_Type_id find_improvement_by_name(const char *s); Impr_Type_id find_improvement_by_name_orig(const char *s); void improvement_status_init(Impr_Status * improvements, size_t elements); /* player related improvement and unit functions */ -bool could_player_eventually_build_improvement(struct player *p, - Impr_Type_id id); +bool can_player_build_improvement_direct(struct player *p, Impr_Type_id id); bool can_player_build_improvement(struct player *p, Impr_Type_id id); +bool can_player_eventually_build_improvement(struct player *p, + Impr_Type_id id); /* city related improvement functions */ void mark_improvement(struct city *pcity,Impr_Type_id id,Impr_Status status); Index: common/packets.def =================================================================== RCS file: /home/freeciv/CVS/freeciv/common/packets.def,v retrieving revision 1.45 diff -u -r1.45 packets.def --- common/packets.def 3 Sep 2004 03:56:58 -0000 1.45 +++ common/packets.def 6 Sep 2004 01:11:10 -0000 @@ -157,7 +157,6 @@ type BIT_STRING = bit_string(char) type WORKLIST = worklist(struct worklist) type TECH_LIST = tech_list(int) -type EFFECT = effect(struct impr_effect) # typedefs for enums type CLAUSE = uint8(enum clause_type) @@ -178,6 +177,11 @@ type ORDERS = uint8(enum unit_orders) type SSET_TYPE = uint8(enum sset_type) +# typedefs for effects +type EFF = uint8(enum effect_type) +type EFR = uint8(enum effect_range) +type REQ = uint8(enum req_type) + # typedefs for IDs type PLAYER = UINT8 type CITY = UINT16 @@ -1140,7 +1144,7 @@ STRING graphic_str[MAX_LEN_NAME]; STRING graphic_alt[MAX_LEN_NAME]; TECH tech_req, obsolete_by; - IMPROVEMENT bldg_req; + IMPROVEMENT bldg_req, replaced_by; BOOL is_wonder; IMPR_RANGE equiv_range; UINT16 build_cost; @@ -1157,8 +1161,6 @@ IMPROVEMENT equiv_dupl[255:equiv_dupl_count]; UINT8 equiv_repl_count; IMPROVEMENT equiv_repl[255:equiv_repl_count]; - UINT8 effect_count; - EFFECT effect[255:effect_count]; end PACKET_RULESET_TERRAIN=105;sc,lsend @@ -1245,6 +1247,8 @@ BOOL slow_invasions; STRING team_name[MAX_NUM_TEAMS][MAX_LEN_NAME]; + + IMPROVEMENT default_building; end @@ -1296,3 +1300,26 @@ UINT8 category; /* which category this is in */ end + +/************** Effects hash packets **********************/ + +PACKET_RULESET_CACHE_GROUP=120;sc,lsend + STRING name[MAX_LEN_NAME]; + + UINT8 num_elements; + IMPROVEMENT improvements[255:num_elements]; + EFR ranges[255:num_elements]; + BOOL survives[255:num_elements]; +end + +PACKET_RULESET_CACHE_EFFECT=121;sc,lsend + IMPROVEMENT id; + EFF eff; + EFR range; + BOOL survives; + SINT32 value; + REQ req; + SINT32 arg; + SINT32 group; +end + Index: common/packets.h =================================================================== RCS file: /home/freeciv/CVS/freeciv/common/packets.h,v retrieving revision 1.162 diff -u -r1.162 packets.h --- common/packets.h 14 Jan 2004 11:58:12 -0000 1.162 +++ common/packets.h 6 Sep 2004 01:11:10 -0000 @@ -19,7 +19,7 @@ #include "connection.h" /* struct connection, MAX_LEN_* */ #include "diptreaty.h" #include "events.h" -#include "effects.h" +#include "improvement.h" #include "map.h" #include "player.h" #include "shared.h" /* MAX_LEN_NAME, MAX_LEN_ADDR */ Index: common/player.c =================================================================== RCS file: /home/freeciv/CVS/freeciv/common/player.c,v retrieving revision 1.150 diff -u -r1.150 player.c --- common/player.c 29 Aug 2004 19:03:31 -0000 1.150 +++ common/player.c 6 Sep 2004 01:11:10 -0000 @@ -65,7 +65,7 @@ { return (TEST_BIT(pplayer->embassy, pplayer2->player_no) || (pplayer == pplayer2) - || (player_owns_active_wonder(pplayer, B_MARCO) + || (get_player_bonus(pplayer, EFT_HAVE_EMBASSIES) > 0 && !is_barbarian(pplayer2))); } @@ -370,31 +370,6 @@ } /************************************************************************** - Return 1 if one of the player's cities has the specified wonder, - and it is not obsolete. -**************************************************************************/ -bool player_owns_active_wonder(struct player *pplayer, - Impr_Type_id id) -{ - return (improvement_exists(id) - && is_wonder(id) - && (!wonder_obsolete(id)) - && player_find_city_by_id(pplayer, game.global_wonders[id])); -} - -/************************************************************************** - ... -**************************************************************************/ -bool player_owns_active_govchange_wonder(struct player *pplayer) -{ - return ( player_owns_active_wonder(pplayer, B_LIBERTY) || - ( (improvement_variant(B_PYRAMIDS)==1) && - player_owns_active_wonder(pplayer, B_PYRAMIDS) ) || - ( (improvement_variant(B_UNITED)==1) && - player_owns_active_wonder(pplayer, B_UNITED) ) ); -} - -/************************************************************************** Returns the number of techs the player has researched which has this flag. Needs to be optimized later (e.g. int tech_flags[TF_LAST] in struct player) Index: common/player.h =================================================================== RCS file: /home/freeciv/CVS/freeciv/common/player.h,v retrieving revision 1.122 diff -u -r1.122 player.h --- common/player.h 3 Sep 2004 04:22:37 -0000 1.122 +++ common/player.h 6 Sep 2004 01:11:10 -0000 @@ -217,7 +217,6 @@ Impr_Status improvements[B_LAST]; /* improvements with equiv_range==Player */ Impr_Status *island_improv; /* improvements with equiv_range==Island, dimensioned to [map.num_continents][game.num_impr_types] */ - struct { int length; void *data; @@ -250,9 +249,6 @@ int unit_id); bool player_in_city_radius(struct player *pplayer, int x, int y); -bool player_owns_active_wonder(struct player *pplayer, - Impr_Type_id id); -bool player_owns_active_govchange_wonder(struct player *pplayer); bool player_knows_improvement_tech(struct player *pplayer, Impr_Type_id id); bool player_knows_techs_with_flag(struct player *pplayer, Index: common/unit.c =================================================================== RCS file: /home/freeciv/CVS/freeciv/common/unit.c,v retrieving revision 1.216 diff -u -r1.216 unit.c --- common/unit.c 31 Aug 2004 04:40:50 -0000 1.216 +++ common/unit.c 6 Sep 2004 01:11:10 -0000 @@ -28,6 +28,7 @@ #include "support.h" #include "tech.h" +#include "city.h" #include "unit.h" /*************************************************************** @@ -53,15 +54,9 @@ case SEA_MOVING: move_rate = (base_move_rate * punit->hp) / unit_type(punit)->hp; - if (player_owns_active_wonder(unit_owner(punit), B_LIGHTHOUSE)) { - move_rate += SINGLE_MOVE; - } - - if (player_owns_active_wonder(unit_owner(punit), B_MAGELLAN)) { - move_rate += (improvement_variant(B_MAGELLAN) == 1) - ? SINGLE_MOVE : 2 * SINGLE_MOVE; - } - + move_rate += (get_player_bonus(unit_owner(punit), EFT_SEA_MOVE) + * SINGLE_MOVE); + if (player_knows_techs_with_flag(unit_owner(punit), TF_BOAT_FAST)) { move_rate += SINGLE_MOVE; } @@ -497,14 +492,8 @@ return AB_TOO_BIG; if (pcity->owner != punit->owner) return AB_NOT_OWNER; - if (improvement_exists(B_AQUEDUCT) - && !city_got_building(pcity, B_AQUEDUCT) - && new_pop > game.aqueduct_size) - return AB_NO_AQUEDUCT; - if (improvement_exists(B_SEWER) - && !city_got_building(pcity, B_SEWER) - && new_pop > game.sewer_size) - return AB_NO_SEWER; + if (!city_can_grow_to(pcity, new_pop)) + return AB_NO_SPACE; return AB_ADD_OK; } @@ -1643,7 +1632,7 @@ **************************************************************************/ int base_trireme_loss_pct(struct player *pplayer, struct unit *punit) { - if (player_owns_active_wonder(pplayer, B_LIGHTHOUSE)) { + if (get_player_bonus(pplayer, EFT_NO_SINK_DEEP) > 0) { return 0; } else if (player_knows_techs_with_flag(pplayer, TF_REDUCE_TRIREME_LOSS2)) { return game.trireme_loss_chance[punit->veteran] / 4; Index: common/unit.h =================================================================== RCS file: /home/freeciv/CVS/freeciv/common/unit.h,v retrieving revision 1.123 diff -u -r1.123 unit.h --- common/unit.h 3 Sep 2004 04:22:37 -0000 1.123 +++ common/unit.h 6 Sep 2004 01:11:10 -0000 @@ -96,11 +96,7 @@ AB_NOT_OWNER, /* Owner of unit is not owner of city */ AB_TOO_BIG, /* City is too big to be added to */ - AB_NO_AQUEDUCT, /* Adding takes city past limit for - aquaduct but city has no - aquaduct */ - AB_NO_SEWER /* Adding takes city past limit for - sewer but city has no sewer */ + AB_NO_SPACE /* Adding takes city past limit */ }; enum unit_upgrade_result { Index: common/unittype.c =================================================================== RCS file: /home/freeciv/CVS/freeciv/common/unittype.c,v retrieving revision 1.39 diff -u -r1.39 unittype.c --- common/unittype.c 26 Aug 2004 06:26:09 -0000 1.39 +++ common/unittype.c 6 Sep 2004 01:11:11 -0000 @@ -476,7 +476,8 @@ if (!unit_type_exists(id)) return FALSE; - if (unit_type_flag(id, F_NUCLEAR) && game.global_wonders[B_MANHATTEN] == 0) + if (unit_type_flag(id, F_NUCLEAR) + && !get_player_bonus(p, EFT_ENABLE_NUKE) > 0) return FALSE; if (unit_type_flag(id, F_NOBUILD)) { return FALSE; Index: common/aicore/cm.c =================================================================== RCS file: /home/freeciv/CVS/freeciv/common/aicore/cm.c,v retrieving revision 1.39 diff -u -r1.39 cm.c --- common/aicore/cm.c 24 Jul 2004 03:43:35 -0000 1.39 +++ common/aicore/cm.c 6 Sep 2004 01:11:11 -0000 @@ -401,7 +401,7 @@ freelog(LOG_NORMAL, " trade = %3d", pcity->trade_prod); freelog(LOG_NORMAL, " gold = %3d (%+3d)", pcity->tax_total, - city_gold_surplus(pcity)); + city_gold_surplus(pcity, pcity->tax_total)); freelog(LOG_NORMAL, " luxury = %3d", pcity->luxury_total); freelog(LOG_NORMAL, " science = %3d", pcity->science_total); } @@ -501,7 +501,7 @@ result->surplus[FOOD] = pcity->food_surplus; result->surplus[SHIELD] = pcity->shield_surplus; result->surplus[TRADE] = pcity->trade_prod; - result->surplus[GOLD] = city_gold_surplus(pcity); + result->surplus[GOLD] = city_gold_surplus(pcity, pcity->tax_total); result->surplus[LUXURY] = pcity->luxury_total; result->surplus[SCIENCE] = pcity->science_total; Index: data/civ1/buildings.ruleset =================================================================== RCS file: /home/freeciv/CVS/freeciv/data/civ1/buildings.ruleset,v retrieving revision 1.36 diff -u -r1.36 buildings.ruleset --- data/civ1/buildings.ruleset 4 Sep 2004 20:19:51 -0000 1.36 +++ data/civ1/buildings.ruleset 6 Sep 2004 01:11:12 -0000 @@ -59,6 +59,51 @@ some movement points left to be airlifted.\ ") +[group_factories] +name = "Factories" +elements = + { "building", "range" + "Mfg. Plant", "City" + "Factory", "City" + } + +[group_generators] +name = "Generators" +elements = + { "building", "range" + "Hoover Dam", "Player" + "Nuclear Plant", "City" + "Hydro Plant", "City" + "Power Plant", "City" + } + +[group_janitors] +name = "Janitors" +elements = + { "building", "range" + "Recycling Center", "City" + "Hoover Dam", "Player" + "Nuclear Plant", "City" + "Hydro Plant", "City" + } + +[group_defenders] +name = "Defenders" +elements = + { "building", "range" + "Great Wall", "Player" + "City Walls", "City" + } + +[group_purifiers] +name = "Purifiers" +elements = + { "building", "range" + "Palace", "City" + "Courthouse", "City" + } + + [building_aqueduct] name = _("Aqueduct") tech_req = "Construction" @@ -75,9 +120,9 @@ build_cost = 120 upkeep = 2 sabotage = 100 -effect = - { "type", "range", "amount" - "Size_Unlimit", "City", 10 +effect = + { "name" + "Size_Unlimit" } sound = "b_aqueduct" sound_alt = "b_generic" @@ -102,9 +147,9 @@ upkeep = 3 sabotage = 100 effect = - { "type", "range", "amount", "cond_bldg" - "Tax_Bonus", "City", 50, "Marketplace" - "Luxury_Bonus", "City", 50, "Marketplace" + { "name", "value", "req_type", "req" + "Tax_Bonus", 50, "Building", "Marketplace" + "Luxury_Bonus", 50, "Building", "Marketplace" } sound = "b_bank" sound_alt = "b_generic" @@ -124,24 +169,17 @@ ;spec_gate = equiv_range = "City" ;equiv_dupl = -equiv_repl = "Sun Tzu's War Academy", "Barracks II", "Barracks III" +equiv_repl = "Barracks II", "Barracks III" obsolete_by = "Gunpowder" is_wonder = 0 build_cost = 40 -upkeep = 0 +upkeep = 1 sabotage = 100 effect = - { "type", "range", "aff_unit" - "Unit_Veteran", "City", "Air" - "Unit_Repair", "City", "Air" - "Unit_Veteran", "City", "Helicopter" - "Unit_Repair", "City", "Helicopter" - "Unit_Veteran", "City", "Land" - "Unit_Repair", "City", "Land" - "Unit_Veteran", "City", "Missile" - "Unit_Repair", "City", "Missile" - "Unit_Veteran", "City", "Sea" - "Unit_Repair", "City", "Sea" + { "name" + "Land_Veteran" + "Sea_Veteran" + "Air_Veteran" } variant = 1 ; FIXME: remove when gen-impr obsoletes sound = "b_barracks_i" @@ -164,24 +202,17 @@ ;spec_gate = equiv_range = "City" ;equiv_dupl = -equiv_repl = "Sun Tzu's War Academy", "Barracks III" +equiv_repl = "Barracks III" obsolete_by = "Combustion" is_wonder = 0 build_cost = 40 -upkeep = 1 +upkeep = 2 sabotage = 100 effect = - { "type", "range", "aff_unit" - "Unit_Veteran", "City", "Air" - "Unit_Repair", "City", "Air" - "Unit_Veteran", "City", "Helicopter" - "Unit_Repair", "City", "Helicopter" - "Unit_Veteran", "City", "Land" - "Unit_Repair", "City", "Land" - "Unit_Veteran", "City", "Missile" - "Unit_Repair", "City", "Missile" - "Unit_Veteran", "City", "Sea" - "Unit_Repair", "City", "Sea" + { "name" + "Land_Veteran" + "Sea_Veteran" + "Air_Veteran" } sound = "b_barracks_ii" sound_alt = "b_generic" @@ -203,24 +234,17 @@ ;spec_gate = equiv_range = "City" ;equiv_dupl = -equiv_repl = "Sun Tzu's War Academy" +;equiv_repl = obsolete_by = "None" is_wonder = 0 build_cost = 40 -upkeep = 2 +upkeep = 3 sabotage = 100 effect = - { "type", "range", "aff_unit" - "Unit_Veteran", "City", "Air" - "Unit_Repair", "City", "Air" - "Unit_Veteran", "City", "Helicopter" - "Unit_Repair", "City", "Helicopter" - "Unit_Veteran", "City", "Land" - "Unit_Repair", "City", "Land" - "Unit_Veteran", "City", "Missile" - "Unit_Repair", "City", "Missile" - "Unit_Veteran", "City", "Sea" - "Unit_Repair", "City", "Sea" + { "name" + "Land_Veteran" + "Sea_Veteran" + "Air_Veteran" } sound = "b_barracks_iii" sound_alt = "b_generic" @@ -249,8 +273,8 @@ upkeep = 3 sabotage = 100 effect = - { "type", "range", "amount" - "Make_Content", "City", 4 + { "name", "value" + "Make_Content", 4 } sound = "b_cathedral" sound_alt = "b_generic" @@ -276,11 +300,10 @@ upkeep = 2 sabotage = 50 effect = - { "type", "range", "amount", "aff_unit" - "Unit_Defend", "City", 300, "Helicopter" - "Unit_Defend", "City", 300, "Land" - "Unit_Defend", "City", 300, "Sea" - "Unit_No_Lose_Pop", "City", 0, "Land" + { "name", "value", "equiv" + "Land_Defend", 200, "Defenders" + "Sea_Defend", 200, "Defenders" + "Unit_No_Lose_Pop" } variant = 1 ; FIXME: remove when gen-impr obsoletes sound = "b_city_walls" @@ -293,33 +316,6 @@ occurs when a defending unit is destroyed by a land unit.\ ") -[building_coastal_defense] -name = _("Coastal Defense") -tech_req = "Never" ; remove when may have indefinite count of improvements -bldg_req = "None" -graphic = "b.coastal_defense" -graphic_alt = "-" -terr_gate = "Ocean" -;spec_gate = -equiv_range = "City" -;equiv_dupl = -;equiv_repl = -obsolete_by = "None" -is_wonder = 0 -build_cost = 80 -upkeep = 1 -sabotage = 100 -effect = - { "type", "range", "amount", "aff_unit" - "Unit_Defend", "City", 200, "Sea" - } -sound = "b_coastal_defense" -sound_alt = "b_generic" -helptext = _("\ -Increases the defence strength of units within a city by a factor\ - of 2 when defending against bombardments from enemy ships.\ -") - [building_colosseum] name = _("Colosseum") tech_req = "Construction" @@ -337,8 +333,8 @@ upkeep = 4 sabotage = 100 effect = - { "type", "range", "amount" - "Make_Content", "City", 3 + { "name", "value" + "Make_Content", 3 } sound = "b_colosseum" sound_alt = "b_generic" @@ -363,10 +359,9 @@ upkeep = 1 sabotage = 100 effect = - { "type", "range", "amount", "cond_gov" - "Corrupt_Pct", "City", 50 - "Make_Content", "City", 1, "Democracy" - "Revolt_Dist_Pct", "City", 50 + { "name", "value", "equiv", "req_type", "req" + "Corrupt_Pct", 50, "Purifiers" + "Waste_Pct", 50, "Purifiers" } sound = "b_courthouse" sound_alt = "b_generic" @@ -394,8 +389,8 @@ upkeep = 4 sabotage = 100 effect = - { "type", "range", "amount" - "Prod_Bonus", "City", 50 + { "name", "value", "equiv" + "Prod_Bonus", 50, "Factories" } sound = "b_factory" sound_alt = "b_generic" @@ -421,8 +416,8 @@ upkeep = 1 sabotage = 100 effect = - { "type", "range", "amount" - "Growth_Food", "City", 50 + { "name" + "Growth_Food" } sound = "b_granary" sound_alt = "b_generic" @@ -435,33 +430,6 @@ ; In Civ1, city size reduction does not generate food like this. ; Dare I ask where this food comes from?? :-) -[building_harbour] -name = _("Harbour") -tech_req = "Never" ; remove when may have indefinite count of improvements -bldg_req = "None" -graphic = "b.harbour" -graphic_alt = "-" -terr_gate = "Ocean" -;spec_gate = -equiv_range = "City" -;equiv_dupl = -;equiv_repl = -obsolete_by = "None" -is_wonder = 0 -build_cost = 60 -upkeep = 1 -sabotage = 100 -effect = - { "type", "range", "amount", "aff_terr", "aff_spec" - "Food_Add_Tile", "City", 1, "Ocean", "None" - } -sound = "b_harbour" -sound_alt = "b_generic" -helptext = _("\ -Gives one extra food resource on all Ocean squares. The city needs\ - to be coastal to build this improvement.\ -") - [building_hydro_plant] name = _("Hydro Plant") tech_req = "Electronics" @@ -479,10 +447,9 @@ upkeep = 4 sabotage = 100 effect = - { "type", "range", "amount", "cond_bldg" - "Prod_Bonus", "City", 50, "Factory" - "Pollu_Prod_Pct", "City", 50 - "Pollu_Prod_Pct", "City", -50, "Recycling Center" + { "name", "value", "equiv" + "Prod_Bonus", 50, "Generators" + "Pollu_Prod_Pct", 2, "Janitors" } sound = "b_hydro_plant" sound_alt = "b_generic" @@ -516,8 +483,8 @@ upkeep = 1 sabotage = 100 effect = - { "type", "range", "amount" - "Science_Bonus", "City", 50 + { "name", "value" + "Science_Bonus", 50 } sound = "b_library" sound_alt = "b_generic" @@ -543,9 +510,9 @@ upkeep = 1 sabotage = 100 effect = - { "type", "range", "amount" - "Tax_Bonus", "City", 50 - "Luxury_Bonus", "City", 50 + { "name", "value" + "Tax_Bonus", 50 + "Luxury_Bonus", 50 } sound = "b_marketplace" sound_alt = "b_generic" @@ -571,8 +538,8 @@ upkeep = 4 sabotage = 100 effect = - { "type", "range", "amount" - "Pollu_Pop_Pct", "City", 0 + { "name", "value" + "Pollu_Pop_Pct", 100 } sound = "b_mass_transit" sound_alt = "b_generic" @@ -599,8 +566,8 @@ upkeep = 6 sabotage = 100 effect = - { "type", "range", "amount", "cond_bldg" - "Prod_Bonus", "City", 50, "Factory" + { "name", "value", "equiv" + "Prod_Bonus", 100, "Factories" } sound = "b_mfg_plant" sound_alt = "b_generic" @@ -623,14 +590,13 @@ equiv_repl = "Hoover Dam", "Power Plant", "Hydro Plant" obsolete_by = "None" is_wonder = 0 -build_cost = 160 +build_cost = 240 upkeep = 2 sabotage = 100 effect = - { "type", "range", "amount", "cond_bldg" - "Prod_Bonus", "City", 50, "Factory" - "Pollu_Prod_Pct", "City", 50 - "Pollu_Prod_Pct", "City", -50, "Recycling Center" + { "name", "value", "equiv" + "Prod_Bonus", 50, "Generators" + "Pollu_Prod_Pct", 2, "Janitors" } sound = "b_nuclear_plant" sound_alt = "b_generic" @@ -649,33 +615,6 @@ ; For Civ1/2 there should be a change of meltdown during ; civil disorder, but that has not been implemented yet. -[building_offshore_platform] -name = _("Offshore Platform") -tech_req = "Never" ; remove when may have indefinite count of improvements -bldg_req = "None" -graphic = "b.offshore_platform" -graphic_alt = "-" -terr_gate = "Ocean" -;spec_gate = -equiv_range = "City" -;equiv_dupl = -;equiv_repl = -obsolete_by = "None" -is_wonder = 0 -build_cost = 160 -upkeep = 3 -sabotage = 100 -effect = - { "type", "range", "amount", "aff_terr", "aff_spec" - "Prod_Add_Tile", "City", 1, "Ocean", "None" - } -sound = "b_offshore_platform" -sound_alt = "b_generic" -helptext = _("\ -Adds 1 extra shield resource on all Ocean squares in a city. The\ - city needs to be coastal to build this improvement.\ -") - [building_palace] name = _("Palace") tech_req = "Masonry" @@ -693,9 +632,12 @@ upkeep = 0 sabotage = 0 effect = - { "type", "range" - "Capital_City", "City" - "Capital_Exists", "Player" + { "name", "value", "equiv" + "Corrupt_Pct", 50, "Purifiers" + "Waste_Pct", 50, "Purifiers" + "Spy_Resistant", 50 + "No_Incite" + "Capital_City" } sound = "b_palace" sound_alt = "b_generic" @@ -712,64 +654,6 @@ results in losing whatever spaceship you might have.\ ") -[building_police_station] -name = _("Police Station") -tech_req = "Never" ; remove when may have indefinite count of improvements -bldg_req = "None" -graphic = "b.police_station" -graphic_alt = "-" -;terr_gate = -;spec_gate = -equiv_range = "City" -;equiv_dupl = -equiv_repl = "Women's Suffrage" -obsolete_by = "None" -is_wonder = 0 -build_cost = 60 -upkeep = 2 -sabotage = 100 -effect = - { "type", "range", "amount", "cond_gov" - "Make_Content_Mil", "City", 1, "Republic" - "Make_Content_Mil", "City", 2, "Democracy" - } -sound = "b_police_station" -sound_alt = "b_generic" -helptext = _("\ -Reduces the unhappiness caused by military units outside the city\ - by 2 under Democracy and 1 under Republic. This improvement has no\ - effect under other governments.\ -") - -[building_port_facility] -name = _("Port Facility") -tech_req = "Never" ; remove when may have indefinite count of improvements -bldg_req = "None" -graphic = "b.port_facility" -graphic_alt = "-" -terr_gate = "Ocean" -;spec_gate = -equiv_range = "City" -;equiv_dupl = -;equiv_repl = -obsolete_by = "None" -is_wonder = 0 -build_cost = 80 -upkeep = 3 -sabotage = 100 -effect = - { "type", "range", "aff_unit" - "Unit_Veteran", "City", "Sea" - "Unit_Repair", "City", "Sea" - } -sound = "b_port_facility" -sound_alt = "b_generic" -helptext = _("\ -Allows a city to build veteran sea units. Also, damaged sea units\ - which stay in town for one full turn without moving are completely\ - restored.\ -") - [building_power_plant] name = _("Power Plant") tech_req = "Refining" @@ -787,8 +671,8 @@ upkeep = 4 sabotage = 100 effect = - { "type", "range", "amount", "cond_bldg" - "Prod_Bonus", "City", 50, "Factory" + { "name", "value", "equiv" + "Prod_Bonus", 50, "Generators" } sound = "b_power_plant" sound_alt = "b_generic" @@ -821,8 +705,8 @@ upkeep = 2 sabotage = 100 effect = - { "type", "range", "amount" - "Pollu_Prod_Pct", "City", 34 + { "name", "value", "equiv" + "Pollu_Prod_Pct", 3, "Janitors" } sound = "b_recycling_center" sound_alt = "b_generic" @@ -832,63 +716,6 @@ generated by production in a city by 66%.\ ") -[building_research_lab] -name = _("Research Lab") -tech_req = "Never" ; remove when may have indefinite count of improvements -bldg_req = "Library" -graphic = "b.research_lab" -graphic_alt = "-" -;terr_gate = -;spec_gate = -equiv_range = "City" -;equiv_dupl = -equiv_repl = "SETI Program" -obsolete_by = "None" -is_wonder = 0 -build_cost = 160 -upkeep = 3 -sabotage = 100 -effect = - { "type", "range", "amount", "cond_bldg" - "Science_Bonus", "City", 50, "Library" - } -sound = "b_research_lab" -sound_alt = "b_generic" -helptext = _("\ -Together with a Library, a Research Lab increases the science\ - production of a city by 100%. \ -Together with a Library and a University, a Research Lab increases\ - the science production of a city by 150%.\ -") - -[building_sam_battery] -name = _("SAM Battery") -tech_req = "Never" ; remove when may have indefinite count of improvements -bldg_req = "None" -graphic = "b.sam_battery" -graphic_alt = "-" -;terr_gate = -;spec_gate = -equiv_range = "City" -;equiv_dupl = -;equiv_repl = -obsolete_by = "None" -is_wonder = 0 -build_cost = 100 -upkeep = 2 -sabotage = 100 -effect = - { "type", "range", "amount", "aff_unit" - "Unit_Defend", "City", 200, "Air" - "Unit_Defend", "City", 200, "Missile" - } -sound = "b_sam_battery" -sound_alt = "b_generic" -helptext = _("\ -Doubles the defense of all units inside the city when attacked by\ - non-nuclear air units.\ -") - [building_sdi_defense] name = _("SDI Defense") tech_req = "Superconductors" @@ -906,9 +733,8 @@ upkeep = 4 sabotage = 100 effect = - { "type", "range", "amount", "aff_unit" - "Nuke_Proof", "City", 3 - "Unit_Defend", "City", 200, "Missile" + { "name" + "Nuke_Proof" } sound = "b_sdi_defense" sound_alt = "b_generic" @@ -960,12 +786,6 @@ build_cost = 320 upkeep = 4 sabotage = 100 -effect = - { "type", "range", "amount", "cond_bldg" - "Prod_Bonus", "City", 50, "Factory" - "Pollu_Prod_Pct", "City", 0 - "Slow_Global_Warm", "World", 10 - } sound = "b_solar_plant" sound_alt = "b_generic" ; /* xgettext:no-c-format */ @@ -999,9 +819,9 @@ build_cost = 160 upkeep = 0 sabotage = 100 -effect = - { "type", "range" - "SS_Component", "Local" +effect = + { "name" + "SS_Component" } sound = "b_space_component" sound_alt = "b_generic" @@ -1030,9 +850,9 @@ build_cost = 320 upkeep = 0 sabotage = 100 -effect = - { "type", "range" - "SS_Module", "Local" +effect = + { "name" + "SS_Module" } sound = "b_space_module" sound_alt = "b_generic" @@ -1070,9 +890,9 @@ build_cost = 80 upkeep = 0 sabotage = 100 -effect = - { "type", "range" - "SS_Structural", "Local" +effect = + { "name" + "SS_Structural" } sound = "b_space_structural" sound_alt = "b_generic" @@ -1085,93 +905,6 @@ must have been built by any player.\ ") -[building_stock_exchange] -name = _("Stock Exchange") -tech_req = "Never" ; remove when may have indefinite count of improvements -bldg_req = "Bank" -graphic = "b.stock_exchange" -graphic_alt = "-" -;terr_gate = -;spec_gate = -equiv_range = "City" -;equiv_dupl = -;equiv_repl = -obsolete_by = "None" -is_wonder = 0 -build_cost = 160 -upkeep = 4 -sabotage = 100 -effect = - { "type", "range", "amount", "cond_bldg" - "Tax_Bonus", "City", 50, "Bank" - "Luxury_Bonus", "City", 50, "Bank" - } -sound = "b_stock_exchange" -sound_alt = "b_generic" -; /* xgettext:no-c-format */ -helptext = _("\ -Together with a Marketplace and a Bank, a Stock Exchange boosts\ - tax and luxury production in a city by 150%.\ -") - -[building_super_highways] -name = _("Super Highways") -tech_req = "Never" ; remove when may have indefinite count of improvements -bldg_req = "None" -graphic = "b.super_highways" -graphic_alt = "-" -;terr_gate = -;spec_gate = -equiv_range = "City" -;equiv_dupl = -;equiv_repl = -obsolete_by = "None" -is_wonder = 0 -build_cost = 160 -upkeep = 3 -sabotage = 100 -effect = - { "type", "range", "amount", "aff_terr", "aff_spec" - "Trade_Per_Tile", "City", 50, "None", "Road" - "Trade_Route_Pct", "City", 10 - } -sound = "b_super_highways" -sound_alt = "b_generic" -; /* xgettext:no-c-format */ -helptext = _("\ -Increases trade resources by 50% on all squares with roads or\ - railroads.\ -") - -[building_supermarket] -name = _("Supermarket") -tech_req = "Never" ; remove when may have indefinite count of improvements -bldg_req = "None" -graphic = "b.supermarket" -graphic_alt = "-" -;terr_gate = -;spec_gate = -equiv_range = "City" -;equiv_dupl = -;equiv_repl = -obsolete_by = "None" -is_wonder = 0 -build_cost = 120 -upkeep = 3 -sabotage = 100 -effect = - { "type", "range", "amount", "aff_terr", "aff_spec" - "Food_Per_Tile", "City", 50, "None", "Farmland" - } -sound = "b_supermarket" -sound_alt = "b_generic" -; /* xgettext:no-c-format */ -helptext = _("\ -Increases the food resources by 50% on each farmland square which\ - is being used around the city. Farmland squares are those which\ - have been irrigated a second time.\ -") - [building_temple] name = _("Temple") tech_req = "Ceremonial Burial" @@ -1189,9 +922,9 @@ upkeep = 1 sabotage = 100 effect = - { "type", "range", "amount", "cond_adv" - "Make_Content", "City", 1 - "Make_Content", "City", 1, "Mysticism" + { "name", "value", "req_type", "req" + "Make_Content", 1 + "Make_Content", 1, "Tech", "Mysticism" } sound = "b_temple" sound_alt = "b_generic" @@ -1218,8 +951,8 @@ upkeep = 3 sabotage = 100 effect = - { "type", "range", "amount", "cond_bldg" - "Science_Bonus", "City", 50, "Library" + { "name", "value", "req_type", "req" + "Science_Bonus", 50, "Building", "Library" } sound = "b_university" sound_alt = "b_generic" @@ -1246,9 +979,9 @@ upkeep = 0 sabotage = 0 effect = - { "type", "range", "survives" - "Reveal_Cities", "Player", 0 - "Enable_Space", "World", 1 + { "name", "range", "survives" + "Reveal_Cities", "Player", 0 + "Enable_Space", "World", 1 } helptext = _("\ All cities on the map become visible for the player who owns it. \ @@ -1256,33 +989,6 @@ they have researched the necessary technologies).\ ") -[building_asmiths_trading_co] -name = _("A.Smith's Trading Co.") -tech_req = "Never" ; remove when may have indefinite count of improvements -bldg_req = "None" -graphic = "b.asmiths_trading_co" -graphic_alt = "-" -;terr_gate = -;spec_gate = -equiv_range = "Player" -;equiv_dupl = -;equiv_repl = -obsolete_by = "None" -is_wonder = 1 -build_cost = 400 -upkeep = 0 -sabotage = 0 -effect = - { "type", "range", "amount" - "Upkeep_Free", "Player", 1 - } -sound = "w_asmiths_trading_co" -sound_alt = "w_generic" -helptext = _("\ -City improvements which would normally have an upkeep of 1 are free\ - of upkeep, for all cities.\ -") - [building_colossus] name = _("Colossus") tech_req = "Bronze Working" @@ -1294,14 +1000,14 @@ equiv_range = "City" ;equiv_dupl = ;equiv_repl = -obsolete_by = "Flight" +obsolete_by = "Electricity" is_wonder = 1 build_cost = 200 upkeep = 0 sabotage = 0 effect = - { "type", "range", "amount" - "Trade_Inc_Tile", "City", 1 + { "name", "value" + "Trade_Inc_Tile", 1 } sound = "w_colossus" sound_alt = "w_generic" @@ -1327,8 +1033,10 @@ upkeep = 0 sabotage = 0 effect = - { "type", "range", "amount" - "Science_Bonus", "City", 50 + { "name", "value", "req_type", "req" + "Science_Bonus", 50, "Building", "Library" + "Science_Bonus", 50, "Building", "University" + "Science_Bonus", 100 } sound = "w_copernicus_observatory" sound_alt = "w_generic" @@ -1354,8 +1062,8 @@ upkeep = 0 sabotage = 0 effect = - { "type", "range", "amount" - "Make_Happy", "Player", 1 + { "name", "range", "value" + "Force_Content", "Player", 1 } sound = "w_cure_for_cancer" sound_alt = "w_generic" @@ -1381,8 +1089,8 @@ upkeep = 0 sabotage = 0 effect = - { "type", "range", "amount" - "Give_Imm_Adv", "Player", 2 + { "name", "range", "value" + "Give_Imm_Tech", "Player", 2 } sound = "w_darwins_voyage" sound_alt = "w_generic" @@ -1408,10 +1116,6 @@ build_cost = 300 upkeep = 0 sabotage = 0 -effect = - { "type", "range", "amount" - "Improve_Rep", "Player", 25 - } sound = "w_eiffel_tower" sound_alt = "w_generic" ; /* xgettext:no-c-format */ @@ -1433,14 +1137,14 @@ equiv_range = "None" ;equiv_dupl = ;equiv_repl = -obsolete_by = "University" +obsolete_by = "Electronics" is_wonder = 1 build_cost = 300 upkeep = 0 sabotage = 0 effect = - { "type", "range", "amount" - "Adv_Parasite", "Player", 2 + { "name", "range", "value" + "Tech_Parasite", "Player", 2 } sound = "w_great_library" sound_alt = "w_generic" @@ -1466,10 +1170,9 @@ upkeep = 0 sabotage = 0 effect = - { "type", "range", "amount", "aff_unit" - "Unit_Defend", "Player", 300, "Land" - "Unit_No_Lose_Pop", "Player", 0, "Land" - "Barb_Attack", "Player", 200 + { "name", "range", "value", "equiv" + "Land_Defend", "Player", 200, "Defenders" + "Sea_Defend", "Player", 200, "Defenders" } sound = "w_great_wall" sound_alt = "w_generic" @@ -1496,9 +1199,8 @@ upkeep = 0 sabotage = 0 effect = - { "type", "range", "amount" - "Make_Happy", "Player", 1 - "Make_Happy", "City", 2 + { "name", "range", "value" + "Make_Happy", "Player", 1 } sound = "w_hanging_gardens" sound_alt = "w_generic" @@ -1527,10 +1229,9 @@ upkeep = 0 sabotage = 0 effect = - { "type", "range", "amount", "cond_bldg" - "Prod_Bonus", "Island", 50, "Factory" - "Pollu_Prod_Pct", "Island", 50 - "Pollu_Prod_Pct", "Island", -50, "Recycling Center" + { "name", "range", "value", "equiv" + "Prod_Bonus", "Continent", 50, "Generators" + "Pollu_Prod_Pct", "Continent", 2, "Janitors" } variant = 1 ; FIXME: remove when gen-impr obsoletes sound = "w_hoover_dam" @@ -1559,6 +1260,11 @@ upkeep = 0 sabotage = 0 effect = + { "name", "range", "value", "req_type", "req" + "Science_Bonus", "Player", 50, "Building", "Library" + "Science_Bonus", "Player", 50, "Building", "University" + } +effect = { "type", "range", "amount" "Science_Bonus", "City", 100 } @@ -1586,8 +1292,8 @@ upkeep = 0 sabotage = 0 effect = - { "type", "range", "amount" - "Make_Content", "Island", 2 + { "name", "range", "value" + "Force_Content", "Continent", 2 } variant = 1 ; FIXME: remove when gen-impr obsoletes sound = "w_js_bachs_cathedral" @@ -1597,59 +1303,6 @@ on the same continent where the wonder is built.\ ") -[building_king_richards_crusade] -name = _("King Richard's Crusade") -tech_req = "Never" ; remove when may have indefinite count of improvements -bldg_req = "None" -graphic = "b.king_richards_crusade" -graphic_alt = "-" -;terr_gate = -;spec_gate = -equiv_range = "City" -;equiv_dupl = -;equiv_repl = -obsolete_by = "Industrialization" -is_wonder = 1 -build_cost = 300 -upkeep = 0 -sabotage = 0 -effect = - { "type", "range", "amount" - "Prod_Add_Tile", "City", 1 - } -sound = "w_king_richards_crusade" -sound_alt = "w_generic" -helptext = _("\ -Adds one extra shield resource on every square around the city\ - where it is built.\ -") - -[building_leonardos_workshop] -name = _("Leonardo's Workshop") -tech_req = "Never" ; remove when may have indefinite count of improvements -bldg_req = "None" -graphic = "b.leonardos_workshop" -graphic_alt = "-" -;terr_gate = -;spec_gate = -equiv_range = "Player" -;equiv_dupl = -;equiv_repl = -obsolete_by = "Automobile" -is_wonder = 1 -build_cost = 400 -upkeep = 0 -sabotage = 0 -effect = - { "type", "range", "amount" - "Upgrade_One_Leap", "Player", 100 - } -sound = "w_leonardos_workshop" -sound_alt = "w_generic" -helptext = _("\ -Upgrades one obsolete unit per game turn.\ -") - [building_lighthouse] name = _("Lighthouse") tech_req = "Map Making" @@ -1667,10 +1320,8 @@ upkeep = 0 sabotage = 0 effect = - { "type", "range", "amount", "aff_unit" - "Unit_Move", "Player", 1, "Sea" - "No_Sink_Deep", "Player" - "Unit_Veteran", "Player", 0, "Sea" + { "name", "range", "value" + "Sea_Move", "Player", 1 } sound = "w_lighthouse" sound_alt = "w_generic" @@ -1699,8 +1350,8 @@ upkeep = 0 sabotage = 0 effect = - { "type", "range", "amount", "aff_unit" - "Unit_Move", "Player", 1, "Sea" + { "name", "range", "value" + "Sea_Move", "Player", 1 } variant = 1 ; FIXME: remove when gen-impr obsoletes sound = "w_magellans_expedition" @@ -1726,40 +1377,14 @@ upkeep = 0 sabotage = 0 effect = - { "type", "range", "survives" - "Enable_Nuke", "World", 1 + { "name", "range", "survives" + "Enable_Nuke", "World", 1 } sound = "w_manhattan_project" sound_alt = "w_generic" ;helptext is set in client/helpdata.c:helptext_wonder() ;helptext = -[building_marco_polos_embassy] -name = _("Marco Polo's Embassy") -tech_req = "Never" ; remove when may have indefinite count of improvements -bldg_req = "None" -graphic = "b.marco_polos_embassy" -graphic_alt = "-" -;terr_gate = -;spec_gate = -equiv_range = "None" -;equiv_dupl = -;equiv_repl = -obsolete_by = "Communism" -is_wonder = 1 -build_cost = 200 -upkeep = 0 -sabotage = 0 -effect = - { "type", "range" - "Have_Embassies", "Player" - } -sound = "w_marco_polos_embassy" -sound_alt = "w_generic" -helptext = _("\ -The player who owns it gets an embassy with all players.\ -") - [building_michelangelos_chapel] name = _("Michelangelo's Chapel") tech_req = "Religion" @@ -1773,12 +1398,12 @@ ;equiv_repl = obsolete_by = "Communism" is_wonder = 1 -build_cost = 400 +build_cost = 300 upkeep = 0 sabotage = 0 effect = - { "type", "range", "amount", "cond_bldg" - "Make_Content", "Player", 4, "Cathedral" + { "name", "value", "req_type", "req" + "Make_Content", 4, "Building", "Cathedral" } variant = 1 ; FIXME: remove when gen-impr obsoletes sound = "w_michelangelos_chapel" @@ -1804,9 +1429,8 @@ upkeep = 0 sabotage = 0 effect = - { "type", "range", "amount", "cond_bldg", "cond_adv" - "Make_Content", "Player", 1, "Temple" - "Make_Content", "Player", 1, "Temple", "Mysticism" + { "name", "value", "req_type", "req" + "Make_Content", 2, "Building", "Temple" } sound = "w_oracle" sound_alt = "w_generic" @@ -1831,9 +1455,9 @@ upkeep = 0 sabotage = 0 effect = - { "type", "range", "amount" - "Any_Government", "Player" - "No_Anarchy", "Player" + { "name", "range" + "Any_Government", "Player" + "No_Anarchy", "Player" } variant = 1 ; FIXME: remove when gen-impr obsoletes sound = "w_pyramids" @@ -1861,8 +1485,8 @@ upkeep = 0 sabotage = 0 effect = - { "type", "range", "amount", "cond_bldg" - "Science_Bonus", "Player", 50, "Library" + { "name", "range", "value" + "Science_Bonus", "Player", 50 } sound = "w_seti_program" sound_alt = "w_generic" @@ -1888,8 +1512,8 @@ upkeep = 0 sabotage = 0 effect = - { "type", "range", "amount" - "Make_Content", "City", 99 + { "name" + "No_Unhappy" } sound = "w_shakespeares_theatre" sound_alt = "w_generic" @@ -1897,64 +1521,6 @@ Makes all unhappy citizens content, in the city where it is located.\ ") -[building_statue_of_liberty] -name = _("Statue of Liberty") -tech_req = "Never" ; remove when may have indefinite count of improvements -bldg_req = "None" -graphic = "b.statue_of_liberty" -graphic_alt = "-" -;terr_gate = -;spec_gate = -equiv_range = "None" -;equiv_dupl = -;equiv_repl = -obsolete_by = "None" -is_wonder = 1 -build_cost = 400 -upkeep = 0 -sabotage = 0 -effect = - { "type", "range" - "Any_Government", "Player" - "No_Anarchy", "Player" - } -sound = "w_statue_of_liberty" -sound_alt = "w_generic" -helptext = _("\ -Allows you to choose any government, including those that have not yet\ - been researched by your civilization, and without the transition\ - period of Anarchy.\ -") - -[building_sun_tzus_war_academy] -name = _("Sun Tzu's War Academy") -tech_req = "Never" ; remove when may have indefinite count of improvements -bldg_req = "None" -graphic = "b.sun_tzus_war_academy" -graphic_alt = "-" -;terr_gate = -;spec_gate = -equiv_range = "Player" -;equiv_dupl = -;equiv_repl = -obsolete_by = "Mobile Warfare" -is_wonder = 1 -build_cost = 300 -upkeep = 0 -sabotage = 0 -effect = - { "type", "range", "amount", "aff_unit" - "Unit_Veteran", "Player", 0, "Land" - "Unit_Vet_Combat", "Player", 100, "Land" - } -sound = "w_sun_tzus_war_academy" -sound_alt = "w_generic" -helptext = _("\ -All your new ground units become veterans (for all cities). \ - The chance of a unit becoming a veteran after a battle increases\ - from 50% to 100%.\ -") - [building_united_nations] name = _("United Nations") tech_req = "Communism" @@ -1972,9 +1538,9 @@ upkeep = 0 sabotage = 0 effect = - { "type", "range" - "Any_Government", "Player" - "No_Anarchy", "Player" + { "name", "range" + "Any_Government", "Player" + "No_Anarchy", "Player" } variant = 1 ; FIXME: remove when gen-impr obsoletes sound = "w_united_nations" @@ -2007,8 +1573,8 @@ upkeep = 0 sabotage = 0 effect = - { "type", "range", "amount" - "Make_Content_Mil", "Player", 1 + { "name", "range", "value" + "Make_Content_Mil_Per", "Player", 1 } variant = 1 ; FIXME: remove when gen-impr obsoletes sound = "w_womens_suffrage" @@ -2036,8 +1602,8 @@ upkeep = 0 sabotage = 0 effect = - { "type", "range", "amount" - "Prod_To_Gold", "City", 100 + { "name" + "Prod_To_Gold" } helptext = _("\ This is not a normal improvement. Instead, setting a city's\ @@ -2046,13 +1612,15 @@ ") -; FIXME: remove all of the following when gen-impr implemented... - [b_special] ; Special values: aqueduct_size=10; +default="Capitalization" + +; FIXME: remove all of the following when gen-impr implemented... + sewer_size=99; ; Techs which modify building effects: Index: data/civ2/buildings.ruleset =================================================================== RCS file: /home/freeciv/CVS/freeciv/data/civ2/buildings.ruleset,v retrieving revision 1.39 diff -u -r1.39 buildings.ruleset --- data/civ2/buildings.ruleset 4 Sep 2004 20:19:51 -0000 1.39 +++ data/civ2/buildings.ruleset 6 Sep 2004 01:11:12 -0000 @@ -24,6 +24,67 @@ ; /*** For details of this file's format, ***/ ; /*** see the default buildings.ruleset. ***/ +[group_cathedrals] +name = "Cathedrals" +elements = + { "building", "range" + "Michelangelo's Chapel", "Player" + "Cathedral", "City" + } + +[group_labs] +name = "Labs" +elements = + { "building", "range" + "SETI Program", "Player" + "Research Lab", "City" + } + +[group_generators] +name = "Generators" +elements = + { "building", "range" + "Hoover Dam", "Player" + "Nuclear Plant", "City" + "Hydro Plant", "City" + "Power Plant", "City" + } + +[group_janitors] +name = "Janitors" +elements = + { "building", "range" + "Recycling Center", "City" + "Hoover Dam", "Player" + "Nuclear Plant", "City" + "Hydro Plant", "City" + } + +[group_defenders] +name = "Defenders" +elements = + { "building", "range" + "Great Wall", "Player" + "City Walls", "City" + } + +[group_peacekeepers] +name = "Peacekeepers" +elements = + { "building", "range" + "Women's Suffrage", "Player" + "Police Station", "City" + } + +[group_purifiers] +name = "Purifiers" +elements = + { "building", "range" + "Palace", "City" + "Courthouse", "City" + } + + [building_airport] name = _("Airport") tech_req = "Radio" @@ -41,10 +102,10 @@ upkeep = 3 sabotage = 100 effect = - { "type", "range", "aff_unit" - "Unit_Veteran", "City", "Air" - "Unit_Repair", "City", "Air" - "Airlift", "City" + { "name" + "Air_Veteran" + "Air_Regen" + "Airlift" } sound = "b_airport" sound_alt = "b_generic" @@ -75,9 +136,9 @@ build_cost = 80 upkeep = 2 sabotage = 100 -effect = - { "type", "range", "amount" - "Size_Unlimit", "City", 8 +effect = + { "name", "value" + "Size_Adj", 4 } sound = "b_aqueduct" sound_alt = "b_generic" @@ -103,9 +164,9 @@ upkeep = 3 sabotage = 100 effect = - { "type", "range", "amount", "cond_bldg" - "Tax_Bonus", "City", 50, "Marketplace" - "Luxury_Bonus", "City", 50, "Marketplace" + { "name", "value", "req_type", "req" + "Tax_Bonus", 50, "Building", "Marketplace" + "Luxury_Bonus", 50, "Building", "Marketplace" } sound = "b_bank" sound_alt = "b_generic" @@ -132,9 +193,9 @@ upkeep = 1 sabotage = 100 effect = - { "type", "range", "aff_unit" - "Unit_Veteran", "City", "Land" - "Unit_Repair", "City", "Land" + { "name" + "Land_Veteran" + "Land_Regen" } sound = "b_barracks_i" sound_alt = "b_generic" @@ -163,9 +224,9 @@ upkeep = 1 sabotage = 100 effect = - { "type", "range", "aff_unit" - "Unit_Veteran", "City", "Land" - "Unit_Repair", "City", "Land" + { "name" + "Land_Veteran" + "Land_Regen" } sound = "b_barracks_ii" sound_alt = "b_generic" @@ -194,9 +255,9 @@ upkeep = 1 sabotage = 100 effect = - { "type", "range", "aff_unit" - "Unit_Veteran", "City", "Land" - "Unit_Repair", "City", "Land" + { "name" + "Land_Veteran" + "Land_Regen" } sound = "b_barracks_iii" sound_alt = "b_generic" @@ -225,10 +286,10 @@ upkeep = 3 sabotage = 100 effect = - { "type", "range", "amount", "cond_adv" - "Make_Content", "City", 3 - "Make_Content", "City", 1, "Theology" - "Make_Content", "City", -1, "Communism" + { "name", "value", "equiv", "req_type", "req" + "Make_Content", 3, "Cathedrals" + "Make_Content", 1, "Cathedrals", "Tech", "Theology" + "Make_Content", -1, "Cathedrals", "Tech", "Communism" } sound = "b_cathedral" sound_alt = "b_generic" @@ -258,11 +319,9 @@ upkeep = 0 sabotage = 50 effect = - { "type", "range", "amount", "cond_bldg", "aff_unit" - "Unit_Defend", "City", 300, "", "Land" - "Unit_No_Lose_Pop", "City", 0, "", "Land" - "Spy_Resistant", "Local", 50 - "Spy_Resistant", "Local", -50, "Palace" + { "name", "value", "equiv" + "Land_Defend", 200, "Defenders" + "Unit_No_Lose_Pop" } sound = "b_city_walls" sound_alt = "b_generic" @@ -291,8 +350,8 @@ upkeep = 1 sabotage = 100 effect = - { "type", "range", "amount", "aff_unit" - "Unit_Defend", "City", 200, "Sea" + { "name", "value" + "Sea_Defend", 100 } sound = "b_coastal_defense" sound_alt = "b_generic" @@ -318,9 +377,9 @@ upkeep = 4 sabotage = 100 effect = - { "type", "range", "amount", "cond_adv" - "Make_Content", "City", 3 - "Make_Content", "City", 1, "Electronics" + { "name", "value", "req_type", "req" + "Make_Content", 3 + "Make_Content", 1, "Tech", "Electricity" } sound = "b_colosseum" sound_alt = "b_generic" @@ -346,10 +405,11 @@ upkeep = 1 sabotage = 100 effect = - { "type", "range", "amount", "cond_gov" - "Corrupt_Pct", "City", 50 - "Make_Content", "City", 1, "Democracy" - "Revolt_Dist_Pct", "City", 50 + { "name", "value", "equiv", "req_type", "req" + "Corrupt_Pct", 50, "Purifiers" + "Waste_Pct", 50, "Purifiers" + "Make_Content", 1, "", "Gov", "Democracy" + "Incite_Dist_Pct", 75 } sound = "b_courthouse" sound_alt = "b_generic" @@ -377,8 +437,8 @@ upkeep = 4 sabotage = 100 effect = - { "type", "range", "amount" - "Prod_Bonus", "City", 50 + { "name", "value" + "Prod_Bonus", 50 } sound = "b_factory" sound_alt = "b_generic" @@ -404,8 +464,8 @@ upkeep = 1 sabotage = 100 effect = - { "type", "range", "amount" - "Growth_Food", "City", 50 + { "name" + "Growth_Food" } sound = "b_granary" sound_alt = "b_generic" @@ -435,8 +495,8 @@ upkeep = 1 sabotage = 100 effect = - { "type", "range", "amount", "aff_terr", "aff_spec" - "Food_Add_Tile", "City", 1, "Ocean", "None" + { "name", "value", "req_type", "req" + "Food_Add_Tile", 1, "Terrain", "Ocean" } sound = "b_harbour" sound_alt = "b_generic" @@ -462,10 +522,10 @@ upkeep = 4 sabotage = 100 effect = - { "type", "range", "amount", "cond_bldg" - "Prod_Bonus", "City", 50, "Factory" - "Pollu_Prod_Pct", "City", 50 - "Pollu_Prod_Pct", "City", -50, "Recycling Center" + { "name", "value", "equiv", "req_type", "req" + "Prod_Bonus", 25, "Generators", "Building", "Factory" + "Prod_Bonus", 25, "Generators", "Building", "Mfg. Plant" + "Pollu_Prod_Pct", 2, "Janitors" } sound = "b_hydro_plant" sound_alt = "b_generic" @@ -501,8 +561,8 @@ upkeep = 1 sabotage = 100 effect = - { "type", "range", "amount" - "Science_Bonus", "City", 50 + { "name", "value" + "Science_Bonus", 50 } sound = "b_library" sound_alt = "b_generic" @@ -528,9 +588,9 @@ upkeep = 1 sabotage = 100 effect = - { "type", "range", "amount" - "Tax_Bonus", "City", 50 - "Luxury_Bonus", "City", 50 + { "name", "value" + "Tax_Bonus", 50 + "Luxury_Bonus", 50 } sound = "b_marketplace" sound_alt = "b_generic" @@ -556,8 +616,8 @@ upkeep = 4 sabotage = 100 effect = - { "type", "range", "amount" - "Pollu_Pop_Pct", "City", 0 + { "name", "value" + "Pollu_Pop_Pct", 100 } sound = "b_mass_transit" sound_alt = "b_generic" @@ -584,8 +644,8 @@ upkeep = 6 sabotage = 100 effect = - { "type", "range", "amount", "cond_bldg" - "Prod_Bonus", "City", 50, "Factory" + { "name", "value", "req_type", "req" + "Prod_Bonus", 50, "Building", "Factory" } sound = "b_mfg_plant" sound_alt = "b_generic" @@ -612,10 +672,10 @@ upkeep = 2 sabotage = 100 effect = - { "type", "range", "amount", "cond_bldg" - "Prod_Bonus", "City", 50, "Factory" - "Pollu_Prod_Pct", "City", 50 - "Pollu_Prod_Pct", "City", -50, "Recycling Center" + { "name", "value", "equiv", "req_type", "req" + "Prod_Bonus", 25, "Generators", "Building", "Factory" + "Prod_Bonus", 25, "Generators", "Building", "Mfg. Plant" + "Pollu_Prod_Pct", 2, "Janitors" } sound = "b_nuclear_plant" sound_alt = "b_generic" @@ -653,8 +713,8 @@ upkeep = 3 sabotage = 100 effect = - { "type", "range", "amount", "aff_terr", "aff_spec" - "Prod_Add_Tile", "City", 1, "Ocean", "None" + { "name", "value", "req_type", "req" + "Prod_Add_Tile", 1, "Terrain", "Ocean" } sound = "b_offshore_platform" sound_alt = "b_generic" @@ -680,10 +740,12 @@ upkeep = 0 sabotage = 0 effect = - { "type", "range", "amount" - "Capital_City", "City" - "Capital_Exists", "Player" - "Spy_Resistant", "City", 50 + { "name", "value", "equiv" + "Corrupt_Pct", 50, "Purifiers" + "Waste_Pct", 50, "Purifiers" + "Spy_Resistant", 50 + "No_Incite" + "Capital_City" } sound = "b_palace" sound_alt = "b_generic" @@ -717,9 +779,9 @@ upkeep = 2 sabotage = 100 effect = - { "type", "range", "amount", "cond_gov" - "Make_Content_Mil", "City", 1, "Republic" - "Make_Content_Mil", "City", 2, "Democracy" + { "name", "value", "equiv", "req_type", "req" + "Make_Content_Mil", 1, "Peacekeepers", "Gov", "Republic" + "Make_Content_Mil", 2, "Peacekeepers", "Gov", "Democracy" } sound = "b_police_station" sound_alt = "b_generic" @@ -746,9 +808,9 @@ upkeep = 3 sabotage = 100 effect = - { "type", "range", "aff_unit" - "Unit_Veteran", "City", "Sea" - "Unit_Repair", "City", "Sea" + { "name" + "Sea_Veteran" + "Sea_Regen" } sound = "b_port_facility" sound_alt = "b_generic" @@ -775,8 +837,9 @@ upkeep = 4 sabotage = 100 effect = - { "type", "range", "amount", "cond_bldg" - "Prod_Bonus", "City", 50, "Factory" + { "name", "value", "equiv", "req_type", "req" + "Prod_Bonus", 25, "Generators", "Building", "Factory" + "Prod_Bonus", 25, "Generators", "Building", "Mfg. Plant" } sound = "b_power_plant" sound_alt = "b_generic" @@ -809,8 +872,8 @@ upkeep = 2 sabotage = 100 effect = - { "type", "range", "amount" - "Pollu_Prod_Pct", "City", 34 + { "name", "value", "equiv" + "Pollu_Prod_Pct", 3, "Janitors" } sound = "b_recycling_center" sound_alt = "b_generic" @@ -837,8 +900,8 @@ upkeep = 3 sabotage = 100 effect = - { "type", "range", "amount", "cond_bldg" - "Science_Bonus", "City", 50, "Library" + { "name", "value", "equiv", "req_type", "req" + "Science_Bonus", 50, "Labs", "Building", "Library" } sound = "b_research_lab" sound_alt = "b_generic" @@ -866,9 +929,8 @@ upkeep = 2 sabotage = 100 effect = - { "type", "range", "amount", "aff_unit" - "Unit_Defend", "City", 200, "Air" - "Unit_Defend", "City", 200, "Missile" + { "name", "value" + "Air_Defend", 100 } sound = "b_sam_battery" sound_alt = "b_generic" @@ -894,9 +956,9 @@ upkeep = 4 sabotage = 100 effect = - { "type", "range", "amount", "aff_unit" - "Nuke_Proof", "City", 3 - "Unit_Defend", "City", 200, "Missile" + { "name", "value" + "Nuke_Proof" + "Missile_Defend", 100 } sound = "b_sdi_defense" sound_alt = "b_generic" @@ -924,9 +986,9 @@ build_cost = 120 upkeep = 2 sabotage = 100 -effect = - { "type", "range", "amount", "cond_bldg" - "Size_Unlimit", "City", 12, "Aqueduct" +effect = + { "name", "req_type", "req" + "Size_Unlimit", "Building", "Aqueduct" } sound = "b_sewer_system" sound_alt = "b_generic" @@ -951,12 +1013,6 @@ build_cost = 320 upkeep = 4 sabotage = 100 -effect = - { "type", "range", "amount", "cond_bldg" - "Prod_Bonus", "City", 50, "Factory" - "Pollu_Prod_Pct", "City", 0 - "Slow_Global_Warm", "World", 10 - } sound = "b_solar_plant" sound_alt = "b_generic" ; /* xgettext:no-c-format */ @@ -990,9 +1046,9 @@ build_cost = 160 upkeep = 0 sabotage = 100 -effect = - { "type", "range" - "SS_Component", "Local" +effect = + { "name" + "SS_Component" } sound = "b_space_component" sound_alt = "b_generic" @@ -1021,9 +1077,9 @@ build_cost = 320 upkeep = 0 sabotage = 100 -effect = - { "type", "range" - "SS_Module", "Local" +effect = + { "name" + "SS_Module" } sound = "b_space_module" sound_alt = "b_generic" @@ -1061,9 +1117,9 @@ build_cost = 80 upkeep = 0 sabotage = 100 -effect = - { "type", "range" - "SS_Structural", "Local" +effect = + { "name" + "SS_Structural" } sound = "b_space_structural" sound_alt = "b_generic" @@ -1093,9 +1149,9 @@ upkeep = 4 sabotage = 100 effect = - { "type", "range", "amount", "cond_bldg" - "Tax_Bonus", "City", 50, "Bank" - "Luxury_Bonus", "City", 50, "Bank" + { "name", "value", "req_type", "req" + "Tax_Bonus", 50, "Building", "Bank" + "Luxury_Bonus", 50, "Building", "Bank" } sound = "b_stock_exchange" sound_alt = "b_generic" @@ -1122,9 +1178,8 @@ upkeep = 3 sabotage = 100 effect = - { "type", "range", "amount", "aff_terr", "aff_spec" - "Trade_Per_Tile", "City", 50, "None", "Road" - "Trade_Route_Pct", "City", 10 + { "name", "value", "req_type", "req" + "Trade_Per_Tile", 50, "Special", "Road" } sound = "b_super_highways" sound_alt = "b_generic" @@ -1151,8 +1206,8 @@ upkeep = 3 sabotage = 100 effect = - { "type", "range", "amount", "aff_terr", "aff_spec" - "Food_Per_Tile", "City", 50, "None", "Farmland" + { "name", "value", "req_type", "req" + "Food_Per_Tile", 50, "Special", "Farmland" } sound = "b_supermarket" sound_alt = "b_generic" @@ -1180,9 +1235,9 @@ upkeep = 1 sabotage = 100 effect = - { "type", "range", "amount", "cond_adv" - "Make_Content", "City", 1 - "Make_Content", "City", 1, "Mysticism" + { "name", "value", "req_type", "req" + "Make_Content", 1 + "Make_Content", 1, "Tech", "Mysticism" } sound = "b_temple" sound_alt = "b_generic" @@ -1209,8 +1264,8 @@ upkeep = 3 sabotage = 100 effect = - { "type", "range", "amount", "cond_bldg" - "Science_Bonus", "City", 50, "Library" + { "name", "value", "req_type", "req" + "Science_Bonus", 50, "Building", "Library" } sound = "b_university" sound_alt = "b_generic" @@ -1237,9 +1292,9 @@ upkeep = 0 sabotage = 0 effect = - { "type", "range", "survives" - "Reveal_Map", "Player", 0 - "Enable_Space", "World", 1 + { "name", "range", "survives" + "Reveal_Map", "Player", 0 + "Enable_Space", "World", 1 } sound = "w_apollo_program" sound_alt = "w_generic" @@ -1266,8 +1321,8 @@ upkeep = 0 sabotage = 0 effect = - { "type", "range", "amount" - "Upkeep_Free", "Player", 1 + { "name", "range", "value" + "Upkeep_Free", "Player", 1 } sound = "w_asmiths_trading_co" sound_alt = "w_generic" @@ -1293,8 +1348,8 @@ upkeep = 0 sabotage = 0 effect = - { "type", "range", "amount" - "Trade_Inc_Tile", "City", 1 + { "name", "value" + "Trade_Inc_Tile", 1 } sound = "w_colossus" sound_alt = "w_generic" @@ -1320,8 +1375,8 @@ upkeep = 0 sabotage = 0 effect = - { "type", "range", "amount" - "Science_Bonus", "City", 50 + { "name", "value" + "Science_Bonus", 50 } sound = "w_copernicus_observatory" sound_alt = "w_generic" @@ -1347,8 +1402,8 @@ upkeep = 0 sabotage = 0 effect = - { "type", "range", "amount" - "Make_Happy", "Player", 1 + { "name", "range", "value" + "Force_Content", "Player", 1 } sound = "w_cure_for_cancer" sound_alt = "w_generic" @@ -1374,8 +1429,8 @@ upkeep = 0 sabotage = 0 effect = - { "type", "range", "amount" - "Give_Imm_Adv", "Player", 2 + { "name", "range", "value" + "Give_Imm_Tech", "Player", 2 } sound = "w_darwins_voyage" sound_alt = "w_generic" @@ -1401,10 +1456,6 @@ build_cost = 300 upkeep = 0 sabotage = 0 -effect = - { "type", "range", "amount" - "Improve_Rep", "Player", 25 - } sound = "w_eiffel_tower" sound_alt = "w_generic" ; /* xgettext:no-c-format */ @@ -1432,8 +1483,8 @@ upkeep = 0 sabotage = 0 effect = - { "type", "range", "amount" - "Adv_Parasite", "Player", 2 + { "name", "range", "value" + "Tech_Parasite", "Player", 2 } sound = "w_great_library" sound_alt = "w_generic" @@ -1459,10 +1510,9 @@ upkeep = 0 sabotage = 0 effect = - { "type", "range", "amount", "aff_unit" - "Unit_Defend", "Player", 300, "Land" - "Unit_No_Lose_Pop", "Player", 0, "Land" - "Barb_Attack", "Player", 200 + { "name", "range", "value", "equiv" + "Land_Defend", "Player", 200, "Defenders" + "Unit_No_Lose_Pop", "Player" } sound = "w_great_wall" sound_alt = "w_generic" @@ -1489,9 +1539,9 @@ upkeep = 0 sabotage = 0 effect = - { "type", "range", "amount" - "Make_Happy", "Player", 1 - "Make_Happy", "City", 2 + { "name", "range", "value" + "Make_Happy", "Player", 1 + "Make_Happy", "City", 2 } sound = "w_hanging_gardens" sound_alt = "w_generic" @@ -1520,10 +1570,10 @@ upkeep = 0 sabotage = 0 effect = - { "type", "range", "amount", "cond_bldg" - "Prod_Bonus", "Player", 50, "Factory" - "Pollu_Prod_Pct", "Player", 50 - "Pollu_Prod_Pct", "Player", -50, "Recycling Center" + { "name", "range", "value", "equiv", "req_type", "req" + "Prod_Bonus", "Player", 25, "Generators", "Building", "Factory" + "Prod_Bonus", "Player", 25, "Generators", "Building", "Mfg. Plant" + "Pollu_Prod_Pct", "Player", 2, "Janitors" } sound = "w_hoover_dam" sound_alt = "w_generic" @@ -1549,8 +1599,8 @@ upkeep = 0 sabotage = 0 effect = - { "type", "range", "amount" - "Science_Bonus", "City", 100 + { "name", "value" + "Science_Bonus", 100 } sound = "w_isaac_newtons_college" sound_alt = "w_generic" @@ -1576,8 +1626,8 @@ upkeep = 0 sabotage = 0 effect = - { "type", "range", "amount" - "Make_Content", "Player", 2 + { "name", "range", "value" + "Force_Content", "Player", 2 } sound = "w_js_bachs_cathedral" sound_alt = "w_generic" @@ -1602,8 +1652,8 @@ upkeep = 0 sabotage = 0 effect = - { "type", "range", "amount" - "Prod_Add_Tile", "City", 1 + { "name", "value" + "Prod_Add_Tile", 1 } sound = "w_king_richards_crusade" sound_alt = "w_generic" @@ -1629,8 +1679,8 @@ upkeep = 0 sabotage = 0 effect = - { "type", "range", "amount" - "Upgrade_One_Leap", "Player", 100 + { "name", "range", "value" + "Upgrade_Unit", "Player", 1 } sound = "w_leonardos_workshop" sound_alt = "w_generic" @@ -1655,10 +1705,10 @@ upkeep = 0 sabotage = 0 effect = - { "type", "range", "amount", "aff_unit" - "Unit_Move", "Player", 1, "Sea" - "No_Sink_Deep", "Player" - "Unit_Veteran", "Player", 0, "Sea" + { "name", "range", "value" + "Sea_Move", "Player", 1 + "No_Sink_Deep", "Player" + "Sea_Veteran", "Player" } sound = "w_lighthouse" sound_alt = "w_generic" @@ -1685,8 +1735,8 @@ upkeep = 0 sabotage = 0 effect = - { "type", "range", "amount", "aff_unit" - "Unit_Move", "Player", 2, "Sea" + { "name", "range", "value" + "Sea_Move", "Player", 2 } sound = "w_magellans_expedition" sound_alt = "w_generic" @@ -1711,8 +1761,8 @@ upkeep = 0 sabotage = 0 effect = - { "type", "range", "survives" - "Enable_Nuke", "World", 1 + { "name", "range", "survives" + "Enable_Nuke", "World", 1 } sound = "w_manhattan_project" sound_alt = "w_generic" @@ -1736,8 +1786,8 @@ upkeep = 0 sabotage = 0 effect = - { "type", "range" - "Have_Embassies", "Player" + { "name", "range" + "Have_Embassies", "Player" } sound = "w_marco_polos_embassy" sound_alt = "w_generic" @@ -1762,10 +1812,10 @@ upkeep = 0 sabotage = 0 effect = - { "type", "range", "amount", "cond_adv" - "Make_Content", "Player", 3 - "Make_Content", "Player", 1, "Theology" - "Make_Content", "Player", -1, "Communism" + { "name", "range", "value", "equiv", "req_type", "req" + "Make_Content", "Player", 3, "Cathedrals" + "Make_Content", "Player", 1, "Cathedrals", "Tech", "Theology" + "Make_Content", "Player", -1, "Cathedrals", "Tech", "Communism" } sound = "w_michelangelos_chapel" sound_alt = "w_generic" @@ -1795,9 +1845,8 @@ upkeep = 0 sabotage = 0 effect = - { "type", "range", "amount", "cond_bldg", "cond_adv" - "Make_Content", "Player", 1, "Temple" - "Make_Content", "Player", 1, "Temple", "Mysticism" + { "name", "value", "req_type", "req" + "Make_Content", 2, "Building", "Temple" } sound = "w_oracle" sound_alt = "w_generic" @@ -1822,8 +1871,8 @@ upkeep = 0 sabotage = 0 effect = - { "type", "range", "amount" - "Growth_Food", "Player", 50 + { "name", "range" + "Growth_Food", "Player" } sound = "w_pyramids" sound_alt = "w_generic" @@ -1848,8 +1897,8 @@ upkeep = 0 sabotage = 0 effect = - { "type", "range", "amount", "cond_bldg" - "Science_Bonus", "Player", 50, "Library" + { "name", "range", "value", "equiv", "req_type", "req" + "Science_Bonus", "Player", 50, "Labs", "Building", "Library" } sound = "w_seti_program" sound_alt = "w_generic" @@ -1875,8 +1924,8 @@ upkeep = 0 sabotage = 0 effect = - { "type", "range", "amount" - "Make_Content", "City", 99 + { "name" + "No_Unhappy" } sound = "w_shakespeares_theatre" sound_alt = "w_generic" @@ -1901,9 +1950,9 @@ upkeep = 0 sabotage = 0 effect = - { "type", "range" - "Any_Government", "Player" - "No_Anarchy", "Player" + { "name", "range" + "Any_Government", "Player" + "No_Anarchy", "Player" } sound = "w_statue_of_liberty" sound_alt = "w_generic" @@ -1930,9 +1979,9 @@ upkeep = 0 sabotage = 0 effect = - { "type", "range", "amount", "aff_unit" - "Unit_Veteran", "Player", 0, "Land" - "Unit_Vet_Combat", "Player", 100, "Land" + { "name", "range", "value" + "Land_Veteran", "Player" + "Land_Vet_Combat", "Player", 100 } sound = "w_sun_tzus_war_academy" sound_alt = "w_generic" @@ -1959,12 +2008,8 @@ upkeep = 0 sabotage = 0 effect = - { "type", "range", "amount", "aff_unit" - "Unit_Recover", "Player", 2, "Air" - "Unit_Recover", "Player", 2, "Helicopter" - "Unit_Recover", "Player", 2, "Land" - "Unit_Recover", "Player", 2, "Missile" - "Unit_Recover", "Player", 2, "Sea" + { "name", "range", "value" + "Unit_Recover", "Player", 2 } sound = "w_united_nations" sound_alt = "w_generic" @@ -1997,9 +2042,9 @@ upkeep = 0 sabotage = 0 effect = - { "type", "range", "amount", "cond_gov" - "Make_Content_Mil", "Player", 1, "Republic" - "Make_Content_Mil", "Player", 2, "Democracy" + { "name", "range", "value", "equiv", "req_type", "req" + "Make_Content_Mil", "Player", 1, "Peacekeepers", "Gov", "Republic" + "Make_Content_Mil", "Player", 2, "Peacekeepers", "Gov", "Democracy" } sound = "w_womens_suffrage" sound_alt = "w_generic" @@ -2027,8 +2072,8 @@ upkeep = 0 sabotage = 0 effect = - { "type", "range", "amount" - "Prod_To_Gold", "City", 100 + { "name" + "Prod_To_Gold" } helptext = _("\ This is not a normal improvement. Instead, setting a city's\ @@ -2037,14 +2082,16 @@ ") -; FIXME: remove all of the following when gen-impr implemented... - [b_special] ; Special values: aqueduct_size=8; -sewer_size=12; +default="Capitalization" + +; FIXME: remove all of the following when gen-impr implemented... + +sewer_size=12 ; Techs which modify building effects: Index: data/default/buildings.ruleset =================================================================== RCS file: /home/freeciv/CVS/freeciv/data/default/buildings.ruleset,v retrieving revision 1.51 diff -u -r1.51 buildings.ruleset --- data/default/buildings.ruleset 4 Sep 2004 20:19:51 -0000 1.51 +++ data/default/buildings.ruleset 6 Sep 2004 01:11:12 -0000 @@ -58,19 +58,92 @@ ; build_cost = production shields required to build ; upkeep = monetary upkeep value ; sabotage = percent chance of diplomat sabotage being successful -; effect { = list of named effects (and parameters thereto): +; effect { = list of effects; parameters are: ; ; ( See doc/README.effects for information and a listing of effects. ) ; -; } (All effects in list(s) are cumulative.) -; sound = optional sound effect associated -; sound_alt = optional alternative sound effect if above not -; supported in client -; helptext = optional help text string; should escape all raw -; newlines so that xgettext parsing works +; eff = effect name; e.g. "Tax_Bonus" +; range = effect range; one of: +; "Local", "City", "Continent", "Player", "World". +; by ommission the range is "City". +; value = modifier value of effect; by ommission +1. +; type = requirement type; one of: +; "None", "Tech", "Gov", "Building", "Special", "Terrain". +; by ommission the type is "None". +; req = requirement data; varies with requirement type. +; +; } the effects in the list are cumulative. ; ; */ <-- avoid gettext warnings +; +; Effect groups are a convenience mechanism to handle +; equivalent effects which may be done by one of several buildings. +; The first building in the 'buildings' list of the group which +; exists wins. +; + +[group_cathedrals] +name = "Cathedrals" +elements = + { "building", "range" + "Michelangelo's Chapel", "Player" + "Cathedral", "City" + } + +[group_labs] +name = "Labs" +elements = + { "building", "range" + "SETI Program", "Player" + "Research Lab", "City" + } + +[group_generators] +name = "Generators" +elements = + { "building", "range" + "Hoover Dam", "Player" + "Nuclear Plant", "City" + "Hydro Plant", "City" + "Power Plant", "City" + } + +[group_janitors] +name = "Janitors" +elements = + { "building", "range" + "Recycling Center", "City" + "Hoover Dam", "Player" + "Nuclear Plant", "City" + "Hydro Plant", "City" + } + +[group_defenders] +name = "Defenders" +elements = + { "building", "range" + "Great Wall", "Player" + "City Walls", "City" + } + +[group_peacekeepers] +name = "Peacekeepers" +elements = + { "building", "range" + "Women's Suffrage", "Player" + "Police Station", "City" + } + +[group_purifiers] +name = "Purifiers" +elements = + { "building", "range" + "Palace", "City" + "Courthouse", "City" + } + + [building_airport] name = _("Airport") tech_req = "Radio" @@ -88,10 +161,10 @@ upkeep = 3 sabotage = 100 effect = - { "type", "range", "aff_unit" - "Unit_Veteran", "City", "Air" - "Unit_Repair", "City", "Air" - "Airlift", "City" + { "name" + "Air_Veteran" + "Air_Regen" + "Airlift" } sound = "b_airport" sound_alt = "b_generic" @@ -122,9 +195,9 @@ build_cost = 60 upkeep = 2 sabotage = 100 -effect = - { "type", "range", "amount" - "Size_Unlimit", "City", 8 +effect = + { "name", "value" + "Size_Adj", 4 } sound = "b_aqueduct" sound_alt = "b_generic" @@ -150,9 +223,9 @@ upkeep = 2 sabotage = 100 effect = - { "type", "range", "amount", "cond_bldg" - "Tax_Bonus", "City", 50, "Marketplace" - "Luxury_Bonus", "City", 50, "Marketplace" + { "name", "value", "req_type", "req" + "Tax_Bonus", 50, "Building", "Marketplace" + "Luxury_Bonus", 50, "Building", "Marketplace" } sound = "b_bank" sound_alt = "b_generic" @@ -174,14 +247,15 @@ ;equiv_dupl = equiv_repl = "Sun Tzu's War Academy","Barracks II", "Barracks III" obsolete_by = "Gunpowder" +replaced_by = "Barracks II" is_wonder = 0 build_cost = 30 upkeep = 1 sabotage = 100 effect = - { "type", "range", "aff_unit" - "Unit_Veteran", "City", "Land" - "Unit_Repair", "City", "Land" + { "name" + "Land_Veteran" + "Land_Regen" } sound = "b_barracks_i" sound_alt = "b_generic" @@ -205,14 +279,15 @@ ;equiv_dupl = equiv_repl = "Sun Tzu's War Academy", "Barracks III" obsolete_by = "Mobile Warfare" +replaced_by = "Barracks III" is_wonder = 0 build_cost = 30 upkeep = 1 sabotage = 100 effect = - { "type", "range", "aff_unit" - "Unit_Veteran", "City", "Land" - "Unit_Repair", "City", "Land" + { "name" + "Land_Veteran" + "Land_Regen" } sound = "b_barracks_ii" sound_alt = "b_generic" @@ -241,9 +316,9 @@ upkeep = 1 sabotage = 100 effect = - { "type", "range", "aff_unit" - "Unit_Veteran", "City", "Land" - "Unit_Repair", "City", "Land" + { "name" + "Land_Veteran" + "Land_Regen" } sound = "b_barracks_iii" sound_alt = "b_generic" @@ -272,10 +347,10 @@ upkeep = 3 sabotage = 100 effect = - { "type", "range", "amount", "cond_adv" - "Make_Content", "City", 3 - "Make_Content", "City", 1, "Theology" - "Make_Content", "City", -1, "Communism" + { "name", "value", "equiv", "req_type", "req" + "Make_Content", 3, "Cathedrals" + "Make_Content", 1, "Cathedrals", "Tech", "Theology" + "Make_Content", -1, "Cathedrals", "Tech", "Communism" } sound = "b_cathedral" sound_alt = "b_generic" @@ -305,11 +380,9 @@ upkeep = 0 sabotage = 50 effect = - { "type", "range", "amount", "cond_bldg", "aff_unit" - "Unit_Defend", "City", 300, "", "Land" - "Unit_No_Lose_Pop", "City", 0, "", "Land" - "Spy_Resistant", "Local", 50 - "Spy_Resistant", "Local", -50, "Palace" + { "name", "value", "equiv" + "Land_Defend", 200, "Defenders" + "Unit_No_Lose_Pop" } sound = "b_city_walls" sound_alt = "b_generic" @@ -338,8 +411,8 @@ upkeep = 1 sabotage = 100 effect = - { "type", "range", "amount", "aff_unit" - "Unit_Defend", "City", 200, "Sea" + { "name", "value" + "Sea_Defend", 100 } sound = "b_coastal_defense" sound_alt = "b_generic" @@ -365,9 +438,9 @@ upkeep = 4 sabotage = 100 effect = - { "type", "range", "amount", "cond_adv" - "Make_Content", "City", 3 - "Make_Content", "City", 1, "Electricity" + { "name", "value", "req_type", "req" + "Make_Content", 3 + "Make_Content", 1, "Tech", "Electricity" } sound = "b_colosseum" sound_alt = "b_generic" @@ -395,10 +468,11 @@ upkeep = 1 sabotage = 100 effect = - { "type", "range", "amount", "cond_gov" - "Corrupt_Pct", "City", 50 - "Make_Content", "City", 1, "Democracy" - "Revolt_Dist_Pct", "City", 50 + { "name", "value", "equiv", "req_type", "req" + "Corrupt_Pct", 50, "Purifiers" + "Waste_Pct", 50, "Purifiers" + "Make_Content", 1, "", "Gov", "Democracy" + "Incite_Dist_Pct", 75 } sound = "b_courthouse" sound_alt = "b_generic" @@ -426,8 +500,8 @@ upkeep = 4 sabotage = 100 effect = - { "type", "range", "amount" - "Prod_Bonus", "City", 50 + { "name", "value" + "Prod_Bonus", 50 } sound = "b_factory" sound_alt = "b_generic" @@ -453,8 +527,8 @@ upkeep = 1 sabotage = 100 effect = - { "type", "range", "amount" - "Growth_Food", "City", 50 + { "name", "value" + "Growth_Food", 50 } sound = "b_granary" sound_alt = "b_generic" @@ -484,8 +558,8 @@ upkeep = 1 sabotage = 100 effect = - { "type", "range", "amount", "aff_terr", "aff_spec" - "Food_Add_Tile", "City", 1, "Ocean", "None" + { "name", "value", "req_type", "req" + "Food_Add_Tile", 1, "Terrain", "Ocean" } sound = "b_harbour" sound_alt = "b_generic" @@ -511,11 +585,10 @@ upkeep = 4 sabotage = 100 effect = - { "type", "range", "amount", "cond_bldg" - "Prod_Bonus", "City", 25, "Factory" - "Prod_Bonus", "City", 25, "Mfg. Plant" - "Pollu_Prod_Pct", "City", 50 - "Pollu_Prod_Pct", "City", -50, "Recycling Center" + { "name", "value", "equiv", "req_type", "req" + "Prod_Bonus", 25, "Generators", "Building", "Factory" + "Prod_Bonus", 25, "Generators", "Building", "Mfg. Plant" + "Pollu_Prod_Pct", 2, "Janitors" } sound = "b_hydro_plant" sound_alt = "b_generic" @@ -554,8 +627,8 @@ upkeep = 1 sabotage = 100 effect = - { "type", "range", "amount" - "Science_Bonus", "City", 50 + { "name", "value" + "Science_Bonus", 50 } sound = "b_library" sound_alt = "b_generic" @@ -581,9 +654,9 @@ upkeep = 0 sabotage = 100 effect = - { "type", "range", "amount" - "Tax_Bonus", "City", 50 - "Luxury_Bonus", "City", 50 + { "name", "value" + "Tax_Bonus", 50 + "Luxury_Bonus", 50 } sound = "b_marketplace" sound_alt = "b_generic" @@ -609,8 +682,8 @@ upkeep = 4 sabotage = 100 effect = - { "type", "range", "amount" - "Pollu_Pop_Pct", "City", 0 + { "name", "value" + "Pollu_Pop_Pct", 100 } sound = "b_mass_transit" sound_alt = "b_generic" @@ -637,8 +710,8 @@ upkeep = 6 sabotage = 100 effect = - { "type", "range", "amount", "cond_bldg" - "Prod_Bonus", "City", 50, "Factory" + { "name", "value", "req_type", "req" + "Prod_Bonus", 50, "Building", "Factory" } sound = "b_mfg_plant" sound_alt = "b_generic" @@ -665,11 +738,10 @@ upkeep = 2 sabotage = 100 effect = - { "type", "range", "amount", "cond_bldg" - "Prod_Bonus", "City", 25, "Factory" - "Prod_Bonus", "City", 25, "Mfg. Plant" - "Pollu_Prod_Pct", "City", 50 - "Pollu_Prod_Pct", "City", -50, "Recycling Center" + { "name", "value", "equiv", "req_type", "req" + "Prod_Bonus", 25, "Generators", "Building", "Factory" + "Prod_Bonus", 25, "Generators", "Building", "Mfg. Plant" + "Pollu_Prod_Pct", 2, "Janitors" } sound = "b_nuclear_plant" sound_alt = "b_generic" @@ -709,8 +781,8 @@ upkeep = 3 sabotage = 100 effect = - { "type", "range", "amount", "aff_terr", "aff_spec" - "Prod_Add_Tile", "City", 1, "Ocean", "None" + { "name", "value", "req_type", "req" + "Prod_Add_Tile", 1, "Terrain", "Ocean" } sound = "b_offshore_platform" sound_alt = "b_generic" @@ -736,10 +808,12 @@ upkeep = 0 sabotage = 0 effect = - { "type", "range", "amount" - "Capital_City", "City" - "Capital_Exists", "Player" - "Spy_Resistant", "City", 50 + { "name", "value", "equiv" + "Corrupt_Pct", 50, "Purifiers" + "Waste_Pct", 50, "Purifiers" + "Spy_Resistant", 50 + "No_Incite" + "Capital_City" } sound = "b_palace" sound_alt = "b_generic" @@ -773,9 +847,9 @@ upkeep = 2 sabotage = 100 effect = - { "type", "range", "amount", "cond_gov" - "Make_Content_Mil", "City", 1, "Republic" - "Make_Content_Mil", "City", 2, "Democracy" + { "name", "value", "equiv", "req_type", "req" + "Make_Content_Mil", 1, "Peacekeepers", "Gov", "Republic" + "Make_Content_Mil", 2, "Peacekeepers", "Gov", "Democracy" } sound = "b_police_station" sound_alt = "b_generic" @@ -805,9 +879,9 @@ upkeep = 3 sabotage = 100 effect = - { "type", "range", "aff_unit" - "Unit_Veteran", "City", "Sea" - "Unit_Repair", "City", "Sea" + { "name" + "Sea_Veteran" + "Sea_Regen" } sound = "b_port_facility" sound_alt = "b_generic" @@ -834,9 +908,9 @@ upkeep = 4 sabotage = 100 effect = - { "type", "range", "amount", "cond_bldg" - "Prod_Bonus", "City", 25, "Factory" - "Prod_Bonus", "City", 25, "Mfg. Plant" + { "name", "value", "equiv", "req_type", "req" + "Prod_Bonus", 25, "Generators", "Building", "Factory" + "Prod_Bonus", 25, "Generators", "Building", "Mfg. Plant" } sound = "b_power_plant" sound_alt = "b_generic" @@ -872,8 +946,8 @@ upkeep = 2 sabotage = 100 effect = - { "type", "range", "amount" - "Pollu_Prod_Pct", "City", 34 + { "name", "value", "equiv" + "Pollu_Prod_Pct", 3, "Janitors" } sound = "b_recycling_center" sound_alt = "b_generic" @@ -900,8 +974,8 @@ upkeep = 3 sabotage = 100 effect = - { "type", "range", "amount", "cond_bldg" - "Science_Bonus", "City", 50, "Library" + { "name", "value", "equiv", "req_type", "req" + "Science_Bonus", 50, "Labs", "Building", "Library" } sound = "b_research_lab" sound_alt = "b_generic" @@ -929,9 +1003,8 @@ upkeep = 2 sabotage = 100 effect = - { "type", "range", "amount", "aff_unit" - "Unit_Defend", "City", 200, "Air" - "Unit_Defend", "City", 200, "Missile" + { "name", "value" + "Air_Defend", 100 } sound = "b_sam_battery" sound_alt = "b_generic" @@ -957,9 +1030,9 @@ upkeep = 4 sabotage = 100 effect = - { "type", "range", "amount", "aff_unit" - "Nuke_Proof", "City", 3 - "Unit_Defend", "City", 200, "Missile" + { "name", "value" + "Nuke_Proof" + "Missile_Defend", 100 } sound = "b_sdi_defense" sound_alt = "b_generic" @@ -987,9 +1060,9 @@ build_cost = 80 upkeep = 2 sabotage = 100 -effect = - { "type", "range", "amount", "cond_bldg" - "Size_Unlimit", "City", 12, "Aqueduct" +effect = + { "name", "req_type", "req" + "Size_Unlimit", "Building", "Aqueduct" } sound = "b_sewer_system" sound_alt = "b_generic" @@ -1014,13 +1087,6 @@ build_cost = 220 upkeep = 4 sabotage = 100 -effect = - { "type", "range", "amount", "cond_bldg" - "Prod_Bonus", "City", 25, "Factory" - "Prod_Bonus", "City", 25, "Mfg. Plant" - "Pollu_Prod_Pct", "City", 0 - "Slow_Global_Warm", "World", 10 - } sound = "b_solar_plant" sound_alt = "b_generic" ; /* xgettext:no-c-format */ @@ -1057,9 +1123,9 @@ build_cost = 160 upkeep = 0 sabotage = 100 -effect = - { "type", "range" - "SS_Component", "Local" +effect = + { "name" + "SS_Component" } sound = "b_space_component" sound_alt = "b_generic" @@ -1088,9 +1154,9 @@ build_cost = 320 upkeep = 0 sabotage = 100 -effect = - { "type", "range" - "SS_Module", "Local" +effect = + { "name" + "SS_Module" } sound = "b_space_module" sound_alt = "b_generic" @@ -1128,9 +1194,9 @@ build_cost = 80 upkeep = 0 sabotage = 100 -effect = - { "type", "range" - "SS_Structural", "Local" +effect = + { "name" + "SS_Structural" } sound = "b_space_structural" sound_alt = "b_generic" @@ -1160,9 +1226,9 @@ upkeep = 3 sabotage = 100 effect = - { "type", "range", "amount", "cond_bldg" - "Tax_Bonus", "City", 50, "Bank" - "Luxury_Bonus", "City", 50, "Bank" + { "name", "value", "req_type", "req" + "Tax_Bonus", 50, "Building", "Bank" + "Luxury_Bonus", 50, "Building", "Bank" } sound = "b_stock_exchange" sound_alt = "b_generic" @@ -1189,8 +1255,8 @@ upkeep = 3 sabotage = 100 effect = - { "type", "range", "amount", "aff_terr", "aff_spec" - "Trade_Per_Tile", "City", 50, "None", "Road" + { "name", "value", "req_type", "req" + "Trade_Per_Tile", 50, "Special", "Road" } sound = "b_super_highways" sound_alt = "b_generic" @@ -1219,8 +1285,8 @@ upkeep = 3 sabotage = 100 effect = - { "type", "range", "amount", "aff_terr", "aff_spec" - "Food_Per_Tile", "City", 50, "None", "Farmland" + { "name", "value", "req_type", "req" + "Food_Per_Tile", 50, "Special", "Farmland" } sound = "b_supermarket" sound_alt = "b_generic" @@ -1248,9 +1314,9 @@ upkeep = 1 sabotage = 100 effect = - { "type", "range", "amount", "cond_adv" - "Make_Content", "City", 1 - "Make_Content", "City", 1, "Mysticism" + { "name", "value", "req_type", "req" + "Make_Content", 1 + "Make_Content", 1, "Tech", "Mysticism" } sound = "b_temple" sound_alt = "b_generic" @@ -1277,8 +1343,8 @@ upkeep = 3 sabotage = 100 effect = - { "type", "range", "amount", "cond_bldg" - "Science_Bonus", "City", 50, "Library" + { "name", "value", "req_type", "req" + "Science_Bonus", 50, "Building", "Library" } sound = "b_university" sound_alt = "b_generic" @@ -1305,9 +1371,9 @@ upkeep = 0 sabotage = 0 effect = - { "type", "range", "survives" - "Reveal_Map", "Player", 0 - "Enable_Space", "World", 1 + { "name", "range", "survives" + "Reveal_Map", "Player", 0 + "Enable_Space", "World", 1 } sound = "w_apollo_program" sound_alt = "w_generic" @@ -1334,8 +1400,8 @@ upkeep = 0 sabotage = 0 effect = - { "type", "range", "amount" - "Upkeep_Free", "Player", 1 + { "name", "range", "value" + "Upkeep_Free", "Player", 1 } sound = "w_asmiths_trading_co" sound_alt = "w_generic" @@ -1361,8 +1427,8 @@ upkeep = 0 sabotage = 0 effect = - { "type", "range", "amount" - "Trade_Inc_Tile", "City", 1 + { "name", "value" + "Trade_Inc_Tile", 1 } sound = "w_colossus" sound_alt = "w_generic" @@ -1388,8 +1454,8 @@ upkeep = 0 sabotage = 0 effect = - { "type", "range", "amount" - "Science_Bonus", "City", 50 + { "name", "value" + "Science_Bonus", 50 } sound = "w_copernicus_observatory" sound_alt = "w_generic" @@ -1415,8 +1481,8 @@ upkeep = 0 sabotage = 0 effect = - { "type", "range", "amount" - "Make_Content", "Player", 1 + { "name", "range", "value" + "Force_Content", "Player", 1 } sound = "w_cure_for_cancer" sound_alt = "w_generic" @@ -1444,8 +1510,8 @@ upkeep = 0 sabotage = 0 effect = - { "type", "range", "amount" - "Give_Imm_Adv", "Player", 2 + { "name", "range", "value" + "Give_Imm_Tech", "Player", 2 } sound = "w_darwins_voyage" sound_alt = "w_generic" @@ -1471,10 +1537,6 @@ build_cost = 300 upkeep = 0 sabotage = 0 -effect = - { "type", "range", "amount" - "Improve_Rep", "Player", 25 - } sound = "w_eiffel_tower" sound_alt = "w_generic" ; /* xgettext:no-c-format */ @@ -1502,8 +1564,8 @@ upkeep = 0 sabotage = 0 effect = - { "type", "range", "amount" - "Adv_Parasite", "Player", 2 + { "name", "range", "value" + "Tech_Parasite", "Player", 2 } sound = "w_great_library" sound_alt = "w_generic" @@ -1529,9 +1591,9 @@ upkeep = 0 sabotage = 0 effect = - { "type", "range", "amount", "aff_unit" - "Unit_Defend", "Player", 300, "Land" - "Unit_No_Lose_Pop", "Player", 0, "Land" + { "name", "range", "value", "equiv" + "Land_Defend", "Player", 200, "Defenders" + "Unit_No_Lose_Pop", "Player" } sound = "w_great_wall" sound_alt = "w_generic" @@ -1559,9 +1621,9 @@ upkeep = 0 sabotage = 0 effect = - { "type", "range", "amount" - "Make_Happy", "Player", 1 - "Make_Happy", "City", 2 + { "name", "range", "value" + "Make_Happy", "Player", 1 + "Make_Happy", "City", 2 } sound = "w_hanging_gardens" sound_alt = "w_generic" @@ -1590,11 +1652,10 @@ upkeep = 0 sabotage = 0 effect = - { "type", "range", "amount", "cond_bldg" - "Prod_Bonus", "Player", 25, "Factory" - "Prod_Bonus", "Player", 25, "Mfg. Plant" - "Pollu_Prod_Pct", "Player", 50 - "Pollu_Prod_Pct", "Player", -50, "Recycling Center" + { "name", "range", "value", "equiv", "req_type", "req" + "Prod_Bonus", "Player", 25, "Generators", "Building", "Factory" + "Prod_Bonus", "Player", 25, "Generators", "Building", "Mfg. Plant" + "Pollu_Prod_Pct", "Player", 2, "Janitors" } sound = "w_hoover_dam" sound_alt = "w_generic" @@ -1620,8 +1681,8 @@ upkeep = 0 sabotage = 0 effect = - { "type", "range", "amount" - "Science_Bonus", "City", 100 + { "name", "value" + "Science_Bonus", 100 } sound = "w_isaac_newtons_college" sound_alt = "w_generic" @@ -1647,8 +1708,8 @@ upkeep = 0 sabotage = 0 effect = - { "type", "range", "amount" - "Make_Content", "Player", 2 + { "name", "range", "value" + "Force_Content", "Player", 2 } sound = "w_js_bachs_cathedral" sound_alt = "w_generic" @@ -1673,8 +1734,8 @@ upkeep = 0 sabotage = 0 effect = - { "type", "range", "amount" - "Prod_Add_Tile", "City", 1 + { "name", "value" + "Prod_Add_Tile", 1 } sound = "w_king_richards_crusade" sound_alt = "w_generic" @@ -1691,7 +1752,7 @@ graphic_alt = "-" ;terr_gate = ;spec_gate = -equiv_range = "Player" +equiv_range = "None" ;equiv_dupl = ;equiv_repl = obsolete_by = "Automobile" @@ -1700,8 +1761,8 @@ upkeep = 0 sabotage = 0 effect = - { "type", "range", "amount" - "Upgrade_One_Leap", "Player", 100 + { "name", "range", "value" + "Upgrade_Unit", "Player", 1 } sound = "w_leonardos_workshop" sound_alt = "w_generic" @@ -1726,10 +1787,10 @@ upkeep = 0 sabotage = 0 effect = - { "type", "range", "amount", "aff_unit" - "Unit_Move", "Player", 1, "Sea" - "No_Sink_Deep", "Player" - "Unit_Veteran", "Player", 0, "Sea" + { "name", "range", "value" + "Sea_Move", "Player", 1 + "No_Sink_Deep", "Player" + "Sea_Veteran", "Player" } sound = "w_lighthouse" sound_alt = "w_generic" @@ -1747,7 +1808,7 @@ graphic_alt = "-" ;terr_gate = ;spec_gate = -equiv_range = "Player" +equiv_range = "None" ;equiv_dupl = ;equiv_repl = obsolete_by = "None" @@ -1756,8 +1817,8 @@ upkeep = 0 sabotage = 0 effect = - { "type", "range", "amount", "aff_unit" - "Unit_Move", "Player", 2, "Sea" + { "name", "range", "value" + "Sea_Move", "Player", 2 } sound = "w_magellans_expedition" sound_alt = "w_generic" @@ -1782,8 +1843,8 @@ upkeep = 0 sabotage = 0 effect = - { "type", "range", "survives" - "Enable_Nuke", "World", 1 + { "name", "range", "survives" + "Enable_Nuke", "World", 1 } sound = "w_manhattan_project" sound_alt = "w_generic" @@ -1807,8 +1868,8 @@ upkeep = 0 sabotage = 0 effect = - { "type", "range" - "Have_Embassies", "Player" + { "name", "range" + "Have_Embassies", "Player" } sound = "w_marco_polos_embassy" sound_alt = "w_generic" @@ -1833,10 +1894,10 @@ upkeep = 0 sabotage = 0 effect = - { "type", "range", "amount", "cond_adv" - "Make_Content", "Player", 3 - "Make_Content", "Player", 1, "Theology" - "Make_Content", "Player", -1, "Communism" + { "name", "range", "value", "equiv", "req_type", "req" + "Make_Content", "Player", 3, "Cathedrals" + "Make_Content", "Player", 1, "Cathedrals", "Tech", "Theology" + "Make_Content", "Player", -1, "Cathedrals", "Tech", "Communism" } sound = "w_michelangelos_chapel" sound_alt = "w_generic" @@ -1866,9 +1927,8 @@ upkeep = 0 sabotage = 0 effect = - { "type", "range", "amount", "cond_bldg", "cond_adv" - "Make_Content", "Player", 1, "Temple" - "Make_Content", "Player", 1, "Temple", "Mysticism" + { "name", "value", "req_type", "req" + "Make_Content", 2, "Building", "Temple" } sound = "w_oracle" sound_alt = "w_generic" @@ -1893,8 +1953,8 @@ upkeep = 0 sabotage = 0 effect = - { "type", "range", "amount" - "Growth_Food", "Player", 50 + { "name", "value", "range" + "Growth_Food", 50, "Player" } sound = "w_pyramids" sound_alt = "w_generic" @@ -1919,8 +1979,8 @@ upkeep = 0 sabotage = 0 effect = - { "type", "range", "amount", "cond_bldg" - "Science_Bonus", "Player", 50, "Library" + { "name", "range", "value", "equiv", "req_type", "req" + "Science_Bonus", "Player", 50, "Labs", "Building", "Library" } sound = "w_seti_program" sound_alt = "w_generic" @@ -1946,8 +2006,8 @@ upkeep = 0 sabotage = 0 effect = - { "type", "range", "amount" - "Make_Content", "City", 99 + { "name" + "No_Unhappy" } sound = "w_shakespeares_theatre" sound_alt = "w_generic" @@ -1972,9 +2032,9 @@ upkeep = 0 sabotage = 0 effect = - { "type", "range" - "Any_Government", "Player" - "No_Anarchy", "Player" + { "name", "range" + "Any_Government", "Player" + "No_Anarchy", "Player" } sound = "w_statue_of_liberty" sound_alt = "w_generic" @@ -2001,9 +2061,9 @@ upkeep = 0 sabotage = 0 effect = - { "type", "range", "amount", "aff_unit" - "Unit_Veteran", "Player", 0, "Land" - "Unit_Vet_Combat", "Player", 100, "Land" + { "name", "range", "value" + "Land_Veteran", "Player" + "Land_Vet_Combat", "Player", 50 } sound = "w_sun_tzus_war_academy" sound_alt = "w_generic" @@ -2030,12 +2090,8 @@ upkeep = 0 sabotage = 0 effect = - { "type", "range", "amount", "aff_unit" - "Unit_Recover", "Player", 2, "Air" - "Unit_Recover", "Player", 2, "Helicopter" - "Unit_Recover", "Player", 2, "Land" - "Unit_Recover", "Player", 2, "Missile" - "Unit_Recover", "Player", 2, "Sea" + { "name", "range", "value" + "Unit_Recover", "Player", 2 } sound = "w_united_nations" sound_alt = "w_generic" @@ -2068,9 +2124,9 @@ upkeep = 0 sabotage = 0 effect = - { "type", "range", "amount", "cond_gov" - "Make_Content_Mil", "Player", 1, "Republic" - "Make_Content_Mil", "Player", 2, "Democracy" + { "name", "range", "value", "equiv", "req_type", "req" + "Make_Content_Mil", "Player", 1, "Peacekeepers", "Gov", "Republic" + "Make_Content_Mil", "Player", 2, "Peacekeepers", "Gov", "Democracy" } sound = "w_womens_suffrage" sound_alt = "w_generic" @@ -2106,8 +2162,8 @@ upkeep = 0 sabotage = 0 effect = - { "type", "range", "amount" - "Prod_To_Gold", "City", 100 + { "name" + "Prod_To_Gold" } ; FIXME: this is the real helptext; restore when have a subordnate analogue ; /* (ignore for gettext until fixed) @@ -2124,14 +2180,16 @@ ") -; FIXME: remove all of the following when gen-impr implemented... - [b_special] ; Special values: -aqueduct_size=8; -sewer_size=12; +aqueduct_size=8 +default="Coinage" + +; FIXME: remove all of the following when gen-impr implemented... + +sewer_size=12 ; Techs which modify building effects: @@ -2139,3 +2197,4 @@ cathedral_minus="Communism" colosseum_plus="Electricity" temple_plus="Mysticism" + Index: data/history/buildings.ruleset =================================================================== RCS file: /home/freeciv/CVS/freeciv/data/history/buildings.ruleset,v retrieving revision 1.11 diff -u -r1.11 buildings.ruleset --- data/history/buildings.ruleset 4 Sep 2004 20:19:51 -0000 1.11 +++ data/history/buildings.ruleset 6 Sep 2004 01:11:14 -0000 @@ -24,6 +24,67 @@ ; /*** For details of this file's format, ***/ ; /*** see the default buildings.ruleset. ***/ +[group_cathedrals] +name = "Cathedrals" +elements = + { "building", "range" + "Michelangelo's Chapel", "Player" + "Cathedral", "City" + } + +[group_labs] +name = "Labs" +elements = + { "building", "range" + "SETI Program", "Player" + "Research Lab", "City" + } + +[group_generators] +name = "Generators" +elements = + { "building", "range" + "Hoover Dam", "Player" + "Nuclear Plant", "City" + "Hydro Plant", "City" + "Power Plant", "City" + } + +[group_janitors] +name = "Janitors" +elements = + { "building", "range" + "Recycling Center", "City" + "Hoover Dam", "Player" + "Nuclear Plant", "City" + "Hydro Plant", "City" + } + +[group_defenders] +name = "Defenders" +elements = + { "building", "range" + "Great Wall", "Player" + "City Walls", "City" + } + +[group_peacekeepers] +name = "Peacekeepers" +elements = + { "building", "range" + "Women's Suffrage", "Player" + "Police Station", "City" + } + +[group_purifiers] +name = "Purifiers" +elements = + { "building", "range" + "Palace", "City" + "Courthouse", "City" + } + + [building_airport] name = _("Airport") tech_req = "Radio" @@ -41,10 +102,10 @@ upkeep = 3 sabotage = 100 effect = - { "type", "range", "aff_unit" - "Unit_Veteran", "City", "Air" - "Unit_Repair", "City", "Air" - "Airlift", "City" + { "name" + "Air_Veteran" + "Air_Regen" + "Airlift" } sound = "b_airport" sound_alt = "b_generic" @@ -75,9 +136,9 @@ build_cost = 80 upkeep = 2 sabotage = 100 -effect = - { "type", "range", "amount" - "Size_Unlimit", "City", 8 +effect = + { "name", "value" + "Size_Adj", 4 } sound = "b_aqueduct" sound_alt = "b_generic" @@ -103,9 +164,9 @@ upkeep = 3 sabotage = 100 effect = - { "type", "range", "amount", "cond_bldg" - "Tax_Bonus", "City", 50, "Marketplace" - "Luxury_Bonus", "City", 50, "Marketplace" + { "name", "value", "req_type", "req" + "Tax_Bonus", 50, "Building", "Marketplace" + "Luxury_Bonus", 50, "Building", "Marketplace" } sound = "b_bank" sound_alt = "b_generic" @@ -127,14 +188,15 @@ ;equiv_dupl = equiv_repl = "Sun Tzu's War Academy","Barracks II", "Barracks III" obsolete_by = "Gunpowder" +replaced_by = "Barracks II" is_wonder = 0 build_cost = 40 upkeep = 1 sabotage = 100 effect = - { "type", "range", "aff_unit" - "Unit_Veteran", "City", "Land" - "Unit_Repair", "City", "Land" + { "name" + "Land_Veteran" + "Land_Regen" } sound = "b_barracks_i" sound_alt = "b_generic" @@ -158,14 +220,15 @@ ;equiv_dupl = equiv_repl = "Sun Tzu's War Academy", "Barracks III" obsolete_by = "Mobile Warfare" +replaced_by = "Barracks III" is_wonder = 0 build_cost = 40 upkeep = 1 sabotage = 100 effect = - { "type", "range", "aff_unit" - "Unit_Veteran", "City", "Land" - "Unit_Repair", "City", "Land" + { "name" + "Land_Veteran" + "Land_Regen" } sound = "b_barracks_ii" sound_alt = "b_generic" @@ -194,9 +257,9 @@ upkeep = 1 sabotage = 100 effect = - { "type", "range", "aff_unit" - "Unit_Veteran", "City", "Land" - "Unit_Repair", "City", "Land" + { "name" + "Land_Veteran" + "Land_Regen" } sound = "b_barracks_iii" sound_alt = "b_generic" @@ -225,10 +288,10 @@ upkeep = 3 sabotage = 100 effect = - { "type", "range", "amount", "cond_adv" - "Make_Content", "City", 3 - "Make_Content", "City", 1, "Theology" - "Make_Content", "City", -1, "Communism" + { "name", "value", "equiv", "req_type", "req" + "Make_Content", 3, "Cathedrals" + "Make_Content", 1, "Cathedrals", "Tech", "Theology" + "Make_Content", -1, "Cathedrals", "Tech", "Communism" } sound = "b_cathedral" sound_alt = "b_generic" @@ -258,11 +321,9 @@ upkeep = 0 sabotage = 50 effect = - { "type", "range", "amount", "cond_bldg", "aff_unit" - "Unit_Defend", "City", 300, "", "Land" - "Unit_No_Lose_Pop", "City", 0, "", "Land" - "Spy_Resistant", "Local", 50 - "Spy_Resistant", "Local", -50, "Palace" + { "name", "value", "equiv" + "Land_Defend", 200, "Defenders" + "Unit_No_Lose_Pop" } sound = "b_city_walls" sound_alt = "b_generic" @@ -291,8 +352,8 @@ upkeep = 1 sabotage = 100 effect = - { "type", "range", "amount", "aff_unit" - "Unit_Defend", "City", 200, "Sea" + { "name", "value" + "Sea_Defend", 100 } sound = "b_coastal_defense" sound_alt = "b_generic" @@ -318,9 +379,9 @@ upkeep = 4 sabotage = 100 effect = - { "type", "range", "amount", "cond_adv" - "Make_Content", "City", 3 - "Make_Content", "City", 1, "Electricity" + { "name", "value", "req_type", "req" + "Make_Content", 3 + "Make_Content", 1, "Tech", "Electricity" } sound = "b_colosseum" sound_alt = "b_generic" @@ -348,10 +409,11 @@ upkeep = 1 sabotage = 100 effect = - { "type", "range", "amount", "cond_gov" - "Corrupt_Pct", "City", 50 - "Make_Content", "City", 1, "Democracy" - "Revolt_Dist_Pct", "City", 50 + { "name", "value", "equiv", "req_type", "req" + "Corrupt_Pct", 50, "Purifiers" + "Waste_Pct", 50, "Purifiers" + "Make_Content", 1, "", "Gov", "Democracy" + "Incite_Dist_Pct", 75 } sound = "b_courthouse" sound_alt = "b_generic" @@ -379,8 +441,8 @@ upkeep = 4 sabotage = 100 effect = - { "type", "range", "amount" - "Prod_Bonus", "City", 50 + { "name", "value" + "Prod_Bonus", 50 } sound = "b_factory" sound_alt = "b_generic" @@ -406,8 +468,8 @@ upkeep = 1 sabotage = 100 effect = - { "type", "range", "amount" - "Growth_Food", "City", 50 + { "name" + "Growth_Food" } sound = "b_granary" sound_alt = "b_generic" @@ -437,8 +499,8 @@ upkeep = 1 sabotage = 100 effect = - { "type", "range", "amount", "aff_terr", "aff_spec" - "Food_Add_Tile", "City", 1, "Ocean", "None" + { "name", "value", "req_type", "req" + "Food_Add_Tile", 1, "Terrain", "Ocean" } sound = "b_harbour" sound_alt = "b_generic" @@ -464,11 +526,10 @@ upkeep = 4 sabotage = 100 effect = - { "type", "range", "amount", "cond_bldg" - "Prod_Bonus", "City", 25, "Factory" - "Prod_Bonus", "City", 25, "Mfg. Plant" - "Pollu_Prod_Pct", "City", 50 - "Pollu_Prod_Pct", "City", -50, "Recycling Center" + { "name", "value", "equiv", "req_type", "req" + "Prod_Bonus", 25, "Generators", "Building", "Factory" + "Prod_Bonus", 25, "Generators", "Building", "Mfg. Plant" + "Pollu_Prod_Pct", 2, "Janitors" } sound = "b_hydro_plant" sound_alt = "b_generic" @@ -507,8 +568,8 @@ upkeep = 1 sabotage = 100 effect = - { "type", "range", "amount" - "Science_Bonus", "City", 50 + { "name", "value" + "Science_Bonus", 50 } sound = "b_library" sound_alt = "b_generic" @@ -534,9 +595,9 @@ upkeep = 1 sabotage = 100 effect = - { "type", "range", "amount" - "Tax_Bonus", "City", 50 - "Luxury_Bonus", "City", 50 + { "name", "value" + "Tax_Bonus", 50 + "Luxury_Bonus", 50 } sound = "b_marketplace" sound_alt = "b_generic" @@ -562,8 +623,8 @@ upkeep = 4 sabotage = 100 effect = - { "type", "range", "amount" - "Pollu_Pop_Pct", "City", 0 + { "name", "value" + "Pollu_Pop_Pct", 100 } sound = "b_mass_transit" sound_alt = "b_generic" @@ -590,8 +651,8 @@ upkeep = 6 sabotage = 100 effect = - { "type", "range", "amount", "cond_bldg" - "Prod_Bonus", "City", 50, "Factory" + { "name", "value", "req_type", "req" + "Prod_Bonus", 50, "Building", "Factory" } sound = "b_mfg_plant" sound_alt = "b_generic" @@ -618,11 +679,10 @@ upkeep = 2 sabotage = 100 effect = - { "type", "range", "amount", "cond_bldg" - "Prod_Bonus", "City", 25, "Factory" - "Prod_Bonus", "City", 25, "Mfg. Plant" - "Pollu_Prod_Pct", "City", 50 - "Pollu_Prod_Pct", "City", -50, "Recycling Center" + { "name", "value", "equiv", "req_type", "req" + "Prod_Bonus", 25, "Generators", "Building", "Factory" + "Prod_Bonus", 25, "Generators", "Building", "Mfg. Plant" + "Pollu_Prod_Pct", 2, "Janitors" } sound = "b_nuclear_plant" sound_alt = "b_generic" @@ -662,8 +722,8 @@ upkeep = 3 sabotage = 100 effect = - { "type", "range", "amount", "aff_terr", "aff_spec" - "Prod_Add_Tile", "City", 1, "Ocean", "None" + { "name", "value", "req_type", "req" + "Prod_Add_Tile", 1, "Terrain", "Ocean" } sound = "b_offshore_platform" sound_alt = "b_generic" @@ -689,10 +749,12 @@ upkeep = 0 sabotage = 0 effect = - { "type", "range", "amount" - "Capital_City", "City" - "Capital_Exists", "Player" - "Spy_Resistant", "City", 50 + { "name", "value", "equiv" + "Corrupt_Pct", 50, "Purifiers" + "Waste_Pct", 50, "Purifiers" + "Spy_Resistant", 50 + "No_Incite" + "Capital_City" } sound = "b_palace" sound_alt = "b_generic" @@ -726,9 +788,9 @@ upkeep = 2 sabotage = 100 effect = - { "type", "range", "amount", "cond_gov" - "Make_Content_Mil", "City", 1, "Republic" - "Make_Content_Mil", "City", 2, "Democracy" + { "name", "value", "equiv", "req_type", "req" + "Make_Content_Mil", 1, "Peacekeepers", "Gov", "Republic" + "Make_Content_Mil", 2, "Peacekeepers", "Gov", "Democracy" } sound = "b_police_station" sound_alt = "b_generic" @@ -758,9 +820,9 @@ upkeep = 3 sabotage = 100 effect = - { "type", "range", "aff_unit" - "Unit_Veteran", "City", "Sea" - "Unit_Repair", "City", "Sea" + { "name" + "Sea_Veteran" + "Sea_Regen" } sound = "b_port_facility" sound_alt = "b_generic" @@ -787,9 +849,9 @@ upkeep = 4 sabotage = 100 effect = - { "type", "range", "amount", "cond_bldg" - "Prod_Bonus", "City", 25, "Factory" - "Prod_Bonus", "City", 25, "Mfg. Plant" + { "name", "value", "equiv", "req_type", "req" + "Prod_Bonus", 25, "Generators", "Building", "Factory" + "Prod_Bonus", 25, "Generators", "Building", "Mfg. Plant" } sound = "b_power_plant" sound_alt = "b_generic" @@ -825,8 +887,8 @@ upkeep = 2 sabotage = 100 effect = - { "type", "range", "amount" - "Pollu_Prod_Pct", "City", 34 + { "name", "value", "equiv" + "Pollu_Prod_Pct", 3, "Janitors" } sound = "b_recycling_center" sound_alt = "b_generic" @@ -853,8 +915,8 @@ upkeep = 3 sabotage = 100 effect = - { "type", "range", "amount", "cond_bldg" - "Science_Bonus", "City", 50, "Library" + { "name", "value", "equiv", "req_type", "req" + "Science_Bonus", 50, "Labs", "Building", "Library" } sound = "b_research_lab" sound_alt = "b_generic" @@ -882,9 +944,8 @@ upkeep = 2 sabotage = 100 effect = - { "type", "range", "amount", "aff_unit" - "Unit_Defend", "City", 200, "Air" - "Unit_Defend", "City", 200, "Missile" + { "name", "value" + "Air_Defend", 100 } sound = "b_sam_battery" sound_alt = "b_generic" @@ -910,9 +971,9 @@ upkeep = 4 sabotage = 100 effect = - { "type", "range", "amount", "aff_unit" - "Nuke_Proof", "City", 3 - "Unit_Defend", "City", 200, "Missile" + { "name", "value" + "Nuke_Proof" + "Missile_Defend", 100 } sound = "b_sdi_defense" sound_alt = "b_generic" @@ -940,9 +1001,9 @@ build_cost = 120 upkeep = 2 sabotage = 100 -effect = - { "type", "range", "amount", "cond_bldg" - "Size_Unlimit", "City", 12, "Aqueduct" +effect = + { "name", "req_type", "req" + "Size_Unlimit", "Building", "Aqueduct" } sound = "b_sewer_system" sound_alt = "b_generic" @@ -967,13 +1028,6 @@ build_cost = 320 upkeep = 4 sabotage = 100 -effect = - { "type", "range", "amount", "cond_bldg" - "Prod_Bonus", "City", 25, "Factory" - "Prod_Bonus", "City", 25, "Mfg. Plant" - "Pollu_Prod_Pct", "City", 0 - "Slow_Global_Warm", "World", 10 - } sound = "b_solar_plant" sound_alt = "b_generic" ; /* xgettext:no-c-format */ @@ -1010,9 +1064,9 @@ build_cost = 160 upkeep = 0 sabotage = 100 -effect = - { "type", "range" - "SS_Component", "Local" +effect = + { "name" + "SS_Component" } sound = "b_space_component" sound_alt = "b_generic" @@ -1041,9 +1095,9 @@ build_cost = 320 upkeep = 0 sabotage = 100 -effect = - { "type", "range" - "SS_Module", "Local" +effect = + { "name" + "SS_Module" } sound = "b_space_module" sound_alt = "b_generic" @@ -1081,9 +1135,9 @@ build_cost = 80 upkeep = 0 sabotage = 100 -effect = - { "type", "range" - "SS_Structural", "Local" +effect = + { "name" + "SS_Structural" } sound = "b_space_structural" sound_alt = "b_generic" @@ -1113,9 +1167,9 @@ upkeep = 4 sabotage = 100 effect = - { "type", "range", "amount", "cond_bldg" - "Tax_Bonus", "City", 50, "Bank" - "Luxury_Bonus", "City", 50, "Bank" + { "name", "value", "req_type", "req" + "Tax_Bonus", 50, "Building", "Bank" + "Luxury_Bonus", 50, "Building", "Bank" } sound = "b_stock_exchange" sound_alt = "b_generic" @@ -1142,8 +1196,8 @@ upkeep = 3 sabotage = 100 effect = - { "type", "range", "amount", "aff_terr", "aff_spec" - "Trade_Per_Tile", "City", 50, "None", "Road" + { "name", "value", "req_type", "req" + "Trade_Per_Tile", 50, "Special", "Road" } sound = "b_super_highways" sound_alt = "b_generic" @@ -1172,8 +1226,8 @@ upkeep = 3 sabotage = 100 effect = - { "type", "range", "amount", "aff_terr", "aff_spec" - "Food_Per_Tile", "City", 50, "None", "Farmland" + { "name", "value", "req_type", "req" + "Food_Per_Tile", 50, "Special", "Farmland" } sound = "b_supermarket" sound_alt = "b_generic" @@ -1201,9 +1255,9 @@ upkeep = 1 sabotage = 100 effect = - { "type", "range", "amount", "cond_adv" - "Make_Content", "City", 1 - "Make_Content", "City", 1, "Mysticism" + { "name", "value", "req_type", "req" + "Make_Content", 1 + "Make_Content", 1, "Tech", "Mysticism" } sound = "b_temple" sound_alt = "b_generic" @@ -1230,8 +1284,8 @@ upkeep = 3 sabotage = 100 effect = - { "type", "range", "amount", "cond_bldg" - "Science_Bonus", "City", 50, "Library" + { "name", "value", "req_type", "req" + "Science_Bonus", 50, "Building", "Library" } sound = "b_university" sound_alt = "b_generic" @@ -1258,9 +1312,9 @@ upkeep = 0 sabotage = 0 effect = - { "type", "range", "survives" - "Reveal_Map", "Player", 0 - "Enable_Space", "World", 1 + { "name", "range", "survives" + "Reveal_Map", "Player", 0 + "Enable_Space", "World", 1 } sound = "w_apollo_program" sound_alt = "w_generic" @@ -1287,8 +1341,8 @@ upkeep = 0 sabotage = 0 effect = - { "type", "range", "amount" - "Upkeep_Free", "Player", 1 + { "name", "range", "value" + "Upkeep_Free", "Player", 1 } sound = "w_asmiths_trading_co" sound_alt = "w_generic" @@ -1314,8 +1368,8 @@ upkeep = 0 sabotage = 0 effect = - { "type", "range", "amount" - "Trade_Inc_Tile", "City", 1 + { "name", "value" + "Trade_Inc_Tile", 1 } sound = "w_colossus" sound_alt = "w_generic" @@ -1341,8 +1395,8 @@ upkeep = 0 sabotage = 0 effect = - { "type", "range", "amount" - "Science_Bonus", "City", 50 + { "name", "value" + "Science_Bonus", 50 } sound = "w_copernicus_observatory" sound_alt = "w_generic" @@ -1368,8 +1422,8 @@ upkeep = 0 sabotage = 0 effect = - { "type", "range", "amount" - "Make_Content", "Player", 1 + { "name", "range", "value" + "Force_Content", "Player", 1 } sound = "w_cure_for_cancer" sound_alt = "w_generic" @@ -1397,8 +1451,8 @@ upkeep = 0 sabotage = 0 effect = - { "type", "range", "amount" - "Give_Imm_Adv", "Player", 2 + { "name", "range", "value" + "Give_Imm_Tech", "Player", 2 } sound = "w_darwins_voyage" sound_alt = "w_generic" @@ -1424,10 +1478,6 @@ build_cost = 300 upkeep = 0 sabotage = 0 -effect = - { "type", "range", "amount" - "Improve_Rep", "Player", 25 - } sound = "w_eiffel_tower" sound_alt = "w_generic" ; /* xgettext:no-c-format */ @@ -1455,8 +1505,8 @@ upkeep = 0 sabotage = 0 effect = - { "type", "range", "amount" - "Adv_Parasite", "Player", 2 + { "name", "range", "value" + "Tech_Parasite", "Player", 2 } sound = "w_great_library" sound_alt = "w_generic" @@ -1482,9 +1532,9 @@ upkeep = 0 sabotage = 0 effect = - { "type", "range", "amount", "aff_unit" - "Unit_Defend", "Player", 300, "Land" - "Unit_No_Lose_Pop", "Player", 0, "Land" + { "name", "range", "value", "equiv" + "Land_Defend", "Player", 200, "Defenders" + "Unit_No_Lose_Pop", "Player" } sound = "w_great_wall" sound_alt = "w_generic" @@ -1512,9 +1562,9 @@ upkeep = 0 sabotage = 0 effect = - { "type", "range", "amount" - "Make_Happy", "Player", 1 - "Make_Happy", "City", 2 + { "name", "range", "value" + "Make_Happy", "Player", 1 + "Make_Happy", "City", 2 } sound = "w_hanging_gardens" sound_alt = "w_generic" @@ -1543,11 +1593,10 @@ upkeep = 0 sabotage = 0 effect = - { "type", "range", "amount", "cond_bldg" - "Prod_Bonus", "Player", 25, "Factory" - "Prod_Bonus", "Player", 25, "Mfg. Plant" - "Pollu_Prod_Pct", "Player", 50 - "Pollu_Prod_Pct", "Player", -50, "Recycling Center" + { "name", "range", "value", "equiv", "req_type", "req" + "Prod_Bonus", "Player", 25, "Generators", "Building", "Factory" + "Prod_Bonus", "Player", 25, "Generators", "Building", "Mfg. Plant" + "Pollu_Prod_Pct", "Player", 2, "Janitors" } sound = "w_hoover_dam" sound_alt = "w_generic" @@ -1573,8 +1622,8 @@ upkeep = 0 sabotage = 0 effect = - { "type", "range", "amount" - "Science_Bonus", "City", 100 + { "name", "value" + "Science_Bonus", 100 } sound = "w_isaac_newtons_college" sound_alt = "w_generic" @@ -1600,8 +1649,8 @@ upkeep = 0 sabotage = 0 effect = - { "type", "range", "amount" - "Make_Content", "Player", 2 + { "name", "range", "value" + "Force_Content", "Player", 2 } sound = "w_js_bachs_cathedral" sound_alt = "w_generic" @@ -1626,8 +1675,8 @@ upkeep = 0 sabotage = 0 effect = - { "type", "range", "amount" - "Prod_Add_Tile", "City", 1 + { "name", "value" + "Prod_Add_Tile", 1 } sound = "w_king_richards_crusade" sound_alt = "w_generic" @@ -1644,7 +1693,7 @@ graphic_alt = "-" ;terr_gate = ;spec_gate = -equiv_range = "Player" +equiv_range = "None" ;equiv_dupl = ;equiv_repl = obsolete_by = "Automobile" @@ -1653,8 +1702,8 @@ upkeep = 0 sabotage = 0 effect = - { "type", "range", "amount" - "Upgrade_One_Leap", "Player", 100 + { "name", "range", "value" + "Upgrade_Unit", "Player", 1 } sound = "w_leonardos_workshop" sound_alt = "w_generic" @@ -1679,10 +1728,10 @@ upkeep = 0 sabotage = 0 effect = - { "type", "range", "amount", "aff_unit" - "Unit_Move", "Player", 1, "Sea" - "No_Sink_Deep", "Player" - "Unit_Veteran", "Player", 0, "Sea" + { "name", "range", "value" + "Sea_Move", "Player", 1 + "No_Sink_Deep", "Player" + "Sea_Veteran", "Player" } sound = "w_lighthouse" sound_alt = "w_generic" @@ -1700,7 +1749,7 @@ graphic_alt = "-" ;terr_gate = ;spec_gate = -equiv_range = "Player" +equiv_range = "None" ;equiv_dupl = ;equiv_repl = obsolete_by = "None" @@ -1709,8 +1758,8 @@ upkeep = 0 sabotage = 0 effect = - { "type", "range", "amount", "aff_unit" - "Unit_Move", "Player", 2, "Sea" + { "name", "range", "value" + "Sea_Move", "Player", 2 } sound = "w_magellans_expedition" sound_alt = "w_generic" @@ -1735,8 +1784,8 @@ upkeep = 0 sabotage = 0 effect = - { "type", "range", "survives" - "Enable_Nuke", "World", 1 + { "name", "range", "survives" + "Enable_Nuke", "World", 1 } sound = "w_manhattan_project" sound_alt = "w_generic" @@ -1760,8 +1809,8 @@ upkeep = 0 sabotage = 0 effect = - { "type", "range" - "Have_Embassies", "Player" + { "name", "range" + "Have_Embassies", "Player" } sound = "w_marco_polos_embassy" sound_alt = "w_generic" @@ -1786,10 +1835,10 @@ upkeep = 0 sabotage = 0 effect = - { "type", "range", "amount", "cond_adv" - "Make_Content", "Player", 3 - "Make_Content", "Player", 1, "Theology" - "Make_Content", "Player", -1, "Communism" + { "name", "range", "value", "equiv", "req_type", "req" + "Make_Content", "Player", 3, "Cathedrals" + "Make_Content", "Player", 1, "Cathedrals", "Tech", "Theology" + "Make_Content", "Player", -1, "Cathedrals", "Tech", "Communism" } sound = "w_michelangelos_chapel" sound_alt = "w_generic" @@ -1819,9 +1868,8 @@ upkeep = 0 sabotage = 0 effect = - { "type", "range", "amount", "cond_bldg", "cond_adv" - "Make_Content", "Player", 1, "Temple" - "Make_Content", "Player", 1, "Temple", "Mysticism" + { "name", "value", "req_type", "req" + "Make_Content", 2, "Building", "Temple" } sound = "w_oracle" sound_alt = "w_generic" @@ -1846,8 +1894,8 @@ upkeep = 0 sabotage = 0 effect = - { "type", "range", "amount" - "Growth_Food", "Player", 50 + { "name", "range" + "Growth_Food", "Player" } sound = "w_pyramids" sound_alt = "w_generic" @@ -1872,8 +1920,8 @@ upkeep = 0 sabotage = 0 effect = - { "type", "range", "amount", "cond_bldg" - "Science_Bonus", "Player", 50, "Library" + { "name", "range", "value", "equiv", "req_type", "req" + "Science_Bonus", "Player", 50, "Labs", "Building", "Library" } sound = "w_seti_program" sound_alt = "w_generic" @@ -1899,8 +1947,8 @@ upkeep = 0 sabotage = 0 effect = - { "type", "range", "amount" - "Make_Content", "City", 99 + { "name" + "No_Unhappy" } sound = "w_shakespeares_theatre" sound_alt = "w_generic" @@ -1925,9 +1973,9 @@ upkeep = 0 sabotage = 0 effect = - { "type", "range" - "Any_Government", "Player" - "No_Anarchy", "Player" + { "name", "range" + "Any_Government", "Player" + "No_Anarchy", "Player" } sound = "w_statue_of_liberty" sound_alt = "w_generic" @@ -1954,9 +2002,9 @@ upkeep = 0 sabotage = 0 effect = - { "type", "range", "amount", "aff_unit" - "Unit_Veteran", "Player", 0, "Land" - "Unit_Vet_Combat", "Player", 100, "Land" + { "name", "range", "value" + "Land_Veteran", "Player" + "Land_Vet_Combat", "Player", 50 } sound = "w_sun_tzus_war_academy" sound_alt = "w_generic" @@ -1983,12 +2031,8 @@ upkeep = 0 sabotage = 0 effect = - { "type", "range", "amount", "aff_unit" - "Unit_Recover", "Player", 2, "Air" - "Unit_Recover", "Player", 2, "Helicopter" - "Unit_Recover", "Player", 2, "Land" - "Unit_Recover", "Player", 2, "Missile" - "Unit_Recover", "Player", 2, "Sea" + { "name", "range", "value" + "Unit_Recover", "Player", 2 } sound = "w_united_nations" sound_alt = "w_generic" @@ -2021,9 +2065,9 @@ upkeep = 0 sabotage = 0 effect = - { "type", "range", "amount", "cond_gov" - "Make_Content_Mil", "Player", 1, "Republic" - "Make_Content_Mil", "Player", 2, "Democracy" + { "name", "range", "value", "equiv", "req_type", "req" + "Make_Content_Mil", "Player", 1, "Peacekeepers", "Gov", "Republic" + "Make_Content_Mil", "Player", 2, "Peacekeepers", "Gov", "Democracy" } sound = "w_womens_suffrage" sound_alt = "w_generic" @@ -2059,8 +2103,8 @@ upkeep = 0 sabotage = 0 effect = - { "type", "range", "amount" - "Prod_To_Gold", "City", 100 + { "name" + "Prod_To_Gold" } ; FIXME: this is the real helptext; restore when have a subordnate analogue ; /* (ignore for gettext until fixed) @@ -2077,14 +2121,16 @@ ") -; FIXME: remove all of the following when gen-impr implemented... - [b_special] ; Special values: -aqueduct_size=8; -sewer_size=12; +aqueduct_size=8 +default="Coinage" + +; FIXME: remove all of the following when gen-impr implemented... + +sewer_size=12 ; Techs which modify building effects: @@ -2092,3 +2138,4 @@ cathedral_minus="Communism" colosseum_plus="Electricity" temple_plus="Mysticism" + Index: doc/README.effects =================================================================== RCS file: /home/freeciv/CVS/freeciv/doc/README.effects,v retrieving revision 1.2 diff -u -r1.2 README.effects --- doc/README.effects 30 Sep 2003 23:20:10 -0000 1.2 +++ doc/README.effects 6 Sep 2004 01:11:14 -0000 @@ -5,7 +5,7 @@ Some effects are not suitable for certain assignments. This will be especially true for unit effects. Unit effects are restricted to Local range. -.type may be one of: +.name may be one of: "Adv_Parasite" - gains advances known by AMOUNT other players @@ -152,7 +152,7 @@ "Prod_Per_Tile" - increases shield production generated on each worked tile by AMOUNT percent -"Prod_To_Gold" - convert production to gold at AMOUNT percent rate +"Prod_To_Gold" - convert production to gold at 1:1 ratio "Reveal_Cities" - make all city tiles known @@ -182,14 +182,18 @@ "Slow_Global_Warm" - reduces the effect of polluted terrain within range on global warming by AMOUNT percent -"Space_Part" - a part of a spaceship; per AMOUNT: - 1 = structural, 2 = component, 3 = module +"SS_Structural" +"SS_Component" +"SS_Module" - a part of a spaceship; this is a "Local" ranged effect. It (for now) applies to improvements which cannot be built unless "Enable_Space" - is felt. + is felt. Buildings which have this effect should probably + not be given any other effects. "Spy_Resistant" - if a spy specifies a target for sabotage, - then she has an AMOUNT percent chance to fail + then she has an AMOUNT percent chance to fail. Also in + diplomatic combat defending diplomatic units in cities will + get an AMOUNT percent bonus. (all Spy_Resistant's are summed before being applied) "Tax_Bonus" - tax revenues are increased by AMOUNT percent @@ -256,21 +260,9 @@ "Unit_Veteran" - all units of class .aff_unit produced are veteran units -"Upgrade_One_Step" - upgrade one obsolete unit per turn, stepping to each - intermediate type; chance to upgrade each unit is - AMOUNT percent - -"Upgrade_One_Leap" - upgrade one obsolete unit per turn, leaping to most - advanced type; chance to upgrade each unit is AMOUNT - percent - -"Upgrade_All_Step" - upgrade all obsolete units each turn, stepping to - each intermediate type; chance to upgrade each unit - is AMOUNT percent - -"Upgrade_All_Leap" - upgrade all obsolete units each turn, leaping to - most advanced type; chance to upgrade each unit is - AMOUNT percent + +"Upgrade_Unit" - upgrade AMOUNT obsolete units per turn to the most + advanced type available. "Upkeep_Free" - improvements with AMOUNT or less upkeep cost become free to upkeep (others are unaffected) Index: server/citytools.c =================================================================== RCS file: /home/freeciv/CVS/freeciv/server/citytools.c,v retrieving revision 1.271 diff -u -r1.271 citytools.c --- server/citytools.c 31 Aug 2004 04:40:50 -0000 1.271 +++ server/citytools.c 6 Sep 2004 01:11:14 -0000 @@ -384,17 +384,6 @@ return tempname; } -/**************************************************************** -... -*****************************************************************/ -bool city_got_barracks(struct city *pcity) -{ - return (city_affected_by_wonder(pcity, B_SUNTZU) || - city_got_building(pcity, B_BARRACKS) || - city_got_building(pcity, B_BARRACKS2) || - city_got_building(pcity, B_BARRACKS3)); -} - /**************************************************************************** Return TRUE iff the city can sell the given improvement. ****************************************************************************/ @@ -437,14 +426,13 @@ G_BUILD_VETERAN_DIPLOMAT) ? 1 : 0); } - if (is_ground_unittype(id) || improvement_variant(B_BARRACKS) == 1) { - return (city_got_barracks(pcity) ? 1 : 0); + if (is_ground_unittype(id)) { + return (get_city_bonus(pcity, EFT_LAND_VETERAN) > 0) ? 1 : 0; } else { if (is_water_unit(id)) { - return ((city_affected_by_wonder(pcity, B_LIGHTHOUSE) - || city_got_building(pcity, B_PORT)) ? 1 : 0); + return (get_city_bonus(pcity, EFT_SEA_VETERAN) > 0) ? 1 : 0; } else { - return (city_got_building(pcity, B_AIRPORT) ? 1 : 0); + return (get_city_bonus(pcity, EFT_AIR_VETERAN) > 0) ? 1 : 0; } } @@ -651,7 +639,7 @@ /* We don't use city_remove_improvement here as the global effects stuff has already been handled by transfer_city */ - pcity->improvements[B_PALACE]=I_NONE; + pcity->improvements[game.palace_building]=I_NONE; /* land barbarians are more likely to destroy city improvements */ if (is_land_barbarian(city_owner(pcity))) @@ -659,7 +647,7 @@ built_impr_iterate(pcity, i) { if (!is_wonder(i) && (myrand(100) < razechance)) { - pcity->improvements[i]=I_NONE; + pcity->improvements[i] = I_NONE; } } built_impr_iterate_end; @@ -710,7 +698,7 @@ pnew_capital = city_list_get(&pplayer->cities, myrand(size)); - city_add_improvement(pnew_capital, B_PALACE); + city_add_improvement(pnew_capital, game.palace_building); /* * send_player_cities will recalculate all cities and send them to @@ -743,7 +731,7 @@ struct unit_list old_city_units; struct player *pgiver = city_owner(pcity); int old_trade_routes[NUM_TRADEROUTES]; - bool had_palace = pcity->improvements[B_PALACE] != I_NONE; + bool had_palace = pcity->improvements[game.palace_building] != I_NONE; char old_city_name[MAX_LEN_NAME]; assert(pgiver != ptaker); @@ -1014,7 +1002,8 @@ int o, x, y; struct player *pplayer = city_owner(pcity); struct tile *ptile = map_get_tile(pcity->x, pcity->y); - bool effect_update, had_palace = pcity->improvements[B_PALACE] != I_NONE; + bool effect_update, + had_palace = pcity->improvements[game.palace_building] != I_NONE; char *city_name = mystrdup(pcity->name); gamelog(GAMELOG_LOSEC, _("%s lose %s (%i,%i)"), Index: server/citytools.h =================================================================== RCS file: /home/freeciv/CVS/freeciv/server/citytools.h,v retrieving revision 1.55 diff -u -r1.55 citytools.h --- server/citytools.h 6 Aug 2004 16:46:24 -0000 1.55 +++ server/citytools.h 6 Sep 2004 01:11:14 -0000 @@ -30,7 +30,6 @@ #define POLLUTION_WEIGHTING 14 /* tentative */ #define WARMING_FACTOR 50 -bool city_got_barracks(struct city *pcity); bool can_sell_building(struct city *pcity, Impr_Type_id id); struct city *find_city_wonder(Impr_Type_id id); int build_points_left(struct city *pcity); @@ -39,6 +38,7 @@ int city_luxury_bonus(struct city *pcity); int city_science_bonus(struct city *pcity); int city_tax_bonus(struct city *pcity); +int city_luxury_bonus(struct city *pcity); void transfer_city_units(struct player *pplayer, struct player *pvictim, struct unit_list *units, struct city *pcity, Index: server/cityturn.c =================================================================== RCS file: /home/freeciv/CVS/freeciv/server/cityturn.c,v retrieving revision 1.259 diff -u -r1.259 cityturn.c --- server/cityturn.c 4 Sep 2004 20:19:51 -0000 1.259 +++ server/cityturn.c 6 Sep 2004 01:11:15 -0000 @@ -67,11 +67,10 @@ static bool city_build_building(struct player *pplayer, struct city *pcity); static bool city_build_unit(struct player *pplayer, struct city *pcity); static bool city_build_stuff(struct player *pplayer, struct city *pcity); -static int improvement_upgrades_to(struct city *pcity, int imp); +static Impr_Type_id building_upgrades_to(struct city *pcity, Impr_Type_id id); static void upgrade_building_prod(struct city *pcity); static Unit_Type_id unit_upgrades_to(struct city *pcity, Unit_Type_id id); static void upgrade_unit_prod(struct city *pcity); -static void obsolete_building_test(struct city *pcity, int b1, int b2); static void pay_for_buildings(struct player *pplayer, struct city *pcity); static bool disband_city(struct city *pcity); @@ -307,10 +306,10 @@ turns_growth = (city_granary_size(pcity->size) - pcity->food_stock - 1) / pcity->food_surplus; - if (!city_got_effect(pcity,B_GRANARY) && !pcity->is_building_unit - && pcity->currently_building == B_GRANARY + if (get_city_bonus(pcity, EFT_GROWTH_FOOD) == 0 + && get_current_construction_bonus(pcity, EFT_GROWTH_FOOD) > 0 && pcity->shield_surplus > 0) { - turns_granary = (impr_build_shield_cost(B_GRANARY) + turns_granary = (impr_build_shield_cost(pcity->currently_building) - pcity->shield_stock) / pcity->shield_surplus; /* if growth and granary completion occur simultaneously, granary preserves food. -AJS */ @@ -320,7 +319,7 @@ E_CITY_GRAN_THROTTLE, _("Game: Suggest throttling growth in %s to use %s " "(being built) more effectively."), pcity->name, - improvement_types[B_GRANARY].name); + improvement_types[pcity->currently_building].name); } } @@ -425,50 +424,42 @@ } /************************************************************************** + Return the percentage of food that is lost in this city. + + Normally this value is 100% but this can be reduced by EFT_GROWTH_FOOD + effects. +**************************************************************************/ +static int granary_savings(const struct city *pcity) +{ + int savings = get_city_bonus(pcity, EFT_GROWTH_FOOD); + + return CLIP(0, savings, 100); +} + +/************************************************************************** Note: We do not send info about the city to the clients as part of this function **************************************************************************/ static void city_increase_size(struct city *pcity) { struct player *powner = city_owner(pcity); bool have_square; - bool has_granary = city_got_effect(pcity, B_GRANARY); + int savings_pct = granary_savings(pcity), new_food; bool rapture_grow = city_rapture_grow(pcity); /* check before size increase! */ - int new_food; - if (!city_got_building(pcity, B_AQUEDUCT) - && pcity->size>=game.aqueduct_size) {/* need aqueduct */ - if (!pcity->is_building_unit && pcity->currently_building == B_AQUEDUCT) { + if (!city_can_grow_to(pcity, pcity->size + 1)) { /* need improvement */ + if (get_current_construction_bonus(pcity, EFT_SIZE_ADJ) > 0) { notify_player_ex(powner, pcity->x, pcity->y, E_CITY_AQ_BUILDING, _("Game: %s needs %s (being built) " "to grow any further."), pcity->name, - improvement_types[B_AQUEDUCT].name); + improvement_types[pcity->currently_building].name); } else { notify_player_ex(powner, pcity->x, pcity->y, E_CITY_AQUEDUCT, - _("Game: %s needs %s to grow any further."), - pcity->name, improvement_types[B_AQUEDUCT].name); - } - /* Granary can only hold so much */ - new_food = (city_granary_size(pcity->size) * - (100 - game.aqueductloss / (1 + (has_granary ? 1 : 0)))) / 100; - pcity->food_stock = MIN(pcity->food_stock, new_food); - return; - } - - if (!city_got_building(pcity, B_SEWER) - && pcity->size>=game.sewer_size) {/* need sewer */ - if (!pcity->is_building_unit && pcity->currently_building == B_SEWER) { - notify_player_ex(powner, pcity->x, pcity->y, E_CITY_AQ_BUILDING, - _("Game: %s needs %s (being built) " - "to grow any further."), pcity->name, - improvement_types[B_SEWER].name); - } else { - notify_player_ex(powner, pcity->x, pcity->y, E_CITY_AQUEDUCT, - _("Game: %s needs %s to grow any further."), - pcity->name, improvement_types[B_SEWER].name); + _("Game: %s needs an improvement to grow any further."), + pcity->name); } /* Granary can only hold so much */ - new_food = (city_granary_size(pcity->size) * - (100 - game.aqueductloss / (1 + (has_granary ? 1 : 0)))) / 100; + new_food = (city_granary_size(pcity->size) * (100 - game.aqueductloss) + * savings_pct) / (100 * 100); pcity->food_stock = MIN(pcity->food_stock, new_food); return; } @@ -478,10 +469,7 @@ if (rapture_grow) { new_food = city_granary_size(pcity->size); } else { - if (has_granary) - new_food = city_granary_size(pcity->size) / 2; - else - new_food = 0; + new_food = city_granary_size(pcity->size) * savings_pct; } pcity->food_stock = MIN(pcity->food_stock, new_food); @@ -547,20 +535,16 @@ pcity->name, utname); gamelog(GAMELOG_UNITFS, _("%s lose %s (famine)"), get_nation_name_plural(city_owner(pcity)->nation), utname); - if (city_got_effect(pcity, B_GRANARY)) - pcity->food_stock=city_granary_size(pcity->size)/2; - else - pcity->food_stock=0; + pcity->food_stock = (city_granary_size(pcity->size) + * granary_savings(pcity)) / 100; return; } } unit_list_iterate_safe_end; notify_player_ex(city_owner(pcity), pcity->x, pcity->y, E_CITY_FAMINE, _("Game: Famine causes population loss in %s."), pcity->name); - if (city_got_effect(pcity, B_GRANARY)) - pcity->food_stock = city_granary_size(pcity->size - 1) / 2; - else - pcity->food_stock = 0; + pcity->food_stock = (city_granary_size(pcity->size - 1) + * granary_savings(pcity)) / 100; city_reduce_size(pcity, 1); } } @@ -570,31 +554,12 @@ **************************************************************************/ void advisor_choose_build(struct player *pplayer, struct city *pcity) { - struct ai_choice choice; Impr_Type_id id = -1; - int want=0; - - init_choice(&choice); - if (!city_owner(pcity)->ai.control) { - /* so that ai_advisor is smart even for humans */ - ai_eval_buildings(pcity); - } - ai_advisor_choose_building(pcity, &choice); /* much smarter version -- Syela */ - freelog(LOG_DEBUG, "Advisor_choose_build got %d/%d" - " from ai_advisor_choose_building.", - choice.choice, choice.want); - id = choice.choice; - want = choice.want; - - if (id >= 0 && id < B_LAST && want > 0) { - change_build_target(pplayer, pcity, id, FALSE, E_IMP_AUTO); - /* making something. */ - return; - } /* Build something random, undecided. */ impr_type_iterate(i) { - if (can_build_improvement(pcity, i) && i != B_PALACE) { + if (can_build_improvement(pcity, i) + && !building_has_effect(i, EFT_CAPITAL_CITY)) { id = i; break; } @@ -675,7 +640,7 @@ target = new_target; } } else if (!is_unit && !can_build_improvement(pcity, target)) { - Impr_Type_id new_target = improvement_upgrades_to(pcity, target); + Impr_Type_id new_target = building_upgrades_to(pcity, target); /* If the city can never build this improvement, drop it. */ if (!can_eventually_build_improvement(pcity, new_target)) { @@ -758,45 +723,47 @@ } /************************************************************************** -... + Follow the list of replaced_by buildings until we hit something that + we can build. Return id if we can't upgrade at all. NB: returning + id doesn't guarantee that pcity really _can_ build id; just that + pcity can't build whatever _obsoletes_ id. **************************************************************************/ -static void obsolete_building_test(struct city *pcity, int b1, int b2) +static Impr_Type_id building_upgrades_to(struct city *pcity, Impr_Type_id id) { - if (pcity->currently_building == b1 - && !pcity->is_building_unit - && can_build_improvement(pcity, b2)) { - pcity->currently_building = b2; + Impr_Type_id check = id, latest_ok = id; + + if (!can_build_improvement_direct(pcity, check)) { + return -1; + } + while(improvement_exists(check = improvement_types[check].replaced_by)) { + if (can_build_improvement_direct(pcity, check)) { + latest_ok = check; + } + } + if (latest_ok == id) { + return -1; /* Can't upgrade */ } -} -/************************************************************************** - If imp is obsolete, return the improvement that _can_ be built that - lead to imp's obsolesence. - !!! Note: I hear that the building ruleset code is going to be - overhauled soon. If this happens, then this function should be updated - to follow the new model. This function will probably look a lot like - unit_upgrades_to(). -**************************************************************************/ -static int improvement_upgrades_to(struct city *pcity, int imp) -{ - if (imp == B_BARRACKS && can_build_improvement(pcity, B_BARRACKS3)) - return B_BARRACKS3; - else if (imp == B_BARRACKS && can_build_improvement(pcity, B_BARRACKS2)) - return B_BARRACKS2; - else if (imp == B_BARRACKS2 && can_build_improvement(pcity, B_BARRACKS3)) - return B_BARRACKS3; - else - return imp; + return latest_ok; } /************************************************************************** -... + Try to upgrade production in pcity. **************************************************************************/ static void upgrade_building_prod(struct city *pcity) { - obsolete_building_test(pcity, B_BARRACKS,B_BARRACKS3); - obsolete_building_test(pcity, B_BARRACKS,B_BARRACKS2); - obsolete_building_test(pcity, B_BARRACKS2,B_BARRACKS3); + struct player *pplayer = city_owner(pcity); + Impr_Type_id upgrades_to = building_upgrades_to(pcity, + pcity->currently_building); + + if (can_build_improvement(pcity, upgrades_to)) { + pcity->currently_building = upgrades_to; + notify_player_ex(pplayer, pcity->x, pcity->y, E_UNIT_UPGRADED, + _("Game: Production of %s is upgraded to %s in %s."), + get_improvement_type(pcity->currently_building)->name, + get_improvement_type(upgrades_to)->name , + pcity->name); + } } /************************************************************************** @@ -903,6 +870,7 @@ static bool city_build_building(struct player *pplayer, struct city *pcity) { bool space_part; + int mod; if (get_current_construction_bonus(pcity, EFT_PROD_TO_GOLD) > 0) { assert(pcity->shield_surplus >= 0); @@ -924,10 +892,10 @@ } if (pcity->shield_stock >= impr_build_shield_cost(pcity->currently_building)) { - if (pcity->currently_building == B_PALACE) { + if (pcity->currently_building == game.palace_building) { city_list_iterate(pplayer->cities, palace) { - if (city_got_building(palace, B_PALACE)) { - city_remove_improvement(palace, B_PALACE); + if (city_got_building(palace, game.palace_building)) { + city_remove_improvement(palace, game.palace_building); break; } } city_list_iterate_end; @@ -971,38 +939,31 @@ _("Game: %s has finished building %s."), pcity->name, improvement_types[pcity->currently_building].name); - if (pcity->currently_building == B_DARWIN) { - Tech_Type_id first, second; - char buffer[200]; + + if ((mod = get_current_construction_bonus(pcity, EFT_GIVE_IMM_TECH))) { + int i; notify_player(pplayer, _("Game: %s boosts research, " - "you gain 2 immediate advances."), - improvement_types[B_DARWIN].name); + "you gain %d immediate advances."), + improvement_types[pcity->currently_building].name, mod); - if (pplayer->research.researching == A_UNSET) { - choose_random_tech(pplayer); - } - do_free_cost(pplayer); - first = pplayer->research.researching; - found_new_tech(pplayer, pplayer->research.researching, TRUE, TRUE, - A_NONE); + for (i = 0; i < mod; i++) { + Tech_Type_id tech = pplayer->research.researching; + + if (tech == A_UNSET) { + choose_random_tech(pplayer); + tech = pplayer->research.researching; + } + do_free_cost(pplayer); + found_new_tech(pplayer, pplayer->research.researching, TRUE, TRUE, + A_NONE); - if (pplayer->research.researching == A_UNSET) { - choose_random_tech(pplayer); + notify_embassies(pplayer, NULL, + _("Game: The %s have acquired %s from %s."), + get_nation_name_plural(pplayer->nation), + get_tech_name(pplayer, tech), + improvement_types[pcity->currently_building].name); } - do_free_cost(pplayer); - second = pplayer->research.researching; - found_new_tech(pplayer, pplayer->research.researching, TRUE, TRUE, - A_NONE); - - (void) mystrlcpy(buffer, get_tech_name(pplayer, first), - sizeof(buffer)); - - notify_embassies(pplayer, NULL, - _("Game: The %s have acquired %s and %s from %s."), - get_nation_name_plural(pplayer->nation), buffer, - get_tech_name(pplayer, second), - improvement_types[B_DARWIN].name); } if (space_part && pplayer->spaceship.state == SSHIP_NONE) { notify_player_ex(NULL, pcity->x, pcity->y, E_SPACESHIP, @@ -1200,7 +1161,10 @@ struct city *capital; int dist, size, cost; - if (city_got_building(pcity, B_PALACE)) { + if (government_has_flag(get_gov_pcity(pcity), G_UNBRIBABLE)) { + return INCITE_IMPOSSIBLE_COST; + } + if (get_city_bonus(pcity, EFT_NO_INCITE) > 0) { return INCITE_IMPOSSIBLE_COST; } @@ -1250,9 +1214,7 @@ /* No capital? Take max penalty! */ dist = 32; } - if (city_got_building(pcity, B_COURTHOUSE)) { - dist /= 4; - } + dist -= (dist * get_city_bonus(pcity, EFT_INCITE_DIST_PCT)) / 100; if (g->fixed_corruption_distance != 0) { dist = MIN(g->fixed_corruption_distance, dist); } @@ -1358,10 +1320,7 @@ pcity->did_sell=FALSE; pcity->did_buy = FALSE; - if (city_got_building(pcity, B_AIRPORT)) - pcity->airlift=TRUE; - else - pcity->airlift=FALSE; + pcity->airlift = (get_city_bonus(pcity, EFT_AIRLIFT) > 0); update_tech(pplayer, pcity->science_total); pplayer->economic.gold+=pcity->tax_total; pay_for_units(pplayer, pcity); Index: server/diplomats.c =================================================================== RCS file: /home/freeciv/CVS/freeciv/server/diplomats.c,v retrieving revision 1.59 diff -u -r1.59 diplomats.c --- server/diplomats.c 1 Sep 2004 03:16:47 -0000 1.59 +++ server/diplomats.c 6 Sep 2004 01:11:15 -0000 @@ -737,7 +737,6 @@ struct city *pcity) { struct player *cplayer; - struct city *capital; int revolt_cost; /* Fetch target civilization's player. Sanity checks. */ @@ -757,12 +756,11 @@ return; } - /* Check for city being the capital. */ - capital = find_palace (city_owner (pcity)); - if (pcity == capital) { + /* See if the city is subvertable. */ + if (get_city_bonus(pcity, EFT_NO_INCITE) > 0) { notify_player_ex(pplayer, pcity->x, pcity->y, E_MY_DIPLOMAT_FAILED, - _("Game: You can't subvert the capital of a nation.")); - freelog (LOG_DEBUG, "incite: city is the capital"); + _("Game: You can't subvert this city.")); + freelog (LOG_DEBUG, "incite: city is protected"); return; } @@ -1031,9 +1029,9 @@ * City Walls, then there is a 50% chance of getting caught. */ vulnerability = get_improvement_type(improvement)->sabotage; - if (city_got_building(pcity, B_PALACE)) { - vulnerability /= 2; - } + + vulnerability -= (vulnerability + * get_city_bonus(pcity, EFT_SPY_RESISTANT) / 100); if (myrand(100) >= vulnerability) { /* Caught! */ notify_player_ex(pplayer, pcity->x, pcity->y, E_MY_DIPLOMAT_FAILED, @@ -1120,9 +1118,8 @@ def += (def/5.0) * pdefender->veteran; if (pdefender_tile->city) { - if (city_got_building(pdefender_tile->city, B_PALACE)) { - def = (def * 3) / 2;/* +50% */ - } + def = def * (100 + get_city_bonus(pdefender_tile->city, + EFT_SPY_RESISTANT)) / 100; } else { if (tile_has_special(pdefender_tile, S_FORTRESS) || tile_has_special(pdefender_tile, S_AIRBASE)) { Index: server/gotohand.c =================================================================== RCS file: /home/freeciv/CVS/freeciv/server/gotohand.c,v retrieving revision 1.183 diff -u -r1.183 gotohand.c --- server/gotohand.c 1 Sep 2004 19:54:18 -0000 1.183 +++ server/gotohand.c 6 Sep 2004 01:11:16 -0000 @@ -922,7 +922,8 @@ struct unit *passenger; struct player *pplayer = unit_owner(punit); bool afraid_of_sinking = (unit_flag(punit, F_TRIREME) && - !player_owns_active_wonder(pplayer, B_LIGHTHOUSE)); + get_player_bonus(pplayer, EFT_NO_SINK_DEEP) == 0); + /* * If the destination is one step away, look around first or just go * there? @@ -1004,18 +1005,11 @@ */ defence_multiplier = 2; if (pcity) { - if (city_got_citywalls(pcity)) { - defence_multiplier += 2; - } - if (city_got_building(pcity, B_SDI)) { - defence_multiplier++; - } - if (city_got_building(pcity, B_SAM)) { - defence_multiplier++; - } - if (city_got_building(pcity, B_COASTAL)) { - defence_multiplier++; - } + /* This isn't very accurate. */ + defence_multiplier += (get_city_bonus(pcity, EFT_LAND_DEFEND) + + get_city_bonus(pcity, EFT_MISSILE_DEFEND) + + get_city_bonus(pcity, EFT_AIR_DEFEND) + + get_city_bonus(pcity, EFT_SEA_DEFEND)) / 100; } /* Index: server/plrhand.c =================================================================== RCS file: /home/freeciv/CVS/freeciv/server/plrhand.c,v retrieving revision 1.319 diff -u -r1.319 plrhand.c --- server/plrhand.c 27 Aug 2004 17:36:53 -0000 1.319 +++ server/plrhand.c 6 Sep 2004 01:11:16 -0000 @@ -126,33 +126,31 @@ /************************************************************************** ... **************************************************************************/ -void great_library(struct player *pplayer) +void do_tech_parasite_effect(struct player *pplayer) { - if (wonder_obsolete(B_GREAT)) - return; - if (find_city_wonder(B_GREAT)) { - if (pplayer->player_no==find_city_wonder(B_GREAT)->owner) { - tech_type_iterate(i) { - if (get_invention(pplayer, i) != TECH_KNOWN - && tech_is_available(pplayer, i) - && game.global_advances[i]>=2) { - notify_player_ex(pplayer, -1, -1, E_TECH_GAIN, - _("Game: %s acquired from The Great Library!"), - advances[i].name); - gamelog(GAMELOG_TECH, _("%s discover %s (Library)"), - get_nation_name_plural(pplayer->nation), advances[i].name); - notify_embassies(pplayer, NULL, - _("Game: The %s have acquired %s" - " from the Great Library."), - get_nation_name_plural(pplayer->nation), - advances[i].name); - - do_free_cost(pplayer); - found_new_tech(pplayer, i, FALSE, FALSE, A_NONE); - break; - } - } tech_type_iterate_end; - } + int mod; + + if ((mod = get_player_bonus(pplayer, EFT_TECH_PARASITE)) > 0) { + tech_type_iterate(i) { + if (get_invention(pplayer, i) != TECH_KNOWN + && tech_is_available(pplayer, i) + && game.global_advances[i] >= mod) { + notify_player_ex(pplayer, -1, -1, E_TECH_GAIN, + _("Game: %s acquired from a building!"), + advances[i].name); + gamelog(GAMELOG_TECH, _("%s discover %s (building)"), + get_nation_name_plural(pplayer->nation), advances[i].name); + notify_embassies(pplayer, NULL, + _("Game: The %s have acquired %s" + " from a building."), + get_nation_name_plural(pplayer->nation), + advances[i].name); + + do_free_cost(pplayer); + found_new_tech(pplayer, i, FALSE, FALSE, A_NONE); + break; + } + } tech_type_iterate_end; } } @@ -289,9 +287,14 @@ { bool bonus_tech_hack = FALSE; bool was_first = FALSE; - bool macro_polo_was_obsolete = wonder_obsolete(B_MARCO); + bool had_embassy[MAX_NUM_PLAYERS]; struct city *pcity; + players_iterate(aplr) { + had_embassy[aplr->player_no] + = (get_player_bonus(aplr, EFT_HAVE_EMBASSIES) > 0); + } players_iterate_end; + /* HACK: A_FUTURE doesn't "exist" and is thus not "available". This may * or may not be the correct thing to do. For these sanity checks we * just special-case it. */ @@ -453,17 +456,14 @@ * Send all player an updated info of the owner of the Marco Polo * Wonder if this wonder has become obsolete. */ - if (!macro_polo_was_obsolete && wonder_obsolete(B_MARCO)) { - struct city *pcity = find_city_wonder(B_MARCO); - - if (pcity) { - struct player *owner = city_owner(pcity); - + players_iterate(owner) { + if (had_embassy[owner->player_no] + && get_player_bonus(owner, EFT_HAVE_EMBASSIES) == 0) { players_iterate(other_player) { send_player_info(owner, other_player); } players_iterate_end; } - } + } players_iterate_end; /* Update Team */ if (next_tech > A_NONE) { @@ -933,7 +933,7 @@ check_player_government_rates(pplayer); global_city_refresh(pplayer); - if (player_owns_active_govchange_wonder(pplayer)) { + if (get_player_bonus(pplayer, EFT_NO_ANARCHY) > 0) { pplayer->revolution_finishes = game.turn; } send_player_info(pplayer, pplayer); Index: server/plrhand.h =================================================================== RCS file: /home/freeciv/CVS/freeciv/server/plrhand.h,v retrieving revision 1.66 diff -u -r1.66 plrhand.h --- server/plrhand.h 3 Sep 2004 04:22:37 -0000 1.66 +++ server/plrhand.h 6 Sep 2004 01:11:16 -0000 @@ -34,7 +34,7 @@ void kill_player(struct player *pplayer); void kill_dying_players(void); void update_revolution(struct player *pplayer); -void great_library(struct player *pplayer); +void do_tech_parasite_effect(struct player *pplayer); void check_player_government_rates(struct player *pplayer); void make_contact(struct player *pplayer1, struct player *pplayer2, int x, int y); Index: server/ruleset.c =================================================================== RCS file: /home/freeciv/CVS/freeciv/server/ruleset.c,v retrieving revision 1.192 diff -u -r1.192 ruleset.c --- server/ruleset.c 31 Aug 2004 04:40:50 -0000 1.192 +++ server/ruleset.c 6 Sep 2004 01:11:18 -0000 @@ -1138,12 +1138,7 @@ nval, B_LAST, filename); exit(EXIT_FAILURE); } - /* FIXME: Remove this restriction when gen-impr implemented. */ - if (nval != B_LAST_ENUM) { - freelog(LOG_FATAL, "Bad number of buildings %d (%s)", nval, filename); - exit(EXIT_FAILURE); - } - /* REMOVE TO HERE when gen-impr implemented. */ + game.num_impr_types = nval; impr_type_iterate(i) { @@ -1152,6 +1147,8 @@ improvement_types[i].name_orig[0] = 0; } impr_type_iterate_end; + ruleset_cache_init(); + free(sec); } @@ -1162,13 +1159,58 @@ { char **sec, *item, **list; int i, j, k, nval, count; - bool problem; struct impr_type *b; - struct impr_effect *e; const char *filename = secfile_filename(file); (void) check_ruleset_capabilities(file, "+1.10.1", filename); + /* Parse effect equivalence effect building groups. */ + sec = secfile_get_secnames_prefix(file, "group_", &nval); + for (i = 0; i < nval; i++) { + struct effect_group *group; + char name[MAX_LEN_NAME]; + + item = secfile_lookup_str(file, "%s.name", sec[i]); + sz_strlcpy(name, item); + + group = effect_group_new(name); + + for (j = 0; + (item = secfile_lookup_str_default(file, NULL, + "%s.elements%d.building", + sec[i], j)); + j++) { + Impr_Type_id id; + enum effect_range range; + bool survives; + + if ((id = find_improvement_by_name(item)) == B_LAST) { + freelog(LOG_ERROR, "for %s unknown improvement: \"%s\" (%s)", + name, item, filename); + continue; + } + + item = secfile_lookup_str_default(file, NULL, "%s.elements%d.range", + sec[i], j); + if (item) { + if ((range = effect_range_from_str(item)) == EFR_LAST) { + freelog(LOG_ERROR, "for %s bad range: \"%s\" (%s)", + name, item, filename); + continue; + } + } else { + range = EFR_CITY; + } + + survives + = secfile_lookup_bool_default(file, FALSE, "%s.elements%d.survives", + sec[i], j); + + effect_group_add(group, id, range, survives); + } + } + free(sec); + sec = secfile_get_secnames_prefix(file, "building_", &nval); for (i = 0; i < nval; i++) { @@ -1263,6 +1305,9 @@ b->obsolete_by = A_LAST; } + b->replaced_by = lookup_impr_type(file, sec[i], "replaced_by", + FALSE, filename, b->name); + b->is_wonder = secfile_lookup_bool(file, "%s.is_wonder", sec[i]); b->build_cost = secfile_lookup_int(file, "%s.build_cost", sec[i]); @@ -1271,164 +1316,82 @@ b->sabotage = secfile_lookup_int(file, "%s.sabotage", sec[i]); - for (count = 0; - secfile_lookup_str_default(file, NULL, "%s.effect%d.type", sec[i], - count); count++) { - /* nothing */ - } - - if (count>MAX_EFFECTS) { - freelog(LOG_FATAL, "For %s maximum number of effects (%d) exceeded", - b->name, MAX_EFFECTS); - exit(EXIT_FAILURE); - } - - b->effect = fc_malloc((count + 1) * sizeof(b->effect[0])); - k = 0; - for (j = 0; j < count; j++) { - e = &b->effect[k]; - problem = FALSE; - - item = secfile_lookup_str(file, "%s.effect%d.type", sec[i], j); - e->type = effect_type_from_str(item); - if (e->type == EFT_LAST) { - freelog(LOG_ERROR, - "for %s effect[%d].type couldn't match type \"%s\" (%s)", - b->name, j, item, filename); - problem = TRUE; - } - - item = - secfile_lookup_str_default(file, "None", "%s.effect%d.range", sec[i], j); - e->range = effect_range_from_str(item); - if (e->range == EFR_LAST) { - freelog(LOG_ERROR, - "for %s effect[%d].range couldn't match range \"%s\" (%s)", - b->name, j, item, filename); - problem = TRUE; - } - - e->amount = - secfile_lookup_int_default(file, 0, "%s.effect%d.amount", sec[i], j); - - e->survives = - secfile_lookup_int_default(file, 0, "%s.effect%d.survives", sec[i], j); - - item = - secfile_lookup_str_default(file, "", "%s.effect%d.cond_bldg", sec[i], j); - if (*item != '\0') { - e->cond_bldg = find_improvement_by_name(item); - if (e->cond_bldg == B_LAST) { - freelog(LOG_ERROR, - "for %s effect[%d].cond_bldg couldn't match improvement \"%s\" (%s)", - b->name, j, item, filename); - problem = TRUE; + /* Parse building effects and add them to the effects hash. */ + { + for (j = 0; + (item = secfile_lookup_str_default(file, NULL, "%s.effect%d.name", + sec[i], j)); + j++) { + int value; + enum effect_type eff; + enum effect_range range; + bool survives; + enum req_type type; + int req, equiv; + + if ((eff = effect_type_from_str(item)) == EFT_LAST) { + freelog(LOG_ERROR, "for %s unknown effect type: \"%s\" (%s)", + b->name, item, filename); + continue; } - } else { - e->cond_bldg = B_LAST; - } - item = - secfile_lookup_str_default(file, "", "%s.effect%d.cond_gov", sec[i], j); - if (*item != '\0') { - struct government *g = find_government_by_name(item); - if (!g) { - freelog(LOG_ERROR, - "for %s effect[%d].cond_gov couldn't match government \"%s\" (%s)", - b->name, j, item, filename); - e->cond_gov = game.government_count; - problem = TRUE; + item = secfile_lookup_str_default(file, "", "%s.effect%d.range", + sec[i], j); + if (*item != '\0') { + if ((range = effect_range_from_str(item)) == EFR_LAST) { + freelog(LOG_ERROR, "for %s bad range: \"%s\" (%s)", + b->name, item, filename); + continue; + } } else { - e->cond_gov = g->index; - } - } else { - e->cond_gov = game.government_count; - } - - item = - secfile_lookup_str_default(file, "None", "%s.effect%d.cond_adv", sec[i], j); - if (*item != '\0') { - e->cond_adv = find_tech_by_name(item); - if (e->cond_adv == A_LAST) { - freelog(LOG_ERROR, - "for %s effect[%d].cond_adv couldn't match tech \"%s\" (%s)", - b->name, j, item, filename); - problem = TRUE; + range = EFR_CITY; } - } else { - e->cond_adv = A_NONE; - } - item = - secfile_lookup_str_default(file, "", "%s.effect%d.cond_eff", sec[i], j); - if (*item != '\0') { - e->cond_eff = effect_type_from_str(item); - if (e->cond_eff == EFT_LAST) { - freelog(LOG_ERROR, - "for %s effect[%d].cond_eff couldn't match effect \"%s\" (%s)", - b->name, j, item, filename); - problem = TRUE; - } - } else { - e->cond_eff = EFT_LAST; - } + survives = secfile_lookup_bool_default(file, FALSE, "%s.effect%d.survives", + sec[i], j); - item = - secfile_lookup_str_default(file, "", "%s.effect%d.aff_unit", sec[i], j); - if (*item != '\0') { - e->aff_unit = unit_class_from_str(item); - if (e->aff_unit == UCL_LAST) { - freelog(LOG_ERROR, - "for %s effect[%d].aff_unit couldn't match class \"%s\" (%s)", - b->name, j, item, filename); - problem = TRUE; - } - } else { - e->aff_unit = UCL_LAST; - } + value = secfile_lookup_int_default(file, 1, "%s.effect%d.value", + sec[i], j); - item = - secfile_lookup_str_default(file, "", "%s.effect%d.aff_terr", sec[i], j); - if (*item != '\0') { - if (0 == strcmp("None", item)) { - e->aff_terr = T_NONE; - } else { - e->aff_terr = get_terrain_by_name(item); - if (e->aff_terr == T_UNKNOWN) { - freelog(LOG_ERROR, - "for %s effect[%d].aff_terr couldn't match terrain \"%s\" (%s)", - b->name, j, item, filename); - e->aff_terr = T_NONE; - problem = TRUE; + item = secfile_lookup_str_default(file, "", "%s.effect%d.equiv", + sec[i], j); + if (*item != '\0') { + if ((equiv = find_effect_group(item)) == -1) { + freelog(LOG_ERROR, "for %s bad effect group: \"%s\" (%s)", + b->name, item, filename); + continue; } + } else { + equiv = -1; } - } else { - e->aff_terr = T_UNKNOWN; - } - item = - secfile_lookup_str_default(file, "", "%s.effect%d.aff_spec", sec[i], j); - if (*item != '\0') { - if (0 == strcmp("None", item)) { - e->aff_spec = S_NO_SPECIAL; - } else { - e->aff_spec = get_special_by_name(item); - if (e->aff_spec == S_NO_SPECIAL) { - freelog(LOG_ERROR, - "for %s effect[%d].aff_spec couldn't match special \"%s\" (%s)", - b->name, j, item, filename); - problem = TRUE; + item = secfile_lookup_str_default(file, "", "%s.effect%d.req_type", + sec[i], j); + if (*item != '\0') { + if ((type = req_type_from_str(item)) == REQ_LAST) { + freelog(LOG_ERROR, "for %s unknown requirement type: \"%s\" (%s)", + b->name, item, filename); + continue; + } + + item = secfile_lookup_str_default(file, NULL, "%s.effect%d.req", + sec[i], j); + + if (!item) { + freelog(LOG_ERROR, "for %s missing requirement data (%s)", + b->name, filename); + continue; + } else { + req = parse_effect_requirement(i, type, item); } - } - } else { - e->aff_spec = S_ALL; - } + } else { + type = REQ_NONE; + req = 0; + } - if (!problem) { - k++; + ruleset_cache_add(i, eff, range, survives, value, type, req, equiv); } } - b->effect[k].type = EFT_LAST; /* FIXME: remove when gen-impr obsoletes */ b->variant = secfile_lookup_int_default(file, 0, "%s.variant", sec[i]); @@ -1446,6 +1409,20 @@ b->helptext = lookup_helptext(file, sec[i]); } + /* + * Hack to allow code that explicitly checks for Palace or City Walls + * to work. + */ + game.palace_building = get_building_for_effect(EFT_CAPITAL_CITY); + if (game.palace_building == B_LAST) { + freelog(LOG_FATAL, "Cannot find any palace building"); + } + + game.land_defend_building = get_building_for_effect(EFT_LAND_DEFEND); + if (game.land_defend_building == B_LAST) { + freelog(LOG_FATAL, "Cannot find any land defend building"); + } + /* Some more consistency checking: */ impr_type_iterate(i) { b = &improvement_types[i]; @@ -1463,21 +1440,24 @@ b->name, advances[b->obsolete_by].name, filename); b->obsolete_by = A_LAST; } - for (j = 0; b->effect[j].type != EFT_LAST; j++) { - if (!tech_exists(b->effect[j].cond_adv)) { - freelog(LOG_ERROR, - "improvement \"%s\": effect conditional on" - " removed tech \"%s\" (%s)", - b->name, advances[b->effect[j].cond_adv].name, filename); - b->effect[j].cond_adv = A_LAST; - } - } } } impr_type_iterate_end; + game.aqueduct_size = secfile_lookup_int(file, "b_special.aqueduct_size"); + + item = secfile_lookup_str(file, "b_special.default"); + if (*item != '\0') { + game.default_building = find_improvement_by_name(item); + if (game.default_building == B_LAST) { + freelog(LOG_ERROR, "Bad value \"%s\" for b_special.default (%s)", + item, filename); + } + } else { + game.default_building = B_LAST; + } + /* FIXME: remove all of the following when gen-impr implemented... */ - game.aqueduct_size = secfile_lookup_int(file, "b_special.aqueduct_size"); game.sewer_size = secfile_lookup_int(file, "b_special.sewer_size"); game.rtech.cathedral_plus = @@ -2004,6 +1984,8 @@ sz_strlcpy(packet.team_name[i], team_get_by_id(i)->name); } + packet.default_building = game.default_building; + lsend_packet_ruleset_control(dest, &packet); } @@ -2390,6 +2372,11 @@ lookup_building_list(file, sec[i], "init_buildings", pl->init_buildings, filename); + /* Load nation specific initial buildings */ + + lookup_building_list(file, sec[i], "init_buildings", pl->init_buildings, + filename); + /* AI techs */ techs = secfile_lookup_str_vec(file, &dim, "%s.tech_goals", sec[i]); @@ -2763,6 +2750,12 @@ lookup_building_list(&file, "options", "global_init_buildings", game.rgame.global_init_buildings, filename); + /* + * Load global initial buildings + */ + lookup_building_list(&file, "options", "global_init_buildings", + game.rgame.global_init_buildings, filename); + /* Enable/Disable killstack */ game.rgame.killstack = secfile_lookup_bool(&file, "combat_rules.killstack"); @@ -2869,7 +2862,6 @@ impr_type_iterate(i) { struct impr_type *b = &improvement_types[i]; struct packet_ruleset_building packet; - struct impr_effect *eff; packet.id = i; sz_strlcpy(packet.name, b->name_orig); @@ -2879,6 +2871,7 @@ packet.bldg_req = b->bldg_req; packet.equiv_range = b->equiv_range; packet.obsolete_by = b->obsolete_by; + packet.replaced_by = b->replaced_by; packet.is_wonder = b->is_wonder; packet.build_cost = b->build_cost; packet.upkeep = b->upkeep; @@ -2904,12 +2897,6 @@ T(equiv_repl, equiv_repl_count, B_LAST); #undef T - packet.effect_count = 0; - for (eff = b->effect; eff->type != EFT_LAST; eff++) { - packet.effect[packet.effect_count] = *eff; - packet.effect_count++; - } - lsend_packet_ruleset_building(dest, &packet); } impr_type_iterate_end; } @@ -3105,7 +3092,8 @@ packet.leader_sex[i] = n->leaders[i].is_male; } packet.city_style = n->city_style; - memcpy(packet.init_techs, n->init_techs, sizeof(packet.init_techs)); + memcpy(packet.init_techs, n->init_techs, + sizeof(packet.init_techs)); sz_strlcpy(packet.class, n->class); sz_strlcpy(packet.legend, n->legend); @@ -3250,7 +3238,9 @@ send_ruleset_buildings(dest); send_ruleset_nations(dest); send_ruleset_cities(dest); + send_ruleset_cache(dest); lsend_packet_thaw_hint(dest); conn_list_do_unbuffer(dest); } + Index: server/score.c =================================================================== RCS file: /home/freeciv/CVS/freeciv/server/score.c,v retrieving revision 1.6 diff -u -r1.6 score.c --- server/score.c 3 Sep 2004 01:21:03 -0000 1.6 +++ server/score.c 6 Sep 2004 01:11:18 -0000 @@ -408,6 +408,8 @@ } city_list_iterate(pplayer->cities, pcity) { + int bonus; + pplayer->score.happy += pcity->ppl_happy[4]; pplayer->score.content += pcity->ppl_content[4]; pplayer->score.unhappy += pcity->ppl_unhappy[4]; @@ -421,11 +423,9 @@ pplayer->score.techout += pcity->science_total; pplayer->score.bnp += pcity->trade_prod; pplayer->score.mfg += pcity->shield_surplus; - if (city_got_building(pcity, B_UNIVERSITY)) { - pplayer->score.literacy += city_population(pcity); - } else if (city_got_building(pcity,B_LIBRARY)) { - pplayer->score.literacy += city_population(pcity) / 2; - } + + bonus = CLIP(0, get_city_bonus(pcity, EFT_SCIENCE_BONUS), 100); + pplayer->score.literacy += (city_population(pcity) * bonus) / 100; } city_list_iterate_end; if (pplayer->player_no == 0) { Index: server/settlers.c =================================================================== RCS file: /home/freeciv/CVS/freeciv/server/settlers.c,v retrieving revision 1.199 diff -u -r1.199 settlers.c --- server/settlers.c 31 Aug 2004 04:40:51 -0000 1.199 +++ server/settlers.c 6 Sep 2004 01:11:18 -0000 @@ -883,9 +883,13 @@ /* It is a virtual unit, so must start in a city... */ struct city *pcity = map_get_city(punit->x, punit->y); + /* The default is to lose 100%. The growth bonus reduces this. */ + int foodloss_pct = 100 - get_city_bonus(pcity, EFT_GROWTH_FOOD); + + foodloss_pct = CLIP(0, foodloss_pct, 100); assert(pcity != NULL); cost = city_granary_size(pcity->size); - if (city_got_effect(pcity, B_GRANARY)) { cost /= 2; } + cost = cost * foodloss_pct / 100; } return cost; Index: server/srv_main.c =================================================================== RCS file: /home/freeciv/CVS/freeciv/server/srv_main.c,v retrieving revision 1.185 diff -u -r1.185 srv_main.c --- server/srv_main.c 4 Sep 2004 21:25:58 -0000 1.185 +++ server/srv_main.c 6 Sep 2004 01:11:19 -0000 @@ -323,40 +323,37 @@ /************************************************************************** ... **************************************************************************/ -static void do_apollo_program(void) +static void do_reveal_effects(void) { - struct city *pcity = find_city_wonder(B_APOLLO); - - if (pcity) { - struct player *pplayer = city_owner(pcity); - - if (game.civstyle == 1) { - players_iterate(other_player) { - city_list_iterate(other_player->cities, pcity) { + players_iterate(pplayer) { + if (get_player_bonus(pplayer, EFT_REVEAL_CITIES) > 0) { + players_iterate(pother) { + city_list_iterate(pother->cities, pcity) { show_area(pplayer, pcity->x, pcity->y, 0); } city_list_iterate_end; } players_iterate_end; - } else { + } + if (get_player_bonus(pplayer, EFT_REVEAL_MAP) > 0) { /* map_know_all will mark all unknown tiles as known and send * tile, unit, and city updates as necessary. No other actions are * needed. */ map_know_all(pplayer); } - } + } players_iterate_end; } /************************************************************************** ... **************************************************************************/ -static void marco_polo_make_contact(void) +static void do_have_embassies_effect(void) { - struct city *pcity = find_city_wonder(B_MARCO); - - if (pcity) { - players_iterate(pplayer) { - make_contact(city_owner(pcity), pplayer, pcity->x, pcity->y); - } players_iterate_end; - } + players_iterate(pplayer) { + if (get_player_bonus(pplayer, EFT_HAVE_EMBASSIES) > 0) { + players_iterate(pother) { + make_contact(pplayer, pother, -1, -1); + } players_iterate_end; + } + } players_iterate_end; } /************************************************************************** @@ -572,7 +569,7 @@ /* Refresh cities */ shuffled_players_iterate(pplayer) { - great_library(pplayer); + do_tech_parasite_effect(pplayer); player_restore_units(pplayer); update_city_activities(pplayer); pplayer->research.changed_from=-1; @@ -589,8 +586,8 @@ } players_iterate_end; flush_packets(); /* to curb major city spam */ - do_apollo_program(); - marco_polo_make_contact(); + do_reveal_effects(); + do_have_embassies_effect(); freelog(LOG_DEBUG, "Auto-Attack phase"); auto_attack(); @@ -1662,6 +1659,7 @@ */ server_state = RUN_GAME_STATE; players_iterate(pplayer) { + ai_data_analyze_rulesets(pplayer); if (pplayer->is_observer) { pplayer->nation = OBSERVER_NATION; } else if (pplayer->nation == NO_NATION_SELECTED && !pplayer->ai.control) { @@ -1819,5 +1817,6 @@ diplhand_free(); game_free(); stdinhand_free(); + ruleset_cache_free(); BV_CLR_ALL(srvarg.draw); } Index: server/unithand.c =================================================================== RCS file: /home/freeciv/CVS/freeciv/server/unithand.c,v retrieving revision 1.303 diff -u -r1.303 unithand.c --- server/unithand.c 26 Aug 2004 18:37:52 -0000 1.303 +++ server/unithand.c 6 Sep 2004 01:11:19 -0000 @@ -443,17 +443,11 @@ _("Game: %s is too big to add %s."), pcity->name, unit_name); break; - case AB_NO_AQUEDUCT: + case AB_NO_SPACE: notify_player_ex(pplayer, punit->x, punit->y, E_NOEVENT, - _("Game: %s needs %s to grow, so you cannot add %s."), - pcity->name, get_improvement_name(B_AQUEDUCT), - unit_name); - break; - case AB_NO_SEWER: - notify_player_ex(pplayer, punit->x, punit->y, E_NOEVENT, - _("Game: %s needs %s to grow, so you cannot add %s."), - pcity->name, get_improvement_name(B_SEWER), - unit_name); + _("Game: %s needs an improvement to grow, so " + "you cannot add %s."), + pcity->name, unit_name); break; default: /* Shouldn't happen */ @@ -715,7 +709,7 @@ if (pcity && pcity->size > 1 - && !city_got_citywalls(pcity) + && get_city_bonus(pcity, EFT_UNIT_NO_LOSE_POP) == 0 && kills_citizen_after_attack(punit)) { city_reduce_size(pcity,1); city_refresh(pcity); @@ -814,8 +808,8 @@ if (punit->hp && (pcity=map_get_city(def_x, def_y)) && pcity->size>1 && - !city_got_citywalls(pcity) && - kills_citizen_after_attack(punit)) { + get_city_bonus(pcity, EFT_UNIT_NO_LOSE_POP) == 0 + && kills_citizen_after_attack(punit)) { city_reduce_size(pcity,1); city_refresh(pcity); send_city_info(NULL, pcity); Index: server/unittools.c =================================================================== RCS file: /home/freeciv/CVS/freeciv/server/unittools.c,v retrieving revision 1.301 diff -u -r1.301 unittools.c --- server/unittools.c 3 Sep 2004 03:56:59 -0000 1.301 +++ server/unittools.c 6 Sep 2004 01:11:21 -0000 @@ -60,7 +60,7 @@ static void unit_restore_movepoints(struct player *pplayer, struct unit *punit); static void update_unit_activity(struct unit *punit); static void wakeup_neighbor_sentries(struct unit *punit); -static void handle_leonardo(struct player *pplayer); +static void do_upgrade_effects(struct player *pplayer); static void sentry_transported_idle_units(struct unit *ptrans); @@ -116,21 +116,22 @@ || unit_type(punit)->veteran[punit->veteran].name[0] == '\0' || unit_flag(punit, F_NO_VETERAN)) { return FALSE; - } - if (is_ground_unittype(punit->type) - && player_owns_active_wonder(get_player(punit->owner), B_SUNTZU)) { - if (myrand(100) < 1.5 * game.veteran_chance[punit->veteran]) { - punit->veteran++; - return TRUE; - } } else { - if (myrand(100) < game.veteran_chance[punit->veteran]) { + struct player *plr; + double mod = 1.0; + + plr = get_player(punit->owner); + + if (is_ground_unittype(punit->type)) { + mod += (0.01 * get_player_bonus(plr, EFT_LAND_VET_COMBAT)); + } + + if (myrand(100) < (mod * game.veteran_chance[punit->veteran])) { punit->veteran++; return TRUE; } + return FALSE; } - - return FALSE; } /************************************************************************** @@ -197,49 +198,42 @@ Do Leonardo's Workshop upgrade(s). Select unit to upgrade by random. --Zamar Now be careful not to strand units at sea with the Workshop. --dwp ****************************************************************************/ -static void handle_leonardo(struct player *pplayer) +static void do_upgrade_effects(struct player *pplayer) { - int leonardo_variant; - + int upgrades = get_player_bonus(pplayer, EFT_UPGRADE_UNIT); struct unit_list candidates; - int candidate_to_upgrade=-1; - int i; + if (upgrades <= 0) { + return; + } - leonardo_variant = improvement_variant(B_LEONARDO); - unit_list_init(&candidates); - + unit_list_iterate(pplayer->units, punit) { if (test_unit_upgrade(punit, TRUE) == UR_OK) { unit_list_insert(&candidates, punit); /* Potential candidate :) */ } } unit_list_iterate_end; - - if (unit_list_size(&candidates) == 0) - return; /* We have Leonardo, but nothing to upgrade! */ - - if (leonardo_variant == 0) - candidate_to_upgrade=myrand(unit_list_size(&candidates)); - - i=0; - unit_list_iterate(candidates, punit) { - if (leonardo_variant != 0 || i == candidate_to_upgrade) { - Unit_Type_id upgrade_type = can_upgrade_unittype(pplayer, punit->type); - - notify_player(pplayer, - _("Game: %s has upgraded %s to %s%s."), - improvement_types[B_LEONARDO].name, - unit_type(punit)->name, - get_unit_type(upgrade_type)->name, - get_location_str_in(pplayer, punit->x, punit->y)); - punit->veteran = 0; - assert(test_unit_upgrade(punit, TRUE) == UR_OK); - upgrade_unit(punit, upgrade_type, TRUE); - } - i++; - } unit_list_iterate_end; - + + while (upgrades > 0 && unit_list_size(&candidates) > 0) { + /* Upgrade one unit. */ + int candidate_to_upgrade = myrand(unit_list_size(&candidates)); + struct unit *punit = unit_list_get(&candidates, candidate_to_upgrade); + Unit_Type_id upgrade_type = can_upgrade_unittype(pplayer, punit->type); + + notify_player(pplayer, + _("Game: %s was upgraded for free to %s%s."), + unit_type(punit)->name, + get_unit_type(upgrade_type)->name, + get_location_str_in(pplayer, punit->x, punit->y)); + + punit->veteran = 0; + assert(test_unit_upgrade(punit, TRUE) == UR_OK); + upgrade_unit(punit, upgrade_type, TRUE); + unit_list_unlink(&candidates, punit); + upgrades--; + } + unit_list_unlink_all(&candidates); } @@ -294,8 +288,7 @@ void player_restore_units(struct player *pplayer) { /* 1) get Leonardo out of the way first: */ - if (player_owns_active_wonder(pplayer, B_LEONARDO)) - handle_leonardo(pplayer); + do_upgrade_effects(pplayer); unit_list_iterate_safe(pplayer->units, punit) { @@ -430,9 +423,8 @@ punit->hp+=hp_gain_coord(punit); } - if (player_owns_active_wonder(pplayer, B_UNITED)) - punit->hp+=2; - + punit->hp += get_player_bonus(pplayer, EFT_UNIT_RECOVER); + if(is_heli_unit(punit)) { struct city *pcity = map_get_city(punit->x,punit->y); if(!pcity) { @@ -492,11 +484,12 @@ else hp=0; if((pcity=map_get_city(punit->x,punit->y))) { - if ((city_got_barracks(pcity) && - (is_ground_unit(punit) || improvement_variant(B_BARRACKS)==1)) || - (city_got_building(pcity, B_AIRPORT) && is_air_unit(punit)) || - (city_got_building(pcity, B_AIRPORT) && is_heli_unit(punit)) || - (city_got_building(pcity, B_PORT) && is_sailing_unit(punit))) { + if ((get_city_bonus(pcity, EFT_LAND_REGEN) > 0 + && is_ground_unit(punit)) + || (get_city_bonus(pcity, EFT_AIR_REGEN) > 0 + && (is_air_unit(punit) || is_heli_unit(punit))) + || (get_city_bonus(pcity, EFT_SEA_REGEN) > 0 + && is_sailing_unit(punit))) { hp=unit_type(punit)->hp; } else
|