<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 Freeciv-dev@gna.org https://mail.gna.org/listinfo/freeciv-dev