diff -Nur -X/data/freeciv-dev/freeciv/diff_ignore freeciv/ai/aicity.c codeciv/ai/aicity.c --- freeciv/ai/aicity.c Tue Dec 19 01:12:09 2000 +++ codeciv/ai/aicity.c Tue Dec 19 01:14:25 2000 @@ -810,7 +810,7 @@ **************************************************************************/ static void ai_manage_city(struct player *pplayer, struct city *pcity) { - city_check_workers(pplayer, pcity); /* no reason not to, many reasons to do so! */ + city_check_workers(pcity, 0); /* no reason not to, many reasons to do so! */ auto_arrange_workers(pcity); if (ai_fix_unhappy(pcity) && ai_fuzzy(pplayer,1)) ai_scientists_taxmen(pcity); @@ -1011,7 +1011,7 @@ city_list_insert(&minilist, acity); } } - city_check_workers(pplayer, pcity); + city_check_workers(pcity, 0); auto_arrange_workers(pcity); if (ai_fix_unhappy(pcity) && ai_fuzzy(pplayer,1)) ai_scientists_taxmen(pcity); @@ -1038,7 +1038,7 @@ city_list_iterate(minilist, acity) city_refresh(acity); /* otherwise food total and stuff was wrong. -- Syela */ - city_check_workers(pplayer, acity); + city_check_workers(acity, 0); add_adjust_workers(acity); city_refresh(acity); if (ai_fix_unhappy(acity) && ai_fuzzy(pplayer,1)) diff -Nur -X/data/freeciv-dev/freeciv/diff_ignore freeciv/ai/aitools.c codeciv/ai/aitools.c --- freeciv/ai/aitools.c Tue Dec 19 01:12:09 2000 +++ codeciv/ai/aitools.c Tue Dec 19 01:14:30 2000 @@ -274,8 +274,8 @@ /* the 4 lines that follow are copied from ai_manage_city - we don't need the sell_obsolete_buildings */ - city_check_workers (pplayer, &tmp_city); - auto_arrange_workers (&tmp_city); + city_check_workers(&tmp_city, 0); + auto_arrange_workers(&tmp_city); if (ai_fix_unhappy (&tmp_city)) ai_scientists_taxmen (&tmp_city); diff -Nur -X/data/freeciv-dev/freeciv/diff_ignore freeciv/common/city.h codeciv/common/city.h --- freeciv/common/city.h Tue Dec 19 01:12:41 2000 +++ codeciv/common/city.h Tue Dec 19 01:14:37 2000 @@ -98,6 +98,7 @@ #define map_city_radius_iterate(city_x, city_y, x_itr, y_itr) \ { \ + int x_itr, y_itr; \ int MCMI_x, MCMI_y; \ for (MCMI_x=0; MCMI_xx-4; x2=pcity->x+4; y1=pcity->y-4; y2=pcity->y+4; - x1=map_adjust_x(x1); x2=map_adjust_x(x2); - y1=map_adjust_y(y1); y2=map_adjust_y(y2); - if(x1>x2) { - for (i=0;ix <= x2 || pcity2->x >= x1) && - (pcity2->y >= y1 && pcity2->y <= y2) ) { - city_check_workers(city_owner(pcity2),pcity2); - send_city_info(city_owner(pcity2), pcity2); - } - city_list_iterate_end; - } - } else { - for (i=0;ix <= x2 && pcity2->x >= x1) && - (pcity2->y >= y1 && pcity2->y <= y2) ) { - city_check_workers(city_owner(pcity2),pcity2); - send_city_info(city_owner(pcity2), pcity2); - } - city_list_iterate_end; + int x, y; + square_iterate(pcity->x, pcity->y, CITY_MAP_SIZE-1, x, y) { + struct city *pcity2 = map_get_city(x, y); + if (pcity2 && pcity2 != pcity) { + city_check_workers(pcity2, 1); + send_city_info(city_owner(pcity2), pcity2); } - } + } square_iterate_end; } /************************************************************************** diff -Nur -X/data/freeciv-dev/freeciv/diff_ignore freeciv/server/citytools.c codeciv/server/citytools.c --- freeciv/server/citytools.c Tue Dec 19 01:12:51 2000 +++ codeciv/server/citytools.c Tue Dec 19 01:14:46 2000 @@ -1107,7 +1107,7 @@ } reestablish_city_trade_routes(pnewcity); - city_check_workers(pplayer ,pnewcity); + city_check_workers(pnewcity, 1); update_map_with_city_workers(pnewcity); city_refresh(pnewcity); initialize_infrastructure_cache(pnewcity); diff -Nur -X/data/freeciv-dev/freeciv/diff_ignore freeciv/server/cityturn.c codeciv/server/cityturn.c --- freeciv/server/cityturn.c Tue Dec 19 01:12:51 2000 +++ codeciv/server/cityturn.c Tue Dec 19 01:24:07 2000 @@ -14,6 +14,7 @@ #include #endif +#include #include #include #include @@ -666,7 +667,7 @@ /************************************************************************** ... **************************************************************************/ -int add_adjust_workers(struct city *pcity) +int add_adjust_workers(struct city *pcity) { int workers=pcity->size; int iswork=0; @@ -674,16 +675,22 @@ int foodneed; int prodneed = 0; int x,y; + city_map_iterate(x, y) if (get_worker_city(pcity, x, y)==C_TILE_WORKER) iswork++; - - iswork--; - if (iswork+city_specialists(pcity)>workers) + iswork--; /* City center */ + + if (iswork+city_specialists(pcity)>workers) { + freelog(LOG_ERROR, "Encountered an inconsistency in" + "add_adjust_workers() for city %s", pcity->name); return 0; + } + if (iswork+city_specialists(pcity)==workers) return 1; - toplace=workers-(iswork+city_specialists(pcity)); + + toplace = workers-(iswork+city_specialists(pcity)); foodneed = -pcity->food_surplus; prodneed = -pcity->shield_surplus; @@ -1450,35 +1457,117 @@ } /************************************************************************** +x,y is in citymap coords. +The new status of the tile is both set and returned. +**************************************************************************/ +static enum city_tile_type city_tile_status(struct city *pcity, int x, int y) +{ + struct tile *ptile = map_get_tile(pcity->x + x - CITY_MAP_SIZE/2, + pcity->y + y - CITY_MAP_SIZE/2); + int is_enemy_at_tile = 0; + + unit_list_iterate(ptile->units, punit) { + if (players_at_war(pcity->owner, punit->owner)) { + is_enemy_at_tile = 1; + } + } unit_list_iterate_end; + + if (is_enemy_at_tile) { + if (get_worker_city(pcity, x, y) == C_TILE_WORKER) { + set_worker_city(pcity, x, y, C_TILE_UNAVAILABLE); + add_adjust_workers(pcity); /* will place the displaced */ + city_refresh(pcity); /* may be unnecessary; can't hurt */ + return C_TILE_UNAVAILABLE; + } else { + set_worker_city(pcity, x, y, C_TILE_UNAVAILABLE); + return C_TILE_UNAVAILABLE; + } + } + + if (get_worker_city(pcity, x, y)==C_TILE_UNAVAILABLE) + set_worker_city(pcity, x, y, C_TILE_EMPTY); /* asume available */ + if (get_worker_city(pcity, x, y)!=C_TILE_WORKER && + !can_place_worker_here(pcity, x, y)) + set_worker_city(pcity, x, y, C_TILE_UNAVAILABLE); /* prove otherwise */ + return get_worker_city(pcity, x, y); +} + +/************************************************************************** 1) check for enemy units on citymap tiles 2) withdraw workers from such tiles 3) mark citymap tiles accordingly empty/unavailable **************************************************************************/ -void city_check_workers(struct player *pplayer, struct city *pcity) +void city_check_workers(struct city *pcity, int update_adjacent_cities) { int x, y; - + + /* make a before image of the city */ + enum city_tile_type city_map_old[CITY_MAP_SIZE][CITY_MAP_SIZE]; city_map_iterate(x, y) { - struct tile *ptile=map_get_tile(pcity->x+x-2, pcity->y+y-2); - - if(unit_list_size(&ptile->units)>0) { - struct unit *punit=unit_list_get(&ptile->units, 0); - if (players_at_war(pplayer->player_no, punit->owner)) { - if (get_worker_city(pcity, x, y)==C_TILE_WORKER) { -/* pcity->ppl_elvis++; -- this is really not polite -- Syela */ - set_worker_city(pcity, x, y, C_TILE_UNAVAILABLE); - add_adjust_workers(pcity); /* will place the displaced */ - city_refresh(pcity); /* may be unnecessary; can't hurt */ - } else - set_worker_city(pcity, x, y, C_TILE_UNAVAILABLE); - continue; + city_map_old[x][y] = pcity->city_map[x][y]; + } + + city_map_iterate(x, y) { + city_tile_status(pcity, x, y); + } + + /* Moving all those workers affects neightbor cities. Update them. */ + if (update_adjacent_cities) { + struct city_list changed; + city_list_init(&changed); + + city_map_iterate(x, y) { + if ((city_map_old[x][y] == C_TILE_WORKER + && pcity->city_map[x][y] != C_TILE_WORKER) + || + (pcity->city_map[x][y] == C_TILE_WORKER + && city_map_old[x][y] != C_TILE_WORKER) + ) { + int x2, y2; + int center_x = pcity->x + x - CITY_MAP_SIZE/2; + int center_y = pcity->y + y - CITY_MAP_SIZE/2; + assert(normalize_map_pos(¢er_x, ¢er_y)); + map_city_radius_iterate(center_x, center_y, x1, y1) { + struct city *pcity2 = map_get_city(x1, y1); + if (pcity2 == pcity) + pcity2 = NULL; + + if (pcity2) { + /* Update the city's citymap */ + city_map_iterate(x2, y2) { + int real_x = x2 + pcity2->x - CITY_MAP_SIZE/2; + int real_y = y2 + pcity2->y - CITY_MAP_SIZE/2; + if (normalize_map_pos(&real_x, &real_y)) { + if (real_x == center_x && real_y == center_y) { + /* ok, we found the internal x, y coords. + now change the map. */ + city_tile_status(pcity2, x2, y2); + } + } + } + } + + /* Check if we already included it in the list to be send. */ + if (pcity2) { + city_list_iterate(changed, pcity3) { + if (pcity2 == pcity3) + pcity2 = NULL; + } city_list_iterate_end; + } + /* insert it. */ + if (pcity2) { + city_list_insert(&changed, pcity2); + } + } map_city_radius_iterate_end; } } - if(get_worker_city(pcity, x, y)==C_TILE_UNAVAILABLE) - set_worker_city(pcity, x, y, C_TILE_EMPTY); - if(get_worker_city(pcity, x, y)!=C_TILE_WORKER && - !can_place_worker_here(pcity, x, y)) - set_worker_city(pcity, x, y, C_TILE_UNAVAILABLE); + + /* OK, we have the list of changed cities, send them */ + city_list_iterate(changed, pcity2) { + send_city_info(city_owner(pcity2), pcity2); + } city_list_iterate_end; + + city_list_unlink_all(&changed); } } @@ -1594,7 +1683,7 @@ struct government *g = get_gov_pcity(pcity); int got_tech = 0; - city_check_workers(pplayer, pcity); + city_check_workers(pcity, 0); city_refresh(pcity); /* the AI often has widespread disorder when the Gardens or Oracle diff -Nur -X/data/freeciv-dev/freeciv/diff_ignore freeciv/server/cityturn.h codeciv/server/cityturn.h --- freeciv/server/cityturn.h Tue Dec 19 01:12:51 2000 +++ codeciv/server/cityturn.h Tue Dec 19 01:14:56 2000 @@ -26,7 +26,7 @@ void auto_arrange_workers(struct city *pcity); /* will arrange the workers */ int add_adjust_workers(struct city *pcity); /* will add workers */ -void city_check_workers(struct player *pplayer, struct city *pcity); +void city_check_workers(struct city *pcity, int send_changed_adjacent_cities); /**** This part isn't meant to be used ****/ /* huh? which part? --dwp */ diff -Nur -X/data/freeciv-dev/freeciv/diff_ignore freeciv/server/maphand.c codeciv/server/maphand.c --- freeciv/server/maphand.c Tue Dec 19 01:12:51 2000 +++ codeciv/server/maphand.c Tue Dec 19 01:15:03 2000 @@ -276,8 +276,6 @@ void give_citymap_from_player_to_player(struct city *pcity, struct player *pfrom, struct player *pdest) { - int x, y; - buffer_shared_vision(pdest); map_city_radius_iterate(pcity->x, pcity->y, x, y) { give_tile_info_from_player_to_player(pfrom, pdest, x, y); @@ -595,8 +593,6 @@ **************************************************************************/ void map_unfog_pseudo_city_area(struct player *pplayer, int x, int y) { - int x_itr, y_itr; - freelog(LOG_DEBUG, "Unfogging city area at %i,%i", x, y); buffer_shared_vision(pplayer); @@ -625,8 +621,6 @@ **************************************************************************/ void map_fog_pseudo_city_area(struct player *pplayer, int x,int y) { - int x_itr, y_itr; - freelog(LOG_DEBUG, "Fogging city area at %i,%i", x, y); buffer_shared_vision(pplayer); diff -Nur -X/data/freeciv-dev/freeciv/diff_ignore freeciv/server/plrhand.c codeciv/server/plrhand.c --- freeciv/server/plrhand.c Tue Dec 19 01:12:52 2000 +++ codeciv/server/plrhand.c Tue Dec 19 01:15:07 2000 @@ -28,6 +28,7 @@ #include "support.h" #include "tech.h" +#include "cityhand.h" #include "citytools.h" #include "cityturn.h" #include "gamelog.h" @@ -615,6 +616,28 @@ } /************************************************************************** +... +**************************************************************************/ +static void refresh_players_cities_if_player2_near(struct player *pplayer, + struct player *pplayer2) +{ + city_list_iterate(pplayer->cities, pcity) { + struct unit *refresh_because_of = NULL; + map_city_radius_iterate(pcity->x, pcity->y, x, y) { + unit_list_iterate(map_get_tile(x, y)->units, penemy) { + if (unit_owner(penemy) == pplayer2) + refresh_because_of = penemy; + } unit_list_iterate_end; + } map_city_radius_iterate_end; + + if (refresh_because_of) { + city_check_workers(pcity, 1); + send_city_info(city_owner(pcity), pcity); + } + } city_list_iterate_end; +} + +/************************************************************************** Handles a player cancelling a "pact" with another player. **************************************************************************/ void handle_player_cancel_pact(struct player *pplayer, int other_player) @@ -723,6 +746,10 @@ free(resolve_list); } } + + /* Refresh all cities which have a unit of the other side within city range. */ + refresh_players_cities_if_player2_near(pplayer, pplayer2); + refresh_players_cities_if_player2_near(pplayer2, pplayer); notify_player(pplayer, _("Game: The diplomatic state between the %s and the %s is now %s."), diff -Nur -X/data/freeciv-dev/freeciv/diff_ignore freeciv/server/settlers.c codeciv/server/settlers.c --- freeciv/server/settlers.c Tue Dec 19 01:12:52 2000 +++ codeciv/server/settlers.c Tue Dec 19 01:15:11 2000 @@ -127,8 +127,6 @@ **************************************************************************/ void generate_minimap(void) { - int x_itr, y_itr; - memset(minimap, 0, sizeof(minimap)); players_iterate(pplayer) { city_list_iterate(pplayer->cities, pcity) { @@ -191,8 +189,6 @@ **************************************************************************/ void locally_zero_minimap(int x, int y) { - int x_itr, y_itr; - map_city_radius_iterate(x, y, x_itr, y_itr) { if (minimap[x_itr][y_itr] > 0) minimap[x_itr][y_itr] = 0; } map_city_radius_iterate_end; diff -Nur -X/data/freeciv-dev/freeciv/diff_ignore freeciv/server/unitfunc.c codeciv/server/unitfunc.c --- freeciv/server/unitfunc.c Tue Dec 19 01:12:52 2000 +++ codeciv/server/unitfunc.c Tue Dec 19 01:15:15 2000 @@ -2744,6 +2744,7 @@ struct packet_generic_integer packet; struct city *pcity = map_get_city(punit->x, punit->y); struct city *phomecity = find_city_by_id(punit->homecity); + int punit_x = punit->x, punit_y = punit->y; remove_unit_sight_points(punit); @@ -2762,6 +2763,15 @@ game_remove_unit(punit->id); + /* This unit may have blocked tiles of adjacent cities. Update them. */ + map_city_radius_iterate(punit_x, punit_y, x, y) { + struct city *pcity2 = map_get_city(x, y); + if (pcity2 && pcity2->owner != punit->owner) { + city_check_workers(pcity2, 1); + send_city_info(city_owner(pcity2), pcity2); + } + } map_city_radius_iterate_end; + if (phomecity) { city_refresh(phomecity); send_city_info(get_player(phomecity->owner), phomecity); @@ -3415,7 +3425,8 @@ cities happiness varies). This also takes into account if the unit enters/leaves a fortress. 2) handles any huts at the units destination. - 3) awakes any sentried units on neightborin tiles + 3) awakes any sentried units on neightboring tiles. + 4) updates adjacent cities' unavailable tiles. FIXME: Sometimes it is not neccesary to send cities because the goverment doesn't care if a unit is away or not. @@ -3489,6 +3500,39 @@ send_city_info(pplayer, homecity); } } + + + /* The unit block different tiles of adjacent enemy cities before and + after. Update the relevant cities, without sending their info twice + if possible... If the city is in the range of both the source and + the destination we only update it when checking at the destination. */ + + /* First check cities near the source. */ + map_city_radius_iterate(src_x, src_y, x1, y1) { + struct city *pcity = map_get_city(x1, y1); + + int is_near_destination = 0; + map_city_radius_iterate(dest_x, dest_y, x2, y2) { + struct city *pcity2 = map_get_city(x2, y2); + if (pcity == pcity2) + is_near_destination = 1; + } map_city_radius_iterate_end; + + if (pcity && pcity->owner != punit->owner + && !is_near_destination) { + city_check_workers(pcity, 1); + send_city_info(city_owner(pcity), pcity); + } + } map_city_radius_iterate_end; + + /* Then check cities near the destination. */ + map_city_radius_iterate(dest_x, dest_y, x1, y1) { + struct city *pcity = map_get_city(x1, y1); + if (pcity && pcity->owner != punit->owner) { + city_check_workers(pcity, 1); + send_city_info(city_owner(pcity), pcity); + } + } map_city_radius_iterate_end; } /**************************************************************************