From b36bd2bddd8b360eb0975b3cfd58ec2e9dffde49 Mon Sep 17 00:00:00 2001 From: Sveinung Kvilhaugsvik Date: Fri, 11 Jun 2021 11:50:58 +0200 Subject: [PATCH 13/14] Add the new DiplRelTile requirement type. It is like the DiplRel requirement type except that it is about the owner of the tile. This allows rules like "a unit can only be expelled if it is on a tile owned by someone its owner has peace with". See osdn #42515 --- ai/default/daieffects.c | 1 + common/fc_types.h | 2 + common/metaknowledge.c | 3 +- common/player.c | 6 ++- common/reqtext.c | 76 ++++++++++++++++++++++++++++++++++++++ common/requirements.c | 30 ++++++++++++++- doc/README.effects | 7 ++++ server/cityturn.c | 1 + server/rssanity.c | 1 + tools/ruledit/univ_value.c | 2 + 10 files changed, 125 insertions(+), 4 deletions(-) diff --git a/ai/default/daieffects.c b/ai/default/daieffects.c index 85c04aaafe..2a4b2146e4 100644 --- a/ai/default/daieffects.c +++ b/ai/default/daieffects.c @@ -807,6 +807,7 @@ bool dai_can_requirement_be_met_in_city(const struct requirement *preq, case VUT_UCLASS: case VUT_UCFLAG: case VUT_DIPLREL: + case VUT_DIPLREL_TILE: case VUT_MAXTILEUNITS: case VUT_STYLE: case VUT_UNITSTATE: diff --git a/common/fc_types.h b/common/fc_types.h index 7bfb784718..c18d8b9949 100644 --- a/common/fc_types.h +++ b/common/fc_types.h @@ -737,6 +737,8 @@ typedef union { #define SPECENUM_VALUE43NAME "MinForeignPct" #define SPECENUM_VALUE44 VUT_ACTIVITY #define SPECENUM_VALUE44NAME "Activity" +#define SPECENUM_VALUE45 VUT_DIPLREL_TILE +#define SPECENUM_VALUE45NAME "DiplRelTile" /* Keep this last. */ #define SPECENUM_COUNT VUT_COUNT #include "specenum_gen.h" diff --git a/common/metaknowledge.c b/common/metaknowledge.c index 588adc2482..3909e6115b 100644 --- a/common/metaknowledge.c +++ b/common/metaknowledge.c @@ -272,7 +272,8 @@ static bool is_req_knowable(const struct player *pow_player, return can_player_see_unit(pow_player, target_unit); } - if (req->source.kind == VUT_DIPLREL) { + if (req->source.kind == VUT_DIPLREL + || req->source.kind == VUT_DIPLREL_TILE) { switch (req->range) { case REQ_RANGE_LOCAL: if (other_player == NULL diff --git a/common/player.c b/common/player.c index 2183e4b3fa..8298814600 100644 --- a/common/player.c +++ b/common/player.c @@ -1754,9 +1754,11 @@ bv_diplrel_all_reqs diplrel_req_contradicts(const struct requirement *req) /* Nothing is known to contradict the requirement yet. */ BV_CLR_ALL(known); - if (req->source.kind != VUT_DIPLREL) { + if (!(req->source.kind == VUT_DIPLREL + || req->source.kind == VUT_DIPLREL_TILE)) { /* No known contradiction of a requirement of any other kind. */ - fc_assert(req->source.kind == VUT_DIPLREL); + fc_assert(req->source.kind == VUT_DIPLREL + || req->source.kind == VUT_DIPLREL_TILE); return known; } diff --git a/common/reqtext.c b/common/reqtext.c index 10a38eea1e..d7ad572009 100644 --- a/common/reqtext.c +++ b/common/reqtext.c @@ -1267,6 +1267,82 @@ bool req_text_insert(char *buf, size_t bufsz, struct player *pplayer, } break; + case VUT_DIPLREL_TILE: + switch (preq->range) { + case REQ_RANGE_PLAYER: + fc_strlcat(buf, prefix, bufsz); + if (preq->present) { + cat_snprintf(buf, bufsz, + /* TRANS: in this and following strings, '%s' can be one + * of a wide range of relationships; e.g., 'Peace', + * 'Never met', 'Foreign', 'Hosts embassy', + * 'Provided Casus Belli' */ + _("Requires that the tile owner has the relationship" + " '%s' with at least one other living player."), + diplrel_name_translation(preq->source.value.diplrel)); + } else { + cat_snprintf(buf, bufsz, + _("Requires that the tile owner does not have the" + " relationship '%s' with any living player."), + diplrel_name_translation(preq->source.value.diplrel)); + } + return TRUE; + case REQ_RANGE_TEAM: + fc_strlcat(buf, prefix, bufsz); + if (preq->present) { + cat_snprintf(buf, bufsz, + _("Requires that somebody on the tile owner's team" + " has the relationship '%s' with at least one other" + " living player."), + diplrel_name_translation(preq->source.value.diplrel)); + } else { + cat_snprintf(buf, bufsz, + _("Requires that nobody on the tile owner's team has" + " the relationship '%s' with any living player."), + diplrel_name_translation(preq->source.value.diplrel)); + } + return TRUE; + case REQ_RANGE_ALLIANCE: + fc_strlcat(buf, prefix, bufsz); + if (preq->present) { + cat_snprintf(buf, bufsz, + _("Requires that somebody in the tile owner's alliance" + " has the relationship '%s' with at least one other " + "living player."), + diplrel_name_translation(preq->source.value.diplrel)); + } else { + cat_snprintf(buf, bufsz, + _("Requires that nobody in the tile owner's alliance " + "has the relationship '%s' with any living player."), + diplrel_name_translation(preq->source.value.diplrel)); + } + return TRUE; + case REQ_RANGE_LOCAL: + fc_strlcat(buf, prefix, bufsz); + if (preq->present) { + cat_snprintf(buf, bufsz, + _("Requires that you have the relationship '%s' with" + " the tile owner."), + diplrel_name_translation(preq->source.value.diplrel)); + } else { + cat_snprintf(buf, bufsz, + _("Requires that you do not have the relationship '%s'" + " with the tile owner."), + diplrel_name_translation(preq->source.value.diplrel)); + } + return TRUE; + case REQ_RANGE_CADJACENT: + case REQ_RANGE_ADJACENT: + case REQ_RANGE_CITY: + case REQ_RANGE_TRADEROUTE: + case REQ_RANGE_CONTINENT: + case REQ_RANGE_WORLD: + case REQ_RANGE_COUNT: + /* Not supported. */ + break; + } + break; + case VUT_UTYPE: switch (preq->range) { case REQ_RANGE_LOCAL: diff --git a/common/requirements.c b/common/requirements.c index 5d58d04afa..d7da160b59 100644 --- a/common/requirements.c +++ b/common/requirements.c @@ -193,6 +193,7 @@ void universal_value_from_str(struct universal *source, const char *value) } break; case VUT_DIPLREL: + case VUT_DIPLREL_TILE: source->value.diplrel = diplrel_by_rule_name(value); if (source->value.diplrel != diplrel_other_invalid()) { return; @@ -464,6 +465,7 @@ struct universal universal_by_number(const enum universals_n kind, } break; case VUT_DIPLREL: + case VUT_DIPLREL_TILE: source.value.diplrel = value; if (source.value.diplrel != diplrel_other_invalid()) { return source; @@ -631,6 +633,7 @@ int universal_number(const struct universal *source) case VUT_NATIONALITY: return nation_number(source->value.nationality); case VUT_DIPLREL: + case VUT_DIPLREL_TILE: return source->value.diplrel; case VUT_UTYPE: return utype_number(source->value.utype); @@ -790,6 +793,7 @@ struct requirement req_from_str(const char *type, const char *range, case VUT_NATION: case VUT_NATIONGROUP: case VUT_DIPLREL: + case VUT_DIPLREL_TILE: case VUT_AI_LEVEL: req.range = REQ_RANGE_PLAYER; break; @@ -861,6 +865,15 @@ struct requirement req_from_str(const char *type, const char *range, || (req.source.value.diplrel == DRO_FOREIGN && req.range != REQ_RANGE_LOCAL); break; + case VUT_DIPLREL_TILE: + invalid = (req.range != REQ_RANGE_LOCAL + && req.range != REQ_RANGE_PLAYER + && req.range != REQ_RANGE_TEAM + && req.range != REQ_RANGE_ALLIANCE) + /* Non local foreign makes no sense. */ + || (req.source.value.diplrel == DRO_FOREIGN + && req.range != REQ_RANGE_LOCAL); + break; case VUT_NATION: case VUT_NATIONGROUP: invalid = (req.range != REQ_RANGE_PLAYER @@ -971,6 +984,7 @@ struct requirement req_from_str(const char *type, const char *range, case VUT_NATIONGROUP: case VUT_STYLE: case VUT_DIPLREL: + case VUT_DIPLREL_TILE: case VUT_MAXTILEUNITS: case VUT_MINTECHS: /* Most requirements don't support 'survives'. */ @@ -1193,6 +1207,7 @@ bool are_requirements_contradictions(const struct requirement *req1, return FALSE; break; case VUT_DIPLREL: + case VUT_DIPLREL_TILE: if (req2->source.kind != req1->source.kind) { /* Finding contradictions across requirement kinds aren't supported * for DiplRel requirements. */ @@ -3038,6 +3053,12 @@ bool is_req_active(const struct player *target_player, eval = is_diplrel_in_range(target_player, other_player, req->range, req->source.value.diplrel); break; + case VUT_DIPLREL_TILE: + eval = is_diplrel_in_range(target_tile ? tile_owner(target_tile) : NULL, + target_player, + req->range, + req->source.value.diplrel); + break; case VUT_UTYPE: if (target_unittype == NULL) { eval = TRI_MAYBE; @@ -3365,6 +3386,7 @@ bool is_req_unchanging(const struct requirement *req) case VUT_MINTECHS: case VUT_NATIONALITY: case VUT_DIPLREL: + case VUT_DIPLREL_TILE: case VUT_MAXTILEUNITS: case VUT_UTYPE: /* Not sure about this one */ case VUT_UTFLAG: /* Not sure about this one */ @@ -3474,6 +3496,7 @@ bool universal_never_there(const struct universal *source) case VUT_MINTECHS: case VUT_NATIONALITY: case VUT_DIPLREL: + case VUT_DIPLREL_TILE: case VUT_MAXTILEUNITS: case VUT_UTYPE: case VUT_UCLASS: @@ -4041,6 +4064,7 @@ bool are_universals_equal(const struct universal *psource1, case VUT_NATIONALITY: return psource1->value.nationality == psource2->value.nationality; case VUT_DIPLREL: + case VUT_DIPLREL_TILE: return psource1->value.diplrel == psource2->value.diplrel; case VUT_UTYPE: return psource1->value.utype == psource2->value.utype; @@ -4164,6 +4188,7 @@ const char *universal_rule_name(const struct universal *psource) case VUT_NATIONGROUP: return nation_group_rule_name(psource->value.nationgroup); case VUT_DIPLREL: + case VUT_DIPLREL_TILE: return diplrel_rule_name(psource->value.diplrel); case VUT_NATIONALITY: return nation_rule_name(psource->value.nationality); @@ -4305,6 +4330,7 @@ const char *universal_name_translation(const struct universal *psource, nation_adjective_translation(psource->value.nationality)); return buf; case VUT_DIPLREL: + case VUT_DIPLREL_TILE: fc_strlcat(buf, diplrel_name_translation(psource->value.diplrel), bufsz); return buf; @@ -4978,7 +5004,8 @@ static enum req_item_found action_found(const struct requirement *preq, static enum req_item_found diplrel_found(const struct requirement *preq, const struct universal *source) { - fc_assert_ret_val(source->kind == VUT_DIPLREL, + fc_assert_ret_val((source->kind == VUT_DIPLREL + || source->kind == VUT_DIPLREL_TILE), ITF_NOT_APPLICABLE); if (preq->source.kind == source->kind) { @@ -5088,6 +5115,7 @@ void universal_found_functions_init(void) universal_found_function[VUT_OTYPE] = &output_type_found; universal_found_function[VUT_ACTION] = &action_found; universal_found_function[VUT_DIPLREL] = &diplrel_found; + universal_found_function[VUT_DIPLREL_TILE] = &diplrel_found; universal_found_function[VUT_UNITSTATE] = &ustate_found; } diff --git a/doc/README.effects b/doc/README.effects index 5ddb7dfe0d..e9dff70130 100644 --- a/doc/README.effects +++ b/doc/README.effects @@ -70,6 +70,7 @@ Nation: World, Alliance, Team, Player NationGroup: World, Alliance, Team, Player Nationality: Traderoute, City DiplRel: World, Alliance, Team, Player, Local +DiplRelTile: Alliance, Team, Player, Local Action: Local OutputType: Local Specialist: Local @@ -719,6 +720,12 @@ Requirement is fulfilled when the tile is "DiplRel", "Foreign", "Local", TRUE | no | no | yes "DiplRel", "Foreign", "Local", FALSE | yes | no | no +The DiplRelTile requirement type +-------------------------------- +Mostly like the DiplRel requirement type. +The player is the tile owner. The second player is DiplRel's player. +Doesn't have the World requirement range as that would be redundant. + The MaxUnitsOnTile requirement type ----------------------------------- Check the number of units present on a tile. Is true if no more than the diff --git a/server/cityturn.c b/server/cityturn.c index 24d6e73c10..cf74771e2b 100644 --- a/server/cityturn.c +++ b/server/cityturn.c @@ -1457,6 +1457,7 @@ static bool worklist_item_postpone_req_vec(struct universal *target, } break; case VUT_DIPLREL: + case VUT_DIPLREL_TILE: /* The tile owner is the city owner */ if (preq->present) { notify_player(pplayer, city_tile(pcity), E_CITY_CANTBUILD, ftc_server, diff --git a/server/rssanity.c b/server/rssanity.c index 42a9a4ad2c..2a2f7788a4 100644 --- a/server/rssanity.c +++ b/server/rssanity.c @@ -374,6 +374,7 @@ static bool sanity_check_req_set(int reqs_of_type[], int local_reqs_of_type[], case VUT_MINCULTURE: case VUT_ACHIEVEMENT: case VUT_DIPLREL: + case VUT_DIPLREL_TILE: /* Can have multiple requirements of these types */ break; case VUT_COUNT: diff --git a/tools/ruledit/univ_value.c b/tools/ruledit/univ_value.c index 111a931be4..805563151b 100644 --- a/tools/ruledit/univ_value.c +++ b/tools/ruledit/univ_value.c @@ -152,6 +152,7 @@ bool universal_value_initial(struct universal *src) src->value.achievement = achievement_by_number(0); return TRUE; case VUT_DIPLREL: + case VUT_DIPLREL_TILE: src->value.diplrel = DS_WAR; return TRUE; case VUT_MAXTILEUNITS: @@ -357,6 +358,7 @@ void universal_kind_values(struct universal *univ, } achievements_re_active_iterate_end; break; case VUT_DIPLREL: + case VUT_DIPLREL_TILE: for (i = 0; i < DS_LAST; i++) { cb(diplstate_type_name(i), univ->value.diplrel == i, data); } -- 2.30.2