From e1469c4c522b03eaf7af2fc5f57416fc70826ab5 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Sat, 19 Oct 2024 19:55:52 +0200 Subject: [PATCH 1/7] fix reading skills in data versions < 360 --- src/kernel/save.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/kernel/save.c b/src/kernel/save.c index f53fdecec..68d445499 100644 --- a/src/kernel/save.c +++ b/src/kernel/save.c @@ -305,10 +305,10 @@ static void writeorder(gamedata *data, const struct order *ord, WRITE_STR(data->store, obuf); } -static void read_skill(gamedata *data, skill *sv) { +static bool read_skill(gamedata *data, skill *sv) { int val; READ_INT(data->store, &val); - assert(val < MAXSKILLS); + if (val < 0) return false; sv->id = (skill_t)val; if (sv->id != NOSKILL) { READ_INT(data->store, &val); @@ -328,6 +328,7 @@ static void read_skill(gamedata *data, skill *sv) { assert(val > 0); } } + return true; } static int skill_cmp(const void *a, const void *b) { @@ -343,8 +344,9 @@ static void read_skills(gamedata *data, unit *u) size_t skill_size = 0; for (;;) { - read_skill(data, sv); - if (sv->id == NOSKILL) break; + if (!read_skill(data, sv)) { + break; + } if (sv->level > 0) { ++sv; ++skill_size; From 88008d87c32172717ec9df145de79f5413e704ba Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Sat, 19 Oct 2024 21:36:37 +0200 Subject: [PATCH 2/7] small tweak to the shadowmaster fix, in cases they don't have stealth for some reason (datafile 999) --- src/kernel/save.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/kernel/save.c b/src/kernel/save.c index 68d445499..0c3631129 100644 --- a/src/kernel/save.c +++ b/src/kernel/save.c @@ -1286,11 +1286,15 @@ void fix_shadows(void) const race *rc = u_race(u); if (rc == rc_demon) { int level = get_level(u, SK_STEALTH); - set_level(u, SK_STEALTH, level / 2); + if (level > 0) { + set_level(u, SK_STEALTH, level / 2); + } } else if (rc == rc_lord) { int level = get_level(u, SK_STEALTH); - set_level(u, SK_STEALTH, level - 1); + if (level > 0) { + set_level(u, SK_STEALTH, level - 1); + } } } } From a66529c7ca64084ce7854b0689862bf18c3f9b05 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Sun, 20 Oct 2024 14:57:11 +0200 Subject: [PATCH 3/7] minimal test for building roads --- src/economy.test.c | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/src/economy.test.c b/src/economy.test.c index 3d347c71b..c673611b9 100644 --- a/src/economy.test.c +++ b/src/economy.test.c @@ -9,6 +9,7 @@ #include #include #include +#include "kernel/connection.h" #include #include #include "kernel/direction.h" // for D_EAST, directions @@ -1698,6 +1699,30 @@ static void test_destroy_cmd(CuTest* tc) { test_teardown(); } +static void test_make_road(CuTest *tc) { + region *r, *r2; + unit *u; + faction *f; + struct item_type *itype; + terrain_type *t_plain; + + test_setup(); + t_plain = test_create_terrain("plain", LAND_REGION); + t_plain->max_road = 100; + u = test_create_unit(f = test_create_faction(), r = test_create_region(0, 0, t_plain)); + r2 = test_create_region(1, 0, t_plain); + set_level(u, SK_ROAD_BUILDING, 10); + scale_number(u, 10); + i_change(&u->items, itype = test_create_itemtype("stone"), 100); + u->thisorder = create_order(K_MAKE, f->locale, + "50 %s %s", param_name(P_ROAD, f->locale), LOC(f->locale, directions[D_EAST])); + make_cmd(u, u->thisorder); + CuAssertIntEquals(tc, 50, i_get(u->items, itype)); + CuAssertIntEquals(tc, 50, rroad(r, D_EAST)); + CuAssertPtrNotNull(tc, get_borders(r, r2)); + test_teardown(); +} + static void test_make_zero(CuTest* tc) { unit* u; faction* f; @@ -1784,6 +1809,7 @@ CuSuite *get_economy_suite(void) SUITE_ADD_TEST(suite, test_destroy_road); SUITE_ADD_TEST(suite, test_destroy_road_limit); SUITE_ADD_TEST(suite, test_destroy_road_guard); + SUITE_ADD_TEST(suite, test_make_road); SUITE_ADD_TEST(suite, test_make_zero); SUITE_ADD_TEST(suite, test_entertain_fair); return suite; From cb4105905acef9dd758749dc75f5c550b174e1a8 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Sun, 20 Oct 2024 16:31:56 +0200 Subject: [PATCH 4/7] test: rroad/rsetroad chore: eliminate confuding r_connect/rconnect duplication --- src/bind_region.c | 2 +- src/kernel/connection.c | 2 +- src/kernel/region.c | 4 ++-- src/kernel/region.h | 3 +-- src/kernel/region.test.c | 13 +++++++++++++ 5 files changed, 18 insertions(+), 6 deletions(-) diff --git a/src/bind_region.c b/src/bind_region.c index 638d3f398..c442573df 100644 --- a/src/bind_region.c +++ b/src/bind_region.c @@ -322,7 +322,7 @@ static int tolua_region_get_next(lua_State * L) direction_t dir = (direction_t)tolua_tonumber(L, 2, 0); if (dir >= 0 && dir < MAXDIRECTIONS) { - tolua_pushusertype(L, (void *)r_connect(self, dir), "region"); + tolua_pushusertype(L, (void *)rconnect(self, dir), "region"); return 1; } return 0; diff --git a/src/kernel/connection.c b/src/kernel/connection.c index 344926fad..2e1198a70 100644 --- a/src/kernel/connection.c +++ b/src/kernel/connection.c @@ -69,7 +69,7 @@ void walk_connections(region *r, void(*cb)(connection *, void *), void *data) { walk_i(r, borders[key], cb, data); for (d = 0; d != MAXDIRECTIONS; ++d) { - region *rn = r_connect(r, d); + region *rn = rconnect(r, d); if (rn) { int k = reg_hashkey(rn); if (k < key) { diff --git a/src/kernel/region.c b/src/kernel/region.c index 7de9b1c65..35e728c6e 100644 --- a/src/kernel/region.c +++ b/src/kernel/region.c @@ -328,11 +328,10 @@ void runhash(region * r) regionhash[key] = DELMARKER; } -region *r_connect(const region * r, direction_t dir) +region *rconnect(const region * r, direction_t dir) { region *result; int x, y; - region *rmodify = (region *)r; if (dir < 0 || dir >= MAXDIRECTIONS) { return NULL; } @@ -344,6 +343,7 @@ region *r_connect(const region * r, direction_t dir) pnormalize(&x, &y, rplane(r)); result = rfindhash(x, y); if (result) { + region *rmodify = (region *)r; rmodify->connect[dir] = result; result->connect[back[dir]] = rmodify; } diff --git a/src/kernel/region.h b/src/kernel/region.h index 494675bf7..a952303a6 100644 --- a/src/kernel/region.h +++ b/src/kernel/region.h @@ -231,8 +231,7 @@ void region_set_owner(struct region *r, struct faction *owner, int turn); struct faction *region_get_owner(const struct region *r); struct alliance *region_get_alliance(const struct region *r); -struct region *r_connect(const struct region *, direction_t dir); -#define rconnect(r, dir) ((r)->connect[dir]?(r)->connect[dir]:r_connect(r, (direction_t)dir)) +struct region *rconnect(const struct region *, direction_t dir); void free_regions(void); void free_land(struct land_region * lr); diff --git a/src/kernel/region.test.c b/src/kernel/region.test.c index e4710f7a3..57477abf4 100644 --- a/src/kernel/region.test.c +++ b/src/kernel/region.test.c @@ -95,6 +95,18 @@ static void test_region_getset_resource(CuTest *tc) { test_teardown(); } +static void test_roads(CuTest *tc) { + region *r, *r2; + + test_setup(); + r = test_create_plain(0, 0); + r2 = test_create_plain(1, 0); + rsetroad(r, D_EAST, 100); + CuAssertIntEquals(tc, 100, rroad(r, D_EAST)); + CuAssertIntEquals(tc, 0, rroad(r2, D_WEST)); + test_teardown(); +} + static void test_trees(CuTest *tc) { region *r; @@ -138,6 +150,7 @@ CuSuite *get_region_suite(void) CuSuite *suite = CuSuiteNew(); SUITE_ADD_TEST(suite, test_newterrain); SUITE_ADD_TEST(suite, test_terraform); + SUITE_ADD_TEST(suite, test_roads); SUITE_ADD_TEST(suite, test_trees); SUITE_ADD_TEST(suite, test_mourning); SUITE_ADD_TEST(suite, test_region_getset_resource); From 1efd284708910111dd291bd72e4a0510f89369db Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Sun, 20 Oct 2024 17:08:08 +0200 Subject: [PATCH 5/7] borders don't need an id. --- src/kernel/connection.c | 9 ++------- src/kernel/connection.h | 5 +---- src/kernel/gamedata.h | 3 ++- src/kernel/region.c | 2 +- src/kernel/region.test.c | 19 ++++++++++++++++++- src/kernel/save.c | 12 +++++++----- src/spells.c | 4 ++-- 7 files changed, 33 insertions(+), 21 deletions(-) diff --git a/src/kernel/connection.c b/src/kernel/connection.c index 2e1198a70..71160f9fb 100644 --- a/src/kernel/connection.c +++ b/src/kernel/connection.c @@ -24,8 +24,6 @@ #include #include -int nextborder = 0; - #define BORDER_MAXHASH 8191 connection *borders[BORDER_MAXHASH]; border_type *bordertypes; @@ -103,7 +101,7 @@ connection *get_borders(const region * r1, const region * r2) return *bp; } -connection *new_border(border_type * type, region * from, region * to, int id) +connection *create_border(border_type * type, region * from, region * to) { connection *b, **bp; @@ -117,7 +115,6 @@ connection *new_border(border_type * type, region * from, region * to, int id) b->type = type; b->from = from; b->to = to; - b->id = (id > 0) ? id : ++nextborder; if (type->init) { type->init(b); @@ -547,7 +544,6 @@ void write_borders(struct storage *store) if (b->type->valid && !b->type->valid(b)) continue; WRITE_TOK(store, b->type->_name); - WRITE_INT(store, b->id); WRITE_INT(store, b->from->uid); WRITE_INT(store, b->to->uid); @@ -612,8 +608,7 @@ int read_borders(gamedata *data) } } if (b == NULL) { - b = new_border(type, from, to, bid); - assert(bid <= nextborder); + b = create_border(type, from, to); } type->read(b, data); if (!type->write) { diff --git a/src/kernel/connection.h b/src/kernel/connection.h index 4f7258de9..832bde8cc 100644 --- a/src/kernel/connection.h +++ b/src/kernel/connection.h @@ -15,15 +15,12 @@ extern "C" { struct gamedata; struct unit; - extern int nextborder; - typedef struct connection { struct border_type *type; /* the type of this connection */ struct connection *next; /* next connection between these regions */ struct connection *nexthash; /* next connection between these regions */ struct region *from, *to; /* borders can be directed edges */ variant data; - int id; /* unique id */ } connection; typedef struct border_type { @@ -86,7 +83,7 @@ extern "C" { connection *get_borders(const struct region *r1, const struct region *r2); /* returns the list of borders between r1 and r2 or r2 and r1 */ - connection *new_border(border_type *type, struct region *from, struct region *to, int id); + connection *create_border(border_type *type, struct region *from, struct region *to); /* creates a connection of the specified type */ void erase_border(connection * b); /* remove the connection from memory */ diff --git a/src/kernel/gamedata.h b/src/kernel/gamedata.h index 3be845535..034517388 100644 --- a/src/kernel/gamedata.h +++ b/src/kernel/gamedata.h @@ -57,8 +57,9 @@ #define FIX_SHADOWS_VERSION 379 /* shadowdemon/-master skills, bug 3011 */ #define FIX_SHAPESHIFT_IRACE_VERSION 380 /* shapeshift spell, bug 2991 */ #define SKILL_DAYS_VERSION 381 /* skills are stored as days, not weeks */ +#define BORDER_ID_VERSION 382 /* borders no longer have an id, from turn 1376 */ -#define RELEASE_VERSION SKILL_DAYS_VERSION /* use for new datafiles */ +#define RELEASE_VERSION BORDER_ID_VERSION /* use for new datafiles */ #define MIN_VERSION UIDHASH_VERSION /* minimal datafile we support */ #define MAX_VERSION RELEASE_VERSION /* change this if we can need to read the future datafile, and we can do so */ diff --git a/src/kernel/region.c b/src/kernel/region.c index 35e728c6e..8fad3c1c3 100644 --- a/src/kernel/region.c +++ b/src/kernel/region.c @@ -544,7 +544,7 @@ void rsetroad(region * r, direction_t d, int val) } if (!b) { if (!val) return; - b = new_border(&bt_road, r, r2, 0); + b = create_border(&bt_road, r, r2); } if (r == b->from) { b->data.sa[0] = (short)val; diff --git a/src/kernel/region.test.c b/src/kernel/region.test.c index 57477abf4..683eb044f 100644 --- a/src/kernel/region.test.c +++ b/src/kernel/region.test.c @@ -5,6 +5,7 @@ #include "building.h" #include "calendar.h" #include "config.h" +#include "connection.h" #include "resources.h" #include "unit.h" #include "terrain.h" @@ -102,8 +103,23 @@ static void test_roads(CuTest *tc) { r = test_create_plain(0, 0); r2 = test_create_plain(1, 0); rsetroad(r, D_EAST, 100); + rsetroad(r2, D_WEST, 50); CuAssertIntEquals(tc, 100, rroad(r, D_EAST)); - CuAssertIntEquals(tc, 0, rroad(r2, D_WEST)); + CuAssertIntEquals(tc, 50, rroad(r2, D_WEST)); + test_teardown(); +} + +static void test_borders(CuTest *tc) { + region *r, *r2; + connection *c; + + test_setup(); + r = test_create_plain(0, 0); + r2 = test_create_plain(1, 0); + CuAssertPtrEquals(tc, NULL, get_borders(r, r2)); + c = create_border(&bt_road, r, r2); + CuAssertPtrEquals(tc, c, get_borders(r, r2)); + CuAssertPtrEquals(tc, c, get_borders(r2, r)); test_teardown(); } @@ -151,6 +167,7 @@ CuSuite *get_region_suite(void) SUITE_ADD_TEST(suite, test_newterrain); SUITE_ADD_TEST(suite, test_terraform); SUITE_ADD_TEST(suite, test_roads); + SUITE_ADD_TEST(suite, test_borders); SUITE_ADD_TEST(suite, test_trees); SUITE_ADD_TEST(suite, test_mourning); SUITE_ADD_TEST(suite, test_region_getset_resource); diff --git a/src/kernel/save.c b/src/kernel/save.c index 0c3631129..fdd436d27 100644 --- a/src/kernel/save.c +++ b/src/kernel/save.c @@ -1790,9 +1790,10 @@ int read_game(gamedata *data) READ_INT(store, &turn); log_debug(" - reading turn %d", turn); rng_init(turn + config_get_int("game.seed", 0)); - READ_INT(store, NULL); /* max_unique_id = ignore */ - READ_INT(store, &nextborder); - + if (data->version < BORDER_ID_VERSION) { + READ_INT(store, NULL); /* max_unique_id = ignore */ + READ_INT(store, NULL); /* nextborder, legacy */ + } read_planes(data); read_alliances(data); @@ -1889,9 +1890,10 @@ int write_game(gamedata *data) { WRITE_SECTION(store); WRITE_INT(store, turn); +#if RELEASE_VERSION < BORDER_ID_VERSION WRITE_INT(store, 0 /* max_unique_id */); - WRITE_INT(store, nextborder); - + WRITE_INT(store, 0 /* nextborder */); +#endif write_planes(store); write_alliances(data); n = listlen(factions); diff --git a/src/spells.c b/src/spells.c index d542a2d70..3b8d3ff2c 100644 --- a/src/spells.c +++ b/src/spells.c @@ -2629,7 +2629,7 @@ static int sp_firewall(castorder * co) b = b->next; } if (b == NULL) { - b = new_border(&bt_firewall, r, r2, 0); + b = create_border(&bt_firewall, r, r2); fd = (wall_data *)b->data.v; fd->force = (int)(force / 2 + 0.5); fd->mage = caster; @@ -3062,7 +3062,7 @@ static int sp_chaossuction(castorder * co) /* TODO: implement with a building */ create_special_direction(r, rt, 2, "vortex_desc", "vortex", false); create_special_direction(rt, r, 2, "vortex_desc", "vortex", false); - new_border(&bt_chaosgate, r, rt, 0); + create_border(&bt_chaosgate, r, rt); ADDMSG(&r->msgs, msg_message("chaosgate_effect_1", "mage", caster)); ADDMSG(&rt->msgs, msg_message("chaosgate_effect_2", "")); From eb0a19cbec551c35bbca921225ba14d816aa0a0e Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Sun, 20 Oct 2024 17:23:21 +0200 Subject: [PATCH 6/7] test borders --- src/kernel/region.test.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/kernel/region.test.c b/src/kernel/region.test.c index 683eb044f..9301a48d6 100644 --- a/src/kernel/region.test.c +++ b/src/kernel/region.test.c @@ -109,9 +109,15 @@ static void test_roads(CuTest *tc) { test_teardown(); } +static void cb_connection(struct connection *c, void *data) +{ + ++*(int *)data; +} + static void test_borders(CuTest *tc) { region *r, *r2; connection *c; + int n = 0; test_setup(); r = test_create_plain(0, 0); @@ -120,6 +126,10 @@ static void test_borders(CuTest *tc) { c = create_border(&bt_road, r, r2); CuAssertPtrEquals(tc, c, get_borders(r, r2)); CuAssertPtrEquals(tc, c, get_borders(r2, r)); + + create_border(&bt_road, r, test_create_plain(-1, 0)); + walk_connections(r, cb_connection, &n); + CuAssertIntEquals(tc, 2, n); test_teardown(); } From 045753c8836e29cbeefe0eff63625e7498473583 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Mon, 21 Oct 2024 22:04:20 +0200 Subject: [PATCH 7/7] =?UTF-8?q?Ausgiebiger=20Lua-Test=20f=C3=BCr=20Karawan?= =?UTF-8?q?serei?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- scripts/roadtest.lua | 11 +++++++++ scripts/tests/e2/buildings.lua | 41 ++++++++++++++++++++++++++++++++++ scripts/tests/e2/items.lua | 1 - scripts/tests/harbor.lua | 1 - scripts/tests/laws.lua | 2 -- 5 files changed, 52 insertions(+), 4 deletions(-) create mode 100644 scripts/roadtest.lua diff --git a/scripts/roadtest.lua b/scripts/roadtest.lua new file mode 100644 index 000000000..6af7f5411 --- /dev/null +++ b/scripts/roadtest.lua @@ -0,0 +1,11 @@ +require 'config' +eressea.read_game(get_turn() .. '.dat') +r = get_region(-55, -22) +print(r) +roads = r.roads +for d = 1, 6 do + print(roads[d]) +end +for b in r.buildings do + print(b) +end diff --git a/scripts/tests/e2/buildings.lua b/scripts/tests/e2/buildings.lua index eee2000de..1eed1ac1b 100644 --- a/scripts/tests/e2/buildings.lua +++ b/scripts/tests/e2/buildings.lua @@ -109,3 +109,44 @@ function test_build_harbour() assert_equal(25, u.building.size) end +function test_caravan() + local r = region.create(0,0, "desert") + local r2 = region.create(1,0, "plain") + local f = faction.create("human") + local u = unit.create(f, r, 10) + u:set_skill("building", 3) + u:set_skill("roadwork", 10) + u:add_item("money", 8000) + u:add_item("horse", 2) + u:add_item("stone", 210) + u:add_item("log", 50) + u:add_item("iron", 10) + u:set_orders("MACHE 100 STRASSE OST") + process_orders() + assert_equal(0, r.roads[3]) -- keine Arme, keine Kekse + u:set_orders("MACHE 1 Karawanserei\nBEZAHLE NICHT") + process_orders() + assert_not_nil(u.building) + assert_equal(1, u.building.size) + u:set_orders("MACHE 100 STRASSE OST\nBEZAHLE NICHT") + process_orders() + assert_equal(0, r.roads[3]) -- Karawane ist noch nicht fertig + u:set_orders("MACHE 9 Karawanserei\nBEZAHLE NICHT") + process_orders() + assert_equal(10, u.building.size) + u:set_orders("MACHE 100 STRASSE OST\nBEZAHLE NICHT") + process_orders() + assert_equal(0, r.roads[3]) -- Karawane ist noch nicht fertig + u:set_orders("MACHE 200 STRASSE OST") + process_orders() + assert_equal(100, r.roads[3]) -- maximaler Ausbau Strasse in Wüsten + assert_equal(100, u:get_item('stone')) + u:set_orders("ZERSTOERE 1") + process_orders() + assert_equal(9, u.building.size) + assert_equal(100, r.roads[3]) + u:set_orders("ZERSTOERE 9") + process_orders() + assert_nil(u.building) + assert_equal(50, r.roads[3]) +end diff --git a/scripts/tests/e2/items.lua b/scripts/tests/e2/items.lua index b94b6277c..d9b24306b 100644 --- a/scripts/tests/e2/items.lua +++ b/scripts/tests/e2/items.lua @@ -392,7 +392,6 @@ function test_speedsail() local u = unit.create(f, r, 1) turn_begin() - u.name = 'Xolgrim' u.ship = ship.create(r, "boat") u:add_item("speedsail", 2) u:clear_orders() diff --git a/scripts/tests/harbor.lua b/scripts/tests/harbor.lua index f0ffa597d..a2f869c9c 100644 --- a/scripts/tests/harbor.lua +++ b/scripts/tests/harbor.lua @@ -206,7 +206,6 @@ function test_leave_harbour() local u = unit.create(f, r1, 1) local u2 = unit.create(f, r, 1) u2.building = b - u.name = 'Xolgrim' u.ship = sh u:set_skill('sailing', 10) diff --git a/scripts/tests/laws.lua b/scripts/tests/laws.lua index 3f52fae10..33cfbf4ab 100644 --- a/scripts/tests/laws.lua +++ b/scripts/tests/laws.lua @@ -171,7 +171,6 @@ function test_give_and_forget() local f = faction.create("human") local u1 = unit.create(f, r, 1) local u2 = unit.create(f, r, 1) - u1.name = 'Xolgrim' u1:set_skill('alchemy', 1) u1:set_skill('crossbow', 1) u2:set_skill('alchemy', 1) @@ -194,7 +193,6 @@ function test_steal_from_pool() local u = unit.create(faction.create("human"), r) u:set_skill('stealth', 1) u:set_orders("BEKLAUE " .. itoa36(u1.id)) - u.name = 'Xolgrim' process_orders() assert_equal(50, u:get_item('money')) assert_equal(50, u2:get_item('money'))