Project

General

Profile

Feature #616 » 0007-Add-MaxDistanceSq-requirement-maximum-squared-distan.patch

main - Alina Lenk, 05/16/2024 01:31 AM

View differences:

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/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 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;
} else if (req1->present == req2->present) {
/* Both bounds are on the same side, can't contradict */
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);
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;
(1-1/3)