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

> [matthias.pfaffer...@mapfa.de - Tue Dec 30 21:34:34 2008]:
> 
> here is an updated version of the patch.

Unfortunately I just made adjustements to you previous
patch today, and was about to post the updated version
when I noticed you already did. :(

Anyway, please at least read over the code in the file
migrate_v3.patch and make sure your patch follows the
same style. Maybe integrate some of the ideas in it,
such as a setting to control the number of turns
between migrations (perhaps better than the hard-coded
5).

In particular:
- No lines longer than 76 characters + 1 newline.
- Multi-line function arguments lined up to column one
  past the initial '(' and similarly for if-statements.
- Use city_tile(pcity) instead of pcity->tile, and similar.
- Use LOG_DEBUG not LOG_NORMAL for debugging messages.
- Use is_capital(pcity) directly instead of find_palace().
- Use const in function arguments if the function
  does not modify the arguments (e.g. the score function).
- Make the default setting values disable migration.

I also wonder if there could arise a situation where
migration happens from city A to city B, and then back
again from city B to city A, because A happened to be
before B in the city list. Perhaps the migration score
should first be calculated for all possible source
and destination cities, then the migrations actually
performed?


Anyway I'll check it again in at least a few days and
when I'm sure you are not working on it too. ;)


-----------------------------------------------------------------------
私の人生は大移住の話から始まります。
 common/game.c      |    1 +
 common/game.h      |    4 ++
 common/packets.def |    1 +
 server/cityturn.c  |  135 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 server/cityturn.h  |    3 +
 server/savegame.c  |    4 ++
 server/settings.c  |   13 +++++
 server/srv_main.c  |    7 +++
 8 files changed, 168 insertions(+), 0 deletions(-)

diff --git a/common/game.c b/common/game.c
index f0d4378..0d5bfab 100644
--- a/common/game.c
+++ b/common/game.c
@@ -275,6 +275,7 @@ void game_init(void)
   game.info.celebratesize = GAME_DEFAULT_CELEBRATESIZE;
   game.info.savepalace    = GAME_DEFAULT_SAVEPALACE;
   game.info.natural_city_names = GAME_DEFAULT_NATURALCITYNAMES;
+  game.info.migration     = GAME_DEFAULT_MIGRATION;
   game.info.angrycitizen  = GAME_DEFAULT_ANGRYCITIZEN;
   game.info.foodbox       = GAME_DEFAULT_FOODBOX;
   game.info.shieldbox = GAME_DEFAULT_SHIELDBOX;
diff --git a/common/game.h b/common/game.h
index 4e75ece..f593bf2 100644
--- a/common/game.h
+++ b/common/game.h
@@ -250,6 +250,10 @@ bool setting_class_is_changeable(enum sset_class class);
 
 #define GAME_DEFAULT_NATURALCITYNAMES TRUE
 
+#define GAME_DEFAULT_MIGRATION       0
+#define GAME_MIN_MIGRATION           0
+#define GAME_MAX_MIGRATION           100
+
 #define GAME_DEFAULT_AQUEDUCTLOSS    0
 #define GAME_MIN_AQUEDUCTLOSS        0
 #define GAME_MAX_AQUEDUCTLOSS        100
diff --git a/common/packets.def b/common/packets.def
index 8455fda..a00a2c4 100644
--- a/common/packets.def
+++ b/common/packets.def
@@ -414,6 +414,7 @@ PACKET_GAME_INFO=15; sc
   UINT8 razechance;
   BOOL savepalace;
   BOOL natural_city_names;
+  UINT8 migration;
   BOOL turnblock;
   BOOL fixedlength;
   BOOL auto_ai_toggle;
diff --git a/server/cityturn.c b/server/cityturn.c
index b860a5e..412eddc 100644
--- a/server/cityturn.c
+++ b/server/cityturn.c
@@ -1867,3 +1867,138 @@ static bool disband_city(struct city *pcity)
   remove_city(pcity);
   return TRUE;
 }
+
+/***************************************************************************
+  Helper function to find the "migration desirability" of a city. The higher
+  the score the more likely citizens will migrate to it.
+
+  The score depends on the total trade and shield output of the city, its
+  size, number of ocean squares around it, and the shield cost of all the
+  improvements in the city. The score is doubled for the player's capital
+  city (the one containing the palace small wonder).
+***************************************************************************/
+static int city_migration_score(const struct city *pcity)
+{
+  int score = 0;
+
+  if (!pcity) {
+    return 0;
+  }
+
+  score = pcity->prod[O_TRADE] + pcity->prod[O_SHIELD];
+  score += 10 * pcity->size;
+  square_iterate(city_tile(pcity), 2, ptile) {
+    if (is_ocean(tile_terrain(ptile))) {
+      score += 2;
+    }
+  } square_iterate_end;
+
+  city_built_iterate(pcity, pimprove) {
+    score += impr_build_shield_cost(pimprove) * 2;
+  } city_built_iterate_end;
+
+  if (find_palace(city_owner(pcity)) == pcity) {
+    score *= 2;
+  }
+
+  return score;
+}
+
+/**************************************************************************
+  Do the migrations between the cities that overlap. Migrants go to the
+  city with higher city_migration_score(), if the growth of the target
+  city is not blocked due to a missing improvement.
+
+  The setting 'game.info.migrations' controls the number of turns between
+  migrations. If this setting is zero, or it is the first turn (T0),
+  migration does no occur.
+**************************************************************************/
+void make_city_migrations(struct player *pplayer)
+{
+  if (!pplayer || game.info.migration <= 0 || game.info.turn <= 0
+      || game.info.turn % game.info.migration != 0) {
+    return;
+  }
+
+  /* first we search for cities that overlap */
+  city_list_iterate(pplayer->cities, source_city) {
+    struct city *best_city = NULL;
+    int score_1 = city_migration_score(source_city);
+    int best_score = 0;
+
+    square_iterate(city_tile(source_city), 2, ptile) {
+      struct city *acity = tile_city(ptile);
+      if (acity) {
+        /* here we have two cities that overlap... */
+        int score_2;
+
+        /* immigrate to cities of the same owner only */
+        if (city_owner(acity) != pplayer) {
+          continue;
+        }
+
+        score_2 = city_migration_score(acity);
+
+        /* immigrate to cities that can grow */
+        if (!city_can_grow_to(acity, acity->size + 1)) {
+          score_2 /= 4;
+        }
+
+        if (score_2 > score_1 && score_2 > best_score) {
+          /* select the best! */
+          best_score = score_2;
+          best_city = acity;
+        }
+      }
+    } square_iterate_end;
+
+    /* do the migration */
+    if (best_score > 0) {
+      char source_city_name[MAX_LEN_NAME];
+
+      /* we copy the city name, maybe we disband it! */
+      sz_strlcpy(source_city_name, city_name(source_city));
+
+      if (city_can_grow_to(best_city, best_city->size + 1)) {
+        /* reduce size of giver */
+        if (source_city->size == 1) {
+          struct city *rcity = NULL;
+          /* find closest city other than pcity */
+          rcity = find_closest_owned_city(pplayer, city_tile(best_city),
+                                          FALSE, source_city);
+          if (rcity) {
+            transfer_city_units(pplayer, pplayer,
+                                source_city->units_supported,
+                                rcity, source_city, -1, TRUE);
+            remove_city(source_city);
+          } else {
+            notify_player(pplayer, city_tile(source_city), E_CITY_TRANSFER,
+                          _("Game: Citizens of %s cannot move to %s "
+                            "because there is no nearby city to support "
+                            "the units from %s."), source_city_name,
+                          city_name(best_city), source_city_name);
+            continue;
+          }
+        } else {
+          city_reduce_size(source_city, 1, pplayer);
+          city_refresh(source_city);
+        }
+        /* raise size of receiver city */
+        city_increase_size(best_city);
+        city_refresh(best_city);
+        /* message to the player */
+        notify_player(pplayer, city_tile(best_city), E_CITY_TRANSFER,
+                      _("Game: Migrants of %s moved to %s "
+                        "in search of a better life."),
+                      source_city_name, city_name(best_city));
+      } else {
+        /* protest! */
+        notify_player(pplayer, city_tile(best_city), E_CITY_TRANSFER,
+                      _("Game: Migrants of %s can't go to %s because "
+                        "it needs an improvement to grow! You are "
+                        "held responsible for its poverty!"),
+                      source_city_name, city_name(best_city));
+      }
+    }
+  } city_list_iterate_end;
+}
diff --git a/server/cityturn.h b/server/cityturn.h
index d4b69e2..9aabe6b 100644
--- a/server/cityturn.h
+++ b/server/cityturn.h
@@ -46,4 +46,7 @@ void remove_obsolete_buildings(struct player *pplayer);
 void advisor_choose_build(struct player *pplayer, struct city *pcity);
 
 void nullify_prechange_production(struct city *pcity);
+
+void make_city_migrations(struct player *pplayer);
+
 #endif  /* FC__CITYTURN_H */
diff --git a/server/savegame.c b/server/savegame.c
index 1fe662b..a571e8d 100644
--- a/server/savegame.c
+++ b/server/savegame.c
@@ -4291,6 +4291,9 @@ static void game_load_internal(struct section_file *file)
     game.info.allowed_city_names =
       secfile_lookup_int_default(file, game.info.allowed_city_names,
                                  "game.allowed_city_names"); 
+    game.info.migration =
+      secfile_lookup_int_default(file, game.info.migration,
+                                 "game.migration");
 
     if(civstyle == 1) {
       string = "civ1";
@@ -4943,6 +4946,7 @@ void game_save(struct section_file *file, const char *save_reason)
   secfile_insert_bool(file, game.info.happyborders, "game.happyborders");
   secfile_insert_int(file, game.info.diplomacy, "game.diplomacy");
   secfile_insert_int(file, game.info.allowed_city_names, "game.allowed_city_names");
+  secfile_insert_int(file, game.info.migration, "game.migration");
 
   {
     /* Now always save these, so the server options reflect the
diff --git a/server/settings.c b/server/settings.c
index 0550776..0812bd3 100644
--- a/server/settings.c
+++ b/server/settings.c
@@ -841,6 +841,19 @@ struct settings_s settings[] = {
               "on the surrounding terrain."),
            NULL, GAME_DEFAULT_NATURALCITYNAMES)
 
+  GEN_INT("migration", game.info.migration,
+          SSET_RULES_FLEXIBLE, SSET_SOCIOLOGY, SSET_RARE, SSET_TO_CLIENT,
+          N_("Turn count between citizen migrations"),
+          N_("This setting controls the number of turns between the "
+             "automatic transfer of citizens between overlapping cities. "
+             "Citizens will generally move to larger cities with higher "
+             "trade output, production output, improvements and available "
+             "ocean tiles. The palace building also greatly increases the "
+             "destination desirability. Citizens will only migrate to "
+             "cities owned by the same player. If this setting is zero, "
+             "migration will be disabled."), NULL,
+          GAME_MIN_MIGRATION, GAME_MAX_MIGRATION, GAME_DEFAULT_MIGRATION)
+
   /* Meta options: these don't affect the internal rules of the game, but
    * do affect players.  Also options which only produce extra server
    * "output" and don't affect the actual game.
diff --git a/server/srv_main.c b/server/srv_main.c
index 3ec018c..d33585e 100644
--- a/server/srv_main.c
+++ b/server/srv_main.c
@@ -869,6 +869,13 @@ static void end_turn(void)
   summon_barbarians(); /* wild guess really, no idea where to put it, but
 			  I want to give them chance to move their units */
 
+  if (game.info.migration > 0) {
+    freelog(LOG_DEBUG, "Season of migrations");
+    players_iterate(pplayer) {
+      make_city_migrations(pplayer);
+    } players_iterate_end;
+  }
+
   update_environmental_upset(S_POLLUTION, &game.info.heating,
 			     &game.info.globalwarming, &game.info.warminglevel,
 			     global_warming);
_______________________________________________
Freeciv-dev mailing list
Freeciv-dev@gna.org
https://mail.gna.org/listinfo/freeciv-dev

Reply via email to