Skip to content

Commit

Permalink
Validate action target kind.
Browse files Browse the repository at this point in the history
Allowing the ruleset to change action target kind requires that Freeciv
validates that the specified target kind will work with the action's result.

See osdn #41498
  • Loading branch information
kvilhaugsvik committed Feb 6, 2021
1 parent 44b0efc commit a26806b
Show file tree
Hide file tree
Showing 3 changed files with 108 additions and 0 deletions.
97 changes: 97 additions & 0 deletions common/actions.c
Expand Up @@ -7596,6 +7596,103 @@ const char *action_target_kind_ruleset_var_name(int act)
return NULL;
}

/**********************************************************************//**
Returns TRUE iff the specified action result works with the specified
action target kind.
**************************************************************************/
bool action_result_legal_target_kind(enum action_result result,
enum action_target_kind tgt_kind)
{
fc_assert_ret_val(action_result_is_valid(result) || result == ACTRES_NONE,
FALSE);
fc_assert_ret_val(action_target_kind_is_valid(tgt_kind),
FALSE);

switch (result) {
case ACTRES_ESTABLISH_EMBASSY:
case ACTRES_SPY_INVESTIGATE_CITY:
case ACTRES_SPY_POISON:
case ACTRES_SPY_STEAL_GOLD:
case ACTRES_SPY_SABOTAGE_CITY:
case ACTRES_SPY_TARGETED_SABOTAGE_CITY:
case ACTRES_SPY_SABOTAGE_CITY_PRODUCTION:
case ACTRES_SPY_STEAL_TECH:
case ACTRES_SPY_TARGETED_STEAL_TECH:
case ACTRES_SPY_INCITE_CITY:
case ACTRES_TRADE_ROUTE:
case ACTRES_MARKETPLACE:
case ACTRES_HELP_WONDER:
case ACTRES_JOIN_CITY:
case ACTRES_STEAL_MAPS:
case ACTRES_SPY_NUKE:
case ACTRES_NUKE_CITY:
case ACTRES_DESTROY_CITY:
case ACTRES_RECYCLE_UNIT:
case ACTRES_HOME_CITY:
case ACTRES_UPGRADE_UNIT:
case ACTRES_AIRLIFT:
case ACTRES_STRIKE_BUILDING:
case ACTRES_STRIKE_PRODUCTION:
case ACTRES_CONQUER_CITY:
case ACTRES_SPY_SPREAD_PLAGUE:
return tgt_kind == ATK_CITY;
case ACTRES_SPY_BRIBE_UNIT:
case ACTRES_SPY_SABOTAGE_UNIT:
case ACTRES_EXPEL_UNIT:
case ACTRES_HEAL_UNIT:
case ACTRES_TRANSPORT_ALIGHT:
case ACTRES_TRANSPORT_UNLOAD:
case ACTRES_TRANSPORT_BOARD:
case ACTRES_TRANSPORT_EMBARK:
return tgt_kind == ATK_UNIT;
case ACTRES_CAPTURE_UNITS:
case ACTRES_BOMBARD:
case ACTRES_NUKE_UNITS:
case ACTRES_ATTACK:
case ACTRES_SPY_ATTACK:
return tgt_kind == ATK_UNITS;
case ACTRES_FOUND_CITY:
case ACTRES_NUKE:
case ACTRES_PARADROP:
case ACTRES_TRANSFORM_TERRAIN:
case ACTRES_CULTIVATE:
case ACTRES_PLANT:
case ACTRES_PILLAGE:
case ACTRES_CLEAN_POLLUTION:
case ACTRES_CLEAN_FALLOUT:
case ACTRES_ROAD:
case ACTRES_BASE:
case ACTRES_MINE:
case ACTRES_IRRIGATE:
case ACTRES_TRANSPORT_DISEMBARK:
return tgt_kind == ATK_TILE;
case ACTRES_CONQUER_EXTRAS:
return tgt_kind == ATK_EXTRAS;
case ACTRES_DISBAND_UNIT:
case ACTRES_CONVERT:
case ACTRES_FORTIFY:
return tgt_kind == ATK_SELF;
case ACTRES_NONE:
switch (tgt_kind) {
case ATK_CITY:
case ATK_UNIT:
case ATK_UNITS:
case ATK_TILE:
case ATK_EXTRAS:
case ATK_SELF:
/* Works with all existing target kinds. */
return TRUE;
case ATK_COUNT:
fc_assert_ret_val(tgt_kind != ATK_COUNT, FALSE);
break;
}
break;
}

/* Should never be reached. */
return FALSE;
}

/**********************************************************************//**
Return actor consuming always ruleset variable name for the action or
NULL if actor consuming always can't be set in the ruleset.
Expand Down
3 changes: 3 additions & 0 deletions common/actions.h
Expand Up @@ -622,6 +622,9 @@ const char *action_max_range_ruleset_var_name(int act);
int action_max_range_default(int act);

const char *action_target_kind_ruleset_var_name(int act);
bool action_result_legal_target_kind(enum action_result result,
enum action_target_kind tgt_kind);

const char *action_actor_consuming_always_ruleset_var_name(action_id act);

const char *action_blocked_by_ruleset_var_name(const struct action *act);
Expand Down
8 changes: 8 additions & 0 deletions server/rssanity.c
Expand Up @@ -1047,6 +1047,14 @@ bool sanity_check_ruleset_data(bool ignore_retired)
action_iterate(act) {
struct action *paction = action_by_number(act);

if (!action_result_legal_target_kind(paction->result,
paction->target_kind)) {
ruleset_error(LOG_ERROR, "Action \"%s\": unsupported target kind %s.",
action_id_rule_name(act),
action_target_kind_name(paction->target_kind));
ok = FALSE;
}

if (paction->min_distance < 0) {
ruleset_error(LOG_ERROR, "Action %s: negative min distance (%d).",
action_id_rule_name(act), paction->min_distance);
Expand Down

0 comments on commit a26806b

Please sign in to comment.