Author: sveinung
Date: Fri Jun 10 12:25:44 2016
New Revision: 32820

URL: http://svn.gna.org/viewcvs/freeciv?rev=32820&view=rev
Log:
More cross target kind action blocking support.

Find target tile and city to evaluate if an action with a different kind of
target blocks an action.

An action with a unit target can't block an action with a non unit target.

Not used yet. Added now to avoid future hard to debug surprises.

See patch #7255

Modified:
    trunk/common/actions.c
    trunk/server/rssanity.c

Modified: trunk/common/actions.c
URL: 
http://svn.gna.org/viewcvs/freeciv/trunk/common/actions.c?rev=32820&r1=32819&r2=32820&view=diff
==============================================================================
--- trunk/common/actions.c      (original)
+++ trunk/common/actions.c      Fri Jun 10 12:25:44 2016
@@ -805,6 +805,108 @@
 }
 
 /**************************************************************************
+  Returns the target tile for actions that may block the specified action.
+  This is needed because some actions can be blocked by an action with a
+  different target kind. The target tile could therefore be missing.
+
+  Example: The ATK_SELF action ACTION_DISBAND_UNIT can be blocked by the
+  ATK_CITY action ACTION_RECYCLE_UNIT.
+**************************************************************************/
+static const struct tile *
+blocked_find_target_tile(const int action_id,
+                         const struct unit *actor_unit,
+                         const struct tile *target_tile_arg,
+                         const struct city *target_city,
+                         const struct unit *target_unit)
+{
+  if (target_tile_arg != NULL) {
+    /* Trust the caller. */
+    return target_tile_arg;
+  }
+
+  switch (action_get_target_kind(action_id)) {
+  case ATK_CITY:
+    fc_assert_ret_val(target_city, NULL);
+    return city_tile(target_city);
+  case ATK_UNIT:
+    fc_assert_ret_val(target_unit, NULL);
+    return unit_tile(target_unit);
+  case ATK_UNITS:
+    fc_assert_ret_val(target_unit || target_tile_arg, NULL);
+    if (target_unit) {
+      return unit_tile(target_unit);
+    }
+    /* Fall through. */
+  case ATK_TILE:
+    fc_assert_ret_val(target_tile_arg, NULL);
+    return target_tile_arg;
+  case ATK_SELF:
+    fc_assert_ret_val(actor_unit, NULL);
+    return unit_tile(actor_unit);
+  case ATK_COUNT:
+    /* Handled below. */
+    break;
+  }
+
+  fc_assert_msg(FALSE, "Bad action target kind %d for action %d",
+                action_get_target_kind(action_id), action_id);
+  return NULL;
+}
+
+/**************************************************************************
+  Returns the target city for actions that may block the specified action.
+  This is needed because some actions can be blocked by an action with a
+  different target kind. The target city argument could therefore be
+  missing.
+
+  Example: The ATK_SELF action ACTION_DISBAND_UNIT can be blocked by the
+  ATK_CITY action ACTION_RECYCLE_UNIT.
+**************************************************************************/
+static const struct city *
+blocked_find_target_city(const int action_id,
+                         const struct unit *actor_unit,
+                         const struct tile *target_tile,
+                         const struct city *target_city_arg,
+                         const struct unit *target_unit)
+{
+  if (target_city_arg != NULL) {
+    /* Trust the caller. */
+    return target_city_arg;
+  }
+
+  switch (action_get_target_kind(action_id)) {
+  case ATK_CITY:
+    fc_assert_ret_val(target_city_arg, NULL);
+    return target_city_arg;
+  case ATK_UNIT:
+    fc_assert_ret_val(target_unit, NULL);
+    fc_assert_ret_val(unit_tile(target_unit), NULL);
+    return tile_city(unit_tile(target_unit));
+  case ATK_UNITS:
+    fc_assert_ret_val(target_unit || target_tile, NULL);
+    if (target_unit) {
+      fc_assert_ret_val(unit_tile(target_unit), NULL);
+      return tile_city(unit_tile(target_unit));
+    }
+    /* Fall through. */
+  case ATK_TILE:
+    fc_assert_ret_val(target_tile, NULL);
+    return tile_city(target_tile);
+  case ATK_SELF:
+    fc_assert_ret_val(actor_unit, NULL);
+    fc_assert_ret_val(unit_tile(actor_unit), NULL);
+    return tile_city(unit_tile(actor_unit));
+  case ATK_COUNT:
+    /* Handled below. */
+    break;
+  }
+
+  fc_assert_msg(FALSE, "Bad action target kind %d for action %d",
+                action_get_target_kind(action_id), action_id);
+  return NULL;
+}
+
+/**************************************************************************
   Returns the action that blocks the specified action or NULL if the
   specified action isn't blocked.
 
@@ -816,17 +918,14 @@
                                     const struct city *target_city_arg,
                                     const struct unit *target_unit)
 {
-  /* Special case ATK_SELF so Help Wonder disband or Recycle Unit disband
-   * can block Disband Unit disband. */
+
 
   const struct tile *target_tile
-      = (action_get_target_kind(action_id) != ATK_SELF
-         ? target_tile_arg
-         : unit_tile(actor_unit));
+      = blocked_find_target_tile(action_id, actor_unit, target_tile_arg,
+                                 target_city_arg, target_unit);
   const struct city *target_city
-      = (action_get_target_kind(action_id) != ATK_SELF
-         ? target_city_arg
-         : tile_city(unit_tile(actor_unit)));
+      = blocked_find_target_city(action_id, actor_unit, target_tile,
+                                 target_city_arg, target_unit);
 
   action_iterate(blocker_id) {
     fc_assert_action(action_get_actor_kind(blocker_id) == AAK_UNIT,

Modified: trunk/server/rssanity.c
URL: 
http://svn.gna.org/viewcvs/freeciv/trunk/server/rssanity.c?rev=32820&r1=32819&r2=32820&view=diff
==============================================================================
--- trunk/server/rssanity.c     (original)
+++ trunk/server/rssanity.c     Fri Jun 10 12:25:44 2016
@@ -887,8 +887,25 @@
     }
   }
 
-  /* Action enablers */
+  /* Actions */
   action_iterate(act) {
+    struct action *paction = action_by_number(act);
+
+    action_iterate(blocker) {
+      if (BV_ISSET(paction->blocked_by, blocker)
+          && action_get_target_kind(blocker) == ATK_UNIT
+          && action_get_target_kind(act) != ATK_UNIT) {
+        /* Can't find an individual unit target to evaluate the blocking
+         * action against. (A tile may have more than one individual
+         * unit) */
+        ruleset_error(LOG_ERROR,
+                      "The action %s can't block %s.",
+                      action_get_rule_name(blocker),
+                      action_get_rule_name(act));
+        ok = FALSE;
+      }
+    } action_iterate_end;
+
     action_enabler_list_iterate(action_enablers_for_action(act), enabler) {
       if (!sanity_check_req_vec(&(enabler->actor_reqs), TRUE, -1,
                                 "Action Enabler Actor Reqs")


_______________________________________________
Freeciv-commits mailing list
Freeciv-commits@gna.org
https://mail.gna.org/listinfo/freeciv-commits

Reply via email to