From 551f349309178ce469ff5c9064e3702267dac85d Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Sat, 28 Oct 2017 19:46:17 +0200 Subject: [PATCH 01/21] begin work on 3.15 release --- src/kernel/version.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/kernel/version.c b/src/kernel/version.c index 65cbeb110..c7d757773 100644 --- a/src/kernel/version.c +++ b/src/kernel/version.c @@ -5,7 +5,7 @@ #ifndef ERESSEA_VERSION /* the version number, if it was not passed to make with -D */ -#define ERESSEA_VERSION "3.14.0" +#define ERESSEA_VERSION "3.15.0" #endif const char *eressea_version(void) { From 1866b95e14a317fed27f9125650760861448afc9 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Sun, 29 Oct 2017 18:03:44 +0100 Subject: [PATCH 02/21] BUG 2381: parse_token overrun. --- src/util/parser.c | 8 ++++++-- src/util/parser.test.c | 10 ++++++++++ 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/src/util/parser.c b/src/util/parser.c index fca066cb1..46a9d3a28 100644 --- a/src/util/parser.c +++ b/src/util/parser.c @@ -177,11 +177,15 @@ char *parse_token(const char **str, char *lbuf, size_t buflen) ++ctoken; } else { - *cursor++ = *ctoken++; + if (cursor - buflen < lbuf - len) { + *cursor++ = *ctoken++; + } } } else if (utf8_character == SPACE_REPLACEMENT) { - *cursor++ = ' '; + if (cursor - buflen < lbuf - len) { + *cursor++ = ' '; + } ++ctoken; } else if (utf8_character == ESCAPE_CHAR) { diff --git a/src/util/parser.test.c b/src/util/parser.test.c index 942aa1866..7690a01b4 100644 --- a/src/util/parser.test.c +++ b/src/util/parser.test.c @@ -28,6 +28,15 @@ static void test_parse_token(CuTest *tc) { CuAssertPtrEquals(tc, NULL, (void *)tok); } +static void test_parse_token_bug_2381(CuTest *tc) { + const char *stok, *s = "Bitte~wechselt~auf~die~trireme~3im9,~sobald~eine~Crew~da~ist,~geht~es~los~:)"; + char token[64]; + + stok = s; + stok = parse_token(&stok, token, sizeof(token)); + CuAssertTrue(tc, strlen(token) < sizeof(token)); +} + static void test_parse_token_limit(CuTest *tc) { char lbuf[8]; const char *tok; @@ -117,6 +126,7 @@ CuSuite *get_parser_suite(void) SUITE_ADD_TEST(suite, test_atoip); SUITE_ADD_TEST(suite, test_skip_token); SUITE_ADD_TEST(suite, test_parse_token); + SUITE_ADD_TEST(suite, test_parse_token_bug_2381); SUITE_ADD_TEST(suite, test_parse_token_limit); SUITE_ADD_TEST(suite, test_parse_token_limit_utf8); SUITE_ADD_TEST(suite, test_gettoken); From 5af5daa3550c800e5fb517966a15fe10519d4183 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Sun, 29 Oct 2017 18:55:43 +0100 Subject: [PATCH 03/21] BUG 2378: Fix magic armor resistance calculation. Use frac_one constant where applicable. --- src/battle.c | 3 ++- src/items/weapons.c | 2 +- src/kernel/build.c | 2 +- src/volcano.c | 4 ++-- 4 files changed, 6 insertions(+), 5 deletions(-) diff --git a/src/battle.c b/src/battle.c index a63caa291..52d0456ad 100644 --- a/src/battle.c +++ b/src/battle.c @@ -1141,7 +1141,7 @@ terminate(troop dt, troop at, int type, const char *damage, bool missile) const weapon_type *dwtype = NULL; const weapon_type *awtype = NULL; const weapon *weapon; - variant res = frac_make(1, 1); + variant res = frac_one; int rda, sk = 0, sd; bool magic = false; @@ -1185,6 +1185,7 @@ terminate(troop dt, troop at, int type, const char *damage, bool missile) } if (magic) { + res = frac_sub(frac_one, res); res = frac_mul(frac_make(da, 1), res); da = res.sa[0] / res.sa[1]; } diff --git a/src/items/weapons.c b/src/items/weapons.c index acb47f0e0..53721bca6 100644 --- a/src/items/weapons.c +++ b/src/items/weapons.c @@ -76,7 +76,7 @@ int *casualties) killed += terminate(dt, *at, AT_SPELL, damage, 1); } } while (force && killed < enemies); - if (casualties) + if (killed > 0 && casualties) *casualties = killed; return true; } diff --git a/src/kernel/build.c b/src/kernel/build.c index 1f4e143df..81a6a90c8 100644 --- a/src/kernel/build.c +++ b/src/kernel/build.c @@ -405,7 +405,7 @@ static int required(int size, int msize, int maxneed) static int matmod(const unit * u, const resource_type * rtype, int value) { if (rtype->modifiers) { - variant save = frac_make(1, 1); + variant save = frac_one; const struct building_type *btype = NULL; const struct race *rc = u_race(u); resource_mod *mod; diff --git a/src/volcano.c b/src/volcano.c index db7166de0..c912bc0df 100644 --- a/src/volcano.c +++ b/src/volcano.c @@ -106,8 +106,8 @@ damage_unit(unit * u, const char *dam, bool physical, bool magic) int damage = dice_rand(dam); if (magic) { variant magres = magic_resistance(u); - magres = frac_sub(frac_make(1, 1), magres); - damage = damage * magres.sa[0] / magres.sa[1]; + int save = magres.sa[0] / magres.sa[1]; + damage -= damage * save; } if (physical) { damage -= nb_armor(u, i); From 0277e10c8d1e1569b1e42519035967c59f43d365 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Sun, 29 Oct 2017 18:03:44 +0100 Subject: [PATCH 04/21] BUG 2381: parse_token overrun. --- src/util/parser.c | 8 ++++++-- src/util/parser.test.c | 10 ++++++++++ 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/src/util/parser.c b/src/util/parser.c index fca066cb1..46a9d3a28 100644 --- a/src/util/parser.c +++ b/src/util/parser.c @@ -177,11 +177,15 @@ char *parse_token(const char **str, char *lbuf, size_t buflen) ++ctoken; } else { - *cursor++ = *ctoken++; + if (cursor - buflen < lbuf - len) { + *cursor++ = *ctoken++; + } } } else if (utf8_character == SPACE_REPLACEMENT) { - *cursor++ = ' '; + if (cursor - buflen < lbuf - len) { + *cursor++ = ' '; + } ++ctoken; } else if (utf8_character == ESCAPE_CHAR) { diff --git a/src/util/parser.test.c b/src/util/parser.test.c index 942aa1866..7690a01b4 100644 --- a/src/util/parser.test.c +++ b/src/util/parser.test.c @@ -28,6 +28,15 @@ static void test_parse_token(CuTest *tc) { CuAssertPtrEquals(tc, NULL, (void *)tok); } +static void test_parse_token_bug_2381(CuTest *tc) { + const char *stok, *s = "Bitte~wechselt~auf~die~trireme~3im9,~sobald~eine~Crew~da~ist,~geht~es~los~:)"; + char token[64]; + + stok = s; + stok = parse_token(&stok, token, sizeof(token)); + CuAssertTrue(tc, strlen(token) < sizeof(token)); +} + static void test_parse_token_limit(CuTest *tc) { char lbuf[8]; const char *tok; @@ -117,6 +126,7 @@ CuSuite *get_parser_suite(void) SUITE_ADD_TEST(suite, test_atoip); SUITE_ADD_TEST(suite, test_skip_token); SUITE_ADD_TEST(suite, test_parse_token); + SUITE_ADD_TEST(suite, test_parse_token_bug_2381); SUITE_ADD_TEST(suite, test_parse_token_limit); SUITE_ADD_TEST(suite, test_parse_token_limit_utf8); SUITE_ADD_TEST(suite, test_gettoken); From 35742e88703f12b4ee9e510763d618f7dc3b9a9c Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Sat, 21 Oct 2017 10:44:07 +0200 Subject: [PATCH 05/21] BUG 2376: Abtreiben zeigt immer Nordwesten an. --- src/main.c | 18 +++++++++--------- src/move.c | 28 ++++++++++++++-------------- src/move.h | 2 +- src/move.test.c | 4 ++-- 4 files changed, 26 insertions(+), 26 deletions(-) diff --git a/src/main.c b/src/main.c index eedb25cf1..0c171f219 100644 --- a/src/main.c +++ b/src/main.c @@ -101,10 +101,11 @@ static dictionary *parse_config(const char *filename) if (cfgpath) { join_path(cfgpath, filename, path, sizeof(path)); log_debug("reading from configuration file %s\n", path); - d = iniparser_load(path); - } else { + d = iniparser_load(path); + } + else { log_debug("reading from configuration file %s\n", filename); - d = iniparser_load(filename); + d = iniparser_load(filename); } if (d) { config_set_from(d, valid_keys); @@ -168,8 +169,7 @@ static int verbosity_to_flags(int verbosity) { static int parse_args(int argc, char **argv) { int i; - int log_stderr = LOG_CPERROR; - int log_flags = LOG_CPERROR | LOG_CPWARNING | LOG_CPINFO; + int log_stderr, log_flags = 2; for (i = 1; i != argc; ++i) { char *argi = argv[i]; @@ -179,9 +179,9 @@ static int parse_args(int argc, char **argv) else if (argi[1] == '-') { /* long format */ if (strcmp(argi + 2, "version") == 0) { printf("Eressea version %s, " - "Copyright (C) 2017 Enno Rehling et al.\n", + "Copyright (C) 2017 Enno Rehling et al.\n", eressea_version()); - return 1; + return 1; #ifdef USE_CURSES } else if (strcmp(argi + 2, "color") == 0) { @@ -300,8 +300,8 @@ int main(int argc, char **argv) setup_signal_handler(); /* parse arguments again, to override ini file */ err = parse_args(argc, argv); - if (err!=0) { - return (err>0) ? 0 : err; + if (err != 0) { + return (err > 0) ? 0 : err; } d = parse_config(inifile); if (!d) { diff --git a/src/move.c b/src/move.c index de2906843..8bf3ee1e0 100644 --- a/src/move.c +++ b/src/move.c @@ -787,22 +787,22 @@ static void msg_to_ship_inmates(ship *sh, unit **firstu, unit **lastu, message * msg_release(msg); } -region * drift_target(ship *sh) { - int d, d_offset = rng_int() % MAXDIRECTIONS; - region *rnext = NULL; +direction_t drift_target(ship *sh) { + direction_t d, dir = rng_int() % MAXDIRECTIONS; + direction_t result = NODIRECTION; for (d = 0; d != MAXDIRECTIONS; ++d) { region *rn; - direction_t dir = (direction_t)((d + d_offset) % MAXDIRECTIONS); - rn = rconnect(sh->region, dir); + direction_t dn = (direction_t)((d + dir) % MAXDIRECTIONS); + rn = rconnect(sh->region, dn); if (rn != NULL && check_ship_allowed(sh, rn) >= 0) { - rnext = rn; - if (!fval(rnext->terrain, SEA_REGION)) { + result = dn; + if (!fval(rn->terrain, SEA_REGION)) { /* prefer drifting towards non-ocean regions */ break; } } } - return rnext; + return result; } static void drifting_ships(region * r) @@ -817,7 +817,7 @@ static void drifting_ships(region * r) region *rnext = NULL; region_list *route = NULL; unit *firstu = r->units, *lastu = NULL, *captain; - direction_t dir = 0; + direction_t dir = NODIRECTION; double ovl; if (sh->type->fishing > 0) { @@ -846,13 +846,13 @@ static void drifting_ships(region * r) } ovl = overload(r, sh); - if (ovl >= overload_start()) { - rnext = NULL; - } - else { + if (ovl < overload_start()) { /* Auswahl einer Richtung: Zuerst auf Land, dann * zufällig. Falls unmögliches Resultat: vergiß es. */ - rnext = drift_target(sh); + dir = drift_target(sh); + if (dir != NODIRECTION) { + rnext = rconnect(sh->region, dir); + } } if (rnext != NULL) { diff --git a/src/move.h b/src/move.h index 4b9c75749..535c76bb2 100644 --- a/src/move.h +++ b/src/move.h @@ -94,7 +94,7 @@ extern "C" { #define SA_NO_COAST -2 int check_ship_allowed(struct ship *sh, const struct region * r); - struct region * drift_target(struct ship *sh); + direction_t drift_target(struct ship *sh); #ifdef __cplusplus } #endif diff --git a/src/move.test.c b/src/move.test.c index c8fdb2436..76940a667 100644 --- a/src/move.test.c +++ b/src/move.test.c @@ -487,9 +487,9 @@ static void test_drifting_ships(CuTest *tc) { r2 = test_create_region(1, 0, t_ocean); st_boat = test_create_shiptype("boat"); sh = test_create_ship(r1, st_boat); - CuAssertPtrEquals(tc, r2, drift_target(sh)); + CuAssertIntEquals(tc, D_EAST, drift_target(sh)); r3 = test_create_region(-1, 0, t_plain); - CuAssertPtrEquals(tc, r3, drift_target(sh)); + CuAssertIntEquals(tc, D_WEST, drift_target(sh)); test_cleanup(); } From 9c24fe4b0771a7b5ede2b5f5f13a40e505e2f813 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Mon, 30 Oct 2017 18:12:24 +0100 Subject: [PATCH 06/21] fix gcc build --- src/move.test.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/move.test.c b/src/move.test.c index 76940a667..d5be5c3f5 100644 --- a/src/move.test.c +++ b/src/move.test.c @@ -477,18 +477,18 @@ static void test_follow_ship_msg(CuTest * tc) { static void test_drifting_ships(CuTest *tc) { ship *sh; - region *r1, *r2, *r3; + region *r; terrain_type *t_ocean, *t_plain; ship_type *st_boat; test_setup(); t_ocean = test_create_terrain("ocean", SEA_REGION); t_plain = test_create_terrain("plain", LAND_REGION); - r1 = test_create_region(0, 0, t_ocean); - r2 = test_create_region(1, 0, t_ocean); + r = test_create_region(0, 0, t_ocean); + test_create_region(1, 0, t_ocean); st_boat = test_create_shiptype("boat"); - sh = test_create_ship(r1, st_boat); + sh = test_create_ship(r, st_boat); CuAssertIntEquals(tc, D_EAST, drift_target(sh)); - r3 = test_create_region(-1, 0, t_plain); + test_create_region(-1, 0, t_plain); CuAssertIntEquals(tc, D_WEST, drift_target(sh)); test_cleanup(); } From a17c8ada71d89fdd29e1523181282df9fb2f0a57 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Sat, 4 Nov 2017 20:10:05 +0100 Subject: [PATCH 07/21] Add a test for the happy case of the BUY command. --- src/economy.test.c | 54 +++++++++++++++++++++++++++++++++++++++++++++ src/kernel/item.h | 3 +-- src/kernel/region.c | 2 +- 3 files changed, 56 insertions(+), 3 deletions(-) diff --git a/src/economy.test.c b/src/economy.test.c index 83c103f7f..c7083ea4c 100644 --- a/src/economy.test.c +++ b/src/economy.test.c @@ -170,6 +170,59 @@ static void test_normals_recruit(CuTest * tc) { test_cleanup(); } +static void test_buy_cmd(CuTest *tc) { + region * r; + unit *u; + building *b; + const resource_type *rt_silver; + const resource_type *rt_luxury; + test_setup(); + + init_resources(); + rt_luxury = get_resourcetype(R_HORSE); + CuAssertPtrNotNull(tc, rt_luxury); + CuAssertPtrNotNull(tc, rt_luxury->itype); + new_luxurytype(rt_luxury->itype, 5); + CuAssertPtrNotNull(tc, rt_luxury->ltype); + rt_silver = get_resourcetype(R_SILVER); + CuAssertPtrNotNull(tc, rt_silver); + CuAssertPtrNotNull(tc, rt_silver->itype); + + r = test_create_region(0, 0, NULL); + fix_demand(r); + CuAssertPtrEquals(tc, rt_luxury->itype, (void *)r_luxury(r)); + u = test_create_unit(test_create_faction(NULL), r); + unit_addorder(u, create_order(K_BUY, u->faction->locale, "1 %s", LOC(u->faction->locale, resourcename(rt_luxury, 0)))); + set_item(u, rt_silver->itype, 1000); + + produce(r); + CuAssertPtrNotNullMsg(tc, "trading requires a castle", test_find_messagetype(u->faction->msgs, "error119")); + test_clear_messages(u->faction); + freset(u, UFL_LONGACTION); + + b = test_create_building(r, test_create_buildingtype("castle")); + produce(r); + CuAssertPtrNotNullMsg(tc, "castle must have size >=2", test_find_messagetype(u->faction->msgs, "error119")); + test_clear_messages(u->faction); + freset(u, UFL_LONGACTION); + + b->size = 2; + produce(r); + CuAssertPtrEquals(tc, NULL, test_find_messagetype(u->faction->msgs, "error119")); + CuAssertPtrNotNullMsg(tc, "traders need SK_TRADE skill", test_find_messagetype(u->faction->msgs, "error102")); + test_clear_messages(u->faction); + freset(u, UFL_LONGACTION); + + /* at last, the happy case: */ + set_level(u, SK_TRADE, 1); + produce(r); + CuAssertPtrNotNull(tc, test_find_messagetype(u->faction->msgs, "buy")); + CuAssertPtrNotNull(tc, test_find_messagetype(u->faction->msgs, "buyamount")); + CuAssertIntEquals(tc, 1, get_item(u, rt_luxury->itype)); + CuAssertIntEquals(tc, 995, get_item(u, rt_silver->itype)); + test_cleanup(); +} + typedef struct request { struct request *next; struct unit *unit; @@ -568,6 +621,7 @@ CuSuite *get_economy_suite(void) SUITE_ADD_TEST(suite, test_normals_recruit); SUITE_ADD_TEST(suite, test_heroes_dont_recruit); SUITE_ADD_TEST(suite, test_tax_cmd); + SUITE_ADD_TEST(suite, test_buy_cmd); SUITE_ADD_TEST(suite, test_maintain_buildings); SUITE_ADD_TEST(suite, test_recruit); return suite; diff --git a/src/kernel/item.h b/src/kernel/item.h index 51ebcd2a1..6477a4923 100644 --- a/src/kernel/item.h +++ b/src/kernel/item.h @@ -224,7 +224,7 @@ extern "C" { /* convenience: */ item *i_change(item ** items, const item_type * it, int delta); - int i_get(const item * i, const item_type * it); + int i_get(const item * items, const item_type * it); /* creation */ resource_type *rt_get_or_create(const char *name); @@ -300,7 +300,6 @@ extern "C" { void register_resources(void); void init_resources(void); - void init_itemtypes(void); void register_item_give(int(*foo) (struct unit *, struct unit *, const struct item_type *, int, struct order *), const char *name); diff --git a/src/kernel/region.c b/src/kernel/region.c index c7e3841fb..3dad8e3ab 100644 --- a/src/kernel/region.c +++ b/src/kernel/region.c @@ -711,7 +711,7 @@ const item_type *r_luxury(const region * r) { struct demand *dmd; if (r->land) { - assert(r->land->demands || !"need to call fix_demands on a region"); + assert(r->land->demands || !"need to call fix_demand on a region"); for (dmd = r->land->demands; dmd; dmd = dmd->next) { if (dmd->value == 0) return dmd->type->itype; From 12646f726ab13e6e112fe50607d8b1fa84b9fb8b Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Sun, 5 Nov 2017 15:11:02 +0100 Subject: [PATCH 08/21] Add a failing test for bug 2379. --- src/economy.c | 21 +++++++---------- src/economy.test.c | 55 +++++++++++++++++++++++++++++++++++++++++++++ src/util/language.c | 3 --- 3 files changed, 63 insertions(+), 16 deletions(-) diff --git a/src/economy.c b/src/economy.c index 7c4b0efd3..3781e0e8e 100644 --- a/src/economy.c +++ b/src/economy.c @@ -1446,24 +1446,19 @@ static void expandbuying(region * r, request * buyorders) const resource_type *rsilver = get_resourcetype(R_SILVER); int max_products; unit *u; - static struct trade { + struct trade { const luxury_type *type; int number; int multi; } trades[MAXLUXURIES], *trade; - static int ntrades = 0; - int i; + int ntrades = 0; const luxury_type *ltype; - if (ntrades == 0) { - for (ntrades = 0, ltype = luxurytypes; ltype; ltype = ltype->next) { - assert(ntrades < MAXLUXURIES); - trades[ntrades++].type = ltype; - } - } - for (i = 0; i != ntrades; ++i) { - trades[i].number = 0; - trades[i].multi = 1; + for (ntrades = 0, ltype = luxurytypes; ltype; ltype = ltype->next) { + assert(ntrades < MAXLUXURIES); + trades[ntrades].number = 0; + trades[ntrades].multi = 1; + trades[ntrades++].type = ltype; } if (!buyorders) @@ -1490,7 +1485,7 @@ static void expandbuying(region * r, request * buyorders) int price, multi; ltype = g_requests[j].type.ltype; trade = trades; - while (trade->type != ltype) + while (trade->type && trade->type != ltype) ++trade; multi = trade->multi; price = ltype->price * multi; diff --git a/src/economy.test.c b/src/economy.test.c index c7083ea4c..5f3ac3828 100644 --- a/src/economy.test.c +++ b/src/economy.test.c @@ -170,6 +170,60 @@ static void test_normals_recruit(CuTest * tc) { test_cleanup(); } +static region *setup_trade_region(CuTest *tc, const struct terrain_type *terrain) { + region *r; + item_type *it_luxury; + struct locale * lang = default_locale; + + new_luxurytype(it_luxury = test_create_itemtype("jewel"), 5); + locale_setstring(lang, it_luxury->rtype->_name, it_luxury->rtype->_name); + CuAssertStrEquals(tc, it_luxury->rtype->_name, LOC(lang, resourcename(it_luxury->rtype, 0))); + + new_luxurytype(it_luxury = test_create_itemtype("balm"), 5); + locale_setstring(lang, it_luxury->rtype->_name, it_luxury->rtype->_name); + CuAssertStrEquals(tc, it_luxury->rtype->_name, LOC(lang, resourcename(it_luxury->rtype, 0))); + + r = test_create_region(0, 0, terrain); + return r; +} + +static unit *setup_trade_unit(CuTest *tc, region *r, const struct race *rc) { + unit *u; + + UNUSED_ARG(tc); + u = test_create_unit(test_create_faction(rc), r); + set_level(u, SK_TRADE, 2); + return u; +} + +static void test_trade_insect(CuTest *tc) { + /* Insekten können in Wüsten und Sümpfen auch ohne Burgen handeln. */ + unit *u; + region *r; + const item_type *it_luxury; + const item_type *it_silver; + struct locale *lang; + + test_setup(); + init_resources(); + + lang = test_create_locale(); + it_silver = get_resourcetype(R_SILVER)->itype; + + r = setup_trade_region(tc, get_terrain("swamp")); + it_luxury = r_luxury(r); + CuAssertPtrNotNull(tc, it_luxury); + + u = setup_trade_unit(tc, r, test_create_race("insect")); + unit_addorder(u, create_order(K_BUY, u->faction->locale, "1 %s", + LOC(u->faction->locale, resourcename(it_luxury->rtype, 0)))); + + set_item(u, it_silver, 10); + produce(u->region); + CuAssertIntEquals(tc, 1, get_item(u, it_luxury)); + CuAssertIntEquals(tc, 5, get_item(u, it_silver)); +} + static void test_buy_cmd(CuTest *tc) { region * r; unit *u; @@ -622,6 +676,7 @@ CuSuite *get_economy_suite(void) SUITE_ADD_TEST(suite, test_heroes_dont_recruit); SUITE_ADD_TEST(suite, test_tax_cmd); SUITE_ADD_TEST(suite, test_buy_cmd); + SUITE_ADD_TEST(suite, test_trade_insect); SUITE_ADD_TEST(suite, test_maintain_buildings); SUITE_ADD_TEST(suite, test_recruit); return suite; diff --git a/src/util/language.c b/src/util/language.c index b3cce61af..a1cda4d2f 100644 --- a/src/util/language.c +++ b/src/util/language.c @@ -45,9 +45,6 @@ typedef struct locale { struct locale_str *strings[SMAXHASH]; } locale; -extern locale *default_locale; -extern locale *locales; - locale *default_locale; locale *locales; From 3fdde8a4aa584c574747863d6438fdcd988f1e75 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Sun, 5 Nov 2017 15:14:54 +0100 Subject: [PATCH 09/21] refactor original trade test to use shared setup function. --- src/economy.test.c | 26 ++++++++++---------------- 1 file changed, 10 insertions(+), 16 deletions(-) diff --git a/src/economy.test.c b/src/economy.test.c index 5f3ac3828..481758891 100644 --- a/src/economy.test.c +++ b/src/economy.test.c @@ -202,17 +202,15 @@ static void test_trade_insect(CuTest *tc) { region *r; const item_type *it_luxury; const item_type *it_silver; - struct locale *lang; test_setup(); init_resources(); - - lang = test_create_locale(); - it_silver = get_resourcetype(R_SILVER)->itype; + test_create_locale(); r = setup_trade_region(tc, get_terrain("swamp")); it_luxury = r_luxury(r); CuAssertPtrNotNull(tc, it_luxury); + it_silver = get_resourcetype(R_SILVER)->itype; u = setup_trade_unit(tc, r, test_create_race("insect")); unit_addorder(u, create_order(K_BUY, u->faction->locale, "1 %s", @@ -229,24 +227,20 @@ static void test_buy_cmd(CuTest *tc) { unit *u; building *b; const resource_type *rt_silver; - const resource_type *rt_luxury; + const item_type *it_luxury; test_setup(); - init_resources(); - rt_luxury = get_resourcetype(R_HORSE); - CuAssertPtrNotNull(tc, rt_luxury); - CuAssertPtrNotNull(tc, rt_luxury->itype); - new_luxurytype(rt_luxury->itype, 5); - CuAssertPtrNotNull(tc, rt_luxury->ltype); + test_create_locale(); + + r = setup_trade_region(tc, get_terrain("swamp")); + it_luxury = r_luxury(r); + CuAssertPtrNotNull(tc, it_luxury); rt_silver = get_resourcetype(R_SILVER); CuAssertPtrNotNull(tc, rt_silver); CuAssertPtrNotNull(tc, rt_silver->itype); - r = test_create_region(0, 0, NULL); - fix_demand(r); - CuAssertPtrEquals(tc, rt_luxury->itype, (void *)r_luxury(r)); u = test_create_unit(test_create_faction(NULL), r); - unit_addorder(u, create_order(K_BUY, u->faction->locale, "1 %s", LOC(u->faction->locale, resourcename(rt_luxury, 0)))); + unit_addorder(u, create_order(K_BUY, u->faction->locale, "1 %s", LOC(u->faction->locale, resourcename(it_luxury->rtype, 0)))); set_item(u, rt_silver->itype, 1000); produce(r); @@ -272,7 +266,7 @@ static void test_buy_cmd(CuTest *tc) { produce(r); CuAssertPtrNotNull(tc, test_find_messagetype(u->faction->msgs, "buy")); CuAssertPtrNotNull(tc, test_find_messagetype(u->faction->msgs, "buyamount")); - CuAssertIntEquals(tc, 1, get_item(u, rt_luxury->itype)); + CuAssertIntEquals(tc, 1, get_item(u, it_luxury)); CuAssertIntEquals(tc, 995, get_item(u, rt_silver->itype)); test_cleanup(); } From 2b81334ba2b8a3dd584ad457ac9ad754c07cf5f7 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Sun, 5 Nov 2017 16:43:01 +0100 Subject: [PATCH 10/21] use the correct swamp terrain, still failing. newterrain is a plague. --- src/economy.test.c | 7 +++++-- src/kernel/terrain.c | 4 ++++ src/tests.c | 16 ++++++++-------- 3 files changed, 17 insertions(+), 10 deletions(-) diff --git a/src/economy.test.c b/src/economy.test.c index 481758891..460ebb5fb 100644 --- a/src/economy.test.c +++ b/src/economy.test.c @@ -206,8 +206,9 @@ static void test_trade_insect(CuTest *tc) { test_setup(); init_resources(); test_create_locale(); + r = setup_trade_region(tc, test_create_terrain("swamp", LAND_REGION)); + init_terrains(); - r = setup_trade_region(tc, get_terrain("swamp")); it_luxury = r_luxury(r); CuAssertPtrNotNull(tc, it_luxury); it_silver = get_resourcetype(R_SILVER)->itype; @@ -220,6 +221,7 @@ static void test_trade_insect(CuTest *tc) { produce(u->region); CuAssertIntEquals(tc, 1, get_item(u, it_luxury)); CuAssertIntEquals(tc, 5, get_item(u, it_silver)); + test_cleanup(); } static void test_buy_cmd(CuTest *tc) { @@ -231,8 +233,9 @@ static void test_buy_cmd(CuTest *tc) { test_setup(); init_resources(); test_create_locale(); + r = setup_trade_region(tc, test_create_terrain("swamp", LAND_REGION)); + init_terrains(); - r = setup_trade_region(tc, get_terrain("swamp")); it_luxury = r_luxury(r); CuAssertPtrNotNull(tc, it_luxury); rt_silver = get_resourcetype(R_SILVER); diff --git a/src/kernel/terrain.c b/src/kernel/terrain.c index e9f448f97..8c7ab8878 100644 --- a/src/kernel/terrain.c +++ b/src/kernel/terrain.c @@ -132,6 +132,10 @@ const struct terrain_type *newterrain(terrain_t t) return NULL; assert(t >= 0); assert(t < MAXTERRAINS); + if (!newterrains[t]) { + log_warning("did you call init_terrains?"); + newterrains[t] = get_terrain(terraindata[t]); + } return newterrains[t]; } diff --git a/src/tests.c b/src/tests.c index 770d2853c..d07124af3 100644 --- a/src/tests.c +++ b/src/tests.c @@ -122,10 +122,10 @@ struct locale * test_create_locale(void) { for (i = 0; i != MAXDIRECTIONS; ++i) { locale_setstring(loc, directions[i], directions[i]); init_direction(loc, i, directions[i]); - init_direction(loc, i, coasts[i]+7); + init_direction(loc, i, coasts[i] + 7); } for (i = 0; i <= ST_FLEE; ++i) { - locale_setstring(loc, combatstatus[i], combatstatus[i]+7); + locale_setstring(loc, combatstatus[i], combatstatus[i] + 7); } for (i = 0; i != MAXKEYWORDS; ++i) { locale_setstring(loc, mkname("keyword", keywords[i]), keywords[i]); @@ -446,10 +446,10 @@ void test_create_world(void) test_create_itemtype("iron"); test_create_itemtype("stone"); - t_plain = test_create_terrain("plain", LAND_REGION | FOREST_REGION | WALK_INTO | CAVALRY_REGION | FLY_INTO); + t_plain = test_create_terrain("plain", LAND_REGION | FOREST_REGION | WALK_INTO | CAVALRY_REGION | FLY_INTO); t_plain->size = 1000; t_plain->max_road = 100; - t_ocean = test_create_terrain("ocean", SEA_REGION | SWIM_INTO | FLY_INTO); + t_ocean = test_create_terrain("ocean", SEA_REGION | SWIM_INTO | FLY_INTO); t_ocean->size = 0; island[0] = test_create_region(0, 0, t_plain); @@ -545,20 +545,20 @@ void assert_message(CuTest * tc, message *msg, char *name, int numpar) { void assert_pointer_parameter(CuTest * tc, message *msg, int index, void *arg) { const message_type *mtype = (msg)->type; - CuAssertIntEquals((tc), VAR_VOIDPTR, mtype->types[(index)]->vtype);CuAssertPtrEquals((tc), (arg), msg->parameters[(index)].v); + CuAssertIntEquals((tc), VAR_VOIDPTR, mtype->types[(index)]->vtype); CuAssertPtrEquals((tc), (arg), msg->parameters[(index)].v); } void assert_int_parameter(CuTest * tc, message *msg, int index, int arg) { const message_type *mtype = (msg)->type; - CuAssertIntEquals((tc), VAR_INT, mtype->types[(index)]->vtype);CuAssertIntEquals((tc), (arg), msg->parameters[(index)].i); + CuAssertIntEquals((tc), VAR_INT, mtype->types[(index)]->vtype); CuAssertIntEquals((tc), (arg), msg->parameters[(index)].i); } void assert_string_parameter(CuTest * tc, message *msg, int index, const char *arg) { const message_type *mtype = (msg)->type; - CuAssertIntEquals((tc), VAR_VOIDPTR, mtype->types[(index)]->vtype);CuAssertStrEquals((tc), (arg), msg->parameters[(index)].v); + CuAssertIntEquals((tc), VAR_VOIDPTR, mtype->types[(index)]->vtype); CuAssertStrEquals((tc), (arg), msg->parameters[(index)].v); } -void disabled_test(void *suite, void (*test)(CuTest *), const char *name) { +void disabled_test(void *suite, void(*test)(CuTest *), const char *name) { (void)test; fprintf(stderr, "%s: SKIP\n", name); } From 440679da87796df8d6c98c16f781fea5dd9bca00 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Sun, 5 Nov 2017 17:00:40 +0100 Subject: [PATCH 11/21] code that uses newterrain needs to set up terrains in tests. --- src/economy.test.c | 20 ++++++++++++++++++++ src/kernel/terrain.c | 15 ++++++++++----- src/laws.test.c | 15 +++++++++++++++ 3 files changed, 45 insertions(+), 5 deletions(-) diff --git a/src/economy.test.c b/src/economy.test.c index 460ebb5fb..e147277b5 100644 --- a/src/economy.test.c +++ b/src/economy.test.c @@ -14,6 +14,7 @@ #include #include #include +#include #include #include @@ -170,6 +171,23 @@ static void test_normals_recruit(CuTest * tc) { test_cleanup(); } +/** + * Create any terrain types that are used by the trade rules. + * + * This should prevent newterrain from returning NULL. + */ +static void setup_terrains(CuTest *tc) { + test_create_terrain("plain", LAND_REGION | FOREST_REGION | WALK_INTO | CAVALRY_REGION | FLY_INTO); + test_create_terrain("ocean", SEA_REGION | SWIM_INTO | FLY_INTO); + test_create_terrain("swamp", LAND_REGION | WALK_INTO | FLY_INTO); + test_create_terrain("desert", LAND_REGION | WALK_INTO | FLY_INTO); + init_terrains(); + CuAssertPtrNotNull(tc, newterrain(T_OCEAN)); + CuAssertPtrNotNull(tc, newterrain(T_PLAIN)); + CuAssertPtrNotNull(tc, newterrain(T_SWAMP)); + CuAssertPtrNotNull(tc, newterrain(T_DESERT)); +} + static region *setup_trade_region(CuTest *tc, const struct terrain_type *terrain) { region *r; item_type *it_luxury; @@ -206,6 +224,7 @@ static void test_trade_insect(CuTest *tc) { test_setup(); init_resources(); test_create_locale(); + setup_terrains(tc); r = setup_trade_region(tc, test_create_terrain("swamp", LAND_REGION)); init_terrains(); @@ -233,6 +252,7 @@ static void test_buy_cmd(CuTest *tc) { test_setup(); init_resources(); test_create_locale(); + setup_terrains(tc); r = setup_trade_region(tc, test_create_terrain("swamp", LAND_REGION)); init_terrains(); diff --git a/src/kernel/terrain.c b/src/kernel/terrain.c index 8c7ab8878..5a70a21e9 100644 --- a/src/kernel/terrain.c +++ b/src/kernel/terrain.c @@ -128,15 +128,20 @@ static const terrain_type *newterrains[MAXTERRAINS]; const struct terrain_type *newterrain(terrain_t t) { - if (t == NOTERRAIN) + const struct terrain_type *result; + if (t == NOTERRAIN) { return NULL; + } assert(t >= 0); assert(t < MAXTERRAINS); - if (!newterrains[t]) { - log_warning("did you call init_terrains?"); - newterrains[t] = get_terrain(terraindata[t]); + result = newterrains[t]; + if (!result) { + result = newterrains[t] = get_terrain(terraindata[t]); } - return newterrains[t]; + if (!result) { + log_error("no such terrain: %s.", terraindata[t]); + } + return result; } terrain_t oldterrain(const struct terrain_type * terrain) diff --git a/src/laws.test.c b/src/laws.test.c index 942b673b0..a4630332a 100644 --- a/src/laws.test.c +++ b/src/laws.test.c @@ -16,6 +16,7 @@ #include #include #include +#include #include #include @@ -864,11 +865,25 @@ static void test_peasant_luck_effect(CuTest *tc) { test_cleanup(); } +/** +* Create any terrain types that are used by demographics. +* +* This should prevent newterrain from returning NULL. +*/ +static void setup_terrains(CuTest *tc) { + test_create_terrain("volcano", SEA_REGION | SWIM_INTO | FLY_INTO); + test_create_terrain("activevolcano", LAND_REGION | WALK_INTO | FLY_INTO); + init_terrains(); + CuAssertPtrNotNull(tc, newterrain(T_VOLCANO)); + CuAssertPtrNotNull(tc, newterrain(T_VOLCANO_SMOKING)); +} + static void test_luck_message(CuTest *tc) { region* r; attrib *a; test_setup(); + setup_terrains(tc); r = test_create_region(0, 0, NULL); rsetpeasants(r, 1); From 96ff0815c481d48d71ad26a12f1520c6239aa7c5 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Sun, 5 Nov 2017 19:15:43 +0100 Subject: [PATCH 12/21] newterrain sucks. --- src/economy.c | 23 ++++++++--------------- src/economy.test.c | 6 +++++- 2 files changed, 13 insertions(+), 16 deletions(-) diff --git a/src/economy.c b/src/economy.c index 3781e0e8e..1576ce7bd 100644 --- a/src/economy.c +++ b/src/economy.c @@ -1067,7 +1067,7 @@ static int required(int want, variant save) { int req = (int)(want * save.sa[0] / save.sa[1]); int r = want * save.sa[0] % save.sa[1]; - if (r>0) ++req; + if (r > 0) ++req; return req; } @@ -1173,7 +1173,7 @@ attrib_allocation(const resource_type * rtype, region * r, allocation * alist) int x = avail * want / nreq; int rx = (avail * want) % nreq; /* Wenn Rest, dann wuerfeln, ob ich was bekomme: */ - if (rx>0 && rng_int() % nreq < rx) ++x; + if (rx > 0 && rng_int() % nreq < rx) ++x; avail -= x; nreq -= want; al->get = x * al->save.sa[1] / al->save.sa[0]; @@ -1590,17 +1590,10 @@ static void buy(unit * u, request ** buyorders, struct order *ord) return; } - if (u_race(u) == get_race(RC_INSECT)) { - /* entweder man ist insekt, oder... */ - if (r->terrain != newterrain(T_SWAMP) && r->terrain != newterrain(T_DESERT) - && !rbuildings(r)) { - cmistake(u, ord, 119, MSG_COMMERCE); - return; - } - } - else { - /* ...oder in der Region mu� es eine Burg geben. */ - building *b = 0; + /* Entweder man ist Insekt in Sumpf/Wueste, oder es muss + * einen Handelsposten in der Region geben: */ + if (u_race(u) != get_race(RC_INSECT) || (r->terrain == newterrain(T_SWAMP) || r->terrain == newterrain(T_DESERT))) { + building *b = NULL; if (r->buildings) { static int cache; static const struct building_type *bt_castle; @@ -2719,7 +2712,7 @@ static void expandloot(region * r, request * lootorders) /* Lowering morale by 1 depending on the looted money (+20%) */ m = region_get_morale(r); - if (m && startmoney>0) { + if (m && startmoney > 0) { if (rng_int() % 100 < 20 + (looted * 80) / startmoney) { /*Nur Moral -1, turns is not changed, so the first time nothing happens if the morale is good*/ region_set_morale(r, m - 1, -1); @@ -2980,7 +2973,7 @@ void produce(struct region *r) static const struct building_type *caravan_bt; static int rc_cache; static const race *rc_insect, *rc_aquarian; - + if (bt_changed(&bt_cache)) { caravan_bt = bt_find("caravan"); } diff --git a/src/economy.test.c b/src/economy.test.c index e147277b5..6303b2ae8 100644 --- a/src/economy.test.c +++ b/src/economy.test.c @@ -181,7 +181,9 @@ static void setup_terrains(CuTest *tc) { test_create_terrain("ocean", SEA_REGION | SWIM_INTO | FLY_INTO); test_create_terrain("swamp", LAND_REGION | WALK_INTO | FLY_INTO); test_create_terrain("desert", LAND_REGION | WALK_INTO | FLY_INTO); + test_create_terrain("mountain", LAND_REGION | WALK_INTO | FLY_INTO); init_terrains(); + CuAssertPtrNotNull(tc, newterrain(T_MOUNTAIN)); CuAssertPtrNotNull(tc, newterrain(T_OCEAN)); CuAssertPtrNotNull(tc, newterrain(T_PLAIN)); CuAssertPtrNotNull(tc, newterrain(T_SWAMP)); @@ -225,7 +227,7 @@ static void test_trade_insect(CuTest *tc) { init_resources(); test_create_locale(); setup_terrains(tc); - r = setup_trade_region(tc, test_create_terrain("swamp", LAND_REGION)); + r = setup_trade_region(tc, get_terrain("swamp")); init_terrains(); it_luxury = r_luxury(r); @@ -240,6 +242,8 @@ static void test_trade_insect(CuTest *tc) { produce(u->region); CuAssertIntEquals(tc, 1, get_item(u, it_luxury)); CuAssertIntEquals(tc, 5, get_item(u, it_silver)); + + terraform_region(r, get_terrain("swamp")); test_cleanup(); } From 373d7380841ec8d8b6543cf796a5deca925d28d4 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Sun, 5 Nov 2017 19:35:06 +0100 Subject: [PATCH 13/21] add a modules.icebergs configuration variable. --- conf/e2/config.json | 3 +++ src/kernel/terrainid.h | 6 +++--- src/kernel/types.h | 1 - src/randenc.c | 13 ++++++++++--- 4 files changed, 16 insertions(+), 7 deletions(-) diff --git a/conf/e2/config.json b/conf/e2/config.json index 0c85b316b..44375f537 100644 --- a/conf/e2/config.json +++ b/conf/e2/config.json @@ -13,7 +13,10 @@ "game.id" : 2, "orders.default": "work", "NewbieImmunity": 8, + "modules.markets": false, + "modules.astralspace": true, "modules.wormholes": true, + "modules.icebergs": true, "entertain.base": 0, "entertain.perlevel": 20, "taxing.perlevel": 20, diff --git a/src/kernel/terrainid.h b/src/kernel/terrainid.h index 7d353d042..29aa72ce5 100644 --- a/src/kernel/terrainid.h +++ b/src/kernel/terrainid.h @@ -14,7 +14,7 @@ extern "C" { #endif - enum { + typedef enum { T_OCEAN = 0, T_PLAIN, T_SWAMP, @@ -29,8 +29,8 @@ extern "C" { T_VOLCANO_SMOKING, T_ICEBERG_SLEEP, T_ICEBERG, - NOTERRAIN = (terrain_t) - 1 - }; + NOTERRAIN = - 1 + } terrain_t; extern const struct terrain_type *newterrain(terrain_t t); extern terrain_t oldterrain(const struct terrain_type *terrain); diff --git a/src/kernel/types.h b/src/kernel/types.h index a20e923d6..9e9ed3b66 100644 --- a/src/kernel/types.h +++ b/src/kernel/types.h @@ -22,7 +22,6 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include #include -typedef short terrain_t; typedef short item_t; struct attrib; diff --git a/src/randenc.c b/src/randenc.c index b2b282eb1..b19b37ef1 100644 --- a/src/randenc.c +++ b/src/randenc.c @@ -610,9 +610,14 @@ static void move_icebergs(void) void create_icebergs(void) { region *r; + const struct terrain_type *t_iceberg, *t_sleep; + + t_iceberg = get_terrain("iceberg"); + t_sleep = get_terrain("iceberg_sleep"); + assert(t_iceberg && t_sleep); for (r = regions; r; r = r->next) { - if (r->terrain == newterrain(T_ICEBERG_SLEEP) && chance(0.05)) { + if (r->terrain == t_sleep && chance(0.05)) { bool has_ocean_neighbour = false; direction_t dir; region *rc; @@ -629,7 +634,7 @@ void create_icebergs(void) if (!has_ocean_neighbour) continue; - rsetterrain(r, T_ICEBERG); + r->terrain = t_iceberg; fset(r, RF_SELECT); move_iceberg(r); @@ -801,7 +806,9 @@ void randomevents(void) region *r; faction *monsters = get_monsters(); - icebergs(); + if (config_get_int("modules.icebergs", 0)) { + icebergs(); + } godcurse(); orc_growth(); demon_skillchanges(); From 5b70d605ceb667e17f150b9b6089eba6aed07e4b Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Sun, 5 Nov 2017 19:38:42 +0100 Subject: [PATCH 14/21] gcc is annoying about switch statements --- src/names.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/names.c b/src/names.c index bc740a704..ef2d58422 100644 --- a/src/names.c +++ b/src/names.c @@ -248,6 +248,8 @@ static void dragon_name(unit * u) case T_GLACIER: ter = 5; break; + default: + ter = 0; } if (num_postfix <=0) { From c597bebb8b235bd1078b9783274dfc82bc7243f3 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Sun, 5 Nov 2017 20:52:04 +0100 Subject: [PATCH 15/21] fix drowning (it's not dependeing on icebergs). --- scripts/tests/common.lua | 1 - src/randenc.c | 11 +++-------- 2 files changed, 3 insertions(+), 9 deletions(-) diff --git a/scripts/tests/common.lua b/scripts/tests/common.lua index 2f10b3e8a..0fda7168e 100644 --- a/scripts/tests/common.lua +++ b/scripts/tests/common.lua @@ -807,7 +807,6 @@ end function test_swim_and_survive() local r = region.create(0, 0, "plain") local f = create_faction('human') - f.nam = "chaos" local u = unit.create(f, r, 1) process_orders() r.terrain = "ocean" diff --git a/src/randenc.c b/src/randenc.c index b19b37ef1..3358360a0 100644 --- a/src/randenc.c +++ b/src/randenc.c @@ -457,10 +457,6 @@ static void melt_iceberg(region * r) /* in Ozean wandeln */ terraform_region(r, newterrain(T_OCEAN)); - - /* Einheiten, die nicht schwimmen k�nnen oder in Schiffen sind, - * ertrinken */ - drown(r); } static void move_iceberg(region * r) @@ -755,12 +751,8 @@ static void demon_skillchanges(void) */ static void icebergs(void) { - region *r; create_icebergs(); move_icebergs(); - for (r = regions; r; r = r->next) { - drown(r); - } } #define HERBS_ROT /* herbs owned by units have a chance to rot. */ @@ -809,6 +801,9 @@ void randomevents(void) if (config_get_int("modules.icebergs", 0)) { icebergs(); } + for (r = regions; r; r = r->next) { + drown(r); + } godcurse(); orc_growth(); demon_skillchanges(); From 7196f799e6a5eb80e3644b20ac29b7128c29027a Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Mon, 6 Nov 2017 20:29:26 +0100 Subject: [PATCH 16/21] add a terrain_changed function for use with static terrain variables. --- src/kernel/terrain.c | 13 +++++++++++++ src/kernel/terrain.h | 12 +++++++----- src/laws.c | 10 ++++++++-- 3 files changed, 28 insertions(+), 7 deletions(-) diff --git a/src/kernel/terrain.c b/src/kernel/terrain.c index 5a70a21e9..4d3f10c74 100644 --- a/src/kernel/terrain.c +++ b/src/kernel/terrain.c @@ -57,6 +57,17 @@ const char *terraindata[MAXTERRAINS] = { }; static terrain_type *registered_terrains; +static int terrain_changes = 1; + +bool terrain_changed(int *cache) { + assert(cache); + if (*cache != terrain_changes) { + *cache = terrain_changes; + return true; + } + return false; +} + void free_terrains(void) { @@ -76,6 +87,7 @@ void free_terrains(void) } free(t); } + ++terrain_changes; } const terrain_type *terrains(void) @@ -110,6 +122,7 @@ const terrain_type *get_terrain(const char *name) { terrain_type * get_or_create_terrain(const char *name) { terrain_type *terrain = terrain_find_i(name); if (!terrain) { + ++terrain_changes; terrain = (terrain_type *)calloc(sizeof(terrain_type), 1); if (terrain) { terrain->_name = strdup(name); diff --git a/src/kernel/terrain.h b/src/kernel/terrain.h index 3d1491867..26c509f75 100644 --- a/src/kernel/terrain.h +++ b/src/kernel/terrain.h @@ -18,6 +18,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #ifndef TERRAIN_H #define TERRAIN_H + #ifdef __cplusplus extern "C" { #endif @@ -68,12 +69,13 @@ extern "C" { struct terrain_type *next; } terrain_type; - extern terrain_type *get_or_create_terrain(const char *name); - extern const terrain_type *terrains(void); - extern const terrain_type *get_terrain(const char *name); - extern const char *terrain_name(const struct region *r); + terrain_type *get_or_create_terrain(const char *name); + const terrain_type *terrains(void); + const terrain_type *get_terrain(const char *name); + const char *terrain_name(const struct region *r); + bool terrain_changed(int *cache); - extern void init_terrains(void); + void init_terrains(void); void free_terrains(void); #ifdef __cplusplus diff --git a/src/laws.c b/src/laws.c index 1f3633d14..0d3f97f9d 100644 --- a/src/laws.c +++ b/src/laws.c @@ -246,9 +246,15 @@ static void calculate_emigration(region * r) int maxp = region_maxworkers(r); int rp = rpeasants(r); int max_immigrants = MAX_IMMIGRATION(maxp - rp); + static int terrain_cache; + static const terrain_type *t_volcano; + static const terrain_type *t_smoking; - if (r->terrain == newterrain(T_VOLCANO) - || r->terrain == newterrain(T_VOLCANO_SMOKING)) { + if (terrain_changed(&terrain_cache)) { + t_volcano = get_terrain("volcano"); + t_smoking = get_terrain("activevolcano"); + } + if (r->terrain == t_volcano || r->terrain == t_smoking) { max_immigrants = max_immigrants / 10; } From 31d15550edf19c1ada2df196ceb524551aa698a0 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Mon, 6 Nov 2017 20:38:28 +0100 Subject: [PATCH 17/21] Add test coverage for NAME ALLIANCE. --- src/kernel/alliance.test.c | 1 - src/laws.test.c | 7 +++++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/src/kernel/alliance.test.c b/src/kernel/alliance.test.c index 885bc8413..e76a11ba2 100644 --- a/src/kernel/alliance.test.c +++ b/src/kernel/alliance.test.c @@ -216,7 +216,6 @@ static void test_alliance_cmd_transfer(CuTest *tc) { test_cleanup(); } - CuSuite *get_alliance_suite(void) { CuSuite *suite = CuSuiteNew(); diff --git a/src/laws.test.c b/src/laws.test.c index a4630332a..787f69715 100644 --- a/src/laws.test.c +++ b/src/laws.test.c @@ -1164,10 +1164,12 @@ static void test_ally_cmd_errors(CuTest *tc) { static void test_name_cmd(CuTest *tc) { unit *u; faction *f; + alliance *al; order *ord; test_setup(); u = test_create_unit(f = test_create_faction(0), test_create_region(0, 0, 0)); + setalliance(f, al = makealliance(42, "")); ord = create_order(K_NAME, f->locale, "%s ' Ho\tdor '", LOC(f->locale, parameters[P_UNIT])); name_cmd(u, ord); @@ -1196,6 +1198,11 @@ static void test_name_cmd(CuTest *tc) { CuAssertStrEquals(tc, "Hodor", u->region->land->name); free_order(ord); + ord = create_order(K_NAME, f->locale, "%s ' Ho\tdor '", LOC(f->locale, parameters[P_ALLIANCE])); + name_cmd(u, ord); + CuAssertStrEquals(tc, "Hodor", al->name); + free_order(ord); + test_cleanup(); } From eccf6bef7ad7bf34fb23c9acf42358893a9ab7ad Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Mon, 6 Nov 2017 21:04:30 +0100 Subject: [PATCH 18/21] consistent naming of module configurations (singular). add module switch for volcano. --- conf/e2/config.json | 7 ++++--- conf/e3/config.json | 6 ++++-- src/kernel/terrain.c | 12 +++++------- src/kernel/terrainid.h | 1 + src/laws.c | 29 +++++++++++++++++------------ src/market.c | 2 +- src/randenc.c | 20 ++++++++++++++------ src/volcano.c | 10 ++++++++++ src/volcano.h | 1 + 9 files changed, 57 insertions(+), 31 deletions(-) diff --git a/conf/e2/config.json b/conf/e2/config.json index 44375f537..5cbe4e378 100644 --- a/conf/e2/config.json +++ b/conf/e2/config.json @@ -13,10 +13,11 @@ "game.id" : 2, "orders.default": "work", "NewbieImmunity": 8, - "modules.markets": false, + "modules.market": false, "modules.astralspace": true, - "modules.wormholes": true, - "modules.icebergs": true, + "modules.wormhole": true, + "modules.iceberg": true, + "modules.volcano": true, "entertain.base": 0, "entertain.perlevel": 20, "taxing.perlevel": 20, diff --git a/conf/e3/config.json b/conf/e3/config.json index b70d415a7..780dc216d 100644 --- a/conf/e3/config.json +++ b/conf/e3/config.json @@ -32,8 +32,10 @@ "database.gameid": 7, "NewbieImmunity": 4, "modules.astralspace": false, - "modules.wormholes": false, - "modules.markets": true, + "modules.wormhole": false, + "modules.market": true, + "modules.iceberg": false, + "modules.volcano": true, "magic.regeneration": 0.75, "magic.power": 0.5, "resource.factor": 0.25, diff --git a/src/kernel/terrain.c b/src/kernel/terrain.c index 4d3f10c74..d606ff91f 100644 --- a/src/kernel/terrain.c +++ b/src/kernel/terrain.c @@ -37,9 +37,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include #include -#define MAXTERRAINS 14 - -const char *terraindata[MAXTERRAINS] = { +static const char *terrainnames[MAXTERRAINS] = { "ocean", "plain", "swamp", @@ -149,10 +147,10 @@ const struct terrain_type *newterrain(terrain_t t) assert(t < MAXTERRAINS); result = newterrains[t]; if (!result) { - result = newterrains[t] = get_terrain(terraindata[t]); + result = newterrains[t] = get_terrain(terrainnames[t]); } if (!result) { - log_error("no such terrain: %s.", terraindata[t]); + log_error("no such terrain: %s.", terrainnames[t]); } return result; } @@ -198,8 +196,8 @@ void init_terrains(void) const terrain_type *newterrain = newterrains[t]; if (newterrain != NULL) continue; - if (terraindata[t] != NULL) { - newterrain = get_terrain(terraindata[t]); + if (terrainnames[t] != NULL) { + newterrain = get_terrain(terrainnames[t]); if (newterrain != NULL) { newterrains[t] = newterrain; } diff --git a/src/kernel/terrainid.h b/src/kernel/terrainid.h index 29aa72ce5..b6235c399 100644 --- a/src/kernel/terrainid.h +++ b/src/kernel/terrainid.h @@ -29,6 +29,7 @@ extern "C" { T_VOLCANO_SMOKING, T_ICEBERG_SLEEP, T_ICEBERG, + MAXTERRAINS, NOTERRAIN = - 1 } terrain_t; diff --git a/src/laws.c b/src/laws.c index 0d3f97f9d..f2460122d 100644 --- a/src/laws.c +++ b/src/laws.c @@ -41,6 +41,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include "teleport.h" #include "calendar.h" #include "guard.h" +#include "volcano.h" /* attributes includes */ #include @@ -72,7 +73,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include #include #include -#include /* for volcanoes in emigration (needs a flag) */ +#include #include /* util includes */ @@ -246,16 +247,20 @@ static void calculate_emigration(region * r) int maxp = region_maxworkers(r); int rp = rpeasants(r); int max_immigrants = MAX_IMMIGRATION(maxp - rp); - static int terrain_cache; - static const terrain_type *t_volcano; - static const terrain_type *t_smoking; - if (terrain_changed(&terrain_cache)) { - t_volcano = get_terrain("volcano"); - t_smoking = get_terrain("activevolcano"); - } - if (r->terrain == t_volcano || r->terrain == t_smoking) { - max_immigrants = max_immigrants / 10; + + if (volcano_module()) { + static int terrain_cache; + static const terrain_type *t_volcano; + static const terrain_type *t_smoking; + + if (terrain_changed(&terrain_cache)) { + t_volcano = newterrain(T_VOLCANO); + t_smoking = newterrain(T_VOLCANO_SMOKING); + } + if (r->terrain == t_volcano || r->terrain == t_smoking) { + max_immigrants = max_immigrants / 10; + } } for (i = 0; max_immigrants > 0 && i != MAXDIRECTIONS; i++) { @@ -4221,7 +4226,7 @@ void turn_process(void) init_processor(); process(); - if (config_get_int("modules.markets", 0)) { + if (markets_module()) { do_markets(); } } @@ -4233,7 +4238,7 @@ void turn_end(void) remove_empty_units(); /* must happen AFTER age, because that would destroy them right away */ - if (config_get_int("modules.wormholes", 0)) { + if (config_get_int("modules.wormhole", 0)) { wormholes_update(); } diff --git a/src/market.c b/src/market.c index 8fd4e3f0d..fd62ae353 100644 --- a/src/market.c +++ b/src/market.c @@ -71,7 +71,7 @@ attrib_type at_market = { bool markets_module(void) { - return (bool)config_get_int("modules.markets", 0); + return (bool)config_get_int("modules.market", 0); } void do_markets(void) diff --git a/src/randenc.c b/src/randenc.c index 3358360a0..dfe7af8bf 100644 --- a/src/randenc.c +++ b/src/randenc.c @@ -432,7 +432,7 @@ void drown(region * r) } } -static void melt_iceberg(region * r) +static void melt_iceberg(region * r, const terrain_type *t_ocean) { attrib *a; unit *u; @@ -456,7 +456,7 @@ static void melt_iceberg(region * r) } /* in Ozean wandeln */ - terraform_region(r, newterrain(T_OCEAN)); + terraform_region(r, t_ocean); } static void move_iceberg(region * r) @@ -585,14 +585,20 @@ static void move_iceberg(region * r) static void move_icebergs(void) { region *r; + static int terrain_cache; + static const terrain_type *t_iceberg, *t_ocean; + if (terrain_changed(&terrain_cache)) { + t_iceberg = newterrain(T_ICEBERG); + t_ocean = newterrain(T_OCEAN); + } for (r = regions; r; r = r->next) { - if (r->terrain == newterrain(T_ICEBERG) && !fval(r, RF_SELECT)) { + if (r->terrain == t_iceberg && !fval(r, RF_SELECT)) { int select = rng_int() % 10; if (select < 4) { /* 4% chance */ fset(r, RF_SELECT); - melt_iceberg(r); + melt_iceberg(r, t_ocean); } else if (select < 64) { /* 60% chance */ @@ -798,7 +804,7 @@ void randomevents(void) region *r; faction *monsters = get_monsters(); - if (config_get_int("modules.icebergs", 0)) { + if (config_get_int("modules.iceberg", 0)) { icebergs(); } for (r = regions; r; r = r->next) { @@ -807,7 +813,9 @@ void randomevents(void) godcurse(); orc_growth(); demon_skillchanges(); - volcano_update(); + if (volcano_module) { + volcano_update(); + } /* Monumente zerfallen, Schiffe verfaulen */ for (r = regions; r; r = r->next) { diff --git a/src/volcano.c b/src/volcano.c index c912bc0df..fe4ce7dd3 100644 --- a/src/volcano.c +++ b/src/volcano.c @@ -314,3 +314,13 @@ void volcano_update(void) } } } + +bool volcano_module(void) +{ + static int cache; + static bool active; + if (config_changed(&cache)) { + active = config_get_int("modules.volcano", 0) != 0; + } + return active; +} diff --git a/src/volcano.h b/src/volcano.h index d06c381cc..225a76143 100644 --- a/src/volcano.h +++ b/src/volcano.h @@ -27,6 +27,7 @@ extern "C" { void volcano_outbreak(struct region * r, struct region *rn); void volcano_update(void); + bool volcano_module(void); #ifdef __cplusplus } From fa42423f3ccdc93a496645b9a3c936421bdaa856 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Mon, 6 Nov 2017 21:10:37 +0100 Subject: [PATCH 19/21] oops. --- src/randenc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/randenc.c b/src/randenc.c index dfe7af8bf..48f7a5827 100644 --- a/src/randenc.c +++ b/src/randenc.c @@ -813,7 +813,7 @@ void randomevents(void) godcurse(); orc_growth(); demon_skillchanges(); - if (volcano_module) { + if (volcano_module()) { volcano_update(); } /* Monumente zerfallen, Schiffe verfaulen */ From 98be298d724f141b75444e714eca82bf546a30f0 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Tue, 7 Nov 2017 19:35:21 +0100 Subject: [PATCH 20/21] reduce monster spawning with configuration settings. --- conf/e2/config.json | 1 + src/monsters.c | 14 +++++++++++--- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/conf/e2/config.json b/conf/e2/config.json index 5cbe4e378..5d29cd1f5 100644 --- a/conf/e2/config.json +++ b/conf/e2/config.json @@ -18,6 +18,7 @@ "modules.wormhole": true, "modules.iceberg": true, "modules.volcano": true, + "monsters.spawn.chance": 50, "entertain.base": 0, "entertain.perlevel": 20, "taxing.perlevel": 20, diff --git a/src/monsters.c b/src/monsters.c index 115759d29..9079b29d6 100644 --- a/src/monsters.c +++ b/src/monsters.c @@ -874,19 +874,27 @@ void spawn_dragons(void) { region *r; faction *monsters = get_or_create_monsters(); + int minage = config_get_int("monsters.spawn.min_age", 100); + int spawn_chance = 100 * config_get_int("monsters.spawn.chance", 100); + if (spawn_chance <= 0) { + /* monster spawning disabled */ + return; + } for (r = regions; r; r = r->next) { unit *u; - + if (r->age < minage) { + continue; + } if (fval(r->terrain, SEA_REGION)) { - if (rng_int() % 10000 < 1) { + if (rng_int() % spawn_chance < 1) { u = spawn_seaserpent(r, monsters); } } else if ((r->terrain == newterrain(T_GLACIER) || r->terrain == newterrain(T_SWAMP) || r->terrain == newterrain(T_DESERT)) - && rng_int() % 10000 < (5 + 100 * chaosfactor(r))) { + && rng_int() % spawn_chance < (5 + 100 * chaosfactor(r))) { if (chance(0.80)) { u = create_unit(r, monsters, nrand(60, 20) + 1, get_race(RC_FIREDRAGON), 0, NULL, NULL); } From 5a0a1f495b03a6780bdf69c87318c2683ae5cb91 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Tue, 7 Nov 2017 19:42:00 +0100 Subject: [PATCH 21/21] BUG 2383: Delete an invalid assertion. https://bugs.eressea.de/view.php?id=2383 --- src/creport.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/creport.c b/src/creport.c index 15e1791f6..30f045b3f 100644 --- a/src/creport.c +++ b/src/creport.c @@ -853,8 +853,6 @@ void cr_output_unit(stream *out, const region * r, const faction * f, stream_printf(out, "\"%s\";Typ\n", translate(zRace, LOC(f->locale, zRace))); if (u->faction == f && irace != u_race(u)) { - assert(skill_enabled(SK_STEALTH) - || !"we're resetting this on load, so.. ircase should never be used"); zRace = rc_name_s(u_race(u), NAME_PLURAL); stream_printf(out, "\"%s\";wahrerTyp\n", translate(zRace, LOC(f->locale, zRace)));