From 71d080dbba699fa25e4339e6c330847112717607 Mon Sep 17 00:00:00 2001 From: Ihnatus Date: Mon, 17 Oct 2022 23:47:35 +0300 Subject: [PATCH] Add continent control to "CityCenter" reqs "Same Continent" checks tile's continent, "Near Same Ocean" checks (obstacle disregarding) ocean connection relative to city center. Correspondingly, changes how "CityCenter" value sometimes works in metaknowledge.c. See OSDN#45907 Signed-off-by: Ihnatus --- common/fc_types.h | 4 ++ common/metaknowledge.c | 17 +++++ common/reqtext.c | 8 +++ common/requirements.c | 142 ++++++++++++++++++++++++++++++++++++++++- doc/README.effects | 19 +++--- 5 files changed, 180 insertions(+), 10 deletions(-) diff --git a/common/fc_types.h b/common/fc_types.h index 57ee66479e..9e0100e610 100644 --- a/common/fc_types.h +++ b/common/fc_types.h @@ -536,6 +536,10 @@ const char *ai_level_name_update_cb(const char *old); #define SPECENUM_VALUE2NAME "Extras Owned" #define SPECENUM_VALUE3 CITYT_WORKED #define SPECENUM_VALUE3NAME "Worked" +#define SPECENUM_VALUE4 CITYT_SAME_CONTINENT +#define SPECENUM_VALUE4NAME "Same Continent" +#define SPECENUM_VALUE5 CITYT_NEAR_SAME_OCEAN +#define SPECENUM_VALUE5NAME "Near Same Ocean" #define SPECENUM_COUNT CITYT_LAST #include "specenum_gen.h" diff --git a/common/metaknowledge.c b/common/metaknowledge.c index 687cf0a041..de4e89f077 100644 --- a/common/metaknowledge.c +++ b/common/metaknowledge.c @@ -358,6 +358,23 @@ static bool is_req_knowable(const struct player *pov_player, * RPT_POSSIBLE. */ return prob_type == RPT_CERTAIN; } + if (context->city == NULL) { + switch (req->source.value.citytile) { + case CITYT_CENTER: + case CITYT_SAME_CONTINENT: + case CITYT_NEAR_SAME_OCEAN: + /* Require the city, not passed */ + return prob_type == RPT_CERTAIN; + case CITYT_CLAIMED: + case CITYT_WORKED: + case CITYT_EXTRAS_OWNED: + /* Do not require a city passed */ + break; + case CITYT_LAST: + /* Invalid */ + return FALSE; + } + } switch (req->range) { case REQ_RANGE_TILE: diff --git a/common/reqtext.c b/common/reqtext.c index a721ce2877..406caa7bf8 100644 --- a/common/reqtext.c +++ b/common/reqtext.c @@ -2883,6 +2883,14 @@ bool req_text_insert(char *buf, size_t bufsz, struct player *pplayer, case CITYT_WORKED: tile_property = _("worked tiles"); break; + case CITYT_SAME_CONTINENT: + /* TRANS: a specific city for each use case */ + tile_property = _("tiles on the same continent as the city"); + break; + case CITYT_NEAR_SAME_OCEAN: + /* TRANS: a specific city for each use case */ + tile_property = _("tiles connected by a body of water to the city"); + break; case CITYT_LAST: fc_assert(preq->source.value.citytile != CITYT_LAST); break; diff --git a/common/requirements.c b/common/requirements.c index e55039613a..1be577ded0 100644 --- a/common/requirements.c +++ b/common/requirements.c @@ -3205,6 +3205,140 @@ static enum fc_tristate is_citytile_in_range(const struct tile *target_tile, break; } + return TRI_MAYBE; + case CITYT_SAME_CONTINENT: + { + int cc; + + if (!target_city) { + return TRI_MAYBE; + } + cc = tile_continent(city_tile(target_city)); + /* Note: No special treatment of 0 == cc here*/ + switch (range) { + case REQ_RANGE_TILE: + return BOOL_TO_TRISTATE(tile_continent(target_tile) == cc); + case REQ_RANGE_CADJACENT: + if (tile_continent(target_tile) == cc) { + return TRI_YES; + } + cardinal_adjc_iterate(&(wld.map), target_tile, adjc_tile) { + if (tile_continent(adjc_tile) == cc) { + return TRI_YES; + } + } cardinal_adjc_iterate_end; + + return TRI_NO; + case REQ_RANGE_ADJACENT: + if (tile_continent(target_tile) == cc) { + return TRI_YES; + } + adjc_iterate(&(wld.map), target_tile, adjc_tile) { + if (tile_continent(adjc_tile) == cc) { + return TRI_YES; + } + } adjc_iterate_end; + + return TRI_NO; + case REQ_RANGE_CITY: + case REQ_RANGE_TRADEROUTE: + 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: + fc_assert_msg(FALSE, "Invalid range %d for citytile.", range); + break; + } + } + + return TRI_MAYBE; + case CITYT_NEAR_SAME_OCEAN: + { + int n = 0, adjc_cont[8]; + + if (!target_city) { + return TRI_MAYBE; + } + adjc_iterate(&(wld.map), city_tile(target_city), adjc_tile) { + int tc = tile_continent(adjc_tile); + + if (tc < 0) { + adjc_cont[n++] = tile_continent(adjc_tile); + } else if (0 == tc) { + /* Likely, it's a black tile in client and we don't know + * We possibly can calculate, but keep it simple */ + return TRI_MAYBE; + } + } adjc_iterate_end; + if (0 == n) { + /* No ocean near the city. But consider Tenochtitlan */ + int cc = tile_continent(city_tile(target_city)); + + if (cc < 0) { + adjc_cont[0] = cc; + n = 1; + } else { + /* If we have a city but no continent for it, + * supposedly we don't really know anything */ + return 0 == cc ? TRI_MAYBE : TRI_NO; + } + } + fc_assert(n <= 4); /* More oceans around one tile is likely a bug */ + switch (range) { + case REQ_RANGE_TILE: + case REQ_RANGE_ADJACENT: + square_iterate(&(wld.map), target_tile, + range == REQ_RANGE_TILE ? 1 : 2, adjc_tile) { + int tc = tile_continent(adjc_tile); + + if (tc > 0) { + continue; + } else if (0 == tc) { + return TRI_MAYBE; + } + for (int i = 0; i < n; i++) { + if (tc == adjc_cont[i]) { + return TRI_YES; + } + } + } square_iterate_end; + + return TRI_NO; + case REQ_RANGE_CADJACENT: + /* Do the same in a 5x5 square without corners (adjc of cadjc) */ + circle_iterate(&(wld.map), target_tile, 5, adjc_tile) { + int tc = tile_continent(adjc_tile); + + if (tc > 0) { + continue; + } else if (0 == tc) { + return TRI_MAYBE; + } + for (int i = 0; i < n; i++) { + if (tc == adjc_cont[i]) { + return TRI_YES; + } + } + } circle_iterate_end; + + return TRI_NO; + case REQ_RANGE_CITY: + case REQ_RANGE_TRADEROUTE: + 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: + fc_assert_msg(FALSE, "Invalid range %d for citytile.", range); + break; + } + } + return TRI_MAYBE; case CITYT_LAST: /* Handled below */ @@ -3975,7 +4109,7 @@ bool is_req_unchanging(const struct requirement *req) case VUT_OTYPE: case VUT_SPECIALIST: /* Only so long as it's at local range only */ case VUT_AI_LEVEL: - case VUT_CITYTILE: + case VUT_CITYTILE: /* FIXME: actually, some terrain alterations are easy */ case VUT_CITYSTATUS: /* We don't *want* owner of our city to change */ case VUT_STYLE: case VUT_TOPO: @@ -5204,6 +5338,12 @@ const char *universal_name_translation(const struct universal *psource, case CITYT_WORKED: fc_strlcat(buf, _("Worked tile"), bufsz); break; + case CITYT_SAME_CONTINENT: + fc_strlcat(buf, _("Tile on the same continent"), bufsz); + break; + case CITYT_NEAR_SAME_OCEAN: + fc_strlcat(buf, _("Tile connected by a body of water"), bufsz); + break; case CITYT_LAST: fc_assert(psource->value.citytile != CITYT_LAST); fc_strlcat(buf, "error", bufsz); diff --git a/doc/README.effects b/doc/README.effects index 836f46cbf0..019f4a92a2 100644 --- a/doc/README.effects +++ b/doc/README.effects @@ -111,26 +111,27 @@ MinSize is the minimum size of a city required. AI is ai player difficulty level. TerrainClass is either "Land" or "Oceanic". TerrainAlter is "CanIrrigate", "CanMine", "CanRoad", "CanBase", or "CanPlace" -CityTile is "Center" (city center), "Claimed" (tile owned), -"Extras Owned" (extra on tile owned), or "Worked" (worked by any city) +CityTile is "Center" (city center), "Claimed" (tile owned by any city), + "Extras Owned" (extra on tile owned), "Worked" (worked by any city), + "Same Continent" or "Near Same Ocean" (as the city center). MinLatitude and MaxLatitude are numbers from -1000 (south pole) to 1000 -(north pole). + (north pole). CityStatus is "OwnedByOriginal", "Starved", "Disorder", or "Celebration" DiplRel is a diplomatic relationship. MaxUnitsOnTile is about the number of units present on a tile. UnitState is "Transported", "Transporting", "OnNativeTile", "OnLivableTile", -"InNativeExtra", "MovedThisTurn" or "HasHomeCity". + "InNativeExtra", "MovedThisTurn" or "HasHomeCity". Activity is "Idle", "Pollution", "Mine", "Irrigate", "Fortified", -"Pillage", "Transform", "Fortifying", "Fallout", -"Base", "Road", "Convert", "Cultivate", or "Plant". + "Pillage", "Transform", "Fortifying", "Fallout", + "Base", "Road", "Convert", "Cultivate", or "Plant". MinMoveFrags is the minimum move fragments the unit must have left. MinCalFrag is the minimum sub-year division the calendar must have reached, -if enabled (see [calendar].fragments in game.ruleset). + if enabled (see [calendar].fragments in game.ruleset). Nationality is fulfilled by any citizens of the given nationality -present in the city. + present in the city. OriginalOwner is the city founding nation ServerSetting is if a Boolean server setting is enabled. The setting must be -visible to all players and affect the game rules. + visible to all players and affect the game rules. Effect types ============ -- 2.34.1