/********************************************************************** Freeciv - Copyright (C) 2002 - Per I. Mathisen This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. ***********************************************************************/ #include #include #include #include "city.h" #include "game.h" #include "log.h" #include "map.h" #include "mem.h" #include "support.h" #include "citymap.h" /* CITYMAP - reserve space for cities * * The citymap is a large integer double array that corresponds to * the freeciv main map. For each tile, it stores three different * and exclusive values in a single int: A positive int signifies * a maximum city radius. A value of zero indicates that the tile is * presently unused and available. A negative value means that this * tile is occupied and reserved by some city. * * Code that uses the citymap should modify its behaviour based on * positive values encountered, and never attempt to steal a tile * which has a negative value. */ static int citymap[MAP_MAX_WIDTH][MAP_MAX_HEIGHT]; #define LOG_CITYMAP LOG_DEBUG /************************************************************************** Initialize citymap. **************************************************************************/ void citymap_init() { memset(&citymap, 0, sizeof(citymap)); } /************************************************************************** Populate citymap with data, used if we loaded a game or scenario **************************************************************************/ void citymap_generate() { int dist = game.rgame.min_dist_bw_cities - 1; memset(citymap, 0, sizeof(citymap)); players_iterate(pplayer) { if (pplayer->ai.control) { city_list_iterate(pplayer->cities, pcity) { citymap[pcity->x][pcity->y] = -pcity->id; square_iterate(pcity->x, pcity->y, dist, x1, y1) { citymap[x1][y1] = -pcity->id; } square_iterate_end; } city_list_iterate_end; } } players_iterate_end; } /************************************************************************** Fill map with city radii **************************************************************************/ void citymap_turn_init() { /* First purge map of all positive values */ whole_map_iterate(x, y) { if (citymap[x][y] > 0) { citymap[x][y] = 0; } } whole_map_iterate_end; /* Second fill it up again */ players_iterate(pplayer) { if (pplayer->ai.control) { city_list_iterate(pplayer->cities, pcity) { city_map_checked_iterate(pcity->x, pcity->y, a, b, x1, y1) { if (citymap[x1][y1] >= 0) { citymap[x1][y1] += 1; } } city_map_checked_iterate_end; } city_list_iterate_end; } } players_iterate_end; } /************************************************************************** Returns a positive value if within a city radius, which is 1 x number of cities you are within the radius of, or zero or less if not. A negative value means this tile is reserved by a city and should not be taken. **************************************************************************/ int citymap_read(int x, int y) { assert(is_normal_map_pos(x, y)); return citymap[x][y]; } /************************************************************************** A tile is reserved if it contains a city or unit id, or a worker is assigned to it. **************************************************************************/ bool citymap_is_reserved(int x, int y) { struct tile *ptile; assert(is_normal_map_pos(x, y)); ptile = map_get_tile(x, y); if (ptile->worked || ptile->city) { return TRUE; } return (citymap[x][y] < 0); } /************************************************************************** This function reserves an area equal to city_min_dist radius around the spot with settler's/city's id. If such a tile is already reserved, it is not touched. **************************************************************************/ void citymap_reserve_city_spot(int x, int y, int id) { assert(is_normal_map_pos(x, y)); freelog(LOG_CITYMAP, "id %d reserving (%d, %d), was %d", id, x, y, citymap[x][y]); assert(citymap[x][y] >= 0); /* Tiles will now be "reserved" by actual workers, so free excess * reservations. Also mark tiles for city overlapping. */ city_map_checked_iterate(x, y, a, b, x1, y1) { if (citymap[x1][y1] == -id) { freelog(LOG_CITYMAP, "freeing (%d, %d) for %d, was %d", x1, y1, id, citymap[x1][y1]); citymap[x1][y1] = 0; } if (citymap[x1][y1] >= 0) { citymap[x1][y1] += 1; } } city_map_checked_iterate_end; /* Now reserve unless already reserved some tiles around our city */ square_iterate(x, y, game.rgame.min_dist_bw_cities - 1, x1, y1) { if (citymap[x1][y1] >= 0) { citymap[x1][y1] = -id; } } square_iterate_end; assert(citymap[x][y] == -id); /* REMOVE ME */ } /************************************************************************** Reverse any reservations we have made in the surrounding area. **************************************************************************/ void citymap_free_city_spot(int x, int y, int id) { assert(is_normal_map_pos(x, y)); /* Note we cannot and should not assert(-citymap[x][y] == id) * since this condition may become invalid for a number of reasons. * In the server, this seems to only happen in the case of huts * suddenly being granted from huts within the radius of a settler's * goto target, but in a client this would be more common. */ city_map_checked_iterate(x, y, a, b, x1, y1) { if (citymap[x1][y1] == -id || citymap[x1][y1] == id) { citymap[x1][y1] = 0; } } city_map_checked_iterate_end; } /************************************************************************** Reserve additional tiles as desired (eg I would reserve best available food tile in addition to adjacent tiles). It is ok to attempt to reserve a tile twice iff it was we who reserved it previously. The target tile MUST be within city radius. **************************************************************************/ void citymap_reserve_tile(int x, int y, int id) { assert(is_normal_map_pos(x, y)); assert(citymap[x][y] >= 0 || citymap[x][y] == -id); citymap[x][y] = -id; }