Feature #614 » 0007-Add-TileRel-requirement-type.patch
| ai/default/daieffects.c | ||
|---|---|---|
|
case VUT_MINCALFRAG:
|
||
|
case VUT_MAX_DISTANCE_SQ:
|
||
|
case VUT_MAX_REGION_TILES:
|
||
|
case VUT_TILE_REL:
|
||
|
case VUT_COUNT:
|
||
|
/* No sensible implementation possible with data available. */
|
||
|
break;
|
||
| ai/default/daimilitary.c | ||
|---|---|---|
|
case VUT_TERRAINALTER:
|
||
|
case VUT_MAX_DISTANCE_SQ:
|
||
|
case VUT_MAX_REGION_TILES:
|
||
|
case VUT_TILE_REL:
|
||
|
case VUT_NONE:
|
||
|
return tri_req_active(context, other_context, req);
|
||
|
case VUT_COUNT:
|
||
| common/fc_types.h | ||
|---|---|---|
|
enum citytile_type citytile;
|
||
|
enum citystatus_type citystatus;
|
||
|
enum plrstate_type plrstate;
|
||
|
enum tilerel_type tilerel;
|
||
|
int minsize;
|
||
|
int minculture;
|
||
|
int minforeignpct;
|
||
| common/metaknowledge.c | ||
|---|---|---|
|
}
|
||
|
}
|
||
|
if (req->source.kind == VUT_TILE_REL) {
|
||
|
if (context->tile == NULL || other_context->tile == NULL) {
|
||
|
/* The tile may exist but not be passed when the problem type is
|
||
|
* RPT_POSSIBLE. */
|
||
|
return prob_type == RPT_CERTAIN;
|
||
|
}
|
||
|
if (tile_get_known(other_context->tile, pov_player) == TILE_UNKNOWN) {
|
||
|
return FALSE;
|
||
|
}
|
||
|
switch (req->range) {
|
||
|
case REQ_RANGE_TILE:
|
||
|
case REQ_RANGE_CADJACENT:
|
||
|
case REQ_RANGE_ADJACENT:
|
||
|
/* TODO: Known tiles might be enough to determine the answer already;
|
||
|
* should we check on an individual requirement basis? */
|
||
|
if (tile_get_known(context->tile, pov_player) == TILE_UNKNOWN) {
|
||
|
return FALSE;
|
||
|
}
|
||
|
range_adjc_iterate(&(wld.map), context->tile, req->range, adj_tile) {
|
||
|
if (tile_get_known(adj_tile, pov_player) == TILE_UNKNOWN) {
|
||
|
return FALSE;
|
||
|
}
|
||
|
} range_adjc_iterate_end;
|
||
|
return TRUE;
|
||
|
case REQ_RANGE_CITY:
|
||
|
case REQ_RANGE_TRADE_ROUTE:
|
||
|
case REQ_RANGE_CONTINENT:
|
||
|
case REQ_RANGE_PLAYER:
|
||
|
case REQ_RANGE_ALLIANCE:
|
||
|
case REQ_RANGE_TEAM:
|
||
|
case REQ_RANGE_WORLD:
|
||
|
case REQ_RANGE_LOCAL:
|
||
|
case REQ_RANGE_COUNT:
|
||
|
/* Non existing range for requirement types. */
|
||
|
return FALSE;
|
||
|
}
|
||
|
}
|
||
|
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_TILE_REL:
|
||
|
switch (preq->source.value.tilerel) {
|
||
|
case TREL_SAME_REGION:
|
||
|
switch (preq->range) {
|
||
|
case REQ_RANGE_TILE:
|
||
|
fc_strlcat(buf, prefix, bufsz);
|
||
|
if (preq->present) {
|
||
|
fc_strlcat(buf, _("Must be on the same continent or ocean."),
|
||
|
bufsz);
|
||
|
} else {
|
||
|
fc_strlcat(buf, _("Must be on a different continent or ocean."),
|
||
|
bufsz);
|
||
|
}
|
||
|
return TRUE;
|
||
|
case REQ_RANGE_CADJACENT:
|
||
|
fc_strlcat(buf, prefix, bufsz);
|
||
|
if (preq->present) {
|
||
|
fc_strlcat(buf, _("Must be cardinally adjacent to the same "
|
||
|
"continent or ocean."),
|
||
|
bufsz);
|
||
|
} else {
|
||
|
fc_strlcat(buf, _("Must not be cardinally adjacent to the same "
|
||
|
"continent or ocean."),
|
||
|
bufsz);
|
||
|
}
|
||
|
return TRUE;
|
||
|
case REQ_RANGE_ADJACENT:
|
||
|
fc_strlcat(buf, prefix, bufsz);
|
||
|
if (preq->present) {
|
||
|
fc_strlcat(buf, _("Must be adjacent to the same continent or "
|
||
|
"ocean."),
|
||
|
bufsz);
|
||
|
} else {
|
||
|
fc_strlcat(buf, _("Must not be adjacent to the same continent "
|
||
|
"or ocean."),
|
||
|
bufsz);
|
||
|
}
|
||
|
return TRUE;
|
||
|
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 TREL_ONLY_OTHER_REGION:
|
||
|
switch (preq->range) {
|
||
|
case REQ_RANGE_CADJACENT:
|
||
|
fc_strlcat(buf, prefix, bufsz);
|
||
|
if (preq->present) {
|
||
|
fc_strlcat(buf, _("May only be cardinally adjacent to this "
|
||
|
"other continent or ocean."),
|
||
|
bufsz);
|
||
|
} else {
|
||
|
fc_strlcat(buf, _("Must be cardinally adjacent to more than "
|
||
|
"just this other continent or ocean."),
|
||
|
bufsz);
|
||
|
}
|
||
|
return TRUE;
|
||
|
case REQ_RANGE_ADJACENT:
|
||
|
fc_strlcat(buf, prefix, bufsz);
|
||
|
if (preq->present) {
|
||
|
fc_strlcat(buf, _("May only be adjacent to this other continent "
|
||
|
"or ocean."),
|
||
|
bufsz);
|
||
|
} else {
|
||
|
fc_strlcat(buf, _("Must be adjacent to more than just this "
|
||
|
"other continent or ocean."),
|
||
|
bufsz);
|
||
|
}
|
||
|
return TRUE;
|
||
|
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_TILE:
|
||
|
case REQ_RANGE_COUNT:
|
||
|
/* Not supported. */
|
||
|
break;
|
||
|
}
|
||
|
break;
|
||
|
case TREL_COUNT:
|
||
|
/* Invalid. */
|
||
|
break;
|
||
|
}
|
||
|
break;
|
||
|
case VUT_COUNT:
|
||
|
break;
|
||
|
}
|
||
| common/requirements.c | ||
|---|---|---|
|
return;
|
||
|
}
|
||
|
break;
|
||
|
case VUT_TILE_REL:
|
||
|
source->value.tilerel = tilerel_type_by_name(value, fc_strcasecmp);
|
||
|
if (source->value.tilerel != TREL_COUNT) {
|
||
|
return;
|
||
|
}
|
||
|
break;
|
||
|
case VUT_COUNT:
|
||
|
break;
|
||
|
}
|
||
| ... | ... | |
|
case VUT_MAX_REGION_TILES:
|
||
|
source.value.region_tiles = value;
|
||
|
return source;
|
||
|
case VUT_TILE_REL:
|
||
|
source.value.tilerel = value;
|
||
|
return source;
|
||
|
case VUT_COUNT:
|
||
|
break;
|
||
|
}
|
||
| ... | ... | |
|
return source->value.distance_sq;
|
||
|
case VUT_MAX_REGION_TILES:
|
||
|
return source->value.region_tiles;
|
||
|
case VUT_TILE_REL:
|
||
|
return source->value.tilerel;
|
||
|
case VUT_COUNT:
|
||
|
break;
|
||
|
}
|
||
| ... | ... | |
|
case VUT_MAX_REGION_TILES:
|
||
|
req.range = REQ_RANGE_CONTINENT;
|
||
|
break;
|
||
|
case VUT_TILE_REL:
|
||
|
req.range = REQ_RANGE_TILE;
|
||
|
if (req.source.value.tilerel == TREL_ONLY_OTHER_REGION) {
|
||
|
/* Not available at Tile range */
|
||
|
req.range = REQ_RANGE_ADJACENT;
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
| ... | ... | |
|
&& req.range != REQ_RANGE_CADJACENT
|
||
|
&& req.range != REQ_RANGE_ADJACENT);
|
||
|
break;
|
||
|
case VUT_TILE_REL:
|
||
|
invalid = (req.range != REQ_RANGE_ADJACENT
|
||
|
&& req.range != REQ_RANGE_CADJACENT
|
||
|
&& req.range != REQ_RANGE_TILE)
|
||
|
/* TREL_ONLY_OTHER_REGION not supported at Tile range */
|
||
|
|| (req.source.value.tilerel == TREL_ONLY_OTHER_REGION
|
||
|
&& req.range == REQ_RANGE_TILE);
|
||
|
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_MAXLATITUDE:
|
||
|
case VUT_MAX_DISTANCE_SQ:
|
||
|
case VUT_MAX_REGION_TILES:
|
||
|
case VUT_TILE_REL:
|
||
|
/* Most requirements don't support 'survives'. */
|
||
|
invalid = survives;
|
||
|
break;
|
||
| ... | ... | |
|
}
|
||
|
}
|
||
|
/**********************************************************************//**
|
||
|
Determine whether a tile relationship 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 tile relationship requirement
|
||
|
**************************************************************************/
|
||
|
static enum fc_tristate
|
||
|
is_tile_rel_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_TILE_REL);
|
||
|
if (context->tile == nullptr || other_context->tile == nullptr) {
|
||
|
/* Note: For some values, we might be able to give a definitive
|
||
|
* TRI_NO answer even if one of the tiles is missing, but that's
|
||
|
* probably not worth the added effort. */
|
||
|
return TRI_MAYBE;
|
||
|
}
|
||
|
switch (req->source.value.tilerel) {
|
||
|
case TREL_SAME_REGION:
|
||
|
if (tile_continent(other_context->tile) == 0) {
|
||
|
return TRI_MAYBE;
|
||
|
}
|
||
|
fc_assert_ret_val_msg((req->range == REQ_RANGE_TILE
|
||
|
|| req->range == REQ_RANGE_CADJACENT
|
||
|
|| req->range == REQ_RANGE_ADJACENT),
|
||
|
TRI_MAYBE,
|
||
|
"Invalid range %d for tile relation \"%s\" req",
|
||
|
req->range, tilerel_type_name(TREL_SAME_REGION));
|
||
|
if (tile_continent(context->tile)
|
||
|
== tile_continent(other_context->tile)) {
|
||
|
return TRI_YES;
|
||
|
} else {
|
||
|
bool seen_unknown = (tile_continent(context->tile) == 0);
|
||
|
Continent_id cont = tile_continent(other_context->tile);
|
||
|
range_adjc_iterate(nmap, context->tile, req->range, adj_tile) {
|
||
|
Continent_id adj_cont = tile_continent(adj_tile);
|
||
|
if (adj_cont == cont) {
|
||
|
return TRI_YES;
|
||
|
} else if (adj_cont == 0) {
|
||
|
seen_unknown = TRUE;
|
||
|
}
|
||
|
} range_adjc_iterate_end;
|
||
|
if (seen_unknown) {
|
||
|
return TRI_MAYBE;
|
||
|
} else {
|
||
|
return TRI_NO;
|
||
|
}
|
||
|
}
|
||
|
break;
|
||
|
case TREL_ONLY_OTHER_REGION:
|
||
|
if (tile_continent(context->tile) == 0
|
||
|
|| tile_continent(other_context->tile) == 0) {
|
||
|
/* Note: We could still give a definitive TRI_NO answer if there are
|
||
|
* too many different adjacent continents, but that's probably not
|
||
|
* worth the added effort. */
|
||
|
return TRI_MAYBE;
|
||
|
}
|
||
|
fc_assert_ret_val_msg((req->range == REQ_RANGE_CADJACENT
|
||
|
|| req->range == REQ_RANGE_ADJACENT),
|
||
|
TRI_MAYBE,
|
||
|
"Invalid range %d for tile relation \"%s\" req",
|
||
|
req->range,
|
||
|
tilerel_type_name(TREL_ONLY_OTHER_REGION));
|
||
|
{
|
||
|
bool seen_unknown = FALSE;
|
||
|
Continent_id cont = tile_continent(context->tile);
|
||
|
Continent_id other_cont = tile_continent(other_context->tile);
|
||
|
range_adjc_iterate(nmap, context->tile, req->range, adj_tile) {
|
||
|
Continent_id adj_cont = tile_continent(adj_tile);
|
||
|
if (adj_cont == 0) {
|
||
|
seen_unknown = TRUE;
|
||
|
} else if (adj_cont != cont && adj_cont != other_cont) {
|
||
|
return TRI_NO;
|
||
|
}
|
||
|
} range_adjc_iterate_end;
|
||
|
if (seen_unknown) {
|
||
|
return TRI_MAYBE;
|
||
|
} else {
|
||
|
return TRI_YES;
|
||
|
}
|
||
|
}
|
||
|
break;
|
||
|
default:
|
||
|
break;
|
||
|
}
|
||
|
fc_assert_msg(FALSE,
|
||
|
"Illegal value %d for tile relationship requirement.",
|
||
|
req->source.value.tilerel);
|
||
|
return TRI_MAYBE;
|
||
|
}
|
||
|
/**********************************************************************//**
|
||
|
Is center of given city in tile. If city is NULL, any city will do.
|
||
|
**************************************************************************/
|
||
| ... | ... | |
|
[VUT_TERRAINALTER] = {is_terrainalter_req_active, REQUCH_NO},
|
||
|
[VUT_TERRAINCLASS] = {is_terrainclass_req_active, REQUCH_NO},
|
||
|
[VUT_TERRFLAG] = {is_terrainflag_req_active, REQUCH_NO},
|
||
|
[VUT_TILE_REL] = {is_tile_rel_req_active, REQUCH_NO},
|
||
|
[VUT_TOPO] = {is_topology_req_active, REQUCH_YES},
|
||
|
[VUT_WRAP] = {is_wrap_req_active, REQUCH_YES},
|
||
|
[VUT_UCFLAG] = {is_unitclassflag_req_active, REQUCH_YES},
|
||
| ... | ... | |
|
case VUT_MINYEAR:
|
||
|
case VUT_MAX_DISTANCE_SQ:
|
||
|
case VUT_MAX_REGION_TILES:
|
||
|
case VUT_TILE_REL:
|
||
|
case VUT_NONE:
|
||
|
case VUT_COUNT:
|
||
|
/* Not implemented. */
|
||
| ... | ... | |
|
return psource1->value.citytile == psource2->value.citytile;
|
||
|
case VUT_CITYSTATUS:
|
||
|
return psource1->value.citystatus == psource2->value.citystatus;
|
||
|
case VUT_TILE_REL:
|
||
|
return psource1->value.tilerel == psource2->value.tilerel;
|
||
|
case VUT_MINLATITUDE:
|
||
|
case VUT_MAXLATITUDE:
|
||
|
return psource1->value.latitude == psource2->value.latitude;
|
||
| ... | ... | |
|
return citytile_type_name(psource->value.citytile);
|
||
|
case VUT_CITYSTATUS:
|
||
|
return citystatus_type_name(psource->value.citystatus);
|
||
|
case VUT_TILE_REL:
|
||
|
return tilerel_type_name(psource->value.tilerel);
|
||
|
case VUT_MINYEAR:
|
||
|
fc_snprintf(buffer, sizeof(buffer), "%d", psource->value.minyear);
|
||
| ... | ... | |
|
break;
|
||
|
}
|
||
|
return buf;
|
||
|
case VUT_TILE_REL:
|
||
|
switch (psource->value.tilerel) {
|
||
|
case TREL_SAME_REGION:
|
||
|
fc_strlcat(buf, _("Same continent/ocean"), bufsz);
|
||
|
break;
|
||
|
case TREL_ONLY_OTHER_REGION:
|
||
|
fc_strlcat(buf, _("Only other continent/ocean"), bufsz);
|
||
|
break;
|
||
|
case TREL_COUNT:
|
||
|
fc_assert(psource->value.tilerel != TREL_COUNT);
|
||
|
fc_strlcat(buf, "error", bufsz);
|
||
|
break;
|
||
|
}
|
||
|
return buf;
|
||
|
case VUT_MINLATITUDE:
|
||
|
/* TRANS: here >= means 'greater than or equal'. */
|
||
|
cat_snprintf(buf, bufsz, _("Latitude >= %d"),
|
||
| doc/README.effects | ||
|---|---|---|
|
MinMoveFrags: Local
|
||
|
MinVeteran: Local
|
||
|
MinHitPoints: Local
|
||
|
TileRel: Tile, Adjacent, CAdjacent
|
||
|
MaxDistanceSq: Tile
|
||
|
MaxRegionTiles: Continent, Adjacent, CAdjacent
|
||
| ... | ... | |
|
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).
|
||
|
TileRel is about the relation to a specific other tile; currently only available
|
||
|
for action enablers (see also README.actions) and a select few effects. It is
|
||
|
one of "Same Region" (on or adjacent to the same continent/ocean as the other
|
||
|
tile, depending on range) or "Only Other Region" (only adjacent to tiles of its
|
||
|
own or the other tile's continent/ocean, not a third one; not available at Tile
|
||
|
range).
|
||
|
MaxDistanceSq is about the (squared) distance between two tiles; currently
|
||
|
only available for action enablers (see also README.actions) and a select
|
||
|
few effects.
|
||
| gen_headers/enums/fc_types_enums.def | ||
|---|---|---|
|
MINCITIES "MinCities"
|
||
|
MAX_DISTANCE_SQ "MaxDistanceSq"
|
||
|
MAX_REGION_TILES "MaxRegionTiles"
|
||
|
TILE_REL "TileRel"
|
||
|
end
|
||
|
/* TileRel requirement types.
|
||
|
* Used in the network protocol */
|
||
|
enum tilerel_type
|
||
|
prefix TREL_
|
||
|
count
|
||
|
values
|
||
|
SAME_REGION "Same Region"
|
||
|
ONLY_OTHER_REGION "Only Other Region"
|
||
|
end
|
||
| server/cityturn.c | ||
|---|---|---|
|
case VUT_OTYPE:
|
||
|
case VUT_SPECIALIST:
|
||
|
case VUT_MAX_DISTANCE_SQ:
|
||
|
case VUT_TILE_REL:
|
||
|
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_GOOD:
|
||
|
case VUT_UTYPE:
|
||
|
case VUT_UCLASS:
|
||
|
case VUT_TILE_REL:
|
||
|
/* Can check different properties. */
|
||
|
case VUT_UTFLAG:
|
||
|
case VUT_UCFLAG:
|
||
| tools/ruledit/univ_value.c | ||
|---|---|---|
|
case VUT_MAX_REGION_TILES:
|
||
|
src->value.region_tiles = 0;
|
||
|
return TRUE;
|
||
|
case VUT_TILE_REL:
|
||
|
src->value.tilerel = TREL_SAME_REGION;
|
||
|
return TRUE;
|
||
|
case VUT_COUNT:
|
||
|
fc_assert(src->kind != VUT_COUNT);
|
||
|
return FALSE;
|
||
| ... | ... | |
|
cb(citystatus_type_name(i), univ->value.citystatus == i, data);
|
||
|
}
|
||
|
break;
|
||
|
case VUT_TILE_REL:
|
||
|
for (i = 0; i < TREL_COUNT; i++) {
|
||
|
cb(tilerel_type_name(i), univ->value.tilerel == i, data);
|
||
|
}
|
||
|
break;
|
||
|
case VUT_ACHIEVEMENT:
|
||
|
achievements_re_active_iterate(pach) {
|
||
|
cb(achievement_rule_name(pach), univ->value.achievement == pach, data);
|
||