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

Reply via email to