Project

General

Profile

Feature #652 » 0007-Support-MaxRegionTiles-at-C-Adjacent-ranges.patch

main - Alina Lenk, 05/20/2024 12:38 AM

View differences:

common/reqtext.c
case VUT_MAX_REGION_TILES:
switch (preq->range) {
case REQ_RANGE_CADJACENT:
fc_strlcat(buf, prefix, bufsz);
/* Off-by-one: The requirement counts the tile itself, we're phrasing
* the helptext in terms of *other* tiles only. */
if (preq->present) {
if (preq->source.value.region_tiles == 1) {
/* Special case for zero */
fc_strlcat(buf,
_("No other cardinally adjacent tile may be part of "
"the same continent or ocean."),
bufsz);
} else {
cat_snprintf(buf, bufsz,
PL_("No more than %d other cardinally adjacent tile "
"may be part of the same continent or ocean.",
"No more than %d other cardinally adjacent tiles "
"may be part of the same continent or ocean.",
preq->source.value.region_tiles - 1),
preq->source.value.region_tiles - 1);
}
} else {
cat_snprintf(buf, bufsz,
PL_("Requires at least %d other cardinally adjacent "
"tile of the same continent or ocean.",
"Requires at least %d other cardinally adjacent "
"tiles of the same continent or ocean.",
preq->source.value.region_tiles),
preq->source.value.region_tiles);
}
return TRUE;
case REQ_RANGE_ADJACENT:
fc_strlcat(buf, prefix, bufsz);
/* Off-by-one: The requirement counts the tile itself, we're phrasing
* the helptext in terms of *other* tiles only. */
if (preq->present) {
if (preq->source.value.region_tiles == 1) {
/* Special case for zero */
fc_strlcat(buf,
_("No other adjacent tile may be part of the same "
"continent or ocean."),
bufsz);
} else {
cat_snprintf(buf, bufsz,
PL_("No more than %d other adjacent tile may be "
"part of the same continent or ocean.",
"No more than %d other adjacent tiles may be "
"part of the same continent or ocean.",
preq->source.value.region_tiles - 1),
preq->source.value.region_tiles - 1);
}
} else {
cat_snprintf(buf, bufsz,
PL_("Requires at least %d other adjacent tile of the "
"same continent or ocean.",
"Requires at least %d other adjacent tiles of the "
"same continent or ocean.",
preq->source.value.region_tiles),
preq->source.value.region_tiles);
}
return TRUE;
case REQ_RANGE_CONTINENT:
fc_strlcat(buf, prefix, bufsz);
if (preq->present) {
......
case REQ_RANGE_WORLD:
case REQ_RANGE_LOCAL:
case REQ_RANGE_TILE:
case REQ_RANGE_CADJACENT:
case REQ_RANGE_ADJACENT:
case REQ_RANGE_CITY:
case REQ_RANGE_TRADE_ROUTE:
case REQ_RANGE_COUNT:
common/requirements.c
invalid = (req.range != REQ_RANGE_PLAYER);
break;
case VUT_MAX_REGION_TILES:
invalid = (req.range != REQ_RANGE_CONTINENT);
invalid = (req.range != REQ_RANGE_CONTINENT
&& req.range != REQ_RANGE_CADJACENT
&& req.range != REQ_RANGE_ADJACENT);
break;
case VUT_IMPROVEMENT:
/* Valid ranges depend on the building genus (wonder/improvement),
......
* for MaxRegionTiles requirements. */
return FALSE;
} else if (req1->range != req2->range) {
/* Counting completely separate things */
/* FIXME: Finding contradictions across ranges not yet supported.
* In particular, a max at a small range and a min at a larger range
* needs extra work to figure out. */
return FALSE;
}
return are_bounds_contradictions(
......
const struct req_context *other_context,
const struct requirement *req)
{
int known_tiles;
bool known_accurate;
int max_tiles, min_tiles = 1;
IS_REQ_ACTIVE_VARIANT_ASSERT(VUT_MAX_REGION_TILES);
switch (req->range) {
case REQ_RANGE_CADJACENT:
case REQ_RANGE_ADJACENT:
/* The tile itself is included in the range */
max_tiles = 1 + ((req->range == REQ_RANGE_CADJACENT)
? nmap->num_cardinal_dirs
: nmap->num_valid_dirs);
if (context->tile == nullptr || tile_continent(context->tile) == 0) {
/* Note: If we know the tile's position, we could come up with a
* better upper bound by checking how many [cardinally] adjacent
* tiles share the same continent/ocean among each other.
* Probably not worth the effort though. */
break;
} else {
Continent_id cont = tile_continent(context->tile);
const enum direction8 *dirlist = ((req->range == REQ_RANGE_CADJACENT)
? nmap->cardinal_dirs
: nmap->valid_dirs);
int dircount = max_tiles - 1;
adjc_dirlist_iterate(nmap, context->tile, adj_tile, _dir,
dirlist, dircount) {
Continent_id adj_cont = tile_continent(adj_tile);
if (adj_cont == cont) {
min_tiles++;
} else if (adj_cont != 0) {
max_tiles--;
}
} adjc_dirlist_iterate_end;
}
break;
case REQ_RANGE_CONTINENT:
{
Continent_id cont = context->tile ? tile_continent(context->tile) : 0;
......
fc_assert_ret_val(cont <= nmap->num_continents, TRI_MAYBE);
fc_assert_ret_val(-cont <= nmap->num_oceans, TRI_MAYBE);
/* Note: We could come up with a better upper bound by subtracting
* all other continent/ocean sizes, or all except the largest if we
* don't know the tile.
* We could even do a flood-fill count of the unknown area bordered
* by known tiles of the continent.
* Probably not worth the effort though. */
max_tiles = nmap->xsize * nmap->ysize;
if (cont > 0) {
known_tiles = nmap->continent_sizes[cont];
known_accurate = (is_server()
|| (nmap->client.continent_unknown_adj_counts[cont] == 0));
min_tiles = nmap->continent_sizes[cont];
if (is_server() || (nmap->client.continent_unknown_adj_counts[cont]
== 0)) {
max_tiles = min_tiles;
}
} else if (cont < 0) {
known_tiles = nmap->ocean_sizes[-cont];
known_accurate = (is_server()
|| (nmap->client.ocean_unknown_adj_counts[-cont] == 0));
} else {
/* Even if we don't know the continent, we know it has at least one
* tile (the target tile) */
known_tiles = 1;
known_accurate = FALSE;
min_tiles = nmap->ocean_sizes[-cont];
if (is_server() || (nmap->client.ocean_unknown_adj_counts[-cont]
== 0)) {
max_tiles = min_tiles;
}
}
}
break;
default:
fc_assert_msg(FALSE,
"Illegal range %d for max tile number requirement.",
"Illegal range %d for max region tiles requirement.",
req->range);
return TRI_MAYBE;
}
if (known_tiles > req->source.value.region_tiles) {
/* We already know about more tiles than the limit */
if (min_tiles > req->source.value.region_tiles) {
return TRI_NO;
} else if (known_accurate) {
/* We know there aren't any more tiles that could break the limit */
} else if (max_tiles <= req->source.value.region_tiles) {
return TRI_YES;
}
return TRI_MAYBE;
doc/README.effects
MinVeteran: Local
MinHitPoints: Local
MaxDistanceSq: Tile
MaxRegionTiles: Continent
MaxRegionTiles: Continent, Adjacent, CAdjacent
MinSize is the minimum size of a city required.
......
MaxDistanceSq is about the (squared) distance between two tiles; currently
only available for action enablers (see also README.actions) and a select
few effects.
MaxRegionTiles is continent or ocean size (number of tiles).
MaxRegionTiles is about the number of tiles of the same continent or ocean as
the target tile in the given range (including the tile itself). At "Continent"
range this is just the full continent/ocean size.
CityStatus is "OwnedByOriginal", "Transferred", "Starved",
"Disorder", or "Celebration"
The difference between "OwnedByOriginal" and "Transferred" is that
server/cityturn.c
break;
case VUT_MAX_REGION_TILES:
/* Changing the continent size is hard; cf. VUT_TERRAINCLASS above.
* Change this when we support other ranges. */
* Change this when we support less fixed ranges (e.g. city?). */
purge = TRUE;
break;
case VUT_ROADFLAG:
server/ruleset/rssanity.c
case VUT_ORIGINAL_OWNER: /* City range -> only one original owner */
case VUT_FORM_AGE:
case VUT_MAX_DISTANCE_SQ: /* Breaks nothing, but has no sense either */
case VUT_MAX_REGION_TILES: /* Breaks nothing, but has no sense either */
/* There can be only one requirement of these types (with current
* range limitations)
* Requirements might be identical, but we consider multiple
......
/* Can have multiple requirements of these types */
case VUT_MINLATITUDE:
case VUT_MAXLATITUDE:
case VUT_MAX_REGION_TILES:
/* Can have multiple requirements at different ranges.
* TODO: Compare to number of legal ranges? */
break;
(1-1/3)