<URL: http://bugs.freeciv.org/Ticket/Display.html?id=40612 >
Hello all, here is an updated version of the patch. The changes are * I added 3 configuration options game.info.migrationdist: - distance for migration (largest value) game.info.migrationplayer: - chance for migration within one nation game.info.migrationworld: - chance for migration between nations * the score for the cities is calculated as score = (city size + feeling) * factors with 'feeling' as measurement for the attitude of the citizens feelings = 1.00 * happy citizens + 0.00 * content citizens - 0.25 * unhappy citizens - 0.50 * unhappy citizens and the factors take into account the buildings as well as the surplus of the city * the build costs of all buildings f = (1.0 + [build shield cost]/1000) * the trade of the city f = (1 + [city surplus trade]/100) * the gold within the city f = (1 + [city surplus gold]/100) * the luxury within the city f = (1 + [city surplus luxury]/100) * the science within the city f = (1 + [city surplus science]/100) For the Migration between two cities their score is modified. If the migrants go from city A to city B the following values are calculated * for city A take into account the persistence factor (=2) A = score A * 2 * for city B take into account the distance between both cities B = score B * (MIGRATION_MAX_DIST - distance A-B) / MIGRATION_MAX_DIST with MIGRATION_MAX_DIST = 7 If A < B some citizens will migrate from city A to city B. If city A has a size of 1 it will be disbanded. This will _not_ happen if it is the last city of a nation. Also citizens will never migrate out of the capital. It game.info.migrationdist is equal to 0 migration will be disabled. Have a nice time Matthias
diff -ur -X./freeciv-2.1.99svn15387/diff_ignore freeciv-2.1.99svn15387/common/game.c freeciv-2.1.99svn.patch/common/game.c --- freeciv-2.1.99svn15387/common/game.c 2008-12-25 19:45:44.000000000 +0100 +++ freeciv-2.1.99svn.patch/common/game.c 2008-12-30 19:04:41.000000000 +0100 @@ -275,6 +275,9 @@ game.info.celebratesize = GAME_DEFAULT_CELEBRATESIZE; game.info.savepalace = GAME_DEFAULT_SAVEPALACE; game.info.natural_city_names = GAME_DEFAULT_NATURALCITYNAMES; + 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.99svn15387/diff_ignore freeciv-2.1.99svn15387/common/game.h freeciv-2.1.99svn.patch/common/game.h --- freeciv-2.1.99svn15387/common/game.h 2008-12-25 19:45:44.000000000 +0100 +++ freeciv-2.1.99svn.patch/common/game.h 2008-12-30 21:38:38.000000000 +0100 @@ -248,6 +248,18 @@ #define GAME_DEFAULT_NATURALCITYNAMES TRUE +#define GAME_DEFAULT_MIGRATION_DIST 4 +#define GAME_MIN_MIGRATION_DIST 0 /* 0 = no migration */ +#define GAME_MAX_MIGRATION_DIST 7 + +#define GAME_DEFAULT_MIGRATION_PLAYER 70 +#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.99svn15387/diff_ignore freeciv-2.1.99svn15387/common/packets.def freeciv-2.1.99svn.patch/common/packets.def --- freeciv-2.1.99svn15387/common/packets.def 2008-12-27 17:25:16.000000000 +0100 +++ freeciv-2.1.99svn.patch/common/packets.def 2008-12-30 19:01:07.000000000 +0100 @@ -414,6 +414,9 @@ UINT8 razechance; BOOL savepalace; BOOL natural_city_names; + UINT8 migrationdist; + UINT8 migrationplayer; + UINT8 migrationworld; BOOL turnblock; BOOL fixedlength; BOOL auto_ai_toggle; diff -ur -X./freeciv-2.1.99svn15387/diff_ignore freeciv-2.1.99svn15387/server/cityturn.c freeciv-2.1.99svn.patch/server/cityturn.c --- freeciv-2.1.99svn15387/server/cityturn.c 2008-12-25 19:45:49.000000000 +0100 +++ freeciv-2.1.99svn.patch/server/cityturn.c 2008-12-30 22:16:17.000000000 +0100 @@ -1867,3 +1867,303 @@ remove_city(pcity); return TRUE; } + +/************************************************************************** + Helpful function to make a score of a city. + + formula: + score = (city size + feeling) * factors + + * feeling of the citizens + + 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.0 + [build shield cost]/1000) + * the trade of the city + f = (1 + [city surplus trade]/100) + * the gold within the city + f = (1 + [city surplus gold]/100) + * the luxury within the city + f = (1 + [city surplus luxury]/100) + * the science within the city + f = (1 + [city surplus science]/100) +**************************************************************************/ +static float city_score(struct city *pcity) +{ + float score = 0.0; + float feeling = 0.0; + float f_build_cost, f_trade, f_gold, f_luxury, f_science = 0.0; + int build_shield_cost = 0; + + /* feeling of the citizens */ + feeling = 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; + f_build_cost = (1.0 + (float)build_shield_cost/1000); + /* take trade into account */ + f_trade = (1.0 + (float)pcity->surplus[O_TRADE]/100); + /* take gold into account */ + f_gold = (1.0 + (float)pcity->surplus[O_GOLD]/100); + /* take luxury into account */ + f_luxury = (1.0 + (float)pcity->surplus[O_LUXURY]/100); + /* take science into account */ + f_science = (1.0 + (float)pcity->surplus[O_SCIENCE]/100); + + score = (pcity->size + feeling) * f_build_cost * f_trade * f_gold + * f_luxury * f_science; + + freelog(LOG_DEBUG, "[M] %s score: (%d + %6.3f) * (%5.3f * %5.3f " + "* %5.3f * %5.3f * %5.3f) = %6.3f", + city_name(pcity), pcity->size, feeling, + f_build_cost, f_trade, f_gold, f_luxury, + f_science, score); + + return score; +} + +/************************************************************************** + Make citizens migrate between two cities. +**************************************************************************/ +static void make_city_migration( + struct player *pplayer_from, struct city *pcity_from, + struct player *pplayer_to, struct city *pcity_to) +{ + char city_from_name[MAX_LEN_NAME]; + struct city *rcity = NULL; + + /* we copy the city name, maybe we disband it! */ + sz_strlcpy(city_from_name, city_name(pcity_from)); + if (city_can_grow_to(pcity_to, pcity_to->size + 1)) { + /* 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, pcity_from->tile, + FALSE, pcity_from); + + if (rcity) { + notify_player(pplayer_from, pcity_from->tile, E_CITY_TRANSFER, + _("Game: %s was disbanded by its citizens."), + city_from_name); + + /* 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); + } else { + /* it's the only city of the nation; stop here */ + notify_player(pplayer_from, pcity_from->tile, E_CITY_TRANSFER, + _("Game: Citizen of %s are unhappy and want to migrate " + "to %s of %s in search for a better life."), + city_from_name, city_name(pcity_to), + player_name(pplayer_to)); + return; + } + } else { + city_reduce_size(pcity_from, 1, pplayer_from); + city_refresh(pcity_from); + } + /* raise size of receiver city */ + city_increase_size(pcity_to); + city_refresh(pcity_to); + + if (pplayer_from == pplayer_to) { + /* migration between one nation */ + notify_player(pplayer_from, pcity_to->tile, E_CITY_TRANSFER, + _("Game: Migrants of %s integrated in %s " + "in search for a better life."), + city_from_name, city_name(pcity_to)); + } else { + /* migration between different nations */ + notify_player(pplayer_from, pcity_to->tile, E_CITY_TRANSFER, + _("Game: Migrants of %s integrated in %s of %s " + "in search for a better life."), + city_from_name, city_name(pcity_to), + player_name(pplayer_to)); + notify_player(pplayer_to, pcity_to->tile, E_CITY_TRANSFER, + _("Game: Migrants of %s of %s integrated in %s " + "in search for a better life."), + city_from_name, player_name(pplayer_from), + city_name(pcity_to)); + } + + freelog(LOG_NORMAL, "[M] T%d migration successful (%s -> %s)", + game.info.turn, city_from_name, city_name(pcity_to)); + + } else { + /* protest! */ + if (pplayer_from == pplayer_to) { + /* migration between one nation */ + notify_player(pplayer_to, pcity_to->tile, E_CITY_TRANSFER, + _("Game: Migrants of %s can't go to %s " + "because it needs an improvement to grow! " + "You are responsible for her poverty!"), + city_from_name, city_name(pcity_to)); + } else { + /* migration between different nations */ + notify_player(pplayer_from, pcity_to->tile, E_CITY_TRANSFER, + _("Game: Migrants of %s can't go to %s of %s " + "because it needs an improvement to grow! " + "Improve your city to keep your citizens!"), + city_from_name, city_name(pcity_to), + player_name(pplayer_to)); + notify_player(pplayer_to, pcity_to->tile, E_CITY_TRANSFER, + _("Game: Migrants of %s of %s can't go to %s " + "because it needs an improvement to grow! " + "You are responsible for her poverty!"), + city_from_name, player_name(pplayer_from), + city_name(pcity_to)); + } + } +} + +/************************************************************************** + Check for citizens who want to migrate between the cities that overlap. + + Migrants go to the better city of both involved, the giver and the receiver. +**************************************************************************/ +void check_city_migrations(struct player *pplayer) +{ + float best_city_player_score; + struct city *best_city_player = NULL; + + float best_city_world_score; + struct city *best_city_world = NULL; + + float score_from; + float score_tmp; + + struct city *acity = NULL; + int dist = 0; + + /* do the calculation only if migration is activated */ + if (game.info.migrationdist == 0 + || (game.info.migrationworld == 0 + && game.info.migrationplayer == 0)) { + return; + } + + /* first we search for cities that overlap */ + city_list_iterate(pplayer->cities, pcity) { + /* no migration out of the capital */ + if (find_palace(city_owner(pcity)) == pcity) { + continue; + } + + /* check only each 5th turn (counted from the funding turn) */ + if (((game.info.turn - pcity->turn_founded) % 5) > 0) { + continue; + } + + /* score of the actual city + * taking into account a persistence factor of 2 */ + score_from = city_score(pcity) * 2; + + freelog(LOG_NORMAL, "[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 square of game.info.migrationdist size */ + square_iterate(pcity->tile, (game.info.migrationdist - 1), ptile) { + acity = tile_city(ptile); + + if (!acity || acity == pcity) { + /* no city or the city in the center */ + continue; + } + + /* distance between the two cities*/ + dist = real_map_distance(pcity->tile, acity->tile); + + /* 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_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); + + 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_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); + } + } 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_NORMAL, "[M] T%d - best city (world): " + "%s (%s) score: %6.3f (> %6.3f)", + game.info.turn, city_name(best_city_world), + player_name(pplayer), + best_city_world_score, score_from); + } + } + } square_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, pcity->tile, 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); + } + + continue; + } + + if (best_city_world_score > 0) { + /* second, do the migration between all nations */ + struct player *pplayer_best_city_world = city_owner(best_city_world); + + if (myrand (100) >= game.info.migrationworld) { + /* no migration */ + notify_player(pplayer, pcity->tile, 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(pplayer_best_city_world)); + } else { + make_city_migration(pplayer, pcity, + pplayer_best_city_world, best_city_world); + } + + continue; + } + + } city_list_iterate_end; + +} diff -ur -X./freeciv-2.1.99svn15387/diff_ignore freeciv-2.1.99svn15387/server/cityturn.h freeciv-2.1.99svn.patch/server/cityturn.h --- freeciv-2.1.99svn15387/server/cityturn.h 2008-12-25 19:45:49.000000000 +0100 +++ freeciv-2.1.99svn.patch/server/cityturn.h 2008-12-30 01:12:01.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.99svn15387/diff_ignore freeciv-2.1.99svn15387/server/savegame.c freeciv-2.1.99svn.patch/server/savegame.c --- freeciv-2.1.99svn15387/server/savegame.c 2008-12-27 17:25:17.000000000 +0100 +++ freeciv-2.1.99svn.patch/server/savegame.c 2008-12-30 19:01:48.000000000 +0100 @@ -4291,6 +4291,15 @@ game.info.allowed_city_names = secfile_lookup_int_default(file, game.info.allowed_city_names, "game.allowed_city_names"); + 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 +4952,9 @@ 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.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.99svn15387/diff_ignore freeciv-2.1.99svn15387/server/settings.c freeciv-2.1.99svn.patch/server/settings.c --- freeciv-2.1.99svn15387/server/settings.c 2008-12-25 19:45:49.000000000 +0100 +++ freeciv-2.1.99svn.patch/server/settings.c 2008-12-30 20:19:29.000000000 +0100 @@ -841,6 +841,34 @@ "on the surrounding terrain."), NULL, GAME_DEFAULT_NATURALCITYNAMES) + 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. " + "Setting this value to 0 will deactivate migration."), + 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.99svn15387/diff_ignore freeciv-2.1.99svn15387/server/srv_main.c freeciv-2.1.99svn.patch/server/srv_main.c --- freeciv-2.1.99svn15387/server/srv_main.c 2008-12-27 17:25:17.000000000 +0100 +++ freeciv-2.1.99svn.patch/server/srv_main.c 2008-12-29 11:51:47.000000000 +0100 @@ -869,6 +869,11 @@ summon_barbarians(); /* wild guess really, no idea where to put it, but I want to give them chance to move their units */ + 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