Author: sveinung Date: Fri Nov 13 06:36:44 2015 New Revision: 30589 URL: http://svn.gna.org/viewcvs/freeciv?rev=30589&view=rev Log: Centralize action actor target distance rules
Store an action's minimum and maximum legal distance between actor and target in the action structure it self. See patch #6588 Modified: trunk/client/goto.c trunk/common/actions.c trunk/common/actions.h Modified: trunk/client/goto.c URL: http://svn.gna.org/viewcvs/freeciv/trunk/client/goto.c?rev=30589&r1=30588&r2=30589&view=diff ============================================================================== --- trunk/client/goto.c (original) +++ trunk/client/goto.c Fri Nov 13 06:36:44 2015 @@ -1620,20 +1620,17 @@ * direction. */ return TRUE; case ORDER_PERFORM_ACTION: - switch (act_id) { - case ACTION_CAPTURE_UNITS: - case ACTION_BOMBARD: - /* Mandatory. A single domestic unit at the target tile will make - * the action illegal. It must therefore be performed from another - * tile. */ + if (!action_id_distance_accepted(act_id, 0)) { + /* Always illegal to do to a target on the actor's own tile. */ return TRUE; - case ACTION_FOUND_CITY: - case ACTION_RECYCLE_UNIT: - /* Currently illegal to perform to a target on another tile. */ + } + + if (!action_id_distance_accepted(act_id, 1)) { + /* Always illegal to perform to a target on a neighbor tile. */ return FALSE; - default: - return FALSE; - } + } + + return FALSE; default: return FALSE; } @@ -1651,15 +1648,12 @@ /* A move is always done in a direction. */ return TRUE; case ORDER_PERFORM_ACTION: - switch (act_id) { - case ACTION_CAPTURE_UNITS: - case ACTION_BOMBARD: - /* A single domestic unit at the target tile will make the action - * illegal. It must therefore be performed from another tile. */ + if (!action_id_distance_accepted(act_id, 0)) { + /* Always illegal to do to a target on the actor's own tile. */ return TRUE; - default: - return FALSE; - } + } + + return FALSE; default: return FALSE; } Modified: trunk/common/actions.c URL: http://svn.gna.org/viewcvs/freeciv/trunk/common/actions.c?rev=30589&r1=30588&r2=30589&view=diff ============================================================================== --- trunk/common/actions.c (original) +++ trunk/common/actions.c Fri Nov 13 06:36:44 2015 @@ -36,7 +36,9 @@ static struct action *action_new(enum gen_action id, enum action_target_kind target_kind, bool hostile, bool requires_details, - bool rare_pop_up); + bool rare_pop_up, + const int min_distance, + const int max_distance); static bool is_enabler_active(const struct action_enabler *enabler, const struct player *actor_player, @@ -63,83 +65,120 @@ { /* Hard code the actions */ actions[ACTION_SPY_POISON] = action_new(ACTION_SPY_POISON, ATK_CITY, - TRUE, FALSE, FALSE); + TRUE, FALSE, FALSE, + 0, 1); actions[ACTION_SPY_SABOTAGE_UNIT] = action_new(ACTION_SPY_SABOTAGE_UNIT, ATK_UNIT, - TRUE, FALSE, FALSE); + TRUE, FALSE, FALSE, + 0, 1); actions[ACTION_SPY_BRIBE_UNIT] = action_new(ACTION_SPY_BRIBE_UNIT, ATK_UNIT, - TRUE, FALSE, FALSE); + TRUE, FALSE, FALSE, + 0, 1); actions[ACTION_SPY_SABOTAGE_CITY] = action_new(ACTION_SPY_SABOTAGE_CITY, ATK_CITY, - TRUE, FALSE, FALSE); + TRUE, FALSE, FALSE, + 0, 1); actions[ACTION_SPY_TARGETED_SABOTAGE_CITY] = action_new(ACTION_SPY_TARGETED_SABOTAGE_CITY, ATK_CITY, - TRUE, TRUE, FALSE); + TRUE, TRUE, FALSE, + 0, 1); actions[ACTION_SPY_INCITE_CITY] = action_new(ACTION_SPY_INCITE_CITY, ATK_CITY, - TRUE, FALSE, FALSE); + TRUE, FALSE, FALSE, + 0, 1); actions[ACTION_ESTABLISH_EMBASSY] = action_new(ACTION_ESTABLISH_EMBASSY, ATK_CITY, - FALSE, FALSE, FALSE); + FALSE, FALSE, FALSE, + 0, 1); actions[ACTION_SPY_STEAL_TECH] = action_new(ACTION_SPY_STEAL_TECH, ATK_CITY, - TRUE, FALSE, FALSE); + TRUE, FALSE, FALSE, + 0, 1); actions[ACTION_SPY_TARGETED_STEAL_TECH] = action_new(ACTION_SPY_TARGETED_STEAL_TECH, ATK_CITY, - TRUE, TRUE, FALSE); + TRUE, TRUE, FALSE, + 0, 1); actions[ACTION_SPY_INVESTIGATE_CITY] = action_new(ACTION_SPY_INVESTIGATE_CITY, ATK_CITY, - TRUE, FALSE, FALSE); + TRUE, FALSE, FALSE, + 0, 1); actions[ACTION_SPY_STEAL_GOLD] = action_new(ACTION_SPY_STEAL_GOLD, ATK_CITY, - TRUE, FALSE, FALSE); + TRUE, FALSE, FALSE, + 0, 1); actions[ACTION_TRADE_ROUTE] = action_new(ACTION_TRADE_ROUTE, ATK_CITY, - FALSE, FALSE, FALSE); + FALSE, FALSE, FALSE, + 0, 1); actions[ACTION_MARKETPLACE] = action_new(ACTION_MARKETPLACE, ATK_CITY, - FALSE, FALSE, FALSE); + FALSE, FALSE, FALSE, + 0, 1); actions[ACTION_HELP_WONDER] = action_new(ACTION_HELP_WONDER, ATK_CITY, - FALSE, FALSE, FALSE); + FALSE, FALSE, FALSE, + 0, 1); actions[ACTION_CAPTURE_UNITS] = action_new(ACTION_CAPTURE_UNITS, ATK_UNITS, - TRUE, FALSE, FALSE); + TRUE, FALSE, FALSE, + /* A single domestic unit at the target tile will make the + * action illegal. It must therefore be performed from + * another tile. */ + 1, 1); actions[ACTION_FOUND_CITY] = action_new(ACTION_FOUND_CITY, ATK_TILE, - FALSE, FALSE, TRUE); + FALSE, FALSE, TRUE, + /* Illegal to perform to a target on another tile. + * Reason: The Freeciv code assumes that the city founding + * unit is located at the tile were the new city is + * founded. */ + 0, 0); actions[ACTION_JOIN_CITY] = action_new(ACTION_JOIN_CITY, ATK_CITY, - FALSE, FALSE, TRUE); + FALSE, FALSE, TRUE, + 0, 1); actions[ACTION_STEAL_MAPS] = action_new(ACTION_STEAL_MAPS, ATK_CITY, - TRUE, FALSE, FALSE); + TRUE, FALSE, FALSE, + 0, 1); actions[ACTION_BOMBARD] = action_new(ACTION_BOMBARD, /* FIXME: Target is actually Units + City */ ATK_UNITS, - TRUE, FALSE, FALSE); + TRUE, FALSE, FALSE, + /* A single domestic unit at the target tile will make the + * action illegal. It must therefore be performed from + * another tile. */ + 1, 1); actions[ACTION_SPY_NUKE] = action_new(ACTION_SPY_NUKE, ATK_CITY, - TRUE, FALSE, FALSE); + TRUE, FALSE, FALSE, + 0, 1); actions[ACTION_NUKE] = action_new(ACTION_NUKE, /* FIXME: Target is actually Tile + Units + City */ ATK_TILE, - TRUE, FALSE, TRUE); + TRUE, FALSE, TRUE, + 0, 1); actions[ACTION_DESTROY_CITY] = action_new(ACTION_DESTROY_CITY, ATK_CITY, - TRUE, FALSE, FALSE); + TRUE, FALSE, FALSE, + 0, 1); actions[ACTION_EXPEL_UNIT] = action_new(ACTION_EXPEL_UNIT, ATK_UNIT, - TRUE, FALSE, FALSE); + TRUE, FALSE, FALSE, + 0, 1); actions[ACTION_RECYCLE_UNIT] = action_new(ACTION_RECYCLE_UNIT, ATK_CITY, - FALSE, FALSE, TRUE); + FALSE, FALSE, TRUE, + /* Illegal to perform to a target on another tile to + * keep the rules exactly as they were for now. */ + 0, 0); actions[ACTION_DISBAND_UNIT] = action_new(ACTION_DISBAND_UNIT, ATK_SELF, - FALSE, FALSE, TRUE); + FALSE, FALSE, TRUE, + 0, 0); /* Initialize the action enabler list */ action_iterate(act) { @@ -203,7 +242,9 @@ static struct action *action_new(enum gen_action id, enum action_target_kind target_kind, bool hostile, bool requires_details, - bool rare_pop_up) + bool rare_pop_up, + const int min_distance, + const int max_distance) { struct action *action; @@ -212,9 +253,22 @@ action->id = id; action->actor_kind = AAK_UNIT; action->target_kind = target_kind; + action->hostile = hostile; action->requires_details = requires_details; action->rare_pop_up = rare_pop_up; + + /* The Freeciv code for all actions controlled by enablers assumes that + * an acting unit is on the same tile as its target or on the tile next + * to it. */ + fc_assert(max_distance <= 1); + + /* The distance between the actor and him self is always 0. */ + fc_assert(target_kind != ATK_SELF + || (min_distance == 0 && max_distance == 0)); + + action->min_distance = min_distance; + action->max_distance = max_distance; /* The ui_name is loaded from the ruleset. Until generalized actions * are ready it has to be defined seperatly from other action data. */ @@ -330,6 +384,19 @@ FALSE, "Action %d don't exist.", action_id); return actions[action_id]->rare_pop_up; +} + +/************************************************************************** + Returns TRUE iff the specified distance between actor and target is + within the range acceptable to the specified action. +**************************************************************************/ +bool action_distance_accepted(const struct action *action, + const int distance) +{ + fc_assert_ret_val(action, FALSE); + + return (distance >= action->min_distance + && distance <= action->max_distance); } /************************************************************************** @@ -946,12 +1013,12 @@ return TRI_NO; } - if (action_get_actor_kind(wanted_action) == AAK_UNIT - && action_get_target_kind(wanted_action) != ATK_SELF) { - /* The Freeciv code for all actions controlled by enablers assumes that - * an acting unit is on the same tile as its target or on the tile next - * to it. */ - if (real_map_distance(actor_tile, target_tile) > 1) { + if (action_get_target_kind(wanted_action) != ATK_SELF) { + if (!action_id_distance_accepted(wanted_action, + 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; } } @@ -1097,22 +1164,9 @@ /* FIXME: The next item may be forbidden from receiving help. But * forbidding the player from recycling a unit because the production * has enough, like Help Wonder does, would be a rule change. */ - - /* Reason: Keep the rules exactly as they were for now. */ - /* Info leak: The actor player knows where his unit is. */ - if (unit_tile(actor_unit) != target_tile) { - return TRI_NO; - } } if (wanted_action == ACTION_FOUND_CITY) { - /* Reason: The Freeciv code assumes that the city founding unit is - * located the the tile were the new city is founded. */ - /* Info leak: The actor player knows where his unit is. */ - if (unit_tile(actor_unit) != target_tile) { - return TRI_NO; - } - /* TODO: Move more individual requirements to the action enabler. */ if (!unit_can_build_city(actor_unit)) { return TRI_NO; Modified: trunk/common/actions.h URL: http://svn.gna.org/viewcvs/freeciv/trunk/common/actions.h?rev=30589&r1=30588&r2=30589&view=diff ============================================================================== --- trunk/common/actions.h (original) +++ trunk/common/actions.h Fri Nov 13 06:36:44 2015 @@ -192,6 +192,11 @@ * action. */ bool rare_pop_up; + /* Limits on the distance on the map between the actor and the target. + * The action is legal iff the distance is min_distance, max_distance or + * a value in between. */ + int min_distance, max_distance; + /* The name of the action shown in the UI */ char ui_name[MAX_LEN_NAME]; }; @@ -254,6 +259,11 @@ bool action_requires_details(int action_id); bool action_id_is_rare_pop_up(int action_id); + +bool action_distance_accepted(const struct action *action, + const int distance); +#define action_id_distance_accepted(action_id, distance) \ + action_distance_accepted(action_by_number(action_id), distance) int action_get_role(int action_id); _______________________________________________ Freeciv-commits mailing list Freeciv-commits@gna.org https://mail.gna.org/listinfo/freeciv-commits