From df89ff76af49418ef193d7314062d991c3281ef4 Mon Sep 17 00:00:00 2001 From: Marko Lindqvist Date: Fri, 20 Oct 2023 08:04:52 +0300 Subject: [PATCH 31/31] Add FormAge requirement type Requested by danau See osdn #48848 Signed-off-by: Marko Lindqvist --- ai/default/daieffects.c | 4 +++ ai/default/daimilitary.c | 1 + common/fc_types.h | 3 ++ common/reqtext.c | 13 ++++++++ common/requirements.c | 68 ++++++++++++++++++++++++++++++++++++++ doc/README.effects | 3 ++ server/cityturn.c | 16 +++++++++ server/rssanity.c | 1 + tools/ruledit/univ_value.c | 4 +++ 9 files changed, 113 insertions(+) diff --git a/ai/default/daieffects.c b/ai/default/daieffects.c index 811860a6ed..83c36e9fc4 100644 --- a/ai/default/daieffects.c +++ b/ai/default/daieffects.c @@ -858,6 +858,10 @@ bool dai_can_requirement_be_met_in_city(const struct requirement *preq, /* No way to remove once present. */ return preq->present; + case VUT_FORM_AGE: + /* FIXME: Sometimes it would be possible to convert back and forth */ + return preq->present; + case VUT_MINFOREIGNPCT: /* No way to add once lost. */ return !preq->present; diff --git a/ai/default/daimilitary.c b/ai/default/daimilitary.c index 1dafcc4648..8ef4f19163 100644 --- a/ai/default/daimilitary.c +++ b/ai/default/daimilitary.c @@ -409,6 +409,7 @@ tactical_req_cb(const struct req_context *context, /* If the attack happens, there is a diplrel that allows it */ return TRI_YES; case VUT_AGE: + case VUT_FORM_AGE: case VUT_MINCALFRAG: case VUT_MINYEAR: /* If it is not near, won't change */ diff --git a/common/fc_types.h b/common/fc_types.h index 1c903880ed..0d863f1015 100644 --- a/common/fc_types.h +++ b/common/fc_types.h @@ -754,6 +754,7 @@ typedef union { int minveteran; int min_hit_points; int age; + int form_age; int min_techs; int latitude; @@ -884,6 +885,8 @@ typedef union { #define SPECENUM_VALUE55NAME "PlayerFlag" #define SPECENUM_VALUE56 VUT_PLAYER_STATE #define SPECENUM_VALUE56NAME "PlayerState" +#define SPECENUM_VALUE57 VUT_FORM_AGE +#define SPECENUM_VALUE57NAME "FormAge" /* Keep this last. */ #define SPECENUM_COUNT VUT_COUNT diff --git a/common/reqtext.c b/common/reqtext.c index d078e3371b..b86b2d1835 100644 --- a/common/reqtext.c +++ b/common/reqtext.c @@ -2868,6 +2868,19 @@ bool req_text_insert(char *buf, size_t bufsz, struct player *pplayer, } return TRUE; + case VUT_FORM_AGE: + fc_strlcat(buf, prefix, bufsz); + if (preq->present) { + cat_snprintf(buf, bufsz, + _("Requires form age of %d turns."), + preq->source.value.form_age); + } else { + cat_snprintf(buf, bufsz, + _("Prevented if form age is over %d turns."), + preq->source.value.form_age); + } + return TRUE; + case VUT_MINTECHS: switch (preq->range) { case REQ_RANGE_WORLD: diff --git a/common/requirements.c b/common/requirements.c index d371812e55..ac02539be4 100644 --- a/common/requirements.c +++ b/common/requirements.c @@ -450,6 +450,12 @@ void universal_value_from_str(struct universal *source, const char *value) return; } break; + case VUT_FORM_AGE: + source->value.form_age = atoi(value); + if (source->value.form_age > 0) { + return; + } + break; case VUT_MINTECHS: source->value.min_techs = atoi(value); if (source->value.min_techs > 0) { @@ -744,6 +750,9 @@ struct universal universal_by_number(const enum universals_n kind, case VUT_AGE: source.value.age = value; return source; + case VUT_FORM_AGE: + source.value.form_age = value; + return source; case VUT_MINTECHS: source.value.min_techs = value; return source; @@ -917,6 +926,8 @@ int universal_number(const struct universal *source) return source->value.min_hit_points; case VUT_AGE: return source->value.age; + case VUT_FORM_AGE: + return source->value.form_age; case VUT_MINTECHS: return source->value.min_techs; case VUT_ACTION: @@ -1054,6 +1065,7 @@ struct requirement req_from_str(const char *type, const char *range, case VUT_MINMOVES: case VUT_MINHP: case VUT_AGE: + case VUT_FORM_AGE: case VUT_ACTION: case VUT_OTYPE: case VUT_SPECIALIST: @@ -1254,6 +1266,9 @@ struct requirement req_from_str(const char *type, const char *range, && req.range != REQ_RANGE_CITY && req.range != REQ_RANGE_PLAYER); break; + case VUT_FORM_AGE: + invalid = (req.range != REQ_RANGE_LOCAL); + break; case VUT_IMPR_GENUS: /* TODO: Support other ranges too. */ invalid = (req.range != REQ_RANGE_LOCAL); @@ -1314,6 +1329,7 @@ struct requirement req_from_str(const char *type, const char *range, case VUT_MINMOVES: case VUT_MINHP: case VUT_AGE: + case VUT_FORM_AGE: case VUT_ACTION: case VUT_OTYPE: case VUT_SPECIALIST: @@ -4280,6 +4296,36 @@ is_age_req_active(const struct req_context *context, } } +/**********************************************************************//** + Determine whether a form age requirement is satisfied in a given context, + ignoring parts of the requirement that can be handled uniformly for all + requirement types. + + context and req must not be null, and req must be a form age requirement +**************************************************************************/ +static enum fc_tristate +is_form_age_req_active(const struct req_context *context, + const struct player *other_player, + const struct requirement *req) +{ + IS_REQ_ACTIVE_VARIANT_ASSERT(VUT_FORM_AGE); + + switch (req->range) { + case REQ_RANGE_LOCAL: + if (context->unit == NULL || !is_server()) { + return TRI_MAYBE; + } else { + return BOOL_TO_TRISTATE( + req->source.value.form_age <= + game.info.turn - context->unit->server.current_form_turn); + } + break; + default: + return TRI_MAYBE; + break; + } +} + /**********************************************************************//** Is center of given city in tile. If city is NULL, any city will do. **************************************************************************/ @@ -5224,6 +5270,7 @@ static struct req_def req_definitions[VUT_COUNT] = { [VUT_ACTIVITY] = {is_activity_req_active, REQUCH_NO}, [VUT_ADVANCE] = {is_tech_req_active, REQUCH_NO}, [VUT_AGE] = {is_age_req_active, REQUCH_YES, REQUC_PRESENT}, + [VUT_FORM_AGE] = {is_form_age_req_active, REQUCH_YES, REQUC_PRESENT}, [VUT_AI_LEVEL] = {is_ai_req_active, REQUCH_HACK}, [VUT_CITYSTATUS] = {is_citystatus_req_active, REQUCH_NO, REQUC_CITYSTATUS}, [VUT_CITYTILE] = {is_citytile_req_active, REQUCH_NO, REQUC_CITYTILE}, @@ -5506,6 +5553,16 @@ tri_req_active_turns(int pass, int period, return TRI_MAYBE; } break; + case VUT_FORM_AGE: + if (context->unit == NULL || !is_server()) { + return TRI_MAYBE; + } else { + int ua = game.info.turn + pass - context->unit->server.current_form_turn; + + present = req->source.value.form_age <= ua; + present1 = req->source.value.form_age <= ua + period; + } + break; case VUT_MINYEAR: present = game.info.year + year_inc >= req->source.value.minyear; present1 = game.info.year + year_inc1 >= req->source.value.minyear; @@ -5776,6 +5833,7 @@ bool universal_never_there(const struct universal *source) case VUT_MINMOVES: case VUT_MINHP: case VUT_AGE: + case VUT_FORM_AGE: case VUT_ROADFLAG: case VUT_MINCALFRAG: case VUT_TERRAIN: @@ -6396,6 +6454,8 @@ bool are_universals_equal(const struct universal *psource1, return psource1->value.min_hit_points == psource2->value.min_hit_points; case VUT_AGE: return psource1->value.age == psource2->value.age; + case VUT_FORM_AGE: + return psource1->value.form_age == psource2->value.form_age; case VUT_MINTECHS: return psource1->value.min_techs == psource2->value.min_techs; case VUT_ACTION: @@ -6549,6 +6609,10 @@ const char *universal_rule_name(const struct universal *psource) case VUT_AGE: fc_snprintf(buffer, sizeof(buffer), "%d", psource->value.age); + return buffer; + case VUT_FORM_AGE: + fc_snprintf(buffer, sizeof(buffer), "%d", psource->value.form_age); + return buffer; case VUT_MINTECHS: fc_snprintf(buffer, sizeof(buffer), "%d", psource->value.min_techs); @@ -6785,6 +6849,10 @@ const char *universal_name_translation(const struct universal *psource, cat_snprintf(buf, bufsz, _("Age %d"), psource->value.age); return buf; + case VUT_FORM_AGE: + cat_snprintf(buf, bufsz, _("Form age %d"), + psource->value.form_age); + return buf; case VUT_MINTECHS: cat_snprintf(buf, bufsz, _("%d Techs"), psource->value.min_techs); diff --git a/doc/README.effects b/doc/README.effects index 8196be0aad..4d186ad88f 100644 --- a/doc/README.effects +++ b/doc/README.effects @@ -96,6 +96,7 @@ ServerSetting: World Age (of unit): Local Age (of city): City Age (of player): Player +FormAge: Local MinSize: Traderoute, City MinCulture: World, Alliance, Team, Player, Traderoute, City MinForeignPct: Traderoute, City @@ -145,6 +146,8 @@ Nationality is fulfilled by any citizens of the given nationality 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. +FormAge is time since latest unit upgrade of conversion. + Effect types ============ diff --git a/server/cityturn.c b/server/cityturn.c index d878bb219b..299c2642d7 100644 --- a/server/cityturn.c +++ b/server/cityturn.c @@ -2109,6 +2109,22 @@ static bool worklist_item_postpone_req_vec(struct universal *target, purge = TRUE; } break; + case VUT_FORM_AGE: + if (preq->present) { + notify_player(pplayer, city_tile(pcity), + E_CITY_CANTBUILD, ftc_server, + _("%s can't build %s from the worklist; " + "only available once %d turns old form. Postponing..."), + city_link(pcity), + tgt_name, + preq->source.value.age); + script_server_signal_emit(signal_name, ptarget, + pcity, "need_form_age"); + } else { + /* Can't go back in time. */ + purge = TRUE; + } + break; case VUT_NONE: case VUT_COUNT: fc_assert_ret_val_msg(FALSE, TRUE, diff --git a/server/rssanity.c b/server/rssanity.c index e0239965fc..489997522b 100644 --- a/server/rssanity.c +++ b/server/rssanity.c @@ -352,6 +352,7 @@ static bool sanity_check_req_set(rs_conversion_logger logger, case VUT_STYLE: case VUT_IMPR_GENUS: case VUT_ORIGINAL_OWNER: /* City range -> only one original owner */ + case VUT_FORM_AGE: /* There can be only one requirement of these types (with current * range limitations) * Requirements might be identical, but we consider multiple diff --git a/tools/ruledit/univ_value.c b/tools/ruledit/univ_value.c index 340f9d8b05..72c9de206f 100644 --- a/tools/ruledit/univ_value.c +++ b/tools/ruledit/univ_value.c @@ -205,6 +205,9 @@ bool universal_value_initial(struct universal *src) case VUT_AGE: src->value.age = 0; return TRUE; + case VUT_FORM_AGE: + src->value.form_age = 0; + return TRUE; case VUT_NATIONGROUP: if (nation_group_count() <= 0) { return FALSE; @@ -491,6 +494,7 @@ void universal_kind_values(struct universal *univ, case VUT_MINVETERAN: case VUT_MINHP: case VUT_AGE: + case VUT_FORM_AGE: case VUT_MINTECHS: case VUT_MINLATITUDE: case VUT_MAXLATITUDE: -- 2.42.0