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

Attached the (hopefully) final version (or the last version for this 
year ;-) )

I included the suggestions / changes from your patch. I also hope, that this 
version follows the coding style guidelines for freeciv.

Am Tuesday 30 December 2008 23:32:48 schrieb Madeline Book:
> <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. :(

sorry - I hat the time and so I did some work on this patch. Now I want to get 
it included ... ;-)

>
> 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).

I added an option game.info.migrationturn with default to 0 (off)

>
> In particular:
> - No lines longer than 76 characters + 1 newline.

done

> - Multi-line function arguments lined up to column one
>   past the initial '(' and similarly for if-statements.

interesting to know; I did it after my feeling ...

done

> - Use city_tile(pcity) instead of pcity->tile, and similar.

I hope done; if there is something missing, please tell me

> - Use LOG_DEBUG not LOG_NORMAL for debugging messages.

Oh, this was for me to test the patch; all set to debug now

> - Use is_capital(pcity) directly instead of find_palace().

done

> - Use const in function arguments if the function
>   does not modify the arguments (e.g. the score function).

done

> - Make the default setting values disable migration.

done

>
> 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?

if people go from A to B, A has a score lower than B. After the migration the 
score of B will be even higher ... but you are right, it could happen. I 
hope, that the turn (game.info.migrationturn) option as well as the default 
possibilities (50% for game.info.migrationplayer and 10% for 
game.info.migrationworld) will prevent this. Also for the score a float is 
used, so even small differences will be taken into account.



I get the following error; could it be related to the migration code 
(remove_city() in make_city_migration())? I have not found a pattern to 
narrow it down if it is the patch or the develop version of freeciv.

civserver: maphand.c:1564: map_claim_ownership: Assertion `((void *)0) == 
playtile->site' failed.

I suspect that after a city is remove something is messed up within the 
server; but remove_city() is also used in similar kind in other functions.

Matthias

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

am finished and will start again if you have some comments; till the 6th of 
January I have some free time ...

>
>
> -----------------------------------------------------------------------
> 私の人生は大移住の話から始まります。



-- 
Matthias Pfafferodt - http://www.mapfa.de
Matthias.Pfafferodt <at> mapfa.de

diff -ur -X./freeciv-2.1.99svn15391/diff_ignore freeciv-2.1.99svn15391/common/game.c freeciv-2.1.99svn.patch/common/game.c
--- freeciv-2.1.99svn15391/common/game.c	2008-12-25 19:45:44.000000000 +0100
+++ freeciv-2.1.99svn.patch/common/game.c	2008-12-31 16:37:12.000000000 +0100
@@ -275,6 +275,10 @@
   game.info.celebratesize = GAME_DEFAULT_CELEBRATESIZE;
   game.info.savepalace    = GAME_DEFAULT_SAVEPALACE;
   game.info.natural_city_names = GAME_DEFAULT_NATURALCITYNAMES;
+  game.info.migrationturn = GAME_DEFAULT_MIGRATION_TURN;
+  game.info.migrationdist = GAME_DEFAULT_MIGRATION_DIST;
+  game.info.migrationworld = GAME_DEFAULT_MIGRATION_WORLD;
+  game.info.migrationplayer = GAME_DEFAULT_MIGRATION_PLAYER;
   game.info.angrycitizen  = GAME_DEFAULT_ANGRYCITIZEN;
   game.info.foodbox       = GAME_DEFAULT_FOODBOX;
   game.info.shieldbox = GAME_DEFAULT_SHIELDBOX;
diff -ur -X./freeciv-2.1.99svn15391/diff_ignore freeciv-2.1.99svn15391/common/game.h freeciv-2.1.99svn.patch/common/game.h
--- freeciv-2.1.99svn15391/common/game.h	2008-12-30 23:29:33.000000000 +0100
+++ freeciv-2.1.99svn.patch/common/game.h	2008-12-31 17:39:10.000000000 +0100
@@ -250,6 +250,22 @@
 
 #define GAME_DEFAULT_NATURALCITYNAMES TRUE
 
+#define GAME_DEFAULT_MIGRATION_TURN  0 /* 0 = no migration */
+#define GAME_MIN_MIGRATION_TURN      0
+#define GAME_MAX_MIGRATION_TURN      100
+
+#define GAME_DEFAULT_MIGRATION_DIST   3
+#define GAME_MIN_MIGRATION_DIST       1
+#define GAME_MAX_MIGRATION_DIST       7
+
+#define GAME_DEFAULT_MIGRATION_PLAYER 50
+#define GAME_MIN_MIGRATION_PLAYER    0
+#define GAME_MAX_MIGRATION_PLAYER    100
+
+#define GAME_DEFAULT_MIGRATION_WORLD 10
+#define GAME_MIN_MIGRATION_WORLD     0
+#define GAME_MAX_MIGRATION_WORLD     100
+
 #define GAME_DEFAULT_AQUEDUCTLOSS    0
 #define GAME_MIN_AQUEDUCTLOSS        0
 #define GAME_MAX_AQUEDUCTLOSS        100
diff -ur -X./freeciv-2.1.99svn15391/diff_ignore freeciv-2.1.99svn15391/common/packets.def freeciv-2.1.99svn.patch/common/packets.def
--- freeciv-2.1.99svn15391/common/packets.def	2008-12-30 23:29:33.000000000 +0100
+++ freeciv-2.1.99svn.patch/common/packets.def	2008-12-31 16:37:16.000000000 +0100
@@ -414,6 +414,10 @@
   UINT8 razechance;
   BOOL savepalace;
   BOOL natural_city_names;
+  UINT8 migrationturn;
+  UINT8 migrationdist;
+  UINT8 migrationplayer;
+  UINT8 migrationworld;
   BOOL turnblock;
   BOOL fixedlength;
   BOOL auto_ai_toggle;
diff -ur -X./freeciv-2.1.99svn15391/diff_ignore freeciv-2.1.99svn15391/server/cityturn.c freeciv-2.1.99svn.patch/server/cityturn.c
--- freeciv-2.1.99svn15391/server/cityturn.c	2008-12-25 19:45:49.000000000 +0100
+++ freeciv-2.1.99svn.patch/server/cityturn.c	2008-12-31 18:45:15.000000000 +0100
@@ -1867,3 +1867,355 @@
   remove_city(pcity);
   return TRUE;
 }
+
+/***************************************************************************
+  Helper function to calculate  a score of a city. It indicates the
+  "migration desirability" of the city. The higher the score the more likely
+  citizens will migrate to it.
+
+  The score depends on the city size, the feeling of its citizens and the 
+  surplus of trade, luxury and science.
+
+  formula:
+    score = ([city size] + feeling) * factors
+
+  * feeling of the citizens
+    feeling = 1.00 * happy citizens
+            + 0.00 * content citizens
+            - 0.25 * unhappy citizens
+            - 0.50 * unhappy citizens
+
+  * factors
+    * the build costs of all buildings
+      f = (1 + (1 - exp(-[build shield cost]/1000))/5)
+    * the trade of the city
+      f = (1 + (1 - exp(-[city surplus trade]/100))/5)
+    * the luxury within the city
+      f = (1 + (1 - exp(-[city surplus luxury]/100))/5)
+    * the science within the city
+      f = (1 + (1 - exp(-[city surplus science]/100))/5)
+
+  all factors f have values between 1 and 1.2; the overall factor will be
+  between 1.0 (smaller cities) and 2.0 (bigger cities)
+
+  [build shield cost], [city surplus trade], [city surplus luxury] and
+  [city surplus science] _must_ be >= 0!
+
+  * for the capital an additional factor of 1.25 is used
+**************************************************************************/
+static float city_score(const struct city *pcity)
+{
+  float score = 0.0;
+  int build_shield_cost = 0;
+
+  if (!pcity) {
+    return 0;
+  }
+
+  /* feeling of the citizens */
+  score = pcity->size + 1.00 * pcity->feel[CITIZEN_HAPPY][FEELING_FINAL]
+          + 0.00 * pcity->feel[CITIZEN_CONTENT][FEELING_FINAL]
+          - 0.25 * pcity->feel[CITIZEN_UNHAPPY][FEELING_FINAL]
+          - 0.50 * pcity->feel[CITIZEN_ANGRY][FEELING_FINAL];
+
+  /* take shild costs of all buidings into account */
+  city_built_iterate(pcity, pimprove) {
+    build_shield_cost += impr_build_shield_cost(pimprove);
+  } city_built_iterate_end;
+  score *= (1 + (1 - exp(-(float)build_shield_cost/1000))/5);
+  /* take trade into account */
+  score *= (1 + (1 - exp(-(float)pcity->surplus[O_TRADE]/100))/5);
+  /* take luxury into account */
+  score *= (1 + (1 - exp(-(float)pcity->surplus[O_LUXURY]/100))/5);
+  /* take science into account */
+  score *= (1 + (1 - exp(-(float)pcity->surplus[O_SCIENCE]/100))/5);
+
+  if (is_capital(pcity)) {
+    /* the capital is a magnet for the citizens */
+    score *= 1.25;
+  }
+
+  freelog(LOG_DEBUG, "[M] %s score: %.3f", city_name(pcity), score);
+
+  return score;
+}
+
+/**************************************************************************
+  Do the migrations between the cities that overlap, if the growth of the
+  target city is not blocked due to a missing improvement or missing food.
+**************************************************************************/
+static bool make_city_migration(const struct player *pplayer_from,
+                                struct city *pcity_from,
+                                const struct player *pplayer_to,
+                                struct city *pcity_to)
+{
+  char city_from_name[MAX_LEN_NAME];
+  struct city *rcity = NULL;
+
+  if (pcity_to->surplus[O_FOOD] < 0) {
+    /* insufficiency food in receiver city; no additional citizens */
+    if (pplayer_from == pplayer_to) {
+      /* migration between one nation */
+      notify_player(pplayer_to, city_tile(pcity_to), E_CITY_TRANSFER,
+                    _("Game: Migrants from %s can't go to %s "
+                      "because there is not enough food available! "
+                      "You are responsible for her poverty!"),
+                    city_name(pcity_from), city_name(pcity_to));
+    } else {
+      /* migration between different nations */
+      notify_player(pplayer_from, city_tile(pcity_to), E_CITY_TRANSFER,
+                    _("Game: Migrants from %s can't go to %s (%s) "
+                      "because there is not enough food available! "
+                      "Improve your city to keep your citizens!"),
+                    city_name(pcity_from), city_name(pcity_to),
+                    player_name(pplayer_to));
+      notify_player(pplayer_to, city_tile(pcity_to), E_CITY_TRANSFER,
+                    _("Game: Migrants from %s (%s) can't go to %s "
+                      "because there is not enough food available! "
+                      "You are responsible for her poverty!"),
+                    city_name(pcity_from), player_name(pplayer_from),
+                    city_name(pcity_to));
+    }
+
+    return FALSE;
+  }
+
+  if (!city_can_grow_to(pcity_to, pcity_to->size + 1)) {
+    /* receiver city can't grow  */
+    if (pplayer_from == pplayer_to) {
+      /* migration between one nation */
+      notify_player(pplayer_to, city_tile(pcity_to), E_CITY_TRANSFER,
+                    _("Game: Migrants from %s can't go to %s "
+                      "because it needs an improvement to grow! "
+                      "You are responsible for her poverty!"),
+                    city_name(pcity_from), city_name(pcity_to));
+    } else {
+      /* migration between different nations */
+      notify_player(pplayer_from, city_tile(pcity_to), E_CITY_TRANSFER,
+                    _("Game: Migrants from %s can't go to %s of %s "
+                      "because it needs an improvement to grow! "
+                      "Improve your city to keep your citizens!"),
+                    city_name(pcity_from), city_name(pcity_to),
+                    player_name(pplayer_to));
+      notify_player(pplayer_to, city_tile(pcity_to), E_CITY_TRANSFER,
+                    _("Game: Migrants from %s of %s can't go to %s "
+                      "because it needs an improvement to grow! "
+                      "You are responsible for her poverty!"),
+                    city_name(pcity_from), player_name(pplayer_from),
+                    city_name(pcity_to));
+    }
+
+    return FALSE;
+  }
+
+  /* we copy the city name, maybe we disband it! */
+  sz_strlcpy(city_from_name, city_name(pcity_from));
+  /* reduce size of giver */
+  if (pcity_from->size == 1) {
+    /* find closest city other of the same player than pcity_from */
+    rcity = find_closest_owned_city(pplayer_from, city_tile(pcity_from),
+                                    FALSE, pcity_from);
+
+    if (rcity) {
+      /* transfer all units to the closest city */
+      transfer_city_units(pplayer_from, pplayer_from,
+                          pcity_from->units_supported, rcity, pcity_from,
+                          -1, TRUE);
+      remove_city(pcity_from);
+
+      notify_player(pplayer_from, city_tile(pcity_from), E_CITY_TRANSFER,
+                    _("Game: %s was disbanded by its citizens."),
+                    city_from_name);
+    } else {
+      /* it's the only city of the nation; stop here */
+      notify_player(pplayer_from, city_tile(pcity_from), E_CITY_TRANSFER,
+                    _("Game: Citizen of %s are unhappy and want to "
+                      "migrate to %s (%s) in search for a better life."),
+                    city_from_name, city_name(pcity_to),
+                    player_name(pplayer_to));
+      return FALSE;
+    }
+  } else {
+    city_reduce_size(pcity_from, 1, pplayer_from);
+    city_refresh_vision(pcity_from);
+    city_refresh(pcity_from);
+  }
+  /* raise size of receiver city */
+  city_increase_size(pcity_to);
+  city_refresh_vision(pcity_to);
+  city_refresh(pcity_to);
+
+  if (pplayer_from == pplayer_to) {
+    /* migration between one nation */
+    notify_player(pplayer_from, city_tile(pcity_to), E_CITY_TRANSFER,
+                  _("Game: Migrants from %s moved to %s in search for a "
+                    "better life."), city_from_name, city_name(pcity_to));
+  } else {
+    /* migration between different nations */
+    notify_player(pplayer_from, city_tile(pcity_to), E_CITY_TRANSFER,
+                  _("Game: Migrants from %s moved to %s (%s) in search "
+                    "for a better life."), city_from_name,
+                  city_name(pcity_to), player_name(pplayer_to));
+    notify_player(pplayer_to, city_tile(pcity_to), E_CITY_TRANSFER,
+                  _("Game: Migrants from %s (%s) moved to %s in search "
+                    "for a better life."), city_from_name,
+                  player_name(pplayer_from), city_name(pcity_to));
+  }
+
+  freelog(LOG_DEBUG, "[M] T%d migration successful (%s -> %s)",
+          game.info.turn, city_from_name, city_name(pcity_to));
+
+  return TRUE;
+}
+
+/**************************************************************************
+  Check for citizens who want to migrate between the cities that overlap.
+  Migrants go to the city with higher score (saved in city->score), if the
+  growth of the target city is not blocked due to a missing improvement.
+
+  The following setting are used:
+
+  'game.info.migrationsturns' controls the number of turns between
+  migration checks for one city (counted from the founding). If this
+  setting is zero, or it is the first turn (T0), migration does no occur.
+
+  'game.info.migrationsdist' is the maximal distance for migration.
+
+  'game.info.migrationsplayer' gives the chance for migration within one
+  nation.
+
+  'game.info.migrationsworld' gives the chance for migration between all
+  nations.
+**************************************************************************/
+void check_city_migrations(struct player *pplayer)
+{
+  if (!pplayer || game.info.migrationturn <= 0 || game.info.turn <= 0
+      || (game.info.migrationworld == 0 && game.info.migrationplayer == 0)
+      ) {
+    return;
+  }
+
+  /* check for each city
+   * city_list_iterate_safe_end must be used because we could
+   * remove one city from the list */
+  city_list_iterate_safe(pplayer->cities, pcity) {
+    /* no migration out of the capital */
+    if (is_capital(pcity)) {
+      continue;
+    }
+
+    /* check only each (game.info.migrationturn) turn
+     * (counted from the funding turn) */
+    if (((game.info.turn - pcity->turn_founded)
+         % game.info.migrationturn) > 0) {
+      continue;
+    }
+
+    float best_city_player_score = 0;
+    struct city *best_city_player = NULL;
+
+    float best_city_world_score = 0;
+    struct city *best_city_world = NULL;
+
+    /* score of the actual city
+     * taking into account a persistence factor of 3 */
+    float score_from = city_score(pcity) * 3;
+    float score_tmp = 0;
+
+    freelog(LOG_DEBUG, "[M] T%d check city: %s score: %6.3f (%s)",
+            game.info.turn, city_name(pcity), score_from,
+            player_name(pplayer));
+
+    best_city_player_score = 0;
+    best_city_world_score = 0;
+
+    /* loop over all tiles in a circle of game.info.migrationdist radius
+     * in search for cities which overlap */
+    circle_iterate(city_tile(pcity),(game.info.migrationdist *
+                                     game.info.migrationdist + 1), ptile) {
+      struct city *acity = tile_city(ptile);
+
+      if (!acity || acity == pcity) {
+        /* no city or the city in the center */
+        continue;
+      }
+
+      /* distance between the two cities */
+      int dist = real_map_distance(city_tile(pcity), city_tile(acity));
+
+      /* score of the second city, weighted by the distance */
+      score_tmp = city_score(acity) * (GAME_MAX_MIGRATION_DIST - dist)
+                  / GAME_MAX_MIGRATION_DIST;
+
+      freelog(LOG_DEBUG, "[M] T%d - compare city: %s (%s) dist: %d "
+              "score: %6.3f", game.info.turn, city_name(acity),
+              player_name(city_owner(acity)), dist, score_tmp);
+
+      if (game.info.migrationplayer != 0 && city_owner(acity) == pplayer) {
+        /* inmigrate in cities of the same owner */
+        if ((score_tmp > score_from)
+            && (score_tmp > best_city_player_score)) {
+          /* select the best! */
+          best_city_player_score = score_tmp;
+          best_city_player = acity;
+
+          freelog(LOG_DEBUG, "[M] T%d - best city (player): %s (%s) score: "
+                  "%6.3f (> %6.3f)", game.info.turn,
+                  city_name(best_city_player), player_name(pplayer),
+                  best_city_player_score, score_from);
+        }
+      } else if (game.info.migrationworld != 0
+                 && city_owner(acity) != pplayer) {
+        /* inmigrate between cities of different owners */
+        if ((score_tmp > score_from)
+            && (score_tmp > best_city_world_score)) {
+          /* select the best! */
+          best_city_world_score = score_tmp;
+          best_city_world = acity;
+
+          freelog(LOG_DEBUG, "[M] T%d - best city (world): %s (%s) score: "
+                  "%6.3f (> %6.3f)", game.info.turn,
+                  city_name(best_city_world),
+                  player_name(city_owner(best_city_world)),
+                  best_city_world_score, score_from);
+        }
+      }
+    } circle_iterate_end;
+
+    if (best_city_player_score > 0) {
+      /* first, do the migration within one nation */
+      if (myrand (100) >= game.info.migrationplayer) {
+        /* no migration */
+        notify_player(pplayer, city_tile(pcity), E_CITY_TRANSFER,
+                      _("Game: Citizens of %s are thinking about migration "
+                        "to %s in search for a better life."),
+                      pcity->name, city_name(best_city_player));
+      } else {
+        make_city_migration(pplayer, pcity, pplayer, best_city_player);
+      }
+
+      /* stop here */
+      continue;
+    }
+
+    if (best_city_world_score > 0) {
+      /* second, do the migration between all nations */
+      if (myrand (100) >= game.info.migrationworld) {
+        /* no migration */
+        notify_player(pplayer, city_tile(pcity), E_CITY_TRANSFER,
+                      _("Game: Citizens of %s are thinking about migration "
+                        "to %s of %s in search for a better life."),
+                      city_name(pcity), city_name(best_city_world),
+                      player_name(city_owner(best_city_world)));
+      } else {
+        make_city_migration(pplayer, pcity, city_owner(best_city_world),
+                            best_city_world);
+      }
+
+      /* stop here */
+      continue;
+    }
+
+  } city_list_iterate_safe_end;
+
+}
diff -ur -X./freeciv-2.1.99svn15391/diff_ignore freeciv-2.1.99svn15391/server/cityturn.h freeciv-2.1.99svn.patch/server/cityturn.h
--- freeciv-2.1.99svn15391/server/cityturn.h	2008-12-25 19:45:49.000000000 +0100
+++ freeciv-2.1.99svn.patch/server/cityturn.h	2008-12-30 23:31:54.000000000 +0100
@@ -46,4 +46,7 @@
 void advisor_choose_build(struct player *pplayer, struct city *pcity);
 
 void nullify_prechange_production(struct city *pcity);
+
+void check_city_migrations(struct player *pplayer);
+
 #endif  /* FC__CITYTURN_H */
diff -ur -X./freeciv-2.1.99svn15391/diff_ignore freeciv-2.1.99svn15391/server/savegame.c freeciv-2.1.99svn.patch/server/savegame.c
--- freeciv-2.1.99svn15391/server/savegame.c	2008-12-27 17:25:17.000000000 +0100
+++ freeciv-2.1.99svn.patch/server/savegame.c	2008-12-31 16:37:16.000000000 +0100
@@ -4291,6 +4291,18 @@
     game.info.allowed_city_names =
       secfile_lookup_int_default(file, game.info.allowed_city_names,
                                  "game.allowed_city_names"); 
+    game.info.migrationturn =
+      secfile_lookup_int_default(file, game.info.migrationturn,
+                                 "game.migrationturn");
+    game.info.migrationdist =
+      secfile_lookup_int_default(file, game.info.migrationdist,
+                                 "game.migrationdist");
+    game.info.migrationplayer =
+      secfile_lookup_int_default(file, game.info.migrationplayer,
+                                 "game.migrationplayer");
+    game.info.migrationworld =
+      secfile_lookup_int_default(file, game.info.migrationworld,
+                                 "game.migrationworld");
 
     if(civstyle == 1) {
       string = "civ1";
@@ -4943,6 +4955,10 @@
   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.migrationturn, "game.migrationturn");
+  secfile_insert_int(file, game.info.migrationdist, "game.migrationdist");
+  secfile_insert_int(file, game.info.migrationplayer, "game.migrationplayer");
+  secfile_insert_int(file, game.info.migrationworld, "game.migrationworld");
 
   {
     /* Now always save these, so the server options reflect the
diff -ur -X./freeciv-2.1.99svn15391/diff_ignore freeciv-2.1.99svn15391/server/settings.c freeciv-2.1.99svn.patch/server/settings.c
--- freeciv-2.1.99svn15391/server/settings.c	2008-12-25 19:45:49.000000000 +0100
+++ freeciv-2.1.99svn.patch/server/settings.c	2008-12-31 16:47:04.000000000 +0100
@@ -841,6 +841,44 @@
               "on the surrounding terrain."),
            NULL, GAME_DEFAULT_NATURALCITYNAMES)
 
+  GEN_INT("migrationturn", game.info.migrationturn,
+          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 happyer "
+             "people, improvements and a surplus of trade, luxury and "
+             "science. The palace building also greatly increases the "
+             "destination desirability. If this setting is zero, "
+             "migration will be disabled."), NULL, GAME_MIN_MIGRATION_TURN,
+          GAME_MAX_MIGRATION_TURN, GAME_DEFAULT_MIGRATION_TURN)
+
+  GEN_INT("migrationdist", game.info.migrationdist,
+          SSET_RULES_FLEXIBLE, SSET_SOCIOLOGY, SSET_RARE, SSET_TO_CLIENT,
+          N_("Distance for migration between cities"),
+          N_("If two cities overlap or are close to each over, citizens "
+             "can migrate between both cities. For example, when this "
+             "value is 3, there can be up to two empty fields between "
+             "two cities for citizens to migrate."), NULL,
+          GAME_MIN_MIGRATION_DIST, GAME_MAX_MIGRATION_DIST,
+          GAME_DEFAULT_MIGRATION_DIST)
+
+  GEN_INT("migrationplayer", game.info.migrationplayer,
+          SSET_RULES_FLEXIBLE, SSET_SOCIOLOGY, SSET_RARE, SSET_TO_CLIENT,
+          N_("Chance for migration within one nation"),
+          N_("Possibility of migration between overlapping cities"
+             "within one nation."),
+          NULL, GAME_MIN_MIGRATION_PLAYER, GAME_MAX_MIGRATION_PLAYER,
+          GAME_DEFAULT_MIGRATION_PLAYER)
+
+  GEN_INT("migrationworld", game.info.migrationworld,
+          SSET_RULES_FLEXIBLE, SSET_SOCIOLOGY, SSET_RARE, SSET_TO_CLIENT,
+          N_("Chance for migration between all cities"),
+          N_("Possibility of migration between overlapping cities"
+             "taking into account cities of all nations."),
+          NULL, GAME_MIN_MIGRATION_WORLD, GAME_MAX_MIGRATION_WORLD,
+          GAME_DEFAULT_MIGRATION_WORLD)
+
   /* 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 -ur -X./freeciv-2.1.99svn15391/diff_ignore freeciv-2.1.99svn15391/server/srv_main.c freeciv-2.1.99svn.patch/server/srv_main.c
--- freeciv-2.1.99svn15391/server/srv_main.c	2008-12-27 17:25:17.000000000 +0100
+++ freeciv-2.1.99svn.patch/server/srv_main.c	2008-12-31 16:52:02.000000000 +0100
@@ -869,6 +869,13 @@
   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.migrationturn > 0) {
+    freelog(LOG_DEBUG, "Season of migrations");
+    players_iterate(pplayer) {
+      check_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