diff --git a/res/core/messages.xml b/res/core/messages.xml
index d983fe455..171c99b47 100644
--- a/res/core/messages.xml
+++ b/res/core/messages.xml
@@ -3658,6 +3658,13 @@
"$unit($unit): '$order($command)' - The unit already uses $resource($using,0)."
"$unit($unit): '$order($command)' - The unit already uses $resource($using,0)."
+
+
+
+
+ "$if($eq($births,1),"Einen Bauern","$int($births) Bauern") besucht unverhofft der Storch."
+ "The stork paid an unexpected visit to $if($eq($births,1),"a peasant","$int($births) peasants")."
+
diff --git a/src/laws.c b/src/laws.c
index d09f16c81..753ce0b8f 100755
--- a/src/laws.c
+++ b/src/laws.c
@@ -258,7 +258,58 @@ static void calculate_emigration(region * r)
}
}
-/** Bauern vermehren sich */
+
+static float peasant_growth_factor(void)
+{
+ return get_param_flt(global.parameters, "rules.peasants.growth.factor", 0.0001F * PEASANTGROWTH);
+}
+
+#ifdef SLOWLUCK
+int peasant_luck_effect(int peasants, int luck, int maxp, float variance) {
+ int n, births=0;
+ float factor = peasant_growth_factor();
+ for (n = peasants; n && luck; --n) {
+ int chances = 0;
+
+ if (luck > 0) {
+ --luck;
+ chances += PEASANTLUCK;
+ }
+
+ while (chances--) {
+ if (rng_double() < factor) {
+ /* Only raise with 75% chance if peasants have
+ * reached 90% of maxpopulation */
+ if (peasants / (float)maxp < 0.9 || chance(PEASANTFORCE)) {
+ ++births;
+ }
+ }
+ }
+ }
+ return births;
+}
+#else
+static float peasant_luck_factor(void)
+{
+ return get_param_flt(global.parameters, "rules.peasants.peasantluck.factor", PEASANTLUCK);
+}
+
+int peasant_luck_effect(int peasants, int luck, int maxp, float variance)
+{
+ int births = 0;
+ double mean = _min(luck, peasants) * peasant_luck_factor()
+ * peasant_growth_factor() * ((peasants / (float)maxp < .9) ? 1 :
+ PEASANTFORCE);
+
+ births = RAND_ROUND(normalvariate(mean, variance * mean));
+ if (births <= 0)
+ births = 1;
+ if (births > peasants / 2)
+ births = peasants / 2 + 1;
+ return births;
+}
+
+#endif
static void peasants(region * r)
{
@@ -268,42 +319,20 @@ static void peasants(region * r)
int n, satiated;
int dead = 0;
- /* Bis zu 1000 Bauern können Zwillinge bekommen oder 1000 Bauern
- * wollen nicht! */
-
if (peasants > 0 && get_param_int(global.parameters, "rules.peasants.growth", 1)) {
- int glueck = 0;
- double fraction = peasants * 0.0001F * PEASANTGROWTH;
- int births = (int)fraction;
+ int luck = 0;
+ double fraction = peasants * peasant_growth_factor();
+ int births = RAND_ROUND(fraction);
attrib *a = a_find(r->attribs, &at_peasantluck);
- if (rng_double() < (fraction - births)) {
- /* because we don't want regions that never grow pga. rounding. */
- ++births;
- }
if (a != NULL) {
- glueck = a->data.i * 1000;
+ luck = a->data.i * 1000;
}
- for (n = peasants; n; --n) {
- int chances = 0;
+ luck = peasant_luck_effect(peasants, luck, maxp, .5);
+ ADDMSG(&r->msgs, msg_message("peasantluck_success", "births", luck));
- if (glueck > 0) {
- --glueck;
- chances += PEASANTLUCK;
- }
-
- while (chances--) {
- if (rng_int() % 10000 < PEASANTGROWTH) {
- /* Only raise with 75% chance if peasants have
- * reached 90% of maxpopulation */
- if (peasants / (float)maxp < 0.9 || chance(PEASANTFORCE)) {
- ++births;
- }
- }
- }
- }
- peasants += births;
+ peasants += births + luck;
}
/* Alle werden satt, oder halt soviele für die es auch Geld gibt */
diff --git a/src/laws.h b/src/laws.h
index f1862a61a..3e9c44013 100755
--- a/src/laws.h
+++ b/src/laws.h
@@ -106,7 +106,7 @@ extern "C" {
const struct unit *u, int modifier);
int armedmen(const struct unit *u, bool siege_weapons);
void force_leave(struct region *r);
-
+ int peasant_luck_effect(int peasants, int luck, int maxp, float variance);
#ifdef __cplusplus
}
diff --git a/src/laws.test.c b/src/laws.test.c
index 2b2f0bb9f..7524e6267 100644
--- a/src/laws.test.c
+++ b/src/laws.test.c
@@ -16,6 +16,7 @@
#include
#include
#include
+#include
#include
#include
@@ -691,6 +692,32 @@ static void test_reserve_self(CuTest *tc) {
test_cleanup();
}
+static void statistic_test(CuTest *tc, int peasants, int luck, int maxp,
+ float variance, int min_value, int max_value)
+{
+ int effect, i;
+ for (i = 0; i < 1000; ++i) {
+ effect = peasant_luck_effect(peasants, luck, maxp, variance);
+ CuAssertTrue(tc, min_value <= effect);
+ CuAssertTrue(tc, max_value >= effect);
+ }
+}
+
+static void test_peasant_luck_effect(CuTest *tc)
+{
+
+ set_param(&global.parameters, "rules.peasants.peasantluck.factor", "10");
+ set_param(&global.parameters, "rules.peasants.growth.factor", "0.001");
+
+ statistic_test(tc, 100, 2, 1000, 0, 1, 1);
+ statistic_test(tc, 1000, 400, 1000, 0, (int)(400 * 10 * 0.001 * .75),
+ (int)(400 * 10 * 0.001 * .75));
+ statistic_test(tc, 1000, 1000, 2000, .5f, 1, 501);
+
+ set_param(&global.parameters, "rules.peasants.growth.factor", "1");
+ statistic_test(tc, 1000, 1000, 1000, 0, 501, 501);
+}
+
CuSuite *get_laws_suite(void)
{
CuSuite *suite = CuSuiteNew();
@@ -721,6 +748,7 @@ CuSuite *get_laws_suite(void)
SUITE_ADD_TEST(suite, test_force_leave_buildings);
SUITE_ADD_TEST(suite, test_force_leave_ships);
SUITE_ADD_TEST(suite, test_force_leave_ships_on_ocean);
+ SUITE_ADD_TEST(suite, test_peasant_luck_effect);
return suite;
}
diff --git a/src/settings.h b/src/settings.h
index e211293b8..81f9f7074 100644
--- a/src/settings.h
+++ b/src/settings.h
@@ -8,7 +8,7 @@
This program may not be used, modified or distributed
without prior permission by the authors of Eressea.
-*/
+ */
/*
* Contains defines for the "free" game (Eressea) .
@@ -25,9 +25,9 @@
/* Vermehrungsrate Bauern in 1/10000.
* TODO: Evt. Berechnungsfehler, reale Vermehrungsraten scheinen höher. */
-#define PEASANTGROWTH 10
+#define PEASANTGROWTH 10
#define BATTLE_KILLS_PEASANTS 20
-#define PEASANTLUCK 10
+#define PEASANTLUCK 10
#define ROW_FACTOR 3 /* factor for combat row advancement rule */
diff --git a/src/test_eressea.c b/src/test_eressea.c
index ca6ebf604..ccbac8463 100644
--- a/src/test_eressea.c
+++ b/src/test_eressea.c
@@ -53,6 +53,7 @@ int RunAllTests(void)
RUN_TESTS(suite, umlaut);
RUN_TESTS(suite, unicode);
RUN_TESTS(suite, strings);
+ RUN_TESTS(suite, rng);
/* kernel */
RUN_TESTS(suite, alliance);
RUN_TESTS(suite, unit);
diff --git a/src/util/CMakeLists.txt b/src/util/CMakeLists.txt
index a08046ae2..249b1c61c 100644
--- a/src/util/CMakeLists.txt
+++ b/src/util/CMakeLists.txt
@@ -9,6 +9,7 @@ bsdstring.test.c
functions.test.c
umlaut.test.c
unicode.test.c
+rng.test.c
)
SET(_FILES
diff --git a/src/util/rng.h b/src/util/rng.h
index 32dbcaeab..2e8e5affb 100644
--- a/src/util/rng.h
+++ b/src/util/rng.h
@@ -39,6 +39,7 @@ extern "C" {
# define rng_double ((rand()%RAND_MAX)/(double)RAND_MAX)
# define RNG_RAND_MAX RAND_MAX
#endif
+#define RAND_ROUND(fractional) ((rng_double() < fractional-(int)fractional)?((int)fractional+1):((int)fractional))
#ifdef __cplusplus
}
#endif
diff --git a/src/util/rng.test.c b/src/util/rng.test.c
new file mode 100644
index 000000000..1740368fb
--- /dev/null
+++ b/src/util/rng.test.c
@@ -0,0 +1,26 @@
+#include
+#include
+
+#include "rng.h"
+
+static void test_rng_round(CuTest * tc)
+{
+ double f;
+ int i, r;
+ for (i = 0; i < 1000; ++i) {
+ f = rng_double();
+ r = RAND_ROUND(f);
+ CuAssertTrue(tc, f >= 0);
+ CuAssertTrue(tc, r <= (int ) f + 1);
+ CuAssertTrue(tc, r >= (int ) f);
+ CuAssertTrue(tc, r == (int ) r);
+ CuAssertTrue(tc, r == RAND_ROUND(r));
+ }
+}
+
+CuSuite *get_rng_suite(void)
+{
+ CuSuite *suite = CuSuiteNew();
+ SUITE_ADD_TEST(suite, test_rng_round);
+ return suite;
+}