Refactor the wage function for readability.

Add a test for wages at different castle sizes.
This commit is contained in:
Enno Rehling 2020-09-16 18:53:35 +02:00
parent 7af2735b7f
commit 44ac1d5573
10 changed files with 147 additions and 58 deletions

View File

@ -1363,9 +1363,11 @@ static void cr_output_region(FILE * F, report_context * ctx, region * r)
fprintf(F, "%d;Rekruten\n", rpeasants(r) / RECRUITFRACTION);
}
if (max_production(r)) {
int p_wage = wage(r, NULL, NULL, turn + 1);
/* Im CR steht der Bauernlohn, der bei Trauer nur 10 ist */
bool mourn = is_mourning(r, turn);
int p_wage = peasant_wage(r, mourn);
fprintf(F, "%d;Lohn\n", p_wage);
if (is_mourning(r, turn + 1)) {
if (mourn) {
fputs("1;mourning\n", F);
}
}

View File

@ -1993,7 +1993,8 @@ expandwork(region * r, econ_request * work_begin, econ_request * work_end, int m
/* n: verbleibende Einnahmen */
/* fishes: maximale Arbeiter */
int jobs = maxwork;
int p_wage = wage(r, NULL, NULL, turn);
bool mourn = is_mourning(r, turn);
int p_wage = peasant_wage(r, mourn);
int money = rmoney(r);
if (total > 0 && !rule_autowork()) {
econ_request *o;
@ -2017,7 +2018,7 @@ expandwork(region * r, econ_request * work_begin, econ_request * work_end, int m
assert(workers >= 0);
u->n = workers * wage(u->region, u->faction, u_race(u), turn);
u->n = workers * wage(u->region, u_race(u));
jobs -= workers;
assert(jobs >= 0);
@ -2061,7 +2062,7 @@ static int work_cmd(unit * u, order * ord, econ_request ** io_req)
}
return 0;
}
w = wage(r, u->faction, u_race(u), turn);
w = wage(r, u_race(u));
add_request(req++, ECON_WORK, u, ord, w * u->number);
*io_req = req;
return u->number;

View File

@ -495,20 +495,22 @@ extern struct attrib_type at_icastle;
/** returns the building's build stage (NOT size in people).
* only makes sense for castles or similar buildings with multiple
* stages */
int buildingeffsize(const building * b, int img)
int buildingeffsize(const building * b, bool imaginary)
{
const struct building_type *btype = NULL;
if (b == NULL)
return 0;
btype = b->type;
if (img) {
if (imaginary) {
const attrib *a = a_find(b->attribs, &at_icastle);
if (a) {
btype = (const struct building_type *)a->data.v;
}
}
else {
btype = b->type;
}
return bt_effsize(btype, b, b->size);
}
@ -518,7 +520,7 @@ int bt_effsize(const building_type * btype, const building * b, int bsize)
bsize = adjust_size(b, bsize);
}
if (btype->stages) {
if (btype && btype->stages) {
int n = 0;
const building_stage *stage = btype->stages;
do {
@ -728,7 +730,7 @@ static const int wagetable[7][3] = {
};
static int
default_wage(const region * r, const faction * f, const race * rc, int in_turn)
default_wage(const region * r, const race * rc)
{
building *b = largestbuilding(r, cmp_wage, false);
int esize = 0;
@ -739,34 +741,32 @@ default_wage(const region * r, const faction * f, const race * rc, int in_turn)
esize = buildingeffsize(b, false);
}
if (f != NULL) {
if (rc != NULL) {
static const struct race *rc_orc, *rc_snotling;
static int rc_cache;
int index = 0;
if (rc == get_race(RC_ORC) || rc == get_race(RC_SNOTLING)) {
if (rc_changed(&rc_cache)) {
rc_orc = get_race(RC_ORC);
rc_snotling = get_race(RC_SNOTLING);
}
if (rc == rc_orc || rc == rc_snotling) {
index = 1;
}
wage = wagetable[esize][index];
}
else {
if (is_mourning(r, in_turn)) {
wage = 10;
}
else if (fval(r->terrain, SEA_REGION)) {
wage = 11;
}
else {
wage = wagetable[esize][2];
}
if (r->attribs && rule_blessed_harvest() == HARVEST_WORK) {
/* E1 rules */
wage += harvest_effect(r);
}
wage = wagetable[esize][2];
}
if (r->attribs) {
attrib *a;
curse *c;
variant vm;
if (rule_blessed_harvest() & HARVEST_WORK) {
/* In E3 */
wage += harvest_effect(r);
}
/* Godcurse: Income -10 */
vm = frac_make(wage, 1);
@ -786,31 +786,37 @@ default_wage(const region * r, const faction * f, const race * rc, int in_turn)
}
static int
minimum_wage(const region * r, const faction * f, const race * rc, int in_turn)
minimum_wage(const region * r, const race * rc)
{
if (f && rc) {
if (rc) {
return rc->maintenance;
}
return default_wage(r, f, rc, in_turn);
return default_wage(r, rc);
}
/**
* Gibt Arbeitslohn fuer entsprechende Rasse zurueck, oder fuer
* die Bauern wenn f == NULL. */
int wage(const region * r, const faction * f, const race * rc, int in_turn)
* die Bauern wenn rc == NULL. */
int wage(const region * r, const race * rc)
{
static int config;
static int rule_wage;
if (config_changed(&config)) {
rule_wage = config_get_int("rules.wage.function", 1);
}
if (rule_wage==0) {
if (rule_wage == 0) {
return 0;
}
if (rule_wage==1) {
return default_wage(r, f, rc, in_turn);
if (rule_wage == 1) {
return default_wage(r, rc);
}
return minimum_wage(r, f, rc, in_turn);
return minimum_wage(r, rc);
}
int peasant_wage(const struct region *r, bool mourn)
{
return mourn ? 10 : wage(r, NULL);
}
int cmp_wage(const struct building *b, const building * a)

View File

@ -116,8 +116,8 @@ extern "C" {
int id, int size, struct order *ord);
bool building_finished(const struct building *b);
int wage(const struct region *r, const struct faction *f,
const struct race *rc, int in_turn);
int wage(const struct region *r, const struct race *rc);
int peasant_wage(const struct region *r, bool mourn);
typedef int(*cmp_building_cb) (const struct building * b,
const struct building * a);
@ -130,7 +130,7 @@ extern "C" {
int building_taxes(const building *b);
/* old functions, still in build.c: */
int buildingeffsize(const building * b, int imaginary);
int buildingeffsize(const building * b, bool imaginary);
void bhash(struct building *b);
void bunhash(struct building *b);
int buildingcapacity(const struct building *b);

View File

@ -434,6 +434,80 @@ static void test_cmp_castle_size(CuTest *tc) {
test_teardown();
}
static void test_wage(CuTest *tc) {
region *r;
building *b;
building_type *btype;
struct building_stage *stage;
race *rc_orc, *rc_elf;
test_setup();
rc_orc = test_create_race("orc");
rc_elf = test_create_race("elf");
rc_elf->maintenance = 13;
btype = test_create_buildingtype("castle");
stage = btype->stages;
stage->construction->maxsize = 2; /* site */
stage = stage->next = calloc(1, sizeof(struct building_stage));
stage->construction = calloc(1, sizeof(struct construction));
stage->construction->maxsize = 8; /* tradepost */
stage = stage->next = calloc(1, sizeof(struct building_stage));
stage->construction = calloc(1, sizeof(struct construction));
stage->construction->maxsize = 40; /* fortification */
stage = stage->next = calloc(1, sizeof(struct building_stage));
stage->construction = calloc(1, sizeof(struct construction));
stage->construction->maxsize = 200; /* fortification */
r = test_create_plain(0, 0);
CuAssertIntEquals(tc, 10, wage(r, rc_elf));
CuAssertIntEquals(tc, 10, wage(r, rc_orc));
CuAssertIntEquals(tc, 11, peasant_wage(r, false));
CuAssertIntEquals(tc, 10, peasant_wage(r, true));
b = test_create_building(r, btype);
b->size = 1;
CuAssertIntEquals(tc, 0, buildingeffsize(b, false));
CuAssertIntEquals(tc, 10, wage(r, rc_elf));
CuAssertIntEquals(tc, 10, wage(r, rc_orc));
CuAssertIntEquals(tc, 11, peasant_wage(r, false));
CuAssertIntEquals(tc, 10, peasant_wage(r, true));
b->size = 2;
CuAssertIntEquals(tc, 1, buildingeffsize(b, false));
b->size = 9;
CuAssertIntEquals(tc, 1, buildingeffsize(b, false));
CuAssertIntEquals(tc, 10, wage(r, rc_elf));
CuAssertIntEquals(tc, 10, wage(r, rc_orc));
CuAssertIntEquals(tc, 11, peasant_wage(r, false));
CuAssertIntEquals(tc, 10, peasant_wage(r, true));
b->size = 10;
CuAssertIntEquals(tc, 2, buildingeffsize(b, false));
b->size = 49;
CuAssertIntEquals(tc, 2, buildingeffsize(b, false));
CuAssertIntEquals(tc, 11, wage(r, rc_elf));
CuAssertIntEquals(tc, 11, wage(r, rc_orc));
CuAssertIntEquals(tc, 12, peasant_wage(r, false));
CuAssertIntEquals(tc, 10, peasant_wage(r, true));
b->size = 50;
CuAssertIntEquals(tc, 3, buildingeffsize(b, false));
b->size = 249;
CuAssertIntEquals(tc, 3, buildingeffsize(b, false));
CuAssertIntEquals(tc, 12, wage(r, rc_elf));
CuAssertIntEquals(tc, 11, wage(r, rc_orc));
CuAssertIntEquals(tc, 13, peasant_wage(r, false));
CuAssertIntEquals(tc, 10, peasant_wage(r, true));
b->size = 250;
CuAssertIntEquals(tc, 4, buildingeffsize(b, false));
CuAssertIntEquals(tc, 13, wage(r, rc_elf));
CuAssertIntEquals(tc, 12, wage(r, rc_orc));
CuAssertIntEquals(tc, 14, peasant_wage(r, false));
CuAssertIntEquals(tc, 10, peasant_wage(r, true));
config_set_int("rules.wage.function", 1);
CuAssertIntEquals(tc, 13, wage(r, rc_elf));
config_set_int("rules.wage.function", 0);
CuAssertIntEquals(tc, 0, wage(r, rc_elf));
config_set_int("rules.wage.function", 2);
CuAssertIntEquals(tc, rc_elf->maintenance, wage(r, rc_elf));
test_teardown();
}
static void test_cmp_wage(CuTest *tc) {
region *r;
building *b1, *b2;
@ -619,6 +693,7 @@ CuSuite *get_building_suite(void)
SUITE_ADD_TEST(suite, test_cmp_castle_size);
SUITE_ADD_TEST(suite, test_cmp_taxes);
SUITE_ADD_TEST(suite, test_cmp_wage);
SUITE_ADD_TEST(suite, test_wage);
SUITE_ADD_TEST(suite, test_cmp_current_owner);
SUITE_ADD_TEST(suite, test_register_building);
SUITE_ADD_TEST(suite, test_btype_defaults);

View File

@ -42,7 +42,7 @@ extern "C" {
bool rule_stealth_anon(void); /* units can anonymize their faction, TARNE PARTEI [NICHT] */
int rule_alliance_limit(void);
int rule_faction_limit(void);
#define HARVEST_WORK 0x00
#define HARVEST_WORK 0x02
#define HARVEST_TAXES 0x01
int rule_blessed_harvest(void);
#define GIVE_SELF 1

View File

@ -602,7 +602,7 @@ int rpeasants(const region * r)
return value;
}
void rsetpeasants(region * r, int value)
int rsetpeasants(region * r, int value)
{
assert(r->land || value==0);
assert(value >= 0);
@ -612,7 +612,9 @@ void rsetpeasants(region * r, int value)
value = USHRT_MAX;
}
r->land->peasants = (unsigned short)value;
return r->land->peasants;
}
return 0;
}
int rmoney(const region * r)
@ -746,17 +748,16 @@ int rsettrees(const region * r, int ageclass, int value)
{
if (!r->land) {
assert(value == 0);
return 0;
}
assert(value >= 0);
if (value < MAXTREES) {
r->land->trees[ageclass] = value;
}
else {
assert(value >= 0);
if (value <= MAXTREES) {
return r->land->trees[ageclass] = value;
}
else {
r->land->trees[ageclass] = MAXTREES;
}
r->land->trees[ageclass] = MAXTREES;
}
return 0;
return r->land->trees[ageclass];
}
region *region_create(int uid)
@ -1095,11 +1096,10 @@ void init_region(region *r)
if (!fval(r, RF_CHAOTIC)) {
int peasants;
int p_wage = 1 + peasant_wage(r, false) + rng_int() % 5;
peasants = (region_maxworkers(r) * (20 + dice(6, 10))) / 100;
if (peasants < 100) peasants = 100;
rsetpeasants(r, peasants);
rsetmoney(r, rpeasants(r) * ((wage(r, NULL, NULL,
INT_MAX) + 1) + rng_int() % 5));
rsetmoney(r, rsetpeasants(r, peasants) * p_wage);
}
}

View File

@ -176,7 +176,7 @@ extern "C" {
int rsettrees(const struct region *r, int ageclass, int value);
int rpeasants(const struct region *r);
void rsetpeasants(struct region *r, int value);
int rsetpeasants(struct region *r, int value);
int rmoney(const struct region *r);
void rsetmoney(struct region *r, int value);
int rhorses(const struct region *r);

View File

@ -743,7 +743,8 @@ void immigration(void)
/* if less than 50 are in the region and there is space and no monster or demon units in the region */
if (repopulate) {
int peasants = rpeasants(r);
int income = wage(r, NULL, NULL, turn) - maintenance_cost(NULL) + 1;
bool mourn = is_mourning(r, turn);
int income = peasant_wage(r, mourn) - maintenance_cost(NULL) + 1;
if (income >= 0 && r->land && (peasants < repopulate) && region_maxworkers(r) >(peasants + 30) * 2) {
int badunit = 0;
unit *u;
@ -754,7 +755,7 @@ void immigration(void)
}
}
if (badunit == 0) {
peasants += (int)(rng_double()*income);
peasants += (int)(rng_double() * income);
rsetpeasants(r, peasants);
}
}
@ -834,8 +835,10 @@ void demographics(void)
if (r->age > 20) {
double mwp = fmax(region_maxworkers(r), 1);
bool mourn = is_mourning(r, turn);
int p_wage = peasant_wage(r, mourn);
double prob =
pow(rpeasants(r) / (mwp * wage(r, NULL, NULL, turn) * 0.13), 4.0)
pow(rpeasants(r) / (mwp * p_wage * 0.13), 4.0)
* PLAGUE_CHANCE;
if (rng_double() < prob) {

View File

@ -1182,11 +1182,13 @@ static void report_statistics(struct stream *out, const region * r, const factio
if (max_production(r) && (!fval(r->terrain, SEA_REGION)
|| f->race == get_race(RC_AQUARIAN))) {
if (markets_module()) { /* hack */
bool mourn = is_mourning(r, turn);
int p_wage = peasant_wage(r, mourn);
m =
msg_message("nr_stat_salary_new", "max", wage(r, NULL, NULL, turn + 1));
msg_message("nr_stat_salary_new", "max", p_wage);
}
else {
m = msg_message("nr_stat_salary", "max", wage(r, f, f->race, turn + 1));
m = msg_message("nr_stat_salary", "max", wage(r, f->race));
}
nr_render(m, f->locale, buf, sizeof(buf), f);
paragraph(out, buf, 2, 2, 0);
@ -1337,7 +1339,7 @@ report_template(const char *filename, report_context * ctx, const char *bom)
}
rps_nowrap(out, buf);
newline(out);
sprintf(buf, "; ECheck Lohn %d", wage(r, f, f->race, turn + 1));
sprintf(buf, "; ECheck Lohn %d", wage(r, f->race));
rps_nowrap(out, buf);
newline(out);
newline(out);