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

This patch gives the possibility to take the gold for the units from the 
overall finances _after_ all cities have added their gold surplus. 
 
 There is a ruleset parameters used to describe the economic system 
 0: gold upkeep for buildings and units has to be paid by the city 
 1: gold upkeep for buildings and units comes from the overall finances 
 (default is economicsystem = 0 = old system) 
 
 For the old system it is done for each city: 
 
 1. get the gold needed for all improvements 
 2. get the gold needed for all units 
 3. check if there is enough gold 
 4. if not, sell buildings 
 5. if not, disband units which need gold upkeep 
 
 For the new system it is changed as 
 
 1. iterate over all cities 
 1.1 get the gold needed for all improvements 
 1.2. get the gold needed for all units 
 2. check if there is enough gold 
 3. if not, sell buildings (randomly chosen) 
 4. if not, disband units which need gold upkeep 
 
 It is possible to add economic systems in-between: 
 
 only pay for the buildings or unit from the overall finances, ... 
 
the freeciv-svn15391-shuffle.patch is needed for this patch.

diff -ur -X./freeciv-2.1.99svn15391/diff_ignore freeciv-2.1.99svn15931/common/game.h freeciv-2.1.99svn.patch_gold/common/game.h
--- freeciv-2.1.99svn15931/common/game.h	2008-12-30 23:29:33.000000000 +0100
+++ freeciv-2.1.99svn.patch_gold/common/game.h	2009-01-02 21:14:42.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     1
+#define GAME_MAX_ECONOMIC_SYSTEM     2
+
 #define GAME_DEFAULT_FOODBOX         100
 #define GAME_MIN_FOODBOX             1
 #define GAME_MAX_FOODBOX             10000
diff -ur -X./freeciv-2.1.99svn15391/diff_ignore freeciv-2.1.99svn15931/common/packets.def freeciv-2.1.99svn.patch_gold/common/packets.def
--- freeciv-2.1.99svn15931/common/packets.def	2008-12-30 23:29:33.000000000 +0100
+++ freeciv-2.1.99svn.patch_gold/common/packets.def	2009-01-02 21:14:43.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.99svn15391/diff_ignore freeciv-2.1.99svn15931/data/civ1/game.ruleset freeciv-2.1.99svn.patch_gold/data/civ1/game.ruleset
--- freeciv-2.1.99svn15931/data/civ1/game.ruleset	2008-12-30 23:29:34.000000000 +0100
+++ freeciv-2.1.99svn.patch_gold/data/civ1/game.ruleset	2009-01-02 21:26:10.000000000 +0100
@@ -56,6 +56,11 @@
 ;   "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 city
+; 1: gold upkeep for buildings and units comes from the overall finances
+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.99svn15391/diff_ignore freeciv-2.1.99svn15931/data/civ2/game.ruleset freeciv-2.1.99svn.patch_gold/data/civ2/game.ruleset
--- freeciv-2.1.99svn15931/data/civ2/game.ruleset	2008-12-30 23:29:34.000000000 +0100
+++ freeciv-2.1.99svn.patch_gold/data/civ2/game.ruleset	2009-01-02 21:26:09.000000000 +0100
@@ -50,6 +50,11 @@
 ;   "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 city
+; 1: gold upkeep for buildings and units comes from the overall finances
+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.99svn15391/diff_ignore freeciv-2.1.99svn15931/data/default/game.ruleset freeciv-2.1.99svn.patch_gold/data/default/game.ruleset
--- freeciv-2.1.99svn15931/data/default/game.ruleset	2008-12-30 23:29:34.000000000 +0100
+++ freeciv-2.1.99svn.patch_gold/data/default/game.ruleset	2009-01-02 21:26:07.000000000 +0100
@@ -68,6 +68,11 @@
 ;   "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 city
+; 1: gold upkeep for buildings and units comes from the overall finances
+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.99svn15391/diff_ignore freeciv-2.1.99svn15931/server/cityturn.c freeciv-2.1.99svn.patch_gold/server/cityturn.c
--- freeciv-2.1.99svn15931/server/cityturn.c	2008-12-25 19:45:49.000000000 +0100
+++ freeciv-2.1.99svn.patch_gold/server/cityturn.c	2009-01-02 21:31:05.000000000 +0100
@@ -82,7 +82,12 @@
 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_list);
+static void balance_finances_nation(struct player *pplayer);
+static void balance_finances_city(struct player *pplayer,
+                                  struct city *pcity);
 
 static bool disband_city(struct city *pcity);
 
@@ -410,16 +415,26 @@
 }
 
 /**************************************************************************
-...
+  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 (done in update_city_activity())
+   * 1: finaces are checked at the end (overall finances) */
   city_list_iterate_safe(pplayer->cities, 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 +1574,129 @@
 /**************************************************************************
   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) {
+      gold_needed += city_improvement_upkeep(pcity, pimprove);
+  } city_built_iterate_end;
+
+  return gold_needed;
+}
+
+/**************************************************************************
+  sell buildings to get gold
+**************************************************************************/
+static bool sell_buildings(struct player *pplayer,
+                           struct city_improve_list *pcity_improve_list)
+{
+  /* randomize the list */
+  city_improve_list_shuffle(pcity_improve_list);
+
+  /* sell buildings from the list */
+  city_improve_list_iterate(pcity_improve_list, 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_list;
+  pcity_improve_list = city_improve_list_new();
+
+  city_list_iterate_safe(pplayer->cities, pcity) {
+    city_built_iterate(pcity, pimprove) {
+      /* get a list list of (pcity, pimprove) */
+      if (can_city_sell_building(pcity, pimprove)) {
+        struct city_improve *pcity_improve;
+
+        pcity_improve->pcity = pcity;
+        pcity_improve->pimprove = pimprove;
+
+        city_improve_list_append(pcity_improve_list, pcity_improve);
+      }
+    } city_built_iterate_end;
+  } city_list_iterate_safe_end;
+
+  /* try to sell buildings */
+  if (sell_buildings(pplayer, pcity_improve_list)) {
+    /* OK; we have a positive amount of gold */
+    return;
+  }
+
+  /* try to disband units */
+  if (sell_units(pplayer, pplayer->units)) {
+    /* OK; we have a positive amount of gold */
+    return;
+  }
+
+  /* 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_list;
+  pcity_improve_list = city_improve_list_new();
+
   city_built_iterate(pcity, pimprove) {
+    /* get a list list of (pcity, pimprove) */
     if (can_city_sell_building(pcity, pimprove)) {
-      int upkeep = city_improvement_upkeep(pcity, pimprove);
+      struct city_improve *pcity_improve;
 
-      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;
+      pcity_improve->pcity = pcity;
+      pcity_improve->pimprove = pimprove;
+
+      city_improve_list_append(pcity_improve_list, pcity_improve);
     }
   } city_built_iterate_end;
+
+  /* try to sell buildings */
+  if (sell_buildings(pplayer, pcity_improve_list)) {
+    /* OK; we have a positive amount of gold */
+    return;
+  }
+
+  /* try to disband units */
+  if (sell_units(pplayer, pcity->units_supported)) {
+    /* OK; we have a positive amount of gold */
+    return;
+  }
+
+  /* should never happen */
+  assert(pplayer->economic.gold >= 0);
 }
 
 /**************************************************************************
@@ -1736,7 +1856,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);
 
@@ -1774,43 +1893,49 @@
     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_units(pcity);
+    pplayer->economic.gold -= pay_for_buildings(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.99svn15391/diff_ignore freeciv-2.1.99svn15931/server/cityturn.h freeciv-2.1.99svn.patch_gold/server/cityturn.h
--- freeciv-2.1.99svn15931/server/cityturn.h	2008-12-25 19:45:49.000000000 +0100
+++ freeciv-2.1.99svn.patch_gold/server/cityturn.h	2009-01-02 20:10:06.000000000 +0100
@@ -18,9 +18,22 @@
 
 #include "fc_types.h"
 
+#define TMP_GOOLDUPKEEP 0
+
 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 +59,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.99svn15391/diff_ignore freeciv-2.1.99svn15931/server/ruleset.c freeciv-2.1.99svn.patch_gold/server/ruleset.c
--- freeciv-2.1.99svn15931/server/ruleset.c	2008-12-30 23:29:34.000000000 +0100
+++ freeciv-2.1.99svn.patch_gold/server/ruleset.c	2009-01-02 21:37:19.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.99svn15391/diff_ignore freeciv-2.1.99svn15931/server/unittools.c freeciv-2.1.99svn.patch_gold/server/unittools.c
--- freeciv-2.1.99svn15931/server/unittools.c	2008-12-25 19:45:49.000000000 +0100
+++ freeciv-2.1.99svn.patch_gold/server/unittools.c	2009-01-02 21:31:08.000000000 +0100
@@ -267,44 +267,59 @@
 }
 
 /***************************************************************************
-  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;
 
-  unit_list_iterate_safe(pcity->units_supported, punit) {
+  return gold_needed;
+}
+
+/**************************************************************************
+  sell units to save gold
+**************************************************************************/
+bool sell_units(struct player *pplayer, struct unit_list *punits)
+{
+  int free_upkeep[O_COUNT];
+
+  memset(free_upkeep, 0, O_COUNT * sizeof(*free_upkeep));
+
+  unit_list_iterate_safe(punits, 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.99svn15391/diff_ignore freeciv-2.1.99svn15931/server/unittools.h freeciv-2.1.99svn.patch_gold/server/unittools.h
--- freeciv-2.1.99svn15931/server/unittools.h	2008-12-25 19:45:49.000000000 +0100
+++ freeciv-2.1.99svn.patch_gold/server/unittools.h	2009-01-02 20:26:18.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 *punits);
 void bounce_unit(struct unit *punit, bool verbose);
 
 /* creation/deletion/upgrading */
diff -ur -X./freeciv-2.1.99svn15391/diff_ignore freeciv-2.1.99svn15931/version.in freeciv-2.1.99svn.patch_gold/version.in
--- freeciv-2.1.99svn15931/version.in	2008-12-30 23:29:34.000000000 +0100
+++ freeciv-2.1.99svn.patch_gold/version.in	2009-01-02 21:24:38.000000000 +0100
@@ -23,5 +23,5 @@
 #   - Avoid adding a new mandatory capability to the development branch for
 #     as long as possible.  We want to maintain network compatibility with
 #     the stable branch for as long as possible.
-NETWORK_CAPSTRING_MANDATORY="+Freeciv.Devel.2008.Dec.28"
+NETWORK_CAPSTRING_MANDATORY="+Freeciv.Devel.2009.Jan.02"
 NETWORK_CAPSTRING_OPTIONAL=""
_______________________________________________
Freeciv-dev mailing list
Freeciv-dev@gna.org
https://mail.gna.org/listinfo/freeciv-dev

Reply via email to