Project

General

Profile

Feature #629 » 0006-Add-MaxRegionTiles-continent-size-requirement-type.patch

main v2 - Alina Lenk, 05/19/2024 10:27 PM

View differences:

ai/default/daieffects.c
case VUT_GOOD:
case VUT_MINCALFRAG:
case VUT_MAX_DISTANCE_SQ:
case VUT_MAX_REGION_TILES:
case VUT_COUNT:
/* No sensible implementation possible with data available. */
break;
ai/default/daimilitary.c
case VUT_TERRFLAG:
case VUT_TERRAINALTER:
case VUT_MAX_DISTANCE_SQ:
case VUT_MAX_REGION_TILES:
case VUT_NONE:
return tri_req_active(context, other_context, req);
case VUT_COUNT:
common/fc_types.h
int min_cities;
int latitude;
int distance_sq;
int region_tiles;
enum topo_flag topo_property;
enum wrap_flag wrap_property;
common/reqtext.c
}
break;
case VUT_MAX_REGION_TILES:
switch (preq->range) {
case REQ_RANGE_CONTINENT:
fc_strlcat(buf, prefix, bufsz);
if (preq->present) {
cat_snprintf(buf, bufsz,
_("Requires a continent or ocean size of at most %d."),
preq->source.value.region_tiles);
} else {
cat_snprintf(buf, bufsz,
_("Requires a continent or ocean size of at least %d."),
preq->source.value.region_tiles + 1);
}
return TRUE;
case REQ_RANGE_PLAYER:
case REQ_RANGE_TEAM:
case REQ_RANGE_ALLIANCE:
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:
/* Not supported. */
break;
}
break;
case VUT_COUNT:
break;
}
common/requirements.c
return;
}
break;
case VUT_MAX_REGION_TILES:
source->value.region_tiles = atoi(value);
if (0 < source->value.region_tiles) {
return;
}
break;
case VUT_COUNT:
break;
}
......
case VUT_MAX_DISTANCE_SQ:
source.value.distance_sq = value;
return source;
case VUT_MAX_REGION_TILES:
source.value.region_tiles = value;
return source;
case VUT_COUNT:
break;
}
......
return source->value.latitude;
case VUT_MAX_DISTANCE_SQ:
return source->value.distance_sq;
case VUT_MAX_REGION_TILES:
return source->value.region_tiles;
case VUT_COUNT:
break;
}
......
case VUT_SERVERSETTING:
req.range = REQ_RANGE_WORLD;
break;
case VUT_MAX_REGION_TILES:
req.range = REQ_RANGE_CONTINENT;
break;
}
}
......
case VUT_PLAYER_STATE:
invalid = (req.range != REQ_RANGE_PLAYER);
break;
case VUT_MAX_REGION_TILES:
invalid = (req.range != REQ_RANGE_CONTINENT);
break;
case VUT_IMPROVEMENT:
/* Valid ranges depend on the building genus (wonder/improvement),
* which might not have been loaded from the ruleset yet.
......
case VUT_MINLATITUDE:
case VUT_MAXLATITUDE:
case VUT_MAX_DISTANCE_SQ:
case VUT_MAX_REGION_TILES:
/* Most requirements don't support 'survives'. */
invalid = survives;
break;
......
return are_requirements_contradictions(req1, &nreq2);
}
/**********************************************************************//**
Returns TRUE iff two bounds that could each be either an upper or lower
bound are contradicting each other. This function assumes that of the
upper and lower bounds, one will be inclusive, the other exclusive.
**************************************************************************/
static inline bool are_bounds_contradictions(int bound1, bool is_upper1,
int bound2, bool is_upper2)
{
/* If the bounds are on opposite sides, and one is inclusive, the other
* exclusive, the number of values that satisfy both bounds is exactly
* their difference, (upper bound) - (lower bound).
* The bounds contradict each other iff this difference is 0 or less,
* i.e. iff (upper bound) <= (lower bound) */
if (is_upper1 && !is_upper2) {
return bound1 <= bound2;
} else if (!is_upper1 && is_upper2) {
return bound1 >= bound2;
}
/* Both are upper or both are lower ~> no contradiction possible */
return FALSE;
}
/**********************************************************************//**
Returns TRUE if req1 and req2 contradicts each other.
......
/* Finding contradictions across requirement kinds aren't supported
* for MinMoveFrags requirements. */
return FALSE;
} else if (req1->present == req2->present) {
/* No contradiction possible. */
return FALSE;
} else {
/* Number of move fragments left can't be larger than the number
* required to be present and smaller than the number required to not
* be present when the number required to be present is smaller than
* the number required to not be present. */
if (req1->present) {
return req1->source.value.minmoves >= req2->source.value.minmoves;
} else {
return req1->source.value.minmoves <= req2->source.value.minmoves;
}
}
break;
return are_bounds_contradictions(
req1->source.value.minmoves, !req1->present,
req2->source.value.minmoves, !req2->present);
case VUT_MINLATITUDE:
case VUT_MAXLATITUDE:
if (req2->source.kind != VUT_MINLATITUDE
......
/* Finding contradictions across requirement kinds isn't supported
* for MaxDistanceSq requirements. */
return FALSE;
} else if (req1->present == req2->present) {
/* Both bounds are on the same side, can't contradict */
}
return are_bounds_contradictions(
req1->source.value.distance_sq, req1->present,
req2->source.value.distance_sq, req2->present);
case VUT_MAX_REGION_TILES:
if (req2->source.kind != VUT_MAX_REGION_TILES) {
/* Finding contradictions across requirement kinds isn't supported
* for MaxRegionTiles requirements. */
return FALSE;
} else if (req1->range != req2->range) {
/* Counting completely separate things */
return FALSE;
}
/* Different bounds ~> contradiction possible.
* Need (negated req value) < (actual value) <= (present req value)
* to be satisfied; impossible iff (present) <= (negated). */
return req1->present
? (req1->source.value.distance_sq <= req2->source.value.distance_sq)
: (req1->source.value.distance_sq >= req2->source.value.distance_sq);
return are_bounds_contradictions(
req1->source.value.region_tiles, req1->present,
req2->source.value.region_tiles, req2->present);
default:
/* No special knowledge exists. The requirements aren't the exact
* opposite of each other per the initial check. */
......
return TRI_MAYBE;
}
/**********************************************************************//**
Determine whether a maximum tiles of same region requirement is satisfied
in a given context, ignoring parts of the requirement that can be handled
uniformly for all requirement types.
context, other_context and req must not be null,
and req must be a max region tiles requirement
**************************************************************************/
static enum fc_tristate
is_max_region_tiles_req_active(const struct civ_map *nmap,
const struct req_context *context,
const struct req_context *other_context,
const struct requirement *req)
{
int known_tiles;
bool known_accurate;
IS_REQ_ACTIVE_VARIANT_ASSERT(VUT_MAX_REGION_TILES);
switch (req->range) {
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);
if (cont > 0) {
known_tiles = nmap->continent_sizes[cont];
known_accurate = (is_server()
|| (nmap->client.continent_unknown_adj_counts[cont] == 0));
} 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;
}
}
break;
default:
fc_assert_msg(FALSE,
"Illegal range %d for max tile number requirement.",
req->range);
return TRI_MAYBE;
}
if (known_tiles > req->source.value.region_tiles) {
/* We already know about more tiles than the limit */
return TRI_NO;
} else if (known_accurate) {
/* We know there aren't any more tiles that could break the limit */
return TRI_YES;
}
return TRI_MAYBE;
}
/**********************************************************************//**
Determine whether a minimum year requirement is satisfied in a given
context, ignoring parts of the requirement that can be handled uniformly
......
[VUT_PLAYER_FLAG] = {is_plr_flag_req_active, REQUCH_NO},
[VUT_PLAYER_STATE] = {is_plr_state_req_active, REQUCH_NO},
[VUT_MAX_DISTANCE_SQ] = {is_max_distance_sq_req_active, REQUCH_YES},
[VUT_MAX_REGION_TILES] = {is_max_region_tiles_req_active, REQUCH_NO},
[VUT_MAXLATITUDE] = {is_latitude_req_active, REQUCH_YES},
[VUT_MAXTILEUNITS] = {is_maxunitsontile_req_active, REQUCH_NO},
[VUT_MINCALFRAG] = {is_mincalfrag_req_active, REQUCH_NO},
......
case VUT_TERRAINALTER:
case VUT_MINYEAR:
case VUT_MAX_DISTANCE_SQ:
case VUT_MAX_REGION_TILES:
case VUT_NONE:
case VUT_COUNT:
/* Not implemented. */
......
return psource1->value.latitude == psource2->value.latitude;
case VUT_MAX_DISTANCE_SQ:
return psource1->value.distance_sq == psource2->value.distance_sq;
case VUT_MAX_REGION_TILES:
return psource1->value.region_tiles == psource2->value.region_tiles;
case VUT_COUNT:
break;
}
......
case VUT_MAX_DISTANCE_SQ:
fc_snprintf(buffer, sizeof(buffer), "%d", psource->value.distance_sq);
return buffer;
case VUT_MAX_REGION_TILES:
fc_snprintf(buffer, sizeof(buffer), "%d", psource->value.region_tiles);
return buffer;
case VUT_COUNT:
break;
......
cat_snprintf(buf, bufsz, _("Squared distance <= %d"),
psource->value.distance_sq);
return buf;
case VUT_MAX_REGION_TILES:
cat_snprintf(buf, bufsz, _("%d or fewer region tiles"),
psource->value.region_tiles);
return buf;
case VUT_COUNT:
break;
}
doc/README.effects
MinVeteran: Local
MinHitPoints: Local
MaxDistanceSq: Tile
MaxRegionTiles: Continent
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).
CityStatus is "OwnedByOriginal", "Transferred", "Starved",
"Disorder", or "Celebration"
The difference between "OwnedByOriginal" and "Transferred" is that
gen_headers/enums/fc_types_enums.def
FORM_AGE "FormAge"
MINCITIES "MinCities"
MAX_DISTANCE_SQ "MaxDistanceSq"
MAX_REGION_TILES "MaxRegionTiles"
end
server/cityturn.c
pcity, "have_terrainflag");
}
break;
case VUT_MAX_REGION_TILES:
/* Changing the continent size is hard; cf. VUT_TERRAINCLASS above.
* Change this when we support other ranges. */
purge = TRUE;
break;
case VUT_ROADFLAG:
if (preq->present) {
notify_player(pplayer, city_tile(pcity),
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
tools/ruledit/univ_value.c
case VUT_MAX_DISTANCE_SQ:
src->value.distance_sq = 0;
return TRUE;
case VUT_MAX_REGION_TILES:
src->value.region_tiles = 0;
return TRUE;
case VUT_COUNT:
fc_assert(src->kind != VUT_COUNT);
return FALSE;
......
case VUT_MINLATITUDE:
case VUT_MAXLATITUDE:
case VUT_MAX_DISTANCE_SQ:
case VUT_MAX_REGION_TILES:
/* Requirement types having numerical value */
cb(nullptr, FALSE, data);
break;
(2-2/4)