diff -Nur -Xfreecivdiff.ignore freeciv-cvs/ai/aiunit.c freeciv-patched/ai/aiunit.c --- freeciv-cvs/ai/aiunit.c 2003-07-24 17:03:47.000000000 +0100 +++ freeciv-patched/ai/aiunit.c 2003-07-24 17:04:40.000000000 +0100 @@ -387,7 +387,8 @@ struct map_position mp; mp.x = x; mp.y = y; - eff_iterator_unit_init(&iter, punit->type, unit_owner(punit), &mp); + eff_iterator_unit_init(&iter, punit->type, punit->type, + unit_owner(punit), &mp); while (eff_iterator_next(&iter)) { if (iter.imeff->type == EFT_NO_SINK_DEEP) { return FALSE; diff -Nur -Xfreecivdiff.ignore freeciv-cvs/client/packhand.c freeciv-patched/client/packhand.c --- freeciv-cvs/client/packhand.c 2003-07-24 17:04:38.000000000 +0100 +++ freeciv-patched/client/packhand.c 2003-07-24 17:04:40.000000000 +0100 @@ -1249,16 +1249,13 @@ game.cooling=pinfo->cooling; if (!can_client_change_view()) { /* Nasty kludge to let old code which assumes B_PALACE and B_CITY work */ - B_PALACE = get_improvement_for_effect(NULL, EFT_CAPITAL_CITY, UCL_LAST); + B_PALACE = get_improvement_for_effect(NULL, EFT_CAPITAL_CITY, NULL); if (B_PALACE == B_LAST) { freelog(LOG_ERROR, "Cannot find any capital city improvement"); exit(EXIT_FAILURE); } - B_CITY = get_improvement_for_effect(NULL, EFT_UNIT_DEFEND, UCL_LAND); - if (B_CITY == B_LAST) { - B_CITY = get_improvement_for_effect(NULL, EFT_UNIT_DEFEND, UCL_LAST); - } + B_CITY = get_improvement_for_effect(NULL, EFT_UNIT_DEFEND, NULL); if (B_CITY == B_LAST) { freelog(LOG_ERROR, "Cannot find any city walls improvement"); exit(EXIT_FAILURE); @@ -1964,6 +1961,7 @@ game.government_when_anarchy = packet->government_when_anarchy; game.default_government = packet->default_government; + game.num_unit_flags = packet->num_unit_flags; game.num_unit_types = packet->num_unit_types; game.num_impr_types = packet->num_impr_types; game.num_tech_types = packet->num_tech_types; @@ -2029,6 +2027,7 @@ u->paratroopers_range = p->paratroopers_range; u->paratroopers_mr_req = p->paratroopers_mr_req; u->paratroopers_mr_sub = p->paratroopers_mr_sub; + u->effect = p->effect; /* pointer assignment */ u->helptext = p->helptext; /* pointer assignment */ @@ -2200,7 +2199,7 @@ b->effect[inx].aff_unit, (b->effect[inx].aff_unit == UCL_LAST) ? "All" : - unit_class_name(b->effect[inx].aff_unit)); + unit_class_names[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, diff -Nur -Xfreecivdiff.ignore freeciv-cvs/common/city.c freeciv-patched/common/city.c --- freeciv-cvs/common/city.c 2003-07-24 17:04:39.000000000 +0100 +++ freeciv-patched/common/city.c 2003-07-24 17:04:40.000000000 +0100 @@ -1747,7 +1747,7 @@ case EFT_FOOD_INC_TILE: case EFT_FOOD_PER_TILE: city_map_iterate(x, y) { - if (is_unit_terrain_affected(imeff, UCL_LAST, tile_terr[x][y], + if (is_unit_terrain_affected(imeff, NULL, tile_terr[x][y], tile_spec[x][y])) { switch(imeff->type) { case EFT_TRADE_ADD_TILE: @@ -1822,7 +1822,10 @@ polpct = 100; int makecontent = 0, makehappy = 0, /* Happiness modifiers */ forcecontent = 0, forcehappy = 0; - int defensepct[UCL_LAST]; /* Defense multipliers */ + int defensepct[UCL_LAST + 1]; /* Defense multipliers */ + int attackpct[UCL_LAST + 1]; /* Attack multipliers */ + int defensefppct[UCL_LAST + 1]; /* Firepower multipliers */ + int attackfppct[UCL_LAST + 1]; int makecontentpct = 100, forcecontentpct = 100; int makecontentmil = 0, makecontentmilper = 0; int corruptadj = 0, corruptpct = 100; @@ -1842,8 +1845,8 @@ pplayer = city_owner(pcity); gov = get_gov_pcity(pcity); - for (i = 0; i < UCL_LAST; i++) { - defensepct[i] = 100; + for (i = 0; i <= UCL_LAST; i++) { + defensepct[i] = attackpct[i] = defensefppct[i] = attackfppct[i] = 100; } city_init_tile_mods(pcity); @@ -1875,23 +1878,28 @@ /* Ignore terrain in the iteration, as it's the terrain of the city center - we need to consider all city tiles too */ - city_effects_iterate_full(iter, pcity, UCL_LAST, T_UNKNOWN, S_ALL) { + city_effects_iterate_full(iter, pcity, NULL, T_UNKNOWN, S_ALL) { if (!handle_tile_bonuses(iter.imeff, pcity->tile_add, pcity->tile_bonuses, pcity->tile_pct, tile_spec, tile_terr) - && is_unit_terrain_affected(iter.imeff, UCL_LAST, terr, spec)) { + && is_unit_terrain_affected(iter.imeff, NULL, terr, spec)) { amount = iter.imeff->amount; switch(iter.imeff->type) { case EFT_UNIT_DEFEND: - if (iter.imeff->aff_unit == UCL_LAST) { - for (i = 0; i < UCL_LAST; i++) { - defensepct[i] = defensepct[i] * amount / 100; - } - } else { - i = iter.imeff->aff_unit; - assert(i >= 0 && i < UCL_LAST); - defensepct[i] = defensepct[i] * amount / 100; - } + defensepct[iter.imeff->aff_unit] = defensepct[iter.imeff->aff_unit] + * amount / 100; + break; + case EFT_UNIT_ATTACK: + attackpct[iter.imeff->aff_unit] = attackpct[iter.imeff->aff_unit] + * amount / 100; + break; + case EFT_UNIT_ATTACK_FIREPOWER: + attackfppct[iter.imeff->aff_unit] = attackfppct[iter.imeff->aff_unit] + * amount / 100; + break; + case EFT_UNIT_DEFEND_FIREPOWER: + defensefppct[iter.imeff->aff_unit] = defensefppct[iter.imeff->aff_unit] + * amount / 100; break; case EFT_TAX_BONUS: tax_bonus += amount; break; @@ -2007,8 +2015,11 @@ pcity->poppoladj = poppoladj; pcity->prodpoladj = prodpoladj; - for (i = 0; i < UCL_LAST; i++) { + for (i = 0; i <= UCL_LAST; i++) { pcity->defensepct[i] = defensepct[i]; + pcity->attackpct[i] = attackpct[i]; + pcity->attackfppct[i] = attackfppct[i]; + pcity->defensefppct[i] = defensefppct[i]; } } diff -Nur -Xfreecivdiff.ignore freeciv-cvs/common/city.h freeciv-patched/common/city.h --- freeciv-cvs/common/city.h 2003-07-24 17:04:39.000000000 +0100 +++ freeciv-patched/common/city.h 2003-07-24 17:04:40.000000000 +0100 @@ -250,8 +250,11 @@ struct tile_mod tile_add[CITY_MAP_SIZE][CITY_MAP_SIZE]; struct tile_mod tile_pct[CITY_MAP_SIZE][CITY_MAP_SIZE]; - /* defense multiplier for each type of attacker */ - int defensepct[UCL_LAST]; + /* combat multipliers for each type of attacker */ + int defensepct[UCL_LAST + 1]; + int attackpct[UCL_LAST + 1]; + int defensefppct[UCL_LAST + 1]; + int attackfppct[UCL_LAST + 1]; /* corruption modifiers from city improvements */ int corruptadj, corruptpct; diff -Nur -Xfreecivdiff.ignore freeciv-cvs/common/combat.c freeciv-patched/common/combat.c --- freeciv-cvs/common/combat.c 2003-07-24 17:02:53.000000000 +0100 +++ freeciv-patched/common/combat.c 2003-07-24 17:04:40.000000000 +0100 @@ -223,12 +223,104 @@ return accum_prob; } +struct impr_eff_unit { + int combatpct; + int firepowerpct; +}; + +static void get_impr_eff_unit(Unit_Type_id att_type, + Unit_Type_id def_type, int x, int y, + struct player *def_player, + struct player *att_player, + bool get_attack, + struct impr_eff_unit *effunit) +{ + int combatpct = 100, firepowerpct = 100; + struct eff_iter iter; + struct map_position mappos; + struct city *pcity = map_get_city(x, y); + int i; + + mappos.x = x; + mappos.y = y; + + if (get_attack) { + eff_iterator_unit_init(&iter, att_type, def_type, NULL, &mappos); + } else { + eff_iterator_unit_init(&iter, def_type, att_type, def_player, &mappos); + } + + /* Ignore effects at City-range and greater if we're in a city, + * as we already have these effects cached; if the attacking unit + * "ignores walls" then we ignore these effects completely. */ + if (unit_type_flag(att_type, F_IGWALL) || pcity) { + for (i = EFR_CITY; i < EFR_LAST; ++i) { + iter.effs[i] = NULL; + } + } + + if (get_attack) { + while (eff_iterator_next(&iter)) { + switch (iter.imeff->type) { + case EFT_UNIT_ATTACK: + combatpct = combatpct * iter.imeff->amount / 100; + break; + case EFT_UNIT_ATTACK_FIREPOWER: + firepowerpct = firepowerpct * iter.imeff->amount / 100; + break; + default: + break; + } + } + } else { + while (eff_iterator_next(&iter)) { + switch (iter.imeff->type) { + case EFT_UNIT_DEFEND: + combatpct = combatpct * iter.imeff->amount / 100; + break; + case EFT_UNIT_DEFEND_FIREPOWER: + firepowerpct = firepowerpct * iter.imeff->amount / 100; + break; + default: + break; + } + } + } + + /* Apply cached city effects */ + if (pcity && !unit_type_flag(att_type, F_IGWALL)) { + struct unit_classes aff_unit; + + if (get_attack) { + get_unittype_classes(def_type, &aff_unit); + for (i = 0; i <= UCL_LAST; ++i) { + if (i == UCL_LAST || is_unit_class_in_set(i, &aff_unit)) { + combatpct = combatpct * pcity->attackpct[i] / 100; + firepowerpct = firepowerpct * pcity->attackfppct[i] / 100; + } + } + } else { + get_unittype_classes(att_type, &aff_unit); + for (i = 0; i <= UCL_LAST; ++i) { + if (i == UCL_LAST || is_unit_class_in_set(i, &aff_unit)) { + combatpct = combatpct * pcity->defensepct[i] / 100; + firepowerpct = firepowerpct * pcity->defensefppct[i] / 100; + } + } + } + } + effunit->combatpct = combatpct; + effunit->firepowerpct = firepowerpct; +} + /************************************************************************** A unit's effective firepower depend on the situation. **************************************************************************/ void get_modified_firepower(struct unit *attacker, struct unit *defender, int *att_fp, int *def_fp) { + struct impr_eff_unit att_effunit, def_effunit; + *att_fp = unit_type(attacker)->firepower; *def_fp = unit_type(defender)->firepower; @@ -238,15 +330,29 @@ *att_fp *= 2; *def_fp = 1; } - - /* - * When attacked by fighters, helicopters have their firepower - * reduced to 1. - */ - if (is_heli_unit(defender) && unit_flag(attacker, F_FIGHTER)) { - *def_fp = 1; - } + /* Effects from generalised improvements */ + get_impr_eff_unit(attacker->type, defender->type, defender->x, defender->y, + unit_owner(defender), unit_owner(attacker), + TRUE, &att_effunit); + get_impr_eff_unit(attacker->type, defender->type, defender->x, defender->y, + unit_owner(defender), unit_owner(attacker), + FALSE, &def_effunit); + + freelog(LOG_DEBUG, + "%s attacking %s: impr-gen firepower multiplier %d", + get_unit_type(attacker->type)->name, + get_unit_type(defender->type)->name, + att_effunit.firepowerpct); + freelog(LOG_DEBUG, + "%s defending against %s: impr-gen firepower multiplier %d", + get_unit_type(defender->type)->name, + get_unit_type(attacker->type)->name, + def_effunit.firepowerpct); + + *def_fp = *def_fp * def_effunit.firepowerpct / 100; + *att_fp = *att_fp * att_effunit.firepowerpct / 100; + /* In land bombardment both units have their firepower reduced to 1 */ if (is_sailing_unit(attacker) && !is_ocean(map_get_terrain(defender->x, defender->y)) @@ -380,13 +486,25 @@ } /*************************************************************************** - return the modified attack power of a unit. Currently they aren't any - modifications... + return the modified attack power of a unit. ***************************************************************************/ int get_total_attack_power(struct unit *attacker, struct unit *defender) { + struct impr_eff_unit effunit; int attackpower = get_attack_power(attacker); + /* Effects from generalised improvements */ + get_impr_eff_unit(attacker->type, defender->type, attacker->x, attacker->y, + unit_owner(defender), unit_owner(attacker), + TRUE, &effunit); + + freelog(LOG_DEBUG, + "%s attacking %s: impr-gen multiplier %d", + get_unit_type(attacker->type)->name, + get_unit_type(defender->type)->name, + effunit.combatpct); + attackpower = attackpower * effunit.combatpct / 100; + return attackpower; } @@ -403,44 +521,23 @@ static int defence_multiplication(Unit_Type_id att_type, Unit_Type_id def_type, int x, int y, int defensepower, bool fortified, + struct player *att_player, struct player *def_player) { struct city *pcity = map_get_city(x, y); - int defensepct = 100; if (unit_type_exists(att_type)) { - if (unit_type_flag(def_type, F_PIKEMEN) - && unit_type_flag(att_type, F_HORSE)) { - defensepower *= 2; - } + /* Effects from generalised improvements */ + struct impr_eff_unit effunit; - if (unit_type_flag(def_type, F_AEGIS) && - (is_air_unittype(att_type) || is_heli_unittype(att_type))) { - defensepower *= 5; - } - - /* Effects from generalised improvements; if we're in a city, use - * the city's cached defense bonus. Only consider effects if the - * attacker does not "ignore" defenses */ - if (!unit_type_flag(att_type, F_IGWALL)) { - if (pcity) { - defensepct = pcity->defensepct[get_unittype_class(att_type)]; - } else { - struct map_position mappos; - - mappos.x = x; mappos.y = y; - unittype_effects_iterate(iter, att_type, def_player, &mappos) { - if (iter.imeff->type == EFT_UNIT_DEFEND) { - defensepct = defensepct * iter.imeff->amount / 100; - } - } unittype_effects_iterate_end; - } - } - defensepower = defensepower * defensepct / 100; + get_impr_eff_unit(att_type, def_type, x, y, def_player, att_player, + FALSE, &effunit); - if (unit_type_flag(att_type, F_FIGHTER) && is_heli_unittype(def_type)) { - defensepower /= 2; - } + freelog(LOG_DEBUG, + "%s defending against %s: impr-gen multiplier %d", + get_unit_type(def_type)->name, + get_unit_type(att_type)->name, effunit.combatpct); + defensepower = defensepower * effunit.combatpct / 100; } if (map_has_special(x, y, S_FORTRESS) && !pcity) { @@ -484,7 +581,7 @@ /* FIXME: we don't know the player, so can't consider Player-range * Unit_Defend improvement effects... */ return defence_multiplication(att_type, def_type, x, y, defensepower, - fortified, NULL); + fortified, NULL, NULL); } /*************************************************************************** @@ -498,7 +595,7 @@ defender->x, defender->y, get_defense_power(defender), defender->activity == ACTIVITY_FORTIFIED, - unit_owner(defender)); + unit_owner(attacker), unit_owner(defender)); } /************************************************************************** diff -Nur -Xfreecivdiff.ignore freeciv-cvs/common/game.c freeciv-patched/common/game.c --- freeciv-cvs/common/game.c 2003-07-24 17:04:39.000000000 +0100 +++ freeciv-patched/common/game.c 2003-07-24 17:04:40.000000000 +0100 @@ -283,6 +283,7 @@ sz_strlcpy(game.rulesetdir, GAME_DEFAULT_RULESETDIR); + game.num_unit_flags = F_LAST; game.num_unit_types = 0; game.num_impr_types = 0; game.num_tech_types = 0; diff -Nur -Xfreecivdiff.ignore freeciv-cvs/common/game.h freeciv-patched/common/game.h --- freeciv-cvs/common/game.h 2003-07-24 17:04:39.000000000 +0100 +++ freeciv-patched/common/game.h 2003-07-24 17:04:40.000000000 +0100 @@ -148,6 +148,7 @@ bool fogofwar_old; /* as the fog_of_war bit get changed by setting the server we need to remember the old setting */ + int num_unit_flags; int num_unit_types; int num_impr_types; int num_tech_types; /* including A_NONE */ diff -Nur -Xfreecivdiff.ignore freeciv-cvs/common/government.c freeciv-patched/common/government.c --- freeciv-cvs/common/government.c 2003-07-24 17:03:11.000000000 +0100 +++ freeciv-patched/common/government.c 2003-07-24 17:04:40.000000000 +0100 @@ -63,7 +63,7 @@ struct ai_gov_tech_hint ai_gov_tech_hints[MAX_NUM_TECH_LIST]; static const char *flag_names[] = { - "Build_Veteran_Diplomats", "Revolution_When_Unhappy", "Has_Senate", + "(unused)", "Revolution_When_Unhappy", "Has_Senate", "Unbribable", "Inspires_Partisans", "Rapture_City_Growth", "Fanatic_Troops", "No_Unhappy_Citizens", "Convert_Tithes_To_Money", "Reduced_Research" diff -Nur -Xfreecivdiff.ignore freeciv-cvs/common/government.h freeciv-patched/common/government.h --- freeciv-cvs/common/government.h 2003-07-10 11:53:36.000000000 +0100 +++ freeciv-patched/common/government.h 2003-07-24 17:04:40.000000000 +0100 @@ -18,6 +18,7 @@ struct city; struct player; struct Sprite; /* opaque; client-gui specific */ +struct impr_effect; #define G_MAGIC (127) /* magic constant, used as flag value */ @@ -25,7 +26,8 @@ #define G_CITY_SIZE_FREE G_MAGIC enum government_flag_id { - G_BUILD_VETERAN_DIPLOMAT=0, /* and Spies (in general: all F_DIPLOMAT) */ + G_BUILD_VETERAN_DIPLOMAT=0, /* obsolete - use Unit_Veteran effect in + * units.ruleset instead */ G_REVOLUTION_WHEN_UNHAPPY, G_HAS_SENATE, /* not implemented */ G_UNBRIBABLE, @@ -152,6 +154,8 @@ int hints; struct Sprite *sprite; + + struct impr_effect *effect; /* list; .type==EFT_LAST terminated */ char *helptext; }; diff -Nur -Xfreecivdiff.ignore freeciv-cvs/common/improvement.c freeciv-patched/common/improvement.c --- freeciv-cvs/common/improvement.c 2003-07-24 17:04:39.000000000 +0100 +++ freeciv-patched/common/improvement.c 2003-07-24 17:04:40.000000000 +0100 @@ -154,7 +154,10 @@ "Make_Content_Mil_Per", "Force_Content", "Force_Content_Pct", - "Force_Happy" + "Force_Happy", + "Unit_Attack", + "Unit_Attack_Firepower", + "Unit_Defend_Firepower" }; /************************************************************************** @@ -1025,7 +1028,9 @@ if (imeff->cond_eff != EFT_LAST && !is_under_effect(impr, pcity, pplayer, imeff->cond_eff)) { freelog(LOG_DEBUG, "Effect requires another effect"); - *cond_eff = TRUE; + if (cond_eff) { + *cond_eff = TRUE; + } return FALSE; } return TRUE; @@ -1071,9 +1076,12 @@ cont = map_get_continent(pcity->x, pcity->y); get_all_effect_vectors(iter->effs, impr, pcity, cont, pplayer); + + iter->utype = U_LAST; iter->impr = impr; iter->pcity = pcity; - iter->aff_unit = UCL_LAST; + iter->pplayer = pplayer; + iter->aff_unit.move_type = LAST_MOVING; if (pcity) { iter->aff_terr = map_get_terrain(pcity->x, pcity->y); @@ -1093,6 +1101,7 @@ the unit is considered unowned and/or unpositioned) **************************************************************************/ void eff_iterator_unit_init(struct eff_iter *iter, Unit_Type_id utype, + Unit_Type_id aff_utype, struct player *pplayer, struct map_position *mp) { int cont = -1; @@ -1107,9 +1116,11 @@ get_all_effect_vectors(iter->effs, B_LAST, pcity, cont, pplayer); + iter->utype = utype; iter->impr = B_LAST; iter->pcity = pcity; - iter->aff_unit = get_unittype_class(utype); + iter->pplayer = pplayer; + get_unittype_classes(aff_utype, &iter->aff_unit); if (mp) { iter->aff_terr = map_get_terrain(mp->x, mp->y); @@ -1145,7 +1156,23 @@ /* Loop over all valid ranges */ for (; iter->range < EFR_LAST; iter->range++) { ceff = iter->effs[iter->range]; - if (ceff) { + /* We don't currently pre-activate unittype effects, so must check + * each effect for activation */ + if (iter->range == EFR_LOCAL && iter->utype != U_LAST) { + if (iter->imeff) { + iter->imeff++; + } else { + iter->imeff = get_unit_type(iter->utype)->effect; + } + for (; iter->imeff && iter->imeff->type != EFT_LAST; iter->imeff++) { + if (is_effect_activated(iter->impr, iter->pcity, iter->pplayer, + iter->imeff, NULL) + && is_city_affected(iter->imeff, iter->pcity)) { + return iter->imeff; + } + } + iter->imeff = NULL; + } else if (ceff) { efflen = ceff_vector_size(ceff); for (; iter->index < efflen; iter->index++) { effect = ceff_vector_get(ceff, iter->index); @@ -1190,7 +1217,7 @@ do { imeff = eff_iterator_next_internal(iter); - if (imeff && is_unit_terrain_affected(imeff, iter->aff_unit, + if (imeff && is_unit_terrain_affected(imeff, &iter->aff_unit, iter->aff_terr, iter->aff_spec)) { return imeff; } @@ -1200,11 +1227,11 @@ /************************************************************************** Returns the next active effect that satisfies the various aff_xxx fields - passed (use UCL_LAST, T_UNKNOWN and/or S_ALL respectively if you want + passed (use NULL, T_UNKNOWN and/or S_ALL respectively if you want any value - except "None" - to match) **************************************************************************/ struct impr_effect *eff_iterator_next_full(struct eff_iter *iter, - Unit_Class_id aff_unit, + struct unit_classes *aff_unit, enum tile_terrain_type aff_terr, enum tile_special_type aff_spec) { @@ -1253,28 +1280,28 @@ /************************************************************************** Returns TRUE if the given effect should affect the given unit/terrain/special, by checking the relevant aff_xxx fields - (Pass in UCL_LAST, T_UNKNOWN, and S_ALL respectively if you don't care + (Pass in NULL, T_UNKNOWN, and S_ALL respectively if you don't care about that field; these values will match everything except "None".) **************************************************************************/ -int is_unit_terrain_affected(struct impr_effect *imeff, Unit_Class_id aff_unit, - enum tile_terrain_type aff_terr, - enum tile_special_type aff_spec) +int is_unit_terrain_affected(struct impr_effect *imeff, + struct unit_classes *aff_unit, + enum tile_terrain_type aff_terr, + enum tile_special_type aff_spec) { - return (aff_unit == UCL_LAST || imeff->aff_unit == UCL_LAST - || imeff->aff_unit == aff_unit) + return is_unit_class_in_set(imeff->aff_unit, aff_unit) && (((aff_terr == T_UNKNOWN && imeff->aff_terr != T_LAST) - || imeff->aff_terr == T_UNKNOWN || imeff->aff_terr == aff_terr) + || imeff->aff_terr == T_UNKNOWN || imeff->aff_terr == aff_terr) || imeff->aff_spec & aff_spec); } /************************************************************************** Returns the index of the improvement which provides the given effect - (constrained to the given unit class and player, if not UCL_LAST and + (constrained to the given unit class and player, if not 0 and NULL respectively) or B_LAST if no suitable improvement could be found. **************************************************************************/ Impr_Type_id get_improvement_for_effect(struct player *pplayer, enum effect_type id, - Unit_Class_id aff_unit) + struct unit_classes *aff_unit) { int impr; struct impr_effect *eff; diff -Nur -Xfreecivdiff.ignore freeciv-cvs/common/improvement.h freeciv-patched/common/improvement.h --- freeciv-cvs/common/improvement.h 2003-07-24 17:04:39.000000000 +0100 +++ freeciv-patched/common/improvement.h 2003-07-24 17:04:40.000000000 +0100 @@ -177,6 +177,9 @@ EFT_FORCE_CONTENT, EFT_FORCE_CONTENT_PCT, EFT_FORCE_HAPPY, + EFT_UNIT_ATTACK, + EFT_UNIT_ATTACK_FIREPOWER, + EFT_UNIT_DEFEND_FIREPOWER, EFT_LAST /* keep this last */ }; @@ -271,12 +274,14 @@ struct eff_iter { struct impr_effect *imeff; /* The next active effect */ struct city *pcity; + struct player *pplayer; Impr_Type_id impr; struct ceff_vector *effs[EFR_LAST]; enum effect_range range; int index; Eff_Status bitmask; - Unit_Class_id aff_unit; + Unit_Type_id utype; + struct unit_classes aff_unit; enum tile_terrain_type aff_terr; enum tile_special_type aff_spec; }; @@ -306,14 +311,16 @@ void eff_iterator_impr_init(struct eff_iter *iter, Impr_Type_id impr, struct city *pcity, struct player *pplayer); void eff_iterator_unit_init(struct eff_iter *iter, Unit_Type_id utype, + Unit_Type_id aff_utype, struct player *pplayer, struct map_position *mp); struct impr_effect *eff_iterator_next(struct eff_iter *iter); struct impr_effect *eff_iterator_next_full(struct eff_iter *iter, - Unit_Class_id aff_unit, + struct unit_classes *aff_unit, enum tile_terrain_type aff_terr, enum tile_special_type aff_spec); Impr_Type_id eff_iterator_get_improvement(struct eff_iter *iter); -int is_unit_terrain_affected(struct impr_effect *imeff, Unit_Class_id aff_unit, +int is_unit_terrain_affected(struct impr_effect *imeff, + struct unit_classes *aff_unit, enum tile_terrain_type aff_terr, enum tile_special_type aff_spec); int is_city_affected(struct impr_effect *imeff, struct city *pcity); @@ -358,22 +365,22 @@ } \ } -#define unit_effects_iterate(EI_iter, punit) \ +#define unit_effects_iterate(EI_iter, punit, aff_unit) \ { \ struct eff_iter EI_iter; \ struct map_position EI_mappos; \ EI_mappos.x = (punit)->x; EI_mappos.y = (punit)->y; \ - eff_iterator_unit_init(&iter, (punit)->type, unit_owner(punit), &EI_mappos); \ + eff_iterator_unit_init(&iter, (punit)->type, (aff_unit)->type, unit_owner(punit), &EI_mappos); \ while (eff_iterator_next(&EI_iter)) { #define unit_effects_iterate_end \ } \ } -#define unittype_effects_iterate(EI_iter, utype, pplayer, mappos) \ +#define unittype_effects_iterate(EI_iter, utype, aff_utype, pplayer, mappos) \ { \ struct eff_iter EI_iter; \ - eff_iterator_unit_init(&iter, utype, pplayer, mappos); \ + eff_iterator_unit_init(&iter, utype, aff_utype, pplayer, mappos); \ while (eff_iterator_next(&EI_iter)) { #define unittype_effects_iterate_end \ @@ -400,7 +407,7 @@ void improvement_status_init(Impr_Status * improvements, size_t elements); Impr_Type_id get_improvement_for_effect(struct player *pplayer, enum effect_type id, - Unit_Class_id aff_unit); + struct unit_classes *aff_unit); /* player related improvement and unit functions */ bool could_player_eventually_build_improvement(struct player *p, diff -Nur -Xfreecivdiff.ignore freeciv-cvs/common/packets.c freeciv-patched/common/packets.c --- freeciv-cvs/common/packets.c 2003-07-24 17:04:39.000000000 +0100 +++ freeciv-patched/common/packets.c 2003-07-24 17:04:40.000000000 +0100 @@ -178,6 +178,10 @@ return result; } +static void dio_put_effects(struct data_out *dout, + const struct impr_effect *effect); +static void dio_get_effects(struct data_in *din, struct impr_effect **peff); + /************************************************************************** presult indicates if there is more packets in the cache. We return result instead of just testing if the returning package is NULL as we sometimes @@ -1946,6 +1950,9 @@ dio_put_uint8(&dout, packet->default_government); dio_put_uint8(&dout, packet->government_when_anarchy); + if (has_capability("impr_gen", pc->capability)) { + dio_put_uint8(&dout, packet->num_unit_flags); + } dio_put_uint8(&dout, packet->num_unit_types); dio_put_uint8(&dout, packet->num_impr_types); dio_put_uint8(&dout, packet->num_tech_types); @@ -1996,6 +2003,11 @@ dio_get_uint8(&din, &packet->default_government); dio_get_uint8(&din, &packet->government_when_anarchy); + if (has_capability("impr_gen", pc->capability)) { + dio_get_uint8(&din, &packet->num_unit_flags); + } else { + packet->num_unit_flags = F_LAST; + } dio_get_uint8(&din, &packet->num_unit_types); dio_get_uint8(&din, &packet->num_impr_types); dio_get_uint8(&din, &packet->num_tech_types); @@ -2067,6 +2079,10 @@ } dio_put_uint8(&dout, packet->pop_cost); + if (has_capability("impr_gen", pc->capability)) { + dio_put_effects(&dout, packet->effect); + } + /* This must be last, so client can determine length: */ if(packet->helptext) { dio_put_string(&dout, packet->helptext); @@ -2127,6 +2143,13 @@ } dio_get_uint8(&din, &packet->pop_cost); + if (has_capability("impr_gen", pc->capability)) { + dio_get_effects(&din, &packet->effect); + } else { + packet->effect = fc_malloc(sizeof(struct impr_effect)); + packet->effect[0].type = EFT_LAST; + } + len = dio_input_remaining(&din); if (len > 0) { packet->helptext = fc_malloc(len); @@ -2212,11 +2235,40 @@ /************************************************************************** ... **************************************************************************/ +static void dio_put_effects(struct data_out *dout, + const struct impr_effect *effect) +{ + const struct impr_effect *eff; + int count; + + assert(effect != NULL); + + for (count = 0, eff = effect; eff->type != EFT_LAST; count++, eff++) { + /* nothing */ + } + + dio_put_uint8(dout, count); + for (eff = effect; eff->type != EFT_LAST; eff++) { + dio_put_uint8(dout, eff->type); + dio_put_uint8(dout, eff->range); + dio_put_sint16(dout, eff->amount); + dio_put_uint8(dout, eff->survives); + dio_put_uint8(dout, eff->cond_bldg); + dio_put_uint8(dout, eff->cond_gov); + dio_put_uint8(dout, eff->cond_adv); + dio_put_uint8(dout, eff->cond_eff); + dio_put_uint8(dout, eff->aff_unit); + dio_put_uint8(dout, eff->aff_terr); + dio_put_uint16(dout, eff->aff_spec); + } +} + +/************************************************************************** +... +**************************************************************************/ int send_packet_ruleset_building(struct connection *pc, const struct packet_ruleset_building *packet) { - struct impr_effect *eff; - int count; SEND_PACKET_START(PACKET_RULESET_BUILDING); dio_put_uint8(&dout, packet->id); @@ -2240,24 +2292,8 @@ dio_put_uint16(&dout, packet->build_cost); dio_put_uint8(&dout, packet->upkeep); dio_put_uint8(&dout, packet->sabotage); - for (count = 0, eff = packet->effect; eff->type != EFT_LAST; - count++, eff++) { - /* nothing */ - } - dio_put_uint8(&dout, count); - for (eff = packet->effect; eff->type != EFT_LAST; eff++) { - dio_put_uint8(&dout, eff->type); - dio_put_uint8(&dout, eff->range); - dio_put_sint16(&dout, eff->amount); - dio_put_uint8(&dout, eff->survives); - dio_put_uint8(&dout, eff->cond_bldg); - dio_put_uint8(&dout, eff->cond_gov); - dio_put_uint8(&dout, eff->cond_adv); - dio_put_uint8(&dout, eff->cond_eff); - dio_put_uint8(&dout, eff->aff_unit); - dio_put_uint8(&dout, eff->aff_terr); - dio_put_uint16(&dout, eff->aff_spec); - } + dio_put_effects(&dout, packet->effect); + dio_put_uint8(&dout, packet->variant); /* FIXME: remove when gen-impr obsoletes */ dio_put_string(&dout, packet->name); @@ -2280,10 +2316,37 @@ /************************************************************************** ... **************************************************************************/ +static void dio_get_effects(struct data_in *din, struct impr_effect **peff) +{ + int count, inx; + struct impr_effect *effect; + + dio_get_uint8(din, &count); + effect = fc_malloc((count + 1) * sizeof(struct impr_effect)); + for (inx = 0; inx < count; inx++) { + dio_get_uint8(din, (int *)&(effect[inx].type)); + dio_get_uint8(din, (int *)&(effect[inx].range)); + dio_get_sint16(din, &(effect[inx].amount)); + dio_get_uint8(din, &(effect[inx].survives)); + dio_get_uint8(din, &(effect[inx].cond_bldg)); + dio_get_uint8(din, &(effect[inx].cond_gov)); + dio_get_uint8(din, &(effect[inx].cond_adv)); + dio_get_uint8(din, (int *)&(effect[inx].cond_eff)); + dio_get_uint8(din, (int *)&(effect[inx].aff_unit)); + dio_get_uint8(din, (int *)&(effect[inx].aff_terr)); + dio_get_uint16(din, (int *)&(effect[inx].aff_spec)); + } + effect[count].type = EFT_LAST; + *peff = effect; +} + +/************************************************************************** +... +**************************************************************************/ struct packet_ruleset_building * receive_packet_ruleset_building(struct connection *pc) { - int len, inx, count; + int len; RECEIVE_PACKET_START(packet_ruleset_building, packet); dio_get_uint8(&din, &packet->id); @@ -2303,22 +2366,8 @@ dio_get_uint16(&din, &packet->build_cost); dio_get_uint8(&din, &packet->upkeep); dio_get_uint8(&din, &packet->sabotage); - dio_get_uint8(&din, &count); - packet->effect = fc_malloc((count + 1) * sizeof(struct impr_effect)); - for (inx = 0; inx < count; inx++) { - dio_get_uint8(&din, (int *)&(packet->effect[inx].type)); - dio_get_uint8(&din, (int *)&(packet->effect[inx].range)); - dio_get_sint16(&din, &(packet->effect[inx].amount)); - dio_get_uint8(&din, &(packet->effect[inx].survives)); - dio_get_uint8(&din, &(packet->effect[inx].cond_bldg)); - dio_get_uint8(&din, &(packet->effect[inx].cond_gov)); - dio_get_uint8(&din, &(packet->effect[inx].cond_adv)); - dio_get_uint8(&din, (int *)&(packet->effect[inx].cond_eff)); - dio_get_uint8(&din, (int *)&(packet->effect[inx].aff_unit)); - dio_get_uint8(&din, (int *)&(packet->effect[inx].aff_terr)); - dio_get_uint16(&din, (int *)&(packet->effect[inx].aff_spec)); - } - packet->effect[count].type = EFT_LAST; + dio_get_effects(&din, &packet->effect); + dio_get_uint8(&din, &packet->variant); /* FIXME: remove when gen-impr obsoletes */ dio_get_string(&din, packet->name, sizeof(packet->name)); diff -Nur -Xfreecivdiff.ignore freeciv-cvs/common/packets.h freeciv-patched/common/packets.h --- freeciv-cvs/common/packets.h 2003-07-24 17:04:39.000000000 +0100 +++ freeciv-patched/common/packets.h 2003-07-24 17:04:40.000000000 +0100 @@ -593,6 +593,7 @@ int sewer_size; int add_to_size_limit; int notradesize, fulltradesize; + int num_unit_flags; int num_unit_types; int num_impr_types; int num_tech_types; @@ -651,6 +652,7 @@ int paratroopers_range; /* max range of paratroopers, F_PARATROOPERS */ int paratroopers_mr_req; int paratroopers_mr_sub; + struct impr_effect *effect; /* Following is a pointer to malloced memory; on the server, it points to putype->helptext, malloced earlier; on the client, diff -Nur -Xfreecivdiff.ignore freeciv-cvs/common/unit.c freeciv-patched/common/unit.c --- freeciv-cvs/common/unit.c 2003-07-24 17:03:47.000000000 +0100 +++ freeciv-patched/common/unit.c 2003-07-24 17:04:40.000000000 +0100 @@ -334,15 +334,6 @@ } /************************************************************************** - Gets the class of a given unit, by examining the unit type's move_type - and flags fields -**************************************************************************/ -Unit_Class_id get_unit_class(struct unit *punit) -{ - return get_unittype_class(punit->type); -} - -/************************************************************************** ... **************************************************************************/ bool is_military_unit(struct unit *punit) @@ -409,6 +400,14 @@ /************************************************************************** ... **************************************************************************/ +void get_unit_classes(struct unit *punit, struct unit_classes *classes) +{ + get_unittype_classes(punit->type, classes); +} + +/************************************************************************** +... +**************************************************************************/ bool kills_citizen_after_attack(struct unit *punit) { return TEST_BIT(game.killcitizen, (int) (unit_type(punit)->move_type) - 1); @@ -1386,7 +1385,7 @@ if (player_knows_techs_with_flag(pplayer, TF_REDUCE_TRIREME_LOSS2)) { losspct = 12; } - eff_iterator_unit_init(&iter, punit->type, pplayer, mp); + eff_iterator_unit_init(&iter, punit->type, punit->type, pplayer, mp); while (eff_iterator_next(&iter)) { if (iter.imeff->type == EFT_NO_SINK_DEEP) { return 0; diff -Nur -Xfreecivdiff.ignore freeciv-cvs/common/unit.h freeciv-patched/common/unit.h --- freeciv-cvs/common/unit.h 2003-07-24 17:03:47.000000000 +0100 +++ freeciv-patched/common/unit.h 2003-07-24 17:04:40.000000000 +0100 @@ -228,13 +228,13 @@ bool is_military_unit(struct unit *punit); /* !set !dip !cara */ bool is_diplomat_unit(struct unit *punit); bool is_square_threatened(struct player *pplayer, int x, int y); -Unit_Class_id get_unit_class(struct unit *punit); bool is_field_unit(struct unit *punit); /* ships+aero */ bool is_hiding_unit(struct unit *punit); bool is_sailing_unit(struct unit *punit); bool is_air_unit(struct unit *punit); bool is_heli_unit(struct unit *punit); bool is_ground_unit(struct unit *punit); +void get_unit_classes(struct unit *punit, struct unit_classes *classes); bool can_unit_add_to_city (struct unit *punit); bool can_unit_build_city (struct unit *punit); bool can_unit_add_or_build_city (struct unit *punit); diff -Nur -Xfreecivdiff.ignore freeciv-cvs/common/unittype.c freeciv-patched/common/unittype.c --- freeciv-cvs/common/unittype.c 2003-07-24 17:02:27.000000000 +0100 +++ freeciv-patched/common/unittype.c 2003-07-24 17:04:40.000000000 +0100 @@ -39,10 +39,10 @@ static const char *move_type_names[] = { "Land", "Sea", "Heli", "Air" }; -static const char *flag_names[] = { +static char flag_names[F_MAX][MAX_LEN_NAME] = { "TradeRoute" ,"HelpWonder", "Missile", "IgZOC", "NonMil", "IgTer", - "Carrier", "OneAttack", "Pikemen", "Horse", "IgWall", "FieldUnit", - "AEGIS", "Fighter", "Marines", "Partial_Invis", "Settlers", "Diplomat", + "Carrier", "OneAttack", "(unused)", "(unused)", "IgWall", "FieldUnit", + "(unused)", "Fighter", "Marines", "Partial_Invis", "Settlers", "Diplomat", "Trireme", "Nuclear", "Spy", "Transform", "Paratroopers", "Airbase", "Cities", "IgTired", "Missile_Carrier", "No_Land_Attack", "AddToCity", "Fanatic" @@ -54,14 +54,6 @@ "BarbarianBuild", "BarbarianBuildTech", "BarbarianLeader", "BarbarianSea", "BarbarianSeaTech" }; -static const char *unit_class_names[] = { - "Air", - "Helicopter", - "Land", - "Missile", - "Nuclear", - "Sea" -}; /************************************************************************** Returns 1 if the unit_type "exists" in this game, 0 otherwise. @@ -103,29 +95,6 @@ return (unit_types[id].move_type == LAND_MOVING); } - /************************************************************************** - Gets the class of a given unit type, by examining the unit type's - move_type and flags fields -**************************************************************************/ -Unit_Class_id get_unittype_class(Unit_Type_id type) -{ - if (unit_type_flag(type, F_NUCLEAR)) { - return UCL_NUCLEAR; - } else if (unit_type_flag(type, F_MISSILE)) { - return UCL_MISSILE; - } else switch (get_unit_type(type)->move_type) { - case LAND_MOVING: - return UCL_LAND; - case SEA_MOVING: - return UCL_SEA; - case HELI_MOVING: - return UCL_HELICOPTER; - case AIR_MOVING: - return UCL_AIR; - } - return UCL_LAST; -} - /************************************************************************** ... **************************************************************************/ @@ -153,6 +122,39 @@ /************************************************************************** ... **************************************************************************/ +void get_unittype_classes(Unit_Type_id id, struct unit_classes *classes) +{ + struct unit_type *ut = get_unit_type(id); + + classes->move_type = ut->move_type; + classes->flags = ut->flags; +} + +/************************************************************************** +... +**************************************************************************/ +bool is_unit_class_in_set(Unit_Class_id id, struct unit_classes *classes) +{ + assert (id >= 0 && id <= UCL_LAST); + + if (id == UCL_LAST || !classes || classes->move_type == LAST_MOVING) { + return TRUE; + } else if (id < F_MAX) { + return BV_ISSET(classes->flags, id); + } else { + if (id - F_MAX == AIR_MOVING + && (BV_ISSET(classes->flags, F_NUCLEAR) + || BV_ISSET(classes->flags, F_MISSILE))) { + return FALSE; + } else { + return (classes->move_type == (id - F_MAX)); + } + } +} + +/************************************************************************** +... +**************************************************************************/ int utype_shield_cost(struct unit_type *ut, struct government *g) { if (government_has_flag(g, G_FANATIC_TROOPS) && @@ -191,7 +193,7 @@ **************************************************************************/ bool unit_type_flag(Unit_Type_id id, int flag) { - assert(flag>=0 && flag=0 && flag= 0) && (id < UCL_LAST)) { - return unit_class_names[id]; - } else { - return ""; - } -} - -/************************************************************************** Return a string with all the names of units with this flag Return NULL if no unit with this flag exists. The string must be free'd @@ -389,39 +379,30 @@ } /************************************************************************** - Convert Unit_Class_id names to enum; case insensitive; - returns UCL_LAST if can't match. -**************************************************************************/ -Unit_Class_id unit_class_from_str(const char *s) -{ - Unit_Class_id i; - - assert(ARRAY_SIZE(unit_class_names) == UCL_LAST); - - for (i = 0; i < UCL_LAST; i++) { - if (mystrcasecmp(unit_class_names[i], s)==0) { - return i; - } - } - return UCL_LAST; -} - -/************************************************************************** Convert flag names to enum; case insensitive; - returns F_LAST if can't match. + returns F_MAX if can't match. **************************************************************************/ enum unit_flag_id unit_flag_from_str(const char *s) { enum unit_flag_id i; - assert(ARRAY_SIZE(flag_names) == F_LAST); + assert(ARRAY_SIZE(flag_names) == F_MAX); - for(i=0; i= F_LAST && id < game.num_unit_flags && id < F_MAX); + sz_strlcpy(flag_names[id], s); } /************************************************************************** @@ -638,6 +619,9 @@ { struct unit_type *p = get_unit_type(id); + free(p->effect); + p->effect = NULL; + free(p->helptext); p->helptext = NULL; } diff -Nur -Xfreecivdiff.ignore freeciv-cvs/common/unittype.h freeciv-patched/common/unittype.h --- freeciv-cvs/common/unittype.h 2003-07-24 17:01:33.000000000 +0100 +++ freeciv-patched/common/unittype.h 2003-07-24 17:04:40.000000000 +0100 @@ -20,6 +20,7 @@ struct government; struct Sprite; /* opaque; client-gui specific */ struct unit; +struct impr_effect; typedef int Unit_Type_id; /* @@ -52,23 +53,10 @@ */ enum unit_move_type { - LAND_MOVING = 1, SEA_MOVING, HELI_MOVING, AIR_MOVING + LAND_MOVING = 1, SEA_MOVING, HELI_MOVING, AIR_MOVING, LAST_MOVING }; -/* Classes for unit types. - * (These must correspond to unit_class_names[] in unit.c.) - */ -enum unit_class_id { - UCL_AIR, - UCL_HELICOPTER, - UCL_LAND, - UCL_MISSILE, - UCL_NUCLEAR, - UCL_SEA, - UCL_LAST /* keep this last */ -}; - -typedef enum unit_class_id Unit_Class_id; +typedef int Unit_Class_id; /* Unit "special effects" flags: Note this is now an enumerated type, and not power-of-two integers @@ -148,6 +136,8 @@ }; #define L_MAX 64 +#define UCL_LAST (F_MAX + LAST_MOVING) + BV_DEFINE(bv_flags, F_MAX); BV_DEFINE(bv_roles, L_MAX); struct unit_type { @@ -187,9 +177,15 @@ int paratroopers_mr_req; int paratroopers_mr_sub; + struct impr_effect *effect; /* list; .type==EFT_LAST terminated */ + char *helptext; }; +struct unit_classes { + enum unit_move_type move_type; + bv_flags flags; +}; extern struct unit_type unit_types[U_LAST]; @@ -205,13 +201,13 @@ bool is_air_unittype(Unit_Type_id id); bool is_heli_unittype(Unit_Type_id id); bool is_ground_unittype(Unit_Type_id id); -Unit_Class_id get_unittype_class(Unit_Type_id type); +void get_unittype_classes(Unit_Type_id id, struct unit_classes *classes); +bool is_unit_class_in_set(Unit_Class_id id, struct unit_classes *classes); int unit_value(Unit_Type_id id); int unit_pop_value(Unit_Type_id id); const char *unit_name(Unit_Type_id id); -const char *unit_class_name(Unit_Class_id id); const char *get_unit_name(Unit_Type_id id); const char *get_units_with_flag_string(int flag); @@ -228,8 +224,8 @@ Unit_Type_id find_unit_type_by_name(const char *s); enum unit_move_type unit_move_type_from_str(const char *s); -Unit_Class_id unit_class_from_str(const char *s); enum unit_flag_id unit_flag_from_str(const char *s); +void unit_flag_set_name(enum unit_flag_id id, const char *s); enum unit_role_id unit_role_from_str(const char *s); bool can_player_build_unit_direct(struct player *p, Unit_Type_id id); diff -Nur -Xfreecivdiff.ignore freeciv-cvs/data/civ1/buildings.ruleset freeciv-patched/data/civ1/buildings.ruleset --- freeciv-cvs/data/civ1/buildings.ruleset 2003-07-24 17:04:14.000000000 +0100 +++ freeciv-patched/data/civ1/buildings.ruleset 2003-07-24 17:04:40.000000000 +0100 @@ -131,17 +131,9 @@ upkeep = 0 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" + { "type", "range" + "Unit_Veteran", "City" + "Unit_Repair", "City" } variant = 1 ; FIXME: remove when gen-impr obsoletes sound = "b_barracks_i" @@ -171,17 +163,9 @@ 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" + { "type", "range" + "Unit_Veteran", "City" + "Unit_Repair", "City" } sound = "b_barracks_ii" sound_alt = "b_generic" @@ -210,17 +194,9 @@ 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" + { "type", "range" + "Unit_Veteran", "City" + "Unit_Repair", "City" } sound = "b_barracks_iii" sound_alt = "b_generic" @@ -277,7 +253,7 @@ sabotage = 100 effect = { "type", "range", "amount", "aff_unit" - "Unit_Defend", "City", 300, "Helicopter" + "Unit_Defend", "City", 300, "Heli" "Unit_Defend", "City", 300, "Land" "Unit_Defend", "City", 300, "Sea" "Unit_No_Lose_Pop", "City", 0, "Land" diff -Nur -Xfreecivdiff.ignore freeciv-cvs/data/civ1/governments.ruleset freeciv-patched/data/civ1/governments.ruleset --- freeciv-cvs/data/civ1/governments.ruleset 2003-07-10 11:53:36.000000000 +0100 +++ freeciv-patched/data/civ1/governments.ruleset 2003-07-24 17:04:40.000000000 +0100 @@ -349,7 +349,7 @@ tech_req = "Communism" graphic = "gov.communism" graphic_alt = "-" -flags = "Build_Veteran_Diplomats" +flags = "-" hints = "Favors_Growth" subgoal = "Monarchy" diff -Nur -Xfreecivdiff.ignore freeciv-cvs/data/civ1/units.ruleset freeciv-patched/data/civ1/units.ruleset --- freeciv-cvs/data/civ1/units.ruleset 2003-07-10 11:53:36.000000000 +0100 +++ freeciv-patched/data/civ1/units.ruleset 2003-07-24 17:04:40.000000000 +0100 @@ -14,6 +14,9 @@ options="1.9" +[userflags] +names = "Horse" + ; Below: The individual units, one per section. ; ; The number can be variable, up to 200. @@ -284,8 +287,15 @@ uk_shield = 1 uk_food = 0 uk_gold = 0 -flags = "Pikemen" +flags = "" roles = "DefendGood", "FirstBuild" +effect = + { "type", "amount", "aff_unit" + "Unit_Defend", 200, "Horse" + } +helptext = _("\ +Gets double defense against units specified as 'mounted'.\ +") [unit_musketeers] name = _("Musketeers") @@ -628,6 +638,9 @@ uk_gold = 0 flags = "Horse" roles = "AttackFast" +helptext = _("\ +Counts as 'mounted' against certain defenders.\ +") [unit_knights] name = _("Knights") @@ -685,6 +698,9 @@ uk_gold = 0 flags = "Horse" roles = "AttackFast", "BarbarianBuildTech", "BarbarianSeaTech" +helptext = _("\ +Counts as 'mounted' against certain defenders.\ +") [unit_civ2_cavalry] name = "Civ2-Cavalry" ; no i18n @@ -1215,8 +1231,17 @@ uk_shield = 1 uk_food = 0 uk_gold = 0 -flags = "AEGIS" +flags = "" roles = "" +effect = + { "type", "amount", "aff_unit" + "Unit_Defend", 500, "Air" + "Unit_Defend", 500, "Heli" + "Unit_Defend", 500, "Missile" + } +helptext = _("\ +Gets quintuple defence against missiles, aeroplanes, and helicopters.\ +") [unit_battleship] name = _("Battleship") @@ -1441,6 +1466,10 @@ uk_gold = 0 flags = "Diplomat", "IgZOC", "NonMil" roles = "Explorer" +effect = + { "type", "cond_gov" + "Unit_Veteran", "Communism" + } helptext = _("\ - A Diplomat can establish embassies with other civilizations\ by moving into another player's city.\ @@ -1487,6 +1516,10 @@ uk_gold = 0 flags = "Diplomat", "IgZOC", "NonMil", "Spy" roles = "" +effect = + { "type", "cond_gov" + "Unit_Veteran", "Communism" + } [unit_caravan] name = _("Caravan") diff -Nur -Xfreecivdiff.ignore freeciv-cvs/data/civ2/governments.ruleset freeciv-patched/data/civ2/governments.ruleset --- freeciv-cvs/data/civ2/governments.ruleset 2003-07-10 11:53:36.000000000 +0100 +++ freeciv-patched/data/civ2/governments.ruleset 2003-07-24 17:04:40.000000000 +0100 @@ -351,7 +351,7 @@ tech_req = "Communism" graphic = "gov.communism" graphic_alt = "-" -flags = "Build_Veteran_Diplomats", "Inspires_Partisans" +flags = "Inspires_Partisans" hints = "Favors_Growth" subgoal = "Monarchy" diff -Nur -Xfreecivdiff.ignore freeciv-cvs/data/civ2/units.ruleset freeciv-patched/data/civ2/units.ruleset --- freeciv-cvs/data/civ2/units.ruleset 2003-07-10 11:53:36.000000000 +0100 +++ freeciv-patched/data/civ2/units.ruleset 2003-07-24 17:04:40.000000000 +0100 @@ -13,6 +13,9 @@ description="Civ2 unit_type data for Freeciv (approximate)" options="1.9" +[userflags] +names = "Horse" + ; Below: The individual units, one per section. ; ; The number can be variable, up to 200. @@ -288,8 +291,15 @@ uk_shield = 1 uk_food = 0 uk_gold = 0 -flags = "Pikemen" +flags = "" roles = "DefendGood", "FirstBuild" +effect = + { "type", "amount", "aff_unit" + "Unit_Defend", 200, "Horse" + } +helptext = _("\ +Gets double defense against units specified as 'mounted'.\ +") [unit_musketeers] name = _("Musketeers") @@ -570,6 +580,9 @@ uk_gold = 0 flags = "Horse" roles = "AttackFast", "Hut", "Barbarian" +helptext = _("\ +Counts as 'mounted' against certain defenders.\ +") [unit_chariot] name = _("Chariot") @@ -598,6 +611,9 @@ uk_gold = 0 flags = "Horse" roles = "AttackFast", "Hut" +helptext = _("\ +Counts as 'mounted' against certain defenders.\ +") [unit_elephants] name = _("Elephants") @@ -654,6 +670,9 @@ uk_gold = 0 flags = "Horse" roles = "AttackFast" +helptext = _("\ +Counts as 'mounted' against certain defenders.\ +") [unit_knights] name = _("Knights") @@ -683,6 +702,9 @@ flags = "Horse" roles = "AttackFast", "HutTech", "BarbarianTech", "BarbarianBuildTech", "BarbarianSeaTech" +helptext = _("\ +Counts as 'mounted' against certain defenders.\ +") [unit_dragoons] name = _("Dragoons") @@ -711,6 +733,9 @@ uk_gold = 0 flags = "Horse" roles = "AttackFast", "BarbarianBuildTech", "BarbarianSeaTech" +helptext = _("\ +Counts as 'mounted' against certain defenders.\ +") [unit_cavalry] name = _("Cavalry") @@ -963,11 +988,18 @@ uk_gold = 0 flags = "FieldUnit", "OneAttack" roles = "" +effect = + { "type", "amount", "aff_unit" + "Unit_Defend", 50, "Fighter" + "Unit_Defend_Firepower", 50, "Fighter" + } helptext = _("\ The Helicopter is a very powerful unit, as it can both fly and\ conquer cities. Care must be exercised, because Helicopters lose a\ small amount of health for every turn not spent in a city, unless\ you have the United Nations wonder.\ +Note that Helicopters suffer halved defense strength and firepower\ + when defending against Fighters.\ ") [unit_stealth_fighter] @@ -1259,8 +1291,17 @@ uk_shield = 1 uk_food = 0 uk_gold = 0 -flags = "AEGIS" +flags = "" roles = "" +effect = + { "type", "amount", "aff_unit" + "Unit_Defend", 500, "Air" + "Unit_Defend", 500, "Heli" + "Unit_Defend", 500, "Missile" + } +helptext = _("\ +Gets quintuple defence against missiles, aeroplanes, and helicopters.\ +") [unit_battleship] name = _("Battleship") @@ -1490,6 +1531,10 @@ uk_gold = 0 flags = "Diplomat", "IgZOC", "NonMil" roles = "" +effect = + { "type", "cond_gov" + "Unit_Veteran", "Communism" + } helptext = _("\ - A Diplomat can establish embassies with other civilizations\ by moving into another player's city.\ @@ -1536,6 +1581,10 @@ uk_gold = 0 flags = "Diplomat", "IgZOC", "NonMil", "Spy" roles = "" +effect = + { "type", "cond_gov" + "Unit_Veteran", "Communism" + } helptext = _("\ A Spy is a full time professional and as such is much more\ skilled in the arts of espionage than her Diplomat predecessor.\ diff -Nur -Xfreecivdiff.ignore freeciv-cvs/data/default/buildings.ruleset freeciv-patched/data/default/buildings.ruleset --- freeciv-cvs/data/default/buildings.ruleset 2003-07-24 17:04:14.000000000 +0100 +++ freeciv-patched/data/default/buildings.ruleset 2003-07-24 17:04:40.000000000 +0100 @@ -2030,7 +2030,7 @@ effect = { "type", "range", "amount", "aff_unit" "Unit_Recover", "Player", 2, "Air" - "Unit_Recover", "Player", 2, "Helicopter" + "Unit_Recover", "Player", 2, "Heli" "Unit_Recover", "Player", 2, "Land" "Unit_Recover", "Player", 2, "Missile" "Unit_Recover", "Player", 2, "Sea" diff -Nur -Xfreecivdiff.ignore freeciv-cvs/data/default/governments.ruleset freeciv-patched/data/default/governments.ruleset --- freeciv-cvs/data/default/governments.ruleset 2003-07-10 11:53:36.000000000 +0100 +++ freeciv-patched/data/default/governments.ruleset 2003-07-24 17:04:40.000000000 +0100 @@ -352,7 +352,7 @@ tech_req = "Communism" graphic = "gov.communism" graphic_alt = "-" -flags = "Build_Veteran_Diplomats", "Inspires_Partisans" +flags = "Inspires_Partisans" hints = "Favors_Growth" subgoal = "Monarchy" diff -Nur -Xfreecivdiff.ignore freeciv-cvs/data/default/units.ruleset freeciv-patched/data/default/units.ruleset --- freeciv-cvs/data/default/units.ruleset 2003-07-10 11:53:36.000000000 +0100 +++ freeciv-patched/data/default/units.ruleset 2003-07-24 17:04:40.000000000 +0100 @@ -21,6 +21,9 @@ description="Default unit_type data for Freeciv" options="1.9" +[userflags] +names = "Horse" + ; Below: The individual units, one per section. ; ; The number can be variable, up to 200. @@ -76,11 +79,11 @@ ; "Carrier" = can transport air and missile units, but not land units ; "Missile_Carrier" = can transport only missiles, but no aircraft or land units ; "OneAttack" = can only make a single attack, regardless of movement points -; "Pikemen" = double defence power against "Horse" flag units -; "Horse" = (no effect) -; "IgWall" = ignore effect of city walls +; "Pikemen" = (obsolete, used only by the AI) +; "Horse" = (obsolete, used only by the AI) +; "IgWall" = ignore Unit_Defend effects at City-range and greater ; "FieldUnit" = cause unhappiness even when not being aggressive -; "AEGIS" = fivefold increased defence against air attacks and missiles +; "AEGIS" = (obsolete, used only by the AI) ; "Fighter" = can attack air units (no other units can normally do this) ; "Marines" = (land only) can attack from transports ; "Partial_Invis" = visible only to adjancent units; does not hide transported @@ -359,8 +362,15 @@ uk_shield = 1 uk_food = 0 uk_gold = 0 -flags = "Pikemen" +flags = "" roles = "DefendGood", "FirstBuild" +effect = + { "type", "amount", "aff_unit" + "Unit_Defend", 200, "Horse" + } +helptext = _("\ +Gets double defense against units specified as 'mounted'.\ +") [unit_musketeers] name = _("Musketeers") @@ -635,6 +645,9 @@ uk_gold = 0 flags = "Horse" roles = "AttackFast", "Hut", "Barbarian" +helptext = _("\ +Counts as 'mounted' against certain defenders.\ +") [unit_chariot] name = _("Chariot") @@ -663,6 +676,9 @@ uk_gold = 0 flags = "Horse" roles = "AttackFast", "Hut" +helptext = _("\ +Counts as 'mounted' against certain defenders.\ +") [unit_elephants] name = _("Elephants") @@ -719,6 +735,9 @@ uk_gold = 0 flags = "Horse" roles = "AttackFast" +helptext = _("\ +Counts as 'mounted' against certain defenders.\ +") [unit_knights] name = _("Knights") @@ -748,6 +767,9 @@ flags = "Horse" roles = "AttackFast", "HutTech", "BarbarianTech", "BarbarianBuildTech", "BarbarianSeaTech" +helptext = _("\ +Counts as 'mounted' against certain defenders.\ +") [unit_dragoons] name = _("Dragoons") @@ -776,6 +798,9 @@ uk_gold = 0 flags = "Horse" roles = "AttackFast", "BarbarianBuildTech", "BarbarianSeaTech" +helptext = _("\ +Counts as 'mounted' against certain defenders.\ +") [unit_cavalry] name = _("Cavalry") @@ -1028,11 +1053,18 @@ uk_gold = 0 flags = "FieldUnit", "OneAttack" roles = "" +effect = + { "type", "amount", "aff_unit" + "Unit_Defend", 50, "Fighter" + "Unit_Defend_Firepower", 50, "Fighter" + } helptext = _("\ The Helicopter is a very powerful unit, as it can both fly and\ conquer cities. Care must be exercised, because Helicopters lose a\ small amount of health for every turn not spent in a city, unless\ you have the United Nations wonder.\ +Note that Helicopters suffer halved defense strength and firepower\ + when defending against Fighters.\ ") [unit_stealth_fighter] @@ -1324,8 +1356,17 @@ uk_shield = 1 uk_food = 0 uk_gold = 0 -flags = "AEGIS" +flags = "" roles = "DefendGood" +effect = + { "type", "amount", "aff_unit" + "Unit_Defend", 500, "Air" + "Unit_Defend", 500, "Heli" + "Unit_Defend", 500, "Missile" + } +helptext = _("\ +Gets quintuple defence against missiles, aeroplanes, and helicopters.\ +") [unit_battleship] name = _("Battleship") @@ -1555,6 +1596,10 @@ uk_gold = 0 flags = "Diplomat", "IgZOC", "NonMil" roles = "" +effect = + { "type", "cond_gov" + "Unit_Veteran", "Communism" + } helptext = _("\ - A Diplomat can establish embassies with other civilizations\ by moving into another player's city.\ @@ -1601,6 +1646,10 @@ uk_gold = 0 flags = "Diplomat", "IgZOC", "NonMil", "Spy" roles = "" +effect = + { "type", "cond_gov" + "Unit_Veteran", "Communism" + } helptext = _("\ A Spy is a full time professional and as such is much more\ skilled in the arts of espionage than her Diplomat predecessor.\ diff -Nur -Xfreecivdiff.ignore freeciv-cvs/doc/README.effects freeciv-patched/doc/README.effects --- freeciv-cvs/doc/README.effects 2003-07-24 17:02:53.000000000 +0100 +++ freeciv-patched/doc/README.effects 2003-07-24 17:04:40.000000000 +0100 @@ -214,6 +214,17 @@ of class .aff_unit (multiple effects are multiplicative) +"Unit_Attack" - multiplies attack by AMOUNT percent against units + of class .aff_unit (multiple effects are multiplicative) + +"Unit_Attack_Firepower"- multiplies firepower by AMOUNT percent + when attacking units of class .aff_unit (multiple + effects are multiplicative) + +"Unit_Defend_Firepower"- multiplies firepower by AMOUNT percent + when defending against units of class .aff_unit + (multiple effects are multiplicative) + "Unit_Move" - adds AMOUNT of movement points to units of class .aff_unit @@ -271,7 +282,8 @@ first affected by the given effect (if unspecified, effect not conditional on other effect) .aff_unit = affects only those units of this class; one of: - "Air", "Helicopter", "Land", "Missile", "Nuclear", "Sea" + "Air", "Heli", "Land", "Missile", "Nuclear", "Sea", + a unit flag, or a class defined in units.ruleset (if unspecified, may affect units of all classes) .aff_terr = affects only those squares of this terrain type (if unspecified, may affect all squares; if "None", diff -Nur -Xfreecivdiff.ignore freeciv-cvs/server/citytools.c freeciv-patched/server/citytools.c --- freeciv-cvs/server/citytools.c 2003-07-24 17:04:40.000000000 +0100 +++ freeciv-patched/server/citytools.c 2003-07-24 17:04:40.000000000 +0100 @@ -509,24 +509,16 @@ **************************************************************************/ bool do_make_unit_veteran(struct city *pcity, Unit_Type_id id) { - Unit_Class_id uclass; - enum tile_terrain_type tile_t; - enum tile_special_type spec_t; - - if (unit_type_flag(id, F_DIPLOMAT)) - return government_has_flag(get_gov_pcity(pcity), G_BUILD_VETERAN_DIPLOMAT); - - /* Fill in the particulars of the new unit, and the city */ - uclass = get_unittype_class(id); - tile_t = map_get_terrain(pcity->x, pcity->y); - spec_t = map_get_special(pcity->x, pcity->y); + struct map_position mappos; + mappos.x = pcity->x; + mappos.y = pcity->y; /* Do we have any veteran-making effects? */ - city_effects_iterate_full(iter, pcity, uclass, tile_t, spec_t) { + unittype_effects_iterate(iter, id, id, city_owner(pcity), &mappos) { if (iter.imeff->type == EFT_UNIT_VETERAN) { return TRUE; } - } city_effects_iterate_full_end; + } unittype_effects_iterate_end; return FALSE; } diff -Nur -Xfreecivdiff.ignore freeciv-cvs/server/ruleset.c freeciv-patched/server/ruleset.c --- freeciv-cvs/server/ruleset.c 2003-07-24 17:04:26.000000000 +0100 +++ freeciv-patched/server/ruleset.c 2003-07-24 17:04:40.000000000 +0100 @@ -74,6 +74,7 @@ static void load_tech_names(struct section_file *file); static void load_unit_names(struct section_file *file); +static void load_unit_userflags(struct section_file *file); static void load_building_names(struct section_file *file); static void load_government_names(struct section_file *file); static void load_terrain_names(struct section_file *file); @@ -658,6 +659,236 @@ } /************************************************************************** + ... +**************************************************************************/ +static void load_unit_userflags(struct section_file *file) +{ + char **slist; + int nval, i; + + game.num_unit_flags = F_LAST; + slist = secfile_lookup_str_vec(file, &nval, "userflags.names"); + if (nval > F_MAX - F_LAST) { + freelog(LOG_ERROR, "Too many user-specified unit flags (%d, max %d)", + nval, F_MAX - F_LAST); + exit(EXIT_FAILURE); + } + + game.num_unit_flags = F_LAST + nval; + for (i = 0; i < nval; ++i) { + unit_flag_set_name(F_LAST + i, slist[i]); + } + free(slist); +} + +/************************************************************************** +... +**************************************************************************/ +static struct impr_effect *load_effects(const char *secname, const char *name, + struct section_file *file, + bool unit_effects) +{ + int count, j, k; + char *item; + struct impr_effect *effects, *e; + const char *filename = secfile_filename(file); + bool problem; + + for (count = 0; + secfile_lookup_str_default(file, NULL, "%s.effect%d.type", secname, + count); count++) { + /* nothing */ + } + + if (count > MAX_EFFECTS) { + freelog(LOG_FATAL, "For %s maximum number of effects (%d) exceeded", + name, MAX_EFFECTS); + exit(EXIT_FAILURE); + } + + effects = fc_malloc((count + 1) * sizeof(struct impr_effect)); + k = 0; + for (j = 0; j < count; j++) { + e = &effects[k]; + problem = FALSE; + + item = secfile_lookup_str(file, "%s.effect%d.type", secname, 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)", + name, j, item, filename); + problem = TRUE; + } + + item = secfile_lookup_str_default(file, "None", + "%s.effect%d.range", secname, 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)", + name, j, item, filename); + problem = TRUE; + } + if (unit_effects) { + if (e->range != EFR_NONE) { + freelog(LOG_ERROR, + "for %s effect ranges are not currently supported (%s)", + name, filename); + problem = TRUE; + } + } + + /* For some effects the range doesn't really matter - so we fix it + to the most convenient range for the code to deal with */ + switch(e->type) { + case EFT_ADV_PARASITE: + case EFT_HAVE_EMBASSIES: + case EFT_REVEAL_CITIES: + case EFT_REVEAL_MAP: + case EFT_NO_ANARCHY: + case EFT_ANY_GOVERNMENT: + e->range = EFR_PLAYER; break; + case EFT_GIVE_IMM_ADV: + e->range = EFR_CITY; break; + default: + break; + } + + e->amount = secfile_lookup_int_default(file, 0, "%s.effect%d.amount", + secname, j); + + e->survives = secfile_lookup_int_default(file, 0, "%s.effect%d.survives", + secname, j); + + item = secfile_lookup_str_default(file, "", "%s.effect%d.cond_bldg", + secname, 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)", + name, j, item, filename); + problem = TRUE; + } + } else { + e->cond_bldg = B_LAST; + } + + item = secfile_lookup_str_default(file, "", "%s.effect%d.cond_gov", + secname, 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)", + name, j, item, filename); + e->cond_gov = game.government_count; + problem = TRUE; + } 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", + secname, 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)", + name, j, item, filename); + problem = TRUE; + } + } else { + e->cond_adv = A_NONE; + } + + item = secfile_lookup_str_default(file, "", "%s.effect%d.cond_eff", + secname, 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)", + name, j, item, filename); + problem = TRUE; + } + } else { + e->cond_eff = EFT_LAST; + } + + item = secfile_lookup_str_default(file, "", "%s.effect%d.aff_unit", + secname, j); + e->aff_unit = UCL_LAST; + if (*item != '\0') { + int index; + + index = unit_flag_from_str(item); + if (index != F_MAX) { + e->aff_unit = index; + } else { + index = unit_move_type_from_str(item); + if (index > 0) { + e->aff_unit = F_MAX + index; + } else { + freelog(LOG_ERROR, + "for %s effect[%d].aff_unit couldn't match type \"%s\" (%s)", + name, j, item, filename); + problem = TRUE; + } + } + } + + item = secfile_lookup_str_default(file, "", "%s.effect%d.aff_terr", + secname, j); + if (*item != '\0') { + if (0 == strcmp("None", item)) { + e->aff_terr = T_LAST; + } 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)", + name, j, item, filename); + e->aff_terr = T_LAST; + problem = TRUE; + } + } + } else { + e->aff_terr = T_UNKNOWN; + } + + item = secfile_lookup_str_default(file, "", "%s.effect%d.aff_spec", + secname, 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)", + name, j, item, filename); + problem = TRUE; + } + } + } else { + e->aff_spec = S_ALL; + } + + if (!problem) { + k++; + } + } + effects[k].type = EFT_LAST; + + return effects; +} + +/************************************************************************** ... **************************************************************************/ static void load_ruleset_units(struct section_file *file) @@ -760,6 +991,8 @@ u->food_cost = secfile_lookup_int(file, "%s.uk_food", sec[i]); u->gold_cost = secfile_lookup_int(file, "%s.uk_gold", sec[i]); + u->effect = load_effects(sec[i], u->name, file, TRUE); + u->helptext = lookup_helptext(file, sec[i]); } unit_type_iterate_end; @@ -776,7 +1009,7 @@ continue; } ival = unit_flag_from_str(sval); - if (ival==F_LAST) { + if (ival==F_MAX) { freelog(LOG_ERROR, "for unit_type \"%s\": bad flag name \"%s\" (%s)", u->name, sval, filename); } @@ -983,9 +1216,7 @@ char *datafile_options; 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); datafile_options = check_ruleset_capabilities(file, "+1.10.1", filename); @@ -1092,180 +1323,7 @@ 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; - } - - /* For some effects the range doesn't really matter - so we fix it - to the most convenient range for the code to deal with */ - switch(e->type) { - case EFT_ADV_PARASITE: - case EFT_HAVE_EMBASSIES: - case EFT_REVEAL_CITIES: - case EFT_REVEAL_MAP: - case EFT_NO_ANARCHY: - case EFT_ANY_GOVERNMENT: - e->range = EFR_PLAYER; break; - case EFT_GIVE_IMM_ADV: - e->range = EFR_CITY; break; - default: - break; - } - - 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; - } - } 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; - } 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; - } - } 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; - } - - 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; - } - - 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_LAST; - } 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_LAST; - problem = TRUE; - } - } - } 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; - } - } - } else { - e->aff_spec = S_ALL; - } - - if (!problem) { - k++; - } - } - b->effect[k].type = EFT_LAST; + b->effect = load_effects(sec[i], b->name, file, FALSE); /* FIXME: remove when gen-impr obsoletes */ b->variant = secfile_lookup_int_default(file, 0, "%s.variant", sec[i]); @@ -1284,16 +1342,13 @@ } /* Nasty kludge to let old code which assumes B_PALACE and B_CITY work */ - B_PALACE = get_improvement_for_effect(NULL, EFT_CAPITAL_CITY, UCL_LAST); + B_PALACE = get_improvement_for_effect(NULL, EFT_CAPITAL_CITY, NULL); if (B_PALACE == B_LAST) { freelog(LOG_ERROR, "Cannot find any capital city improvement"); exit(EXIT_FAILURE); } - B_CITY = get_improvement_for_effect(NULL, EFT_UNIT_DEFEND, UCL_LAND); - if (B_CITY == B_LAST) { - B_CITY = get_improvement_for_effect(NULL, EFT_UNIT_DEFEND, UCL_LAST); - } + B_CITY = get_improvement_for_effect(NULL, EFT_UNIT_DEFEND, NULL); if (B_CITY == B_LAST) { freelog(LOG_ERROR, "Cannot find any city walls improvement"); exit(EXIT_FAILURE); @@ -1688,6 +1743,8 @@ = secfile_lookup_int(file, "%s.production_shield_penalty,1", sec[i]); g->celeb_food_before_penalty = secfile_lookup_int(file, "%s.production_food_penalty,1", sec[i]); + + g->effect = load_effects(sec[i], g->name, file, FALSE); g->helptext = lookup_helptext(file, sec[i]); } government_iterate_end; @@ -1835,6 +1892,7 @@ packet.government_when_anarchy = game.government_when_anarchy; packet.default_government = game.default_government; + packet.num_unit_flags = game.num_unit_flags; packet.num_unit_types = game.num_unit_types; packet.num_impr_types = game.num_impr_types; packet.num_tech_types = game.num_tech_types; @@ -2544,6 +2602,7 @@ packet.paratroopers_range = u->paratroopers_range; packet.paratroopers_mr_req = u->paratroopers_mr_req; packet.paratroopers_mr_sub = u->paratroopers_mr_sub; + packet.effect = u->effect; /* pointer assignment */ packet.helptext = u->helptext; /* pointer assignment */ lsend_packet_ruleset_unit(dest, &packet); @@ -2879,6 +2938,7 @@ openload_ruleset_file(&unitfile, "units"); load_unit_names(&unitfile); + load_unit_userflags(&unitfile); openload_ruleset_file(&terrfile, "terrain"); load_terrain_names(&terrfile); diff -Nur -Xfreecivdiff.ignore freeciv-cvs/server/unittools.c freeciv-patched/server/unittools.c --- freeciv-cvs/server/unittools.c 2003-07-24 17:03:47.000000000 +0100 +++ freeciv-patched/server/unittools.c 2003-07-24 17:04:40.000000000 +0100 @@ -117,7 +117,7 @@ return; /* Do we have any veteran-making effects? */ - unit_effects_iterate(iter, punit) { + unit_effects_iterate(iter, punit, punit) { if (iter.imeff->type == EFT_UNIT_VET_COMBAT) { amount = MAX(amount, iter.imeff->amount); } @@ -229,7 +229,7 @@ struct unit_list candidates; int upgrade_all, upgrade_leap, i, candidate_to_upgrade = -1; int upgrade_type; - Unit_Class_id uclass; + struct unit_classes aff_unit; enum tile_special_type spec_t; enum tile_terrain_type tile_t; @@ -245,11 +245,11 @@ unit_list_init(&candidates); unit_list_iterate(pplayer->units, punit) { - uclass = get_unit_class(punit); tile_t = map_get_terrain(punit->x, punit->y); spec_t = map_get_special(punit->x, punit->y); + get_unit_classes(punit, &aff_unit); - if (is_unit_terrain_affected(iter->imeff, uclass, tile_t, spec_t) && + if (is_unit_terrain_affected(iter->imeff, &aff_unit, tile_t, spec_t) && (continent == -1 || continent == map_get_continent(punit->x, punit->y)) && (!pcity || pcity == map_get_city(punit->x, punit->y)) && @@ -607,7 +607,7 @@ int hp_recover = 0, move_modifier = 0; /* Add effects of generalised improvements */ - unit_effects_iterate(iter, punit) { + unit_effects_iterate(iter, punit, punit) { switch(iter.imeff->type) { case EFT_UNIT_REPAIR: fullrepair = TRUE;