diff -Nur -X/data/freeciv-dev/freeciv/diff_ignore freeciv/client/packhand.c crashciv/freeciv/client/packhand.c --- freeciv/client/packhand.c Tue Jan 9 01:19:00 2001 +++ crashciv/freeciv/client/packhand.c Tue Jan 9 20:31:28 2001 @@ -282,15 +282,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; } @@ -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/citytools.c crashciv/freeciv/server/citytools.c --- freeciv/server/citytools.c Tue Jan 9 00:15:52 2001 +++ crashciv/freeciv/server/citytools.c Tue Jan 9 21:41:11 2001 @@ -14,6 +14,7 @@ #include #endif +#include #include #include @@ -635,46 +636,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 +690,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 +711,8 @@ vunit->hp); } + unit_list_unlink(units, vunit); + vunit->homecity = 0; wipe_unit_spec_safe(vunit, NULL, 0); } unit_list_iterate_end; @@ -1006,15 +1004,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."), @@ -1074,110 +1064,95 @@ 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); + + 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); + 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); + reestablish_city_trade_routes(pcity); + 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); + remove_obsolete_buildings_city(pcity, 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); + 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); + } - maybe_make_first_contact(pnewcity->x, pnewcity->y, pplayer->player_no); + map_fog_pseudo_city_area(pgiver, pcity->x, pcity->y); + maybe_make_first_contact(pcity->x, pcity->y, ptaker->player_no); - return pnewcity; + return pcity; } /************************************************************************** diff -Nur -X/data/freeciv-dev/freeciv/diff_ignore freeciv/server/citytools.h crashciv/freeciv/server/citytools.h --- freeciv/server/citytools.h Wed Dec 27 00:05:21 2000 +++ crashciv/freeciv/server/citytools.h Tue Jan 9 21:39:02 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 crashciv/freeciv/server/cityturn.c --- freeciv/server/cityturn.c Tue Jan 9 00:15:52 2001 +++ crashciv/freeciv/server/cityturn.c Tue Jan 9 20:30:20 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 crashciv/freeciv/server/diplhand.c --- freeciv/server/diplhand.c Wed Dec 20 15:40:56 2000 +++ crashciv/freeciv/server/diplhand.c Tue Jan 9 21:42:27 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 crashciv/freeciv/server/diplomats.c --- freeciv/server/diplomats.c Tue Jan 9 01:52:32 2001 +++ crashciv/freeciv/server/diplomats.c Tue Jan 9 21:42:54 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 crashciv/freeciv/server/unithand.c --- freeciv/server/unithand.c Tue Jan 9 00:15:53 2001 +++ crashciv/freeciv/server/unithand.c Tue Jan 9 21:43:58 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)