diff -Nur -X/home/thue/freeciv-dev/no.freeciv freeciv/server/citytools.c badpatch/server/citytools.c --- freeciv/server/citytools.c Fri Apr 21 19:03:19 2000 +++ badpatch/server/citytools.c Fri Apr 21 19:45:14 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,53 +675,45 @@ 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; } - -/* - * dist_nearest_city (in ai.c) does not seem to do what I want or expect - * this function finds the closest friendly city to pos x,y. I'm sure - * there must be a similar function somewhere, I just can't find it. - * - * - Kris Bubendorfer - */ - -struct city *find_closest_owned_city(struct player *pplayer, int x, int y) +/**************************************************************** +dist_nearest_city (in ai.c) does not seem to do what I want or expect +this function finds the closest friendly city to pos x,y. I'm sure +there must be a similar function somewhere, I just can't find it. + + - Kris Bubendorfer + +If sea_required, returned city must be adjacent to ocean. +If pexclcity, do not return it as the closest city. +Returns NULL if no satisfactory city can be found. +*****************************************************************/ +struct city *find_closest_owned_city(struct player *pplayer, int x, int y, + int sea_required, struct city *pexclcity) { - 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)) && + (!pexclcity || (pexclcity != pcity))) { + dist = real_map_distance(x, y, pcity->x, pcity->y); + rcity = pcity; + } + city_list_iterate_end; + return rcity; } -/* - * This function creates a new player and copies all of it's science - * research etc. Players are both thrown into anarchy and gold is - * split between both players. - * - Kris Bubendorfer - */ - +/***************************************************************** +This function creates a new player and copies all of it's science +research etc. Players are both thrown into anarchy and gold is +split between both players. + - Kris Bubendorfer +*****************************************************************/ static struct player *split_player(struct player *pplayer) { int *nations_used, i, num_nations_avail=game.playable_nation_count, pick; @@ -993,17 +984,19 @@ } -/*************************************************************** +/************************************************************************** Handles all transactions in relation to transferring a city. -the three last arguments are passed to transfer_city_units, -which is called in the middle of the function. -***************************************************************/ + +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 *pcity, int kill_outside, int transfer_unit_verbose, int resolve_stack) { struct city *pnewcity; - int i; + int *resolve_list=NULL; + int i, no_units=0; if (!pcity) return NULL; @@ -1030,10 +1023,32 @@ map_unfog_city_area(pnewcity); + /* 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)); + if (no_units > 0) { + resolve_list = fc_malloc(no_units * 2 * sizeof(int)); + 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_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 && (no_units > 0) && resolve_list) { + 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 -Nur -X/home/thue/freeciv-dev/no.freeciv freeciv/server/citytools.h badpatch/server/citytools.h --- freeciv/server/citytools.h Fri Apr 21 19:03:19 2000 +++ badpatch/server/citytools.h Fri Apr 21 19:23:53 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, struct city *pexclcity); void adjust_city_free_cost(int *num_free, int *this_cost); diff -Nur -X/home/thue/freeciv-dev/no.freeciv freeciv/server/cityturn.c badpatch/server/cityturn.c --- freeciv/server/cityturn.c Fri Apr 21 19:03:20 2000 +++ badpatch/server/cityturn.c Fri Apr 21 19:23:53 2000 @@ -1601,24 +1601,14 @@ /************************************************************************** disband a city into a settler, supported by the closest city -- Massimo **************************************************************************/ - static void disband_city(struct city *pcity) { struct player *pplayer = get_player(pcity->owner); - int x = pcity->x, y = pcity->y, dist, dist1; + int x = pcity->x, y = pcity->y; struct city *rcity=NULL; - /* We cannot use find_closest_owned_city, since it would return pcity */ - if (city_list_get(&pplayer->cities, 0)) { - dist = 9999; - city_list_iterate(pplayer->cities, pcity1); - dist1 = real_map_distance(x, y, pcity1->x, pcity1->y); - if (dist1 && dist1 < dist) { - dist = dist1; - rcity = pcity1; - } - city_list_iterate_end; - } + /* find closest city other than pcity */ + rcity = find_closest_owned_city(pplayer, x, y, 0, pcity); if (!rcity) { /* What should we do when we try to disband our only city? */ @@ -1634,7 +1624,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 -Nur -X/home/thue/freeciv-dev/no.freeciv freeciv/server/unitfunc.c badpatch/server/unitfunc.c --- freeciv/server/unitfunc.c Fri Apr 21 19:03:20 2000 +++ badpatch/server/unitfunc.c Fri Apr 21 19:23:53 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 badpatch/server/unittools.c --- freeciv/server/unittools.c Fri Apr 21 19:03:20 2000 +++ badpatch/server/unittools.c Fri Apr 21 20:17:13 2000 @@ -670,14 +670,26 @@ return 0; /* as good a quick'n'dirty should be -- Syela */ } - +/************************************************************************** +... +**************************************************************************/ +static void disband_stack_conflict_unit(struct unit *punit, int verbose) +{ + freelog(LOG_VERBOSE, "Disbanded %s's %s at (%d, %d)", + get_player(punit->owner)->name, unit_name(punit->type), + punit->x, punit->y); + if (verbose) { + notify_player(get_player(punit->owner), + _("Game: Disbanded your %s at (%d, %d)."), + unit_name(punit->type), punit->x, punit->y); + } + wipe_unit(get_player(punit->owner), punit); +} /************************************************************************** Return first unit on square that is not owned by player. - - Kris Bubendorfer **************************************************************************/ - struct unit *is_enemy_unit_on_tile(int x, int y, int owner) { unit_list_iterate(map_get_tile(x, y)->units, punit) @@ -693,8 +705,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 +722,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 +751,70 @@ 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), NULL); + ccity = find_closest_owned_city(get_player(cunit->owner), x, y, + is_sailing_unit(cunit), NULL); + + if (pcity && ccity) { + 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); + } else { + /* At least one of the unit owners doesn't have any cities; + If the other owner have cities we teleport his units home. + We take care not to teleport the unit to the original square, + as that would cause the while loop in this function to + potentially never stop */ + if (pcity) { + if (same_pos(x, y, pcity->x, pcity->y)) + disband_stack_conflict_unit(cunit, verbose); + else + teleport_unit_to_city(punit, pcity, 0, verbose); + } else if (ccity) { + if (same_pos(x, y, ccity->x, ccity->y)) + disband_stack_conflict_unit(punit, verbose); + else + teleport_unit_to_city(cunit, ccity, 0, verbose); + } else { /* !pcity && !ccity */ + disband_stack_conflict_unit(punit, verbose); + } + } + } /* end while */ - /* There is only one players units left on this square. If there is not - enough transporter capacity left , send surplus to the closest friendly + /* There is only one player's units left on this square. If there is not + 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, NULL); + if (vcity) + teleport_unit_to_city(vunit, vcity, 0, verbose); + else + disband_stack_conflict_unit(vunit, verbose); break; /* break out of unit_list_iterate loop */ } } diff -Nur -X/home/thue/freeciv-dev/no.freeciv freeciv/server/unittools.h badpatch/server/unittools.h --- freeciv/server/unittools.h Fri Apr 21 19:03:20 2000 +++ badpatch/server/unittools.h Fri Apr 21 19:23:53 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);