Feature #616 » 0004-Add-MaxDistanceSq-requirement-maximum-squared-distan.patch
ai/default/daieffects.c | ||
---|---|---|
case VUT_ACTION:
|
||
case VUT_GOOD:
|
||
case VUT_MINCALFRAG:
|
||
case VUT_MAX_DISTANCE_SQ:
|
||
case VUT_COUNT:
|
||
/* No sensible implementation possible with data available. */
|
||
break;
|
ai/default/daimilitary.c | ||
---|---|---|
case VUT_TERRAINCLASS:
|
||
case VUT_TERRFLAG:
|
||
case VUT_TERRAINALTER:
|
||
case VUT_MAX_DISTANCE_SQ:
|
||
case VUT_NONE:
|
||
return tri_req_active(context, other_context, req);
|
||
case VUT_COUNT:
|
common/fc_types.h | ||
---|---|---|
int min_techs;
|
||
int min_cities;
|
||
int latitude;
|
||
int distance_sq;
|
||
enum topo_flag topo_property;
|
||
enum wrap_flag wrap_property;
|
common/metaknowledge.c | ||
---|---|---|
}
|
||
}
|
||
if (req->source.kind == VUT_MAX_DISTANCE_SQ) {
|
||
if (context->tile == nullptr || other_context->tile == nullptr) {
|
||
/* The tiles may exist but not be passed when the problem type is
|
||
* RPT_POSSIBLE. */
|
||
return prob_type == RPT_CERTAIN;
|
||
}
|
||
/* Tile locations and their distance are fixed */
|
||
return TRUE;
|
||
}
|
||
if (req->source.kind == VUT_ACTION
|
||
|| req->source.kind == VUT_OTYPE) {
|
||
/* This requirement type is intended to specify the situation. */
|
common/reqtext.c | ||
---|---|---|
}
|
||
break;
|
||
case VUT_MAX_DISTANCE_SQ:
|
||
switch (preq->range) {
|
||
case REQ_RANGE_TILE:
|
||
fc_strlcat(buf, prefix, bufsz);
|
||
/* Test some special cases */
|
||
switch (preq->source.value.distance_sq)
|
||
{
|
||
case 0:
|
||
if (preq->present) {
|
||
fc_strlcat(buf, _("Must be the same tile."), bufsz);
|
||
} else {
|
||
fc_strlcat(buf, _("Must not be the same tile."), bufsz);
|
||
}
|
||
break;
|
||
case 1:
|
||
if (preq->present) {
|
||
fc_strlcat(buf, _("Must be cardinally adjacent."), bufsz);
|
||
} else {
|
||
fc_strlcat(buf, _("Must not be cardinally adjacent."), bufsz);
|
||
}
|
||
break;
|
||
case 2:
|
||
case 3:
|
||
if (preq->present) {
|
||
fc_strlcat(buf, _("Must be adjacent."), bufsz);
|
||
} else {
|
||
fc_strlcat(buf, _("Must not be adjacent."), bufsz);
|
||
}
|
||
break;
|
||
default:
|
||
if (preq->present) {
|
||
cat_snprintf(buf, bufsz,
|
||
_("The squared distance between the tiles "
|
||
"must be at most %d."),
|
||
preq->source.value.distance_sq);
|
||
} else {
|
||
cat_snprintf(buf, bufsz,
|
||
_("The squared distance between the tiles "
|
||
"must be at least %d."),
|
||
preq->source.value.distance_sq + 1);
|
||
}
|
||
break;
|
||
}
|
||
return TRUE;
|
||
case REQ_RANGE_CADJACENT:
|
||
case REQ_RANGE_ADJACENT:
|
||
case REQ_RANGE_CITY:
|
||
case REQ_RANGE_TRADE_ROUTE:
|
||
case REQ_RANGE_CONTINENT:
|
||
case REQ_RANGE_PLAYER:
|
||
case REQ_RANGE_TEAM:
|
||
case REQ_RANGE_ALLIANCE:
|
||
case REQ_RANGE_WORLD:
|
||
case REQ_RANGE_LOCAL:
|
||
case REQ_RANGE_COUNT:
|
||
/* Not supported. */
|
||
break;
|
||
}
|
||
break;
|
||
case VUT_COUNT:
|
||
break;
|
||
}
|
common/requirements.c | ||
---|---|---|
return;
|
||
}
|
||
break;
|
||
case VUT_MAX_DISTANCE_SQ:
|
||
source->value.distance_sq = atoi(value);
|
||
if (0 <= source->value.distance_sq) {
|
||
return;
|
||
}
|
||
break;
|
||
case VUT_COUNT:
|
||
break;
|
||
}
|
||
... | ... | |
case VUT_MAXLATITUDE:
|
||
source.value.latitude = value;
|
||
return source;
|
||
case VUT_MAX_DISTANCE_SQ:
|
||
source.value.distance_sq = value;
|
||
return source;
|
||
case VUT_COUNT:
|
||
break;
|
||
}
|
||
... | ... | |
case VUT_MINLATITUDE:
|
||
case VUT_MAXLATITUDE:
|
||
return source->value.latitude;
|
||
case VUT_MAX_DISTANCE_SQ:
|
||
return source->value.distance_sq;
|
||
case VUT_COUNT:
|
||
break;
|
||
}
|
||
... | ... | |
case VUT_MAXTILEUNITS:
|
||
case VUT_MINLATITUDE:
|
||
case VUT_MAXLATITUDE:
|
||
case VUT_MAX_DISTANCE_SQ:
|
||
req.range = REQ_RANGE_TILE;
|
||
break;
|
||
case VUT_COUNTER:
|
||
... | ... | |
&& req.range != REQ_RANGE_ADJACENT);
|
||
break;
|
||
case VUT_TERRAINALTER: /* XXX could in principle support C/ADJACENT */
|
||
case VUT_MAX_DISTANCE_SQ:
|
||
invalid = (req.range != REQ_RANGE_TILE);
|
||
break;
|
||
case VUT_CITYTILE:
|
||
... | ... | |
case VUT_MINCITIES:
|
||
case VUT_MINLATITUDE:
|
||
case VUT_MAXLATITUDE:
|
||
case VUT_MAX_DISTANCE_SQ:
|
||
/* 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
|
||
... | ... | |
}
|
||
return FALSE;
|
||
case VUT_MAX_DISTANCE_SQ:
|
||
if (req2->source.kind != VUT_MAX_DISTANCE_SQ) {
|
||
/* Finding contradictions across requirement kinds isn't supported
|
||
* for MaxDistanceSq requirements. */
|
||
return FALSE;
|
||
}
|
||
return are_bounds_contradictions(
|
||
req1->source.value.distance_sq, req1->present,
|
||
req2->source.value.distance_sq, req2->present);
|
||
default:
|
||
/* No special knowledge exists. The requirements aren't the exact
|
||
* opposite of each other per the initial check. */
|
||
... | ... | |
#define IS_REQ_ACTIVE_VARIANT_ASSERT(_kind) \
|
||
{ \
|
||
fc_assert_ret_val(req != NULL, TRI_MAYBE); \
|
||
fc_assert_ret_val(req != nullptr, TRI_MAYBE); \
|
||
fc_assert_ret_val(req->source.kind == _kind, TRI_MAYBE); \
|
||
fc_assert(context != NULL); \
|
||
fc_assert(context != nullptr); \
|
||
fc_assert(other_context != nullptr); \
|
||
}
|
||
/**********************************************************************//**
|
||
... | ... | |
return TRI_MAYBE;
|
||
}
|
||
/**********************************************************************//**
|
||
Determine whether a maximum squared distance 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 squared distance requirement
|
||
**************************************************************************/
|
||
static enum fc_tristate
|
||
is_max_distance_sq_req_active(const struct civ_map *nmap,
|
||
const struct req_context *context,
|
||
const struct req_context *other_context,
|
||
const struct requirement *req)
|
||
{
|
||
IS_REQ_ACTIVE_VARIANT_ASSERT(VUT_MAX_DISTANCE_SQ);
|
||
switch (req->range) {
|
||
case REQ_RANGE_TILE:
|
||
if (context->tile == nullptr || other_context->tile == nullptr) {
|
||
return TRI_MAYBE;
|
||
}
|
||
return BOOL_TO_TRISTATE(
|
||
sq_map_distance(context->tile, other_context->tile)
|
||
<= req->source.value.distance_sq
|
||
);
|
||
default:
|
||
break;
|
||
}
|
||
fc_assert_msg(FALSE,
|
||
"Illegal range %d for max squared distance requirement.",
|
||
req->range);
|
||
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_IMPR_FLAG] = {is_buildingflag_req_active, REQUCH_YES},
|
||
[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_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_TERRFLAG:
|
||
case VUT_TERRAINALTER:
|
||
case VUT_MINYEAR:
|
||
case VUT_MAX_DISTANCE_SQ:
|
||
case VUT_NONE:
|
||
case VUT_COUNT:
|
||
/* Not implemented. */
|
||
... | ... | |
case VUT_MINLATITUDE:
|
||
case VUT_MAXLATITUDE:
|
||
return psource1->value.latitude == psource2->value.latitude;
|
||
case VUT_MAX_DISTANCE_SQ:
|
||
return psource1->value.distance_sq == psource2->value.distance_sq;
|
||
case VUT_COUNT:
|
||
break;
|
||
}
|
||
... | ... | |
case VUT_MAXLATITUDE:
|
||
fc_snprintf(buffer, sizeof(buffer), "%d", psource->value.latitude);
|
||
return buffer;
|
||
case VUT_MAX_DISTANCE_SQ:
|
||
fc_snprintf(buffer, sizeof(buffer), "%d", psource->value.distance_sq);
|
||
return buffer;
|
||
case VUT_COUNT:
|
||
break;
|
||
... | ... | |
cat_snprintf(buf, bufsz, _("Latitude <= %d"),
|
||
psource->value.latitude);
|
||
return buf;
|
||
case VUT_MAX_DISTANCE_SQ:
|
||
/* TRANS: here <= means 'less than or equal'. */
|
||
cat_snprintf(buf, bufsz, _("Squared distance <= %d"),
|
||
psource->value.distance_sq);
|
||
return buf;
|
||
case VUT_COUNT:
|
||
break;
|
||
}
|
doc/README.actions | ||
---|---|---|
target requirement vector to the actor requirement vector.
|
||
* Asymmetric local DiplRel requirements must test for the same thing in
|
||
the opposite direction. Example: "Hosts embassy" -> "Has embassy"
|
||
A "MaxDistanceSq" requirement with the range "Tile" should always be put in
|
||
the actor requirements, for the same reasons.
|
||
Actions and Lua
|
||
===============
|
doc/README.effects | ||
---|---|---|
MinMoveFrags: Local
|
||
MinVeteran: Local
|
||
MinHitPoints: Local
|
||
MaxDistanceSq: Tile
|
||
MinSize is the minimum size of a city required.
|
||
... | ... | |
is a port, it's a tile of the nearby ocean but not of its continent).
|
||
MinLatitude and MaxLatitude are numbers from -1000 (south pole) to 1000
|
||
(north pole).
|
||
MaxDistanceSq is about the (squared) distance between two tiles; currently
|
||
only available for action enablers (see also README.actions) and a select
|
||
few effects.
|
||
CityStatus is "OwnedByOriginal", "Transferred", "Starved",
|
||
"Disorder", or "Celebration"
|
||
The difference between "OwnedByOriginal" and "Transferred" is that
|
gen_headers/enums/fc_types_enums.def | ||
---|---|---|
PLAYER_STATE "PlayerState"
|
||
FORM_AGE "FormAge"
|
||
MINCITIES "MinCities"
|
||
MAX_DISTANCE_SQ "MaxDistanceSq"
|
||
end
|
server/cityturn.c | ||
---|---|---|
case VUT_ACTION:
|
||
case VUT_OTYPE:
|
||
case VUT_SPECIALIST:
|
||
case VUT_MAX_DISTANCE_SQ:
|
||
case VUT_TERRAINALTER: /* XXX could do this in principle */
|
||
/* Will only happen with a bogus ruleset. */
|
||
log_error("worklist_change_build_target() has bogus preq");
|
server/ruleset/rssanity.c | ||
---|---|---|
case VUT_IMPR_GENUS:
|
||
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 */
|
||
/* There can be only one requirement of these types (with current
|
||
* range limitations)
|
||
* Requirements might be identical, but we consider multiple
|
||
... | ... | |
req_to_fstring(preq, &astr));
|
||
astr_free(&astr);
|
||
ok = FALSE;
|
||
} else if (preq->source.kind == VUT_MAX_DISTANCE_SQ
|
||
&& preq->range == REQ_RANGE_TILE) {
|
||
struct astring astr;
|
||
/* A Tile-ranged MaxDistanceSq requirement can be expressed as a
|
||
* requirement in actor_reqs. Demand that it is there. */
|
||
ruleset_error(logger, LOG_ERROR,
|
||
_("Action enabler for %s has a tile MaxDistanceSq "
|
||
"requirement %s in target_reqs! Please read the "
|
||
"section \"Requirement vector rules\" in "
|
||
"doc/README.actions"),
|
||
action_id_rule_name(act),
|
||
req_to_fstring(preq, &astr));
|
||
astr_free(&astr);
|
||
ok = FALSE;
|
||
}
|
||
} requirement_vector_iterate_end;
|
||
tools/ruledit/univ_value.c | ||
---|---|---|
case VUT_MAXLATITUDE:
|
||
src->value.latitude = 0;
|
||
return TRUE;
|
||
case VUT_MAX_DISTANCE_SQ:
|
||
src->value.distance_sq = 0;
|
||
return TRUE;
|
||
case VUT_COUNT:
|
||
fc_assert(src->kind != VUT_COUNT);
|
||
return FALSE;
|
||
... | ... | |
case VUT_MINCITIES:
|
||
case VUT_MINLATITUDE:
|
||
case VUT_MAXLATITUDE:
|
||
case VUT_MAX_DISTANCE_SQ:
|
||
/* Requirement types having numerical value */
|
||
cb(nullptr, FALSE, data);
|
||
break;
|