diff --git a/src/bind_region.c b/src/bind_region.c index 414752cf6..29c7e6893 100644 --- a/src/bind_region.c +++ b/src/bind_region.c @@ -527,7 +527,7 @@ static int tolua_region_get_peasants(lua_State * L) region *self = (region *)tolua_tousertype(L, 1, NULL); if (self) { - lua_pushinteger(L, self->land ? self->land->peasants : 0); + lua_pushinteger(L, rpeasants(self)); return 1; } return 0; @@ -538,7 +538,7 @@ static int tolua_region_set_peasants(lua_State * L) region *self = (region *)tolua_tousertype(L, 1, NULL); if (self && self->land) { - self->land->peasants = lua_tointeger(L, 2); + rsetpeasants(self, lua_tointeger(L, 2)); } return 0; } diff --git a/src/kernel/region.c b/src/kernel/region.c index 3fbcd2533..d7ae32130 100644 --- a/src/kernel/region.c +++ b/src/kernel/region.c @@ -625,7 +625,10 @@ void rsetpeasants(region * r, int value) assert(r->land || value==0); assert(value >= 0); if (r->land) { - r->land->peasants = value; + if (value > USHRT_MAX) { + value = USHRT_MAX; + } + r->land->peasants = (unsigned short)value; } } diff --git a/src/kernel/region.h b/src/kernel/region.h index 9398919b5..6f1afd4ad 100644 --- a/src/kernel/region.h +++ b/src/kernel/region.h @@ -97,12 +97,12 @@ extern "C" { char *display; demand *demands; const struct item_type *herbtype; + unsigned short peasants; + short newpeasants; int herbs; int morale; int trees[3]; /* 0 -> seeds, 1 -> shoots, 2 -> trees */ int horses; - int peasants; - int newpeasants; int money; struct region_owner *ownership; } land_region; diff --git a/src/laws.c b/src/laws.c index c55ec662f..36d914cde 100644 --- a/src/laws.c +++ b/src/laws.c @@ -281,14 +281,13 @@ static void live(region * r) #define MAX_EMIGRATION(p) ((p)/MAXDIRECTIONS) #define MAX_IMMIGRATION(p) ((p)*2/3) -static void calculate_emigration(region * r) +void peasant_migration(region * r) { int i; int maxp = region_maxworkers(r); int rp = rpeasants(r); int max_immigrants = MAX_IMMIGRATION(maxp - rp); - if (volcano_module()) { static int terrain_cache; static const terrain_type *t_volcano; @@ -314,8 +313,14 @@ static void calculate_emigration(region * r) if (max_emigration > 0) { if (max_emigration > max_immigrants) max_emigration = max_immigrants; - r->land->newpeasants += max_emigration; - rc->land->newpeasants -= max_emigration; + if (max_emigration + r->land->newpeasants > USHRT_MAX) { + max_emigration = USHRT_MAX - r->land->newpeasants; + } + if (max_emigration + rc->land->newpeasants > USHRT_MAX) { + max_emigration = USHRT_MAX - rc->land->newpeasants; + } + r->land->newpeasants += (short)max_emigration; + rc->land->newpeasants -= (short)max_emigration; max_immigrants -= max_emigration; } } @@ -779,6 +784,7 @@ void immigration(void) /* FIXME: kann ernsthaft abs(newpeasants) > rpeasants(r) sein? */ if (rp < 0) rp = 0; rsetpeasants(r, rp); + r->land->newpeasants = 0; } /* Genereate some (0-6 depending on the income) peasants out of nothing */ /* if less than 50 are in the region and there is space and no monster or demon units in the region */ @@ -878,7 +884,7 @@ void demographics(void) /* Seuchen erst nachdem die Bauern sich vermehrt haben * und gewandert sind */ - calculate_emigration(r); + peasant_migration(r); peasants(r, peasant_rules); if (r->age > 20) { diff --git a/src/laws.h b/src/laws.h index 8834eff1e..fe423302e 100755 --- a/src/laws.h +++ b/src/laws.h @@ -94,6 +94,7 @@ extern "C" { int reserve_self(struct unit *u, struct order *ord); int claim_cmd(struct unit *u, struct order *ord); void transfer_faction(struct faction *fsrc, struct faction *fdst); + void peasant_migration(struct region * r); void nmr_warnings(void); bool nmr_death(const struct faction * f, int turn, int timeout); diff --git a/src/laws.test.c b/src/laws.test.c index 58a6c9a6e..795656706 100644 --- a/src/laws.test.c +++ b/src/laws.test.c @@ -1931,6 +1931,53 @@ static void test_long_order_on_ocean(CuTest *tc) { test_teardown(); } +static void test_peasant_migration(CuTest *tc) { + region *r1, *r2; + int rmax; + + test_setup(); + config_set("rules.economy.repopulate_maximum", "0"); + r1 = test_create_plain(0, 0); + rsettrees(r1, 0, 0); + rsettrees(r1, 1, 0); + rsettrees(r1, 2, 0); + rmax = region_maxworkers(r1); + r2 = test_create_plain(0, 1); + rsettrees(r2, 0, 0); + rsettrees(r2, 1, 0); + rsettrees(r2, 2, 0); + + rsetpeasants(r1, rmax - 90); + rsetpeasants(r2, rmax); + peasant_migration(r1); + immigration(); + CuAssertIntEquals(tc, rmax - 90, rpeasants(r1)); + CuAssertIntEquals(tc, rmax, rpeasants(r2)); + + rsetpeasants(r1, rmax - 90); + rsetpeasants(r2, rmax + 60); + peasant_migration(r1); + immigration(); + CuAssertIntEquals(tc, rmax - 80, rpeasants(r1)); + CuAssertIntEquals(tc, rmax + 50, rpeasants(r2)); + + rsetpeasants(r1, rmax - 6); /* max 4 immigrants. */ + rsetpeasants(r2, rmax + 60); /* max 10 emigrants. */ + peasant_migration(r1); + immigration(); /* 4 peasants will move */ + CuAssertIntEquals(tc, rmax - 2, rpeasants(r1)); + CuAssertIntEquals(tc, rmax + 56, rpeasants(r2)); + + rsetpeasants(r1, rmax - 6); /* max 4 immigrants. */ + rsetpeasants(r2, rmax + 6); /* max 1 emigrant. */ + peasant_migration(r1); + immigration(); /* 4 peasants will move */ + CuAssertIntEquals(tc, rmax - 5, rpeasants(r1)); + CuAssertIntEquals(tc, rmax + 5, rpeasants(r2)); + + test_teardown(); +} + static void test_quit(CuTest *tc) { faction *f; unit *u; @@ -2177,6 +2224,7 @@ CuSuite *get_laws_suite(void) SUITE_ADD_TEST(suite, test_long_orders); SUITE_ADD_TEST(suite, test_long_order_on_ocean); SUITE_ADD_TEST(suite, test_quit); + SUITE_ADD_TEST(suite, test_peasant_migration); #ifdef QUIT_WITH_TRANSFER SUITE_ADD_TEST(suite, test_quit_transfer); SUITE_ADD_TEST(suite, test_quit_transfer_limited);