Author: sveinung
Date: Thu Sep 17 14:43:15 2015
New Revision: 29911

URL: http://svn.gna.org/viewcvs/freeciv?rev=29911&view=rev
Log:
Close wonder specific "Help Wonder" loop hole

The ruleset can now forbid doing an action to a city based on what it
builds. This is less useful for the "Help Wonder" action than expected.

A rule that forbids using a caravan to help a specific wonder can be avoided
in many rulesets. The rule is avoided by switching to a wonder that legally
can received help from a caravan, get the shields and then switch back.
Rulesets where no wonder that can receive caravan shield can be built at the
same time as a wonder that can't aren't affected.

Close the loop hole by only allowing the caravan shields to count if the
new production can be helped by the "Help Wonder" action.

A related loop hole remains for complex rule sets: If "Wonder A" only can
receive help from "Unit 1" while "Wonder B" can receive help from "Unit 2" a
player could switch from "Wonder A" to "Wonder B", use a "Unit 2" to help
build the wonder and then switch back. Solving that isn't in the scope of
this patch.

Only caravan shields are touched. Switching between the hard coded
categories still halves the amount of shields.

See patch #6357

Modified:
    trunk/ai/default/advdomestic.c
    trunk/ai/default/aiunit.c
    trunk/client/packhand.c
    trunk/common/aicore/caravan.c
    trunk/common/city.c
    trunk/common/city.h
    trunk/server/ruleset.c

Modified: trunk/ai/default/advdomestic.c
URL: 
http://svn.gna.org/viewcvs/freeciv/trunk/ai/default/advdomestic.c?rev=29911&r1=29910&r2=29911&view=diff
==============================================================================
--- trunk/ai/default/advdomestic.c      (original)
+++ trunk/ai/default/advdomestic.c      Thu Sep 17 14:43:15 2015
@@ -93,7 +93,11 @@
   if (pcity == wonder_city 
       || wonder_city == NULL
       || city_data->distance_to_wonder_city <= 0
+      || !city_production_gets_caravan_shields(wonder_city->production)
+      /* TODO: Should helping to build a unit be considered when legal? */
       || VUT_UTYPE == wonder_city->production.kind
+      /* TODO: Should helping to build an improvement be considered when
+       * legal? */
       || !is_wonder(wonder_city->production.value.building)) {
     /* A distance of zero indicates we are very far away, possibly
      * on another continent. */

Modified: trunk/ai/default/aiunit.c
URL: 
http://svn.gna.org/viewcvs/freeciv/trunk/ai/default/aiunit.c?rev=29911&r1=29910&r2=29911&view=diff
==============================================================================
--- trunk/ai/default/aiunit.c   (original)
+++ trunk/ai/default/aiunit.c   Thu Sep 17 14:43:15 2015
@@ -2173,8 +2173,8 @@
             && !(can_cities_trade(homecity, city_dest)
                  && can_establish_trade_route(homecity, city_dest)))
         || (unit_data->task == AIUNIT_WONDER
-            && city_dest->production.kind == VUT_IMPROVEMENT
-            && !is_wonder(city_dest->production.value.building))
+            /* Helping the (new) production is illegal. */
+            && !city_production_gets_caravan_shields(city_dest->production))
         || (unit_data->task == AIUNIT_TRADE
             && real_map_distance(city_dest->tile, unit_tile(punit)) <= 1
             && !(is_action_enabled_unit_on_city(ACTION_TRADE_ROUTE,

Modified: trunk/client/packhand.c
URL: 
http://svn.gna.org/viewcvs/freeciv/trunk/client/packhand.c?rev=29911&r1=29910&r2=29911&view=diff
==============================================================================
--- trunk/client/packhand.c     (original)
+++ trunk/client/packhand.c     Thu Sep 17 14:43:15 2015
@@ -3072,6 +3072,9 @@
     u->unknown_move_cost = utype_unknown_move_cost(u);
     unit_type_action_cache_set(u);
   } unit_type_iterate_end;
+
+  /* Cache what city production can receive help from caravans. */
+  city_production_caravan_shields_init();
 
   /* We are not going to crop any more sprites from big sprites, free them. */
   finish_loading_sprites(tileset);

Modified: trunk/common/aicore/caravan.c
URL: 
http://svn.gna.org/viewcvs/freeciv/trunk/common/aicore/caravan.c?rev=29911&r1=29910&r2=29911&view=diff
==============================================================================
--- trunk/common/aicore/caravan.c       (original)
+++ trunk/common/aicore/caravan.c       Thu Sep 17 14:43:15 2015
@@ -359,8 +359,13 @@
   int shields_at_arrival;
 
   if (!param->consider_wonders
+      /* TODO: Should helping an ally to build be considered when legal? */
       || unit_owner(caravan) != city_owner(dest)
+      || !city_production_gets_caravan_shields(dest->production)
+      /* TODO: Should helping to build a unit be considered when legal? */
       || VUT_UTYPE == dest->production.kind
+      /* TODO: Should helping to build an improvement be considered when
+       * legal? */
       || !is_wonder(dest->production.value.building)) {
     return 0;
   }

Modified: trunk/common/city.c
URL: 
http://svn.gna.org/viewcvs/freeciv/trunk/common/city.c?rev=29911&r1=29910&r2=29911&view=diff
==============================================================================
--- trunk/common/city.c (original)
+++ trunk/common/city.c Thu Sep 17 14:43:15 2015
@@ -1691,6 +1691,76 @@
    return rule_name(&city_styles[style].name);
 }
 
+/* Cache of what city production caravan shields are allowed to help. */
+static bv_imprs caravan_helped_impr;
+static bv_unit_types caravan_helped_utype;
+
+/**************************************************************************
+  Initialize the cache of what city production can use shields from
+  caravans.
+**************************************************************************/
+void city_production_caravan_shields_init(void)
+{
+  struct requirement prod_as_req;
+
+  /* Remove old data. */
+  BV_CLR_ALL(caravan_helped_impr);
+  BV_CLR_ALL(caravan_helped_utype);
+
+  /* Common for all production kinds. */
+  prod_as_req.range = REQ_RANGE_LOCAL;
+  prod_as_req.survives = FALSE;
+  prod_as_req.present = TRUE;
+
+  /* Check improvements */
+  prod_as_req.source.kind = VUT_IMPROVEMENT;
+
+  improvement_iterate(itype) {
+    if (!is_wonder(itype)) {
+      /* Only wonders can currently use caravan shields. Next! */
+      continue;
+    }
+
+    /* Check this improvement. */
+    prod_as_req.source.value.building = itype;
+
+    action_enabler_list_iterate(action_enablers_for_action(
+                                  ACTION_HELP_WONDER),
+                                enabler) {
+      if (!does_req_contradicts_reqs(&prod_as_req,
+                                     &(enabler->target_reqs))) {
+        /* This improvement kind can receive caravan shields. */
+
+        BV_SET(caravan_helped_impr, improvement_index(itype));
+
+        /* Move on to the next improvment */
+        break;
+      }
+    } action_enabler_list_iterate_end;
+  } improvement_iterate_end;
+
+  /* Units can't currently use caravan shields. */
+}
+
+/**************************************************************************
+  Returns TRUE iff the specified production should get shields from
+  units that has done ACTION_HELP_WONDER.
+**************************************************************************/
+bool city_production_gets_caravan_shields(const struct universal tgt)
+{
+  switch (tgt.kind) {
+  case VUT_IMPROVEMENT:
+    return BV_ISSET(caravan_helped_impr,
+                    improvement_index(tgt.value.building));
+  case VUT_UTYPE:
+    return BV_ISSET(caravan_helped_utype,
+                    utype_index(tgt.value.utype));
+  default:
+    fc_assert(FALSE);
+    return FALSE;
+  };
+}
+
 /**************************************************************************
  Compute and optionally apply the change-production penalty for the given
  production change (to target) in the given city (pcity).
@@ -1765,7 +1835,7 @@
 
   /* Caravan shields are penalized (just as if you disbanded the caravan)
    * if you're not building a wonder. */
-  if (new_class == PCT_WONDER) {
+  if (city_production_gets_caravan_shields(target)) {
     unpenalized_shields += pcity->caravan_shields;
   } else {
     penalized_shields += pcity->caravan_shields;

Modified: trunk/common/city.h
URL: 
http://svn.gna.org/viewcvs/freeciv/trunk/common/city.h?rev=29911&r1=29910&r2=29911&view=diff
==============================================================================
--- trunk/common/city.h (original)
+++ trunk/common/city.h Thu Sep 17 14:43:15 2015
@@ -588,6 +588,8 @@
 int city_production_turns_to_build(const struct city *pcity,
                                   bool include_shield_stock);
 
+bool city_production_gets_caravan_shields(const struct universal tgt);
+
 int city_change_production_penalty(const struct city *pcity,
                                   struct universal target);
 int city_turns_to_build(const struct city *pcity,
@@ -624,6 +626,7 @@
 int compare_iter_index(const void *a, const void *b);
 void generate_city_map_indices(void);
 void free_city_map_index(void);
+void city_production_caravan_shields_init(void);
 
 /* output on spot */
 int city_tile_output(const struct city *pcity, const struct tile *ptile,

Modified: trunk/server/ruleset.c
URL: 
http://svn.gna.org/viewcvs/freeciv/trunk/server/ruleset.c?rev=29911&r1=29910&r2=29911&view=diff
==============================================================================
--- trunk/server/ruleset.c      (original)
+++ trunk/server/ruleset.c      Thu Sep 17 14:43:15 2015
@@ -7187,6 +7187,7 @@
     unit_type_iterate(u) {
       u->unknown_move_cost = utype_unknown_move_cost(u);
     } unit_type_iterate_end;
+    city_production_caravan_shields_init();
 
     /* Build advisors unit class cache corresponding to loaded rulesets */
     adv_units_ruleset_init();


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

Reply via email to