From 3c8ff4e76e8a6d6eac16ae0f749daf3f171e0be7 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Sat, 3 Feb 2018 09:58:56 +0100 Subject: [PATCH 1/8] CMAKE_BUILD_TYPE is a cache variable --- s/cmake-init | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/s/cmake-init b/s/cmake-init index 7adbc9a0b..2a3e97fc4 100755 --- a/s/cmake-init +++ b/s/cmake-init @@ -58,7 +58,7 @@ fi cat >| $BUILD/config.cmake < Date: Sat, 3 Feb 2018 12:57:43 +0100 Subject: [PATCH 2/8] optimize sizeof(skill) --- src/kernel/save.c | 41 ++++++++++++++++++++++++----------------- src/kernel/skills.h | 8 ++++---- 2 files changed, 28 insertions(+), 21 deletions(-) diff --git a/src/kernel/save.c b/src/kernel/save.c index 9dc0030e0..607d5c5a8 100644 --- a/src/kernel/save.c +++ b/src/kernel/save.c @@ -321,23 +321,35 @@ static void writeorder(gamedata *data, const struct order *ord, WRITE_STR(data->store, obuf); } +static void read_skill(gamedata *data, skill *sv) { + int val; + READ_INT(data->store, &val); + sv->id = (skill_t)val; + if (sv->id != NOSKILL) { + READ_INT(data->store, &val); + sv->old = sv->level = val; + READ_INT(data->store, &val); + sv->weeks = val; + } +} + static void read_skills(gamedata *data, unit *u) { if (data->version < SKILLSORT_VERSION) { + skill skills[MAXSKILLS], *sv = skills; + size_t sz; + u->skill_size = 0; for (;;) { - int n = NOSKILL, level, weeks; - skill_t sk; - READ_INT(data->store, &n); - sk = (skill_t)n; - if (sk == NOSKILL) break; - READ_INT(data->store, &level); - READ_INT(data->store, &weeks); - if (level) { - skill *sv = add_skill(u, sk); - sv->level = sv->old = (unsigned char)level; - sv->weeks = (unsigned char)weeks; + read_skill(data, sv); + if (sv->id == NOSKILL) break; + if (sv->level > 0) { + ++sv; + ++u->skill_size; } } + sz = u->skill_size * sizeof(skill); + u->skills = malloc(sz); + memcpy(u->skills, skills, sz); } else { int i; @@ -345,12 +357,7 @@ static void read_skills(gamedata *data, unit *u) u->skills = malloc(sizeof(skill)*u->skill_size); for (i = 0; i != u->skill_size; ++i) { skill *sv = u->skills + i; - int val; - READ_INT(data->store, &val); - sv->id = (skill_t)val; - READ_INT(data->store, &sv->level); - sv->old = sv->level; - READ_INT(data->store, &sv->weeks); + read_skill(data, sv); } } } diff --git a/src/kernel/skills.h b/src/kernel/skills.h index 6e8aeb167..7b7cc3f04 100644 --- a/src/kernel/skills.h +++ b/src/kernel/skills.h @@ -26,10 +26,10 @@ extern "C" { #endif typedef struct skill { - skill_t id; - int level; - int weeks; - int old; + skill_t id : 16; + int level : 16; + int weeks : 16; + int old : 16; } skill; typedef int(*skillmod_fun) (const struct unit *, const struct region *, From f1be8caa46b4a59d6d55c41ce396f4e8483593ff Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Sat, 3 Feb 2018 14:16:01 +0100 Subject: [PATCH 3/8] more skill size savings. --- src/kernel/save.c | 21 +++++++++++++++++---- src/kernel/ship.test.c | 3 ++- src/kernel/skills.h | 8 ++++---- src/kernel/unit.c | 1 + src/study.c | 1 + 5 files changed, 25 insertions(+), 9 deletions(-) diff --git a/src/kernel/save.c b/src/kernel/save.c index 607d5c5a8..3843efb12 100644 --- a/src/kernel/save.c +++ b/src/kernel/save.c @@ -324,20 +324,29 @@ static void writeorder(gamedata *data, const struct order *ord, static void read_skill(gamedata *data, skill *sv) { int val; READ_INT(data->store, &val); + assert(val < MAXSKILLS); sv->id = (skill_t)val; if (sv->id != NOSKILL) { READ_INT(data->store, &val); + assert(val < CHAR_MAX); sv->old = sv->level = val; READ_INT(data->store, &val); + assert(val < CHAR_MAX); sv->weeks = val; } } +static int skill_cmp(const void *a, const void *b) { + const skill * sa = (const skill *)a; + const skill * sb = (const skill *)b; + return sa->id - sb->id; +} + static void read_skills(gamedata *data, unit *u) { if (data->version < SKILLSORT_VERSION) { skill skills[MAXSKILLS], *sv = skills; - size_t sz; + u->skill_size = 0; for (;;) { read_skill(data, sv); @@ -347,9 +356,13 @@ static void read_skills(gamedata *data, unit *u) ++u->skill_size; } } - sz = u->skill_size * sizeof(skill); - u->skills = malloc(sz); - memcpy(u->skills, skills, sz); + if (u->skill_size > 0) { + size_t sz = u->skill_size * sizeof(skill); + + qsort(skills, u->skill_size, sizeof(skill), skill_cmp); + u->skills = malloc(sz); + memcpy(u->skills, skills, sz); + } } else { int i; diff --git a/src/kernel/ship.test.c b/src/kernel/ship.test.c index 69766276c..aa4dc5755 100644 --- a/src/kernel/ship.test.c +++ b/src/kernel/ship.test.c @@ -619,7 +619,8 @@ static void test_shipspeed_max_range(CuTest *tc) { CuAssertIntEquals_Msg(tc, "skill bonus from movement.shipspeed.skillbonus", 3, shipspeed(sh, cap)); set_level(cap, SK_SAILING, stype->cptskill + 15); - set_level(crew, SK_SAILING, (stype->sumskill - stype->cptskill) * 15); + scale_number(crew, 15); + set_level(crew, SK_SAILING, stype->sumskill - stype->cptskill); CuAssertIntEquals_Msg(tc, "skill-bonus cannot exceed max_range", 4, shipspeed(sh, cap)); test_teardown(); } diff --git a/src/kernel/skills.h b/src/kernel/skills.h index 7b7cc3f04..649fa92cf 100644 --- a/src/kernel/skills.h +++ b/src/kernel/skills.h @@ -26,10 +26,10 @@ extern "C" { #endif typedef struct skill { - skill_t id : 16; - int level : 16; - int weeks : 16; - int old : 16; + skill_t id : 8; + int level : 8; + int weeks : 8; + int old : 8; } skill; typedef int(*skillmod_fun) (const struct unit *, const struct region *, diff --git a/src/kernel/unit.c b/src/kernel/unit.c index 40e67ebae..367ea4d97 100644 --- a/src/kernel/unit.c +++ b/src/kernel/unit.c @@ -795,6 +795,7 @@ void set_level(unit * u, skill_t sk, int value) skill *sv = u->skills; assert(sk != SK_MAGIC || !u->faction || u->number == 1 || fval(u->faction, FFL_NPC)); + assert(value <= CHAR_MAX && value >= CHAR_MIN); if (!skill_enabled(sk)) return; diff --git a/src/study.c b/src/study.c index f446e34ab..09f228f45 100644 --- a/src/study.c +++ b/src/study.c @@ -828,6 +828,7 @@ void learn_skill(unit *u, skill_t sk, int days) { int leveldays = STUDYDAYS * u->number; int weeks = 0; + assert(sk >= 0 && sk < MAXSKILLS); if (inject_learn_fun) { inject_learn_fun(u, sk, days); return; From ba14fab3a33a7ad73e96fe057e35cf0cb01c6632 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Sat, 3 Feb 2018 14:49:35 +0100 Subject: [PATCH 4/8] macros should have uppercase names. --- src/creport.c | 4 ++-- src/kernel/faction.c | 5 +++-- src/kernel/faction.h | 2 +- src/kernel/save.c | 6 +++--- src/report.c | 10 +++++----- src/reports.c | 4 ++-- 6 files changed, 16 insertions(+), 15 deletions(-) diff --git a/src/creport.c b/src/creport.c index 912011911..fa17c426d 100644 --- a/src/creport.c +++ b/src/creport.c @@ -1568,7 +1568,7 @@ report_computer(const char *filename, report_context * ctx, const char *bom) } fprintf(F, "%d;age\n", f->age); fprintf(F, "%d;Optionen\n", f->options); - if (f->options & want(O_SCORE) && f->age > DISPLAYSCORE) { + if (f->options & WANT_OPTION(O_SCORE) && f->age > DISPLAYSCORE) { char score[32]; write_score(score, sizeof(score), f->score); fprintf(F, "%s;Punkte\n", score); @@ -1615,7 +1615,7 @@ report_computer(const char *filename, report_context * ctx, const char *bom) print_items(F, f->items, f->locale); fputs("OPTIONEN\n", F); for (i = 0; i != MAXOPTIONS; ++i) { - int flag = want(i); + int flag = WANT_OPTION(i); if (options[i]) { fprintf(F, "%d;%s\n", (f->options & flag) ? 1 : 0, options[i]); } diff --git a/src/kernel/faction.c b/src/kernel/faction.c index a31b063b7..90649600f 100755 --- a/src/kernel/faction.c +++ b/src/kernel/faction.c @@ -253,8 +253,9 @@ faction *addfaction(const char *email, const char *password, ADDMSG(&f->msgs, msg_message("changepasswd", "value", password)); f->options = - want(O_REPORT) | want(O_ZUGVORLAGE) | want(O_COMPUTER) | want(O_COMPRESS) | - want(O_ADRESSEN) | want(O_STATISTICS); + WANT_OPTION(O_REPORT) | WANT_OPTION(O_ZUGVORLAGE) | + WANT_OPTION(O_COMPUTER) | WANT_OPTION(O_COMPRESS) | + WANT_OPTION(O_ADRESSEN) | WANT_OPTION(O_STATISTICS); f->no = unused_faction_id(); if (rule_region_owners()) { diff --git a/src/kernel/faction.h b/src/kernel/faction.h index e884c71c6..25913e73d 100644 --- a/src/kernel/faction.h +++ b/src/kernel/faction.h @@ -99,7 +99,7 @@ extern "C" { extern struct faction *factions; -#define want(option) (1<store, &n); f->options = n; - n = want(O_REPORT) | want(O_COMPUTER); + n = WANT_OPTION(O_REPORT) | WANT_OPTION(O_COMPUTER); if ((f->options & n) == 0) { /* Kein Report eingestellt, Fehler */ f->options |= n; } if (data->version < JSON_REPORT_VERSION) { /* mistakes were made in the past*/ - f->options &= ~want(O_JSON); + f->options &= ~WANT_OPTION(O_JSON); } read_allies(data, f); read_groups(data, f); @@ -1139,7 +1139,7 @@ void write_faction(gamedata *data, const faction * f) WRITE_INT(data->store, ur->y); } WRITE_SECTION(data->store); - WRITE_INT(data->store, f->options & ~want(O_DEBUG)); + WRITE_INT(data->store, f->options & ~WANT_OPTION(O_DEBUG)); WRITE_SECTION(data->store); for (sf = f->allies; sf; sf = sf->next) { diff --git a/src/report.c b/src/report.c index 25a92ede2..6543b153b 100644 --- a/src/report.c +++ b/src/report.c @@ -2048,7 +2048,7 @@ report_plaintext(const char *filename, report_context * ctx, attrib *a; message *m; unsigned char op; - int maxh, bytes, ix = want(O_STATISTICS); + int maxh, bytes, ix = WANT_OPTION(O_STATISTICS); int wants_stats = (f->options & ix); FILE *F = fopen(filename, "w"); stream strm = { 0 }, *out = &strm; @@ -2098,18 +2098,18 @@ report_plaintext(const char *filename, report_context * ctx, centre(out, buf, true); } } - if ((f->options & want(O_COMPUTER)) == 0) { + if ((f->options & WANT_OPTION(O_COMPUTER)) == 0) { const char *s; s = locale_getstring(f->locale, "newbie_info_cr"); if (s) { newline(out); centre(out, s, true); } - f->options |= want(O_COMPUTER); + f->options |= WANT_OPTION(O_COMPUTER); } } newline(out); - if (f->options & want(O_SCORE) && f->age > DISPLAYSCORE) { + if (f->options & WANT_OPTION(O_SCORE) && f->age > DISPLAYSCORE) { char score[32], avg[32]; write_score(score, sizeof(score), f->score); write_score(avg, sizeof(avg), average_score_of_age(f->age, f->age / 24 + 1)); @@ -2164,7 +2164,7 @@ report_plaintext(const char *filename, report_context * ctx, if (wrptr(&bufp, &size, bytes) != 0) WARN_STATIC_BUFFER(); for (op = 0; op != MAXOPTIONS; op++) { - if (f->options & want(op) && options[op]) { + if (f->options & WANT_OPTION(op) && options[op]) { bytes = (int)str_strlcpy(bufp, " ", size); if (wrptr(&bufp, &size, bytes) != 0) WARN_STATIC_BUFFER(); diff --git a/src/reports.c b/src/reports.c index b3aee94e0..602edb83c 100644 --- a/src/reports.c +++ b/src/reports.c @@ -928,7 +928,7 @@ spskill(char *buffer, size_t size, const struct locale * lang, if (!u->number) return 0; if (sv->level <= 0) { - if (sv->old <= 0 || (u->faction->options & want(O_SHOWSKCHANGE)) == 0) { + if (sv->old <= 0 || (u->faction->options & WANT_OPTION(O_SHOWSKCHANGE)) == 0) { return 0; } } @@ -964,7 +964,7 @@ spskill(char *buffer, size_t size, const struct locale * lang, if (wrptr(&bufp, &size, snprintf(bufp, size, "%d", effsk)) != 0) WARN_STATIC_BUFFER(); - if (u->faction->options & want(O_SHOWSKCHANGE)) { + if (u->faction->options & WANT_OPTION(O_SHOWSKCHANGE)) { int oldeff = 0; int diff; From 613c0edf2f899b64d8f51b549335880cb1d75098 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Sat, 3 Feb 2018 15:25:03 +0100 Subject: [PATCH 5/8] add most basic test coverage for cmd_loot --- src/economy.c | 1 - src/economy.test.c | 39 ++++++++++++++++++++++++++++++++++----- 2 files changed, 34 insertions(+), 6 deletions(-) diff --git a/src/economy.c b/src/economy.c index b675f0b09..3dacf7c4b 100644 --- a/src/economy.c +++ b/src/economy.c @@ -2534,7 +2534,6 @@ static void expandloot(region * r, econ_request * lootorders) region_set_morale(r, m - 1, -1); } } - for (u = r->units; u; u = u->next) { if (u->n >= 0) { add_income(u, IC_LOOT, u->wants, u->n); diff --git a/src/economy.test.c b/src/economy.test.c index 282c9fc64..545693233 100644 --- a/src/economy.test.c +++ b/src/economy.test.c @@ -312,12 +312,21 @@ static void test_buy_cmd(CuTest *tc) { test_teardown(); } +static void arm_unit(unit *u) { + item_type *it_sword; + + it_sword = test_create_itemtype("sword"); + new_weapontype(it_sword, 0, frac_zero, NULL, 0, 0, 0, SK_MELEE); + i_change(&u->items, it_sword, u->number); + set_level(u, SK_MELEE, 1); +} + static void test_tax_cmd(CuTest *tc) { order *ord; faction *f; region *r; unit *u; - item_type *sword, *silver; + item_type *silver; econ_request *taxorders = 0; test_setup(); @@ -337,10 +346,7 @@ static void test_tax_cmd(CuTest *tc) { silver = get_resourcetype(R_SILVER)->itype; - sword = test_create_itemtype("sword"); - new_weapontype(sword, 0, frac_zero, NULL, 0, 0, 0, SK_MELEE); - i_change(&u->items, sword, 1); - set_level(u, SK_MELEE, 1); + arm_unit(u); tax_cmd(u, ord, &taxorders); CuAssertPtrNotNull(tc, test_find_messagetype(u->faction->msgs, "error_no_tax_skill")); @@ -692,6 +698,28 @@ static void test_modify_production(CuTest *tc) { test_teardown(); } +static void test_loot(CuTest *tc) { + unit *u; + faction *f; + item_type *it_silver; + + test_setup(); + setup_production(); + it_silver = test_create_silver(); + config_set("rules.enable_loot", "1"); + u = test_create_unit(f = test_create_faction(NULL), test_create_region(0, 0, NULL)); + u->thisorder = create_order(K_LOOT, f->locale, NULL); + produce(u->region); + CuAssertPtrNotNull(tc, test_find_messagetype(f->msgs, "error48")); /* unit is unarmed */ + test_clear_messages(f); + arm_unit(u); + produce(u->region); + CuAssertPtrNotNull(tc, test_find_messagetype(f->msgs, "income")); /* unit is unarmed */ + CuAssertIntEquals(tc, 2 * TAXFRACTION, i_get(u->items, it_silver)); + CuAssertIntEquals(tc, UFL_LONGACTION | UFL_NOTMOVING, fval(u, UFL_LONGACTION | UFL_NOTMOVING)); + test_teardown(); +} + CuSuite *get_economy_suite(void) { CuSuite *suite = CuSuiteNew(); @@ -711,5 +739,6 @@ CuSuite *get_economy_suite(void) SUITE_ADD_TEST(suite, test_trade_insect); SUITE_ADD_TEST(suite, test_maintain_buildings); SUITE_ADD_TEST(suite, test_recruit); + SUITE_ADD_TEST(suite, test_loot); return suite; } From e1d33e55a4af3cf7b95ac06801fb6e1d1e241d57 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Sat, 3 Feb 2018 20:24:16 +0100 Subject: [PATCH 6/8] refactor econ_request union for readability. --- src/economy.c | 16 +++++++++------- src/economy.h | 10 +++++++--- src/economy.test.c | 22 ++++++++++++++++++++++ src/steal.c | 6 +++--- 4 files changed, 41 insertions(+), 13 deletions(-) diff --git a/src/economy.c b/src/economy.c index 3dacf7c4b..162ee3d61 100644 --- a/src/economy.c +++ b/src/economy.c @@ -88,7 +88,7 @@ static econ_request entertainers[1024]; static econ_request *nextentertainer; static int entertaining; -static econ_request *g_requests; +static econ_request *g_requests; /* TODO: no need for this to be module-global */ #define RECRUIT_MERGE 1 static int rules_recruit = -1; @@ -181,7 +181,9 @@ unsigned int expand_production(region * r, econ_request * requests, econ_request } while (requests) { econ_request *req = requests->next; - free_order(requests->ord); + if (requests->ord) { + free_order(requests->ord); + } free(requests); requests = req; } @@ -1484,7 +1486,7 @@ static void expandbuying(region * r, econ_request * buyorders) for (j = 0; j != norders; j++) { int price, multi; - ltype = g_requests[j].type.ltype; + ltype = g_requests[j].type.trade.ltype; trade = trades; while (trade->type && trade->type != ltype) ++trade; @@ -1654,7 +1656,7 @@ static void buy(unit * u, econ_request ** buyorders, struct order *ord) return; } o = (econ_request *)calloc(1, sizeof(econ_request)); - o->type.ltype = ltype; /* sollte immer gleich sein */ + o->type.trade.ltype = ltype; /* sollte immer gleich sein */ o->unit = u; o->qty = n; @@ -1758,7 +1760,7 @@ static void expandselling(region * r, econ_request * sellorders, int limit) for (j = 0; j != norders; j++) { const luxury_type *search = NULL; - const luxury_type *ltype = g_requests[j].type.ltype; + const luxury_type *ltype = g_requests[j].type.trade.ltype; int multi = r_demand(r, ltype); int i; int use = 0; @@ -1970,7 +1972,7 @@ static bool sell(unit * u, econ_request ** sellorders, struct order *ord) /* Wenn andere Einheiten das selbe verkaufen, mu� ihr Zeug abgezogen * werden damit es nicht zweimal verkauft wird: */ for (o = *sellorders; o; o = o->next) { - if (o->type.ltype == ltype && o->unit->faction == u->faction) { + if (o->type.trade.ltype == ltype && o->unit->faction == u->faction) { int fpool = o->qty - get_pooled(o->unit, itype->rtype, GET_RESERVE, INT_MAX); if (fpool < 0) fpool = 0; @@ -2010,7 +2012,7 @@ static bool sell(unit * u, econ_request ** sellorders, struct order *ord) o = (econ_request *)calloc(1, sizeof(econ_request)); o->unit = u; o->qty = n; - o->type.ltype = ltype; + o->type.trade.ltype = ltype; addlist(sellorders, o); return unlimited; diff --git a/src/economy.h b/src/economy.h index 2689a654b..47f3e77ec 100644 --- a/src/economy.h +++ b/src/economy.h @@ -51,10 +51,14 @@ extern "C" { struct unit *unit; struct order *ord; int qty; - int no; union { - bool goblin; /* stealing */ - const struct luxury_type *ltype; /* trading */ + struct { + int no; + bool goblin; /* stealing */ + } steal; + struct { + const struct luxury_type *ltype; /* trading */ + } trade; } type; } econ_request; diff --git a/src/economy.test.c b/src/economy.test.c index 545693233..1d9149ff2 100644 --- a/src/economy.test.c +++ b/src/economy.test.c @@ -720,6 +720,27 @@ static void test_loot(CuTest *tc) { test_teardown(); } +static void test_expand_production(CuTest *tc) { + econ_request *orders; + econ_request *results = NULL; + region *r; + unit *u; + + test_setup(); + orders = calloc(1, sizeof(econ_request)); + orders->qty = 2; + orders->unit = u = test_create_unit(test_create_faction(NULL), r = test_create_region(0, 0, NULL)); + orders->next = NULL; + + u->n = 1; /* will be overwritten */ + CuAssertIntEquals(tc, 2, expand_production(r, orders, &results)); + CuAssertPtrNotNull(tc, results); + CuAssertPtrEquals(tc, u, results[0].unit); + CuAssertPtrEquals(tc, u, results[1].unit); + CuAssertIntEquals(tc, 0, u->n); + test_teardown(); +} + CuSuite *get_economy_suite(void) { CuSuite *suite = CuSuiteNew(); @@ -740,5 +761,6 @@ CuSuite *get_economy_suite(void) SUITE_ADD_TEST(suite, test_maintain_buildings); SUITE_ADD_TEST(suite, test_recruit); SUITE_ADD_TEST(suite, test_loot); + SUITE_ADD_TEST(suite, test_expand_production); return suite; } diff --git a/src/steal.c b/src/steal.c index cd2aa9c26..f0b0d03d5 100644 --- a/src/steal.c +++ b/src/steal.c @@ -72,7 +72,7 @@ void expandstealing(region * r, econ_request * stealorders) break; } - u = findunitg(requests[j].no, r); + u = findunitg(requests[j].type.steal.no, r); if (u && u->region == r) { n = get_pooled(u, rsilver, GET_ALL, INT_MAX); @@ -237,8 +237,8 @@ void steal_cmd(unit * u, struct order *ord, econ_request ** stealorders) o = (econ_request *)calloc(1, sizeof(econ_request)); o->unit = u; o->qty = 1; /* Betrag steht in u->wants */ - o->no = u2->no; - o->type.goblin = goblin; /* Merken, wenn Goblin-Spezialklau */ + o->type.steal.no = u2->no; + o->type.steal.goblin = goblin; /* Merken, wenn Goblin-Spezialklau */ o->next = *stealorders; *stealorders = o; From 6f7c8743b3c4f31358985f4e7cabf5c2d0e1a710 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Sat, 3 Feb 2018 20:45:19 +0100 Subject: [PATCH 7/8] remove a lot of struct copying in the stupid expand function. --- src/economy.c | 265 +++++++++++++++++++++++---------------------- src/economy.h | 2 +- src/economy.test.c | 6 +- src/steal.c | 16 +-- 4 files changed, 149 insertions(+), 140 deletions(-) diff --git a/src/economy.c b/src/economy.c index 162ee3d61..62094e5df 100644 --- a/src/economy.c +++ b/src/economy.c @@ -88,7 +88,7 @@ static econ_request entertainers[1024]; static econ_request *nextentertainer; static int entertaining; -static econ_request *g_requests; /* TODO: no need for this to be module-global */ +static econ_request **g_requests; /* TODO: no need for this to be module-global */ #define RECRUIT_MERGE 1 static int rules_recruit = -1; @@ -141,7 +141,7 @@ static void scramble(void *data, unsigned int n, size_t width) } } -unsigned int expand_production(region * r, econ_request * requests, econ_request **results) +unsigned int expand_production(region * r, econ_request * requests, econ_request ***results) { unit *u; econ_request *o; @@ -161,24 +161,28 @@ unsigned int expand_production(region * r, econ_request * requests, econ_request if (norders > 0) { int i = 0; - econ_request *split; - split = (econ_request *)calloc(norders, sizeof(econ_request)); + econ_request **split; + split = calloc(norders, sizeof(econ_request *)); for (o = requests; o; o = o->next) { if (o->qty > 0) { unsigned int j; for (j = o->qty; j; j--) { - split[i] = *o; - split[i].unit->n = 0; + split[i] = o; + o->unit->n = 0; i++; } } } - scramble(split, norders, sizeof(econ_request)); + scramble(split, norders, sizeof(econ_request *)); *results = split; } else { *results = NULL; } + return norders; +} + +static void free_requests(econ_request *requests) { while (requests) { econ_request *req = requests->next; if (requests->ord) { @@ -187,7 +191,6 @@ unsigned int expand_production(region * r, econ_request * requests, econ_request free(requests); requests = req; } - return norders; } static unsigned int expandorders(region * r, econ_request * requests) { @@ -1479,54 +1482,54 @@ static void expandbuying(region * r, econ_request * buyorders) * G�ter pro Monat ist. j sind die Befehle, i der Index des * gehandelten Produktes. */ if (max_products > 0) { - unsigned int j; unsigned int norders = expandorders(r, buyorders); - if (!norders) - return; - for (j = 0; j != norders; j++) { - int price, multi; - ltype = g_requests[j].type.trade.ltype; - trade = trades; - while (trade->type && trade->type != ltype) - ++trade; - multi = trade->multi; - price = ltype->price * multi; + if (norders) { + unsigned int j; + for (j = 0; j != norders; j++) { + int price, multi; + ltype = g_requests[j]->type.trade.ltype; + trade = trades; + while (trade->type && trade->type != ltype) + ++trade; + multi = trade->multi; + price = ltype->price * multi; - if (get_pooled(g_requests[j].unit, rsilver, GET_DEFAULT, - price) >= price) { - item *items; - /* litems z�hlt die G�ter, die verkauft wurden, u->n das Geld, das - * verdient wurde. Dies mu� gemacht werden, weil der Preis st�ndig sinkt, - * man sich also das verdiente Geld und die verkauften Produkte separat - * merken mu�. */ - attrib *a; + if (get_pooled(g_requests[j]->unit, rsilver, GET_DEFAULT, + price) >= price) { + item *items; + /* litems z�hlt die G�ter, die verkauft wurden, u->n das Geld, das + * verdient wurde. Dies mu� gemacht werden, weil der Preis st�ndig sinkt, + * man sich also das verdiente Geld und die verkauften Produkte separat + * merken mu�. */ + attrib *a; - u = g_requests[j].unit; - a = a_find(u->attribs, &at_luxuries); - if (a == NULL) { - a = a_add(&u->attribs, a_new(&at_luxuries)); + u = g_requests[j]->unit; + a = a_find(u->attribs, &at_luxuries); + if (a == NULL) { + a = a_add(&u->attribs, a_new(&at_luxuries)); + } + items = a->data.v; + + i_change(&items, ltype->itype, 1); + a->data.v = items; + i_change(&g_requests[j]->unit->items, ltype->itype, 1); + use_pooled(u, rsilver, GET_DEFAULT, price); + if (u->n < 0) + u->n = 0; + u->n += price; + + rsetmoney(r, rmoney(r) + price); + + /* Falls mehr als max_products Bauern ein Produkt verkauft haben, steigt + * der Preis Multiplikator f�r das Produkt um den Faktor 1. Der Z�hler + * wird wieder auf 0 gesetzt. */ + if (++trade->number == max_products) { + trade->number = 0; + ++trade->multi; + } + fset(u, UFL_LONGACTION | UFL_NOTMOVING); } - items = a->data.v; - - i_change(&items, ltype->itype, 1); - a->data.v = items; - i_change(&g_requests[j].unit->items, ltype->itype, 1); - use_pooled(u, rsilver, GET_DEFAULT, price); - if (u->n < 0) - u->n = 0; - u->n += price; - - rsetmoney(r, rmoney(r) + price); - - /* Falls mehr als max_products Bauern ein Produkt verkauft haben, steigt - * der Preis Multiplikator f�r das Produkt um den Faktor 1. Der Z�hler - * wird wieder auf 0 gesetzt. */ - if (++trade->number == max_products) { - trade->number = 0; - ++trade->multi; - } - fset(u, UFL_LONGACTION | UFL_NOTMOVING); } } free(g_requests); @@ -1754,79 +1757,77 @@ static void expandselling(region * r, econ_request * sellorders, int limit) * Runde erweitert werden kann. */ norders = expandorders(r, sellorders); - if (norders == 0) { - return; - } - - for (j = 0; j != norders; j++) { - const luxury_type *search = NULL; - const luxury_type *ltype = g_requests[j].type.trade.ltype; - int multi = r_demand(r, ltype); - int i; - int use = 0; - for (i = 0, search = luxurytypes; search != ltype; search = search->next) { - /* TODO: this is slow and lame! */ - ++i; - } - if (counter[i] >= limit) - continue; - if (counter[i] + 1 > max_products && multi > 1) - --multi; - price = ltype->price * multi; - - if (money >= price) { - item *itm; - attrib *a; - u = g_requests[j].unit; - a = a_find(u->attribs, &at_luxuries); - if (!a) { - a = a_add(&u->attribs, a_new(&at_luxuries)); - } - itm = (item *)a->data.v; - i_change(&itm, ltype->itype, 1); - a->data.v = itm; - ++use; - if (u->n < 0) { - u->n = 0; + if (norders > 0) { + for (j = 0; j != norders; j++) { + const luxury_type *search = NULL; + const luxury_type *ltype = g_requests[j]->type.trade.ltype; + int multi = r_demand(r, ltype); + int i; + int use = 0; + for (i = 0, search = luxurytypes; search != ltype; search = search->next) { + /* TODO: this is slow and lame! */ + ++i; } + if (counter[i] >= limit) + continue; + if (counter[i] + 1 > max_products && multi > 1) + --multi; + price = ltype->price * multi; - if (hafenowner) { - if (hafenowner->faction != u->faction) { - int abgezogenhafen = price / 10; - hafencollected += abgezogenhafen; - price -= abgezogenhafen; - money -= abgezogenhafen; + if (money >= price) { + item *itm; + attrib *a; + u = g_requests[j]->unit; + a = a_find(u->attribs, &at_luxuries); + if (!a) { + a = a_add(&u->attribs, a_new(&at_luxuries)); + } + itm = (item *)a->data.v; + i_change(&itm, ltype->itype, 1); + a->data.v = itm; + ++use; + if (u->n < 0) { + u->n = 0; + } + + if (hafenowner) { + if (hafenowner->faction != u->faction) { + int abgezogenhafen = price / 10; + hafencollected += abgezogenhafen; + price -= abgezogenhafen; + money -= abgezogenhafen; + } + } + if (maxb) { + if (maxowner->faction != u->faction) { + int abgezogensteuer = price * tax_per_size[maxeffsize] / 100; + taxcollected += abgezogensteuer; + price -= abgezogensteuer; + money -= abgezogensteuer; + } + } + u->n += price; + change_money(u, price); + fset(u, UFL_LONGACTION | UFL_NOTMOVING); + + /* r->money -= price; --- dies wird eben nicht ausgef�hrt, denn die + * Produkte k�nnen auch als Steuern eingetrieben werden. In der Region + * wurden Silberst�cke gegen Luxusg�ter des selben Wertes eingetauscht! + * Falls mehr als max_products Kunden ein Produkt gekauft haben, sinkt + * die Nachfrage f�r das Produkt um 1. Der Z�hler wird wieder auf 0 + * gesetzt. */ + + if (++counter[i] > max_products) { + int d = r_demand(r, ltype); + if (d > 1) { + r_setdemand(r, ltype, d - 1); + } + counter[i] = 0; } } - if (maxb) { - if (maxowner->faction != u->faction) { - int abgezogensteuer = price * tax_per_size[maxeffsize] / 100; - taxcollected += abgezogensteuer; - price -= abgezogensteuer; - money -= abgezogensteuer; - } + if (use > 0) { + use_pooled(g_requests[j]->unit, ltype->itype->rtype, GET_DEFAULT, use); } - u->n += price; - change_money(u, price); - fset(u, UFL_LONGACTION | UFL_NOTMOVING); - - /* r->money -= price; --- dies wird eben nicht ausgef�hrt, denn die - * Produkte k�nnen auch als Steuern eingetrieben werden. In der Region - * wurden Silberst�cke gegen Luxusg�ter des selben Wertes eingetauscht! - * Falls mehr als max_products Kunden ein Produkt gekauft haben, sinkt - * die Nachfrage f�r das Produkt um 1. Der Z�hler wird wieder auf 0 - * gesetzt. */ - - if (++counter[i] > max_products) { - int d = r_demand(r, ltype); - if (d > 1) { - r_setdemand(r, ltype, d - 1); - } - counter[i] = 0; - } - } - if (use > 0) { - use_pooled(g_requests[j].unit, ltype->itype->rtype, GET_DEFAULT, use); } } free(g_requests); @@ -2520,8 +2521,8 @@ static void expandloot(region * r, econ_request * lootorders) int startmoney = rmoney(r); for (i = 0; i != norders && startmoney > looted + TAXFRACTION * 2; i++) { - change_money(g_requests[i].unit, TAXFRACTION); - g_requests[i].unit->n += TAXFRACTION; + change_money(g_requests[i]->unit, TAXFRACTION); + g_requests[i]->unit->n += TAXFRACTION; /*Looting destroys double the money*/ looted += TAXFRACTION * 2; } @@ -2554,8 +2555,8 @@ void expandtax(region * r, econ_request * taxorders) if (norders > 0) { unsigned int i; for (i = 0; i != norders && rmoney(r) > TAXFRACTION; i++) { - change_money(g_requests[i].unit, TAXFRACTION); - g_requests[i].unit->n += TAXFRACTION; + change_money(g_requests[i]->unit, TAXFRACTION); + g_requests[i]->unit->n += TAXFRACTION; rsetmoney(r, rmoney(r) - TAXFRACTION); } free(g_requests); @@ -2938,18 +2939,23 @@ void produce(struct region *r) if (!rule_autowork()) { expandwork(r, workers, nextworker, region_maxworkers(r)); } - if (taxorders) + if (taxorders) { expandtax(r, taxorders); + free_requests(taxorders); + } - if (lootorders) + if (lootorders) { expandloot(r, lootorders); - + free_requests(lootorders); + } /* An erster Stelle Kaufen (expandbuying), die Bauern so Geld bekommen, um * nachher zu beim Verkaufen (expandselling) den Spielern abkaufen zu * k�nnen. */ - if (buyorders) + if (buyorders) { expandbuying(r, buyorders); + free_requests(buyorders); + } if (sellorders) { int limit = rpeasants(r) / TRADE_FRACTION; @@ -2957,13 +2963,16 @@ void produce(struct region *r) && buildingtype_exists(r, caravan_bt, true)) limit *= 2; expandselling(r, sellorders, limited ? limit : INT_MAX); + free_requests(sellorders); } /* Die Spieler sollen alles Geld verdienen, bevor sie beklaut werden * (expandstealing). */ - if (stealorders) + if (stealorders) { expandstealing(r, stealorders); + free_requests(stealorders); + } assert(rmoney(r) >= 0); assert(rpeasants(r) >= 0); diff --git a/src/economy.h b/src/economy.h index 47f3e77ec..99558bf80 100644 --- a/src/economy.h +++ b/src/economy.h @@ -69,7 +69,7 @@ extern "C" { void produce(struct region *r); void auto_work(struct region *r); - unsigned int expand_production(struct region * r, struct econ_request * requests, struct econ_request **results); + unsigned int expand_production(struct region * r, struct econ_request * requests, struct econ_request ***results); typedef enum income_t { IC_WORK, IC_ENTERTAIN, IC_TAX, IC_TRADE, IC_TRADETAX, IC_STEAL, IC_MAGIC, IC_LOOT } income_t; void add_income(struct unit * u, income_t type, int want, int qty); diff --git a/src/economy.test.c b/src/economy.test.c index 1d9149ff2..d4322fef7 100644 --- a/src/economy.test.c +++ b/src/economy.test.c @@ -722,7 +722,7 @@ static void test_loot(CuTest *tc) { static void test_expand_production(CuTest *tc) { econ_request *orders; - econ_request *results = NULL; + econ_request **results = NULL; region *r; unit *u; @@ -735,8 +735,8 @@ static void test_expand_production(CuTest *tc) { u->n = 1; /* will be overwritten */ CuAssertIntEquals(tc, 2, expand_production(r, orders, &results)); CuAssertPtrNotNull(tc, results); - CuAssertPtrEquals(tc, u, results[0].unit); - CuAssertPtrEquals(tc, u, results[1].unit); + CuAssertPtrEquals(tc, u, results[0]->unit); + CuAssertPtrEquals(tc, u, results[1]->unit); CuAssertIntEquals(tc, 0, u->n); test_teardown(); } diff --git a/src/steal.c b/src/steal.c index f0b0d03d5..65316f1dd 100644 --- a/src/steal.c +++ b/src/steal.c @@ -51,7 +51,7 @@ void expandstealing(region * r, econ_request * stealorders) const resource_type *rsilver = get_resourcetype(R_SILVER); unsigned int j; unsigned int norders; - econ_request *requests; + econ_request **requests; assert(rsilver); @@ -68,11 +68,11 @@ void expandstealing(region * r, econ_request * stealorders) unit *u; int n = 0; - if (requests[j].unit->n > requests[j].unit->wants) { + if (requests[j]->unit->n > requests[j]->unit->wants) { break; } - u = findunitg(requests[j].type.steal.no, r); + u = findunitg(requests[j]->type.steal.no, r); if (u && u->region == r) { n = get_pooled(u, rsilver, GET_ALL, INT_MAX); @@ -82,16 +82,16 @@ void expandstealing(region * r, econ_request * stealorders) n = 10; } if (n > 0) { - int w = requests[j].unit->wants; + int w = requests[j]->unit->wants; if (n > w) n = w; use_pooled(u, rsilver, GET_ALL, n); - requests[j].unit->n = n; - change_money(requests[j].unit, n); + requests[j]->unit->n = n; + change_money(requests[j]->unit, n); ADDMSG(&u->faction->msgs, msg_message("stealeffect", "unit region amount", u, u->region, n)); } - add_income(requests[j].unit, IC_STEAL, requests[j].unit->wants, requests[j].unit->n); - fset(requests[j].unit, UFL_LONGACTION | UFL_NOTMOVING); + add_income(requests[j]->unit, IC_STEAL, requests[j]->unit->wants, requests[j]->unit->n); + fset(requests[j]->unit, UFL_LONGACTION | UFL_NOTMOVING); } free(requests); } From 5b61f895a2f6dddb1667fdd53175720a9334d917 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Sat, 3 Feb 2018 20:52:24 +0100 Subject: [PATCH 8/8] further reduce teh amount of temporary storage required by the economy module. --- src/economy.c | 8 ++------ src/economy.h | 4 +++- 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/src/economy.c b/src/economy.c index 62094e5df..82890888e 100644 --- a/src/economy.c +++ b/src/economy.c @@ -185,9 +185,6 @@ unsigned int expand_production(region * r, econ_request * requests, econ_request static void free_requests(econ_request *requests) { while (requests) { econ_request *req = requests->next; - if (requests->ord) { - free_order(requests->ord); - } free(requests); requests = req; } @@ -347,7 +344,7 @@ static int do_recruiting(recruitment * recruits, int available) if (number > afford) number = afford; } if (u->number + number > UNIT_MAXSIZE) { - ADDMSG(&u->faction->msgs, msg_feedback(u, req->ord, "error_unit_size", + ADDMSG(&u->faction->msgs, msg_feedback(u, req->type.recruit.ord, "error_unit_size", "maxsize", UNIT_MAXSIZE)); number = UNIT_MAXSIZE - u->number; assert(number >= 0); @@ -382,7 +379,6 @@ void free_recruitments(recruitment * recruits) while (rec->requests) { econ_request *req = rec->requests; rec->requests = req->next; - free_order(req->ord); free(req); } free(rec); @@ -560,7 +556,7 @@ static void recruit(unit * u, struct order *ord, econ_request ** recruitorders) o = (econ_request *)calloc(1, sizeof(econ_request)); o->qty = n; o->unit = u; - o->ord = copy_order(ord); + o->type.recruit.ord = ord; addlist(recruitorders, o); } diff --git a/src/economy.h b/src/economy.h index 99558bf80..ec12ae0ca 100644 --- a/src/economy.h +++ b/src/economy.h @@ -49,9 +49,11 @@ extern "C" { typedef struct econ_request { struct econ_request *next; struct unit *unit; - struct order *ord; int qty; union { + struct { + struct order *ord; + } recruit; struct { int no; bool goblin; /* stealing */