diff -Nur -X/home/thue/freeciv-dev/no.freeciv freeciv/server/citytools.c transfer_city_bugs/server/citytools.c --- freeciv/server/citytools.c Sat Apr 8 14:29:46 2000 +++ transfer_city_bugs/server/citytools.c Sat Apr 8 20:22:20 2000 @@ -693,23 +693,21 @@ * 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; } @@ -974,7 +972,6 @@ unit_list_iterate(pplayer->units, punit) resolve_unit_stack(punit->x, punit->y, 0); unit_list_iterate_end; - notify_player(0, _("Game: The capture of %s's capital and the destruction " diff -Nur -X/home/thue/freeciv-dev/no.freeciv freeciv/server/citytools.h transfer_city_bugs/server/citytools.h --- freeciv/server/citytools.h Sat Apr 8 14:29:46 2000 +++ transfer_city_bugs/server/citytools.h Sat Apr 8 20:22:39 2000 @@ -65,7 +65,7 @@ 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 -Nur -X/home/thue/freeciv-dev/no.freeciv freeciv/server/unitfunc.c transfer_city_bugs/server/unitfunc.c --- freeciv/server/unitfunc.c Sat Apr 8 14:29:47 2000 +++ transfer_city_bugs/server/unitfunc.c Sat Apr 8 21:06:26 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 -Nur -X/home/thue/freeciv-dev/no.freeciv freeciv/server/unittools.c transfer_city_bugs/server/unittools.c --- freeciv/server/unittools.c Sat Apr 8 14:29:47 2000 +++ transfer_city_bugs/server/unittools.c Sat Apr 8 21:11:00 2000 @@ -694,7 +694,7 @@ - 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; @@ -733,67 +742,55 @@ void resolve_unit_stack(int x, int y, int verbose) { - struct unit *punit = unit_list_get(&map_get_tile(x, y)->units, 0), *cunit; + struct city *pcity, *ccity; + struct unit *punit, *cunit; - 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) { punit = unit_list_get(&map_get_tile(x, y)->units, 0); + if (!punit) + 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. I imagine this caused quite a few random crashes before... */ + if (!pcity) { + if (!ccity) { + wipe_unit(get_player(punit->owner), punit); /* Nowhere to go. Wipe a unit */ + break; + } else { + teleport_unit_to_city(cunit, ccity, 0, verbose); /*Only one of them has a homecity. Send it home */ + break; + } + } else if (!ccity) /* pcity is non-NULL */ + teleport_unit_to_city(punit, pcity, 0, verbose); + + /* 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. */ - - if(!punit && cunit) - punit = cunit; + punit = unit_list_get(&map_get_tile(x, y)->units, 0); - if(punit && map_get_terrain(punit->x, punit->y)==T_OCEAN && - !is_enough_transporter_space(get_player(punit->owner), x, y)){ - unit_list_iterate(map_get_tile(x, y)->units, vunit){ - struct city *vcity = find_closest_owned_city(get_player(vunit->owner), x, y); - if(is_ground_unit(vunit)){ - 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); - } + if(punit && map_get_terrain(punit->x, punit->y) == T_OCEAN && + !is_enough_transporter_space(get_player(punit->owner), x, y)) { + unit_list_iterate(map_get_tile(x, y)->units, vunit) { + struct city *vcity = find_closest_owned_city(get_player(vunit->owner), x, y, 0); + if (!vcity) { + wipe_unit(get_player(vunit->owner), vunit); + return; } + if(is_ground_unit(vunit)) + teleport_unit_to_city(vunit, vcity, 0, verbose); } unit_list_iterate_end; } diff -Nur -X/home/thue/freeciv-dev/no.freeciv freeciv/server/unittools.h transfer_city_bugs/server/unittools.h --- freeciv/server/unittools.h Sat Apr 8 14:29:47 2000 +++ transfer_city_bugs/server/unittools.h Sat Apr 8 20:36:32 2000 @@ -51,7 +51,7 @@ 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);