diff -Nur -Xdiff_ignore freeciv_cvs/ai/aicity.c freeciv/ai/aicity.c --- freeciv_cvs/ai/aicity.c Tue Jan 23 14:45:02 2001 +++ freeciv/ai/aicity.c Fri Feb 16 16:13:25 2001 @@ -395,10 +395,8 @@ unit_types[bestchoice.choice].name); notify_player(pplayer, _("Game: %s disbanded in %s."), unit_types[punit->type].name, pcity->name); - /* FIXME: should be handled in server... */ - pcity->shield_stock+=(get_unit_type(punit->type)->build_cost/2); - send_city_info(pplayer, pcity); - wipe_unit_safe(punit, &myiter); + + do_unit_disband_safe(pcity, punit, &myiter); } } } diff -Nur -Xdiff_ignore freeciv_cvs/client/packhand.c freeciv/client/packhand.c --- freeciv_cvs/client/packhand.c Fri Feb 16 16:03:56 2001 +++ freeciv/client/packhand.c Fri Feb 16 16:13:25 2001 @@ -351,6 +351,8 @@ pcity->changed_from_id=packet->changed_from_id; pcity->changed_from_is_unit=packet->changed_from_is_unit; pcity->before_change_shields=packet->before_change_shields; + pcity->unit_disbanded_shields=packet->unit_disbanded_shields; + pcity->caravan_shields=packet->caravan_shields; i=0; for(y=0; yshield_stock; + int shield_stock_after_adjustment; + enum building_class_type orig_class; + enum building_class_type new_class; + int put_penalty; /* boolean */ - freelog(LOG_DEBUG, "compute change-production penalty: %s -> %s", - pcity->is_building_unit ? - unit_types[pcity->currently_building].name : - improvement_types[pcity->currently_building].name, - is_unit ? - unit_types[target].name : - improvement_types[target].name - ); - freelog(LOG_DEBUG, - "before: (stock=%d last/test=%d/%d changed=%d year=%d orig: %d %s)", - pcity->shield_stock, - pcity->turn_last_built, game_next_year(pcity->turn_last_built), - pcity->turn_changed_target, game.year, - pcity->before_change_shields, - pcity->changed_from_is_unit ? - unit_types[pcity->changed_from_id].name : - improvement_types[pcity->changed_from_id].name - ); + if (pcity->changed_from_is_unit) + orig_class=TYPE_UNIT; + else if (is_wonder(pcity->changed_from_id)) + orig_class=TYPE_WONDER; + else + orig_class=TYPE_NORMAL_IMPROVEMENT; - /* If already building this thing, nothing to do... */ - if ((pcity->is_building_unit == is_unit) && - (pcity->currently_building == target)) { - freelog(LOG_DEBUG, "...did not change production; do nothing"); - return shield_stock_after_adjustment; - } + if (is_unit) + new_class=TYPE_UNIT; + else if (is_wonder(target)) + new_class=TYPE_WONDER; + else + new_class=TYPE_NORMAL_IMPROVEMENT; - /* We're changing production... */ - if (((pcity->is_building_unit != is_unit) || - (!is_unit && - (is_wonder(pcity->currently_building) != is_wonder(target)))) && - (game_next_year(pcity->turn_last_built) < game.year)) { - /* We've changed "class", and it's not the turn immed after completion. */ - freelog(LOG_DEBUG, "...changed prod class in latter year"); - if (pcity->turn_changed_target != game.year) { - /* This is the first change this turn... */ - freelog(LOG_DEBUG, " ...first change this year; penalty"); - /* Compute new shield_stock after production penalty. */ - shield_stock_after_adjustment /= 2; - /* Only if really applying the penalty... */ - if (apply_it) { - /* Apply the penalty. */ - pcity->shield_stock = shield_stock_after_adjustment; - /* Only set turn_changed_target when we actually cop the penalty - - otherwise you can change to something of the same class first, - and suffer no penalty for any later changes in the same turn. */ - pcity->turn_changed_target = game.year; - } - } else if ((pcity->changed_from_is_unit == is_unit) && - (is_unit || - (is_wonder(pcity->changed_from_id) == is_wonder(target)))) { - /* This is a change back to the initial production class... */ - freelog(LOG_DEBUG, " ...revert to initial production class"); - /* Compute new shield_stock after reverting penalty. */ - shield_stock_after_adjustment = pcity->before_change_shields; - /* Only if really applying the penalty... */ - if (apply_it) { - /* Undo penalty. */ - pcity->shield_stock = shield_stock_after_adjustment; - /* Pretend we havn't changed this turn. */ - pcity->turn_changed_target = GAME_START_YEAR; - } -#ifdef DEBUG - } else { - freelog(LOG_DEBUG, " ...latter change in year; no penalty"); -#endif - } -#ifdef DEBUG - } else { - freelog(LOG_DEBUG, "...same class or first year; no penalty"); -#endif - } + put_penalty = (orig_class != new_class && + game_next_year(pcity->turn_last_built) < game.year)? 1 : 0; + + if (put_penalty) + shield_stock_after_adjustment = pcity->before_change_shields/2; + else + shield_stock_after_adjustment = pcity->before_change_shields; - freelog(LOG_DEBUG, - "--> %-3d (stock=%d last/test=%d/%d changed=%d year=%d orig: %d %s)", - shield_stock_after_adjustment, - pcity->shield_stock, - pcity->turn_last_built, game_next_year(pcity->turn_last_built), - pcity->turn_changed_target, game.year, - pcity->before_change_shields, - pcity->changed_from_is_unit ? - unit_types[pcity->changed_from_id].name : - improvement_types[pcity->changed_from_id].name - ); + /* Do not put penalty on these. It shouldn't matter whether you disband unit + before or after changing production...*/ + shield_stock_after_adjustment += pcity->unit_disbanded_shields; + if (new_class == TYPE_WONDER) /* No penalty! */ + shield_stock_after_adjustment += pcity->caravan_shields; + else /* Same as you had disbanded caravans. 50 percent penalty is logical! */ + shield_stock_after_adjustment += pcity->caravan_shields/2; + + if (apply_it) { + pcity->shield_stock = shield_stock_after_adjustment; + + if (new_class != orig_class) + pcity->turn_changed_target = game.year; + /* Do we really need this at all? */ + else + pcity->turn_changed_target = GAME_START_YEAR; + /* Pretend we have changed nothing */ + } + return shield_stock_after_adjustment; } diff -Nur -Xdiff_ignore freeciv_cvs/common/city.h freeciv/common/city.h --- freeciv_cvs/common/city.h Tue Jan 23 14:45:16 2001 +++ freeciv/common/city.h Fri Feb 16 16:13:25 2001 @@ -23,6 +23,9 @@ struct government; struct tile; +enum building_class_type { + TYPE_UNIT, TYPE_NORMAL_IMPROVEMENT, TYPE_WONDER +}; enum specialist_type { SP_ELVIS, SP_SCIENTIST, SP_TAXMAN @@ -215,6 +218,8 @@ int turn_changed_target; /* Suffer shield loss at most once per turn */ int changed_from_id; /* If changed this turn, what changed from (id) */ int changed_from_is_unit; /* If changed this turn, what changed from (unit?) */ + int unit_disbanded_shields; /* If you disband unit in a city. Count them */ + int caravan_shields; /* If caravan has helped city to build wonder. */ int before_change_shields; /* If changed this turn, shields before penalty */ int anarchy; /* anarchy rounds count */ int rapture; /* rapture rounds count */ diff -Nur -Xdiff_ignore freeciv_cvs/common/packets.c freeciv/common/packets.c --- freeciv_cvs/common/packets.c Thu Jan 25 14:25:57 2001 +++ freeciv/common/packets.c Fri Feb 16 16:13:25 2001 @@ -2237,6 +2237,11 @@ cptr=put_uint16(cptr, req->before_change_shields); } +if (pc && has_capability("production_change_fix2", pc->capability)) { + cptr=put_uint16(cptr, req->unit_disbanded_shields); + cptr=put_uint16(cptr, req->caravan_shields); +} + /* when removing "worklist_true_ids" capability, may want to remove the 'pc' argument (?) */ cptr=put_worklist(cptr, &req->worklist, pc, 1); @@ -2325,6 +2330,14 @@ packet->turn_changed_target = GAME_START_YEAR; packet->changed_from_id = packet->currently_building; packet->before_change_shields = packet->shield_stock; +} + +if (pc && has_capability("production_change_fix2", pc->capability)) { + iget_uint16(&iter, &packet->unit_disbanded_shields); + iget_uint16(&iter, &packet->caravan_shields); +} else { + packet->unit_disbanded_shields = 0; + packet->caravan_shields = 0; } /* when removing "worklist_true_ids" capability, diff -Nur -Xdiff_ignore freeciv_cvs/common/packets.h freeciv/common/packets.h --- freeciv_cvs/common/packets.h Thu Jan 25 14:25:57 2001 +++ freeciv/common/packets.h Fri Feb 16 16:13:25 2001 @@ -346,6 +346,8 @@ int changed_from_id; int changed_from_is_unit; int before_change_shields; + int unit_disbanded_shields; + int caravan_shields; struct worklist worklist; diff -Nur -Xdiff_ignore freeciv_cvs/server/cityhand.c freeciv/server/cityhand.c --- freeciv_cvs/server/cityhand.c Fri Feb 16 16:03:52 2001 +++ freeciv/server/cityhand.c Fri Feb 16 16:13:25 2001 @@ -272,6 +272,9 @@ pplayer->economic.gold-=cost; if (pcity->shield_stock < total){ + /* As we never put penalty on unit_disbanded_shields, we can + * fully well add the missing shields there. */ + pcity->unit_disbanded_shields += total - pcity->shield_stock; pcity->shield_stock=total; /* AI wants this -- Syela */ pcity->did_buy=1; /* !PS: no need to set buy flag otherwise */ } diff -Nur -Xdiff_ignore freeciv_cvs/server/citytools.c freeciv/server/citytools.c --- freeciv_cvs/server/citytools.c Fri Feb 16 16:03:56 2001 +++ freeciv/server/citytools.c Fri Feb 16 16:17:21 2001 @@ -820,7 +820,7 @@ pcity->improvements[i]=0; } } - pcity->before_change_shields = 0; + nullify_prechange_production(pcity); pcity->shield_stock = 0; } @@ -1019,6 +1019,8 @@ pcity->changed_from_id = 0; pcity->changed_from_is_unit = 0; pcity->before_change_shields = 0; + pcity->unit_disbanded_shields = 0; + pcity->caravan_shields = 0; pcity->anarchy=0; pcity->rapture=0; @@ -1493,6 +1495,8 @@ packet->changed_from_id=pcity->changed_from_id; packet->changed_from_is_unit=pcity->changed_from_is_unit; packet->before_change_shields=pcity->before_change_shields; + packet->unit_disbanded_shields=pcity->unit_disbanded_shields; + packet->caravan_shields=pcity->caravan_shields; copy_worklist(&packet->worklist, pcity->worklist); packet->diplomat_investigate=dipl_invest; diff -Nur -Xdiff_ignore freeciv_cvs/server/cityturn.c freeciv/server/cityturn.c --- freeciv_cvs/server/cityturn.c Fri Feb 16 16:03:56 2001 +++ freeciv/server/cityturn.c Fri Feb 16 16:13:25 2001 @@ -81,8 +81,9 @@ static void disband_city(struct city *pcity); -static void begin_city_turn(struct player *pplayer, struct city *pcity); +static void define_orig_production_values(struct city *pcity); static int update_city_activity(struct player *pplayer, struct city *pcity); +static void nullify_caravan_and_disband_plus(struct city *pcity); static void worker_loop(struct city *pcity, int *foodneed, int *prodneed, int *workers); @@ -835,7 +836,7 @@ void begin_cities_turn(struct player *pplayer) { city_list_iterate(pplayer->cities, pcity) - begin_city_turn(pplayer, pcity); + define_orig_production_values(pcity); city_list_iterate_end; } @@ -1306,11 +1307,16 @@ } unit_list_iterate_end; } - + + /* Now we confirm changes made last turn. */ pcity->shield_stock+=pcity->shield_surplus; + pcity->before_change_shields=pcity->shield_stock; + nullify_caravan_and_disband_plus(pcity); + if (!pcity->is_building_unit) { if (pcity->currently_building==B_CAPITAL) { pplayer->economic.gold+=pcity->shield_surplus; + pcity->before_change_shields=0; pcity->shield_stock=0; } upgrade_building_prod(pcity); @@ -1341,7 +1347,9 @@ space_part = 0; pcity->improvements[pcity->currently_building]=1; } - pcity->shield_stock-=improvement_value(pcity->currently_building); + pcity->before_change_shields-= + improvement_value(pcity->currently_building); + pcity->shield_stock-=improvement_value(pcity->currently_building); pcity->turn_last_built = game.year; /* to eliminate micromanagement */ if(is_wonder(pcity->currently_building)) { @@ -1432,7 +1440,8 @@ do_make_unit_veteran(pcity, pcity->currently_building), pcity->id, -1); /* to eliminate micromanagement, we only subtract the unit's cost */ - pcity->shield_stock-=unit_value(pcity->currently_building); + pcity->before_change_shields-=unit_value(pcity->currently_building); + pcity->shield_stock-=unit_value(pcity->currently_building); if (city_built_city_builder) { pcity->size--; @@ -1712,13 +1721,13 @@ /************************************************************************** Called every turn, at beginning of turn, for every city. **************************************************************************/ -static void begin_city_turn(struct player *pplayer, struct city *pcity) +static void define_orig_production_values(struct city *pcity) { /* remember what this city is building at start of turn, so user can switch production back without penalty */ pcity->changed_from_id = pcity->currently_building; pcity->changed_from_is_unit = pcity->is_building_unit; - pcity->before_change_shields = pcity->shield_stock; + freelog(LOG_DEBUG, "In %s, building %s. Beg of Turn shields = %d", pcity->name, @@ -1727,6 +1736,18 @@ improvement_types[pcity->changed_from_id].name, pcity->before_change_shields ); +} + +static void nullify_caravan_and_disband_plus(struct city *pcity) +{ + pcity->unit_disbanded_shields=0; + pcity->caravan_shields=0; +} + +void nullify_prechange_production(struct city *pcity) +{ + nullify_caravan_and_disband_plus(pcity); + pcity->before_change_shields=0; } /************************************************************************** diff -Nur -Xdiff_ignore freeciv_cvs/server/cityturn.h freeciv/server/cityturn.h --- freeciv_cvs/server/cityturn.h Fri Feb 16 16:03:52 2001 +++ freeciv/server/cityturn.h Fri Feb 16 16:13:25 2001 @@ -37,4 +37,5 @@ void remove_obsolete_buildings_city(struct city *pcity, int refresh); void remove_obsolete_buildings(struct player *plr); +void nullify_prechange_production(struct city *pcity); #endif /* FC__CITYTURN_H */ diff -Nur -Xdiff_ignore freeciv_cvs/server/diplomats.c freeciv/server/diplomats.c --- freeciv_cvs/server/diplomats.c Fri Feb 16 16:03:56 2001 +++ freeciv/server/diplomats.c Fri Feb 16 16:13:25 2001 @@ -802,7 +802,8 @@ pcity->name, get_nation_name (pplayer->nation)); pcity->shield_stock = 0; - + nullify_prechange_production(pcity); + /* You get a technology advance, too! */ get_a_tech (pplayer, cplayer); @@ -983,7 +984,8 @@ /* Do it. */ pcity->shield_stock = 0; - /* Report it. */ + nullify_prechange_production(pcity); /* Make it impossible to recover */ + /* Report it. */ if (pcity->is_building_unit) prod = unit_name (pcity->currently_building); else diff -Nur -Xdiff_ignore freeciv_cvs/server/savegame.c freeciv/server/savegame.c --- freeciv_cvs/server/savegame.c Fri Feb 16 16:03:53 2001 +++ freeciv/server/savegame.c Fri Feb 16 16:13:25 2001 @@ -775,7 +775,13 @@ pcity->before_change_shields= secfile_lookup_int_default(file, pcity->shield_stock, "player%d.c%d.before_change_shields", plrno, i); - + pcity->unit_disbanded_shields= + secfile_lookup_int_default(file, 0, + "player%d.c%d.unit_disbanded_shields", plrno, i); + pcity->caravan_shields= + secfile_lookup_int_default(file, 0, + "player%d.c%d.caravan_shields", plrno, i); + pcity->did_buy=secfile_lookup_int(file, "player%d.c%d.did_buy", plrno,i); pcity->did_sell = @@ -1417,6 +1423,11 @@ "player%d.c%d.changed_from_is_unit", plrno, i); secfile_insert_int(file, pcity->before_change_shields, "player%d.c%d.before_change_shields", plrno, i); + secfile_insert_int(file, pcity->unit_disbanded_shields, + "player%d.c%d.unit_disbanded_shields", plrno, i); + secfile_insert_int(file, pcity->caravan_shields, + "player%d.c%d.caravan_shields", plrno, i); + secfile_insert_int(file, pcity->anarchy, "player%d.c%d.anarchy", plrno,i); secfile_insert_int(file, pcity->rapture, "player%d.c%d.rapture", plrno,i); secfile_insert_int(file, pcity->was_happy, "player%d.c%d.was_happy", plrno,i); diff -Nur -Xdiff_ignore freeciv_cvs/server/unithand.c freeciv/server/unithand.c --- freeciv_cvs/server/unithand.c Fri Feb 16 16:03:53 2001 +++ freeciv/server/unithand.c Fri Feb 16 16:13:25 2001 @@ -332,7 +332,25 @@ Disband a unit. If its in a city, add 1/2 of the worth of the unit to the city's shield stock for the current production. "iter" may be NULL, see wipe_unit_safe for details. + NOTE: Ai calls do_unit_disband_safe directly, but player calls + of course handle_unit_disband_safe **************************************************************************/ +void do_unit_disband_safe(struct city *pcity, struct unit *punit, + struct genlist_iterator *iter) +{ + if (pcity) { + pcity->shield_stock+=(get_unit_type(punit->type)->build_cost/2); + /* If we change production later at this turn. No penalty is added. */ + pcity->unit_disbanded_shields+=(get_unit_type(punit->type)->build_cost/2); + + /* Note: Nowadays it's possible to disband unit in allied city and + * your ally receives those shields. Should it be like this? Why not? + * That's why we must use city_owner instead of pplayer -- Zamar */ + send_city_info(city_owner(pcity), pcity); + } + wipe_unit_safe(punit, iter); +} + void handle_unit_disband_safe(struct player *pplayer, struct packet_unit_request *req, struct genlist_iterator *iter) @@ -340,11 +358,8 @@ struct unit *punit; struct city *pcity; if((punit=player_find_unit_by_id(pplayer, req->unit_id))) { - if ((pcity=map_get_city(punit->x, punit->y))) { - pcity->shield_stock+=(get_unit_type(punit->type)->build_cost/2); - send_city_info(pplayer, pcity); - } - wipe_unit_safe(punit, iter); + pcity=map_get_city(punit->x, punit->y); + do_unit_disband_safe(pcity, punit, iter); } } @@ -1146,10 +1161,13 @@ /* we're there! */ pcity_dest->shield_stock+=50; - if (build_points_left(pcity_dest) < 0) { + pcity_dest->caravan_shields+=50; /*If we change production we dont lose them*/ + + /*if (build_points_left(pcity_dest) < 0) { pcity_dest->shield_stock = improvement_value(pcity_dest->currently_building); - } - + }*/ + /* No need for this. Overproduction should take care of this -- Zamar */ + conn_list_do_buffer(&pplayer->connections); notify_player_ex(pplayer, pcity_dest->x, pcity_dest->y, E_NOEVENT, _("Game: Your %s helps build the %s in %s (%d remaining)."), diff -Nur -Xdiff_ignore freeciv_cvs/server/unithand.h freeciv/server/unithand.h --- freeciv_cvs/server/unithand.h Tue Jan 9 14:40:23 2001 +++ freeciv/server/unithand.h Fri Feb 16 16:13:25 2001 @@ -33,6 +33,8 @@ void handle_unit_disband_safe(struct player *pplayer, struct packet_unit_request *req, struct genlist_iterator *iter); +void do_unit_disband_safe(struct city *pcity, struct unit *punit, + struct genlist_iterator *iter); /* Ai uses this directly */ void handle_unit_build_city(struct player *pplayer, struct packet_unit_request *req); void handle_unit_info(struct player *pplayer, struct packet_unit_info *pinfo);