<URL: http://bugs.freeciv.org/Ticket/Display.html?id=40619 >

The gold upkeep patch (version 2)

changes:

- give the struct for the list some memory and free all used memory
- split the patch in two parts:
  * the patch
  * some freelog(LOG_NORMAL,...) debugging messages
- correct an error in the definition of the default value
- additional comments / explanations
- randomly chosen unit to disband

The patch was tested with an adapted ruleset (gold upkeep).

Matthias

diff -ur -X./freeciv-2.1.99svn15393/diff_ignore freeciv-2.1.99svn.patch_gold/server/cityturn.c freeciv-2.1.99svn.patch_gold_debug/server/cityturn.c
--- freeciv-2.1.99svn.patch_gold/server/cityturn.c	2009-01-04 22:08:54.000000000 +0100
+++ freeciv-2.1.99svn.patch_gold_debug/server/cityturn.c	2009-01-04 22:08:03.000000000 +0100
@@ -428,7 +428,6 @@
   int gold;
   gold=pplayer->economic.gold;
   pplayer->bulbs_last_turn = 0;
-
   /* finances depend on the setting for 'game.info.economicsystem'
    * 0: finances are check for each city (old system; done in
    *    update_city_activity())
@@ -440,7 +439,11 @@
   if (game.info.economicsystem == 1 && pplayer->economic.gold < 0) {
     /* not enough gold - we have to sell something or even kill some
      * units (only with gold upkeep!) to get the gold */
+    freelog(LOG_NORMAL,"[E:N] %d - %6d (balance:start)",
+            game.info.economicsystem, pplayer->economic.gold);
     balance_finances_nation(pplayer);
+    freelog(LOG_NORMAL,"[E:N] %d - %6d (balance:end)",
+            game.info.economicsystem, pplayer->economic.gold);
   }
 
   pplayer->ai.prev_gold = gold;
@@ -1952,14 +1955,24 @@
     update_tech(pplayer, pcity->prod[O_SCIENCE]);
 
     /* finances */
+    freelog(LOG_NORMAL,"[E:C %s] %d - %6d (before)", city_name(pcity),
+            game.info.economicsystem, pplayer->economic.gold);
     pplayer->economic.gold += pcity->prod[O_GOLD];
+    freelog(LOG_NORMAL,"[E:C %s] %d - %6d (prod)", city_name(pcity),
+            game.info.economicsystem, pplayer->economic.gold);
     pplayer->economic.gold -= pay_for_buildings(pcity);
+    freelog(LOG_NORMAL,"[E:C %s] %d - %6d (buildings)", city_name(pcity),
+            game.info.economicsystem, pplayer->economic.gold);
     pplayer->economic.gold -= pay_for_units(pcity);
+    freelog(LOG_NORMAL,"[E:C %s] %d - %6d (units)", city_name(pcity),
+            game.info.economicsystem, pplayer->economic.gold);
 
     if (game.info.economicsystem == 0 && pplayer->economic.gold < 0) {
       /* not enough gold - we have to sell something or even kill some
        * units (only with gold upkeep!) to get the gold */
       balance_finances_city(pplayer, pcity);
+      freelog(LOG_NORMAL,"[E:C %s] %d - %6d (balance)", city_name(pcity),
+              game.info.economicsystem, pplayer->economic.gold);
     }
 
     if(city_unhappy(pcity)) {
diff -ur -X./freeciv-2.1.99svn15393/diff_ignore freeciv-2.1.99svn.patch_shuffle/common/game.h freeciv-2.1.99svn.patch_gold/common/game.h
--- freeciv-2.1.99svn.patch_shuffle/common/game.h	2008-12-30 23:29:33.000000000 +0100
+++ freeciv-2.1.99svn.patch_gold/common/game.h	2009-01-04 21:54:19.000000000 +0100
@@ -183,6 +183,10 @@
 #define GAME_MIN_AIFILL              0
 #define GAME_MAX_AIFILL              GAME_MAX_MAX_PLAYERS
 
+#define GAME_DEFAULT_ECONOMIC_SYSTEM 0
+#define GAME_MIN_ECONOMIC_SYSTEM     0
+#define GAME_MAX_ECONOMIC_SYSTEM     1
+
 #define GAME_DEFAULT_FOODBOX         100
 #define GAME_MIN_FOODBOX             1
 #define GAME_MAX_FOODBOX             10000
diff -ur -X./freeciv-2.1.99svn15393/diff_ignore freeciv-2.1.99svn.patch_shuffle/common/packets.def freeciv-2.1.99svn.patch_gold/common/packets.def
--- freeciv-2.1.99svn.patch_shuffle/common/packets.def	2008-12-30 23:29:33.000000000 +0100
+++ freeciv-2.1.99svn.patch_gold/common/packets.def	2009-01-04 21:22:01.000000000 +0100
@@ -389,6 +389,7 @@
   UINT8 diplcost, freecost, conquercost;
   UINT8 angrycitizen;
   UINT8 techpenalty;
+  UINT8 economicsystem;
   UINT32 foodbox;
   UINT32 shieldbox;
   UINT32 sciencebox;
diff -ur -X./freeciv-2.1.99svn15393/diff_ignore freeciv-2.1.99svn.patch_shuffle/data/civ1/game.ruleset freeciv-2.1.99svn.patch_gold/data/civ1/game.ruleset
--- freeciv-2.1.99svn.patch_shuffle/data/civ1/game.ruleset	2008-12-30 23:29:34.000000000 +0100
+++ freeciv-2.1.99svn.patch_gold/data/civ1/game.ruleset	2009-01-04 21:54:25.000000000 +0100
@@ -56,6 +56,17 @@
 ;   "Fallout"   - Nuclear Fallout (distinct from industrial/population).
 nuke_contamination	= "Pollution"
 
+; Parameters used to describe the economic system
+; 0: Gold upkeep for buildings and units has to be paid by the each city.
+;    If there is not enough gold, randomly chosen buildings of the city
+;    are sold. If there still is not enough gold, units of this city with
+;    gold upkeep are disbanded. (old system)
+; 1: Gold upkeep for buildings and units comes from the overall finances.
+;    If there is not enough gold first randomly chosen buildings (taking
+;    into account _all_ cities) are sold, after that units with gold upkeep
+;    are disbanded.
+economicsystem = 0
+
 ; Parameters used to generalize the calculation of city granary size:
 ;   if city_size <= num_inis:
 ;     city_granary_size = (granary_food_ini[city_size] * foodbox / 100)
diff -ur -X./freeciv-2.1.99svn15393/diff_ignore freeciv-2.1.99svn.patch_shuffle/data/civ2/game.ruleset freeciv-2.1.99svn.patch_gold/data/civ2/game.ruleset
--- freeciv-2.1.99svn.patch_shuffle/data/civ2/game.ruleset	2008-12-30 23:29:34.000000000 +0100
+++ freeciv-2.1.99svn.patch_gold/data/civ2/game.ruleset	2009-01-04 21:54:28.000000000 +0100
@@ -50,6 +50,17 @@
 ;   "Fallout"   - Nuclear Fallout (distinct from industrial/population).
 nuke_contamination	= "Pollution"
 
+; Parameters used to describe the economic system
+; 0: Gold upkeep for buildings and units has to be paid by the each city.
+;    If there is not enough gold, randomly chosen buildings of the city
+;    are sold. If there still is not enough gold, units of this city with
+;    gold upkeep are disbanded. (old system)
+; 1: Gold upkeep for buildings and units comes from the overall finances.
+;    If there is not enough gold first randomly chosen buildings (taking
+;    into account _all_ cities) are sold, after that units with gold upkeep
+;    are disbanded.
+economicsystem = 0
+
 ; Parameters used to generalize the calculation of city granary size:
 ;   if city_size <= num_inis:
 ;     city_granary_size = (granary_food_ini[city_size] * foodbox / 100)
diff -ur -X./freeciv-2.1.99svn15393/diff_ignore freeciv-2.1.99svn.patch_shuffle/data/default/game.ruleset freeciv-2.1.99svn.patch_gold/data/default/game.ruleset
--- freeciv-2.1.99svn.patch_shuffle/data/default/game.ruleset	2008-12-30 23:29:34.000000000 +0100
+++ freeciv-2.1.99svn.patch_gold/data/default/game.ruleset	2009-01-04 21:54:22.000000000 +0100
@@ -68,6 +68,17 @@
 ;   "Fallout"   - Nuclear Fallout (distinct from industrial/population).
 nuke_contamination	= "Fallout"
 
+; Parameters used to describe the economic system
+; 0: Gold upkeep for buildings and units has to be paid by the each city.
+;    If there is not enough gold, randomly chosen buildings of the city
+;    are sold. If there still is not enough gold, units of this city with
+;    gold upkeep are disbanded. (old system)
+; 1: Gold upkeep for buildings and units comes from the overall finances.
+;    If there is not enough gold first randomly chosen buildings (taking
+;    into account _all_ cities) are sold, after that units with gold upkeep
+;    are disbanded.
+economicsystem = 0
+
 ; Parameters used to generalize the calculation of city granary size:
 ;   if city_size <= num_inis:
 ;     city_granary_size = (granary_food_ini[city_size] * foodbox / 100)
diff -ur -X./freeciv-2.1.99svn15393/diff_ignore freeciv-2.1.99svn.patch_shuffle/server/cityturn.c freeciv-2.1.99svn.patch_gold/server/cityturn.c
--- freeciv-2.1.99svn.patch_shuffle/server/cityturn.c	2008-12-25 19:45:49.000000000 +0100
+++ freeciv-2.1.99svn.patch_gold/server/cityturn.c	2009-01-04 22:08:54.000000000 +0100
@@ -82,7 +82,18 @@
 static struct unit_type *unit_upgrades_to(struct city *pcity,
 					  struct unit_type *id);
 static void upgrade_unit_prod(struct city *pcity);
-static void pay_for_buildings(struct player *pplayer, struct city *pcity);
+static int pay_for_buildings(const struct city *pcity);
+static bool sell_buildings(struct player *pplayer,
+                           struct city_improve_list *pcity_improve_sell);
+static void balance_finances_nation(struct player *pplayer);
+static void balance_finances_city(struct player *pplayer,
+                                  struct city *pcity);
+
+static struct city_improve *create_city_improve(struct city *pcity,
+                                                struct impr_type *pimprove);
+static void destroy_city_improve(struct city_improve *pcity_improve);
+static void destroy_city_improve_list(
+  struct city_improve_list *pcity_improve_list);
 
 static bool disband_city(struct city *pcity);
 
@@ -410,16 +421,28 @@
 }
 
 /**************************************************************************
-...
+  update all cities of one nation (costs for buildings, unit upkeep, ...)
 **************************************************************************/
 void update_city_activities(struct player *pplayer)
 {
   int gold;
   gold=pplayer->economic.gold;
   pplayer->bulbs_last_turn = 0;
+
+  /* finances depend on the setting for 'game.info.economicsystem'
+   * 0: finances are check for each city (old system; done in
+   *    update_city_activity())
+   * 1: finances are checked at the end (overall finances) */
   city_list_iterate_safe(pplayer->cities, pcity)
-     update_city_activity(pplayer, pcity);
+    update_city_activity(pplayer, pcity);
   city_list_iterate_safe_end;
+
+  if (game.info.economicsystem == 1 && pplayer->economic.gold < 0) {
+    /* not enough gold - we have to sell something or even kill some
+     * units (only with gold upkeep!) to get the gold */
+    balance_finances_nation(pplayer);
+  }
+
   pplayer->ai.prev_gold = gold;
   /* This test include the cost of the units because pay_for_units is called
    * in update_city_activity */
@@ -1559,24 +1582,178 @@
 /**************************************************************************
   Pay for upkeep costs for all buildings, or sell them.
 **************************************************************************/
-static void pay_for_buildings(struct player *pplayer, struct city *pcity)
+static int pay_for_buildings(const struct city *pcity)
 {
+  int gold_needed = 0;
+
   city_built_iterate(pcity, pimprove) {
-    if (can_city_sell_building(pcity, pimprove)) {
-      int upkeep = city_improvement_upkeep(pcity, pimprove);
+      gold_needed += city_improvement_upkeep(pcity, pimprove);
+  } city_built_iterate_end;
 
-      if (pplayer->economic.gold - upkeep < 0) {
-	notify_player(pplayer, pcity->tile, E_IMP_AUCTIONED,
-			 _("Can't afford to maintain %s in %s, "
-			   "building sold!"),
-			 improvement_name_translation(pimprove),
-			 city_name(pcity));
-	do_sell_building(pplayer, pcity, pimprove);
-	city_refresh(pcity);
-      } else
-        pplayer->economic.gold -= upkeep;
+  return gold_needed;
+}
+
+/**************************************************************************
+  sell buildings to get gold
+**************************************************************************/
+static bool sell_buildings(struct player *pplayer,
+                           struct city_improve_list *pcity_improve_sell)
+{
+  /* randomize the list */
+  city_improve_list_shuffle(pcity_improve_sell);
+
+  /* sell buildings from the list */
+  city_improve_list_iterate(pcity_improve_sell, pcity_improve) {
+    if (can_city_sell_building(pcity_improve->pcity,
+                               pcity_improve->pimprove)) {
+      notify_player(pplayer, city_tile(pcity_improve->pcity),
+                    E_IMP_AUCTIONED, _("Can't afford to maintain %s in "
+                                       "%s, building sold!"),
+                    improvement_name_translation(pcity_improve->pimprove),
+                    city_name(pcity_improve->pcity));
+      do_sell_building(pplayer, pcity_improve->pcity,
+                       pcity_improve->pimprove);
+      city_refresh(pcity_improve->pcity);
+
+      /* get the upkeep back */
+      pplayer->economic.gold +=
+        city_improvement_upkeep(pcity_improve->pcity,
+                                pcity_improve->pimprove);
+
+      if (pplayer->economic.gold >= 0) {
+        /* no debts left */
+        return TRUE;
+      }
+    }
+  } city_improve_list_iterate_end;
+
+  return FALSE;
+}
+
+/**************************************************************************
+  balance the gold of a nation by selling some buildings. If this does not
+  help disband some units which need gold upkeep
+**************************************************************************/
+static void balance_finances_nation(struct player *pplayer)
+{
+  struct city_improve_list *pcity_improve_sell;
+  pcity_improve_sell = city_improve_list_new();
+
+  struct unit_list *punit_sell;
+  punit_sell = unit_list_new();
+
+  city_list_iterate(pplayer->cities, pcity) {
+    /* create *a list of all buildings (pcity, pimprove) */
+    city_built_iterate(pcity, pimprove) {
+      if (can_city_sell_building(pcity, pimprove)) {
+        struct city_improve *pcity_improve = fc_calloc(1,
+                                               sizeof(*pcity_improve));
+
+        pcity_improve->pcity = pcity;
+        pcity_improve->pimprove = pimprove;
+
+        city_improve_list_append(pcity_improve_sell, pcity_improve);
+      }
+    } city_built_iterate_end;
+
+    /* create a list of all units */
+    unit_list_iterate(pcity->units_supported, punit) {
+        unit_list_append(punit_sell, punit);
+    } unit_list_iterate_end;
+  } city_list_iterate_end;
+
+  /* try to sell some buildings */
+  if (!sell_buildings(pplayer, pcity_improve_sell)) {
+    /* still not enough gold - disband units */
+    sell_units(pplayer, punit_sell);
+  }
+
+  /* free memory */
+  destroy_city_improve_list(pcity_improve_sell);
+  city_improve_list_free(pcity_improve_sell);
+  unit_list_free(punit_sell);
+
+  /* should never happen */
+  assert(pplayer->economic.gold >= 0);
+}
+
+/**************************************************************************
+  balance the gold of one city by selling some buildings. If this does not
+  help disband some units which need gold upkeep
+**************************************************************************/
+static void balance_finances_city(struct player *pplayer,
+                                  struct city *pcity)
+{
+  struct city_improve_list *pcity_improve_sell;
+  pcity_improve_sell = city_improve_list_new();
+
+  struct unit_list *punit_sell;
+  punit_sell = unit_list_new();
+
+  /* create *a list of all buildings (pcity, pimprove) */
+  city_built_iterate(pcity, pimprove) {
+    if (can_city_sell_building(pcity, pimprove)) {
+      struct city_improve *pcity_improve = create_city_improve(pcity,
+                                                               pimprove);
+      city_improve_list_append(pcity_improve_sell, pcity_improve);
     }
   } city_built_iterate_end;
+
+  /* create a list of all units */
+  unit_list_iterate(pcity->units_supported, punit) {
+      unit_list_append(punit_sell, punit);
+  } unit_list_iterate_end;
+
+  /* try to sell some buildings */
+  if (!sell_buildings(pplayer, pcity_improve_sell)) {
+    /* still not enough gold - disband units */
+    sell_units(pplayer, punit_sell);
+  }
+
+  /* free memory */
+  destroy_city_improve_list(pcity_improve_sell);
+  city_improve_list_free(pcity_improve_sell);
+  unit_list_free(punit_sell);
+
+  /* should never happen */
+  assert(pplayer->economic.gold >= 0);
+}
+
+/**************************************************************************
+  create a struct city_improve
+**************************************************************************/
+static struct city_improve *create_city_improve(struct city *pcity,
+                                                struct impr_type *pimprove)
+{
+  struct city_improve *pcity_improve = fc_calloc(1,
+                                                 sizeof(*pcity_improve));
+
+  pcity_improve->pcity = pcity;
+  pcity_improve->pimprove = pimprove;
+
+  return pcity_improve;
+}
+
+/**************************************************************************
+  destroy a struct city_improve
+**************************************************************************/
+static void destroy_city_improve(struct city_improve *pcity_improve)
+{
+  /* ensure no pointers remain */
+  memset(pcity_improve, 0, sizeof(*pcity_improve));
+  free(pcity_improve);
+}
+
+/**************************************************************************
+  destroy all structs city_improve in the corresponding list
+**************************************************************************/
+static void destroy_city_improve_list(
+  struct city_improve_list *pcity_improve_list)
+{
+  /* destroy all elements of the list */
+  city_improve_list_iterate(pcity_improve_list, pcity_improve) {
+    destroy_city_improve(pcity_improve);
+  } city_improve_list_iterate_end;
 }
 
 /**************************************************************************
@@ -1736,7 +1913,6 @@
 static void update_city_activity(struct player *pplayer, struct city *pcity)
 {
   struct government *g = government_of_city(pcity);
-  int saved_id = pcity->id;
 
   city_refresh(pcity);
 
@@ -1768,49 +1944,55 @@
 	return;
     }
 
-    pcity->is_updated=TRUE;
+    pcity->is_updated = TRUE;
 
-    pcity->did_sell=FALSE;
+    pcity->did_sell = FALSE;
     pcity->did_buy = FALSE;
     pcity->airlift = get_city_bonus(pcity, EFT_AIRLIFT);
     update_tech(pplayer, pcity->prod[O_SCIENCE]);
-    pplayer->economic.gold+=pcity->prod[O_GOLD];
-    pay_for_units(pplayer, pcity);
-    if (city_exist(saved_id)) {
-      pay_for_buildings(pplayer, pcity);
-
-      if(city_unhappy(pcity)) { 
-        pcity->anarchy++;
-        if (pcity->anarchy == 1) {
-          notify_player(pplayer, pcity->tile, E_CITY_DISORDER,
-                        _("Civil disorder in %s."),
-                        city_name(pcity));
-        } else {
-          notify_player(pplayer, pcity->tile, E_CITY_DISORDER,
-                        _("CIVIL DISORDER CONTINUES in %s."),
-                        city_name(pcity));
-        }
+
+    /* finances */
+    pplayer->economic.gold += pcity->prod[O_GOLD];
+    pplayer->economic.gold -= pay_for_buildings(pcity);
+    pplayer->economic.gold -= pay_for_units(pcity);
+
+    if (game.info.economicsystem == 0 && pplayer->economic.gold < 0) {
+      /* not enough gold - we have to sell something or even kill some
+       * units (only with gold upkeep!) to get the gold */
+      balance_finances_city(pplayer, pcity);
+    }
+
+    if(city_unhappy(pcity)) {
+      pcity->anarchy++;
+      if (pcity->anarchy == 1) {
+        notify_player(pplayer, pcity->tile, E_CITY_DISORDER,
+                      _("Civil disorder in %s."),
+                      city_name(pcity));
       } else {
-        if (pcity->anarchy != 0) {
-          notify_player(pplayer, pcity->tile, E_CITY_NORMAL,
-                        _("Order restored in %s."),
-                        city_name(pcity));
-        }
-        pcity->anarchy = 0;
+        notify_player(pplayer, pcity->tile, E_CITY_DISORDER,
+                      _("CIVIL DISORDER CONTINUES in %s."),
+                      city_name(pcity));
       }
-      check_pollution(pcity);
-
-      send_city_info(NULL, pcity);
-      if (pcity->anarchy>2 
-          && get_player_bonus(pplayer, EFT_REVOLUTION_WHEN_UNHAPPY) > 0) {
-        notify_player(pplayer, pcity->tile, E_ANARCHY,
-                      _("The people have overthrown your %s, "
-                        "your country is in turmoil."),
-                      government_name_translation(g));
-        handle_player_change_government(pplayer, government_number(g));
+    } else {
+      if (pcity->anarchy != 0) {
+        notify_player(pplayer, pcity->tile, E_CITY_NORMAL,
+                      _("Order restored in %s."),
+                      city_name(pcity));
       }
-      sanity_check_city(pcity);
+      pcity->anarchy = 0;
     }
+    check_pollution(pcity);
+
+    send_city_info(NULL, pcity);
+    if (pcity->anarchy>2 
+        && get_player_bonus(pplayer, EFT_REVOLUTION_WHEN_UNHAPPY) > 0) {
+      notify_player(pplayer, pcity->tile, E_ANARCHY,
+                    _("The people have overthrown your %s, "
+                      "your country is in turmoil."),
+                    government_name_translation(g));
+      handle_player_change_government(pplayer, government_number(g));
+    }
+    sanity_check_city(pcity);
   }
 }
 
diff -ur -X./freeciv-2.1.99svn15393/diff_ignore freeciv-2.1.99svn.patch_shuffle/server/cityturn.h freeciv-2.1.99svn.patch_gold/server/cityturn.h
--- freeciv-2.1.99svn.patch_shuffle/server/cityturn.h	2008-12-25 19:45:49.000000000 +0100
+++ freeciv-2.1.99svn.patch_gold/server/cityturn.h	2009-01-04 21:33:23.000000000 +0100
@@ -21,6 +21,17 @@
 struct conn_list;
 struct cm_result;
 
+/* (city, improvement) pairs */
+struct city_improve {
+  struct city *pcity;
+  struct impr_type *pimprove;
+};
+
+/* get 'struct city_improve_list' and related functions: */
+#define SPECLIST_TAG city_improve
+#define SPECLIST_TYPE struct city_improve
+#include "speclist.h"
+
 void city_refresh(struct city *pcity);          /* call if city has changed */
 void city_refresh_for_player(struct player *pplayer); /* tax/govt changed */
 
@@ -46,4 +57,10 @@
 void advisor_choose_build(struct player *pplayer, struct city *pcity);
 
 void nullify_prechange_production(struct city *pcity);
+
+#define city_improve_list_iterate(city_improve_list, _city_improve)    \
+    TYPED_LIST_ITERATE(struct city_improve, city_improve_list,         \
+                       _city_improve)
+#define city_improve_list_iterate_end  LIST_ITERATE_END
+
 #endif  /* FC__CITYTURN_H */
diff -ur -X./freeciv-2.1.99svn15393/diff_ignore freeciv-2.1.99svn.patch_shuffle/server/ruleset.c freeciv-2.1.99svn.patch_gold/server/ruleset.c
--- freeciv-2.1.99svn.patch_shuffle/server/ruleset.c	2008-12-30 23:29:34.000000000 +0100
+++ freeciv-2.1.99svn.patch_gold/server/ruleset.c	2009-01-04 21:22:01.000000000 +0100
@@ -3016,6 +3016,17 @@
     game.info.nuke_contamination = CONTAMINATION_POLLUTION;
   }
 
+  game.info.economicsystem
+    = secfile_lookup_int_default(&file, GAME_DEFAULT_ECONOMIC_SYSTEM,
+                                 "civstyle.economicsystem");
+  if (game.info.economicsystem > GAME_MAX_ECONOMIC_SYSTEM
+      || game.info.economicsystem < GAME_MIN_ECONOMIC_SYSTEM) {
+    freelog(LOG_ERROR, "Bad value %d for economicsystem. Using default"
+            "value (%d).", game.info.economicsystem, 
+            GAME_DEFAULT_ECONOMIC_SYSTEM);
+    game.info.economicsystem = GAME_DEFAULT_ECONOMIC_SYSTEM;
+  }
+
   food_ini = secfile_lookup_int_vec(&file, &game.info.granary_num_inis, 
 				    "civstyle.granary_food_ini");
   if (game.info.granary_num_inis > MAX_GRANARY_INIS) {
diff -ur -X./freeciv-2.1.99svn15393/diff_ignore freeciv-2.1.99svn.patch_shuffle/server/unittools.c freeciv-2.1.99svn.patch_gold/server/unittools.c
--- freeciv-2.1.99svn.patch_shuffle/server/unittools.c	2008-12-25 19:45:49.000000000 +0100
+++ freeciv-2.1.99svn.patch_gold/server/unittools.c	2009-01-04 21:22:01.000000000 +0100
@@ -267,44 +267,62 @@
 }
 
 /***************************************************************************
-  Pay the cost of supported units of one city
+  get the gold needed to pay the cost to support the units of one city
 ***************************************************************************/
-void pay_for_units(struct player *pplayer, struct city *pcity)
+int pay_for_units(const struct city *pcity)
 {
-  int potential_gold = 0;
+  int gold_needed = 0;
   int free_upkeep[O_COUNT];
 
   memset(free_upkeep, 0, O_COUNT * sizeof(*free_upkeep));
   free_upkeep[O_GOLD] = get_city_output_bonus(pcity, get_output_type(O_GOLD),
                                               EFT_UNIT_UPKEEP_FREE_PER_CITY);
 
-  city_built_iterate(pcity, pimprove) {
-    if (can_city_sell_building(pcity, pimprove)) {
-      potential_gold += impr_sell_gold(pimprove);
-    }
-  } city_built_iterate_end;
+  unit_list_iterate(pcity->units_supported, punit) {
+    int upkeep[O_COUNT];
+
+    city_unit_upkeep(punit, upkeep, free_upkeep);
+    gold_needed += upkeep[O_GOLD];
+  } unit_list_iterate_end;
+
+  return gold_needed;
+}
+
+/**************************************************************************
+  sell units to save gold
+**************************************************************************/
+bool sell_units(struct player *pplayer, struct unit_list *punit_sell)
+{
+  int free_upkeep[O_COUNT];
+
+  memset(free_upkeep, 0, O_COUNT * sizeof(*free_upkeep));
+
+  /* randomize the list */
+  city_improve_list_shuffle(punit_sell);
 
-  unit_list_iterate_safe(pcity->units_supported, punit) {
+  unit_list_iterate_safe(punit_sell, punit) {
     int upkeep[O_COUNT];
 
     city_unit_upkeep(punit, upkeep, free_upkeep);
 
-    if (pplayer->economic.gold + potential_gold < upkeep[O_GOLD]) {
-      /* We cannot upkeep this unit any longer and selling off city
-       * improvements will not help so we will have to disband */
-      assert(pplayer->economic.gold + potential_gold >= 0);
-
-      notify_player(pplayer, NULL, E_UNIT_LOST_MISC,
-		       _("Not enough gold. %s disbanded"),
-		       unit_name_translation(punit));
+    if (upkeep[O_GOLD] > 0) {
+      /* this unit needs gold - disband it */
+      notify_player(pplayer, unit_tile(punit), E_UNIT_LOST_MISC,
+                    _("Not enough gold. %s disbanded"),
+                    unit_name_translation(punit));
       wipe_unit(punit);
-    } else {
-      /* Gold can get negative here as city improvements will be sold
-       * afterwards to balance our budget. FIXME: Should units with gold 
-       * upkeep give gold when they are disbanded? */
-      pplayer->economic.gold -= upkeep[O_GOLD];
+
+      /* get the gold back */
+      pplayer->economic.gold += upkeep[O_GOLD];
+    }
+
+    if (pplayer->economic.gold >= 0) {
+      /* no debts left */
+      return TRUE;
     }
   } unit_list_iterate_safe_end;
+
+  return FALSE;
 }
 
 /***************************************************************************
diff -ur -X./freeciv-2.1.99svn15393/diff_ignore freeciv-2.1.99svn.patch_shuffle/server/unittools.h freeciv-2.1.99svn.patch_gold/server/unittools.h
--- freeciv-2.1.99svn.patch_shuffle/server/unittools.h	2008-12-25 19:45:49.000000000 +0100
+++ freeciv-2.1.99svn.patch_gold/server/unittools.h	2009-01-04 21:22:01.000000000 +0100
@@ -50,7 +50,8 @@
 		       enum vision_layer vlayer);
 void unit_refresh_vision(struct unit *punit);
 void unit_list_refresh_vision(struct unit_list *punitlist);
-void pay_for_units(struct player *pplayer, struct city *pcity);
+int pay_for_units(const struct city *pcity);
+bool sell_units(struct player *pplayer, struct unit_list *punit_sell);
 void bounce_unit(struct unit *punit, bool verbose);
 
 /* creation/deletion/upgrading */
_______________________________________________
Freeciv-dev mailing list
Freeciv-dev@gna.org
https://mail.gna.org/listinfo/freeciv-dev

Reply via email to