<URL: http://bugs.freeciv.org/Ticket/Display.html?id=40612 >
The migration patch (version 6)
changes:
- split the patch in three parts:
* the patch
* patch to add an option for the food check
* some freelog(LOG_NORMAL,...) debugging messages
The patch was tested.
Matthias
diff -ur -X./freeciv-2.1.99svn15393/diff_ignore freeciv-2.1.99svn.patch_migration_food/server/cityturn.c freeciv-2.1.99svn.patch_migration_debug/server/cityturn.c
--- freeciv-2.1.99svn.patch_migration_food/server/cityturn.c 2009-01-04 21:28:25.000000000 +0100
+++ freeciv-2.1.99svn.patch_migration_debug/server/cityturn.c 2009-01-04 22:19:27.000000000 +0100
@@ -1466,7 +1466,7 @@
utype_name_translation(utype));
/* Log before signal emitting, so pointers are certainly valid */
- freelog(LOG_VERBOSE, "%s %s tried to build %s, which is not available.",
+ freelog(LOG_NORMAL, "%s %s tried to build %s, which is not available.",
nation_rule_name(nation_of_city(pcity)),
city_name(pcity),
utype_rule_name(utype));
@@ -2076,7 +2076,7 @@
player_name(pplayer_from), city_name(pcity_to));
}
- freelog(LOG_DEBUG, "[M] T%d migration successful (%s -> %s)",
+ freelog(LOG_NORMAL, "[M] T%d migration successful (%s -> %s)",
game.info.turn, city_from_name, city_name(pcity_to));
return TRUE;
@@ -2136,7 +2136,7 @@
float score_from = city_score(pcity) * 3;
float score_tmp = 0;
- freelog(LOG_DEBUG, "[M] T%d check city: %s score: %6.3f (%s)",
+ freelog(LOG_NORMAL, "[M] T%d check city: %s score: %6.3f (%s)",
game.info.turn, city_name(pcity), score_from,
player_name(pplayer));
@@ -2161,7 +2161,7 @@
score_tmp = city_score(acity) * (GAME_MAX_MIGRATION_DIST + 1 - dist)
/ (GAME_MAX_MIGRATION_DIST + 1);
- freelog(LOG_DEBUG, "[M] T%d - compare city: %s (%s) dist: %d "
+ freelog(LOG_NORMAL, "[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);
@@ -2173,7 +2173,7 @@
best_city_player_score = score_tmp;
best_city_player = acity;
- freelog(LOG_DEBUG, "[M] T%d - best city (player): %s (%s) score: "
+ freelog(LOG_NORMAL, "[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);
@@ -2187,7 +2187,7 @@
best_city_world_score = score_tmp;
best_city_world = acity;
- freelog(LOG_DEBUG, "[M] T%d - best city (world): %s (%s) score: "
+ freelog(LOG_NORMAL, "[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)),
diff -ur -X./freeciv-2.1.99svn15393/diff_ignore freeciv-2.1.99svn.patch_migration/common/game.c freeciv-2.1.99svn.patch_migration_food/common/game.c
--- freeciv-2.1.99svn.patch_migration/common/game.c 2009-01-04 21:22:21.000000000 +0100
+++ freeciv-2.1.99svn.patch_migration_food/common/game.c 2009-01-04 21:22:39.000000000 +0100
@@ -276,6 +276,7 @@
game.info.savepalace = GAME_DEFAULT_SAVEPALACE;
game.info.natural_city_names = GAME_DEFAULT_NATURALCITYNAMES;
game.info.migrationturn = GAME_DEFAULT_MIGRATION_TURN;
+ game.info.migrationturn = GAME_DEFAULT_MIGRATION_FOOD;
game.info.migrationdist = GAME_DEFAULT_MIGRATION_DIST;
game.info.migrationworld = GAME_DEFAULT_MIGRATION_WORLD;
game.info.migrationplayer = GAME_DEFAULT_MIGRATION_PLAYER;
diff -ur -X./freeciv-2.1.99svn15393/diff_ignore freeciv-2.1.99svn.patch_migration/common/game.h freeciv-2.1.99svn.patch_migration_food/common/game.h
--- freeciv-2.1.99svn.patch_migration/common/game.h 2009-01-04 21:22:21.000000000 +0100
+++ freeciv-2.1.99svn.patch_migration_food/common/game.h 2009-01-04 21:22:39.000000000 +0100
@@ -254,6 +254,8 @@
#define GAME_MIN_MIGRATION_TURN 0
#define GAME_MAX_MIGRATION_TURN 100
+#define GAME_DEFAULT_MIGRATION_FOOD TRUE
+
#define GAME_DEFAULT_MIGRATION_DIST 3
#define GAME_MIN_MIGRATION_DIST 1
#define GAME_MAX_MIGRATION_DIST 7
diff -ur -X./freeciv-2.1.99svn15393/diff_ignore freeciv-2.1.99svn.patch_migration/common/packets.def freeciv-2.1.99svn.patch_migration_food/common/packets.def
--- freeciv-2.1.99svn.patch_migration/common/packets.def 2009-01-04 21:22:21.000000000 +0100
+++ freeciv-2.1.99svn.patch_migration_food/common/packets.def 2009-01-04 21:22:39.000000000 +0100
@@ -415,6 +415,7 @@
BOOL savepalace;
BOOL natural_city_names;
UINT8 migrationturn;
+ BOOL migrationfood;
UINT8 migrationdist;
UINT8 migrationplayer;
UINT8 migrationworld;
diff -ur -X./freeciv-2.1.99svn15393/diff_ignore freeciv-2.1.99svn.patch_migration/server/cityturn.c freeciv-2.1.99svn.patch_migration_food/server/cityturn.c
--- freeciv-2.1.99svn.patch_migration/server/cityturn.c 2009-01-04 21:27:30.000000000 +0100
+++ freeciv-2.1.99svn.patch_migration_food/server/cityturn.c 2009-01-04 21:28:25.000000000 +0100
@@ -1970,7 +1970,7 @@
char city_from_name[MAX_LEN_NAME];
struct city *rcity = NULL;
- if (pcity_to->surplus[O_FOOD] < 0) {
+ if (game.info.migrationfood && pcity_to->surplus[O_FOOD] < 0) {
/* insufficiency food in receiver city; no additional citizens */
if (pplayer_from == pplayer_to) {
/* migration between one nation */
diff -ur -X./freeciv-2.1.99svn15393/diff_ignore freeciv-2.1.99svn.patch_migration/server/savegame.c freeciv-2.1.99svn.patch_migration_food/server/savegame.c
--- freeciv-2.1.99svn.patch_migration/server/savegame.c 2009-01-04 21:22:21.000000000 +0100
+++ freeciv-2.1.99svn.patch_migration_food/server/savegame.c 2009-01-04 21:22:39.000000000 +0100
@@ -4294,6 +4294,9 @@
game.info.migrationturn =
secfile_lookup_int_default(file, game.info.migrationturn,
"game.migrationturn");
+ game.info.migrationfood =
+ secfile_lookup_bool_default(file, game.info.migrationfood,
+ "game.migrationfood");
game.info.migrationdist =
secfile_lookup_int_default(file, game.info.migrationdist,
"game.migrationdist");
@@ -4956,6 +4959,7 @@
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_bool(file, game.info.migrationfood, "game.migrationfood");
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");
diff -ur -X./freeciv-2.1.99svn15393/diff_ignore freeciv-2.1.99svn.patch_migration/server/settings.c freeciv-2.1.99svn.patch_migration_food/server/settings.c
--- freeciv-2.1.99svn.patch_migration/server/settings.c 2009-01-04 21:22:21.000000000 +0100
+++ freeciv-2.1.99svn.patch_migration_food/server/settings.c 2009-01-04 21:22:39.000000000 +0100
@@ -854,6 +854,13 @@
GAME_MIN_MIGRATION_TURN, GAME_MAX_MIGRATION_TURN,
GAME_DEFAULT_MIGRATION_TURN)
+ GEN_BOOL("migrationfood", game.info.migrationfood,
+ SSET_RULES_FLEXIBLE, SSET_SOCIOLOGY, SSET_RARE, SSET_TO_CLIENT,
+ N_("Migration is limited by the amount of food available"),
+ N_("If enabled, migration is limited by the amount of food "
+ "available in the receiving city."),
+ NULL, GAME_DEFAULT_MIGRATION_FOOD)
+
GEN_INT("migrationdist", game.info.migrationdist,
SSET_RULES_FLEXIBLE, SSET_SOCIOLOGY, SSET_RARE, SSET_TO_CLIENT,
N_("Distance for migration between cities"),
diff -ur -X./freeciv-2.1.99svn15393/diff_ignore freeciv-2.1.99svn15393/common/game.c freeciv-2.1.99svn.patch_migration/common/game.c
--- freeciv-2.1.99svn15393/common/game.c 2008-12-25 19:45:44.000000000 +0100
+++ freeciv-2.1.99svn.patch_migration/common/game.c 2009-01-04 21:22:21.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.99svn15393/diff_ignore freeciv-2.1.99svn15393/common/game.h freeciv-2.1.99svn.patch_migration/common/game.h
--- freeciv-2.1.99svn15393/common/game.h 2008-12-30 23:29:33.000000000 +0100
+++ freeciv-2.1.99svn.patch_migration/common/game.h 2009-01-04 21:22:21.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.99svn15393/diff_ignore freeciv-2.1.99svn15393/common/packets.def freeciv-2.1.99svn.patch_migration/common/packets.def
--- freeciv-2.1.99svn15393/common/packets.def 2008-12-30 23:29:33.000000000 +0100
+++ freeciv-2.1.99svn.patch_migration/common/packets.def 2009-01-04 21:22:21.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.99svn15393/diff_ignore freeciv-2.1.99svn15393/server/cityturn.c freeciv-2.1.99svn.patch_migration/server/cityturn.c
--- freeciv-2.1.99svn15393/server/cityturn.c 2008-12-25 19:45:49.000000000 +0100
+++ freeciv-2.1.99svn.patch_migration/server/cityturn.c 2009-01-04 21:27:30.000000000 +0100
@@ -90,6 +90,12 @@
static void update_city_activity(struct player *pplayer, struct city *pcity);
static void nullify_caravan_and_disband_plus(struct city *pcity);
+static float city_score(const struct city *pcity);
+static bool make_city_migration(const struct player *pplayer_from,
+ struct city *pcity_from,
+ const struct player *pplayer_to,
+ struct city *pcity_to);
+
/**************************************************************************
...
**************************************************************************/
@@ -1867,3 +1873,363 @@
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!
+
+ * if the city has at least one wonder a factor of 1.25 is added
+ * 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;
+ bool has_wonder = FALSE;
+
+ if (!pcity) {
+ return 0.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];
+
+ /* calculate shield build cost for all buildings */
+ city_built_iterate(pcity, pimprove) {
+ build_shield_cost += impr_build_shield_cost(pimprove);
+ if (is_wonder(pimprove)) {
+ /* this city has a wonder */
+ has_wonder = TRUE;
+ }
+ } city_built_iterate_end;
+ /* take shield costs of all buidings into account; normalized by 1000 */
+ score *= (1 + (1 - exp(-(float)build_shield_cost/1000))/5);
+ /* take trade into account; normalized by 100 */
+ score *= (1 + (1 - exp(-(float)pcity->surplus[O_TRADE]/100))/5);
+ /* take luxury into account; normalized by 100 */
+ score *= (1 + (1 - exp(-(float)pcity->surplus[O_LUXURY]/100))/5);
+ /* take science into account; normalized by 100 */
+ score *= (1 + (1 - exp(-(float)pcity->surplus[O_SCIENCE]/100))/5);
+
+ if (has_wonder) {
+ /* people like wonders */
+ score *= 1.25;
+ }
+
+ 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,
+ _("Migrants from %s can't go to %s because there is "
+ "not enough food available!"),
+ city_name(pcity_from), city_name(pcity_to));
+ } else {
+ /* migration between different nations */
+ notify_player(pplayer_from, city_tile(pcity_to), E_CITY_TRANSFER,
+ _("Migrants from %s can't go to %s (%s) because there "
+ "is not enough food available!"),
+ city_name(pcity_from), city_name(pcity_to),
+ player_name(pplayer_to));
+ notify_player(pplayer_to, city_tile(pcity_to), E_CITY_TRANSFER,
+ _("Migrants from %s (%s) can't go to %s because there "
+ "is not enough food available!"),
+ 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,
+ _("Migrants from %s can't go to %s because it needs "
+ "an improvement to grow!"),
+ city_name(pcity_from), city_name(pcity_to));
+ } else {
+ /* migration between different nations */
+ notify_player(pplayer_from, city_tile(pcity_to), E_CITY_TRANSFER,
+ _("Migrants from %s can't go to %s of %s because it "
+ "needs an improvement to grow!"),
+ city_name(pcity_from), city_name(pcity_to),
+ player_name(pplayer_to));
+ notify_player(pplayer_to, city_tile(pcity_to), E_CITY_TRANSFER,
+ _("Migrants from %s of %s can't go to %s because it "
+ "needs an improvement to grow!"),
+ 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) {
+ /* do not destroy wonders */
+ city_built_iterate(pcity_from, pimprove) {
+ if (is_wonder(pimprove)) {
+ return FALSE;
+ }
+ } city_built_iterate_end;
+
+ /* 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,
+ _("%s was disbanded by its citizens."),
+ city_from_name);
+ } else {
+ /* it's the only city of the nation */
+ 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,
+ _("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,
+ _("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,
+ _("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, if the growth of the target
+ city is not blocked due to a missing improvement.
+
+ The following setting are used:
+
+ 'game.info.migrationsturn' 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 + 1 - dist)
+ / (GAME_MAX_MIGRATION_DIST + 1);
+
+ 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,
+ _("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,
+ _("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.99svn15393/diff_ignore freeciv-2.1.99svn15393/server/cityturn.h freeciv-2.1.99svn.patch_migration/server/cityturn.h
--- freeciv-2.1.99svn15393/server/cityturn.h 2008-12-25 19:45:49.000000000 +0100
+++ freeciv-2.1.99svn.patch_migration/server/cityturn.h 2009-01-04 21:22:21.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.99svn15393/diff_ignore freeciv-2.1.99svn15393/server/savegame.c freeciv-2.1.99svn.patch_migration/server/savegame.c
--- freeciv-2.1.99svn15393/server/savegame.c 2008-12-27 17:25:17.000000000 +0100
+++ freeciv-2.1.99svn.patch_migration/server/savegame.c 2009-01-04 21:22:21.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.99svn15393/diff_ignore freeciv-2.1.99svn15393/server/settings.c freeciv-2.1.99svn.patch_migration/server/settings.c
--- freeciv-2.1.99svn15393/server/settings.c 2008-12-25 19:45:49.000000000 +0100
+++ freeciv-2.1.99svn.patch_migration/server/settings.c 2009-01-04 21:22:21.000000000 +0100
@@ -841,6 +841,45 @@
"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 (especially wonders) 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.99svn15393/diff_ignore freeciv-2.1.99svn15393/server/srv_main.c freeciv-2.1.99svn.patch_migration/server/srv_main.c
--- freeciv-2.1.99svn15393/server/srv_main.c 2008-12-27 17:25:17.000000000 +0100
+++ freeciv-2.1.99svn.patch_migration/server/srv_main.c 2009-01-04 21:22:21.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
[email protected]
https://mail.gna.org/listinfo/freeciv-dev