diff -ru -X /home/jjm/cvs/no.freeciv FreecivCVS/server/citytools.c freeciv/server/citytools.c --- FreecivCVS/server/citytools.c Fri Apr 14 08:53:35 2000 +++ freeciv/server/citytools.c Fri Apr 14 09:59:50 2000 @@ -603,9 +603,8 @@ */ void transfer_city_units(struct player *pplayer, struct player *pvictim, struct city *pcity, struct city *vcity, - int kill_outside, int verbose, int resolve_stack) + int kill_outside, int verbose) { - int ux, uy; int x = vcity->x; int y = vcity->y; @@ -676,15 +675,7 @@ vunit->hp); } - ux = vunit->x; - uy = vunit->y; wipe_unit_spec_safe(0, vunit, NULL, 0); - - if (resolve_stack && !new_home_city) { - /* Now make sure that if we just deleted a transporter the - carried units are not left floating in the water */ - resolve_unit_stack(ux, uy, 1); - } } unit_list_iterate_end; } @@ -696,23 +687,23 @@ * there must be a similar function somewhere, I just can't find it. * * - Kris Bubendorfer + * + * returns NULL if no satisfactory city can be found. */ -struct city *find_closest_owned_city(struct player *pplayer, int x, int y) +struct city *find_closest_owned_city(struct player *pplayer, int x, int y, + int sea_required) { - int dist; - struct city *rcity = city_list_get(&pplayer->cities, 0); - - if(rcity){ - dist = real_map_distance(x, y, rcity->x, rcity->y); - - city_list_iterate(pplayer->cities, pcity) - if (real_map_distance(x, y, pcity->x, pcity->y) < dist){ - dist = real_map_distance(x, y, pcity->x, pcity->y); - rcity = pcity; - } - city_list_iterate_end; - } + int dist = -1; + struct city *rcity = NULL; + city_list_iterate(pplayer->cities, pcity) + if ((real_map_distance(x, y, pcity->x, pcity->y) < dist || dist == -1) && + (!sea_required || is_terrain_near_tile(pcity->x, pcity->y, T_OCEAN))) { + dist = real_map_distance(x, y, pcity->x, pcity->y); + rcity = pcity; + } + city_list_iterate_end; + return rcity; } @@ -1003,7 +994,8 @@ int transfer_unit_verbose, int resolve_stack) { struct city *pnewcity; - int i; + int *resolve_list; + int i, no_units; if (!pcity) return NULL; @@ -1030,10 +1022,28 @@ map_unfog_city_area(pnewcity); + /* All kinds of nasty things happen if we resolve the stack while both + cities exist. So we save the list and do it afterwards */ + no_units = unit_list_size(&(pcity->units_supported)); + if (no_units > 0) /* remove a warning about allocating nothing */ + resolve_list = fc_malloc(no_units * 2 * sizeof(int)); + else + resolve_list = NULL; + 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_end; transfer_city_units(pplayer, cplayer, pnewcity, pcity, - kill_outside, transfer_unit_verbose, resolve_stack); + kill_outside, transfer_unit_verbose); remove_city(pcity); - map_set_city(pnewcity->x, pnewcity->y, pnewcity); + map_set_city(pnewcity->x, pnewcity->y, pnewcity); + if (resolve_stack) + for (i = 0; i < no_units * 2; i += 2) + resolve_unit_stack(resolve_list[i], resolve_list[i+1], + transfer_unit_verbose); + free(resolve_list); reestablish_city_trade_routes(pnewcity); city_check_workers(pplayer ,pnewcity); diff -ru -X /home/jjm/cvs/no.freeciv FreecivCVS/server/citytools.h freeciv/server/citytools.h --- FreecivCVS/server/citytools.h Fri Apr 7 17:38:11 2000 +++ freeciv/server/citytools.h Fri Apr 14 10:00:01 2000 @@ -59,13 +59,14 @@ int worst_worker_tile_value(struct city *pcity); void transfer_city_units(struct player *pplayer, struct player *pvictim, struct city *pcity, struct city *vcity, - int kill_outside, int verbose, int resolve_unit_stack); + 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 *pcity, int kill_outside, int transfer_unit_verbose, int resolve_stack); -struct city *find_closest_owned_city(struct player *pplayer, int x, int y); +struct city *find_closest_owned_city(struct player *pplayer, int x, int y, + int sea_required); void adjust_city_free_cost(int *num_free, int *this_cost); diff -ru -X /home/jjm/cvs/no.freeciv FreecivCVS/server/cityturn.c freeciv/server/cityturn.c --- FreecivCVS/server/cityturn.c Fri Apr 7 17:38:11 2000 +++ freeciv/server/cityturn.c Fri Apr 14 09:56:11 2000 @@ -1632,7 +1632,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, 0); + transfer_city_units(pplayer, pplayer, rcity, pcity, -1, 1); notify_player_ex(pplayer, x, y, E_UNIT_BUILD, _("Game: %s is disbanded into %s."), diff -ru -X /home/jjm/cvs/no.freeciv FreecivCVS/server/unitfunc.c freeciv/server/unitfunc.c --- FreecivCVS/server/unitfunc.c Fri Apr 7 17:38:13 2000 +++ freeciv/server/unitfunc.c Fri Apr 14 09:56:11 2000 @@ -1146,7 +1146,7 @@ maybe_make_veteran (pdiplomat); /* being teleported costs all movement */ - if (!teleport_unit_to_city (pdiplomat, spyhome, -1)) { + if (!teleport_unit_to_city (pdiplomat, spyhome, -1, 0)) { send_unit_info (pplayer, pdiplomat); freelog (LOG_NORMAL, "Bug in diplomat_escape: Spy can't teleport."); return; diff -ru -X /home/jjm/cvs/no.freeciv FreecivCVS/server/unittools.c freeciv/server/unittools.c --- FreecivCVS/server/unittools.c Fri Apr 14 09:53:12 2000 +++ freeciv/server/unittools.c Fri Apr 14 10:00:48 2000 @@ -693,8 +693,8 @@ (If specified cost is <0, then teleportation costs all movement.) - Kris Bubendorfer **************************************************************************/ - -int teleport_unit_to_city(struct unit *punit, struct city *pcity, int mov_cost) +int teleport_unit_to_city(struct unit *punit, struct city *pcity, int mov_cost, + int verbose) { int src_x = punit->x,src_y = punit->y; if(pcity->owner == punit->owner){ @@ -710,6 +710,15 @@ unit_list_insert(&map_get_tile(pcity->x, pcity->y)->units, punit); send_unit_info_to_onlookers(0, punit, src_x,src_y); + freelog(LOG_VERBOSE, "Teleported %s's %s from (%d, %d) to %s", + get_player(punit->owner)->name, unit_name(punit->type), + src_x, src_y, pcity->name); + if (verbose) { + notify_player(get_player(punit->owner), + _("Game: Teleported your %s from (%d, %d) to %s."), + unit_name(punit->type), src_x, src_y, pcity->name); + } + return 1; } return 0; @@ -730,73 +739,64 @@ If verbose is true, the unit owner gets messages about where each units goes. --dwp **************************************************************************/ - void resolve_unit_stack(int x, int y, int verbose) { struct unit *punit, *cunit; - punit = unit_list_get(&map_get_tile(x, y)->units, 0); - if (!punit) - return; - cunit = is_enemy_unit_on_tile(x, y, punit->owner); - - while(punit && cunit){ - struct city *pcity = find_closest_owned_city(get_player(punit->owner), x, y); - struct city *ccity = find_closest_owned_city(get_player(cunit->owner), x, y); - - if(map_distance(x, y, pcity->x, pcity->y) - < map_distance(x, y, ccity->x, ccity->y)){ - teleport_unit_to_city(cunit, ccity, 0); - freelog(LOG_VERBOSE, "Teleported %s's %s from (%d, %d) to %s", - get_player(cunit->owner)->name, unit_name(cunit->type), - x, y,ccity->name); - if (verbose) { - notify_player(get_player(cunit->owner), - _("Game: Teleported your %s from (%d, %d) to %s."), - unit_name(cunit->type), x, y,ccity->name); - } - }else{ - teleport_unit_to_city(punit, pcity, 0); - freelog(LOG_VERBOSE, "Teleported %s's %s from (%d, %d) to %s", - get_player(punit->owner)->name, unit_name(punit->type), - x, y, pcity->name); - if (verbose) { - notify_player(get_player(punit->owner), - _("Game: Teleported your %s from (%d, %d) to %s."), - unit_name(punit->type), x, y, pcity->name); - } - } - + /* We start by reducing the unit list until we only have units from one nation */ + while(1){ + struct city *pcity, *ccity; punit = unit_list_get(&map_get_tile(x, y)->units, 0); if (!punit) - break; + return; cunit = is_enemy_unit_on_tile(x, y, punit->owner); + if (!cunit) + break; + pcity = find_closest_owned_city(get_player(punit->owner), x, y, + is_sailing_unit(punit)); + ccity = find_closest_owned_city(get_player(cunit->owner), x, y, + is_sailing_unit(cunit)); + + /* First look if both cities exist. */ + if (!pcity) { + if (!ccity) { + /* Nowhere to go. Wipe a unit */ + wipe_unit(get_player(punit->owner), punit); + continue; + } else { + /*Only one of them has a homecity. Send it home */ + teleport_unit_to_city(cunit, ccity, 0, verbose); + continue; + } + } else if (!ccity) {/* pcity is non-NULL */ + teleport_unit_to_city(punit, pcity, 0, verbose); + continue; + } + + /* Both cities exist. Send the unit that is fathest from home home */ + if(map_distance(x, y, pcity->x, pcity->y) + < map_distance(x, y, ccity->x, ccity->y)) + teleport_unit_to_city(cunit, ccity, 0, verbose); + else + teleport_unit_to_city(punit, pcity, 0, verbose); } /* There is only one players units left on this square. If there is not - enough transporter capacity left , send surplus to the closest friendly + enough transporter capacity left send surplus to the closest friendly city. */ + punit = unit_list_get(&map_get_tile(x, y)->units, 0); - if(!punit && cunit) - punit = cunit; - - if(punit && map_get_terrain(punit->x, punit->y)==T_OCEAN) { + if(punit && map_get_terrain(x, y) == T_OCEAN) { while(!is_enough_transporter_space(get_player(punit->owner), x, y)) { unit_list_iterate(map_get_tile(x, y)->units, vunit) { if(is_ground_unit(vunit)) { struct city *vcity = - find_closest_owned_city(get_player(vunit->owner), x, y); - teleport_unit_to_city(vunit, vcity, 0); - freelog(LOG_VERBOSE, "Teleported %s's %s to %s" - " as there is no transport space on square (%d, %d)", - get_player(vunit->owner)->name, unit_name(vunit->type), - vcity->name, x, y); - if (verbose) { - notify_player(get_player(vunit->owner), - _("Game: Teleported your %s to %s as there is" - " no transport space on square (%d, %d)."), - unit_name(vunit->type), vcity->name, x, y); - } + find_closest_owned_city(get_player(vunit->owner), x, y, 0); + printf("%s\n", vcity->name); + if (vcity) + teleport_unit_to_city(vunit, vcity, 0, verbose); + else + wipe_unit(get_player(vunit->owner), vunit); break; /* break out of unit_list_iterate loop */ } } diff -ru -X /home/jjm/cvs/no.freeciv FreecivCVS/server/unittools.h freeciv/server/unittools.h --- FreecivCVS/server/unittools.h Sat Mar 4 09:13:22 2000 +++ freeciv/server/unittools.h Fri Apr 14 10:00:57 2000 @@ -51,7 +51,8 @@ int build_points_left(struct city *pcity); int can_place_partisan(int x, int y); int enemies_at(struct unit *punit, int x, int y); -int teleport_unit_to_city(struct unit *punit, struct city *pcity, int mov_cost); +int teleport_unit_to_city(struct unit *punit, struct city *pcity, int mov_cost, + int verbose); struct unit *is_enemy_unit_on_tile(int x, int y, int owner); void resolve_unit_stack(int x, int y, int verbose);