From 4a2a082c9fd0b9783ab5c0397d893823de423474 Mon Sep 17 00:00:00 2001 From: Marko Lindqvist Date: Mon, 26 Sep 2022 05:21:53 +0300 Subject: [PATCH 38/38] Fix barbarians' exception to unit tech requirements - Introduce are_reqs_active_ranges() - Call are_reqs_active_ranges() only for ranges not already checked by the player level check, when checking if the specific city can build a unit This means: - City level check does not override barbarians' exception player range tech requirements - Counts as an optimization as the player and higher range requirements are not checked twice See osdn #45571 Signed-off-by: Marko Lindqvist --- common/city.c | 23 ++++++++++++++--------- common/requirements.c | 23 +++++++++++++++++++++++ common/requirements.h | 6 ++++++ 3 files changed, 43 insertions(+), 9 deletions(-) diff --git a/common/city.c b/common/city.c index 094014944e..3ba7d379a2 100644 --- a/common/city.c +++ b/common/city.c @@ -897,15 +897,20 @@ bool can_city_build_unit_direct(const struct city *pcity, return FALSE; } - /* Check unit build requirements. */ - if (!are_reqs_active(&(const struct req_context) { - .player = city_owner(pcity), - .city = pcity, - .tile = city_tile(pcity), - .unittype = punittype, - }, - NULL, - &punittype->build_reqs, RPT_CERTAIN)) { + /* Check unit build requirements. + * Above player level check already checked anything with range >= REQ_RANGE_PLAYER. + * Don't recheck those. Not only for optimization, but also not to override the + * special handling of tech requirements for barbarians */ + if (!are_reqs_active_ranges(0, /* The lowest range; REQ_RANGE_LOCAL */ + REQ_RANGE_PLAYER - 1, + &(const struct req_context) { + .player = city_owner(pcity), + .city = pcity, + .tile = city_tile(pcity), + .unittype = punittype, + }, + NULL, + &punittype->build_reqs, RPT_CERTAIN)) { return FALSE; } diff --git a/common/requirements.c b/common/requirements.c index a9de864423..44741fce5c 100644 --- a/common/requirements.c +++ b/common/requirements.c @@ -3919,6 +3919,29 @@ bool are_reqs_active(const struct req_context *context, return FALSE; } } requirement_vector_iterate_end; + + return TRUE; +} + +/**********************************************************************//** + Like are_reqs_active() but checks only requirements that have + one of the ranges between min_range and max_range. +**************************************************************************/ +bool are_reqs_active_ranges(const enum req_range min_range, + const enum req_range max_range, + const struct req_context *context, + const struct player *other_player, + const struct requirement_vector *reqs, + const enum req_problem_type prob_type) +{ + requirement_vector_iterate(reqs, preq) { + if (preq->range >= min_range && preq->range <= max_range) { + if (!is_req_active(context, other_player, preq, prob_type)) { + return FALSE; + } + } + } requirement_vector_iterate_end; + return TRUE; } diff --git a/common/requirements.h b/common/requirements.h index 9e98c15829..068756dcb5 100644 --- a/common/requirements.h +++ b/common/requirements.h @@ -146,6 +146,12 @@ bool are_reqs_active(const struct req_context *context, const struct player *other_player, const struct requirement_vector *reqs, const enum req_problem_type prob_type); +bool are_reqs_active_ranges(const enum req_range min_range, + const enum req_range max_range, + const struct req_context *context, + const struct player *other_player, + const struct requirement_vector *reqs, + const enum req_problem_type prob_type); bool is_req_unchanging(const struct requirement *req); -- 2.35.1