Project

General

Profile

Feature #1732 ยป 0036-Add-tiledef-requirement-type.patch

Marko Lindqvist, 11/15/2025 05:42 AM

View differences:

ai/default/daicity.c
/* Unskilled in channel digging and merchantry */
case VUT_TERRAIN:
case VUT_EXTRA:
case VUT_TILEDEF:
case VUT_GOOD:
case VUT_TERRAINCLASS:
case VUT_TERRFLAG:
ai/default/daieffects.c
case VUT_ROADFLAG:
case VUT_EXTRAFLAG:
case VUT_EXTRA:
case VUT_TILEDEF:
/* TODO: These could be determined by building a map of all
* possible futures (e.g. terrain transformations, etc.),
* and traversing it for all tiles in largest possible range
ai/default/daimilitary.c
case VUT_ROADFLAG:
case VUT_TERRAIN:
case VUT_EXTRA:
case VUT_TILEDEF:
case VUT_GOOD:
case VUT_TERRAINCLASS:
case VUT_TERRFLAG:
common/extras.h
} extra_type_list_iterate_rev_end \
}
/* TODO: Tiledef requirement types */
#define extra_deps_iterate(_reqs, _dep) \
{ \
requirement_vector_iterate(_reqs, preq) { \
common/fc_types.h
struct unit_class *uclass;
const struct unit_type *utype;
struct extra_type *extra;
struct tiledef *tiledef;
struct achievement *achievement;
struct nation_group *nationgroup;
struct nation_style *style;
common/metaknowledge.c
|| req->source.kind == VUT_TERRAINALTER
|| req->source.kind == VUT_EXTRA
|| req->source.kind == VUT_EXTRAFLAG
|| req->source.kind == VUT_ROADFLAG) {
|| req->source.kind == VUT_ROADFLAG
|| req->source.kind == VUT_TILEDEF) {
if (context->tile == nullptr) {
/* The tile may exist but not be passed when the problem type is
* RPT_POSSIBLE. */
common/reqtext.c
#include "server_settings.h"
#include "specialist.h"
#include "terrain.h"
#include "tiledef.h"
#include "reqtext.h"
......
}
break;
case VUT_TILEDEF:
switch (preq->range) {
case REQ_RANGE_LOCAL:
fc_strlcat(buf, prefix, bufsz);
if (preq->present) {
cat_snprintf(buf, bufsz,
_("Only applies to \"%s\" tiledef."),
tiledef_name_translation(preq->source.value.tiledef));
} else {
cat_snprintf(buf, bufsz,
_("Does not apply to \"%s\" tiledef."),
tiledef_name_translation(preq->source.value.tiledef));
}
return TRUE;
case REQ_RANGE_TILE:
fc_strlcat(buf, prefix, bufsz);
if (preq->present) {
cat_snprintf(buf, bufsz,
Q_("?tiledef:Requires %s on the tile."),
tiledef_name_translation(preq->source.value.tiledef));
} else {
cat_snprintf(buf, bufsz,
Q_("?tiledef:Prevented by %s on the tile."),
tiledef_name_translation(preq->source.value.tiledef));
}
return TRUE;
case REQ_RANGE_CADJACENT:
fc_strlcat(buf, prefix, bufsz);
if (preq->present) {
cat_snprintf(buf, bufsz,
Q_("?tiledef:Requires %s on the tile or a cardinally "
"adjacent tile."),
tiledef_name_translation(preq->source.value.tiledef));
} else {
cat_snprintf(buf, bufsz,
Q_("?tiledef:Prevented by %s on the tile or any cardinally "
"adjacent tile."),
tiledef_name_translation(preq->source.value.tiledef));
}
return TRUE;
case REQ_RANGE_ADJACENT:
fc_strlcat(buf, prefix, bufsz);
if (preq->present) {
cat_snprintf(buf, bufsz,
Q_("?tiledef:Requires %s on the tile or an adjacent "
"tile."),
tiledef_name_translation(preq->source.value.tiledef));
} else {
cat_snprintf(buf, bufsz,
Q_("?tiledef:Prevented by %s on the tile or any adjacent "
"tile."),
tiledef_name_translation(preq->source.value.tiledef));
}
return TRUE;
case REQ_RANGE_CITY:
fc_strlcat(buf, prefix, bufsz);
if (preq->present) {
cat_snprintf(buf, bufsz,
Q_("?tiledef:Requires %s on a tile within the city "
"radius."),
tiledef_name_translation(preq->source.value.tiledef));
} else {
cat_snprintf(buf, bufsz,
Q_("?tiledef:Prevented by %s on any tile within the city "
"radius."),
tiledef_name_translation(preq->source.value.tiledef));
}
return TRUE;
case REQ_RANGE_TRADE_ROUTE:
fc_strlcat(buf, prefix, bufsz);
if (preq->present) {
cat_snprintf(buf, bufsz,
Q_("?tiledef:Requires %s on a tile within the city "
"radius, or the city radius of a trade partner."),
tiledef_name_translation(preq->source.value.tiledef));
} else {
cat_snprintf(buf, bufsz,
Q_("?tiledef:Prevented by %s on any tile within the city "
"radius or the city radius of a trade partner."),
tiledef_name_translation(preq->source.value.tiledef));
}
return TRUE;
case REQ_RANGE_CONTINENT:
case REQ_RANGE_PLAYER:
case REQ_RANGE_TEAM:
case REQ_RANGE_ALLIANCE:
case REQ_RANGE_WORLD:
case REQ_RANGE_COUNT:
/* Not supported. */
break;
}
break;
case VUT_GOOD:
switch (preq->range) {
case REQ_RANGE_CITY:
common/requirements.c
#include "server_settings.h"
#include "specialist.h"
#include "style.h"
#include "tiledef.h"
#include "victory.h" /* victory_enabled() */
#include "requirements.h"
......
return;
}
break;
case VUT_TILEDEF:
source->value.tiledef = tiledef_by_rule_name(value);
if (source->value.tiledef != nullptr) {
return;
}
break;
case VUT_GOOD:
source->value.good = goods_by_rule_name(value);
if (source->value.good != nullptr) {
......
case VUT_EXTRA:
source.value.extra = extra_by_number(value);
return source;
case VUT_TILEDEF:
source.value.tiledef = tiledef_by_number(value);
return source;
case VUT_GOOD:
source.value.good = goods_by_number(value);
return source;
......
return source->value.plr_flag;
case VUT_EXTRA:
return extra_number(source->value.extra);
case VUT_TILEDEF:
return tiledef_number(source->value.tiledef);
case VUT_GOOD:
return goods_number(source->value.good);
case VUT_TERRAIN:
......
req.range = REQ_RANGE_LOCAL;
break;
case VUT_EXTRA:
case VUT_TILEDEF:
case VUT_ROADFLAG:
case VUT_EXTRAFLAG:
/* Keep old behavior */
......
case VUT_EXTRAFLAG:
invalid = (req.range > REQ_RANGE_TRADE_ROUTE);
break;
case VUT_TILEDEF:
invalid = (req.range > REQ_RANGE_TRADE_ROUTE
|| req.range == REQ_RANGE_LOCAL);
break;
case VUT_ACHIEVEMENT:
case VUT_MINTECHS:
case VUT_FUTURETECHS:
......
case VUT_ROADFLAG:
case VUT_EXTRAFLAG:
case VUT_EXTRA:
case VUT_TILEDEF:
case VUT_GOOD:
case VUT_TECHFLAG:
case VUT_ACHIEVEMENT:
......
return TRI_MAYBE;
}
/**********************************************************************//**
Determine whether a tiledef 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 tiledef requirement
**************************************************************************/
static enum fc_tristate
is_tiledef_req_active(const struct civ_map *nmap,
const struct req_context *context,
const struct req_context *other_context,
const struct requirement *req)
{
const struct tiledef *ptdef;
enum fc_tristate ret;
IS_REQ_ACTIVE_VARIANT_ASSERT(VUT_TILEDEF);
ptdef = req->source.value.tiledef;
switch (req->range) {
case REQ_RANGE_TILE:
/* The requirement is filled if the tile has tiledef of requested type. */
if (!context->tile) {
return TRI_MAYBE;
}
return BOOL_TO_TRISTATE(tile_matches_tiledef(ptdef, context->tile));
case REQ_RANGE_CADJACENT:
if (!context->tile) {
return TRI_MAYBE;
}
return BOOL_TO_TRISTATE(tile_matches_tiledef(ptdef, context->tile)
|| is_tiledef_card_near(nmap, context->tile, ptdef));
case REQ_RANGE_ADJACENT:
if (!context->tile) {
return TRI_MAYBE;
}
return BOOL_TO_TRISTATE(tile_matches_tiledef(ptdef, context->tile)
|| is_tiledef_near_tile(nmap, context->tile, ptdef));
case REQ_RANGE_CITY:
if (!context->city) {
return TRI_MAYBE;
}
city_tile_iterate(nmap, city_map_radius_sq_get(context->city),
city_tile(context->city), ptile) {
if (tile_matches_tiledef(ptdef, ptile)) {
return TRI_YES;
}
} city_tile_iterate_end;
return TRI_NO;
case REQ_RANGE_TRADE_ROUTE:
if (!context->city) {
return TRI_MAYBE;
}
city_tile_iterate(nmap, city_map_radius_sq_get(context->city),
city_tile(context->city), ptile) {
if (tile_matches_tiledef(ptdef, ptile)) {
return TRI_YES;
}
} city_tile_iterate_end;
ret = TRI_NO;
trade_partners_iterate(context->city, trade_partner) {
if (trade_partner == nullptr) {
ret = TRI_MAYBE;
} else {
city_tile_iterate(nmap, city_map_radius_sq_get(trade_partner),
city_tile(trade_partner), ptile) {
if (tile_matches_tiledef(ptdef, ptile)) {
return TRI_YES;
}
} city_tile_iterate_end;
}
} trade_partners_iterate_end;
return ret;
case REQ_RANGE_LOCAL:
case REQ_RANGE_CONTINENT:
case REQ_RANGE_PLAYER:
case REQ_RANGE_TEAM:
case REQ_RANGE_ALLIANCE:
case REQ_RANGE_WORLD:
case REQ_RANGE_COUNT:
break;
}
fc_assert_msg(FALSE, "Invalid range %d.", req->range);
return TRI_MAYBE;
}
/**********************************************************************//**
Determine whether a goods requirement is satisfied in a given context,
ignoring parts of the requirement that can be handled uniformly for all
......
[VUT_DIPLREL_UNITANY] = {is_diplrel_unitany_req_active, REQUCH_NO},
[VUT_DIPLREL_UNITANY_O] = {is_diplrel_unitany_o_req_active, REQUCH_NO},
[VUT_EXTRA] = {is_extra_req_active, REQUCH_NO, REQUC_LOCAL},
[VUT_TILEDEF] = {is_tiledef_req_active, REQUCH_NO, REQUC_LOCAL},
[VUT_EXTRAFLAG] = {is_extraflag_req_active, REQUCH_NO, REQUC_LOCAL},
[VUT_FUTURETECHS] = {is_futuretechs_req_active, REQUCH_ACT, REQUC_WORLD},
[VUT_GOOD] = {is_good_req_active, REQUCH_NO},
......
case VUT_MINCALFRAG:
case VUT_TERRAIN:
case VUT_EXTRA:
case VUT_TILEDEF:
case VUT_GOOD:
case VUT_TERRAINCLASS:
case VUT_TERRFLAG:
......
return psource1->value.plrstate == psource2->value.plrstate;
case VUT_EXTRA:
return psource1->value.extra == psource2->value.extra;
case VUT_TILEDEF:
return psource1->value.tiledef == psource2->value.tiledef;
case VUT_GOOD:
return psource1->value.good == psource2->value.good;
case VUT_TERRAIN:
......
return plrstate_type_name(psource->value.plrstate);
case VUT_EXTRA:
return extra_rule_name(psource->value.extra);
case VUT_TILEDEF:
return tiledef_rule_name(psource->value.tiledef);
case VUT_GOOD:
return goods_rule_name(psource->value.good);
case VUT_TERRAIN:
......
case VUT_EXTRA:
fc_strlcat(buf, extra_name_translation(psource->value.extra), bufsz);
return buf;
case VUT_TILEDEF:
fc_strlcat(buf, tiledef_name_translation(psource->value.tiledef), bufsz);
return buf;
case VUT_GOOD:
fc_strlcat(buf, goods_name_translation(psource->value.good), bufsz);
return buf;
......
/**********************************************************************//**
Find if an extra type fulfills a requirement
TODO: Handle simple VUT_TILEDEF cases.
**************************************************************************/
static enum req_item_found extra_type_found(const struct requirement *preq,
const struct universal *source)
doc/README.effects
Site: World, Alliance, Team, Player, Continent, Traderoute,
City, Tile, Local
Extra: Local, Tile, Adjacent, CAdjacent, Traderoute, City
Tiledef: Tile, Adjacent, CAdjacent, Traderoute, City
RoadFlag: Local, Tile, Adjacent, CAdjacent, Traderoute, City
ExtraFlag: Local, Tile, Adjacent, CAdjacent, Traderoute, City
Terrain: Tile, Adjacent, CAdjacent, Traderoute, City
gen_headers/enums/fc_types_enums.def
/* More generic terrain type currently "Land" or "Ocean" */
TERRAINCLASS "TerrainClass"
TERRFLAG "TerrainFlag"
TILEDEF "Tiledef"
TILE_REL "TileRel"
TOPO "Topology"
UCFLAG "UnitClassFlag"
server/cityturn.c
#include "server_settings.h"
#include "specialist.h"
#include "tech.h"
#include "tiledef.h"
#include "traderoutes.h"
#include "unit.h"
#include "unitlist.h"
......
pcity, "have_extra");
}
break;
case VUT_TILEDEF:
if (preq->present) {
notify_player(pplayer, city_tile(pcity),
E_CITY_CANTBUILD, ftc_server,
Q_("?tiledef:%s can't build %s from the worklist; "
"%s is required. Postponing..."),
city_link(pcity),
tgt_name,
tiledef_name_translation(preq->source.value.tiledef));
script_server_signal_emit(signal_name, ptarget,
pcity, "need_tiledef");
} else {
notify_player(pplayer, city_tile(pcity),
E_CITY_CANTBUILD, ftc_server,
Q_("?tiledef:%s can't build %s from the worklist; "
"%s is prohibited. Postponing..."),
city_link(pcity),
tgt_name,
tiledef_name_translation(preq->source.value.tiledef));
script_server_signal_emit(signal_name, ptarget,
pcity, "have_tiledef");
}
break;
case VUT_GOOD:
if (preq->present) {
notify_player(pplayer, city_tile(pcity),
server/ruleset/rssanity.c
case VUT_WRAP:
/* Can have multiple, since it's flag based (wrapx & wrapy) */
case VUT_EXTRA:
case VUT_TILEDEF:
/* Note that there can be more than 1 extra / tile. */
case VUT_MAXTILETOTALUNITS:
case VUT_MAXTILETOPUNITS:
tools/ruledit/univ_value.c
#include "server_settings.h"
#include "specialist.h"
#include "tech.h"
#include "tiledef.h"
#include "traderoutes.h"
/* server */
......
}
src->value.extra = extra_by_number(0);
return TRUE;
case VUT_TILEDEF:
if (game.control.num_tiledef_types <= 0) {
return FALSE;
}
src->value.tiledef = tiledef_by_number(0);
return TRUE;
case VUT_TECHFLAG:
src->value.techflag = TF_BONUS_TECH;
return TRUE;
......
cb(extra_rule_name(pextra), univ->value.extra == pextra, data);
} extra_type_re_active_iterate_end;
break;
case VUT_TILEDEF:
tiledef_iterate(ptd) {
cb(tiledef_rule_name(ptd), univ->value.tiledef == ptd, data);
} tiledef_iterate_end;
break;
case VUT_STYLE:
styles_re_active_iterate(pstyle) {
cb(style_rule_name(pstyle), univ->value.style == pstyle, data);
    (1-1/1)