[Freeciv-Dev] Re: (PR#11311) death to smallpox?
[Top] [All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index] [Thread Index]
<URL: http://bugs.freeciv.org/Ticket/Display.html?id=11311 >
On Tue, 27 Sep 2005, Jason Short wrote:
> Here is an updated version of the patch.
New one attached. I had to remove the ruleset changes, though.
> The main problem remaining is an ugly one: with the "covered" value.
> Currently:
>
> * ptile->covered gives the number of cities that have access to the free
> output and bonuses from this tile
> * It is updated when cities are built or destroyed, and recalculated on
> game load.If citymap size were to change during the course of a game,
> it would have to be updated then too.
I have to note that this and related problems happen because cities are
created instantly. If city making was a unit activity like all other and
resolved on end turn, such problems would go away.
> * It does not respect borders.Doing so makes things substantially more
> complicated, since it has to be updated when borders change and this
> already coincides with founding of cities.The end result is the "long"
> caluclation would have to be done, that is O(n^2) in the citymap size of
> a city.
With the new borders rule this problem should be gone.
- Per
Index: server/citytools.c
===================================================================
--- server/citytools.c (revision 11583)
+++ server/citytools.c (working copy)
@@ -991,7 +991,14 @@
/* Place a worker at the city center; this is the free-worked tile.
* This must be done before the city refresh (below) so that the city
* is in a sane state. */
- server_set_tile_city(pcity, CITY_MAP_SIZE/2, CITY_MAP_SIZE/2, C_TILE_WORKER);
+ city_map_checked_iterate(pcity->tile, x, y, ptile) {
+ ptile->covered++;
+ assert(ptile->covered == map_tile_get_coverage(ptile));
+ send_tile_info(NULL, ptile);
+ if (is_free_worked_tile(x, y)) {
+ server_set_tile_city(pcity, x, y, C_TILE_WORKER);
+ }
+ } city_map_checked_iterate_end;
/* Refresh the city. First a city refresh is done (this shouldn't
* send any packets to the client because the city has no supported units)
@@ -1147,6 +1154,12 @@
/* Update available tiles in adjacent cities. */
map_city_radius_iterate(ptile, tile1) {
+ if (TRUE) {
+ assert(tile1->covered > 0);
+ tile1->covered--;
+ send_tile_info(NULL, tile1);
+ assert(tile1->covered == map_tile_get_coverage(tile1));
+ }
/* For every tile the city could have used. */
map_city_radius_iterate(tile1, tile2) {
/* We see what cities are inside reach of the tile. */
@@ -1581,6 +1594,7 @@
}
output_type_iterate(o) {
+ packet->free[o] = pcity->free[o];
packet->surplus[o] = pcity->surplus[o];
packet->waste[o] = pcity->waste[o];
packet->unhappy_penalty[o] = pcity->unhappy_penalty[o];
Index: server/ruleset.c
===================================================================
--- server/ruleset.c (revision 11583)
+++ server/ruleset.c (working copy)
@@ -1489,6 +1489,9 @@
/* terrain details */
+ output_type_iterate(o) {
+ terrain_control.terrain_bonuses[o] = FALSE;
+ } output_type_iterate_end;
terrain_type_iterate(pterrain) {
char **slist;
const int i = pterrain->index;
@@ -1525,6 +1528,14 @@
pterrain->output[o]
= secfile_lookup_int_default(file, 0, "%s.%s", sec[i],
get_output_identifier(o));
+ pterrain->add[o]
+ = secfile_lookup_int_default(file, 0, "%s.%s_add", sec[i],
+ get_output_identifier(o));
+ pterrain->bonus[o]
+ = secfile_lookup_int_default(file, 0, "%s.%s_bonus",
+ sec[i],
+ get_output_identifier(o));
+ terrain_control.terrain_bonuses[o] |= (pterrain->bonus[o] > 0);
} output_type_iterate_end;
res = secfile_lookup_str_vec (file, &nval, "%s.resources", sec[i]);
Index: server/maphand.c
===================================================================
--- server/maphand.c (revision 11583)
+++ server/maphand.c (working copy)
@@ -470,6 +470,7 @@
} else {
info.spec_sprite[0] = '\0';
}
+ info.covered = ptile->covered; /* Minor cheating. */
conn_list_iterate(dest, pconn) {
struct player *pplayer = pconn->player;
@@ -1697,6 +1698,35 @@
}
/*************************************************************************
+ Calculate how many cities have access to this tile.
+
+ Currently this doesn't restrict coverage by borders, because doing so
+ would make the updating logic substantially more complicated.
+*************************************************************************/
+int map_tile_get_coverage(const struct tile *ptile)
+{
+ int covered = 0;
+
+ city_map_checked_iterate(ptile, cx, cy, itr_tile) {
+ if (itr_tile->city) {
+ covered++;
+ }
+ } city_map_checked_iterate_end;
+
+ return covered;
+}
+
+/*************************************************************************
+ Calculate how many cities have access to each tile.
+*************************************************************************/
+void map_calculate_coverage(void)
+{
+ whole_map_iterate(ptile) {
+ ptile->covered = map_tile_get_coverage(ptile);
+ } whole_map_iterate_end;
+}
+
+/*************************************************************************
Return size in tiles of the given continent(not ocean)
*************************************************************************/
int get_continent_size(Continent_id id)
Index: server/maphand.h
===================================================================
--- server/maphand.h (revision 11583)
+++ server/maphand.h (working copy)
@@ -96,6 +96,9 @@
void map_claim_ownership(struct tile *ptile, struct player *owner,
struct tile *source);
+int map_tile_get_coverage(const struct tile *ptile);
+void map_calculate_coverage(void);
+
void check_terrain_change(struct tile *ptile, struct terrain *oldter);
int get_continent_size(Continent_id id);
int get_ocean_size(Continent_id id);
Index: server/sanitycheck.c
===================================================================
--- server/sanitycheck.c (revision 11583)
+++ server/sanitycheck.c (working copy)
@@ -194,6 +194,8 @@
} adjc_iterate_end;
}
+ SANITY_CHECK(ptile->covered == map_tile_get_coverage(ptile));
+
if (pcity) {
SANITY_TILE(ptile, same_pos(pcity->tile, ptile));
}
@@ -304,11 +306,12 @@
/* Sanity check city size versus worker and specialist counts. */
city_map_iterate(x, y) {
- if (get_worker_city(pcity, x, y) == C_TILE_WORKER) {
+ if (get_worker_city(pcity, x, y) == C_TILE_WORKER
+ && !is_free_worked_tile(x, y)) {
workers++;
}
} city_map_iterate_end;
- if (workers + city_specialists(pcity) != pcity->size + 1) {
+ if (workers + city_specialists(pcity) != pcity->size) {
int diff = pcity->size + 1 - workers - city_specialists(pcity);
SANITY_CITY(pcity, workers + city_specialists(pcity) == pcity->size + 1);
Index: server/savegame.c
===================================================================
--- server/savegame.c (revision 11583)
+++ server/savegame.c (working copy)
@@ -3914,6 +3914,8 @@
initialize_globals();
apply_unit_ordering();
+ map_calculate_coverage();
+
/* Make sure everything is consistent. */
players_iterate(pplayer) {
unit_list_iterate(pplayer->units, punit) {
Index: common/packets.def
===================================================================
--- common/packets.def (revision 11583)
+++ common/packets.def (working copy)
@@ -339,6 +339,7 @@
TERRAIN type;
UINT8 known;
+ UINT8 covered;
BOOL special[S_LAST];
RESOURCE resource;
PLAYER owner;
@@ -500,6 +501,7 @@
UINT8 specialists_size;
UINT8 specialists[SP_MAX:specialists_size];
+ SINT16 free[O_MAX];
SINT16 surplus[O_MAX];
UINT16 waste[O_MAX];
SINT16 unhappy_penalty[O_MAX];
@@ -1135,6 +1137,7 @@
BOOL may_irrigate; /* may build irrigation/farmland */
BOOL may_mine; /* may build mines */
BOOL may_transform; /* may transform terrain */
+ BOOL terrain_bonuses[O_MAX];
/* parameters */
UINT8 ocean_reclaim_requirement_pct; /* # adjacent land tiles for reclaim */
@@ -1220,6 +1223,8 @@
SINT8 defense_bonus;
UINT8 output[O_MAX];
+ SINT8 bonus[O_MAX];
+ SINT8 add[O_MAX];
UINT8 num_resources;
RESOURCE resources[MAX_NUM_RESOURCES:num_resources];
@@ -1344,6 +1349,8 @@
STRING name_orig[MAX_LEN_NAME];
UINT8 output[O_MAX];
+ SINT8 bonus[O_MAX];
+ SINT8 add[O_MAX];
STRING graphic_str[MAX_LEN_NAME];
STRING graphic_alt[MAX_LEN_NAME];
end
Index: common/city.c
===================================================================
--- common/city.c (revision 11583)
+++ common/city.c (working copy)
@@ -1438,15 +1438,36 @@
int get_final_city_output_bonus(const struct city *pcity, Output_type_id otype)
{
struct output_type *output = &output_types[otype];
+ int bonus0 = get_city_terrain_bonus(pcity, otype);
int bonus1 = 100 + get_city_tile_output_bonus(pcity, NULL, output,
EFT_OUTPUT_BONUS);
int bonus2 = 100 + get_city_tile_output_bonus(pcity, NULL, output,
EFT_OUTPUT_BONUS_2);
- return MAX(bonus1 * bonus2 / 100, 0);
+ return MAX(((bonus0 * bonus1 / 100) * bonus2 / 100), 0);
}
/**************************************************************************
+ ?
+**************************************************************************/
+int get_city_terrain_bonus(const struct city *pcity, Output_type_id otype)
+{
+ int bonus = 0;
+
+ if (terrain_control.terrain_bonuses[otype]) {
+ const int factor = 420; /* Avoid rounding errors. lcm(2..7) == 420. */
+
+ map_city_radius_iterate(pcity->tile, ptile) {
+ if (tile_get_known(ptile, pcity->owner) != TILE_UNKNOWN) {
+ bonus += tile_get_output_bonus(ptile, otype) * factor / ptile->covered;
+ }
+ } map_city_radius_iterate_end;
+ bonus /= factor;
+ }
+ return 100 + bonus;
+}
+
+/**************************************************************************
Return the amount of gold generated by buildings under "tithe" attribute
governments.
**************************************************************************/
@@ -1562,6 +1583,24 @@
}
/****************************************************************************
+ Calculate the free output received by the city.
+****************************************************************************/
+static void city_get_free_output(const struct city *pcity, int *output)
+{
+ const int factor = 420; /* lcm(2..7) */
+
+ memset(output, 0, O_COUNT * sizeof(*output));
+ map_city_radius_iterate(pcity->tile, ptile) {
+ output_type_iterate(o) {
+ output[o] += factor * tile_get_output_add(ptile, o) / ptile->covered;
+ } output_type_iterate_end;
+ } map_city_radius_iterate_end;
+ output_type_iterate(o) {
+ output[o] /= factor;
+ } output_type_iterate_end;
+}
+
+/****************************************************************************
This function sets all the values in the pcity->tile_output[] array. This
should be called near the beginning of generic_city_refresh. It doesn't
depend on anything else in the refresh and doesn't change when workers are
@@ -1912,7 +1951,7 @@
*/
output_type_iterate(o) {
- pcity->prod[o] = pcity->citizen_base[o];
+ pcity->prod[o] = pcity->citizen_base[o] + pcity->free[o];
} output_type_iterate_end;
/* Add on special extra incomes: trade routes and tithes. */
@@ -2094,6 +2133,7 @@
set_city_bonuses(pcity); /* Calculate the bonus[] array values. */
set_city_tile_output(pcity); /* Calculate the tile_output[] values. */
city_support(pcity, send_unit_info); /* manage settlers, and units */
+ city_get_free_output(pcity, pcity->free);
}
/* Calculate output from citizens. */
Index: common/city.h
===================================================================
--- common/city.h (revision 11583)
+++ common/city.h (working copy)
@@ -230,6 +230,7 @@
int trade[NUM_TRADEROUTES], trade_value[NUM_TRADEROUTES];
/* the productions */
+ int free[O_MAX]; /* Free output received by the city. */
int surplus[O_MAX]; /* Final surplus in each category. */
int waste[O_MAX]; /* Waste/corruption in each category. */
int unhappy_penalty[O_MAX]; /* Penalty from unhappy cities. */
@@ -499,6 +500,7 @@
Specialist_type_id best_specialist(Output_type_id otype,
const struct city *pcity);
int get_final_city_output_bonus(const struct city *pcity, Output_type_id
otype);
+int get_city_terrain_bonus(const struct city *pcity, Output_type_id otype);
bool city_built_last_turn(const struct city *pcity);
/* city creation / destruction */
Index: common/tile.c
===================================================================
--- common/tile.c (revision 11583)
+++ common/tile.c (working copy)
@@ -174,6 +174,41 @@
}
/****************************************************************************
+ The bonus multiplier provided by this tile. This free bonus should be
+ split between all cities for whom the tile is inside the citymap of
+ (see map_tile_get_coverage). It works identically to
+ the EFT_OUTPUT_BONUS.
+****************************************************************************/
+int tile_get_output_bonus(const struct tile *ptile, Output_type_id output)
+{
+ if (!ptile->terrain) {
+ return 0;
+ }
+ if (ptile->resource) {
+ return ptile->resource->bonus[output];
+ } else {
+ return ptile->terrain->bonus[output];
+ }
+}
+
+/****************************************************************************
+ The free output provided by this tile. This free output should be
+ split between all cities for whom the tile is inside the citymap of
+ (see map_tile_get_coverage).
+****************************************************************************/
+int tile_get_output_add(const struct tile *ptile, Output_type_id output)
+{
+ if (!ptile->terrain) {
+ return 0;
+ }
+ if (ptile->resource) {
+ return ptile->resource->add[output];
+ } else {
+ return ptile->terrain->add[output];
+ }
+}
+
+/****************************************************************************
Time to complete the given activity on the given tile.
****************************************************************************/
int tile_activity_time(enum unit_activity activity, const struct tile *ptile)
Index: common/tile.h
===================================================================
--- common/tile.h (revision 11583)
+++ common/tile.h (working copy)
@@ -35,6 +35,7 @@
struct unit_list *units;
bv_player tile_known, tile_seen[V_COUNT];
struct city *worked; /* city working tile, or NULL if none */
+ int covered; /* Number of cities whose citymaps cover the tile. */
Continent_id continent;
struct player *owner; /* Player owning this tile, or NULL. */
struct tile *owner_source; /* what makes it owned by owner */
@@ -70,6 +71,9 @@
enum known_type tile_get_known(const struct tile *ptile,
const struct player *pplayer);
+int tile_get_output_bonus(const struct tile *ptile, Output_type_id otype);
+int tile_get_output_add(const struct tile *ptile, Output_type_id otype);
+
/* An arbitrary somewhat integer value. Activity times are multiplied by
* this amount, and divided by them later before being used. This may
* help to avoid rounding errors; however it should probably be removed. */
Index: common/terrain.h
===================================================================
--- common/terrain.h (revision 11583)
+++ common/terrain.h (working copy)
@@ -112,6 +112,8 @@
int defense_bonus; /* % defense bonus - defaults to zero */
int output[O_MAX];
+ int bonus[O_MAX];
+ int add[O_MAX];
const struct resource **resources; /* NULL-terminated */
@@ -158,6 +160,8 @@
char name_orig[MAX_LEN_NAME];
char identifier; /* server-only, same as terrain->identifier */
int output[O_MAX]; /* Amount added by this resource. */
+ int bonus[O_MAX];
+ int add[O_MAX];
char graphic_str[MAX_LEN_NAME];
char graphic_alt[MAX_LEN_NAME];
};
Index: common/map.c
===================================================================
--- common/map.c (revision 11583)
+++ common/map.c (working copy)
@@ -275,6 +275,7 @@
} vision_layer_iterate_end;
ptile->continent = 0;
ptile->city = NULL;
+ ptile->covered = 0;
ptile->units = unit_list_new();
ptile->worked = NULL; /* pointer to city working tile */
ptile->owner = NULL; /* Tile not claimed by any nation. */
Index: ai/aisettler.c
===================================================================
--- ai/aisettler.c (revision 11583)
+++ ai/aisettler.c (working copy)
@@ -152,15 +152,21 @@
/* Food */
result->citymap[i][j].food
- = base_city_get_output_tile(i, j, pcity, FALSE, O_FOOD);
+ = (base_city_get_output_tile(i, j, pcity, FALSE, O_FOOD)
+ + 4 * tile_get_output_add(ptile, O_FOOD));
/* Shields */
result->citymap[i][j].shield
- = base_city_get_output_tile(i, j, pcity, FALSE, O_SHIELD);
+ = (base_city_get_output_tile(i, j, pcity, FALSE, O_SHIELD)
+ + 4 * tile_get_output_add(ptile, O_SHIELD));
/* Trade */
result->citymap[i][j].trade
- = base_city_get_output_tile(i, j, pcity, FALSE, O_TRADE);
+ = (base_city_get_output_tile(i, j, pcity, FALSE, O_TRADE)
+ + 4 * tile_get_output_add(ptile, O_TRADE)
+ + 4 * tile_get_output_add(ptile, O_GOLD)
+ + 4 * tile_get_output_add(ptile, O_LUXURY)
+ + 4 * tile_get_output_add(ptile, O_SCIENCE));
sum = result->citymap[i][j].food * ai->food_priority
+ result->citymap[i][j].trade * ai->science_priority
@@ -168,7 +174,8 @@
/* Balance perfection */
sum *= PERFECTION / 2;
- if (result->citymap[i][j].food >= 2) {
+ if (result->citymap[i][j].food >= 2
+ || tile_get_output_add(ptile, O_FOOD) > 0) {
sum *= 2; /* we need this to grow */
}
Index: client/citydlg_common.c
===================================================================
--- client/citydlg_common.c (revision 11583)
+++ client/citydlg_common.c (working copy)
@@ -395,6 +395,12 @@
buf[0] = '\0';
+ if (pcity->free[otype] != 0) {
+ cat_snprintf(buf, bufsz,
+ _("%+4d : Free from terrain\n"), pcity->free[otype]);
+ total += pcity->free[otype];
+ }
+
cat_snprintf(buf, bufsz,
_("%+4d : Citizens\n"), pcity->citizen_base[otype]);
total += pcity->citizen_base[otype];
@@ -435,6 +441,18 @@
}
}
+/* was if (priority == 0 && terrain_control.terrain_bonuses[otype]) { ?? */
+ if (terrain_control.terrain_bonuses[otype]) {
+ const int base = total, bonus = get_city_terrain_bonus(pcity, otype);
+
+ total = total * bonus / 100;
+ if (total != base) {
+ cat_snprintf(buf, bufsz,
+ _("%+4d : Bonus from terrain\n"),
+ total - base);
+ }
+ }
+
for (priority = 0; priority < 2; priority++) {
enum effect_type eft[] = {EFT_OUTPUT_BONUS, EFT_OUTPUT_BONUS_2};
Index: client/packhand.c
===================================================================
--- client/packhand.c (revision 11583)
+++ client/packhand.c (working copy)
@@ -466,6 +466,7 @@
}
output_type_iterate(o) {
+ pcity->free[o] = packet->free[o];
pcity->surplus[o] = packet->surplus[o];
pcity->waste[o] = packet->waste[o];
pcity->unhappy_penalty[o] = packet->unhappy_penalty[o];
@@ -624,7 +625,6 @@
}
}
-
if (can_client_change_view()) {
refresh_city_mapcanvas(pcity, pcity->tile, FALSE, FALSE);
}
@@ -2024,6 +2024,8 @@
unit_list_unlink_all(ptile->units);
}
+ ptile->covered = packet->covered;
+
/* update continents */
if (ptile->continent != packet->continent && ptile->continent != 0
&& packet->continent > 0) {
@@ -2331,6 +2333,8 @@
output_type_iterate(o) {
pterrain->output[o] = p->output[o];
+ pterrain->bonus[o] = p->bonus[o];
+ pterrain->add[o] = p->add[o];
} output_type_iterate_end;
pterrain->resources = fc_calloc(p->num_resources + 1,
@@ -2388,6 +2392,8 @@
output_type_iterate(o) {
presource->output[o] = p->output[o];
+ presource->bonus[o] = p->bonus[o];
+ presource->add[o] = p->add[o];
} output_type_iterate_end;
tileset_setup_resource(tileset, presource);
- [Freeciv-Dev] Re: (PR#11311) death to smallpox?,
Per I. Mathisen <=
|
|