From d97f771414a079fd5490119f365b9b4485ad443d Mon Sep 17 00:00:00 2001 From: Marko Lindqvist Date: Thu, 27 Apr 2023 22:10:05 +0300 Subject: [PATCH 44/44] Fix client crash on evaluating Traderoute range requirements Some bad evaluations of such requirements get corrected in the process, affecting also server side. Reported by bard See osdn #47653 Signed-off-by: Marko Lindqvist --- common/requirements.c | 277 ++++++++++++++++++++++++++++-------------- 1 file changed, 185 insertions(+), 92 deletions(-) diff --git a/common/requirements.c b/common/requirements.c index 364a603f74..5025b38b0d 100644 --- a/common/requirements.c +++ b/common/requirements.c @@ -2087,13 +2087,18 @@ is_building_req_active(const struct req_context *context, if (num_city_buildings(context->city, building) > 0) { return TRI_YES; } else { + enum fc_tristate ret = TRI_NO; + trade_partners_iterate(context->city, trade_partner) { - if (num_city_buildings(trade_partner, building) > 0) { + if (trade_partner == NULL) { + ret = TRI_MAYBE; + } else if (num_city_buildings(trade_partner, building) > 0) { return TRI_YES; } } trade_partners_iterate_end; + + return ret; } - return TRI_NO; } else { return TRI_MAYBE; } @@ -2387,12 +2392,17 @@ is_minculture_req_active(const struct req_context *context, if (city_culture(context->city) >= minculture) { return TRI_YES; } else { + enum fc_tristate ret = TRI_NO; + trade_partners_iterate(context->city, trade_partner) { - if (city_culture(trade_partner) >= minculture) { + if (trade_partner == NULL) { + ret = TRI_MAYBE; + } else if (city_culture(trade_partner) >= minculture) { return TRI_YES; } } trade_partners_iterate_end; - return TRI_MAYBE; + + return ret; } case REQ_RANGE_PLAYER: case REQ_RANGE_TEAM: @@ -2459,14 +2469,21 @@ is_minforeignpct_req_active(const struct req_context *context, if (foreign_pct >= min_foreign_pct) { return TRI_YES; } else { + enum fc_tristate ret = TRI_NO; + trade_partners_iterate(context->city, trade_partner) { - foreign_pct = citizens_nation_foreign(trade_partner) * 100 - / city_size_get(trade_partner); - if (foreign_pct >= min_foreign_pct) { - return TRI_YES; + if (trade_partner == NULL) { + ret = TRI_MAYBE; + } else { + foreign_pct = citizens_nation_foreign(trade_partner) * 100 + / city_size_get(trade_partner); + if (foreign_pct >= min_foreign_pct) { + return TRI_YES; + } } } trade_partners_iterate_end; - return TRI_MAYBE; + + return ret; } case REQ_RANGE_PLAYER: case REQ_RANGE_TEAM: @@ -2568,6 +2585,7 @@ is_extra_req_active(const struct req_context *context, const struct requirement *req) { const struct extra_type *pextra; + enum fc_tristate ret; IS_REQ_ACTIVE_VARIANT_ASSERT(VUT_EXTRA); @@ -2620,16 +2638,22 @@ is_extra_req_active(const struct req_context *context, return TRI_YES; } } city_tile_iterate_end; + + ret = TRI_NO; trade_partners_iterate(context->city, trade_partner) { - city_tile_iterate(city_map_radius_sq_get(trade_partner), - city_tile(trade_partner), ptile) { - if (tile_has_extra(ptile, pextra)) { - return TRI_YES; - } - } city_tile_iterate_end; + if (trade_partner == NULL) { + ret = TRI_MAYBE; + } else { + city_tile_iterate(city_map_radius_sq_get(trade_partner), + city_tile(trade_partner), ptile) { + if (tile_has_extra(ptile, pextra)) { + return TRI_YES; + } + } city_tile_iterate_end; + } } trade_partners_iterate_end; - return TRI_NO; + return ret; case REQ_RANGE_CONTINENT: case REQ_RANGE_PLAYER: @@ -2802,22 +2826,33 @@ is_terrain_req_active(const struct req_context *context, return TRI_MAYBE; } if (pterrain != NULL) { + enum fc_tristate ret; + city_tile_iterate(city_map_radius_sq_get(context->city), city_tile(context->city), ptile) { if (tile_terrain(ptile) == pterrain) { return TRI_YES; } } city_tile_iterate_end; + + ret = TRI_NO; trade_partners_iterate(context->city, trade_partner) { - city_tile_iterate(city_map_radius_sq_get(trade_partner), - city_tile(trade_partner), ptile) { - if (tile_terrain(ptile) == pterrain) { - return TRI_YES; - } - } city_tile_iterate_end; + if (trade_partner == NULL) { + ret = TRI_MAYBE; + } else { + city_tile_iterate(city_map_radius_sq_get(trade_partner), + city_tile(trade_partner), ptile) { + if (tile_terrain(ptile) == pterrain) { + return TRI_YES; + } + } city_tile_iterate_end; + } } trade_partners_iterate_end; + + return ret; } - return TRI_NO; + + return TRI_MAYBE; case REQ_RANGE_CONTINENT: case REQ_RANGE_PLAYER: case REQ_RANGE_TEAM: @@ -2847,6 +2882,7 @@ is_terrainclass_req_active(const struct req_context *context, const struct requirement *req) { enum terrain_class pclass; + enum fc_tristate ret; IS_REQ_ACTIVE_VARIANT_ASSERT(VUT_TERRAINCLASS); @@ -2878,6 +2914,7 @@ is_terrainclass_req_active(const struct req_context *context, city_tile_iterate(city_map_radius_sq_get(context->city), city_tile(context->city), ptile) { const struct terrain *pterrain = tile_terrain(ptile); + if (pterrain != T_UNKNOWN && terrain_type_terrain_class(pterrain) == pclass) { return TRI_YES; @@ -2892,24 +2929,31 @@ is_terrainclass_req_active(const struct req_context *context, city_tile_iterate(city_map_radius_sq_get(context->city), city_tile(context->city), ptile) { const struct terrain *pterrain = tile_terrain(ptile); + if (pterrain != T_UNKNOWN && terrain_type_terrain_class(pterrain) == pclass) { return TRI_YES; } } city_tile_iterate_end; + ret = TRI_NO; trade_partners_iterate(context->city, trade_partner) { - city_tile_iterate(city_map_radius_sq_get(trade_partner), - city_tile(trade_partner), ptile) { - const struct terrain *pterrain = tile_terrain(ptile); - if (pterrain != T_UNKNOWN - && terrain_type_terrain_class(pterrain) == pclass) { - return TRI_YES; - } - } city_tile_iterate_end; + if (trade_partner == NULL) { + ret = TRI_MAYBE; + } else { + city_tile_iterate(city_map_radius_sq_get(trade_partner), + city_tile(trade_partner), ptile) { + const struct terrain *pterrain = tile_terrain(ptile); + + if (pterrain != T_UNKNOWN + && terrain_type_terrain_class(pterrain) == pclass) { + return TRI_YES; + } + } city_tile_iterate_end; + } } trade_partners_iterate_end; - return TRI_NO; + return ret; case REQ_RANGE_CONTINENT: case REQ_RANGE_PLAYER: case REQ_RANGE_TEAM: @@ -2939,6 +2983,7 @@ is_terrainflag_req_active(const struct req_context *context, const struct requirement *req) { enum terrain_flag_id terrflag; + enum fc_tristate ret; IS_REQ_ACTIVE_VARIANT_ASSERT(VUT_TERRFLAG); @@ -2976,6 +3021,7 @@ is_terrainflag_req_active(const struct req_context *context, city_tile_iterate(city_map_radius_sq_get(context->city), city_tile(context->city), ptile) { const struct terrain *pterrain = tile_terrain(ptile); + if (pterrain != T_UNKNOWN && terrain_has_flag(pterrain, terrflag)) { return TRI_YES; @@ -2990,24 +3036,31 @@ is_terrainflag_req_active(const struct req_context *context, city_tile_iterate(city_map_radius_sq_get(context->city), city_tile(context->city), ptile) { const struct terrain *pterrain = tile_terrain(ptile); + if (pterrain != T_UNKNOWN && terrain_has_flag(pterrain, terrflag)) { return TRI_YES; } } city_tile_iterate_end; + ret = TRI_NO; trade_partners_iterate(context->city, trade_partner) { - city_tile_iterate(city_map_radius_sq_get(trade_partner), - city_tile(trade_partner), ptile) { - const struct terrain *pterrain = tile_terrain(ptile); - if (pterrain != T_UNKNOWN - && terrain_has_flag(pterrain, terrflag)) { - return TRI_YES; - } - } city_tile_iterate_end; + if (trade_partner == NULL) { + ret = TRI_MAYBE; + } else { + city_tile_iterate(city_map_radius_sq_get(trade_partner), + city_tile(trade_partner), ptile) { + const struct terrain *pterrain = tile_terrain(ptile); + + if (pterrain != T_UNKNOWN + && terrain_has_flag(pterrain, terrflag)) { + return TRI_YES; + } + } city_tile_iterate_end; + } } trade_partners_iterate_end; - return TRI_NO; + return ret; case REQ_RANGE_CONTINENT: case REQ_RANGE_PLAYER: case REQ_RANGE_TEAM: @@ -3036,6 +3089,7 @@ is_roadflag_req_active(const struct req_context *context, const struct requirement *req) { enum road_flag_id roadflag; + enum fc_tristate ret; IS_REQ_ACTIVE_VARIANT_ASSERT(VUT_ROADFLAG); @@ -3048,6 +3102,7 @@ is_roadflag_req_active(const struct req_context *context, return TRI_MAYBE; } struct road_type *r = extra_road_get(context->extra); + return BOOL_TO_TRISTATE( r && road_has_flag(r, roadflag) ); @@ -3093,16 +3148,21 @@ is_roadflag_req_active(const struct req_context *context, } } city_tile_iterate_end; + ret = TRI_NO; trade_partners_iterate(context->city, trade_partner) { - city_tile_iterate(city_map_radius_sq_get(trade_partner), - city_tile(trade_partner), ptile) { - if (tile_has_road_flag(ptile, roadflag)) { - return TRI_YES; - } - } city_tile_iterate_end; + if (trade_partner == NULL) { + ret = TRI_MAYBE; + } else { + city_tile_iterate(city_map_radius_sq_get(trade_partner), + city_tile(trade_partner), ptile) { + if (tile_has_road_flag(ptile, roadflag)) { + return TRI_YES; + } + } city_tile_iterate_end; + } } trade_partners_iterate_end; - return TRI_NO; + return ret; case REQ_RANGE_CONTINENT: case REQ_RANGE_PLAYER: case REQ_RANGE_TEAM: @@ -3130,6 +3190,7 @@ is_extraflag_req_active(const struct req_context *context, const struct requirement *req) { enum extra_flag_id extraflag; + enum fc_tristate ret; IS_REQ_ACTIVE_VARIANT_ASSERT(VUT_EXTRAFLAG); @@ -3182,16 +3243,21 @@ is_extraflag_req_active(const struct req_context *context, } } city_tile_iterate_end; + ret = TRI_NO; trade_partners_iterate(context->city, trade_partner) { - city_tile_iterate(city_map_radius_sq_get(trade_partner), - city_tile(trade_partner), ptile) { - if (tile_has_extra_flag(ptile, extraflag)) { - return TRI_YES; - } - } city_tile_iterate_end; + if (trade_partner == NULL) { + ret = TRI_MAYBE; + } else { + city_tile_iterate(city_map_radius_sq_get(trade_partner), + city_tile(trade_partner), ptile) { + if (tile_has_extra_flag(ptile, extraflag)) { + return TRI_YES; + } + } city_tile_iterate_end; + } } trade_partners_iterate_end; - return TRI_NO; + return ret; case REQ_RANGE_CONTINENT: case REQ_RANGE_PLAYER: case REQ_RANGE_TEAM: @@ -3483,6 +3549,7 @@ is_nationality_req_active(const struct req_context *context, const struct requirement *req) { const struct nation_type *nationality; + enum fc_tristate ret; IS_REQ_ACTIVE_VARIANT_ASSERT(VUT_NATIONALITY); @@ -3510,15 +3577,20 @@ is_nationality_req_active(const struct req_context *context, } } citizens_iterate_end; + ret = TRI_NO; trade_partners_iterate(context->city, trade_partner) { - citizens_iterate(trade_partner, slot, count) { - if (player_slot_get_player(slot)->nation == nationality) { - return TRI_YES; - } - } citizens_iterate_end; + if (trade_partner == NULL) { + ret = TRI_MAYBE; + } else { + citizens_iterate(trade_partner, slot, count) { + if (player_slot_get_player(slot)->nation == nationality) { + return TRI_YES; + } + } citizens_iterate_end; + } } trade_partners_iterate_end; - return TRI_NO; + return ret; case REQ_RANGE_PLAYER: case REQ_RANGE_TEAM: case REQ_RANGE_ALLIANCE: @@ -4538,23 +4610,22 @@ is_citystatus_req_active(const struct req_context *context, return BOOL_TO_TRISTATE(city_owner(context->city) == context->city->original); case REQ_RANGE_TRADEROUTE: { - bool found = (city_owner(context->city) == context->city->original); - bool maybe = FALSE; + enum fc_tristate ret; + if (city_owner(context->city) == context->city->original) { + return TRI_YES; + } + + ret = TRI_NO; trade_partners_iterate(context->city, trade_partner) { - if (trade_partner->original == NULL) { - maybe = TRUE; + if (trade_partner == NULL || trade_partner->original == NULL) { + ret = TRI_MAYBE; } else if (city_owner(trade_partner) == trade_partner->original) { - found = TRUE; - break; + return TRI_YES; } } trade_partners_iterate_end; - if (!found && maybe) { - return TRI_MAYBE; - } - - return BOOL_TO_TRISTATE(found); + return ret; } case REQ_RANGE_LOCAL: case REQ_RANGE_TILE: @@ -4580,16 +4651,22 @@ is_citystatus_req_active(const struct req_context *context, return BOOL_TO_TRISTATE(context->city->had_famine); case REQ_RANGE_TRADEROUTE: { - bool found = context->city->had_famine; + enum fc_tristate ret; + if (context->city->had_famine) { + return TRI_YES; + } + + ret = TRI_NO; trade_partners_iterate(context->city, trade_partner) { - if (trade_partner->had_famine) { - found = TRUE; - break; + if (trade_partner == NULL) { + ret = TRI_MAYBE; + } else if (trade_partner->had_famine) { + return TRI_YES; } } trade_partners_iterate_end; - return BOOL_TO_TRISTATE(found); + return ret; } case REQ_RANGE_LOCAL: case REQ_RANGE_TILE: @@ -4615,16 +4692,22 @@ is_citystatus_req_active(const struct req_context *context, return BOOL_TO_TRISTATE(context->city->anarchy > 0); case REQ_RANGE_TRADEROUTE: { - bool found = (context->city->anarchy > 0); + enum fc_tristate ret; + if (context->city->anarchy > 0) { + return TRI_YES; + } + + ret = TRI_NO; trade_partners_iterate(context->city, trade_partner) { - if (trade_partner->anarchy > 0) { - found = TRUE; - break; + if (trade_partner == NULL) { + ret = TRI_MAYBE; + } else if (trade_partner->anarchy > 0) { + return TRI_YES; } } trade_partners_iterate_end; - return BOOL_TO_TRISTATE(found); + return ret; } case REQ_RANGE_LOCAL: case REQ_RANGE_TILE: @@ -4650,16 +4733,22 @@ is_citystatus_req_active(const struct req_context *context, return BOOL_TO_TRISTATE(context->city->rapture > 0); case REQ_RANGE_TRADEROUTE: { - bool found = (context->city->rapture > 0); + enum fc_tristate ret; + if (context->city->rapture > 0) { + return TRI_YES; + } + + ret = TRI_NO; trade_partners_iterate(context->city, trade_partner) { - if (trade_partner->rapture > 0) { - found = TRUE; - break; + if (trade_partner == NULL) { + ret = TRI_MAYBE; + } else if (trade_partner->rapture > 0) { + return TRI_YES; } } trade_partners_iterate_end; - return BOOL_TO_TRISTATE(found); + return ret; } case REQ_RANGE_LOCAL: case REQ_RANGE_TILE: @@ -4708,18 +4797,22 @@ is_minsize_req_active(const struct req_context *context, return TRI_MAYBE; } else { if (req->range == REQ_RANGE_TRADEROUTE) { - bool found = FALSE; + enum fc_tristate ret; if (city_size_get(context->city) >= req->source.value.minsize) { return TRI_YES; } + + ret = TRI_NO; trade_partners_iterate(context->city, trade_partner) { - if (city_size_get(trade_partner) >= req->source.value.minsize) { - found = TRUE; - break; + if (trade_partner == NULL) { + ret = TRI_MAYBE; + } else if (city_size_get(trade_partner) >= req->source.value.minsize) { + return TRI_YES; } } trade_partners_iterate_end; - return BOOL_TO_TRISTATE(found); + + return ret; } else { return BOOL_TO_TRISTATE(city_size_get(context->city) >= req->source.value.minsize); -- 2.39.2