From 9723cd2811fc10fd9f0d7b4ab7b1ae533fbe6933 Mon Sep 17 00:00:00 2001 From: Alina Lenk Date: Mon, 14 Feb 2022 03:36:19 +0100 Subject: [PATCH 3/3] Introduce new req_context struct for requirement targets See osdn #43809 Signed-off-by: Alina Lenk --- ai/default/aidata.c | 4 +- ai/default/aitech.c | 18 +- ai/default/aiunit.c | 15 +- ai/default/daicity.c | 43 +- ai/default/daidomestic.c | 14 +- ai/default/daimilitary.c | 16 +- client/control.c | 12 +- client/helpdata.c | 9 +- client/tilespec.c | 13 +- common/actions.c | 964 +++++++++++++-------------- common/base.c | 16 +- common/city.c | 57 +- common/combat.c | 26 +- common/diptreaty.c | 11 +- common/disaster.c | 8 +- common/effects.c | 202 +++--- common/effects.h | 10 +- common/extras.c | 70 +- common/government.c | 4 +- common/improvement.c | 33 +- common/map.c | 7 +- common/metaknowledge.c | 190 +++--- common/metaknowledge.h | 22 +- common/multipliers.c | 2 +- common/player.c | 15 +- common/requirements.c | 216 +++--- common/requirements.h | 45 +- common/research.c | 30 +- common/road.c | 23 +- common/scriptcore/api_game_effects.c | 14 +- common/scriptcore/api_game_methods.c | 10 +- common/style.c | 14 +- common/traderoutes.c | 36 +- common/unit.c | 44 +- common/unittype.c | 21 +- server/actiontools.c | 27 +- server/advisors/advruleset.c | 5 +- server/citytools.c | 9 +- server/cityturn.c | 7 +- server/diplhand.c | 15 +- server/diplomats.c | 34 +- server/generator/startpos.c | 8 +- server/savegame/savegame2.c | 5 +- server/unithand.c | 67 +- server/unittools.c | 21 +- 45 files changed, 1282 insertions(+), 1150 deletions(-) diff --git a/ai/default/aidata.c b/ai/default/aidata.c index 21978bec2a..36953f0840 100644 --- a/ai/default/aidata.c +++ b/ai/default/aidata.c @@ -540,6 +540,7 @@ void dai_gov_value(struct ai_type *ait, struct player *pplayer, } city_list_iterate_end; city_list_iterate(pplayer->cities, pcity) { bool capital; + const struct req_context context = { .player = pplayer, .city = pcity }; *val += dai_city_want(pplayer, pcity, adv, NULL); capital = is_capital(pcity); @@ -557,8 +558,7 @@ void dai_gov_value(struct ai_type *ait, struct player *pplayer, present = preq->present; continue; } - if (!is_req_active(pplayer, NULL, pcity, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, preq, RPT_POSSIBLE)) { + if (!is_req_active(&context, NULL, preq, RPT_POSSIBLE)) { active = FALSE; break; /* presence doesn't matter for inactive effects. */ } diff --git a/ai/default/aitech.c b/ai/default/aitech.c index 1ee41d0bfb..d9a1db342f 100644 --- a/ai/default/aitech.c +++ b/ai/default/aitech.c @@ -258,6 +258,10 @@ static void dai_tech_effect_values(struct ai_type *ait, struct player *pplayer) adv_want v; adv_want tech_want; bool capital; + const struct req_context context = { + .player = pplayer, + .city = pcity, + }; v = dai_tech_base_want(ait, pplayer, pcity, padv); capital = is_capital(pcity); @@ -275,8 +279,7 @@ static void dai_tech_effect_values(struct ai_type *ait, struct player *pplayer) present = preq->present; continue; } - if (!is_req_active(pplayer, NULL, pcity, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, preq, RPT_POSSIBLE)) { + if (!is_req_active(&context, NULL, preq, RPT_POSSIBLE)) { active = FALSE; break; /* presence doesn't matter for inactive effects. */ @@ -426,9 +429,16 @@ struct unit_type *dai_wants_defender_against(struct ai_type *ait, building = utype_needs_improvement(deftype, pcity); if (building != NULL && !can_player_build_improvement_direct(pplayer, building)) { + const struct req_context context = { + .player = pplayer, + .city = pcity, + .tile = city_tile(pcity), + .unittype = deftype, + .building = building, + }; + requirement_vector_iterate(&building->reqs, preq) { - if (!is_req_active(pplayer, NULL, pcity, building, city_tile(pcity), - NULL, deftype, NULL, NULL, NULL, preq, RPT_CERTAIN)) { + if (!is_req_active(&context, NULL, preq, RPT_CERTAIN)) { if (VUT_ADVANCE == preq->source.kind && preq->present) { int iimprtech = advance_number(preq->source.value.advance); diff --git a/ai/default/aiunit.c b/ai/default/aiunit.c index 132fb36220..a9a0b9e093 100644 --- a/ai/default/aiunit.c +++ b/ai/default/aiunit.c @@ -2849,26 +2849,29 @@ void dai_manage_units(struct ai_type *ait, struct player *pplayer) /**********************************************************************//** Returns an improvement that will make it possible to build units of the - specified type the specified city. Returns FALSE if no new improvement + specified type the specified city. Returns NULL if no new improvement will make it possible or if no improvement is needed. **************************************************************************/ const struct impr_type *utype_needs_improvement(const struct unit_type *putype, const struct city *pcity) { const struct impr_type *impr_req = NULL; + const struct req_context context = { + .player = city_owner(pcity), + .city = pcity, + .tile = city_tile(pcity), + .unittype = putype, + }; requirement_vector_iterate(&putype->build_reqs, preq) { - if (is_req_active(city_owner(pcity), NULL, - pcity, NULL, city_tile(pcity), NULL, - putype, NULL, NULL, NULL, - preq, RPT_CERTAIN)) { + if (is_req_active(&context, NULL, preq, RPT_CERTAIN)) { /* Already there. */ continue; } if (!dai_can_requirement_be_met_in_city(preq, city_owner(pcity), pcity)) { /* The unit type can't be built at all. */ - return FALSE; + return NULL; } if (VUT_IMPROVEMENT == preq->source.kind && preq->present) { /* This is (one of) the building(s) required. */ diff --git a/ai/default/daicity.c b/ai/default/daicity.c index b709447ef0..577aef20a9 100644 --- a/ai/default/daicity.c +++ b/ai/default/daicity.c @@ -1339,14 +1339,18 @@ static bool adjust_wants_for_reqs(struct ai_type *ait, struct tech_vector needed_techs; struct impr_vector needed_improvements; + const struct req_context context = { + .player = pplayer, + .city = pcity, + .tile = city_tile(pcity), + .building = pimprove, + }; + tech_vector_init(&needed_techs); impr_vector_init(&needed_improvements); requirement_vector_iterate(&pimprove->reqs, preq) { - const bool active = is_req_active(pplayer, NULL, pcity, pimprove, - pcity->tile, NULL, NULL, NULL, NULL, - NULL, - preq, RPT_POSSIBLE); + const bool active = is_req_active(&context, NULL, preq, RPT_POSSIBLE); if (VUT_ADVANCE == preq->source.kind && preq->present && !active) { /* Found a missing technology requirement for this improvement. */ @@ -1581,6 +1585,20 @@ static void adjust_improvement_wants_by_effects(struct ai_type *ait, int turns = 9999; int place = tile_continent(pcity->tile); + /* FIXME: Do we really need the effects check to be made *without* + * passing the city tile? */ + const struct req_context effect_ctxt = { + .player = pplayer, + .city = pcity, + .building = pimprove, + }; + const struct req_context actenabler_ctxt = { + .player = pplayer, + .city = pcity, + .tile = city_tile(pcity), + .building = pimprove, + }; + /* Remove team members from the equation */ players_iterate(aplayer) { if (aplayer->team @@ -1675,8 +1693,7 @@ static void adjust_improvement_wants_by_effects(struct ai_type *ait, present = preq->present; continue; } - if (!is_req_active(pplayer, NULL, pcity, pimprove, NULL, NULL, NULL, - NULL, NULL, NULL, preq, RPT_POSSIBLE)) { + if (!is_req_active(&effect_ctxt, NULL, preq, RPT_POSSIBLE)) { active = FALSE; if (VUT_ADVANCE == preq->source.kind && preq->present) { /* This missing requirement is a missing tech requirement. @@ -1770,10 +1787,7 @@ static void adjust_improvement_wants_by_effects(struct ai_type *ait, } } - if (!is_req_active(pplayer, NULL, pcity, pimprove, - city_tile(pcity), NULL, NULL, NULL, NULL, - NULL, - preq, RPT_POSSIBLE)) { + if (!is_req_active(&actenabler_ctxt, NULL, preq, RPT_POSSIBLE)) { active = FALSE; break; } @@ -2043,6 +2057,12 @@ Impr_type_id dai_find_source_building(struct city *pcity, { int greatest_value = 0; const struct impr_type *best_building = NULL; + const struct req_context context = { + .player = city_owner(pcity), + .city = pcity, + .tile = city_tile(pcity), + .unittype = utype, + }; effect_list_iterate(get_effects(effect_type), peffect) { if (peffect->value > greatest_value) { @@ -2059,8 +2079,7 @@ Impr_type_id dai_find_source_building(struct city *pcity, break; } } else if (utype != NULL - && !is_req_active(city_owner(pcity), NULL, pcity, NULL, city_tile(pcity), - NULL, utype, NULL, NULL, NULL, preq, RPT_POSSIBLE)) { + && !is_req_active(&context, NULL, preq, RPT_POSSIBLE)) { /* Effect requires other kind of unit than what we are interested about */ wrong_unit = TRUE; break; diff --git a/ai/default/daidomestic.c b/ai/default/daidomestic.c index ede7a2c47f..14c2ed9014 100644 --- a/ai/default/daidomestic.c +++ b/ai/default/daidomestic.c @@ -361,12 +361,14 @@ static void dai_choose_trade_route(struct ai_type *ait, struct city *pcity, trade_action = utype_can_do_action(unit_type, ACTION_TRADE_ROUTE) ? ACTION_TRADE_ROUTE : ACTION_MARKETPLACE; bonus = get_target_bonus_effects(NULL, - pplayer, NULL, - pcity, NULL, - city_tile(pcity), - NULL, NULL, - NULL, NULL, - action_by_number(trade_action), + &(const struct req_context) { + .player = pplayer, + .city = pcity, + .tile = city_tile(pcity), + .action = + action_by_number(trade_action), + }, + NULL, EFT_TRADE_REVENUE_BONUS); /* Be mercy full to players with small amounts. Round up. */ diff --git a/ai/default/daimilitary.c b/ai/default/daimilitary.c index 713c26edca..3ea7be5286 100644 --- a/ai/default/daimilitary.c +++ b/ai/default/daimilitary.c @@ -1025,12 +1025,16 @@ static void process_attacker_want(struct ai_type *ait, adv_want want; int move_time; int vuln; - int veteran_level = get_target_bonus_effects(NULL, - pplayer, NULL, pcity, - NULL, city_tile(pcity), - NULL, punittype, NULL, - NULL, NULL, - EFT_VETERAN_BUILD); + int veteran_level + = get_target_bonus_effects(NULL, + &(const struct req_context) { + .player = pplayer, + .city = pcity, + .tile = city_tile(pcity), + .unittype = punittype, + }, + NULL, + EFT_VETERAN_BUILD); /* Cost (shield equivalent) of gaining these techs. */ /* FIXME? Katvrr advises that this should be weighted more heavily in big * danger. */ diff --git a/client/control.c b/client/control.c index 3c4f3cdd69..7b1ce3684c 100644 --- a/client/control.c +++ b/client/control.c @@ -1383,6 +1383,10 @@ bool can_unit_do_connect(struct unit *punit, { struct tile *ptile = unit_tile(punit); struct road_type *proad = NULL; + const struct req_context unit_ctxt = { + .unit = punit, + .unittype = unit_type_get(punit), + }; /* HACK: This code duplicates that in * can_unit_do_activity_targeted_at(). The general logic here is that @@ -1403,9 +1407,7 @@ bool can_unit_do_connect(struct unit *punit, if (tile_has_road(ptile, proad)) { /* This tile has road, can unit build road to other tiles too? */ - return are_reqs_active(NULL, NULL, NULL, NULL, NULL, - punit, unit_type_get(punit), NULL, NULL, NULL, - &tgt->reqs, RPT_POSSIBLE); + return are_reqs_active(&unit_ctxt, NULL, &tgt->reqs, RPT_POSSIBLE); } /* To start connect, unit must be able to build road to this @@ -1424,9 +1426,7 @@ bool can_unit_do_connect(struct unit *punit, return FALSE; } if (tile_has_extra(ptile, tgt)) { - return are_reqs_active(NULL, NULL, NULL, NULL, NULL, - punit, unit_type_get(punit), NULL, NULL, NULL, - &tgt->reqs, RPT_POSSIBLE); + return are_reqs_active(&unit_ctxt, NULL, &tgt->reqs, RPT_POSSIBLE); } return can_be_irrigated(ptile, punit) diff --git a/client/helpdata.c b/client/helpdata.c index e2ef44f75d..f9929e8005 100644 --- a/client/helpdata.c +++ b/client/helpdata.c @@ -4308,9 +4308,14 @@ void helptext_government(char *buf, size_t bufsz, struct player *pplayer, * requirements were simple enough. */ struct output_type *potype = output_type != O_LAST ? get_output_type(output_type) : NULL; + world_value = - get_target_bonus_effects(NULL, NULL, NULL, NULL, NULL, NULL, - NULL, unittype, potype, NULL, NULL, + get_target_bonus_effects(NULL, + &(const struct req_context) { + .unittype = unittype, + .output = potype, + }, + NULL, peffect->type); net_value = peffect->value + world_value; } diff --git a/client/tilespec.c b/client/tilespec.c index 315a3f8524..ade3acb0a4 100644 --- a/client/tilespec.c +++ b/client/tilespec.c @@ -5347,10 +5347,15 @@ static int fill_grid_sprite_array(const struct tileset *t, if (unit_drawn_with_city_outline(pfocus_unit, FALSE)) { struct tile *utile = unit_tile(pfocus_unit); int radius = game.info.init_city_radius_sq - + get_target_bonus_effects(NULL, unit_owner(pfocus_unit), NULL, - NULL, NULL, utile, NULL, NULL, - NULL, NULL, NULL, - EFT_CITY_RADIUS_SQ); + + get_target_bonus_effects( + NULL, + &(const struct req_context) { + .player = unit_owner(pfocus_unit), + .tile = utile, + }, + NULL, + EFT_CITY_RADIUS_SQ + ); if (city_tile_to_city_map(&dummy_x, &dummy_y, radius, utile, tile)) { diff --git a/common/actions.c b/common/actions.c index 6d781c13af..602a0cc31e 100644 --- a/common/actions.c +++ b/common/actions.c @@ -123,22 +123,8 @@ action_target_compl_calc(enum action_result result, enum action_sub_target_kind sub_tgt_kind); static bool is_enabler_active(const struct action_enabler *enabler, - const struct player *actor_player, - const struct city *actor_city, - const struct impr_type *actor_building, - const struct tile *actor_tile, - const struct unit *actor_unit, - const struct unit_type *actor_unittype, - const struct output_type *actor_output, - const struct specialist *actor_specialist, - const struct player *target_player, - const struct city *target_city, - const struct impr_type *target_building, - const struct tile *target_tile, - const struct unit *target_unit, - const struct unit_type *target_unittype, - const struct output_type *target_output, - const struct specialist *target_specialist); + const struct req_context *actor, + const struct req_context *target); static inline bool action_prob_is_signal(const struct act_prob probability); @@ -3579,23 +3565,25 @@ action_actor_utype_hard_reqs_ok(const struct action *paction, Can return maybe when not omniscient. Should always return yes or no when omniscient. + + + Passing NULL for actor is equivalent to passing an empty context. This + may or may not be legal depending on the action. **************************************************************************/ static enum fc_tristate action_hard_reqs_actor(const struct action *paction, - const struct player *actor_player, - const struct city *actor_city, - const struct impr_type *actor_building, - const struct tile *actor_tile, - const struct unit *actor_unit, - const struct unit_type *actor_unittype, - const struct output_type *actor_output, - const struct specialist *actor_specialist, + const struct req_context *actor, const bool omniscient, const struct city *homecity) { enum action_result result = paction->result; - if (!action_actor_utype_hard_reqs_ok_full(paction, actor_unittype, TRUE)) { + if (actor == NULL) { + actor = req_context_empty(); + } + + if (!action_actor_utype_hard_reqs_ok_full(paction, actor->unittype, + TRUE)) { /* Info leak: The actor player knows the type of their unit. */ /* The actor unit type can't perform the action because of hard * unit type requirements. */ @@ -3608,7 +3596,7 @@ action_hard_reqs_actor(const struct action *paction, /* Reason: Keep the old rules. */ /* Info leak: The player knows if their unit already has paradropped this * turn. */ - if (actor_unit->paradropped) { + if (actor->unit->paradropped) { return TRI_NO; } @@ -3619,24 +3607,25 @@ action_hard_reqs_actor(const struct action *paction, /* Obligatory hard requirement. Checked here too since * action_hard_reqs_actor() may be called before any * action enablers are checked. */ - if (actor_city == NULL) { + if (actor->city == NULL) { /* No city to airlift from. */ return TRI_NO; } - if (actor_player != city_owner(actor_city) + if (actor->player != city_owner(actor->city) && !(game.info.airlifting_style & AIRLIFTING_ALLIED_SRC - && pplayers_allied(actor_player, city_owner(actor_city)))) { + && pplayers_allied(actor->player, + city_owner(actor->city)))) { /* Not allowed to airlift from this source. */ return TRI_NO; } - if (!(omniscient || city_owner(actor_city) == actor_player)) { + if (!(omniscient || city_owner(actor->city) == actor->player)) { /* Can't check for airlifting capacity. */ return TRI_MAYBE; } - if (0 >= actor_city->airlift + if (0 >= actor->city->airlift && (!(game.info.airlifting_style & AIRLIFTING_UNLIMITED_SRC) || !game.info.airlift_from_always_enabled)) { /* The source cannot airlift for this turn (maybe already airlifted @@ -3651,15 +3640,15 @@ action_hard_reqs_actor(const struct action *paction, case ACTRES_CONVERT: /* Reason: Keep the old rules. */ /* Info leak: The player knows their unit's cargo and location. */ - if (!unit_can_convert(actor_unit)) { + if (!unit_can_convert(actor->unit)) { return TRI_NO; } break; case ACTRES_TRANSPORT_BOARD: case ACTRES_TRANSPORT_EMBARK: - if (unit_transported(actor_unit)) { - if (!can_unit_unload(actor_unit, unit_transport_get(actor_unit))) { + if (unit_transported(actor->unit)) { + if (!can_unit_unload(actor->unit, unit_transport_get(actor->unit))) { /* Can't leave current transport. */ return TRI_NO; } @@ -3667,7 +3656,7 @@ action_hard_reqs_actor(const struct action *paction, break; case ACTRES_TRANSPORT_DISEMBARK: - if (!can_unit_unload(actor_unit, unit_transport_get(actor_unit))) { + if (!can_unit_unload(actor->unit, unit_transport_get(actor->unit))) { /* Keep the old rules about Unreachable and disembarks. */ return TRI_NO; } @@ -3757,25 +3746,14 @@ action_hard_reqs_actor(const struct action *paction, * remember that this is called from action_prob(). Should information the player don't have access to be used in a test it must check if the evaluation can see the thing being tested. + + Passing NULL for actor or target is equivalent to passing an empty + context. This may or may not be legal depending on the action. **************************************************************************/ static enum fc_tristate is_action_possible(const action_id wanted_action, - const struct player *actor_player, - const struct city *actor_city, - const struct impr_type *actor_building, - const struct tile *actor_tile, - const struct unit *actor_unit, - const struct unit_type *actor_unittype, - const struct output_type *actor_output, - const struct specialist *actor_specialist, - const struct player *target_player, - const struct city *target_city, - const struct impr_type *target_building, - const struct tile *target_tile, - const struct unit *target_unit, - const struct unit_type *target_unittype, - const struct output_type *target_output, - const struct specialist *target_specialist, + const struct req_context *actor, + const struct req_context *target, const struct extra_type *target_extra, const bool omniscient, const struct city *homecity) @@ -3786,17 +3764,24 @@ is_action_possible(const action_id wanted_action, struct terrain *pterrain; struct action *paction; + if (actor == NULL) { + actor = req_context_empty(); + } + if (target == NULL) { + target = req_context_empty(); + } + fc_assert_msg((action_id_get_target_kind(wanted_action) == ATK_CITY - && target_city != NULL) + && target->city != NULL) || (action_id_get_target_kind(wanted_action) == ATK_TILE - && target_tile != NULL) + && target->tile != NULL) || (action_id_get_target_kind(wanted_action) == ATK_EXTRAS - && target_tile != NULL) + && target->tile != NULL) || (action_id_get_target_kind(wanted_action) == ATK_UNIT - && target_unit != NULL) + && target->unit != NULL) || (action_id_get_target_kind(wanted_action) == ATK_UNITS /* At this level each individual unit is tested. */ - && target_unit != NULL) + && target->unit != NULL) || (action_id_get_target_kind(wanted_action) == ATK_SELF), "Missing target!"); @@ -3805,21 +3790,21 @@ is_action_possible(const action_id wanted_action, /* Only check requirement against the target unit if the actor can see it * or if the evaluator is omniscient. The game checking the rules is * omniscient. The player asking about their odds isn't. */ - can_see_tgt_unit = (omniscient || (target_unit - && can_player_see_unit(actor_player, - target_unit))); + can_see_tgt_unit = (omniscient || (target->unit + && can_player_see_unit(actor->player, + target->unit))); /* Only check requirement against the target tile if the actor can see it * or if the evaluator is omniscient. The game checking the rules is * omniscient. The player asking about their odds isn't. */ can_see_tgt_tile = (omniscient - || plr_sees_tile(actor_player, target_tile)); + || plr_sees_tile(actor->player, target->tile)); /* Info leak: The player knows where their unit is. */ if (action_get_target_kind(paction) != ATK_SELF && !action_distance_accepted(paction, - real_map_distance(actor_tile, - target_tile))) { + real_map_distance(actor->tile, + target->tile))) { /* The distance between the actor and the target isn't inside the * action's accepted range. */ return TRI_NO; @@ -3835,7 +3820,7 @@ is_action_possible(const action_id wanted_action, * and target is acceptable would leak distance to target unit if the * target unit can't be seen. */ - if (!can_player_see_unit(actor_player, target_unit)) { + if (!can_player_see_unit(actor->player, target->unit)) { return TRI_NO; } break; @@ -3843,9 +3828,9 @@ is_action_possible(const action_id wanted_action, /* The Freeciv code assumes that the player is aware of the target * city's existence. (How can you order an airlift to a city when you * don't know its city ID?) */ - if (fc_funcs->player_tile_city_id_get(city_tile(target_city), - actor_player) - != target_city->id) { + if (fc_funcs->player_tile_city_id_get(city_tile(target->city), + actor->player) + != target->city->id) { return TRI_NO; } break; @@ -3860,19 +3845,15 @@ is_action_possible(const action_id wanted_action, break; } - if (action_is_blocked_by(paction, actor_unit, - target_tile, target_city, target_unit)) { + if (action_is_blocked_by(paction, actor->unit, + target->tile, target->city, target->unit)) { /* Allows an action to block an other action. If a blocking action is * legal the actions it blocks becomes illegal. */ return TRI_NO; } /* Actor specific hard requirements. */ - out = action_hard_reqs_actor(paction, - actor_player, actor_city, actor_building, - actor_tile, actor_unit, actor_unittype, - actor_output, actor_specialist, - omniscient, homecity); + out = action_hard_reqs_actor(paction, actor, omniscient, homecity); if (out == TRI_NO) { /* Illegal because of a hard actor requirement. */ @@ -3896,8 +3877,8 @@ is_action_possible(const action_id wanted_action, return TRI_MAYBE; } - if (utype_player_already_has_this_unique(actor_player, - target_unittype)) { + if (utype_player_already_has_this_unique(actor->player, + target->unittype)) { return TRI_NO; } @@ -3911,17 +3892,17 @@ is_action_possible(const action_id wanted_action, /* Reason: The Freeciv code don't support selecting a target tech * unless it is known that the victim player has it. */ /* Info leak: The actor player knowns whose techs they can see. */ - if (!can_see_techs_of_target(actor_player, target_player)) { + if (!can_see_techs_of_target(actor->player, target->player)) { return TRI_NO; } break; case ACTRES_SPY_STEAL_GOLD: - /* If actor_unit can do the action the actor_player can see how much - * gold target_player have. Not requireing it is therefore pointless. + /* If actor->unit can do the action the actor->player can see how much + * gold target->player have. Not requireing it is therefore pointless. */ - if (target_player->economic.gold <= 0) { + if (target->player->economic.gold <= 0) { return TRI_NO; } @@ -3937,14 +3918,14 @@ is_action_possible(const action_id wanted_action, * cities can't trade at all. */ /* TODO: Should this restriction (and the above restriction that the * actor unit must have a home city) be kept for Enter Marketplace? */ - if (!can_cities_trade(homecity, target_city)) { + if (!can_cities_trade(homecity, target->city)) { return TRI_NO; } /* There are more restrictions on establishing a trade route than on * entering the market place. */ if (action_has_result(paction, ACTRES_TRADE_ROUTE) - && !can_establish_trade_route(homecity, target_city)) { + && !can_establish_trade_route(homecity, target->city)) { return TRI_NO; } } @@ -3960,12 +3941,12 @@ is_action_possible(const action_id wanted_action, * been hurried (bought or helped). The information isn't revealed when * asking for action probabilities since omniscient is FALSE. */ if (!omniscient - && !can_player_see_city_internals(actor_player, target_city)) { + && !can_player_see_city_internals(actor->player, target->city)) { return TRI_MAYBE; } - if (!(target_city->shield_stock - < city_production_build_shield_cost(target_city))) { + if (!(target->city->shield_stock + < city_production_build_shield_cost(target->city))) { return TRI_NO; } @@ -3978,20 +3959,20 @@ is_action_possible(const action_id wanted_action, return TRI_NO; } - if (can_see_tgt_tile && tile_city(target_tile)) { + if (can_see_tgt_tile && tile_city(target->tile)) { /* Reason: a tile can have 0 or 1 cities. */ return TRI_NO; } - if (citymindist_prevents_city_on_tile(target_tile)) { + if (citymindist_prevents_city_on_tile(target->tile)) { if (omniscient) { /* No need to check again. */ return TRI_NO; } else { - square_iterate(&(wld.map), target_tile, + square_iterate(&(wld.map), target->tile, game.info.citymindist - 1, otile) { if (tile_city(otile) != NULL - && plr_sees_tile(actor_player, otile)) { + && plr_sees_tile(actor->player, otile)) { /* Known to be blocked by citymindist */ return TRI_NO; } @@ -4010,9 +3991,9 @@ is_action_possible(const action_id wanted_action, if (!omniscient) { /* The player may not have enough information to find out if * citymindist blocks or not. This doesn't depend on if it blocks. */ - square_iterate(&(wld.map), target_tile, + square_iterate(&(wld.map), target->tile, game.info.citymindist - 1, otile) { - if (!plr_sees_tile(actor_player, otile)) { + if (!plr_sees_tile(actor->player, otile)) { /* Could have a city that blocks via citymindist. Even if this * tile has TER_NO_CITIES terrain the player don't know that it * didn't change and had a city built on it. */ @@ -4028,18 +4009,18 @@ is_action_possible(const action_id wanted_action, int new_pop; if (!omniscient - && !player_can_see_city_externals(actor_player, target_city)) { + && !player_can_see_city_externals(actor->player, target->city)) { return TRI_MAYBE; } - new_pop = city_size_get(target_city) + unit_pop_value(actor_unit); + new_pop = city_size_get(target->city) + unit_pop_value(actor->unit); if (new_pop > game.info.add_to_size_limit) { /* Reason: Make the add_to_size_limit setting work. */ return TRI_NO; } - if (!city_can_grow_to(target_city, new_pop)) { + if (!city_can_grow_to(target->city, new_pop)) { /* Reason: respect city size limits. */ /* Info leak: when it is legal to join a foreign city is legal and * the EFT_SIZE_UNLIMIT effect or the EFT_SIZE_ADJ effect depends on @@ -4053,7 +4034,8 @@ is_action_possible(const action_id wanted_action, break; case ACTRES_NUKE_UNITS: - if (unit_attack_units_at_tile_result(actor_unit, paction, target_tile) + if (unit_attack_units_at_tile_result(actor->unit, paction, + target->tile) != ATT_OK) { /* Unreachable. */ return TRI_NO; @@ -4064,15 +4046,15 @@ is_action_possible(const action_id wanted_action, case ACTRES_HOME_CITY: /* Reason: can't change to what is. */ /* Info leak: The player knows their unit's current home city. */ - if (homecity != NULL && homecity->id == target_city->id) { + if (homecity != NULL && homecity->id == target->city->id) { /* This is already the unit's home city. */ return TRI_NO; } { - int slots = unit_type_get(actor_unit)->city_slots; + int slots = unit_type_get(actor->unit)->city_slots; - if (slots > 0 && city_unit_slots_available(target_city) < slots) { + if (slots > 0 && city_unit_slots_available(target->city) < slots) { return TRI_NO; } } @@ -4093,7 +4075,7 @@ is_action_possible(const action_id wanted_action, * of cargo, they can predict if there will be enough room in the unit * upgraded to, as long as they know what unit type their unit will end * up as. */ - if (unit_upgrade_test(actor_unit, FALSE) != UU_OK) { + if (unit_upgrade_test(actor->unit, FALSE) != UU_OK) { return TRI_NO; } @@ -4103,33 +4085,33 @@ is_action_possible(const action_id wanted_action, case ACTRES_PARADROP_CONQUER: /* Reason: Keep the old rules. */ /* Info leak: The player knows if they know the target tile. */ - if (!plr_knows_tile(actor_player, target_tile)) { + if (!plr_knows_tile(actor->player, target->tile)) { return TRI_NO; } - if (plr_sees_tile(actor_player, target_tile)) { + if (plr_sees_tile(actor->player, target->tile)) { /* Check for seen stuff that may kill the actor unit. */ /* Reason: Keep the old rules. Be merciful. */ /* Info leak: The player sees the target tile. */ - if (!can_unit_exist_at_tile(&(wld.map), actor_unit, target_tile) + if (!can_unit_exist_at_tile(&(wld.map), actor->unit, target->tile) && (!BV_ISSET(paction->sub_results, ACT_SUB_RES_MAY_EMBARK) - || !unit_could_load_at(actor_unit, target_tile))) { + || !unit_could_load_at(actor->unit, target->tile))) { return TRI_NO; } /* Reason: Keep the old rules. Be merciful. */ /* Info leak: The player sees the target tile. */ - if (is_non_attack_city_tile(target_tile, actor_player)) { + if (is_non_attack_city_tile(target->tile, actor->player)) { return TRI_NO; } /* Reason: Be merciful. */ /* Info leak: The player sees all units checked. Invisible units are * ignored. */ - unit_list_iterate(target_tile->units, pother) { - if (can_player_see_unit(actor_player, pother) - && !pplayers_allied(actor_player, unit_owner(pother))) { + unit_list_iterate(target->tile->units, pother) { + if (can_player_see_unit(actor->player, pother) + && !pplayers_allied(actor->player, unit_owner(pother))) { return TRI_NO; } } unit_list_iterate_end; @@ -4138,8 +4120,8 @@ is_action_possible(const action_id wanted_action, /* Reason: Keep paratroopers_range working. */ /* Info leak: The player knows the location of the actor and of the * target tile. */ - if (unit_type_get(actor_unit)->paratroopers_range - < real_map_distance(actor_tile, target_tile)) { + if (unit_type_get(actor->unit)->paratroopers_range + < real_map_distance(actor->tile, target->tile)) { return TRI_NO; } @@ -4148,8 +4130,8 @@ is_action_possible(const action_id wanted_action, case ACTRES_AIRLIFT: /* Reason: Keep the old rules. */ /* Info leak: same as test_unit_can_airlift_to() */ - switch (test_unit_can_airlift_to(omniscient ? NULL : actor_player, - actor_unit, target_city)) { + switch (test_unit_can_airlift_to(omniscient ? NULL : actor->player, + actor->unit, target->city)) { case AR_OK: return TRI_YES; case AR_OK_SRC_UNKNOWN: @@ -4170,18 +4152,18 @@ is_action_possible(const action_id wanted_action, case ACTRES_ATTACK: /* Reason: Keep the old rules. */ - if (!can_unit_attack_tile(actor_unit, paction, target_tile)) { + if (!can_unit_attack_tile(actor->unit, paction, target->tile)) { return TRI_NO; } break; case ACTRES_WIPE_UNITS: - if (!can_unit_attack_tile(actor_unit, paction, target_tile)) { + if (!can_unit_attack_tile(actor->unit, paction, target->tile)) { return TRI_NO; } - unit_list_iterate(target_tile->units, punit) { - if (get_total_defense_power(actor_unit, punit) > 0) { + unit_list_iterate(target->tile->units, punit) { + if (get_total_defense_power(actor->unit, punit) > 0) { return TRI_NO; } } unit_list_iterate_end; @@ -4189,7 +4171,7 @@ is_action_possible(const action_id wanted_action, case ACTRES_CONQUER_CITY: /* Reason: "Conquer City" involves moving into the city. */ - if (!unit_can_move_to_tile(&(wld.map), actor_unit, target_tile, + if (!unit_can_move_to_tile(&(wld.map), actor->unit, target->tile, FALSE, FALSE, TRUE)) { return TRI_NO; } @@ -4198,7 +4180,7 @@ is_action_possible(const action_id wanted_action, case ACTRES_CONQUER_EXTRAS: /* Reason: "Conquer Extras" involves moving to the tile. */ - if (!unit_can_move_to_tile(&(wld.map), actor_unit, target_tile, + if (!unit_can_move_to_tile(&(wld.map), actor->unit, target->tile, FALSE, FALSE, FALSE)) { return TRI_NO; } @@ -4207,7 +4189,7 @@ is_action_possible(const action_id wanted_action, * unit_move(), in action_actor_utype_hard_reqs_ok_full(), in * helptext_extra(), in helptext_unit(), in do_attack() and in * diplomat_bribe(). */ - if (!tile_has_claimable_base(target_tile, actor_unittype)) { + if (!tile_has_claimable_base(target->tile, actor->unittype)) { return TRI_NO; } break; @@ -4215,45 +4197,45 @@ is_action_possible(const action_id wanted_action, case ACTRES_HEAL_UNIT: /* Reason: It is not the healthy who need a doctor, but the sick. */ /* Info leak: the actor can see the target's HP. */ - if (!(target_unit->hp < target_unittype->hp)) { + if (!(target->unit->hp < target->unittype->hp)) { return TRI_NO; } break; case ACTRES_TRANSFORM_TERRAIN: - pterrain = tile_terrain(target_tile); + pterrain = tile_terrain(target->tile); if (pterrain->transform_result == T_NONE || pterrain == pterrain->transform_result - || !terrain_surroundings_allow_change(target_tile, + || !terrain_surroundings_allow_change(target->tile, pterrain->transform_result) || (terrain_has_flag(pterrain->transform_result, TER_NO_CITIES) - && (tile_city(target_tile)))) { + && (tile_city(target->tile)))) { return TRI_NO; } break; case ACTRES_CULTIVATE: - pterrain = tile_terrain(target_tile); + pterrain = tile_terrain(target->tile); if (pterrain->cultivate_result == NULL) { return TRI_NO; } - if (!terrain_surroundings_allow_change(target_tile, + if (!terrain_surroundings_allow_change(target->tile, pterrain->cultivate_result) || (terrain_has_flag(pterrain->cultivate_result, TER_NO_CITIES) - && tile_city(target_tile))) { + && tile_city(target->tile))) { return TRI_NO; } break; case ACTRES_PLANT: - pterrain = tile_terrain(target_tile); + pterrain = tile_terrain(target->tile); if (pterrain->plant_result == NULL) { return TRI_NO; } - if (!terrain_surroundings_allow_change(target_tile, + if (!terrain_surroundings_allow_change(target->tile, pterrain->plant_result) || (terrain_has_flag(pterrain->plant_result, TER_NO_CITIES) - && tile_city(target_tile))) { + && tile_city(target->tile))) { return TRI_NO; } break; @@ -4266,7 +4248,8 @@ is_action_possible(const action_id wanted_action, /* Reason: This is not a road. */ return TRI_NO; } - if (!can_build_road(extra_road_get(target_extra), actor_unit, target_tile)) { + if (!can_build_road(extra_road_get(target_extra), actor->unit, + target->tile)) { return TRI_NO; } break; @@ -4279,8 +4262,8 @@ is_action_possible(const action_id wanted_action, /* Reason: This is not a base. */ return TRI_NO; } - if (!can_build_base(actor_unit, - extra_base_get(target_extra), target_tile)) { + if (!can_build_base(actor->unit, + extra_base_get(target_extra), target->tile)) { return TRI_NO; } break; @@ -4294,7 +4277,7 @@ is_action_possible(const action_id wanted_action, return TRI_NO; } - if (!can_build_extra(target_extra, actor_unit, target_tile)) { + if (!can_build_extra(target_extra, actor->unit, target->tile)) { return TRI_NO; } break; @@ -4308,20 +4291,20 @@ is_action_possible(const action_id wanted_action, return TRI_NO; } - if (!can_build_extra(target_extra, actor_unit, target_tile)) { + if (!can_build_extra(target_extra, actor->unit, target->tile)) { return TRI_NO; } break; case ACTRES_PILLAGE: - pterrain = tile_terrain(target_tile); + pterrain = tile_terrain(target->tile); if (pterrain->pillage_time == 0) { return TRI_NO; } { - bv_extras pspresent = get_tile_infrastructure_set(target_tile, NULL); - bv_extras psworking = get_unit_tile_pillage_set(target_tile); + bv_extras pspresent = get_tile_infrastructure_set(target->tile, NULL); + bv_extras psworking = get_unit_tile_pillage_set(target->tile); bv_extras pspossible; BV_CLR_ALL(pspossible); @@ -4331,8 +4314,8 @@ is_action_possible(const action_id wanted_action, /* Only one unit can pillage a given improvement at a time */ if (BV_ISSET(pspresent, idx) && (!BV_ISSET(psworking, idx) - || actor_unit->activity_target == pextra) - && can_remove_extra(pextra, actor_unit, target_tile)) { + || actor->unit->activity_target == pextra) + && can_remove_extra(pextra, actor->unit, target->tile)) { bool required = FALSE; extra_type_iterate(pdepending) { @@ -4385,7 +4368,7 @@ is_action_possible(const action_id wanted_action, { const struct extra_type *pextra; - pterrain = tile_terrain(target_tile); + pterrain = tile_terrain(target->tile); if (pterrain->clean_pollution_time == 0) { return TRI_NO; } @@ -4395,10 +4378,10 @@ is_action_possible(const action_id wanted_action, } else { /* TODO: Make sure that all callers set target so that * we don't need this fallback. */ - pextra = prev_extra_in_tile(target_tile, + pextra = prev_extra_in_tile(target->tile, ERM_CLEANPOLLUTION, - actor_player, - actor_unit); + actor->player, + actor->unit); if (pextra == NULL) { /* No available pollution extras */ return TRI_NO; @@ -4409,11 +4392,11 @@ is_action_possible(const action_id wanted_action, return TRI_NO; } - if (!can_remove_extra(pextra, actor_unit, target_tile)) { + if (!can_remove_extra(pextra, actor->unit, target->tile)) { return TRI_NO; } - if (tile_has_extra(target_tile, pextra)) { + if (tile_has_extra(target->tile, pextra)) { return TRI_YES; } @@ -4425,7 +4408,7 @@ is_action_possible(const action_id wanted_action, { const struct extra_type *pextra; - pterrain = tile_terrain(target_tile); + pterrain = tile_terrain(target->tile); if (pterrain->clean_fallout_time == 0) { return TRI_NO; } @@ -4435,10 +4418,10 @@ is_action_possible(const action_id wanted_action, } else { /* TODO: Make sure that all callers set target so that * we don't need this fallback. */ - pextra = prev_extra_in_tile(target_tile, + pextra = prev_extra_in_tile(target->tile, ERM_CLEANFALLOUT, - actor_player, - actor_unit); + actor->player, + actor->unit); if (pextra == NULL) { /* No available pollution extras */ return TRI_NO; @@ -4449,11 +4432,11 @@ is_action_possible(const action_id wanted_action, return TRI_NO; } - if (!can_remove_extra(pextra, actor_unit, target_tile)) { + if (!can_remove_extra(pextra, actor->unit, target->tile)) { return TRI_NO; } - if (tile_has_extra(target_tile, pextra)) { + if (tile_has_extra(target->tile, pextra)) { return TRI_YES; } @@ -4462,38 +4445,39 @@ is_action_possible(const action_id wanted_action, break; case ACTRES_TRANSPORT_ALIGHT: - if (!can_unit_unload(actor_unit, target_unit)) { + if (!can_unit_unload(actor->unit, target->unit)) { /* Keep the old rules about Unreachable and disembarks. */ return TRI_NO; } break; case ACTRES_TRANSPORT_BOARD: - if (unit_transported(actor_unit)) { - if (target_unit == unit_transport_get(actor_unit)) { + if (unit_transported(actor->unit)) { + if (target->unit == unit_transport_get(actor->unit)) { /* Already inside this transport. */ return TRI_NO; } } - if (!could_unit_load(actor_unit, target_unit)) { + if (!could_unit_load(actor->unit, target->unit)) { /* Keep the old rules. */ return TRI_NO; } break; case ACTRES_TRANSPORT_LOAD: - if (unit_transported(target_unit)) { - if (actor_unit == unit_transport_get(target_unit)) { + if (unit_transported(target->unit)) { + if (actor->unit == unit_transport_get(target->unit)) { /* Already transporting this unit. */ return TRI_NO; } } - if (!could_unit_load(target_unit, actor_unit)) { + if (!could_unit_load(target->unit, actor->unit)) { /* Keep the old rules. */ return TRI_NO; } - if (unit_transported(target_unit)) { - if (!can_unit_unload(target_unit, unit_transport_get(target_unit))) { + if (unit_transported(target->unit)) { + if (!can_unit_unload(target->unit, + unit_transport_get(target->unit))) { /* Can't leave current transport. */ return TRI_NO; } @@ -4501,14 +4485,14 @@ is_action_possible(const action_id wanted_action, break; case ACTRES_TRANSPORT_UNLOAD: - if (!can_unit_unload(target_unit, actor_unit)) { + if (!can_unit_unload(target->unit, actor->unit)) { /* Keep the old rules about Unreachable and disembarks. */ return TRI_NO; } break; case ACTRES_TRANSPORT_DISEMBARK: - if (!unit_can_move_to_tile(&(wld.map), actor_unit, target_tile, + if (!unit_can_move_to_tile(&(wld.map), actor->unit, target->tile, FALSE, FALSE, FALSE)) { /* Reason: involves moving to the tile. */ return TRI_NO; @@ -4516,11 +4500,11 @@ is_action_possible(const action_id wanted_action, /* We cannot move a transport into a tile that holds * units or cities not allied with all of our cargo. */ - if (get_transporter_capacity(actor_unit) > 0) { - unit_list_iterate(unit_tile(actor_unit)->units, pcargo) { - if (unit_contained_in(pcargo, actor_unit) - && (is_non_allied_unit_tile(target_tile, unit_owner(pcargo)) - || is_non_allied_city_tile(target_tile, + if (get_transporter_capacity(actor->unit) > 0) { + unit_list_iterate(unit_tile(actor->unit)->units, pcargo) { + if (unit_contained_in(pcargo, actor->unit) + && (is_non_allied_unit_tile(target->tile, unit_owner(pcargo)) + || is_non_allied_city_tile(target->tile, unit_owner(pcargo)))) { return TRI_NO; } @@ -4529,28 +4513,28 @@ is_action_possible(const action_id wanted_action, break; case ACTRES_TRANSPORT_EMBARK: - if (unit_transported(actor_unit)) { - if (target_unit == unit_transport_get(actor_unit)) { + if (unit_transported(actor->unit)) { + if (target->unit == unit_transport_get(actor->unit)) { /* Already inside this transport. */ return TRI_NO; } } - if (!could_unit_load(actor_unit, target_unit)) { + if (!could_unit_load(actor->unit, target->unit)) { /* Keep the old rules. */ return TRI_NO; } - if (!unit_can_move_to_tile(&(wld.map), actor_unit, target_tile, + if (!unit_can_move_to_tile(&(wld.map), actor->unit, target->tile, FALSE, TRUE, FALSE)) { /* Reason: involves moving to the tile. */ return TRI_NO; } /* We cannot move a transport into a tile that holds * units or cities not allied with all of our cargo. */ - if (get_transporter_capacity(actor_unit) > 0) { - unit_list_iterate(unit_tile(actor_unit)->units, pcargo) { - if (unit_contained_in(pcargo, actor_unit) - && (is_non_allied_unit_tile(target_tile, unit_owner(pcargo)) - || is_non_allied_city_tile(target_tile, + if (get_transporter_capacity(actor->unit) > 0) { + unit_list_iterate(unit_tile(actor->unit)->units, pcargo) { + if (unit_contained_in(pcargo, actor->unit) + && (is_non_allied_unit_tile(target->tile, unit_owner(pcargo)) + || is_non_allied_city_tile(target->tile, unit_owner(pcargo)))) { return TRI_NO; } @@ -4563,17 +4547,17 @@ is_action_possible(const action_id wanted_action, bool found; if (!omniscient - && !can_player_see_hypotetic_units_at(actor_player, - target_tile)) { + && !can_player_see_hypotetic_units_at(actor->player, + target->tile)) { /* May have a hidden diplomatic defender. */ return TRI_MAYBE; } found = FALSE; - unit_list_iterate(target_tile->units, punit) { + unit_list_iterate(target->tile->units, punit) { struct player *uplayer = unit_owner(punit); - if (uplayer == actor_player) { + if (uplayer == actor->player) { /* Won't defend against its owner. */ continue; } @@ -4601,11 +4585,11 @@ is_action_possible(const action_id wanted_action, case ACTRES_HUT_ENTER: case ACTRES_HUT_FRIGHTEN: /* Reason: involves moving to the tile. */ - if (!unit_can_move_to_tile(&(wld.map), actor_unit, target_tile, + if (!unit_can_move_to_tile(&(wld.map), actor->unit, target->tile, FALSE, FALSE, FALSE)) { return TRI_NO; } - if (!unit_can_displace_hut(actor_unit, target_tile)) { + if (!unit_can_displace_hut(actor->unit, target->tile)) { /* Reason: keep extra rmreqs working. */ return TRI_NO; } @@ -4613,23 +4597,23 @@ is_action_possible(const action_id wanted_action, case ACTRES_UNIT_MOVE: /* Reason: is moving to the tile. */ - if (!unit_can_move_to_tile(&(wld.map), actor_unit, target_tile, + if (!unit_can_move_to_tile(&(wld.map), actor->unit, target->tile, FALSE, FALSE, FALSE)) { return TRI_NO; } /* Reason: Don't override "Transport Embark" */ - if (!can_unit_exist_at_tile(&(wld.map), actor_unit, target_tile)) { + if (!can_unit_exist_at_tile(&(wld.map), actor->unit, target->tile)) { return TRI_NO; } /* We cannot move a transport into a tile that holds * units or cities not allied with all of our cargo. */ - if (get_transporter_capacity(actor_unit) > 0) { - unit_list_iterate(unit_tile(actor_unit)->units, pcargo) { - if (unit_contained_in(pcargo, actor_unit) - && (is_non_allied_unit_tile(target_tile, unit_owner(pcargo)) - || is_non_allied_city_tile(target_tile, + if (get_transporter_capacity(actor->unit) > 0) { + unit_list_iterate(unit_tile(actor->unit)->units, pcargo) { + if (unit_contained_in(pcargo, actor->unit) + && (is_non_allied_unit_tile(target->tile, unit_owner(pcargo)) + || is_non_allied_city_tile(target->tile, unit_owner(pcargo)))) { return TRI_NO; } @@ -4640,7 +4624,7 @@ is_action_possible(const action_id wanted_action, case ACTRES_SPY_ESCAPE: /* Reason: Be merciful. */ /* Info leak: The player know if they have any cities. */ - if (city_list_size(actor_player->cities) < 1) { + if (city_list_size(actor->player->cities) < 1) { return TRI_NO; } break; @@ -4655,17 +4639,18 @@ is_action_possible(const action_id wanted_action, * what user really wants. * Allow bombing when player does not know if there's units in * target tile. */ - if (tile_city(target_tile) == NULL - && fc_funcs->player_tile_vision_get(target_tile, actor_player, V_MAIN) - && fc_funcs->player_tile_vision_get(target_tile, actor_player, + if (tile_city(target->tile) == NULL + && fc_funcs->player_tile_vision_get(target->tile, actor->player, + V_MAIN) + && fc_funcs->player_tile_vision_get(target->tile, actor->player, V_INVIS) - && fc_funcs->player_tile_vision_get(target_tile, actor_player, + && fc_funcs->player_tile_vision_get(target->tile, actor->player, V_SUBSURFACE)) { bool hiding_extra = FALSE; extra_type_iterate(pextra) { if (pextra->eus == EUS_HIDDEN - && tile_has_extra(target_tile, pextra)) { + && tile_has_extra(target->tile, pextra)) { hiding_extra = TRUE; break; } @@ -4674,8 +4659,8 @@ is_action_possible(const action_id wanted_action, if (!hiding_extra) { bool has_target = FALSE; - unit_list_iterate(target_tile->units, punit) { - if (is_unit_reachable_at(punit, actor_unit, target_tile)) { + unit_list_iterate(target->tile->units, punit) { + if (is_unit_reachable_at(punit, actor->unit, target->tile)) { has_target = TRUE; break; } @@ -4718,34 +4703,17 @@ is_action_possible(const action_id wanted_action, /**********************************************************************//** Return TRUE iff the action enabler is active + + actor may be NULL. This is equivalent to passing an empty context. + target may be NULL. This is equivalent to passing an empty context. **************************************************************************/ static bool is_enabler_active(const struct action_enabler *enabler, - const struct player *actor_player, - const struct city *actor_city, - const struct impr_type *actor_building, - const struct tile *actor_tile, - const struct unit *actor_unit, - const struct unit_type *actor_unittype, - const struct output_type *actor_output, - const struct specialist *actor_specialist, - const struct player *target_player, - const struct city *target_city, - const struct impr_type *target_building, - const struct tile *target_tile, - const struct unit *target_unit, - const struct unit_type *target_unittype, - const struct output_type *target_output, - const struct specialist *target_specialist) -{ - return are_reqs_active(actor_player, target_player, actor_city, - actor_building, actor_tile, - actor_unit, actor_unittype, - actor_output, actor_specialist, NULL, + const struct req_context *actor, + const struct req_context *target) +{ + return are_reqs_active(actor, target != NULL ? target->player : NULL, &enabler->actor_reqs, RPT_CERTAIN) - && are_reqs_active(target_player, actor_player, target_city, - target_building, target_tile, - target_unit, target_unittype, - target_output, target_specialist, NULL, + && are_reqs_active(target, actor != NULL ? actor->player : NULL, &enabler->target_reqs, RPT_CERTAIN); } @@ -4754,39 +4722,19 @@ static bool is_enabler_active(const struct action_enabler *enabler, Note that the action may disable it self because of hard requirements even if an action enabler returns TRUE. + + Passing NULL for actor or target is equivalent to passing an empty + context. This may or may not be legal depending on the action. **************************************************************************/ static bool is_action_enabled(const action_id wanted_action, - const struct player *actor_player, - const struct city *actor_city, - const struct impr_type *actor_building, - const struct tile *actor_tile, - const struct unit *actor_unit, - const struct unit_type *actor_unittype, - const struct output_type *actor_output, - const struct specialist *actor_specialist, - const struct player *target_player, - const struct city *target_city, - const struct impr_type *target_building, - const struct tile *target_tile, - const struct unit *target_unit, - const struct unit_type *target_unittype, - const struct output_type *target_output, - const struct specialist *target_specialist, + const struct req_context *actor, + const struct req_context *target, const struct extra_type *target_extra, const struct city *actor_home) { enum fc_tristate possible; - possible = is_action_possible(wanted_action, - actor_player, actor_city, - actor_building, actor_tile, - actor_unit, actor_unittype, - actor_output, actor_specialist, - target_player, target_city, - target_building, target_tile, - target_unit, target_unittype, - target_output, target_specialist, - target_extra, + possible = is_action_possible(wanted_action, actor, target, target_extra, TRUE, actor_home); if (possible != TRI_YES) { @@ -4801,14 +4749,7 @@ static bool is_action_enabled(const action_id wanted_action, action_enabler_list_iterate(action_enablers_for_action(wanted_action), enabler) { - if (is_enabler_active(enabler, actor_player, actor_city, - actor_building, actor_tile, - actor_unit, actor_unittype, - actor_output, actor_specialist, - target_player, target_city, - target_building, target_tile, - target_unit, target_unittype, - target_output, target_specialist)) { + if (is_enabler_active(enabler, actor, target)) { return TRUE; } } action_enabler_list_iterate_end; @@ -4863,13 +4804,21 @@ is_action_enabled_unit_on_city_full(const action_id wanted_action, target_utype = tgt_city_local_utype(target_city); return is_action_enabled(wanted_action, - unit_owner(actor_unit), tile_city(actor_tile), - NULL, actor_tile, - actor_unit, unit_type_get(actor_unit), - NULL, NULL, - city_owner(target_city), target_city, - target_building, city_tile(target_city), - NULL, target_utype, NULL, NULL, NULL, + &(const struct req_context) { + .player = unit_owner(actor_unit), + .city = tile_city(actor_tile), + .tile = actor_tile, + .unit = actor_unit, + .unittype = unit_type_get(actor_unit), + }, + &(const struct req_context) { + .player = city_owner(target_city), + .city = target_city, + .building = target_building, + .tile = city_tile(target_city), + .unittype = target_utype, + }, + NULL, actor_home); } @@ -4930,15 +4879,21 @@ is_action_enabled_unit_on_unit_full(const action_id wanted_action, } return is_action_enabled(wanted_action, - unit_owner(actor_unit), tile_city(actor_tile), - NULL, actor_tile, - actor_unit, unit_type_get(actor_unit), - NULL, NULL, - unit_owner(target_unit), - tile_city(unit_tile(target_unit)), NULL, - unit_tile(target_unit), - target_unit, unit_type_get(target_unit), - NULL, NULL, NULL, + &(const struct req_context) { + .player = unit_owner(actor_unit), + .city = tile_city(actor_tile), + .tile = actor_tile, + .unit = actor_unit, + .unittype = unit_type_get(actor_unit), + }, + &(const struct req_context) { + .player = unit_owner(target_unit), + .city = tile_city(unit_tile(target_unit)), + .tile = unit_tile(target_unit), + .unit = target_unit, + .unittype = unit_type_get(target_unit), + }, + NULL, actor_home); } @@ -4971,6 +4926,8 @@ is_action_enabled_unit_on_units_full(const action_id wanted_action, const struct tile *actor_tile, const struct tile *target_tile) { + const struct req_context *actor_ctxt; + if (actor_unit == NULL || target_tile == NULL || unit_list_size(target_tile->units) == 0) { /* Can't do an action when actor or target are missing. */ @@ -4999,17 +4956,24 @@ is_action_enabled_unit_on_units_full(const action_id wanted_action, return FALSE; } + actor_ctxt = &(const struct req_context) { + .player = unit_owner(actor_unit), + .city = tile_city(actor_tile), + .tile = actor_tile, + .unit = actor_unit, + .unittype = unit_type_get(actor_unit), + }; + unit_list_iterate(target_tile->units, target_unit) { - if (!is_action_enabled(wanted_action, - unit_owner(actor_unit), tile_city(actor_tile), - NULL, actor_tile, - actor_unit, unit_type_get(actor_unit), - NULL, NULL, - unit_owner(target_unit), - tile_city(unit_tile(target_unit)), NULL, - unit_tile(target_unit), - target_unit, unit_type_get(target_unit), - NULL, NULL, NULL, actor_home)) { + if (!is_action_enabled(wanted_action, actor_ctxt, + &(const struct req_context) { + .player = unit_owner(target_unit), + .city = tile_city(unit_tile(target_unit)), + .tile = unit_tile(target_unit), + .unit = target_unit, + .unittype = unit_type_get(target_unit), + }, + NULL, actor_home)) { /* One unit makes it impossible for all units. */ return FALSE; } @@ -5077,12 +5041,18 @@ is_action_enabled_unit_on_tile_full(const action_id wanted_action, } return is_action_enabled(wanted_action, - unit_owner(actor_unit), tile_city(actor_tile), - NULL, actor_tile, - actor_unit, unit_type_get(actor_unit), - NULL, NULL, - tile_owner(target_tile), tile_city(target_tile), - NULL, target_tile, NULL, NULL, NULL, NULL, + &(const struct req_context) { + .player = unit_owner(actor_unit), + .city = tile_city(actor_tile), + .tile = actor_tile, + .unit = actor_unit, + .unittype = unit_type_get(actor_unit), + }, + &(const struct req_context) { + .player = tile_owner(target_tile), + .city = tile_city(target_tile), + .tile = target_tile, + }, target_extra, actor_home); } @@ -5146,13 +5116,18 @@ is_action_enabled_unit_on_extras_full(const action_id wanted_action, } return is_action_enabled(wanted_action, - unit_owner(actor_unit), tile_city(actor_tile), - NULL, actor_tile, - actor_unit, unit_type_get(actor_unit), - NULL, NULL, - target_tile->extras_owner, - tile_city(target_tile), - NULL, target_tile, NULL, NULL, NULL, NULL, + &(const struct req_context) { + .player = unit_owner(actor_unit), + .city = tile_city(actor_tile), + .tile = actor_tile, + .unit = actor_unit, + .unittype = unit_type_get(actor_unit), + }, + &(const struct req_context) { + .player = target_tile->extras_owner, + .city = tile_city(target_tile), + .tile = target_tile, + }, target_extra, actor_home); } @@ -5215,11 +5190,14 @@ is_action_enabled_unit_on_self_full(const action_id wanted_action, } return is_action_enabled(wanted_action, - unit_owner(actor_unit), tile_city(actor_tile), - NULL, actor_tile, - actor_unit, unit_type_get(actor_unit), + &(const struct req_context) { + .player = unit_owner(actor_unit), + .city = tile_city(actor_tile), + .tile = actor_tile, + .unit = actor_unit, + .unittype = unit_type_get(actor_unit), + }, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, actor_home); } @@ -5253,42 +5231,35 @@ bool is_action_enabled_unit_on_self(const action_id wanted_action, TRI_MAYBE if the player don't know enough to tell. If meta knowledge is missing TRI_MAYBE will be returned. + + target may be NULL. This is equivalent to passing an empty context. **************************************************************************/ static enum fc_tristate action_enabled_local(const action_id wanted_action, - const struct player *actor_player, - const struct city *actor_city, - const struct impr_type *actor_building, - const struct tile *actor_tile, - const struct unit *actor_unit, - const struct output_type *actor_output, - const struct specialist *actor_specialist, - const struct player *target_player, - const struct city *target_city, - const struct impr_type *target_building, - const struct tile *target_tile, - const struct unit *target_unit, - const struct output_type *target_output, - const struct specialist *target_specialist) + const struct req_context *actor, + const struct req_context *target) { enum fc_tristate current; enum fc_tristate result; + if (actor == NULL || actor->player == NULL) { + /* Need actor->player for point of view */ + return TRI_MAYBE; + } + + if (target == NULL) { + target = req_context_empty(); + } + result = TRI_NO; action_enabler_list_iterate(action_enablers_for_action(wanted_action), enabler) { - current = fc_tristate_and(mke_eval_reqs(actor_player, actor_player, - target_player, actor_city, - actor_building, actor_tile, - actor_unit, actor_output, - actor_specialist, + current = fc_tristate_and(mke_eval_reqs(actor->player, actor, + target->player, &enabler->actor_reqs, RPT_CERTAIN), - mke_eval_reqs(actor_player, target_player, - actor_player, target_city, - target_building, target_tile, - target_unit, target_output, - target_specialist, + mke_eval_reqs(actor->player, target, + actor->player, &enabler->target_reqs, RPT_CERTAIN)); if (current == TRI_YES) { @@ -5307,24 +5278,17 @@ action_enabled_local(const action_id wanted_action, The knowledge of the actor is assumed to be given in the parameters. If meta knowledge is missing TRI_MAYBE will be returned. + + context may be NULL. This is equivalent to passing an empty context. **************************************************************************/ static bool is_effect_val_known(enum effect_type effect_type, - const struct player *pow_player, - const struct player *target_player, - const struct player *other_player, - const struct city *target_city, - const struct impr_type *target_building, - const struct tile *target_tile, - const struct unit *target_unit, - const struct output_type *target_output, - const struct specialist *target_specialist) + const struct player *pov_player, + const struct req_context *context, + const struct player *other_player) { effect_list_iterate(get_effects(effect_type), peffect) { - if (TRI_MAYBE == mke_eval_reqs(pow_player, target_player, - other_player, target_city, - target_building, target_tile, - target_unit, target_output, - target_specialist, + if (TRI_MAYBE == mke_eval_reqs(pov_player, context, + other_player, &(peffect->reqs), RPT_CERTAIN)) { return FALSE; } @@ -5416,21 +5380,24 @@ static struct act_prob ap_dipl_battle_win(const struct unit *pattacker, /* Defense bonus. */ { + const struct req_context defender_ctxt = { + .player = tile_owner(pdefender->tile), + .city = tile_city(pdefender->tile), + .tile = pdefender->tile, + }; if (!is_effect_val_known(EFT_SPY_RESISTANT, unit_owner(pattacker), - tile_owner(pdefender->tile), NULL, - tile_city(pdefender->tile), NULL, - pdefender->tile, NULL, NULL, NULL)) { + &defender_ctxt, + NULL)) { return ACTPROB_NOT_KNOWN; } /* Reduce the chance of an attack by EFT_SPY_RESISTANT percent. */ - chance -= chance - * get_target_bonus_effects(NULL, - tile_owner(pdefender->tile), NULL, - tile_city(pdefender->tile), NULL, - pdefender->tile, NULL, NULL, NULL, - NULL, NULL, - EFT_SPY_RESISTANT) / 100; + chance -= chance * get_target_bonus_effects( + NULL, + &defender_ctxt, + NULL, + EFT_SPY_RESISTANT + ) / 100; } /* Convert to action probability */ @@ -5499,11 +5466,20 @@ action_prob_pre_action_dice_roll(const struct player *act_player, const struct action *paction) { if (is_effect_val_known(EFT_ACTION_ODDS_PCT, act_player, - act_player, tgt_player, tgt_city, - NULL, NULL, act_unit, NULL, NULL) + &(const struct req_context) { + .player = act_player, + .city = tgt_city, + .unit = act_unit, + .unittype = unit_type_get(act_unit), + }, + tgt_player) && is_effect_val_known(EFT_ACTION_RESIST_PCT, act_player, - tgt_player, act_player, tgt_city, - NULL, NULL, act_unit, NULL, NULL)) { + &(const struct req_context) { + .player = tgt_player, + .city = tgt_city, + .unit = act_unit, + }, + act_player)) { int unconverted = action_dice_roll_odds(act_player, act_unit, tgt_city, tgt_player, paction); struct act_prob result = { .min = unconverted * ACTPROB_VAL_1_PCT, @@ -5570,56 +5546,30 @@ action_prob_battle_then_dice_roll(const struct player *act_player, actor survives. For actions that cost money it is assumed that the player has and is willing to spend the money. This is so the player can figure out what their odds are before deciding to get the extra money. + + Passing NULL for actor or target is equivalent to passing an empty + context. This may or may not be legal depending on the action. **************************************************************************/ static struct act_prob action_prob(const action_id wanted_action, - const struct player *actor_player, - const struct city *actor_city, - const struct impr_type *actor_building, - const struct tile *actor_tile, - const struct unit *actor_unit, - const struct unit_type *actor_unittype_p, - const struct output_type *actor_output, - const struct specialist *actor_specialist, + const struct req_context *actor, const struct city *actor_home, - const struct player *target_player, - const struct city *target_city, - const struct impr_type *target_building, - const struct tile *target_tile, - const struct unit *target_unit, - const struct unit_type *target_unittype_p, - const struct output_type *target_output, - const struct specialist *target_specialist, + const struct req_context *target, const struct extra_type *target_extra) { int known; struct act_prob chance; - const struct unit_type *actor_unittype; - const struct unit_type *target_unittype; const struct action *paction = action_by_number(wanted_action); - if (actor_unittype_p == NULL && actor_unit != NULL) { - actor_unittype = unit_type_get(actor_unit); - } else { - actor_unittype = actor_unittype_p; + if (actor == NULL) { + actor = req_context_empty(); + } + if (target == NULL) { + target = req_context_empty(); } - if (target_unittype_p == NULL && target_unit != NULL) { - target_unittype = unit_type_get(target_unit); - } else { - target_unittype = target_unittype_p; - } - - known = is_action_possible(wanted_action, - actor_player, actor_city, - actor_building, actor_tile, - actor_unit, actor_unittype, - actor_output, actor_specialist, - target_player, target_city, - target_building, target_tile, - target_unit, target_unittype, - target_output, target_specialist, + known = is_action_possible(wanted_action, actor, target, target_extra, FALSE, actor_home); @@ -5633,25 +5583,16 @@ action_prob(const action_id wanted_action, known = fc_tristate_and(known, action_enabled_local(wanted_action, - actor_player, actor_city, - actor_building, actor_tile, - actor_unit, - actor_output, - actor_specialist, - target_player, target_city, - target_building, target_tile, - target_unit, - target_output, - target_specialist)); + actor, target)); switch (paction->result) { case ACTRES_SPY_POISON: /* All uncertainty comes from potential diplomatic battles and the * (diplchance server setting and the) Action_Odds_Pct effect controlled * dice roll before the action. */ - chance = action_prob_battle_then_dice_roll(actor_player, actor_unit, - target_city, target_unit, - target_tile, target_player, + chance = action_prob_battle_then_dice_roll(actor->player, actor->unit, + target->city, target->unit, + target->tile, target->player, paction); break; case ACTRES_SPY_STEAL_GOLD: @@ -5665,17 +5606,17 @@ action_prob(const action_id wanted_action, break; case ACTRES_SPY_SABOTAGE_UNIT: /* All uncertainty comes from potential diplomatic battles. */ - chance = ap_diplomat_battle(actor_unit, target_unit, target_tile, + chance = ap_diplomat_battle(actor->unit, target->unit, target->tile, paction); break; case ACTRES_SPY_BRIBE_UNIT: /* All uncertainty comes from potential diplomatic battles. */ - chance = ap_diplomat_battle(actor_unit, target_unit, target_tile, + chance = ap_diplomat_battle(actor->unit, target->unit, target->tile, paction); break; case ACTRES_SPY_ATTACK: /* All uncertainty comes from potential diplomatic battles. */ - chance = ap_diplomat_battle(actor_unit, NULL, target_tile, + chance = ap_diplomat_battle(actor->unit, NULL, target->tile, paction); break; case ACTRES_SPY_SABOTAGE_CITY: @@ -5696,8 +5637,8 @@ action_prob(const action_id wanted_action, case ACTRES_SPY_STEAL_TECH: /* Do the victim have anything worth taking? */ known = fc_tristate_and(known, - tech_can_be_stolen(actor_player, - target_player)); + tech_can_be_stolen(actor->player, + target->player)); /* TODO: Calculate actual chance */ @@ -5705,8 +5646,8 @@ action_prob(const action_id wanted_action, case ACTRES_SPY_TARGETED_STEAL_TECH: /* Do the victim have anything worth taking? */ known = fc_tristate_and(known, - tech_can_be_stolen(actor_player, - target_player)); + tech_can_be_stolen(actor->player, + target->player)); /* TODO: Calculate actual chance */ @@ -5753,9 +5694,10 @@ action_prob(const action_id wanted_action, /* All uncertainty comes from potential diplomatic battles and the * (diplchance server setting and the) Action_Odds_Pct effect controlled * dice roll before the action. */ - chance = action_prob_battle_then_dice_roll(actor_player, actor_unit, - target_city, target_unit, - target_tile, target_player, + chance = action_prob_battle_then_dice_roll(actor->player, actor->unit, + target->city, target->unit, + target->tile, + target->player, paction); break; case ACTRES_NUKE: @@ -5798,11 +5740,11 @@ action_prob(const action_id wanted_action, break; case ACTRES_ATTACK: { - struct unit *defender_unit = get_defender(actor_unit, target_tile, + struct unit *defender_unit = get_defender(actor->unit, target->tile, paction); - if (can_player_see_unit(actor_player, defender_unit)) { - double unconverted = unit_win_chance(actor_unit, defender_unit, + if (can_player_see_unit(actor->player, defender_unit)) { + double unconverted = unit_win_chance(actor->unit, defender_unit, paction); chance.min = MAX(ACTPROB_VAL_MIN, @@ -5828,8 +5770,8 @@ action_prob(const action_id wanted_action, case ACTRES_STRIKE_PRODUCTION: /* All uncertainty comes from the (diplchance server setting and the) * Action_Odds_Pct effect controlled dice roll before the action. */ - chance = action_prob_pre_action_dice_roll(actor_player, actor_unit, - target_city, target_player, + chance = action_prob_pre_action_dice_roll(actor->player, actor->unit, + target->city, target->player, paction); break; case ACTRES_CONQUER_CITY: @@ -5989,12 +5931,21 @@ action_prob_vs_city_full(const struct unit* actor_unit, target_utype = tgt_city_local_utype(target_city); return action_prob(act_id, - unit_owner(actor_unit), tile_city(actor_tile), - NULL, actor_tile, actor_unit, NULL, - NULL, NULL, actor_home, - city_owner(target_city), target_city, - target_building, city_tile(target_city), - NULL, target_utype, NULL, NULL, NULL); + &(const struct req_context) { + .player = unit_owner(actor_unit), + .city = tile_city(actor_tile), + .tile = actor_tile, + .unit = actor_unit, + .unittype = unit_type_get(actor_unit), + }, + actor_home, + &(const struct req_context) { + .player = city_owner(target_city), + .city = target_city, + .building = target_building, + .tile = city_tile(target_city), + .unittype = target_utype, + }, NULL); } /**********************************************************************//** @@ -6060,14 +6011,22 @@ action_prob_vs_unit_full(const struct unit* actor_unit, } return action_prob(act_id, - unit_owner(actor_unit), tile_city(actor_tile), - NULL, actor_tile, actor_unit, NULL, - NULL, NULL, + &(const struct req_context) { + .player = unit_owner(actor_unit), + .city = tile_city(actor_tile), + .tile = actor_tile, + .unit = actor_unit, + .unittype = unit_type_get(actor_unit), + }, actor_home, - unit_owner(target_unit), - tile_city(unit_tile(target_unit)), NULL, - unit_tile(target_unit), - target_unit, NULL, NULL, NULL, NULL); + &(const struct req_context) { + .player = unit_owner(target_unit), + .city = tile_city(unit_tile(target_unit)), + .tile = unit_tile(target_unit), + .unit = target_unit, + .unittype = unit_type_get(target_unit), + }, + NULL); } /**********************************************************************//** @@ -6097,6 +6056,7 @@ action_prob_vs_units_full(const struct unit* actor_unit, const struct tile* target_tile) { struct act_prob prob_all; + const struct req_context *actor_ctxt; const struct action *act = action_by_number(act_id); if (actor_unit == NULL || target_tile == NULL) { @@ -6202,6 +6162,14 @@ action_prob_vs_units_full(const struct unit* actor_unit, target_tile) ? ACTPROB_CERTAIN : ACTPROB_NOT_KNOWN); + actor_ctxt = &(const struct req_context) { + .player = unit_owner(actor_unit), + .city = tile_city(actor_tile), + .tile = actor_tile, + .unit = actor_unit, + .unittype = unit_type_get(actor_unit), + }; + unit_list_iterate(target_tile->units, target_unit) { struct act_prob prob_unit; @@ -6211,17 +6179,15 @@ action_prob_vs_units_full(const struct unit* actor_unit, continue; } - prob_unit = action_prob(act_id, - unit_owner(actor_unit), - tile_city(actor_tile), - NULL, actor_tile, actor_unit, NULL, - NULL, NULL, - actor_home, - unit_owner(target_unit), - tile_city(unit_tile(target_unit)), NULL, - unit_tile(target_unit), - target_unit, NULL, NULL, - NULL, NULL); + prob_unit = action_prob(act_id, actor_ctxt, actor_home, + &(const struct req_context) { + .player = unit_owner(target_unit), + .city = tile_city(unit_tile(target_unit)), + .tile = unit_tile(target_unit), + .unit = target_unit, + .unittype = unit_type_get(target_unit), + }, + NULL); if (!action_prob_possible(prob_unit)) { /* One unit makes it impossible for all units. */ @@ -6316,11 +6282,20 @@ action_prob_vs_tile_full(const struct unit *actor_unit, } return action_prob(act_id, - unit_owner(actor_unit), tile_city(actor_tile), - NULL, actor_tile, actor_unit, NULL, - NULL, NULL, actor_home, - tile_owner(target_tile), tile_city(target_tile), NULL, - target_tile, NULL, NULL, NULL, NULL, target_extra); + &(const struct req_context) { + .player = unit_owner(actor_unit), + .city = tile_city(actor_tile), + .tile = actor_tile, + .unit = actor_unit, + .unittype = unit_type_get(actor_unit), + }, + actor_home, + &(const struct req_context) { + .player = tile_owner(target_tile), + .city = tile_city(target_tile), + .tile = target_tile, + }, + target_extra); } /**********************************************************************//** @@ -6388,12 +6363,20 @@ action_prob_vs_extras_full(const struct unit *actor_unit, } return action_prob(act_id, - unit_owner(actor_unit), tile_city(actor_tile), - NULL, actor_tile, actor_unit, NULL, - NULL, NULL, actor_home, - target_tile->extras_owner, tile_city(target_tile), - NULL, - target_tile, NULL, NULL, NULL, NULL, target_extra); + &(const struct req_context) { + .player = unit_owner(actor_unit), + .city = tile_city(actor_tile), + .tile = actor_tile, + .unit = actor_unit, + .unittype = unit_type_get(actor_unit), + }, + actor_home, + &(const struct req_context) { + .player = target_tile->extras_owner, + .city = tile_city(target_tile), + .tile = target_tile, + }, + target_extra); } /**********************************************************************//** @@ -6452,10 +6435,15 @@ action_prob_self_full(const struct unit* actor_unit, } return action_prob(act_id, - unit_owner(actor_unit), tile_city(actor_tile), - NULL, actor_tile, actor_unit, NULL, NULL, NULL, + &(const struct req_context) { + .player = unit_owner(actor_unit), + .city = tile_city(actor_tile), + .tile = actor_tile, + .unit = actor_unit, + .unittype = unit_type_get(actor_unit), + }, actor_home, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL); } @@ -7166,21 +7154,30 @@ int action_dice_roll_odds(const struct player *act_player, odds = odds + ((odds * get_target_bonus_effects(NULL, - act_player, tgt_player, - tgt_city, NULL, NULL, - act_unit, actu_type, - NULL, NULL, paction, + &(const struct req_context) { + .player = act_player, + .city = tgt_city, + .unit = act_unit, + .unittype = actu_type, + .action = paction, + }, + tgt_player, EFT_ACTION_ODDS_PCT)) / 100) - ((odds * get_target_bonus_effects(NULL, - tgt_player, act_player, - tgt_city, NULL, NULL, - act_unit, actu_type, - NULL, NULL, paction, + &(const struct req_context) { + .player = tgt_player, + .city = tgt_city, + .unit = act_unit, + .unittype = actu_type, + .action = paction, + }, + act_player, EFT_ACTION_RESIST_PCT)) / 100); + /* Odds are between 0% and 100%. */ return CLIP(0, odds, 100); } @@ -7208,24 +7205,16 @@ bool action_immune_government(struct government *gov, action_id act) /**********************************************************************//** Returns TRUE if the wanted action can be done to the target. + + target may be NULL. This is equivalent to passing an empty context. **************************************************************************/ static bool is_target_possible(const action_id wanted_action, - const struct player *actor_player, - const struct player *target_player, - const struct city *target_city, - const struct impr_type *target_building, - const struct tile *target_tile, - const struct unit *target_unit, - const struct unit_type *target_unittype, - const struct output_type *target_output, - const struct specialist *target_specialist) + const struct player *actor_player, + const struct req_context *target) { action_enabler_list_iterate(action_enablers_for_action(wanted_action), enabler) { - if (are_reqs_active(target_player, actor_player, target_city, - target_building, target_tile, - target_unit, target_unittype, - target_output, target_specialist, NULL, + if (are_reqs_active(target, actor_player, &enabler->target_reqs, RPT_POSSIBLE)) { return TRUE; } @@ -7248,9 +7237,11 @@ bool is_action_possible_on_city(action_id act_id, action_id_get_target_kind(act_id))); return is_target_possible(act_id, actor_player, - city_owner(target_city), target_city, NULL, - city_tile(target_city), NULL, NULL, - NULL, NULL); + &(const struct req_context) { + .player = city_owner(target_city), + .city = target_city, + .tile = city_tile(target_city), + }); } /**********************************************************************//** @@ -7262,9 +7253,13 @@ bool action_maybe_possible_actor_unit(const action_id act_id, const struct unit *actor_unit) { const struct player *actor_player = unit_owner(actor_unit); - const struct tile *actor_tile = unit_tile(actor_unit); - const struct city *actor_city = tile_city(actor_tile); - const struct unit_type *actor_unittype = unit_type_get(actor_unit); + const struct req_context actor_ctxt = { + .player = actor_player, + .city = tile_city(unit_tile(actor_unit)), + .tile = unit_tile(actor_unit), + .unit = actor_unit, + .unittype = unit_type_get(actor_unit), + }; const struct action *paction = action_by_number(act_id); enum fc_tristate result; @@ -7276,11 +7271,8 @@ bool action_maybe_possible_actor_unit(const action_id act_id, return FALSE; } - result = action_hard_reqs_actor(paction, - actor_player, actor_city, NULL, - actor_tile, actor_unit, actor_unittype, - NULL, NULL, FALSE, - game_city_by_number(actor_unit->homecity)); + result = action_hard_reqs_actor(paction, &actor_ctxt, FALSE, + unit_home(actor_unit)); if (result == TRI_NO) { /* The hard requirements aren't fulfilled. */ @@ -7290,9 +7282,7 @@ bool action_maybe_possible_actor_unit(const action_id act_id, action_enabler_list_iterate(action_enablers_for_action(act_id), enabler) { const enum fc_tristate current - = mke_eval_reqs(actor_player, - actor_player, NULL, actor_city, NULL, actor_tile, - actor_unit, NULL, NULL, + = mke_eval_reqs(actor_player, &actor_ctxt, NULL, &enabler->actor_reqs, /* Needed since no player to evaluate DiplRel * requirements against. */ diff --git a/common/base.c b/common/base.c index 2dba332c55..c87c542667 100644 --- a/common/base.c +++ b/common/base.c @@ -39,8 +39,11 @@ bool player_can_build_base(const struct base_type *pbase, pextra = base_extra_get(pbase); - return are_reqs_active(pplayer, tile_owner(ptile), NULL, NULL, ptile, - NULL, NULL, NULL, NULL, NULL, + return are_reqs_active(&(const struct req_context) { + .player = pplayer, + .tile = ptile, + }, + tile_owner(ptile), &pextra->reqs, RPT_POSSIBLE); } @@ -57,8 +60,13 @@ bool can_build_base(const struct unit *punit, const struct base_type *pbase, return FALSE; } - return are_reqs_active(pplayer, tile_owner(ptile), NULL, NULL, - ptile, punit, unit_type_get(punit), NULL, NULL, NULL, + return are_reqs_active(&(const struct req_context) { + .player = pplayer, + .tile = ptile, + .unit = punit, + .unittype = unit_type_get(punit), + }, + tile_owner(ptile), &pextra->reqs, RPT_CERTAIN); } diff --git a/common/city.c b/common/city.c index 05bb02af3e..fc3b2fbbc0 100644 --- a/common/city.c +++ b/common/city.c @@ -830,8 +830,12 @@ bool can_city_build_improvement_direct(const struct city *pcity, return FALSE; } - return are_reqs_active(city_owner(pcity), NULL, pcity, NULL, - pcity->tile, NULL, NULL, NULL, NULL, NULL, + return are_reqs_active(&(const struct req_context) { + .player = city_owner(pcity), + .city = pcity, + .tile = pcity->tile, + }, + NULL, &(pimprove->reqs), RPT_CERTAIN); } @@ -859,6 +863,12 @@ bool can_city_build_improvement_now(const struct city *pcity, bool can_city_build_improvement_later(const struct city *pcity, const struct impr_type *pimprove) { + const struct req_context city_ctxt = { + .player = city_owner(pcity), + .city = pcity, + .tile = city_tile(pcity), + }; + /* Can the _player_ ever build this improvement? */ if (!can_player_build_improvement_later(city_owner(pcity), pimprove)) { return FALSE; @@ -868,9 +878,7 @@ bool can_city_build_improvement_later(const struct city *pcity, * they can never be met). */ requirement_vector_iterate(&pimprove->reqs, preq) { if (is_req_unchanging(preq) - && !is_req_active(city_owner(pcity), NULL, pcity, NULL, - pcity->tile, NULL, NULL, NULL, NULL, NULL, - preq, RPT_POSSIBLE)) { + && !is_req_active(&city_ctxt, NULL, preq, RPT_POSSIBLE)) { return FALSE; } } requirement_vector_iterate_end; @@ -890,9 +898,13 @@ bool can_city_build_unit_direct(const struct city *pcity, } /* Check unit build requirements. */ - if (!are_reqs_active(city_owner(pcity), NULL, - pcity, NULL, city_tile(pcity), NULL, punittype, - NULL, NULL, NULL, + 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)) { return FALSE; } @@ -1028,9 +1040,12 @@ int city_unit_slots_available(const struct city *pcity) bool city_can_use_specialist(const struct city *pcity, Specialist_type_id type) { - return are_reqs_active(city_owner(pcity), NULL, pcity, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, - &specialist_by_number(type)->reqs, RPT_POSSIBLE); + return are_reqs_active(&(const struct req_context) { + .player = city_owner(pcity), + .city = pcity, + }, + NULL, + &specialist_by_number(type)->reqs, RPT_POSSIBLE); } /**********************************************************************//** @@ -1233,9 +1248,13 @@ int city_tile_output(const struct city *pcity, const struct tile *ptile, bool is_celebrating, Output_type_id otype) { int prod; + const struct req_context city_ctxt = { + .player = pcity ? city_owner(pcity) : NULL, + .city = pcity, + .tile = ptile, + }; struct terrain *pterrain = tile_terrain(ptile); const struct output_type *output = &output_types[otype]; - struct player *pplayer = NULL; fc_assert_ret_val(otype >= 0 && otype < O_LAST, 0); @@ -1250,27 +1269,19 @@ int city_tile_output(const struct city *pcity, const struct tile *ptile, prod += tile_resource(ptile)->data.resource->output[otype]; } - if (pcity != NULL) { - pplayer = city_owner(pcity); - } - switch (otype) { case O_SHIELD: if (pterrain->mining_shield_incr != 0) { prod += pterrain->mining_shield_incr - * get_target_bonus_effects(NULL, pplayer, NULL, pcity, NULL, - ptile, NULL, NULL, NULL, NULL, NULL, - EFT_MINING_PCT) + * get_target_bonus_effects(NULL, &city_ctxt, NULL, EFT_MINING_PCT) / 100; } break; case O_FOOD: if (pterrain->irrigation_food_incr != 0) { prod += pterrain->irrigation_food_incr - * get_target_bonus_effects(NULL, pplayer, NULL, pcity, NULL, - ptile, NULL, NULL, NULL, NULL, NULL, - EFT_IRRIGATION_PCT) - / 100; + * get_target_bonus_effects(NULL, &city_ctxt, NULL, + EFT_IRRIGATION_PCT) / 100; } break; case O_TRADE: diff --git a/common/combat.c b/common/combat.c index b5edd61120..14114276e0 100644 --- a/common/combat.c +++ b/common/combat.c @@ -505,12 +505,14 @@ struct city *sdi_try_defend(const struct player *owner, struct city *pcity = tile_city(ptile1); if (pcity - && fc_rand(100) < get_target_bonus_effects(NULL, - city_owner(pcity), owner, - pcity, NULL, ptile, - NULL, NULL, - NULL, NULL, NULL, - EFT_NUKE_PROOF)) { + && fc_rand(100) + < get_target_bonus_effects(NULL, + &(const struct req_context) { + .player = city_owner(pcity), + .city = pcity, + .tile = ptile, + }, + owner, EFT_NUKE_PROOF)) { return pcity; } } square_iterate_end; @@ -675,9 +677,15 @@ static int defense_multiplication(const struct unit_type *att_type, defensepower = defensepower * (100 - + get_target_bonus_effects(NULL, unit_owner(def), NULL, - pcity, NULL, ptile, def, - unit_type_get(def), NULL, NULL, NULL, + + get_target_bonus_effects(NULL, + &(const struct req_context) { + .player = unit_owner(def), + .city = pcity, + .tile = ptile, + .unit = def, + .unittype = unit_type_get(def), + }, + NULL, EFT_FORTIFY_DEFENSE_BONUS)) / 100; return defensepower; diff --git a/common/diptreaty.c b/common/diptreaty.c index 5d007c2ce4..650ff84d50 100644 --- a/common/diptreaty.c +++ b/common/diptreaty.c @@ -183,12 +183,11 @@ bool add_clause(struct Treaty *ptreaty, struct player *pfrom, return FALSE; } - if (!are_reqs_active(pfrom, pto, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - &clause_infos[type].giver_reqs, RPT_POSSIBLE) - || !are_reqs_active(pto, pfrom, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - &clause_infos[type].receiver_reqs, RPT_POSSIBLE)) { + if (!are_reqs_active(&(const struct req_context) { .player = pfrom }, + pto, &clause_infos[type].giver_reqs, RPT_POSSIBLE) + || !are_reqs_active(&(const struct req_context) { .player = pto }, + pfrom, &clause_infos[type].receiver_reqs, + RPT_POSSIBLE)) { return FALSE; } diff --git a/common/disaster.c b/common/disaster.c index e2e1722e4d..9cfb2a0c85 100644 --- a/common/disaster.c +++ b/common/disaster.c @@ -139,7 +139,11 @@ bool disaster_has_effect(const struct disaster_type *pdis, bool can_disaster_happen(const struct disaster_type *pdis, const struct city *pcity) { - return are_reqs_active(city_owner(pcity), NULL, pcity, NULL, - city_tile(pcity), NULL, NULL, NULL, NULL, NULL, + return are_reqs_active(&(const struct req_context) { + .player = city_owner(pcity), + .city = pcity, + .tile = city_tile(pcity), + }, + NULL, &pdis->reqs, RPT_POSSIBLE); } diff --git a/common/effects.c b/common/effects.c index 878afe2c59..11ba70ab54 100644 --- a/common/effects.c +++ b/common/effects.c @@ -595,16 +595,11 @@ bool building_has_effect(const struct impr_type *pimprove, active, which would prevent it from taking effect. (Assumes that any requirement specified in the ruleset with a negative sense is an impediment.) + + context may be NULL. This is equivalent to passing an empty context. **************************************************************************/ -static bool is_effect_prevented(const struct player *target_player, +static bool is_effect_prevented(const struct req_context *context, const struct player *other_player, - const struct city *target_city, - const struct impr_type *target_building, - const struct tile *target_tile, - const struct unit *target_unit, - const struct unit_type *target_unittype, - const struct output_type *target_output, - const struct specialist *target_specialist, const struct effect *peffect, const enum req_problem_type prob_type) { @@ -612,10 +607,7 @@ static bool is_effect_prevented(const struct player *target_player, /* Only check present=FALSE requirements; these will return _FALSE_ * from is_req_active() if met, and need reversed prob_type */ if (!preq->present - && !is_req_active(target_player, other_player, target_city, - target_building, target_tile, - target_unit, target_unittype, - target_output, target_specialist, NULL, + && !is_req_active(context, other_player, preq, REVERSED_RPT(prob_type))) { return TRUE; } @@ -652,9 +644,12 @@ bool is_building_replaced(const struct city *pcity, * checked depends on the range of the effect. */ /* Prob_type is not reversed here. disabled is equal to replaced, not * reverse */ - if (!is_effect_prevented(city_owner(pcity), NULL, pcity, - pimprove, - NULL, NULL, NULL, NULL, NULL, + if (!is_effect_prevented(&(const struct req_context) { + .player = city_owner(pcity), + .city = pcity, + .building = pimprove, + }, + NULL, peffect, prob_type)) { return FALSE; } @@ -666,45 +661,39 @@ bool is_building_replaced(const struct city *pcity, /**********************************************************************//** Returns the effect bonus of a given type for any target. - target gives the type of the target - (player,city,building,tile) give the exact target + context gives the target (or targets) to evaluate requirements against effect_type gives the effect type to be considered + context may be NULL. This is equivalent to passing an empty context. + Returns the effect sources of this type _currently active_. The returned vector must be freed (building_vector_free) when the caller is done with it. **************************************************************************/ int get_target_bonus_effects(struct effect_list *plist, - const struct player *target_player, + const struct req_context *context, const struct player *other_player, - const struct city *target_city, - const struct impr_type *target_building, - const struct tile *target_tile, - const struct unit *target_unit, - const struct unit_type *target_unittype, - const struct output_type *target_output, - const struct specialist *target_specialist, - const struct action *target_action, enum effect_type effect_type) { int bonus = 0; + if (context == NULL) { + context = req_context_empty(); + } + /* Loop over all effects of this type. */ effect_list_iterate(get_effects(effect_type), peffect) { /* For each effect, see if it is active. */ - if (are_reqs_active(target_player, other_player, target_city, - target_building, target_tile, - target_unit, target_unittype, - target_output, target_specialist, target_action, + if (are_reqs_active(context, other_player, &peffect->reqs, RPT_CERTAIN)) { /* This code will add value of effect. If there's multiplier for * effect and target_player aren't null, then value is multiplied * by player's multiplier factor. */ if (peffect->multiplier) { - if (target_player) { + if (context->player) { bonus += (peffect->value - * player_multiplier_effect_value(target_player, + * player_multiplier_effect_value(context->player, peffect->multiplier)) / 100; } } else { @@ -729,10 +718,7 @@ int get_world_bonus(enum effect_type effect_type) return 0; } - return get_target_bonus_effects(NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, - effect_type); + return get_target_bonus_effects(NULL, NULL, NULL, effect_type); } /**********************************************************************//** @@ -746,9 +732,11 @@ int get_player_bonus(const struct player *pplayer, } return get_target_bonus_effects(NULL, - pplayer, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, - NULL, effect_type); + &(const struct req_context) { + .player = pplayer, + }, + NULL, + effect_type); } /**********************************************************************//** @@ -761,8 +749,11 @@ int get_city_bonus(const struct city *pcity, enum effect_type effect_type) } return get_target_bonus_effects(NULL, - city_owner(pcity), NULL, pcity, NULL, - city_tile(pcity), NULL, NULL, NULL, NULL, + &(const struct req_context) { + .player = city_owner(pcity), + .city = pcity, + .tile = city_tile(pcity), + }, NULL, effect_type); } @@ -773,16 +764,18 @@ int get_city_bonus(const struct city *pcity, enum effect_type effect_type) **************************************************************************/ int get_tile_bonus(const struct tile *ptile, enum effect_type effect_type) { - struct city *pcity = tile_city(ptile); - if (!initialized) { return 0; } return get_target_bonus_effects(NULL, - tile_owner(ptile), NULL, pcity, NULL, - ptile, NULL, NULL, NULL, NULL, - NULL, effect_type); + &(const struct req_context) { + .player = tile_owner(ptile), + .city = tile_city(ptile), + .tile = ptile, + }, + NULL, + effect_type); } /**********************************************************************//** @@ -797,8 +790,12 @@ int get_city_specialist_output_bonus(const struct city *pcity, fc_assert_ret_val(pspecialist != NULL, 0); fc_assert_ret_val(poutput != NULL, 0); return get_target_bonus_effects(NULL, - city_owner(pcity), NULL, pcity, NULL, - NULL, NULL, NULL, poutput, pspecialist, + &(const struct req_context) { + .player = city_owner(pcity), + .city = pcity, + .output = poutput, + .specialist = pspecialist, + }, NULL, effect_type); } @@ -822,8 +819,13 @@ int get_city_tile_output_bonus(const struct city *pcity, { fc_assert_ret_val(pcity != NULL, 0); return get_target_bonus_effects(NULL, - city_owner(pcity), NULL, pcity, NULL, - ptile, NULL, NULL, poutput, NULL, NULL, + &(const struct req_context) { + .player = city_owner(pcity), + .city = pcity, + .tile = ptile, + .output = poutput, + }, + NULL, effect_type); } @@ -842,8 +844,13 @@ int get_tile_output_bonus(const struct city *pcity, const struct player *pplayer = pcity ? city_owner(pcity) : NULL; return get_target_bonus_effects(NULL, - pplayer, NULL, pcity, NULL, - ptile, NULL, NULL, poutput, NULL, NULL, + &(const struct req_context) { + .player = pplayer, + .city = pcity, + .tile = ptile, + .output = poutput, + }, + NULL, effect_type); } @@ -861,8 +868,12 @@ int get_player_output_bonus(const struct player *pplayer, fc_assert_ret_val(pplayer != NULL, 0); fc_assert_ret_val(poutput != NULL, 0); fc_assert_ret_val(effect_type != EFT_COUNT, 0); - return get_target_bonus_effects(NULL, pplayer, NULL, NULL, NULL, NULL, - NULL, NULL, poutput, NULL, NULL, + return get_target_bonus_effects(NULL, + &(const struct req_context) { + .player = pplayer, + .output= poutput, + }, + NULL, effect_type); } @@ -880,8 +891,12 @@ int get_city_output_bonus(const struct city *pcity, fc_assert_ret_val(pcity != NULL, 0); fc_assert_ret_val(poutput != NULL, 0); fc_assert_ret_val(effect_type != EFT_COUNT, 0); - return get_target_bonus_effects(NULL, city_owner(pcity), NULL, pcity, - NULL, NULL, NULL, NULL, poutput, NULL, + return get_target_bonus_effects(NULL, + &(const struct req_context) { + .player = city_owner(pcity), + .city = pcity, + .output = poutput, + }, NULL, effect_type); } @@ -899,10 +914,13 @@ int get_building_bonus(const struct city *pcity, fc_assert_ret_val(NULL != pcity && NULL != building, 0); return get_target_bonus_effects(NULL, - city_owner(pcity), NULL, pcity, - building, - NULL, NULL, NULL, NULL, - NULL, NULL, effect_type); + &(const struct req_context) { + .player = city_owner(pcity), + .city = pcity, + .building = building, + }, + NULL, + effect_type); } /**********************************************************************//** @@ -934,9 +952,15 @@ int get_unittype_bonus(const struct player *pplayer, } return get_target_bonus_effects(NULL, - pplayer, NULL, pcity, NULL, ptile, - NULL, punittype, NULL, - NULL, paction, effect_type); + &(const struct req_context) { + .player = pplayer, + .city = pcity, + .tile = ptile, + .unittype = punittype, + .action = paction, + }, + NULL, + effect_type); } /**********************************************************************//** @@ -950,12 +974,15 @@ int get_unit_bonus(const struct unit *punit, enum effect_type effect_type) fc_assert_ret_val(punit != NULL, 0); return get_target_bonus_effects(NULL, - unit_owner(punit), - NULL, - unit_tile(punit) - ? tile_city(unit_tile(punit)) : NULL, - NULL, unit_tile(punit), - punit, unit_type_get(punit), NULL, NULL, + &(const struct req_context) { + .player = unit_owner(punit), + .city = unit_tile(punit) + ? tile_city(unit_tile(punit)) + : NULL, + .tile = unit_tile(punit), + .unit = punit, + .unittype = unit_type_get(punit), + }, NULL, effect_type); } @@ -982,14 +1009,14 @@ int get_unit_vs_tile_bonus(const struct tile *ptile, } return get_target_bonus_effects(NULL, - pplayer, + &(const struct req_context) { + .player = pplayer, + .city = tile_city(ptile), + .tile = ptile, + .unit = punit, + .unittype = utype, + }, tile_owner(ptile), - tile_city(ptile), - NULL, - ptile, - punit, - utype, - NULL, NULL, NULL, etype); } @@ -1009,8 +1036,10 @@ int get_player_bonus_effects(struct effect_list *plist, fc_assert_ret_val(pplayer != NULL, 0); return get_target_bonus_effects(plist, - pplayer, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, + &(const struct req_context) { + .player = pplayer, + }, + NULL, effect_type); } @@ -1031,8 +1060,12 @@ int get_city_bonus_effects(struct effect_list *plist, fc_assert_ret_val(pcity != NULL, 0); return get_target_bonus_effects(plist, - city_owner(pcity), NULL, pcity, NULL, - NULL, NULL, NULL, poutput, NULL, NULL, + &(const struct req_context) { + .player = city_owner(pcity), + .city = pcity, + .output = poutput, + }, + NULL, effect_type); } @@ -1084,6 +1117,11 @@ int get_potential_improvement_bonus(const struct impr_type *pimprove, if (plist) { int power = 0; + const struct req_context context = { + .player = owner, + .city = pcity, + .building = pimprove, + }; effect_list_iterate(plist, peffect) { bool present = TRUE; @@ -1100,9 +1138,7 @@ int get_potential_improvement_bonus(const struct impr_type *pimprove, continue; } - if (!is_req_active(owner, NULL, pcity, pimprove, - NULL, NULL, NULL, NULL, NULL, NULL, - preq, prob_type)) { + if (!is_req_active(&context, NULL, preq, prob_type)) { useful = FALSE; break; } diff --git a/common/effects.h b/common/effects.h index 698eca9e05..c5788b71bf 100644 --- a/common/effects.h +++ b/common/effects.h @@ -454,16 +454,8 @@ int get_city_bonus_effects(struct effect_list *plist, enum effect_type effect_type); int get_target_bonus_effects(struct effect_list *plist, - const struct player *target_player, + const struct req_context *context, const struct player *other_player, - const struct city *target_city, - const struct impr_type *target_building, - const struct tile *target_tile, - const struct unit *target_unit, - const struct unit_type *target_unittype, - const struct output_type *target_output, - const struct specialist *target_specialist, - const struct action *target_action, enum effect_type effect_type); bool building_has_effect(const struct impr_type *pimprove, diff --git a/common/extras.c b/common/extras.c index 2d4c12b197..ce15d2e24b 100644 --- a/common/extras.c +++ b/common/extras.c @@ -415,8 +415,12 @@ bool player_can_build_extra(const struct extra_type *pextra, return FALSE; } - return are_reqs_active(pplayer, tile_owner(ptile), NULL, NULL, ptile, - NULL, NULL, NULL, NULL, NULL, &pextra->reqs, + return are_reqs_active(&(const struct req_context) { + .player = pplayer, + .tile = ptile, + }, + tile_owner(ptile), + &pextra->reqs, RPT_POSSIBLE); } @@ -478,8 +482,14 @@ bool can_build_extra(const struct extra_type *pextra, return FALSE; } - return are_reqs_active(pplayer, tile_owner(ptile), NULL, NULL, ptile, - punit, unit_type_get(punit), NULL, NULL, NULL, &pextra->reqs, + return are_reqs_active(&(const struct req_context) { + .player = pplayer, + .tile = ptile, + .unit = punit, + .unittype = unit_type_get(punit), + }, + tile_owner(ptile), + &pextra->reqs, RPT_CERTAIN); } @@ -528,8 +538,12 @@ bool player_can_remove_extra(const struct extra_type *pextra, } /* For huts, it's not checked if player has any non-HUT_NOTHING units */ - return are_reqs_active(pplayer, tile_owner(ptile), NULL, NULL, ptile, - NULL, NULL, NULL, NULL, NULL, &pextra->rmreqs, + return are_reqs_active(&(const struct req_context) { + .player = pplayer, + .tile = ptile, + }, + tile_owner(ptile), + &pextra->rmreqs, RPT_POSSIBLE); } @@ -546,9 +560,14 @@ bool can_remove_extra(const struct extra_type *pextra, return FALSE; } - return are_reqs_active(unit_owner(punit), tile_owner(ptile), NULL, NULL, - ptile, punit, unit_type_get(punit), NULL, NULL, - NULL, &pextra->rmreqs, RPT_CERTAIN); + return are_reqs_active(&(const struct req_context) { + .player = unit_owner(punit), + .tile = ptile, + .unit = punit, + .unittype = unit_type_get(punit), + }, + tile_owner(ptile), + &pextra->rmreqs, RPT_CERTAIN); } /************************************************************************//** @@ -594,9 +613,8 @@ bool is_native_tile_to_extra(const struct extra_type *pextra, } } - return are_reqs_active(NULL, NULL, NULL, NULL, ptile, - NULL, NULL, NULL, NULL, NULL, - &pextra->reqs, RPT_POSSIBLE); + return are_reqs_active(&(const struct req_context) { .tile = ptile }, + NULL, &pextra->reqs, RPT_POSSIBLE); } /************************************************************************//** @@ -637,15 +655,19 @@ bool hut_on_tile(const struct tile *ptile) bool unit_can_enter_hut(const struct unit *punit, const struct tile *ptile) { + const struct req_context context = { + .player = unit_owner(punit), + .tile = ptile, + }; + if (!(unit_can_do_action_result(punit, ACTRES_HUT_ENTER) || unit_can_do_action_sub_result(punit, ACT_SUB_RES_HUT_ENTER))) { return FALSE; } extra_type_by_rmcause_iterate(ERM_ENTER, extra) { if (tile_has_extra(ptile, extra) - && are_reqs_active(unit_owner(punit), tile_owner(ptile), NULL, NULL, - ptile, NULL, NULL, NULL, NULL, NULL, &extra->rmreqs, - RPT_POSSIBLE)){ + && are_reqs_active(&context, tile_owner(ptile), &extra->rmreqs, + RPT_POSSIBLE)) { return TRUE; } } extra_type_by_rmcause_iterate_end; @@ -659,6 +681,11 @@ bool unit_can_enter_hut(const struct unit *punit, bool unit_can_displace_hut(const struct unit *punit, const struct tile *ptile) { + const struct req_context context = { + .player = unit_owner(punit), + .tile = ptile, + }; + if (!(unit_can_do_action_result(punit, ACTRES_HUT_FRIGHTEN) || unit_can_do_action_sub_result(punit, ACT_SUB_RES_HUT_FRIGHTEN) || unit_can_do_action_result(punit, ACTRES_HUT_ENTER) @@ -667,9 +694,8 @@ bool unit_can_displace_hut(const struct unit *punit, } extra_type_by_rmcause_iterate(ERM_ENTER, extra) { if (tile_has_extra(ptile, extra) - && are_reqs_active(unit_owner(punit), tile_owner(ptile), NULL, NULL, - ptile, NULL, NULL, NULL, NULL, NULL, &extra->rmreqs, - RPT_POSSIBLE)){ + && are_reqs_active(&context, tile_owner(ptile), &extra->rmreqs, + RPT_POSSIBLE)) { return TRUE; } } extra_type_by_rmcause_iterate_end; @@ -1017,8 +1043,8 @@ bool can_extra_appear(const struct extra_type *pextra, const struct tile *ptile) && is_extra_caused_by(pextra, EC_APPEARANCE) && is_native_tile_to_extra(pextra, ptile) && !extra_conflicting_on_tile(pextra, ptile) - && are_reqs_active(NULL, tile_owner(ptile), NULL, NULL, ptile, - NULL, NULL, NULL, NULL, NULL, + && are_reqs_active(&(const struct req_context) { .tile = ptile }, + tile_owner(ptile), &pextra->appearance_reqs, RPT_CERTAIN); } @@ -1030,8 +1056,8 @@ bool can_extra_disappear(const struct extra_type *pextra, const struct tile *pti return tile_has_extra(ptile, pextra) && is_extra_removed_by(pextra, ERM_DISAPPEARANCE) && can_extra_be_removed(pextra, ptile) - && are_reqs_active(NULL, tile_owner(ptile), NULL, NULL, ptile, - NULL, NULL, NULL, NULL, NULL, + && are_reqs_active(&(const struct req_context) { .tile = ptile }, + tile_owner(ptile), &pextra->disappearance_reqs, RPT_CERTAIN); } diff --git a/common/government.c b/common/government.c index e1d001d2bb..4ef19aff87 100644 --- a/common/government.c +++ b/common/government.c @@ -176,8 +176,8 @@ bool can_change_to_government(struct player *pplayer, return TRUE; } - return are_reqs_active(pplayer, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, &gov->reqs, RPT_CERTAIN); + return are_reqs_active(&(const struct req_context) { .player = pplayer }, + NULL, &gov->reqs, RPT_CERTAIN); } diff --git a/common/improvement.c b/common/improvement.c index 218c8cfda6..c06340da7e 100644 --- a/common/improvement.c +++ b/common/improvement.c @@ -275,8 +275,11 @@ int impr_estimate_build_shield_cost(const struct player *pplayer, int base = pimprove->build_cost * (100 + get_target_bonus_effects(NULL, - pplayer, NULL, NULL, pimprove, - ptile, NULL, NULL, NULL, NULL, + &(const struct req_context) { + .player = pplayer, + .building = pimprove, + .tile = ptile, + }, NULL, EFT_IMPR_BUILD_COST_PCT)) / 100; @@ -407,15 +410,15 @@ bool improvement_obsolete(const struct player *pplayer, const struct impr_type *pimprove, const struct city *pcity) { - struct tile *ptile = NULL; - - if (pcity != NULL) { - ptile = city_tile(pcity); - } + const struct req_context context = { + .player = pplayer, + .city = pcity, + .tile = pcity ? city_tile(pcity) : NULL, + .building = pimprove, + }; requirement_vector_iterate(&pimprove->obsolete_by, preq) { - if (is_req_active(pplayer, NULL, pcity, pimprove, ptile, NULL, NULL, - NULL, NULL, NULL, preq, RPT_CERTAIN)) { + if (is_req_active(&context, NULL, preq, RPT_CERTAIN)) { return TRUE; } } requirement_vector_iterate_end; @@ -655,6 +658,8 @@ bool is_improvement_redundant(const struct city *pcity, bool can_player_build_improvement_direct(const struct player *p, const struct impr_type *pimprove) { + const struct req_context context = { .player = p }; + bool space_part = FALSE; if (!valid_improvement(pimprove)) { @@ -663,8 +668,7 @@ bool can_player_build_improvement_direct(const struct player *p, requirement_vector_iterate(&pimprove->reqs, preq) { if (preq->range >= REQ_RANGE_PLAYER - && !is_req_active(p, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, preq, RPT_CERTAIN)) { + && !is_req_active(&context, NULL, preq, RPT_CERTAIN)) { return FALSE; } } requirement_vector_iterate_end; @@ -729,6 +733,8 @@ bool can_player_build_improvement_now(const struct player *p, bool can_player_build_improvement_later(const struct player *p, const struct impr_type *pimprove) { + const struct req_context context = { .player = p }; + if (!valid_improvement(pimprove)) { return FALSE; } @@ -744,9 +750,8 @@ bool can_player_build_improvement_later(const struct player *p, * they can never be met). */ requirement_vector_iterate(&pimprove->reqs, preq) { if (preq->range >= REQ_RANGE_PLAYER - && is_req_unchanging(preq) - && !is_req_active(p, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, preq, RPT_POSSIBLE)) { + && is_req_unchanging(preq) + && !is_req_active(&context, NULL, preq, RPT_POSSIBLE)) { return FALSE; } } requirement_vector_iterate_end; diff --git a/common/map.c b/common/map.c index ad0ff45331..2dba730cb5 100644 --- a/common/map.c +++ b/common/map.c @@ -114,9 +114,10 @@ bv_extras get_tile_infrastructure_set(const struct tile *ptile, tile_remove_extra(missingset, pextra); extra_type_iterate(pdependant) { if (tile_has_extra(ptile, pdependant)) { - if (!are_reqs_active(NULL, NULL, NULL, NULL, missingset, - NULL, NULL, NULL, NULL, NULL, - &pdependant->reqs, RPT_POSSIBLE)) { + if (!are_reqs_active(&(const struct req_context) { + .tile = missingset, + }, + NULL, &pdependant->reqs, RPT_POSSIBLE)) { dependency = TRUE; break; } diff --git a/common/metaknowledge.c b/common/metaknowledge.c index 071f43de4e..84026fdf15 100644 --- a/common/metaknowledge.c +++ b/common/metaknowledge.c @@ -146,26 +146,26 @@ static bool can_plr_see_all_sym_diplrels_of(const struct player *pplayer, } /**********************************************************************//** - Is an evaluation of the requirement accurate when pow_player evaluates + Is an evaluation of the requirement accurate when pov_player evaluates it? + context may be NULL. This is equivalent to passing an empty context. + TODO: Move the data to a data file. That will - let non programmers help complete it and/or fix what is wrong - let clients not written in C use the data **************************************************************************/ -static bool is_req_knowable(const struct player *pow_player, - const struct player *target_player, +static bool is_req_knowable(const struct player *pov_player, + const struct req_context *context, const struct player *other_player, - const struct city *target_city, - const struct impr_type *target_building, - const struct tile *target_tile, - const struct unit *target_unit, - const struct output_type *target_output, - const struct specialist *target_specialist, const struct requirement *req, const enum req_problem_type prob_type) { - fc_assert_ret_val_msg(NULL != pow_player, false, "No point of view"); + fc_assert_ret_val_msg(NULL != pov_player, FALSE, "No point of view"); + + if (context == NULL) { + context = req_context_empty(); + } if (req->source.kind == VUT_UTFLAG || req->source.kind == VUT_UTYPE @@ -175,13 +175,13 @@ static bool is_req_knowable(const struct player *pow_player, || req->source.kind == VUT_MINHP) { switch (req->range) { case REQ_RANGE_LOCAL: - if (target_unit == NULL) { + if (context->unit == NULL) { /* The unit may exist but not be passed when the problem type is * RPT_POSSIBLE. */ return prob_type == RPT_CERTAIN; } - return target_unit && can_player_see_unit(pow_player, target_unit); + return can_player_see_unit(pov_player, context->unit); case REQ_RANGE_TILE: case REQ_RANGE_CADJACENT: case REQ_RANGE_ADJACENT: @@ -200,7 +200,7 @@ static bool is_req_knowable(const struct player *pow_player, if (req->source.kind == VUT_UNITSTATE) { fc_assert_ret_val_msg(req->range == REQ_RANGE_LOCAL, FALSE, "Wrong range"); - if (target_unit == NULL) { + if (context->unit == NULL) { /* The unit may exist but not be passed when the problem type is * RPT_POSSIBLE. */ return prob_type == RPT_CERTAIN; @@ -213,11 +213,11 @@ static bool is_req_knowable(const struct player *pow_player, case USP_NATIVE_TILE: case USP_NATIVE_EXTRA: /* Known if the unit is seen by the player. */ - return target_unit && can_player_see_unit(pow_player, target_unit); + return can_player_see_unit(pov_player, context->unit); case USP_HAS_HOME_CITY: case USP_MOVED_THIS_TURN: /* Known to the unit's owner. */ - return target_unit && unit_owner(target_unit) == pow_player; + return unit_owner(context->unit) == pov_player; case USP_COUNT: fc_assert_msg(req->source.value.unit_state != USP_COUNT, "Invalid unit state property."); @@ -229,7 +229,7 @@ static bool is_req_knowable(const struct player *pow_player, if (req->source.kind == VUT_MINMOVES) { fc_assert_ret_val_msg(req->range == REQ_RANGE_LOCAL, FALSE, "Wrong range"); - if (target_unit == NULL) { + if (context->unit == NULL) { /* The unit may exist but not be passed when the problem type is * RPT_POSSIBLE. */ return prob_type == RPT_CERTAIN; @@ -238,7 +238,7 @@ static bool is_req_knowable(const struct player *pow_player, switch (req->range) { case REQ_RANGE_LOCAL: /* The owner can see if their unit has move fragments left. */ - return unit_owner(target_unit) == pow_player; + return unit_owner(context->unit) == pov_player; case REQ_RANGE_TILE: case REQ_RANGE_CADJACENT: case REQ_RANGE_ADJACENT: @@ -259,18 +259,18 @@ static bool is_req_knowable(const struct player *pow_player, fc_assert_ret_val_msg(req->range == REQ_RANGE_LOCAL, FALSE, "Wrong range"); - if (target_unit == NULL) { + if (context->unit == NULL) { /* The unit may exist but not be passed when the problem type is * RPT_POSSIBLE. */ return prob_type == RPT_CERTAIN; } - if (unit_owner(target_unit) == pow_player) { + if (unit_owner(context->unit) == pov_player) { return TRUE; } /* Sent in package_short_unit() */ - return can_player_see_unit(pow_player, target_unit); + return can_player_see_unit(pov_player, context->unit); } if (req->source.kind == VUT_DIPLREL @@ -281,36 +281,36 @@ static bool is_req_knowable(const struct player *pow_player, switch (req->range) { case REQ_RANGE_LOCAL: if (other_player == NULL - || target_player == NULL) { + || context->player == NULL) { /* The two players may exist but not be passed when the problem * type is RPT_POSSIBLE. */ return prob_type == RPT_CERTAIN; } - if (pow_player == target_player - || pow_player == other_player) { + if (pov_player == context->player + || pov_player == other_player) { return TRUE; } - if (can_plr_see_all_sym_diplrels_of(pow_player, target_player) - || can_plr_see_all_sym_diplrels_of(pow_player, other_player)) { + if (can_plr_see_all_sym_diplrels_of(pov_player, context->player) + || can_plr_see_all_sym_diplrels_of(pov_player, other_player)) { return TRUE; } /* TODO: Non symmetric diplomatic relationships. */ break; case REQ_RANGE_PLAYER: - if (target_player == NULL) { + if (context->player == NULL) { /* The target player may exist but not be passed when the problem * type is RPT_POSSIBLE. */ return prob_type == RPT_CERTAIN; } - if (pow_player == target_player) { + if (pov_player == context->player) { return TRUE; } - if (can_plr_see_all_sym_diplrels_of(pow_player, target_player)) { + if (can_plr_see_all_sym_diplrels_of(pov_player, context->player)) { return TRUE; } @@ -339,13 +339,13 @@ static bool is_req_knowable(const struct player *pow_player, } if (req->source.kind == VUT_MINSIZE) { - if (target_city == NULL) { + if (context->city == NULL) { /* The city may exist but not be passed when the problem type is * RPT_POSSIBLE. */ return prob_type == RPT_CERTAIN; } - if (player_can_see_city_externals(pow_player, target_city)) { + if (player_can_see_city_externals(pov_player, context->city)) { return TRUE; } } @@ -353,7 +353,7 @@ static bool is_req_knowable(const struct player *pow_player, if (req->source.kind == VUT_CITYTILE) { struct city *pcity; - if (target_tile == NULL) { + if (context->tile == NULL) { /* The tile may exist but not be passed when the problem type is * RPT_POSSIBLE. */ return prob_type == RPT_CERTAIN; @@ -362,23 +362,23 @@ static bool is_req_knowable(const struct player *pow_player, switch (req->range) { case REQ_RANGE_TILE: /* Known because the tile is seen */ - if (tile_is_seen(target_tile, pow_player)) { + if (tile_is_seen(context->tile, pov_player)) { return TRUE; } /* The player knows their city even if they can't see it */ - pcity = tile_city(target_tile); - return pcity && city_owner(pcity) == pow_player; + pcity = tile_city(context->tile); + return pcity && city_owner(pcity) == pov_player; case REQ_RANGE_CADJACENT: /* Known because the tile is seen */ - if (is_tile_seen_cadj(pow_player, target_tile)) { + if (is_tile_seen_cadj(pov_player, context->tile)) { return TRUE; } /* The player knows their city even if they can't see it */ - cardinal_adjc_iterate(&(wld.map), target_tile, ptile) { + cardinal_adjc_iterate(&(wld.map), context->tile, ptile) { pcity = tile_city(ptile); - if (pcity && city_owner(pcity) == pow_player) { + if (pcity && city_owner(pcity) == pov_player) { return TRUE; } } cardinal_adjc_iterate_end; @@ -387,14 +387,14 @@ static bool is_req_knowable(const struct player *pow_player, return FALSE; case REQ_RANGE_ADJACENT: /* Known because the tile is seen */ - if (is_tile_seen_adj(pow_player, target_tile)) { + if (is_tile_seen_adj(pov_player, context->tile)) { return TRUE; } /* The player knows their city even if they can't see it */ - adjc_iterate(&(wld.map), target_tile, ptile) { + adjc_iterate(&(wld.map), context->tile, ptile) { pcity = tile_city(ptile); - if (pcity && city_owner(pcity) == pow_player) { + if (pcity && city_owner(pcity) == pov_player) { return TRUE; } } adjc_iterate_end; @@ -419,14 +419,14 @@ static bool is_req_knowable(const struct player *pow_player, /* The only legal range when this was written was local. */ fc_assert(req->range == REQ_RANGE_LOCAL); - if (!target_city) { + if (context->city == NULL) { /* RPT_CERTAIN: Can't be. No city to contain it. * RPT_POSSIBLE: A city like that may exist but not be passed. */ return prob_type == RPT_CERTAIN; } /* Local BuildingGenus could be about city production. */ - return can_player_see_city_internals(pow_player, target_city); + return can_player_see_city_internals(pov_player, context->city); } if (req->source.kind == VUT_IMPROVEMENT) { @@ -440,28 +440,28 @@ static bool is_req_knowable(const struct player *pow_player, * Wonders are always visible. */ return TRUE; case REQ_RANGE_TRADEROUTE: - /* Could be known for trade routes to cities owned by pow_player as + /* Could be known for trade routes to cities owned by pov_player as * long as the requirement is present. Not present requirements would * require knowledge that no trade routes to another foreign city * exists (since all possible trade routes are to a city owned by - * pow_player). Not worth the complexity, IMHO. */ + * pov_player). Not worth the complexity, IMHO. */ return FALSE; case REQ_RANGE_CITY: case REQ_RANGE_LOCAL: - if (!target_city) { + if (context->city == NULL) { /* RPT_CERTAIN: Can't be. No city to contain it. * RPT_POSSIBLE: A city like that may exist but not be passed. */ return prob_type == RPT_CERTAIN; } - if (can_player_see_city_internals(pow_player, target_city)) { + if (can_player_see_city_internals(pov_player, context->city)) { /* Anyone that can see city internals (like the owner) known all * its improvements. */ return TRUE; } if (is_improvement_visible(req->source.value.building) - && player_can_see_city_externals(pow_player, target_city)) { + && player_can_see_city_externals(pov_player, context->city)) { /* Can see visible improvements when the outside of the city is * seen. */ return TRUE; @@ -480,7 +480,7 @@ static bool is_req_knowable(const struct player *pow_player, if (req->source.kind == VUT_NATION || req->source.kind == VUT_NATIONGROUP) { - if (!target_player + if (context->player == NULL && (req->range == REQ_RANGE_PLAYER || req->range == REQ_RANGE_TEAM || req->range == REQ_RANGE_ALLIANCE)) { @@ -495,13 +495,13 @@ static bool is_req_knowable(const struct player *pow_player, if (req->source.kind == VUT_ADVANCE || req->source.kind == VUT_TECHFLAG) { if (req->range == REQ_RANGE_PLAYER) { - if (!target_player) { + if (context->player == NULL) { /* The player (that may or may not possess the tech) may exist but * not be passed when the problem type is RPT_POSSIBLE. */ return prob_type == RPT_CERTAIN; } - return can_see_techs_of_target(pow_player, target_player); + return can_see_techs_of_target(pov_player, context->player); } else if (req->range == REQ_RANGE_WORLD && req->survives) { /* game.info.global_advances is sent to each player */ return TRUE; @@ -510,19 +510,19 @@ static bool is_req_knowable(const struct player *pow_player, if (req->source.kind == VUT_GOVERNMENT) { if (req->range == REQ_RANGE_PLAYER) { - if (!target_player) { + if (context->player == NULL) { /* The player (that may or may not possess the tech) may exist but * not be passed when the problem type is RPT_POSSIBLE. */ return prob_type == RPT_CERTAIN; } - return (pow_player == target_player - || could_intel_with_player(pow_player, target_player)); + return (pov_player == context->player + || could_intel_with_player(pov_player, context->player)); } } if (req->source.kind == VUT_MAXTILEUNITS) { - if (target_tile == NULL) { + if (context->tile == NULL) { /* The tile may exist but not be passed when the problem type is * RPT_POSSIBLE. */ return prob_type == RPT_CERTAIN; @@ -530,24 +530,24 @@ static bool is_req_knowable(const struct player *pow_player, switch (req->range) { case REQ_RANGE_TILE: - return can_player_see_hypotetic_units_at(pow_player, target_tile); + return can_player_see_hypotetic_units_at(pov_player, context->tile); case REQ_RANGE_CADJACENT: - if (!can_player_see_hypotetic_units_at(pow_player, target_tile)) { + if (!can_player_see_hypotetic_units_at(pov_player, context->tile)) { return FALSE; } - cardinal_adjc_iterate(&(wld.map), target_tile, adjc_tile) { - if (!can_player_see_hypotetic_units_at(pow_player, adjc_tile)) { + cardinal_adjc_iterate(&(wld.map), context->tile, adjc_tile) { + if (!can_player_see_hypotetic_units_at(pov_player, adjc_tile)) { return FALSE; } } cardinal_adjc_iterate_end; return TRUE; case REQ_RANGE_ADJACENT: - if (!can_player_see_hypotetic_units_at(pow_player, target_tile)) { + if (!can_player_see_hypotetic_units_at(pov_player, context->tile)) { return FALSE; } - adjc_iterate(&(wld.map), target_tile, adjc_tile) { - if (!can_player_see_hypotetic_units_at(pow_player, adjc_tile)) { + adjc_iterate(&(wld.map), context->tile, adjc_tile) { + if (!can_player_see_hypotetic_units_at(pov_player, adjc_tile)) { return FALSE; } } adjc_iterate_end; @@ -574,7 +574,7 @@ static bool is_req_knowable(const struct player *pow_player, || req->source.kind == VUT_EXTRA || req->source.kind == VUT_EXTRAFLAG || req->source.kind == VUT_ROADFLAG) { - if (target_tile == NULL) { + if (context->tile == NULL) { /* The tile may exist but not be passed when the problem type is * RPT_POSSIBLE. */ return prob_type == RPT_CERTAIN; @@ -582,27 +582,27 @@ static bool is_req_knowable(const struct player *pow_player, switch (req->range) { case REQ_RANGE_TILE: - return tile_is_seen(target_tile, pow_player); + return tile_is_seen(context->tile, pov_player); case REQ_RANGE_CADJACENT: /* TODO: The answer is known when the universal is located on a seen * tile. Is returning TRUE in those cases worth the added complexity * and the extra work for the computer? */ - return is_tile_seen_cadj(pow_player, target_tile); + return is_tile_seen_cadj(pov_player, context->tile); case REQ_RANGE_ADJACENT: /* TODO: The answer is known when the universal is located on a seen * tile. Is returning TRUE in those cases worth the added complexity * and the extra work for the computer? */ - return is_tile_seen_adj(pow_player, target_tile); + return is_tile_seen_adj(pov_player, context->tile); case REQ_RANGE_CITY: /* TODO: The answer is known when the universal is located on a seen * tile. Is returning TRUE in those cases worth the added complexity * and the extra work for the computer? */ - return is_tile_seen_city(pow_player, target_city); + return is_tile_seen_city(pov_player, context->city); case REQ_RANGE_TRADEROUTE: /* TODO: The answer is known when the universal is located on a seen * tile. Is returning TRUE in those cases worth the added complexity * and the extra work for the computer? */ - return is_tile_seen_traderoute(pow_player, target_city); + return is_tile_seen_traderoute(pov_player, context->city); case REQ_RANGE_CONTINENT: case REQ_RANGE_PLAYER: case REQ_RANGE_ALLIANCE: @@ -631,41 +631,25 @@ static bool is_req_knowable(const struct player *pow_player, } /**********************************************************************//** - Evaluate a single requirement given pow_player's knowledge. + Evaluate a single requirement given pov_player's knowledge. - Note: Assumed to use pow_player's data. + context may be NULL. This is equivalent to passing an empty context. + + Note: Assumed to use pov_player's data. **************************************************************************/ enum fc_tristate -mke_eval_req(const struct player *pow_player, - const struct player *target_player, +mke_eval_req(const struct player *pov_player, + const struct req_context *context, const struct player *other_player, - const struct city *target_city, - const struct impr_type *target_building, - const struct tile *target_tile, - const struct unit *target_unit, - const struct output_type *target_output, - const struct specialist *target_specialist, const struct requirement *req, const enum req_problem_type prob_type) { - const struct unit_type *target_unittype; - - if (!is_req_knowable(pow_player, target_player, other_player, - target_city, target_building, target_tile, - target_unit, target_output, - target_specialist, req, prob_type)) { + if (!is_req_knowable(pov_player, context, other_player, + req, prob_type)) { return TRI_MAYBE; } - if (target_unit) { - target_unittype = unit_type_get(target_unit); - } else { - target_unittype = NULL; - } - - if (is_req_active(target_player, other_player, target_city, - target_building, target_tile, target_unit, target_unittype, - target_output, target_specialist, NULL, req, prob_type)) { + if (is_req_active(context, other_player, req, prob_type)) { return TRI_YES; } else { return TRI_NO; @@ -673,20 +657,16 @@ mke_eval_req(const struct player *pow_player, } /**********************************************************************//** - Evaluate a requirement vector given pow_player's knowledge. + Evaluate a requirement vector given pov_player's knowledge. + + context may be NULL. This is equivalent to passing an empty context. - Note: Assumed to use pow_player's data. + Note: Assumed to use pov_player's data. **************************************************************************/ enum fc_tristate -mke_eval_reqs(const struct player *pow_player, - const struct player *target_player, +mke_eval_reqs(const struct player *pov_player, + const struct req_context *context, const struct player *other_player, - const struct city *target_city, - const struct impr_type *target_building, - const struct tile *target_tile, - const struct unit *target_unit, - const struct output_type *target_output, - const struct specialist *target_specialist, const struct requirement_vector *reqs, const enum req_problem_type prob_type) { @@ -695,10 +675,8 @@ mke_eval_reqs(const struct player *pow_player, result = TRI_YES; requirement_vector_iterate(reqs, preq) { - current = mke_eval_req(pow_player, target_player, other_player, - target_city, target_building, target_tile, - target_unit, target_output, - target_specialist, preq, prob_type); + current = mke_eval_req(pov_player, context, other_player, + preq, prob_type); if (current == TRI_NO) { return TRI_NO; } else if (current == TRI_MAYBE) { diff --git a/common/metaknowledge.h b/common/metaknowledge.h index 89cfa0487b..14ebeb2b21 100644 --- a/common/metaknowledge.h +++ b/common/metaknowledge.h @@ -22,33 +22,21 @@ extern "C" { #endif /* __cplusplus */ enum fc_tristate -mke_eval_req(const struct player *pow_player, - const struct player *target_player, +mke_eval_req(const struct player *pov_player, + const struct req_context *context, const struct player *other_player, - const struct city *target_city, - const struct impr_type *target_building, - const struct tile *target_tile, - const struct unit *target_unit, - const struct output_type *target_output, - const struct specialist *target_specialist, const struct requirement *req, const enum req_problem_type prob_type); enum fc_tristate -mke_eval_reqs(const struct player *pow_player, - const struct player *target_player, +mke_eval_reqs(const struct player *pov_player, + const struct req_context *context, const struct player *other_player, - const struct city *target_city, - const struct impr_type *target_building, - const struct tile *target_tile, - const struct unit *target_unit, - const struct output_type *target_output, - const struct specialist *target_specialist, const struct requirement_vector *reqs, const enum req_problem_type prob_type); -bool can_see_techs_of_target(const struct player *pow_player, +bool can_see_techs_of_target(const struct player *pov_player, const struct player *target_player); #ifdef __cplusplus diff --git a/common/multipliers.c b/common/multipliers.c index d3e0276b2a..14b250134d 100644 --- a/common/multipliers.c +++ b/common/multipliers.c @@ -145,6 +145,6 @@ bool multiplier_can_be_changed(struct multiplier *pmul, struct player *pplayer) } } - return are_reqs_active(pplayer, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + return are_reqs_active(&(const struct req_context) { .player = pplayer }, NULL, &pmul->reqs, RPT_CERTAIN); } diff --git a/common/player.c b/common/player.c index fc242bd8ce..516aca10f5 100644 --- a/common/player.c +++ b/common/player.c @@ -1575,13 +1575,14 @@ enum casus_belli_range casus_belli_range_for(const struct player *offender, * gets a casus belli if CASUS_BELLI_OUTRAGE or above. */ casus_belli_amount = get_target_bonus_effects(NULL, - offender, tgt_plr, - tile_city(tgt_tile), - NULL, - tgt_tile, - NULL, off_ut, - NULL, NULL, - paction, + &(const struct req_context) { + .player = offender, + .city = tile_city(tgt_tile), + .tile = tgt_tile, + .unittype = off_ut, + .action = paction, + }, + tgt_plr, outcome); if (casus_belli_amount >= CASUS_BELLI_OUTRAGE) { diff --git a/common/requirements.c b/common/requirements.c index 240c9ee46a..3b40d7d49f 100644 --- a/common/requirements.c +++ b/common/requirements.c @@ -713,6 +713,16 @@ int universal_number(const struct universal *source) } +/**********************************************************************//** + Returns a pointer to a statically-allocated, empty requirement context. +**************************************************************************/ +const struct req_context *req_context_empty(void) +{ + static const struct req_context empty = {}; + return ∅ +} + + /**********************************************************************//** Returns the given requirement as a formatted string ready for printing. Does not care about the 'quiet' property. @@ -3177,32 +3187,24 @@ is_achievement_in_range(const struct player *target_player, /**********************************************************************//** Checks the requirement to see if it is active on the given target. - target gives the type of the target - (player,city,building,tile) give the exact target + context gives the target (or targets) to evaluate against req gives the requirement itself + context may be NULL. This is equivalent to passing an empty context. + Make sure you give all aspects of the target when calling this function: for instance if you have TARGET_CITY pass the city's owner as the target player as well as the city itself as the target city. **************************************************************************/ -bool is_req_active(const struct player *target_player, +bool is_req_active(const struct req_context *context, const struct player *other_player, - const struct city *target_city, - const struct impr_type *target_building, - const struct tile *target_tile, - const struct unit *target_unit, - const struct unit_type *target_unittype, - const struct output_type *target_output, - const struct specialist *target_specialist, - const struct action *target_action, const struct requirement *req, const enum req_problem_type prob_type) { enum fc_tristate eval = TRI_NO; - /* The supplied unit has a type. Use it if the unit type is missing. */ - if (target_unittype == NULL && target_unit != NULL) { - target_unittype = unit_type_get(target_unit); + if (context == NULL) { + context = req_context_empty(); } /* Note the target may actually not exist. In particular, effects that @@ -3215,197 +3217,204 @@ bool is_req_active(const struct player *target_player, break; case VUT_ADVANCE: /* The requirement is filled if the player owns the tech. */ - eval = is_tech_in_range(target_player, req->range, req->survives, + eval = is_tech_in_range(context->player, req->range, req->survives, advance_number(req->source.value.advance)); break; case VUT_TECHFLAG: - eval = is_techflag_in_range(target_player, req->range, + eval = is_techflag_in_range(context->player, req->range, req->source.value.techflag); break; case VUT_GOVERNMENT: /* The requirement is filled if the player is using the government. */ - if (target_player == NULL) { + if (context->player == NULL) { eval = TRI_MAYBE; } else { - eval = BOOL_TO_TRISTATE(government_of_player(target_player) == req->source.value.govern); + eval = BOOL_TO_TRISTATE(government_of_player(context->player) + == req->source.value.govern); } break; case VUT_ACHIEVEMENT: - eval = is_achievement_in_range(target_player, req->range, + eval = is_achievement_in_range(context->player, req->range, req->source.value.achievement); break; case VUT_STYLE: - if (target_player == NULL) { + if (context->player == NULL) { eval = TRI_MAYBE; } else { - eval = BOOL_TO_TRISTATE(target_player->style == req->source.value.style); + eval = BOOL_TO_TRISTATE(context->player->style + == req->source.value.style); } break; case VUT_IMPROVEMENT: - eval = is_building_in_range(target_player, target_city, - target_building, + eval = is_building_in_range(context->player, context->city, + context->building, req->range, req->survives, req->source.value.building); break; case VUT_IMPR_GENUS: - eval = (target_building ? BOOL_TO_TRISTATE( - target_building->genus - == req->source.value.impr_genus) - : TRI_MAYBE); + eval = (context->building ? BOOL_TO_TRISTATE( + context->building->genus + == req->source.value.impr_genus) + : TRI_MAYBE); break; case VUT_EXTRA: - eval = is_extra_type_in_range(target_tile, target_city, + eval = is_extra_type_in_range(context->tile, context->city, req->range, req->survives, req->source.value.extra); break; case VUT_GOOD: - eval = is_goods_type_in_range(target_tile, target_city, + eval = is_goods_type_in_range(context->tile, context->city, req->range, req->survives, req->source.value.good); break; case VUT_TERRAIN: - eval = is_terrain_in_range(target_tile, target_city, + eval = is_terrain_in_range(context->tile, context->city, req->range, req->survives, req->source.value.terrain); break; case VUT_TERRFLAG: - eval = is_terrainflag_in_range(target_tile, target_city, + eval = is_terrainflag_in_range(context->tile, context->city, req->range, req->survives, req->source.value.terrainflag); break; case VUT_NATION: - eval = is_nation_in_range(target_player, req->range, req->survives, + eval = is_nation_in_range(context->player, req->range, req->survives, req->source.value.nation); break; case VUT_NATIONGROUP: - eval = is_nation_group_in_range(target_player, req->range, req->survives, + eval = is_nation_group_in_range(context->player, req->range, + req->survives, req->source.value.nationgroup); break; case VUT_NATIONALITY: - eval = is_nationality_in_range(target_city, req->range, + eval = is_nationality_in_range(context->city, req->range, req->source.value.nationality); break; case VUT_DIPLREL: - eval = is_diplrel_in_range(target_player, other_player, req->range, + eval = is_diplrel_in_range(context->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, + eval = is_diplrel_in_range(context->tile ? tile_owner(context->tile) + : NULL, + context->player, req->range, req->source.value.diplrel); break; case VUT_DIPLREL_TILE_O: - eval = is_diplrel_in_range(target_tile ? tile_owner(target_tile) : NULL, + eval = is_diplrel_in_range(context->tile ? tile_owner(context->tile) + : NULL, other_player, req->range, req->source.value.diplrel); break; case VUT_DIPLREL_UNITANY: - eval = is_diplrel_unitany_in_range(target_tile, target_player, + eval = is_diplrel_unitany_in_range(context->tile, context->player, req->range, req->source.value.diplrel); break; case VUT_DIPLREL_UNITANY_O: - eval = is_diplrel_unitany_in_range(target_tile, other_player, + eval = is_diplrel_unitany_in_range(context->tile, other_player, req->range, req->source.value.diplrel); break; case VUT_UTYPE: - if (target_unittype == NULL) { + if (context->unittype == NULL) { eval = TRI_MAYBE; } else { - eval = is_unittype_in_range(target_unittype, + eval = is_unittype_in_range(context->unittype, req->range, req->survives, req->source.value.utype); } break; case VUT_UTFLAG: - eval = is_unitflag_in_range(target_unittype, + eval = is_unitflag_in_range(context->unittype, req->range, req->survives, req->source.value.unitflag); break; case VUT_UCLASS: - if (target_unittype == NULL) { + if (context->unittype == NULL) { eval = TRI_MAYBE; } else { - eval = is_unitclass_in_range(target_unittype, + eval = is_unitclass_in_range(context->unittype, req->range, req->survives, req->source.value.uclass); } break; case VUT_UCFLAG: - if (target_unittype == NULL) { + if (context->unittype == NULL) { eval = TRI_MAYBE; } else { - eval = is_unitclassflag_in_range(target_unittype, + eval = is_unitclassflag_in_range(context->unittype, req->range, req->survives, req->source.value.unitclassflag); } break; case VUT_MINVETERAN: - if (target_unit == NULL) { + if (context->unit == NULL) { eval = TRI_MAYBE; } else { eval = - BOOL_TO_TRISTATE(target_unit->veteran >= req->source.value.minveteran); + BOOL_TO_TRISTATE(context->unit->veteran + >= req->source.value.minveteran); } break; case VUT_UNITSTATE: - if (target_unit == NULL) { + if (context->unit == NULL) { eval = TRI_MAYBE; } else { - eval = is_unit_state(target_unit, + eval = is_unit_state(context->unit, req->range, req->survives, req->source.value.unit_state); } break; case VUT_ACTIVITY: - eval = unit_activity_in_range(target_unit, + eval = unit_activity_in_range(context->unit, req->range, req->source.value.activity); break; case VUT_MINMOVES: - if (target_unit == NULL) { + if (context->unit == NULL) { eval = TRI_MAYBE; } else { eval = BOOL_TO_TRISTATE( - req->source.value.minmoves <= target_unit->moves_left); + req->source.value.minmoves <= context->unit->moves_left); } break; case VUT_MINHP: - if (target_unit == NULL) { + if (context->unit == NULL) { eval = TRI_MAYBE; } else { eval = BOOL_TO_TRISTATE( - req->source.value.min_hit_points <= target_unit->hp); + req->source.value.min_hit_points <= context->unit->hp); } break; case VUT_AGE: switch (req->range) { case REQ_RANGE_LOCAL: - if (target_unit == NULL || !is_server()) { + if (context->unit == NULL || !is_server()) { eval = TRI_MAYBE; } else { eval = BOOL_TO_TRISTATE( req->source.value.age <= - game.info.turn - target_unit->server.birth_turn); + game.info.turn - context->unit->server.birth_turn); } break; case REQ_RANGE_CITY: - if (target_city == NULL) { + if (context->city == NULL) { eval = TRI_MAYBE; } else { eval = BOOL_TO_TRISTATE( req->source.value.age <= - game.info.turn - target_city->turn_founded); + game.info.turn - context->city->turn_founded); } break; case REQ_RANGE_PLAYER: - if (target_player == NULL) { + if (context->player == NULL) { eval = TRI_MAYBE; } else { eval = - BOOL_TO_TRISTATE(req->source.value.age <= player_age(target_player)); + BOOL_TO_TRISTATE(req->source.value.age + <= player_age(context->player)); } break; default: @@ -3420,11 +3429,14 @@ bool is_req_active(const struct player *target_player, eval = ((game.info.global_advance_count - 1) >= req->source.value.min_techs); break; case REQ_RANGE_PLAYER: - if (target_player == NULL) { + if (context->player == NULL) { eval = TRI_MAYBE; } else { /* "None" does not count */ - eval = ((research_get(target_player)->techs_researched - 1) >= req->source.value.min_techs); + eval = BOOL_TO_TRISTATE( + (research_get(context->player)->techs_researched - 1) + >= req->source.value.min_techs + ); } break; default: @@ -3432,30 +3444,32 @@ bool is_req_active(const struct player *target_player, } break; case VUT_ACTION: - eval = BOOL_TO_TRISTATE(target_action - && action_number(target_action) + eval = BOOL_TO_TRISTATE(context->action + && action_number(context->action) == action_number(req->source.value.action)); break; case VUT_OTYPE: - eval = BOOL_TO_TRISTATE(target_output - && target_output->index == req->source.value.outputtype); + eval = BOOL_TO_TRISTATE(context->output + && context->output->index + == req->source.value.outputtype); break; case VUT_SPECIALIST: - eval = BOOL_TO_TRISTATE(target_specialist - && target_specialist == req->source.value.specialist); + eval = BOOL_TO_TRISTATE(context->specialist + && context->specialist + == req->source.value.specialist); break; case VUT_MINSIZE: - if (target_city == NULL) { + if (context->city == NULL) { eval = TRI_MAYBE; } else { if (req->range == REQ_RANGE_TRADEROUTE) { bool found = FALSE; - if (city_size_get(target_city) >= req->source.value.minsize) { + if (city_size_get(context->city) >= req->source.value.minsize) { eval = TRI_YES; break; } - trade_partners_iterate(target_city, trade_partner) { + trade_partners_iterate(context->city, trade_partner) { if (city_size_get(trade_partner) >= req->source.value.minsize) { found = TRUE; break; @@ -3463,42 +3477,45 @@ bool is_req_active(const struct player *target_player, } trade_partners_iterate_end; eval = BOOL_TO_TRISTATE(found); } else { - eval = BOOL_TO_TRISTATE(city_size_get(target_city) >= req->source.value.minsize); + eval = BOOL_TO_TRISTATE(city_size_get(context->city) + >= req->source.value.minsize); } } break; case VUT_MINCULTURE: - eval = is_minculture_in_range(target_city, target_player, req->range, + eval = is_minculture_in_range(context->city, context->player, + req->range, req->source.value.minculture); break; case VUT_MINFOREIGNPCT: - eval = is_minforeignpct_in_range(target_city, req->range, + eval = is_minforeignpct_in_range(context->city, req->range, req->source.value.minforeignpct); break; case VUT_AI_LEVEL: - if (target_player == NULL) { + if (context->player == NULL) { eval = TRI_MAYBE; } else { - eval = BOOL_TO_TRISTATE(is_ai(target_player) - && target_player->ai_common.skill_level == req->source.value.ai_level); + eval = BOOL_TO_TRISTATE(is_ai(context->player) + && context->player->ai_common.skill_level + == req->source.value.ai_level); } break; case VUT_MAXTILEUNITS: - eval = is_tile_units_in_range(target_tile, req->range, + eval = is_tile_units_in_range(context->tile, req->range, req->source.value.max_tile_units); break; case VUT_TERRAINCLASS: - eval = is_terrain_class_in_range(target_tile, target_city, + eval = is_terrain_class_in_range(context->tile, context->city, req->range, req->survives, req->source.value.terrainclass); break; case VUT_ROADFLAG: - eval = is_roadflag_in_range(target_tile, target_city, + eval = is_roadflag_in_range(context->tile, context->city, req->range, req->survives, req->source.value.roadflag); break; case VUT_EXTRAFLAG: - eval = is_extraflag_in_range(target_tile, target_city, + eval = is_extraflag_in_range(context->tile, context->city, req->range, req->survives, req->source.value.extraflag); break; @@ -3516,28 +3533,28 @@ bool is_req_active(const struct player *target_player, req->source.value.ssetval)); break; case VUT_TERRAINALTER: - if (target_tile == NULL) { + if (context->tile == NULL) { eval = TRI_MAYBE; } else { - eval = is_terrain_alter_possible_in_range(target_tile, + eval = is_terrain_alter_possible_in_range(context->tile, req->range, req->survives, req->source.value.terrainalter); } break; case VUT_CITYTILE: - if (target_tile == NULL) { + if (context->tile == NULL) { eval = TRI_MAYBE; } else { - eval = is_citytile_in_range(target_tile, target_city, + eval = is_citytile_in_range(context->tile, context->city, req->range, req->source.value.citytile); } break; case VUT_CITYSTATUS: - if (target_city == NULL) { + if (context->city == NULL) { eval = TRI_MAYBE; } else { - eval = is_citystatus_in_range(target_city, + eval = is_citystatus_in_range(context->city, req->range, req->source.value.citystatus); } @@ -3564,35 +3581,24 @@ bool is_req_active(const struct player *target_player, /**********************************************************************//** Checks the requirement(s) to see if they are active on the given target. - target gives the type of the target - (player,city,building,tile) give the exact target + context gives the target (or targets) to evaluate against reqs gives the requirement vector. The function returns TRUE only if all requirements are active. + context may be NULL. This is equivalent to passing an empty context. + Make sure you give all aspects of the target when calling this function: for instance if you have TARGET_CITY pass the city's owner as the target player as well as the city itself as the target city. **************************************************************************/ -bool are_reqs_active(const struct player *target_player, +bool are_reqs_active(const struct req_context *context, const struct player *other_player, - const struct city *target_city, - const struct impr_type *target_building, - const struct tile *target_tile, - const struct unit *target_unit, - const struct unit_type *target_unittype, - const struct output_type *target_output, - const struct specialist *target_specialist, - const struct action *target_action, const struct requirement_vector *reqs, const enum req_problem_type prob_type) { requirement_vector_iterate(reqs, preq) { - if (!is_req_active(target_player, other_player, target_city, - target_building, target_tile, - target_unit, target_unittype, - target_output, target_specialist, target_action, - preq, prob_type)) { + if (!is_req_active(context, other_player, preq, prob_type)) { return FALSE; } } requirement_vector_iterate_end; diff --git a/common/requirements.h b/common/requirements.h index f68d70abee..71468abea7 100644 --- a/common/requirements.h +++ b/common/requirements.h @@ -88,6 +88,27 @@ struct requirement { TYPED_VECTOR_ITERATE(struct requirement, req_vec, preq) #define requirement_vector_iterate_end VECTOR_ITERATE_END +/* A set of targets to evaluate requirements against. Depending on what the + * requirements in question are for, most of these entries will usually be + * NULL. For instance, when evaluating the construction requirements for a + * building, there is no target unit, specialist etc. */ +struct req_context { + const struct player *player; + const struct city *city; + const struct tile *tile; + + /* for local-ranged requirements only */ + const struct unit *unit; + const struct unit_type *unittype; + const struct impr_type *building; + const struct output_type *output; + const struct specialist *specialist; + const struct action *action; +}; + +/* req_context-related functions */ +const struct req_context *req_context_empty(void); + /* General requirement functions. */ struct requirement req_from_str(const char *type, const char *range, bool survives, bool present, bool quiet, @@ -110,28 +131,12 @@ bool are_requirements_contradictions(const struct requirement *req1, bool does_req_contradicts_reqs(const struct requirement *req, const struct requirement_vector *vec); -bool is_req_active(const struct player *target_player, - const struct player *other_player, - const struct city *target_city, - const struct impr_type *target_building, - const struct tile *target_tile, - const struct unit *target_unit, - const struct unit_type *target_unittype, - const struct output_type *target_output, - const struct specialist *target_specialist, - const struct action *target_action, - const struct requirement *req, +bool is_req_active(const struct req_context *context, + const struct player *other_player, + const struct requirement *req, const enum req_problem_type prob_type); -bool are_reqs_active(const struct player *target_player, +bool are_reqs_active(const struct req_context *context, const struct player *other_player, - const struct city *target_city, - const struct impr_type *target_building, - const struct tile *target_tile, - const struct unit *target_unit, - const struct unit_type *target_unittype, - const struct output_type *target_output, - const struct specialist *target_specialist, - const struct action *target_action, const struct requirement_vector *reqs, const enum req_problem_type prob_type); diff --git a/common/research.c b/common/research.c index e1c4409365..b0ab1e654a 100644 --- a/common/research.c +++ b/common/research.c @@ -298,26 +298,14 @@ research_advance_name_translation(const struct research *presearch, If may become active if all unchangeable requirements are active. ****************************************************************************/ -static bool reqs_may_activate(const struct player *target_player, +static bool reqs_may_activate(const struct req_context *context, const struct player *other_player, - const struct city *target_city, - const struct impr_type *target_building, - const struct tile *target_tile, - const struct unit *target_unit, - const struct unit_type *target_unittype, - const struct output_type *target_output, - const struct specialist *target_specialist, - const struct action *target_action, const struct requirement_vector *reqs, const enum req_problem_type prob_type) { requirement_vector_iterate(reqs, preq) { if (is_req_unchanging(preq) - && !is_req_active(target_player, other_player, target_city, - target_building, target_tile, - target_unit, target_unittype, - target_output, target_specialist, target_action, - preq, prob_type)) { + && !is_req_active(context, other_player, preq, prob_type)) { return FALSE; } } requirement_vector_iterate_end; @@ -337,16 +325,8 @@ static bool reqs_may_activate(const struct player *target_player, static bool research_allowed(const struct research *presearch, Tech_type_id tech, - bool (*reqs_eval)(const struct player *tplr, + bool (*reqs_eval)(const struct req_context *context, const struct player *oplr, - const struct city *tcity, - const struct impr_type *tbld, - const struct tile *ttile, - const struct unit *tunit, - const struct unit_type *tutype, - const struct output_type *top, - const struct specialist *tspe, - const struct action *tact, const struct requirement_vector *reqs, const enum req_problem_type ptype)) { @@ -360,8 +340,8 @@ research_allowed(const struct research *presearch, } research_players_iterate(presearch, pplayer) { - if (reqs_eval(pplayer, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, &(adv->research_reqs), RPT_CERTAIN)) { + if (reqs_eval(&(const struct req_context) { .player = pplayer }, + NULL, &(adv->research_reqs), RPT_CERTAIN)) { /* It is enough that one player that shares research is allowed to * research it. * Reasoning: Imagine a tech with that requires a nation in the diff --git a/common/road.c b/common/road.c index 48e1194eae..da7514f41e 100644 --- a/common/road.c +++ b/common/road.c @@ -206,13 +206,12 @@ static bool are_road_reqs_fulfilled(const struct road_type *proad, const struct tile *ptile) { struct extra_type *pextra = road_extra_get(proad); - const struct unit_type *utype; - - if (punit == NULL) { - utype = NULL; - } else { - utype = unit_type_get(punit); - } + const struct req_context context = { + .player = pplayer, + .tile = ptile, + .unit = punit, + .unittype = punit ? unit_type_get(punit) : NULL, + }; if (requirement_vector_size(&proad->first_reqs) > 0) { bool beginning = TRUE; @@ -242,16 +241,14 @@ static bool are_road_reqs_fulfilled(const struct road_type *proad, } extra_type_list_iterate_end; if (beginning) { - if (!are_reqs_active(pplayer, tile_owner(ptile), NULL, NULL, ptile, - punit, utype, NULL, NULL, NULL, + if (!are_reqs_active(&context, tile_owner(ptile), &proad->first_reqs, RPT_POSSIBLE)) { return FALSE; } } } - return are_reqs_active(pplayer, tile_owner(ptile), NULL, NULL, ptile, - punit, utype, NULL, NULL, NULL, + return are_reqs_active(&context, tile_owner(ptile), &pextra->reqs, RPT_POSSIBLE); } @@ -441,8 +438,8 @@ bool is_native_tile_to_road(const struct road_type *proad, pextra = road_extra_get(proad); - return are_reqs_active(NULL, NULL, NULL, NULL, ptile, - NULL, NULL, NULL, NULL, NULL, + return are_reqs_active(&(const struct req_context) { .tile = ptile }, + NULL, &pextra->reqs, RPT_POSSIBLE); } diff --git a/common/scriptcore/api_game_effects.c b/common/scriptcore/api_game_effects.c index f182a52ab4..d37d10a94c 100644 --- a/common/scriptcore/api_game_effects.c +++ b/common/scriptcore/api_game_effects.c @@ -97,13 +97,15 @@ int api_effects_unit_bonus(lua_State *L, Unit *punit, Player *other_player, } return get_target_bonus_effects(NULL, - unit_owner(punit), + &(const struct req_context) { + .player = unit_owner(punit), + .city = unit_tile(punit) + ? tile_city(unit_tile(punit)) : NULL, + .tile = unit_tile(punit), + .unit = punit, + .unittype = unit_type_get(punit), + }, other_player, - unit_tile(punit) - ? tile_city(unit_tile(punit)) : NULL, - NULL, unit_tile(punit), - punit, unit_type_get(punit), NULL, NULL, - NULL, etype); } diff --git a/common/scriptcore/api_game_methods.c b/common/scriptcore/api_game_methods.c index 7d89161749..2f0a867eab 100644 --- a/common/scriptcore/api_game_methods.c +++ b/common/scriptcore/api_game_methods.c @@ -273,9 +273,13 @@ int api_methods_city_inspire_partisans(lua_State *L, City *self, if (inspired) { /* Cannot use get_city_bonus() as it would use city's current owner * instead of inspirer. */ - return get_target_bonus_effects(NULL, inspirer, NULL, self, NULL, - city_tile(self), NULL, NULL, NULL, - NULL, NULL, EFT_INSPIRE_PARTISANS); + return get_target_bonus_effects(NULL, + &(const struct req_context) { + .player = inspirer, + .city = self, + .tile = city_tile(self), + }, + NULL, EFT_INSPIRE_PARTISANS); } return 0; diff --git a/common/style.c b/common/style.c index 61ca259447..d2acf226ab 100644 --- a/common/style.c +++ b/common/style.c @@ -185,11 +185,10 @@ struct music_style *music_style_by_number(int id) struct music_style *player_music_style(struct player *plr) { struct music_style *best = NULL; + const struct req_context plr_context = { .player = plr }; music_styles_iterate(pms) { - if (are_reqs_active(plr, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, &pms->reqs, - RPT_CERTAIN)) { + if (are_reqs_active(&plr_context, NULL, &pms->reqs, RPT_CERTAIN)) { best = pms; } } music_styles_iterate_end; @@ -242,11 +241,14 @@ int basic_city_style_for_style(struct nation_style *pstyle) int city_style(struct city *pcity) { int i; - struct player *plr = city_owner(pcity); + const struct req_context context = { + .player = city_owner(pcity), + .city = pcity, + .tile = city_tile(pcity), + }; for (i = game.control.styles_count - 1; i >= 0; i--) { - if (are_reqs_active(plr, NULL, pcity, NULL, city_tile(pcity), - NULL, NULL, NULL, NULL, NULL, + if (are_reqs_active(&context, NULL, &city_styles[i].reqs, RPT_CERTAIN)) { return i; } diff --git a/common/traderoutes.c b/common/traderoutes.c index 5783c0d97f..db7e85c7a3 100644 --- a/common/traderoutes.c +++ b/common/traderoutes.c @@ -489,19 +489,22 @@ int get_caravan_enter_city_trade_bonus(const struct city *pc1, /* Trade_revenue_bonus increases revenue by power of 2 in milimes */ bonus = get_target_bonus_effects(NULL, - city_owner(pc1), city_owner(pc2), - pc1, NULL, city_tile(pc1), /* TODO: Should unit requirements be * allowed so stuff like moves left and * unit type can modify the bonus? */ - NULL, NULL, - NULL, NULL, + &(const struct req_context) { + .player = city_owner(pc1), + .city = pc1, + .tile = city_tile(pc1), /* Could be used to reduce the one time * bonus if no trade route is * established. */ - action_by_number(establish_trade ? - ACTION_TRADE_ROUTE : - ACTION_MARKETPLACE), + .action = action_by_number( + establish_trade + ? ACTION_TRADE_ROUTE + : ACTION_MARKETPLACE + ), + }, city_owner(pc2), EFT_TRADE_REVENUE_BONUS); /* Be mercy full to players with small amounts. Round up. */ @@ -658,17 +661,14 @@ bool goods_has_flag(const struct goods_type *pgood, enum goods_flag_id flag) bool goods_can_be_provided(const struct city *pcity, struct goods_type *pgood, struct unit *punit) { - const struct unit_type *ptype; - - if (punit != NULL) { - ptype = unit_type_get(punit); - } else { - ptype = NULL; - } - - return are_reqs_active(city_owner(pcity), NULL, - pcity, NULL, city_tile(pcity), - punit, ptype, NULL, NULL, NULL, + return are_reqs_active(&(const struct req_context) { + .player = city_owner(pcity), + .city = pcity, + .tile = city_tile(pcity), + .unit = punit, + .unittype = punit ? unit_type_get(punit) : NULL, + }, + NULL, &pgood->reqs, RPT_CERTAIN); } diff --git a/common/unit.c b/common/unit.c index 419d7d48a2..be6edebfcc 100644 --- a/common/unit.c +++ b/common/unit.c @@ -240,10 +240,13 @@ int unit_shield_value(const struct unit *punit, value = utype_build_shield_cost_base(punittype); value += ((value * get_target_bonus_effects(NULL, - act_player, NULL, - NULL, NULL, NULL, - punit, punittype, - NULL, NULL, paction, + &(const struct req_context) { + .player = act_player, + .unit = punit, + .unittype = punittype, + .action = paction, + }, + NULL, EFT_UNIT_SHIELD_VALUE_PCT)) / 100); @@ -2035,13 +2038,18 @@ int unit_pays_mp_for_action(const struct action *paction, int mpco; mpco = get_target_bonus_effects(NULL, - unit_owner(punit), + &(const struct req_context) { + .player = unit_owner(punit), + .city = unit_tile(punit) + ? tile_city(unit_tile(punit)) + : NULL, + .tile = unit_tile(punit), + .unit = punit, + .unittype = unit_type_get(punit), + .action = paction, + }, NULL, - unit_tile(punit) - ? tile_city(unit_tile(punit)) : NULL, - NULL, unit_tile(punit), - punit, unit_type_get(punit), NULL, NULL, - paction, EFT_ACTION_SUCCESS_MOVE_COST); + EFT_ACTION_SUCCESS_MOVE_COST); mpco += utype_pays_mp_for_action_base(paction, unit_type_get(punit)); @@ -2187,11 +2195,17 @@ int unit_bribe_cost(struct unit *punit, struct player *briber) /* Rule set specific cost modification */ cost += (cost - * get_target_bonus_effects(NULL, unit_owner(punit), briber, - game_city_by_number(punit->homecity), - NULL, ptile, - punit, unit_type_get(punit), NULL, NULL, - NULL, + * get_target_bonus_effects(NULL, + &(const struct req_context) { + .player = unit_owner(punit), + .city = game_city_by_number( + punit->homecity + ), + .tile = ptile, + .unit = punit, + .unittype = unit_type_get(punit), + }, + briber, EFT_UNIT_BRIBE_COST_PCT)) / 100; diff --git a/common/unittype.c b/common/unittype.c index 88591b7496..38ffc4e3c2 100644 --- a/common/unittype.c +++ b/common/unittype.c @@ -1472,12 +1472,15 @@ int utype_pays_mp_for_action_estimate(const struct action *paction, * EFT_ACTION_SUCCESS_MOVE_COST depends on unit state. Add unit state * parameters? */ mpco += get_target_bonus_effects(NULL, - act_player, - NULL, - tile_city(post_action_tile), - NULL, tgt_tile, - NULL, putype, NULL, NULL, - paction, EFT_ACTION_SUCCESS_MOVE_COST); + &(const struct req_context) { + .player = act_player, + .city = tile_city(post_action_tile), + .tile = tgt_tile, + .unittype = putype, + .action = paction, + }, + NULL, + EFT_ACTION_SUCCESS_MOVE_COST); return mpco; } @@ -2014,6 +2017,8 @@ bool utype_player_already_has_this(const struct player *pplayer, bool can_player_build_unit_direct(const struct player *p, const struct unit_type *punittype) { + const struct req_context context = { .player = p, .unittype = punittype }; + fc_assert_ret_val(NULL != punittype, FALSE); if (is_barbarian(p) @@ -2077,9 +2082,7 @@ bool can_player_build_unit_direct(const struct player *p, /* The question *here* is if the *player* can build this unit */ continue; } - if (!is_req_active(p, NULL, - NULL, NULL, NULL, NULL, punittype, NULL, NULL, NULL, - preq, RPT_CERTAIN)) { + if (!is_req_active(&context, NULL, preq, RPT_CERTAIN)) { return FALSE; } } requirement_vector_iterate_end; diff --git a/server/actiontools.c b/server/actiontools.c index 5b679d206f..9aae537ab9 100644 --- a/server/actiontools.c +++ b/server/actiontools.c @@ -82,10 +82,15 @@ void action_success_target_pay_mp(struct action *paction, if (unit_is_alive(target_id)) { int spent_mp = get_target_bonus_effects( NULL, - unit_owner(target), NULL, - unit_tile(target) ? tile_city(unit_tile(target)) : NULL, - NULL, unit_tile(target), target, unit_type_get(target), - NULL, NULL, paction, + &(const struct req_context) { + .player = unit_owner(target), + .city = unit_tile(target) ? tile_city(unit_tile(target)) : NULL, + .tile = unit_tile(target), + .unit = target, + .unittype = unit_type_get(target), + .action = paction, + }, + NULL, EFT_ACTION_SUCCESS_TARGET_MOVE_COST); target->moves_left = MAX(0, target->moves_left - spent_mp); @@ -941,11 +946,17 @@ action_auto_perf_unit_sel(const enum action_auto_perf_cause cause, const struct output_type *eval_output, const struct action *eval_action) { + const struct req_context actor_ctxt = { + .player = unit_owner(actor), + .tile = unit_tile(actor), + .unit = actor, + .unittype = unit_type_get(actor), + .output = eval_output, + .action = eval_action, + }; + action_auto_perf_by_cause_iterate(cause, autoperformer) { - if (are_reqs_active(unit_owner(actor), other_player, - NULL, NULL, unit_tile(actor), - actor, unit_type_get(actor), - eval_output, NULL, eval_action, + if (are_reqs_active(&actor_ctxt, other_player, &autoperformer->reqs, RPT_CERTAIN)) { /* Select this action auto performer. */ return autoperformer; diff --git a/server/advisors/advruleset.c b/server/advisors/advruleset.c index b1a204bf69..8a3595b73a 100644 --- a/server/advisors/advruleset.c +++ b/server/advisors/advruleset.c @@ -78,13 +78,14 @@ void adv_units_ruleset_init(void) } unit_class_iterate_end; unit_type_iterate(ptype) { + const struct req_context context = { .unittype = ptype }; + ptype->adv.igwall = TRUE; effect_list_iterate(get_effects(EFT_DEFEND_BONUS), peffect) { if (peffect->value > 0) { requirement_vector_iterate(&peffect->reqs, preq) { - if (!is_req_active(NULL, NULL, NULL, NULL, NULL, NULL, ptype, - NULL, NULL, NULL, preq, RPT_POSSIBLE)) { + if (!is_req_active(&context, NULL, preq, RPT_POSSIBLE)) { ptype->adv.igwall = FALSE; break; } diff --git a/server/citytools.c b/server/citytools.c index 123c6b4450..58350fc4f1 100644 --- a/server/citytools.c +++ b/server/citytools.c @@ -3148,6 +3148,11 @@ void city_landlocked_sell_coastal_improvements(struct tile *ptile) if (pcity) { struct player *pplayer = city_owner(pcity); + const struct req_context city_ctxt = { + .player = pplayer, + .city = pcity, + .tile = pcity->tile, + }; /* Sell all buildings (but not Wonders) that must be next to the ocean */ city_built_iterate(pcity, pimprove) { @@ -3159,9 +3164,7 @@ void city_landlocked_sell_coastal_improvements(struct tile *ptile) if ((VUT_TERRAIN == preq->source.kind || VUT_TERRAINCLASS == preq->source.kind || VUT_TERRFLAG == preq->source.kind) - && !is_req_active(city_owner(pcity), NULL, pcity, NULL, - pcity->tile, NULL, NULL, NULL, NULL, NULL, - preq, TRUE)) { + && !is_req_active(&city_ctxt, NULL, preq, RPT_CERTAIN)) { int price = impr_sell_gold(pimprove); do_sell_building(pplayer, pcity, pimprove, "landlocked"); diff --git a/server/cityturn.c b/server/cityturn.c index 20a1def809..3a679b39d1 100644 --- a/server/cityturn.c +++ b/server/cityturn.c @@ -1133,6 +1133,10 @@ static bool worklist_item_postpone_req_vec(struct universal *target, const char *tgt_name; const struct requirement_vector *build_reqs; const char *signal_name; + const struct req_context city_ctxt = { + .player = pplayer, + .city = pcity, + }; bool purge = FALSE; bool known = FALSE; @@ -1157,8 +1161,7 @@ static bool worklist_item_postpone_req_vec(struct universal *target, } requirement_vector_iterate(build_reqs, preq) { - if (!is_req_active(pplayer, NULL, pcity, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, preq, RPT_POSSIBLE)) { + if (!is_req_active(&city_ctxt, NULL, preq, RPT_POSSIBLE)) { known = TRUE; switch (preq->source.kind) { case VUT_ADVANCE: diff --git a/server/diplhand.c b/server/diplhand.c index 06b73b8c5e..16f98892f5 100644 --- a/server/diplhand.c +++ b/server/diplhand.c @@ -167,6 +167,9 @@ void handle_diplomacy_accept_treaty_req(struct player *pplayer, bool worker_refresh_required = FALSE; struct player *pother = player_by_number(counterpart); + const struct req_context player_ctxt = { .player = pplayer }; + const struct req_context other_ctxt = { .player = pother }; + if (NULL == pother || pplayer == pother) { return; } @@ -195,11 +198,9 @@ void handle_diplomacy_accept_treaty_req(struct player *pplayer, if (pclause->from == pplayer) { struct clause_info *info = clause_info_get(pclause->type); - if (!are_reqs_active(pplayer, pother, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + if (!are_reqs_active(&player_ctxt, pother, &(info->giver_reqs), RPT_POSSIBLE) - || !are_reqs_active(pother, pplayer, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + || !are_reqs_active(&other_ctxt, pplayer, &(info->receiver_reqs), RPT_POSSIBLE)) { log_error("Requirements of a clause between %s and %s not fullfilled", player_name(pplayer), player_name(pother)); @@ -350,11 +351,9 @@ void handle_diplomacy_accept_treaty_req(struct player *pplayer, if (pclause->from == pother) { struct clause_info *info = clause_info_get(pclause->type); - if (!are_reqs_active(pother, pplayer, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + if (!are_reqs_active(&other_ctxt, pplayer, &(info->giver_reqs), RPT_POSSIBLE) - || !are_reqs_active(pplayer, pother, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + || !are_reqs_active(&player_ctxt, pother, &(info->receiver_reqs), RPT_POSSIBLE)) { notify_player(pplayer, NULL, E_DIPLOMACY, ftc_server, _("Clause requirements are no longer fulfilled. " diff --git a/server/diplomats.c b/server/diplomats.c index 7d5c4d6348..4430a29379 100644 --- a/server/diplomats.c +++ b/server/diplomats.c @@ -1728,21 +1728,22 @@ bool spy_steal_some_maps(struct player *act_player, struct unit *act_unit, /* Steal it. */ normal_tile_prob = 100 + get_target_bonus_effects(NULL, - act_player, tgt_player, - /* Decide once requests from ruleset + &(const struct req_context) { + .player = act_player, + /* City: Decide once requests from ruleset * authors arrive. Could be target city or * - with a refactoring - the city at the * tile that may be transferred. */ - NULL, - NULL, - /* Decide once requests from ruleset + /* Tile: Decide once requests from ruleset * authors arrive. Could be actor unit * tile, target city tile or even - with a * refactoring - the tile that may be * transferred. */ - NULL, - act_unit, unit_type_get(act_unit), - NULL, NULL, paction, + .unit = act_unit, + .unittype = unit_type_get(act_unit), + .action = paction, + }, + tgt_player, EFT_MAPS_STOLEN_PCT); give_distorted_map(tgt_player, act_player, normal_tile_prob, @@ -1944,13 +1945,16 @@ static bool diplomat_success_vs_defender(struct unit *pattacker, } /* Reduce the chance of an attack by EFT_SPY_RESISTANT percent. */ - chance -= chance - * get_target_bonus_effects(NULL, - tile_owner(pdefender_tile), NULL, - tile_city(pdefender_tile), NULL, - pdefender_tile, NULL, NULL, NULL, - NULL, NULL, - EFT_SPY_RESISTANT) / 100; + chance -= chance * get_target_bonus_effects( + NULL, + &(const struct req_context) { + .player = tile_owner(pdefender_tile), + .city = tile_city(pdefender_tile), + .tile = pdefender_tile, + }, + NULL, + EFT_SPY_RESISTANT + ) / 100; chance = CLIP(0, chance, 100); diff --git a/server/generator/startpos.c b/server/generator/startpos.c index 6482aa9f71..d97e490d00 100644 --- a/server/generator/startpos.c +++ b/server/generator/startpos.c @@ -65,14 +65,16 @@ static int get_tile_value(struct tile *ptile) roaded = tile_virtual_new(ptile); if (num_role_units(L_SETTLERS) > 0) { - struct unit_type *start_worker = get_role_unit(L_SETTLERS, 0); + const struct req_context start_worker_ctxt = { + .tile = roaded, + .unittype = get_role_unit(L_SETTLERS, 0), + }; extra_type_by_cause_iterate(EC_ROAD, pextra) { struct road_type *proad = extra_road_get(pextra); if (road_can_be_built(proad, roaded) - && are_reqs_active(NULL, NULL, NULL, NULL, roaded, - NULL, start_worker, NULL, NULL, NULL, + && are_reqs_active(&start_worker_ctxt, NULL, &pextra->reqs, RPT_CERTAIN)) { tile_add_extra(roaded, pextra); } diff --git a/server/savegame/savegame2.c b/server/savegame/savegame2.c index 0b379ad64f..b8fd1872d9 100644 --- a/server/savegame/savegame2.c +++ b/server/savegame/savegame2.c @@ -911,6 +911,7 @@ static void sg_special_set(struct tile *ptile, bv_extras *extras, char ch, if (cause != EC_COUNT) { struct tile *vtile = tile_virtual_new(ptile); struct terrain *pterr = tile_terrain(vtile); + const struct req_context tile_ctxt = { .tile = vtile }; /* Do not let the extras already set to the real tile mess with setup * of the player tiles if that's what we're doing. */ @@ -930,8 +931,8 @@ static void sg_special_set(struct tile *ptile, bv_extras *extras, char ch, if ((!is_extra_caused_by(candidate, EC_BASE) || tile_city(vtile) != NULL || extra_base_get(candidate)->border_sq <= 0) - && are_reqs_active(NULL, tile_owner(vtile), NULL, NULL, vtile, - NULL, NULL, NULL, NULL, NULL, &candidate->reqs, + && are_reqs_active(&tile_ctxt, tile_owner(vtile), + &candidate->reqs, RPT_POSSIBLE)) { pextra = candidate; break; diff --git a/server/unithand.c b/server/unithand.c index 832dc1afd4..975042addd 100644 --- a/server/unithand.c +++ b/server/unithand.c @@ -639,16 +639,19 @@ static bool do_heal_unit(struct player *act_player, fc_assert_ret_val(tgt_tile, FALSE); /* The max amount of HP that can be added. */ - healing_limit = ((get_target_bonus_effects(NULL, - unit_owner(act_unit), - unit_owner(tgt_unit), - tile_city(unit_tile(act_unit)), - NULL, unit_tile(act_unit), - act_unit, - unit_type_get(act_unit), - NULL, NULL, paction, - EFT_HEAL_UNIT_PCT) - + 100) + healing_limit = ((get_target_bonus_effects( + NULL, + &(const struct req_context) { + .player = unit_owner(act_unit), + .city = tile_city(unit_tile(act_unit)), + .tile = unit_tile(act_unit), + .unit = act_unit, + .unittype = unit_type_get(act_unit), + .action = paction, + }, + unit_owner(tgt_unit), + EFT_HEAL_UNIT_PCT + ) + 100) * tgt_hp_max) / 100; /* Heal the target unit. */ @@ -2833,6 +2836,13 @@ static bool illegal_action_pay_price(struct player *pplayer, int punishment_mp; int punishment_hp; + const struct req_context actor_ctxt = { + .player = unit_owner(act_unit), + .unit = act_unit, + .unittype = unit_type_get(act_unit), + .action = stopped_action, + }; + /* Don't punish the player for something the game did. Don't tell the * player that the rules required the game to try to do something * illegal. */ @@ -2850,17 +2860,7 @@ static bool illegal_action_pay_price(struct player *pplayer, /* The mistake may have a cost. */ /* HP cost */ - punishment_hp = get_target_bonus_effects(NULL, - unit_owner(act_unit), - tgt_player, - NULL, - NULL, - NULL, - act_unit, - unit_type_get(act_unit), - NULL, - NULL, - stopped_action, + punishment_hp = get_target_bonus_effects(NULL, &actor_ctxt, tgt_player, EFT_ILLEGAL_ACTION_HP_COST); /* Stay in range */ @@ -2912,17 +2912,7 @@ static bool illegal_action_pay_price(struct player *pplayer, } /* MP cost */ - punishment_mp = get_target_bonus_effects(NULL, - unit_owner(act_unit), - tgt_player, - NULL, - NULL, - NULL, - act_unit, - unit_type_get(act_unit), - NULL, - NULL, - stopped_action, + punishment_mp = get_target_bonus_effects(NULL, &actor_ctxt, tgt_player, EFT_ILLEGAL_ACTION_MOVE_COST); /* Stay in range */ @@ -4339,10 +4329,15 @@ static void unit_attack_civilian_casualties(const struct unit *punit, if (pcity && get_target_bonus_effects(NULL, - city_owner(pcity), NULL, pcity, NULL, - city_tile(pcity), - punit, unit_type_get(punit), NULL, NULL, - paction, EFT_UNIT_NO_LOSE_POP) <= 0 + &(const struct req_context) { + .player = city_owner(pcity), + .city = pcity, + .tile = city_tile(pcity), + .unit = punit, + .unittype = unit_type_get(punit), + .action = paction, + }, + NULL, EFT_UNIT_NO_LOSE_POP) <= 0 && (game.info.killcitizen && uclass_has_flag(unit_class_get(punit), UCF_KILLCITIZEN))) { struct player *cplayer = city_owner(pcity); diff --git a/server/unittools.c b/server/unittools.c index 168dca2f5b..21eb54213a 100644 --- a/server/unittools.c +++ b/server/unittools.c @@ -2796,13 +2796,15 @@ void do_nuclear_explosion(const struct action *paction, { int nuke_radius_size = get_target_bonus_effects(NULL, - pplayer, NULL, - /* Wait for users before choosing home city - * or target tile city */ + &(const struct req_context) { + .player = pplayer, + /* City: Wait for users before choosing + * home city or target tile city */ + .tile = ptile, + .unittype = act_utype, + .action = paction, + }, NULL, - NULL, ptile, - NULL, act_utype, - NULL, NULL, paction, EFT_NUKE_BLAST_RADIUS_1_SQ); circle_iterate(&(wld.map), ptile, nuke_radius_size, ptile1) { @@ -3039,11 +3041,14 @@ static void unit_enter_hut(struct unit *punit, bool frighten_hut) int id = punit->id; struct tile *ptile = unit_tile(punit); bool hut = FALSE; + const struct req_context context = { + .player = pplayer, + .tile = ptile, + }; extra_type_by_rmcause_iterate(ERM_ENTER, pextra) { if (tile_has_extra(ptile, pextra) - && are_reqs_active(pplayer, tile_owner(ptile), NULL, NULL, ptile, - NULL, NULL, NULL, NULL, NULL, &pextra->rmreqs, + && are_reqs_active(&context, tile_owner(ptile), &pextra->rmreqs, RPT_CERTAIN) ) { hut = TRUE; -- 2.17.1