diff -Nur -X/data/freeciv-dev/freeciv/diff_ignore freeciv/client/packhand.c transciv/client/packhand.c --- freeciv/client/packhand.c Wed Jan 10 16:38:52 2001 +++ transciv/client/packhand.c Wed Jan 10 16:40:46 2001 @@ -282,17 +282,8 @@ pcity=find_city_by_id(packet->id); if (pcity && (pcity->owner != packet->owner)) { - /* With current server, this shouldn't happen: when city changes - * owner it is re-created with a new id. Unclear what to do here; - * try to cope... - */ - freelog(LOG_ERROR, - "Got existing city id (%d %s) with wrong owner (%d %s, old %d %s)", - packet->id, pcity->name, packet->owner, - get_player(packet->owner)->name, pcity->owner, - get_player(pcity->owner)->name); client_remove_city(pcity); - pcity = 0; + pcity = NULL; } if(!pcity) { @@ -331,7 +322,7 @@ pcity->ppl_taxman=packet->ppl_taxman; pcity->city_options=packet->city_options; - + for (i=0;i<4;i++) { pcity->trade[i]=packet->trade[i]; pcity->trade_value[i]=packet->trade_value[i]; @@ -499,15 +490,6 @@ pcity=find_city_by_id(packet->id); if (pcity && (pcity->owner != packet->owner)) { - /* With current server, this shouldn't happen: when city changes - * owner it is re-created with a new id. Unclear what to do here; - * try to cope... - */ - freelog(LOG_ERROR, - "Got existing city id (%d %s) with wrong owner (%d %s, old %d %s)", - packet->id, pcity->name, packet->owner, - get_player(packet->owner)->name, pcity->owner, - get_player(pcity->owner)->name); client_remove_city(pcity); pcity = 0; } diff -Nur -X/data/freeciv-dev/freeciv/diff_ignore freeciv/server/cityhand.c transciv/server/cityhand.c --- freeciv/server/cityhand.c Wed Jan 10 16:38:57 2001 +++ transciv/server/cityhand.c Wed Jan 10 16:50:43 2001 @@ -53,7 +53,6 @@ static void package_dumb_city(struct player* pplayer, int x, int y, struct packet_short_city *packet); -static void remove_trade_route(int c1, int c2); static void send_adjacent_cities(struct city *pcity); char **misc_city_names; @@ -891,7 +890,7 @@ /************************************************************************** ... **************************************************************************/ -static void remove_trade_route(int c1, int c2) +void remove_trade_route(int c1, int c2) { int i; struct city *pc1, *pc2; @@ -905,7 +904,7 @@ } if (pc2) { for (i=0;i<4;i++) - if (pc2->trade[i]==c2) + if (pc2->trade[i]==c1) pc2->trade[i]=0; } } @@ -994,26 +993,6 @@ if (pcity->city_map[x][y] == C_TILE_WORKER) set_worker_city(pcity, x, y, C_TILE_WORKER); } -} - -/************************************************************************** -The following has to be called every time a city, pcity, has changed -owner to update the city's traderoutes. -**************************************************************************/ -void reestablish_city_trade_routes(struct city *pcity) -{ - int i; - struct city *oldtradecity; - - for (i=0;i<4;i++) { - if (pcity->trade[i]) { - oldtradecity=find_city_by_id(pcity->trade[i]); - pcity->trade[i]=0; - if (can_establish_trade_route(pcity, oldtradecity)) { - establish_trade_route(pcity, oldtradecity); - } - } - } } /************************************************************************** diff -Nur -X/data/freeciv-dev/freeciv/diff_ignore freeciv/server/cityhand.h transciv/server/cityhand.h --- freeciv/server/cityhand.h Wed Jan 10 16:39:00 2001 +++ transciv/server/cityhand.h Wed Jan 10 16:40:54 2001 @@ -55,9 +55,9 @@ int establish_trade_route(struct city *pc1, struct city *pc2); +void remove_trade_route(int c1, int c2); void send_player_cities(struct player *pplayer); void update_map_with_city_workers(struct city *pcity); -void reestablish_city_trade_routes(struct city *pcity); void handle_city_options(struct player *pplayer, struct packet_generic_values *preq); diff -Nur -X/data/freeciv-dev/freeciv/diff_ignore freeciv/server/citytools.c transciv/server/citytools.c --- freeciv/server/citytools.c Wed Jan 10 16:39:04 2001 +++ transciv/server/citytools.c Wed Jan 10 17:03:14 2001 @@ -14,6 +14,7 @@ #include #endif +#include #include #include @@ -36,6 +37,7 @@ #include "cityhand.h" #include "cityturn.h" #include "gamehand.h" /* send_game_info */ +#include "gamelog.h" #include "maphand.h" #include "player.h" #include "plrhand.h" @@ -635,46 +637,47 @@ Interpretation of kill_outside changed to mean the radius outside of which supported units are killed. If 0, all supported units not in the city are killed. If -1, no supported units are killed. --jjm - - pcity can be NULL. ***********************************************************************/ void transfer_city_units(struct player *pplayer, struct player *pvictim, - struct city *pcity, struct city *vcity, + struct unit_list *units, struct city *pcity, + struct city *exclude_city, int kill_outside, int verbose) { - int x = vcity->x; - int y = vcity->y; + int x = pcity->x; + int y = pcity->y; /* Transfer enemy units in the city to the new owner */ unit_list_iterate(map_get_tile(x, y)->units, vunit) { /* Dont transfer units already owned by new city-owner --wegge */ if (unit_owner(vunit) == pvictim && pcity) { freelog(LOG_VERBOSE, "Transfered %s in %s from %s to %s", - unit_name(vunit->type), vcity->name, pvictim->name, pplayer->name); + unit_name(vunit->type), pcity->name, pvictim->name, pplayer->name); if (verbose) { notify_player(pvictim, _("Game: Transfered %s in %s from %s to %s."), - unit_name(vunit->type), vcity->name, + unit_name(vunit->type), pcity->name, pvictim->name, pplayer->name); } create_unit_full(pplayer, x, y, vunit->type, vunit->veteran, pcity->id, vunit->moves_left, vunit->hp); + unit_list_unlink(units, vunit); + vunit->homecity = 0; wipe_unit_safe(vunit, &myiter); } } unit_list_iterate_end; /* Any remaining units supported by the city are either given new home * cities or maybe destroyed */ - unit_list_iterate(vcity->units_supported, vunit) { - struct city* new_home_city = map_get_city(vunit->x, vunit->y); - if(new_home_city) { + unit_list_iterate(*units, vunit) { + struct city *new_home_city = map_get_city(vunit->x, vunit->y); + if (new_home_city && new_home_city != exclude_city) { /* unit is in another city: make that the new homecity, unless that city is actually the same city (happens if disbanding) */ if (pvictim == city_owner(new_home_city)) { freelog(LOG_VERBOSE, "Changed homecity of %s's %s in %s", pvictim->name, unit_name(vunit->type), new_home_city->name); - if(verbose) { + if (verbose) { notify_player(pvictim, _("Game: Changed homecity of %s in %s."), unit_name(vunit->type), new_home_city->name); } @@ -688,19 +691,13 @@ pvictim->name, pplayer->name); } } - if(new_home_city != vcity) { - create_unit_full(city_owner(new_home_city), vunit->x, vunit->y, - vunit->type, vunit->veteran, new_home_city->id, - vunit->moves_left, vunit->hp); - } else if (pcity){ - create_unit_full(pplayer, vunit->x, vunit->y, - vunit->type, vunit->veteran, pcity->id, - vunit->moves_left, vunit->hp); - } - } else if(((kill_outside < 0) || - ((kill_outside > 0) && - (real_map_distance(vunit->x, vunit->y, x, y) <= kill_outside))) - && pcity) { + create_unit_full(city_owner(new_home_city), vunit->x, vunit->y, + vunit->type, vunit->veteran, new_home_city->id, + vunit->moves_left, vunit->hp); + } else if (((kill_outside < 0) || + ((kill_outside > 0) && + (real_map_distance(vunit->x, vunit->y, x, y) <= kill_outside))) + && pcity) { freelog(LOG_VERBOSE, "Transfered %s at (%d, %d) from %s to %s", unit_name(vunit->type), vunit->x, vunit->y, pvictim->name, pplayer->name); @@ -715,6 +712,8 @@ vunit->hp); } + unit_list_unlink(units, vunit); + vunit->homecity = 0; wipe_unit_spec_safe(vunit, NULL, 0); } unit_list_iterate_end; @@ -1006,15 +1005,7 @@ a unit from another city, and both cities join the rebellion. We resolved stack conflicts for each city we would teleport the first of the units we met since the other would have another owner */ - if(!(pnewcity = transfer_city(cplayer, pplayer, pcity, -1, 0, 0, 0))){ - freelog(LOG_VERBOSE, - "Transfer city returned no city - aborting civil war."); - unit_list_iterate(pplayer->units, punit) - resolve_unit_stack(punit->x, punit->y, 0); - unit_list_iterate_end; - return; - } - + pnewcity = transfer_city(cplayer, pcity, -1, 0, 0, 0); freelog(LOG_VERBOSE, "%s declares allegiance to %s", pnewcity->name, cplayer->name); notify_player(pplayer, _("Game: %s declares allegiance to %s."), @@ -1068,116 +1059,138 @@ pcity->shield_stock = 0; } +/************************************************************************** +The following has to be called every time a city, pcity, has changed +owner to update the city's traderoutes. +**************************************************************************/ +static void reestablish_city_trade_routes(struct city *pcity, int cities[4]) +{ + int i; + struct city *oldtradecity; + + for (i=0; i<4; i++) { + if (cities[i]) { + oldtradecity = find_city_by_id(cities[i]); + assert(oldtradecity); + if (can_establish_trade_route(pcity, oldtradecity)) { + establish_trade_route(pcity, oldtradecity); + } + /* refresh regardless; either it lost a trade route or + the trade route revenue changed. */ + city_refresh(oldtradecity); + send_city_info(city_owner(oldtradecity), oldtradecity); + } + } +} + /********************************************************************** Handles all transactions in relation to transferring a city. The kill_outside and transfer_unit_verbose arguments are passed to transfer_city_units(), which is called in the middle of the function. ***********************************************************************/ -struct city *transfer_city(struct player *pplayer, struct player *cplayer, +struct city *transfer_city(struct player *ptaker, struct city *pcity, int kill_outside, int transfer_unit_verbose, int resolve_stack, int raze) { - struct city *pnewcity; - int *resolve_list=NULL; - int i, no_units=0; - - if (!pcity) - return NULL; - - if (cplayer==pplayer || cplayer==NULL) - return NULL; - - if(pcity->owner != cplayer->player_no) - return NULL; + struct map_position *resolve_list = NULL; + int i, no_units = 0; + struct unit_list old_city_units; + struct player *pgiver = city_owner(pcity); + int old_trade_routes[4]; + + assert(pgiver != ptaker); + + old_city_units = pcity->units_supported; + unit_list_iterate(old_city_units, punit) { + /* otherwise they would point to a bad city. */ + punit->homecity = 0; + } unit_list_iterate_end; + unit_list_init(&pcity->units_supported); - pnewcity=fc_malloc(sizeof(struct city)); - *pnewcity=*pcity; - pnewcity->worklist = fc_malloc(sizeof(struct worklist)); - *pnewcity->worklist = *pcity->worklist; - - pnewcity->id=get_next_id_number(); - idex_register_city(pnewcity); - - for (i = 0; i < game.num_impr_types; i++) { - if (is_wonder(i) && city_got_building(pnewcity, i)) - game.global_wonders[i] = pnewcity->id; - } - pnewcity->owner = pplayer->player_no; - unit_list_init(&pnewcity->units_supported); - city_list_insert(&pplayer->cities, pnewcity); + city_list_unlink(&pgiver->cities, pcity); + pcity->owner = ptaker->player_no; + city_list_insert(&ptaker->cities, pcity); - give_citymap_from_player_to_player(pcity, cplayer, pplayer); - map_unfog_city_area(pnewcity); + give_citymap_from_player_to_player(pcity, pgiver, ptaker); + map_unfog_city_area(pcity); /* transfer_city_units() destroys the city's units_supported list; we save the list so we can resolve units afterwards. */ if (resolve_stack) { - no_units = unit_list_size(&(pcity->units_supported)); + no_units = unit_list_size(&old_city_units); if (no_units > 0) { - resolve_list = fc_malloc(no_units * 2 * sizeof(int)); + resolve_list = fc_malloc(no_units * sizeof(struct map_position)); if (resolve_list) { i = 0; - unit_list_iterate(pcity->units_supported, punit) { - resolve_list[i] = punit->x; - resolve_list[i+1] = punit->y; - i += 2; + unit_list_iterate(old_city_units, punit) { + resolve_list[i].x = punit->x; + resolve_list[i].y = punit->y; + i++; } unit_list_iterate_end; + assert(i == no_units); } } } - transfer_city_units(pplayer, cplayer, pnewcity, pcity, + transfer_city_units(ptaker, pgiver, &old_city_units, + pcity, NULL, kill_outside, transfer_unit_verbose); - remove_city(pcity); - map_set_city(pnewcity->x, pnewcity->y, pnewcity); - reset_move_costs(pnewcity->x, pnewcity->y); + /* The units themselves are allready freed by transfer_city_units. */ + unit_list_unlink_all(&old_city_units); + reset_move_costs(pcity->x, pcity->y); if (resolve_stack && (no_units > 0) && resolve_list) { - for (i = 0; i < no_units * 2; i += 2) - resolve_unit_stack(resolve_list[i], resolve_list[i+1], + for (i = 0; i < no_units ; i++) + resolve_unit_stack(resolve_list[i].x, resolve_list[i].y, transfer_unit_verbose); free(resolve_list); } - reestablish_city_trade_routes(pnewcity); - city_check_workers(pnewcity, 1); - update_map_with_city_workers(pnewcity); - city_refresh(pnewcity); - initialize_infrastructure_cache(pnewcity); + /* Update the city's trade routes. */ + for (i=0; i<4; i++) + old_trade_routes[i] = pcity->trade[i]; + for (i=0; i<4; i++) + remove_trade_route(pcity->trade[i], pcity->id); + reestablish_city_trade_routes(pcity, old_trade_routes); + + + city_check_workers(pcity, 1); + update_map_with_city_workers(pcity); + city_refresh(pcity); + initialize_infrastructure_cache(pcity); if (raze) - raze_city(pnewcity); + raze_city(pcity); /* If the city was building something we haven't invented we must change production. */ /* advisor_choose_build(pcity); we add the civ bug here :) */ - send_city_info(0, pnewcity); + send_city_info(0, pcity); /* What wasn't obsolete for the old owner may be so now. */ - remove_obsolete_buildings_city(pnewcity, 1); - - if (terrain_control.may_road && - (player_knows_techs_with_flag (pplayer, TF_RAILROAD)) && - (!player_knows_techs_with_flag (cplayer, TF_RAILROAD)) && - (!(map_get_special (pnewcity->x, pnewcity->y) & S_RAILROAD))) { - notify_player (pplayer, - _("Game: The people in %s are stunned by your" - " technological insight!\n" - " Workers spontaneously gather and upgrade" - " the city with railroads."), - pnewcity->name); - map_set_special (pnewcity->x, pnewcity->y, S_RAILROAD); - send_tile_info (0, pnewcity->x, pnewcity->y); - } - - /* We lose visibility as the old city is removed, and if the square isn't - shown here the old owner will never get told about the new city */ - update_dumb_city(cplayer, pnewcity); - send_city_info(cplayer, pnewcity); + remove_obsolete_buildings_city(pcity, 1); - maybe_make_first_contact(pnewcity->x, pnewcity->y, pplayer->player_no); + if (terrain_control.may_road + && player_knows_techs_with_flag (ptaker, TF_RAILROAD) + && !(map_get_special(pcity->x, pcity->y) & S_RAILROAD)) { + notify_player(ptaker, + _("Game: The people in %s are stunned by your" + " technological insight!\n" + " Workers spontaneously gather and upgrade" + " the city with railroads."), + pcity->name); + map_set_special(pcity->x, pcity->y, S_RAILROAD); + send_tile_info(0, pcity->x, pcity->y); + } + + map_fog_pseudo_city_area(pgiver, pcity->x, pcity->y); + maybe_make_first_contact(pcity->x, pcity->y, ptaker->player_no); + + gamelog(GAMELOG_LOSEC,"%s lose %s (%i,%i)", + get_nation_name_plural(pgiver->nation), + pcity->name, pcity->x, pcity->y); - return pnewcity; + return pcity; } /************************************************************************** diff -Nur -X/data/freeciv-dev/freeciv/diff_ignore freeciv/server/citytools.h transciv/server/citytools.h --- freeciv/server/citytools.h Wed Jan 10 16:39:07 2001 +++ transciv/server/citytools.h Wed Jan 10 16:41:01 2001 @@ -57,11 +57,12 @@ int worst_worker_tile_value(struct city *pcity); int best_worker_tile_value(struct city *pcity); void transfer_city_units(struct player *pplayer, struct player *pvictim, - struct city *pcity, struct city *vcity, + struct unit_list *units, struct city *pcity, + struct city *exclude_city, int kill_outside, int verbose); int civil_war_triggered(struct player *pplayer); void civil_war(struct player *pplayer); -struct city *transfer_city(struct player *pplayer, struct player *cplayer, +struct city *transfer_city(struct player *pplayer, struct city *pcity, int kill_outside, int transfer_unit_verbose, int resolve_stack, int raze); struct city *find_closest_owned_city(struct player *pplayer, int x, int y, diff -Nur -X/data/freeciv-dev/freeciv/diff_ignore freeciv/server/cityturn.c transciv/server/cityturn.c --- freeciv/server/cityturn.c Wed Jan 10 16:39:11 2001 +++ transciv/server/cityturn.c Wed Jan 10 16:41:04 2001 @@ -1809,7 +1809,7 @@ pcity->id, -1); /* shift all the units supported by pcity (including the new settler) to rcity */ - transfer_city_units(pplayer, pplayer, rcity, pcity, -1, 1); + transfer_city_units(pplayer, pplayer, &pcity->units_supported, rcity, pcity, -1, 1); notify_player_ex(pplayer, x, y, E_UNIT_BUILD, _("Game: %s is disbanded into %s."), diff -Nur -X/data/freeciv-dev/freeciv/diff_ignore freeciv/server/diplhand.c transciv/server/diplhand.c --- freeciv/server/diplhand.c Wed Jan 10 16:39:14 2001 +++ transciv/server/diplhand.c Wed Jan 10 16:41:10 2001 @@ -193,7 +193,7 @@ notify_player(pgiver, _("Game: You give city of %s to %s."), pcity->name, pdest->name); - if(!(pnewcity = transfer_city(pdest, pgiver, pcity, -1, 1, 1, 0))){ + if (!(pnewcity = transfer_city(pdest, pcity, -1, 1, 1, 0))) { freelog(LOG_NORMAL, "Transfer city returned no city - skipping clause."); break; } diff -Nur -X/data/freeciv-dev/freeciv/diff_ignore freeciv/server/diplomats.c transciv/server/diplomats.c --- freeciv/server/diplomats.c Wed Jan 10 16:39:17 2001 +++ transciv/server/diplomats.c Wed Jan 10 16:41:14 2001 @@ -817,7 +817,7 @@ are within one square of the city) to the new owner. Remember that pcity is destroyed as part of the transfer, Which is why we do this last */ - transfer_city (pplayer, cplayer, pcity, 1, 1, 1, 0); + transfer_city (pplayer, pcity, 1, 1, 1, 0); /* Update the players gold in the client */ send_player_info(pplayer, pplayer); diff -Nur -X/data/freeciv-dev/freeciv/diff_ignore freeciv/server/unithand.c transciv/server/unithand.c --- freeciv/server/unithand.c Wed Jan 10 16:39:20 2001 +++ transciv/server/unithand.c Wed Jan 10 16:41:17 2001 @@ -1336,7 +1336,7 @@ get_a_tech(pplayer, cplayer); make_partisans(pcity); - transfer_city(pplayer, cplayer, pcity , 0, 0, 1, 1); + transfer_city(pplayer, pcity , 0, 0, 1, 1); send_player_info(pplayer, pplayer); /* Update techs */ if (do_civil_war)