From eb4b756b55d5da875815cb2ae6467aba593d20dd Mon Sep 17 00:00:00 2001 From: Alina Lenk Date: Tue, 15 Feb 2022 00:26:15 +0100 Subject: [PATCH 5/5] Allow extras as targets for local-ranged requirements See osdn #43808 Signed-off-by: Alina Lenk --- common/metaknowledge.c | 15 ++++++++ common/reqtext.c | 47 +++++++++++++++++++++-- common/requirements.c | 87 +++++++++++++++++++++++++++++------------- common/requirements.h | 1 + doc/README.effects | 6 +-- server/rssanity.c | 25 +++++++++++- 6 files changed, 146 insertions(+), 35 deletions(-) diff --git a/common/metaknowledge.c b/common/metaknowledge.c index 84026fdf15..a5225027c2 100644 --- a/common/metaknowledge.c +++ b/common/metaknowledge.c @@ -567,6 +567,21 @@ static bool is_req_knowable(const struct player *pov_player, } } + if (req->source.kind == VUT_EXTRA + || req->source.kind == VUT_EXTRAFLAG + || req->source.kind == VUT_ROADFLAG) { + if (req->range == REQ_RANGE_LOCAL) { + if (context->extra == NULL) { + /* The extra may exist but not be passed when the problem type is + * RPT_POSSIBLE. */ + return prob_type == RPT_CERTAIN; + } + /* The extra is given; we can figure out whether it matches. */ + return TRUE; + } + /* Other ranges handled below */ + } + if (req->source.kind == VUT_TERRAIN || req->source.kind == VUT_TERRFLAG || req->source.kind == VUT_TERRAINCLASS diff --git a/common/reqtext.c b/common/reqtext.c index d8d5341a20..a9ff2b9994 100644 --- a/common/reqtext.c +++ b/common/reqtext.c @@ -773,6 +773,18 @@ bool req_text_insert(char *buf, size_t bufsz, struct player *pplayer, case VUT_EXTRA: switch (preq->range) { + case REQ_RANGE_LOCAL: + fc_strlcat(buf, prefix, bufsz); + if (preq->present) { + cat_snprintf(buf, bufsz, + _("Only applies to \"%s\" extras."), + extra_name_translation(preq->source.value.extra)); + } else { + cat_snprintf(buf, bufsz, + _("Does not apply to \"%s\" extras."), + extra_name_translation(preq->source.value.extra)); + } + return TRUE; case REQ_RANGE_TILE: fc_strlcat(buf, prefix, bufsz); if (preq->present) { @@ -846,7 +858,6 @@ bool req_text_insert(char *buf, size_t bufsz, struct player *pplayer, case REQ_RANGE_TEAM: case REQ_RANGE_ALLIANCE: case REQ_RANGE_WORLD: - case REQ_RANGE_LOCAL: case REQ_RANGE_COUNT: /* Not supported. */ break; @@ -2418,6 +2429,22 @@ bool req_text_insert(char *buf, size_t bufsz, struct player *pplayer, case VUT_ROADFLAG: switch (preq->range) { + case REQ_RANGE_LOCAL: + fc_strlcat(buf, prefix, bufsz); + if (preq->present) { + cat_snprintf(buf, bufsz, + /* TRANS: %s is a (translatable) road flag. */ + _("Only applies to roads with the \"%s\" flag."), + road_flag_id_translated_name + (preq->source.value.roadflag)); + } else { + cat_snprintf(buf, bufsz, + /* TRANS: %s is a (translatable) road flag. */ + _("Does not apply to roads with the \"%s\" flag."), + road_flag_id_translated_name + (preq->source.value.roadflag)); + } + return TRUE; case REQ_RANGE_TILE: fc_strlcat(buf, prefix, bufsz); if (preq->present) { @@ -2504,7 +2531,6 @@ bool req_text_insert(char *buf, size_t bufsz, struct player *pplayer, case REQ_RANGE_TEAM: case REQ_RANGE_ALLIANCE: case REQ_RANGE_WORLD: - case REQ_RANGE_LOCAL: case REQ_RANGE_COUNT: /* Not supported. */ break; @@ -2513,6 +2539,22 @@ bool req_text_insert(char *buf, size_t bufsz, struct player *pplayer, case VUT_EXTRAFLAG: switch (preq->range) { + case REQ_RANGE_LOCAL: + fc_strlcat(buf, prefix, bufsz); + if (preq->present) { + cat_snprintf(buf, bufsz, + /* TRANS: %s is a (translatable) extra flag. */ + _("Only applies to extras with the \"%s\" flag."), + extra_flag_id_translated_name + (preq->source.value.extraflag)); + } else { + cat_snprintf(buf, bufsz, + /* TRANS: %s is a (translatable) extra flag. */ + _("Does not apply to extras with the \"%s\" flag."), + extra_flag_id_translated_name + (preq->source.value.extraflag)); + } + return TRUE; case REQ_RANGE_TILE: fc_strlcat(buf, prefix, bufsz); if (preq->present) { @@ -2599,7 +2641,6 @@ bool req_text_insert(char *buf, size_t bufsz, struct player *pplayer, case REQ_RANGE_TEAM: case REQ_RANGE_ALLIANCE: case REQ_RANGE_WORLD: - case REQ_RANGE_LOCAL: case REQ_RANGE_COUNT: /* Not supported. */ break; diff --git a/common/requirements.c b/common/requirements.c index 3b40d7d49f..0329815e57 100644 --- a/common/requirements.c +++ b/common/requirements.c @@ -790,11 +790,14 @@ struct requirement req_from_str(const char *type, const char *range, req.range = REQ_RANGE_LOCAL; break; case VUT_EXTRA: + case VUT_ROADFLAG: + case VUT_EXTRAFLAG: + /* keep old behavior */ + req.range = REQ_RANGE_TILE; + break; case VUT_TERRAIN: case VUT_TERRFLAG: case VUT_TERRAINCLASS: - case VUT_ROADFLAG: - case VUT_EXTRAFLAG: case VUT_TERRAINALTER: case VUT_CITYTILE: case VUT_MAXTILEUNITS: @@ -841,17 +844,19 @@ struct requirement req_from_str(const char *type, const char *range, * might not have been loaded yet. */ switch (req.source.kind) { case VUT_TERRAIN: - case VUT_EXTRA: case VUT_TERRAINCLASS: case VUT_TERRFLAG: - case VUT_ROADFLAG: - case VUT_EXTRAFLAG: invalid = (req.range != REQ_RANGE_TILE && req.range != REQ_RANGE_CADJACENT && req.range != REQ_RANGE_ADJACENT && req.range != REQ_RANGE_CITY && req.range != REQ_RANGE_TRADEROUTE); break; + case VUT_EXTRA: + case VUT_ROADFLAG: + case VUT_EXTRAFLAG: + invalid = (req.range > REQ_RANGE_TRADEROUTE); + break; case VUT_ADVANCE: case VUT_TECHFLAG: case VUT_ACHIEVEMENT: @@ -1885,12 +1890,19 @@ is_tile_units_in_range(const struct tile *target_tile, enum req_range range, /**********************************************************************//** Is there a source extra type within range of the target? **************************************************************************/ -static enum fc_tristate is_extra_type_in_range(const struct tile *target_tile, - const struct city *target_city, - enum req_range range, bool survives, - struct extra_type *pextra) +static enum fc_tristate +is_extra_type_in_range(const struct extra_type *target_extra, + const struct tile *target_tile, + const struct city *target_city, + enum req_range range, bool survives, + struct extra_type *pextra) { switch (range) { + case REQ_RANGE_LOCAL: + if (!target_extra) { + return TRI_MAYBE; + } + return BOOL_TO_TRISTATE(target_extra == pextra); case REQ_RANGE_TILE: /* The requirement is filled if the tile has extra of requested type. */ if (!target_tile) { @@ -1948,7 +1960,6 @@ static enum fc_tristate is_extra_type_in_range(const struct tile *target_tile, case REQ_RANGE_TEAM: case REQ_RANGE_ALLIANCE: case REQ_RANGE_WORLD: - case REQ_RANGE_LOCAL: case REQ_RANGE_COUNT: break; } @@ -2239,12 +2250,24 @@ static enum fc_tristate is_terrainflag_in_range(const struct tile *target_tile, /**********************************************************************//** Is there a road with the given flag within range of the target? **************************************************************************/ -static enum fc_tristate is_roadflag_in_range(const struct tile *target_tile, - const struct city *target_city, - enum req_range range, bool survives, - enum road_flag_id roadflag) +static enum fc_tristate +is_roadflag_in_range(const struct extra_type *target_extra, + const struct tile *target_tile, + const struct city *target_city, + enum req_range range, bool survives, + enum road_flag_id roadflag) { switch (range) { + case REQ_RANGE_LOCAL: + { + if (!target_extra) { + return TRI_MAYBE; + } + struct road_type *r = extra_road_get(target_extra); + return BOOL_TO_TRISTATE( + r && road_has_flag(r, roadflag) + ); + } case REQ_RANGE_TILE: /* The requirement is filled if the tile has a road with correct flag. */ if (!target_tile) { @@ -2301,7 +2324,6 @@ static enum fc_tristate is_roadflag_in_range(const struct tile *target_tile, case REQ_RANGE_TEAM: case REQ_RANGE_ALLIANCE: case REQ_RANGE_WORLD: - case REQ_RANGE_LOCAL: case REQ_RANGE_COUNT: break; } @@ -2314,12 +2336,19 @@ static enum fc_tristate is_roadflag_in_range(const struct tile *target_tile, /**********************************************************************//** Is there an extra with the given flag within range of the target? **************************************************************************/ -static enum fc_tristate is_extraflag_in_range(const struct tile *target_tile, - const struct city *target_city, - enum req_range range, bool survives, - enum extra_flag_id extraflag) +static enum fc_tristate +is_extraflag_in_range(const struct extra_type *target_extra, + const struct tile *target_tile, + const struct city *target_city, + enum req_range range, bool survives, + enum extra_flag_id extraflag) { switch (range) { + case REQ_RANGE_LOCAL: + if (!target_extra) { + return TRI_MAYBE; + } + return BOOL_TO_TRISTATE(extra_has_flag(target_extra, extraflag)); case REQ_RANGE_TILE: /* The requirement is filled if the tile has an extra with correct flag. */ if (!target_tile) { @@ -2376,7 +2405,6 @@ static enum fc_tristate is_extraflag_in_range(const struct tile *target_tile, case REQ_RANGE_TEAM: case REQ_RANGE_ALLIANCE: case REQ_RANGE_WORLD: - case REQ_RANGE_LOCAL: case REQ_RANGE_COUNT: break; } @@ -3258,7 +3286,8 @@ bool is_req_active(const struct req_context *context, : TRI_MAYBE); break; case VUT_EXTRA: - eval = is_extra_type_in_range(context->tile, context->city, + eval = is_extra_type_in_range(context->extra, + context->tile, context->city, req->range, req->survives, req->source.value.extra); break; @@ -3510,12 +3539,14 @@ bool is_req_active(const struct req_context *context, req->source.value.terrainclass); break; case VUT_ROADFLAG: - eval = is_roadflag_in_range(context->tile, context->city, - req->range, req->survives, - req->source.value.roadflag); + eval = is_roadflag_in_range(context->extra, + context->tile, context->city, + req->range, req->survives, + req->source.value.roadflag); break; case VUT_EXTRAFLAG: - eval = is_extraflag_in_range(context->tile, context->city, + eval = is_extraflag_in_range(context->extra, + context->tile, context->city, req->range, req->survives, req->source.value.extraflag); break; @@ -3659,10 +3690,12 @@ bool is_req_unchanging(const struct requirement *req) case VUT_MINMOVES: case VUT_MINHP: case VUT_AGE: - case VUT_ROADFLAG: - case VUT_EXTRAFLAG: case VUT_MINCALFRAG: /* cyclically available */ return FALSE; + case VUT_ROADFLAG: + case VUT_EXTRAFLAG: + /* FIXME: These should probably be treated the same as VUT_EXTRA */ + return req->range == REQ_RANGE_LOCAL; case VUT_TERRAIN: case VUT_EXTRA: case VUT_GOOD: diff --git a/common/requirements.h b/common/requirements.h index 71468abea7..c395fa6c11 100644 --- a/common/requirements.h +++ b/common/requirements.h @@ -101,6 +101,7 @@ struct req_context { const struct unit *unit; const struct unit_type *unittype; const struct impr_type *building; + const struct extra_type *extra; const struct output_type *output; const struct specialist *specialist; const struct action *action; diff --git a/doc/README.effects b/doc/README.effects index 8290101939..174a43bad8 100644 --- a/doc/README.effects +++ b/doc/README.effects @@ -57,9 +57,9 @@ Achievement: World, Alliance, Team, Player Gov: Player Building: World, Alliance, Team, Player, Continent, Traderoute, City, Local BuildingGenus: Local -Extra: Tile, Adjacent, CAdjacent, Traderoute, City -RoadFlag: Tile, Adjacent, CAdjacent, Traderoute, City -ExtraFlag: Tile, Adjacent, CAdjacent, Traderoute, City +Extra: Local, 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 Good: City UnitType: Local diff --git a/server/rssanity.c b/server/rssanity.c index 04bb71de00..2969c34548 100644 --- a/server/rssanity.c +++ b/server/rssanity.c @@ -227,7 +227,9 @@ static bool sanity_check_req_individual(struct requirement *preq, /**********************************************************************//** Helper function for sanity_check_req_list() and sanity_check_req_vec() **************************************************************************/ -static bool sanity_check_req_set(int reqs_of_type[], int tile_reqs_of_type[], +static bool sanity_check_req_set(int reqs_of_type[], + int local_reqs_of_type[], + int tile_reqs_of_type[], struct requirement *preq, bool conjunctive, int max_tiles, const char *list_for) { @@ -251,6 +253,23 @@ static bool sanity_check_req_set(int reqs_of_type[], int tile_reqs_of_type[], } rc = reqs_of_type[preq->source.kind]; + if (preq->range == REQ_RANGE_LOCAL && preq->present) { + local_reqs_of_type[preq->source.kind]++; + + switch (preq->source.kind) { + case VUT_EXTRA: + if (local_reqs_of_type[VUT_EXTRA] > 1) { + log_error("%s: Requirement list has multiple local-ranged extra" + " requirements (did you mean to make them tile-ranged?)", + list_for); + return FALSE; + } + break; + default: + break; + } + } + if (preq->range == REQ_RANGE_TILE && preq->present) { tile_reqs_of_type[preq->source.kind]++; @@ -416,6 +435,7 @@ static bool sanity_check_req_vec(const struct requirement_vector *preqs, { struct req_vec_problem *problem; int reqs_of_type[VUT_COUNT]; + int local_reqs_of_type[VUT_COUNT]; int tile_reqs_of_type[VUT_COUNT]; /* Initialize requirement counters */ @@ -423,7 +443,8 @@ static bool sanity_check_req_vec(const struct requirement_vector *preqs, memset(tile_reqs_of_type, 0, sizeof(tile_reqs_of_type)); requirement_vector_iterate(preqs, preq) { - if (!sanity_check_req_set(reqs_of_type, tile_reqs_of_type, preq, + if (!sanity_check_req_set(reqs_of_type, local_reqs_of_type, + tile_reqs_of_type, preq, conjunctive, max_tiles, list_for)) { return FALSE; } -- 2.17.1