1 /***********************************************************************
2 Freeciv - Copyright (C) 2003 - Per I. Mathisen
3 This program is free software; you can redistribute it and/or modify
4 it under the terms of the GNU General Public License as published by
5 the Free Software Foundation; either version 2, or (at your option)
8 This program is distributed in the hope that it will be useful,
9 but WITHOUT ANY WARRANTY; without even the implied warranty of
10 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 GNU General Public License for more details.
12 ***********************************************************************/
15 #include <fc_config.h>
36 /* CITYMAP - reserve space for cities
38 * The citymap is a large int double array that corresponds to
39 * the freeciv main map. For each tile, it stores three different
40 * and exclusive values in a single int: A positive int tells you
41 * how many cities can use this tile (a crowdedness inidicator). A
42 * value of zero indicates that the tile is presently unused and
43 * available. A negative value means that this tile is occupied
44 * and reserved by some city or unit: in this case the value gives
45 * the negative of the ID of the city or unit that has reserved the
48 * Code that uses the citymap should modify its behaviour based on
49 * positive values encountered, and never attempt to steal a tile
50 * which has a negative value.
53 static int *citymap
= NULL
;
55 #define log_citymap log_debug
57 /**************************************************************************
58 Initialize citymap by reserving worked tiles and establishing the
59 crowdedness of (virtual) cities.
60 **************************************************************************/
61 void citymap_turn_init(struct player
*pplayer
)
63 /* The citymap is reinitialized at the start of ever turn. This includes
64 * a call to realloc, which only really matters if this is the first turn
65 * of the game (but it's easier than a separate function to do this). */
66 citymap
= fc_realloc(citymap
, MAP_INDEX_SIZE
* sizeof(*citymap
));
67 memset(citymap
, 0, MAP_INDEX_SIZE
* sizeof(*citymap
));
69 players_iterate(pother
) {
70 city_list_iterate(pother
->cities
, pcity
) {
71 struct tile
*pcenter
= city_tile(pcity
);
73 /* reserve at least the default (squared) city radius */
74 city_tile_iterate(MAX(city_map_radius_sq_get(pcity
),
75 CITY_MAP_DEFAULT_RADIUS_SQ
),
77 struct city
*pwork
= tile_worked(ptile
);
80 citymap
[tile_index(ptile
)] = -(pwork
->id
);
82 citymap
[tile_index(ptile
)]++;
84 } city_tile_iterate_end
;
85 } city_list_iterate_end
;
86 } players_iterate_end
;
88 unit_list_iterate(pplayer
->units
, punit
) {
89 if (unit_is_cityfounder(punit
)
90 && punit
->server
.adv
->task
== AUT_BUILD_CITY
) {
92 /* use default (squared) city radius */
93 city_tile_iterate(CITY_MAP_DEFAULT_RADIUS_SQ
, punit
->goto_tile
,
95 if (citymap
[tile_index(ptile
)] >= 0) {
96 citymap
[tile_index(ptile
)]++;
98 } city_tile_iterate_end
;
100 citymap
[tile_index(punit
->goto_tile
)] = -(punit
->id
);
102 } unit_list_iterate_end
;
105 /**************************************************************************
106 Free resources allocated for citymap.
107 **************************************************************************/
108 void citymap_free(void)
110 if (citymap
!= NULL
) {
115 /**************************************************************************
116 This function reserves a single tile for a (possibly virtual) city with
117 a settler's or a city's id. Then it 'crowds' tiles that this city can
118 use to make them less attractive to other cities we may consider making.
119 **************************************************************************/
120 void citymap_reserve_city_spot(struct tile
*ptile
, int id
)
123 log_citymap("id %d reserving (%d, %d), was %d",
124 id
, TILE_XY(ptile
), citymap
[tile_index(ptile
)]);
125 fc_assert_ret(0 <= citymap
[tile_index(ptile
)]);
126 #endif /* FREECIV_DEBUG */
128 /* Tiles will now be "reserved" by actual workers, so free excess
129 * reservations. Also mark tiles for city overlapping, or 'crowding'.
130 * Uses the default city map size / squared city radius. */
131 city_tile_iterate(CITY_MAP_DEFAULT_RADIUS_SQ
, ptile
, ptile1
) {
132 if (citymap
[tile_index(ptile1
)] == -id
) {
133 citymap
[tile_index(ptile1
)] = 0;
135 if (citymap
[tile_index(ptile1
)] >= 0) {
136 citymap
[tile_index(ptile1
)]++;
138 } city_tile_iterate_end
;
140 citymap
[tile_index(ptile
)] = -(id
);
143 /**************************************************************************
144 Reverse any reservations we have made in the surrounding area.
145 **************************************************************************/
146 void citymap_free_city_spot(struct tile
*ptile
, int id
)
148 city_tile_iterate(CITY_MAP_DEFAULT_RADIUS_SQ
, ptile
, ptile1
) {
149 if (citymap
[tile_index(ptile1
)] == -(id
)) {
150 citymap
[tile_index(ptile1
)] = 0;
151 } else if (citymap
[tile_index(ptile1
)] > 0) {
152 citymap
[tile_index(ptile1
)]--;
154 } city_tile_iterate_end
;
157 /**************************************************************************
158 Reserve additional tiles as desired (eg I would reserve best available
159 food tile in addition to adjacent tiles)
160 **************************************************************************/
161 void citymap_reserve_tile(struct tile
*ptile
, int id
)
164 fc_assert_ret(!citymap_is_reserved(ptile
));
167 citymap
[tile_index(ptile
)] = -id
;
170 /**************************************************************************
171 Returns a positive value if within a city radius, which is 1 x number of
172 cities you are within the radius of, or zero or less if not. A negative
173 value means this tile is reserved by a city and should not be taken.
174 **************************************************************************/
175 int citymap_read(struct tile
*ptile
)
177 return citymap
[tile_index(ptile
)];
180 /**************************************************************************
181 A tile is reserved if it contains a city or unit id, or a worker is
183 **************************************************************************/
184 bool citymap_is_reserved(struct tile
*ptile
)
186 if (NULL
!= tile_worked(ptile
) /*|| tile_city(ptile)*/) {
189 return (citymap
[tile_index(ptile
)] < 0);