Complete.Org:
Mailing Lists:
Archives:
freeciv-dev:
December 2002: [Freeciv-Dev] (PR#2521) general effects framework |
[Freeciv-Dev] (PR#2521) general effects framework[Date Prev][Date Next][Thread Prev][Thread Next][Date Index] [Thread Index]
Here is the first draft of the first step toward general-improvements. This is the initial framework. Current situation (for the uninitiated): improvements have certain "effects" defined in data/default/buildings.ruleset that define what they can do when built. Read the ruleset for for specific info. Except for the spaceship parts effect, these "effects" currently do nothing. Everything is hardcoded by building all throughout the codebase. There is an access method to theses effects currently, but it is not complete, and after examining it, I have found it lacking and fairly unintelligable. What the patch does (tutorial): This patch gives (what I think) is an improved and complete access method to these effects. In a nutshell, each improvement has an "effect definition" that it gets from the ruleset. on startup, these can be found in: struct impr_type { ... struct effect_defn_list effect_defs; ... } When an improvement is built, an effect [struct effect] is created (which has a pointer to the definition) for each effect definition in the list. Each effect is then added to an effect list based on the range of its definition. The ranges are: "None", "Local", "City", "Island", "Player", and "World". Each range defines where the effect is felt. For example, if the effect has World range, it will be felt by everything (all cities, improvements, units, etc) by all players. If it has City range, it will be felt by everything in the city (or perhaps on the city tiles) where the improvement is built that is creating the effect. Thus effects created by improvements have a "home" (if an effect survives an improvement's destruction, it becomes "homeless"). Once the effect is added, you can check for the effect by iterating though the lists of effects. For example, say, you had a spy attempting to sabotage a city's city walls. Now two effects that a given city wall have are: effect = { "type", "range", "amount", "cond_bldg" "Spy_Resistant", "Local", 50 "Spy_Resistant", "Local", -50, "Palace" } Local in this context means that this effect _only_ matters for this improvement. Let's read the definition: "Spy_Resistant" - if a spy specifies a target for sabotage, then she has an AMOUNT percent chance to fail (all Spy_Resistant's are summed before being applied) Note that the second effect depends on there being a "Palace" in the same city as the walls improvement (that's because it [the palace] confers Spy_Resistance of 50% on the entire city that it's in, and we don't want the wall to double the effect...). Now to check to see if the Spy fails to sabotage the walls... For motivation, let's say she begins with a 25% chance of failure. To apply effects, we need to iterate through all the applicable effects, now we need to check for the Spy_Resistant effect in ALL the lists that affect the walls. In this case, we need to look at 2. the Local list (that the improvement has (actually stored as pcity->impr_effects[B_CITY]), the City list where the walls are located (pcity->effects), the Island list (on which that city is located (pplayer->island_effects[map_get_continent(pcity->x, pcity->y)]), the Player list for the player who owns the city and its improvement (pplayer->effects), and finally the World list (game->effects). Each of these lists could possibly have an effect which confers Spy_Resistant. Instead of going though each one by hand, fortunately we have an iterator function which helps us: void effect_iterator_init(struct effect_iter *iter, unsigned int ranges, struct player *pplayer, struct city *pcity, int id, enum effect_type type); which describes the kind of search to do and: struct effect *effect_iterator_get_next_active(struct effect_iter *iter); which returns an (active) matching effect. struct effect_iter iter; struct effect *eff; int failure_chance = 25; effect_iterator_init(&iter, EFR_LAST, pplayer, pcity, walls_impr_id, EFT_SPY_RESISTANT); while( (eff = effect_iterator_get_next_active(&iter)) ) { failure_chance += eff->defn->amount; } my, wasn't that nice? A word on the init function the range EFR_LAST is a synonym for iterate through all applicable ranges (as defined by pplayer, pcity, and walls_impr_id). If you needed just the World and Island ranges for some reason, you would do: effect_iterator_init(&iter, EFR_WORLD|EFR_ISLAND, pplayer, pcity, walls_impr_id, EFT_SPY_RESISTANT); so ranges can be ORed together. If you needed to look for all active effects, use EFT_LAST instead of EFT_SPY_RESISTANT. What else the patch does (the bonus): Improvements aren't the only things that can have effects. Nations, governments and techs can also have effects (any effects from these must be World or Player ranged). Note: non-improvements effects are known to be buggy in this version. Beware. Also easily extensible from this framework are unit effects (which will be restricted to Local ranged effects). What the patch doesn't do (the downside): With the exception of the spaceship parts, this patch really does nothing yet. Adding zany effects to buildings will do nothing to gameplay. This is the framework patch. But as you can see from the above example, it ain't hard to actually to the next step. Oh, and island effects are not implemented yet. So don't specify anything as Island ranged. This is the result of a bit of disagreement as to how to proceed with regard to who defines an island. There is a lot of debugging information (to be removed when it's committed) that will help you see that effects are actually getting added and removed. do ser -d 4:effects.c to see it. Enjoy. -mike
effects1.diff.bz2
buildings.ruleset.bz2
|