From 22367249dbba8cb1d10a11ead24ab7fead8c1592 Mon Sep 17 00:00:00 2001 From: Steffen Mecke Date: Thu, 12 Nov 2015 16:09:26 +0100 Subject: [PATCH 1/9] fix morale change when region owner changes http://bugs.eressea.de/view.php?id=2139 Conflicts: scripts/tests/e3/castles.lua --- scripts/tests/e3/castles.lua | 4 ++ scripts/tests/e3/morale.lua | 105 +++++++++++++++++++++++++---------- scripts/tests/e3/rules.lua | 6 ++ src/bind_region.c | 9 +++ src/buildno.h | 2 +- src/kernel/region.c | 40 ++++++------- src/kernel/region.h | 3 +- src/kernel/save.c | 18 +++--- src/kernel/version.h | 3 +- 9 files changed, 131 insertions(+), 59 deletions(-) diff --git a/scripts/tests/e3/castles.lua b/scripts/tests/e3/castles.lua index f061d1ea4..1fd4e13e9 100644 --- a/scripts/tests/e3/castles.lua +++ b/scripts/tests/e3/castles.lua @@ -7,6 +7,10 @@ function setup() eressea.settings.set("rules.food.flags", "4") end +function teardown() + eressea.settings.set("rules.food.flags", "0") +end + function test_small_castles() local r = region.create(0, 0, "plain") local f1 = faction.create("noreply@eressea.de", "human", "de") diff --git a/scripts/tests/e3/morale.lua b/scripts/tests/e3/morale.lua index a47b0e9e4..c01fad186 100644 --- a/scripts/tests/e3/morale.lua +++ b/scripts/tests/e3/morale.lua @@ -4,12 +4,17 @@ module("tests.e3.morale", package.seeall, lunit.testcase ) function setup() eressea.game.reset() + eressea.settings.set("rules.food.flags", "4") -- food is free end -function test_when_owner_returns_morale_drops_only_2() +function teardown() + eressea.settings.set("rules.food.flags", "0") +end + +function test_when_owner_returns_morale_stays() local r = region.create(0, 0, "plain") assert_equal(1, r.morale) - local f1 = faction.create("noreply@eressea.de", "human", "de") + local f1 = faction.create("owner_returns@eressea.de", "human", "de") local u1 = unit.create(f1, r, 1) u1:add_item("money", 10000) local b = building.create(r, "castle") @@ -25,21 +30,21 @@ function test_when_owner_returns_morale_drops_only_2() assert_equal(5, r.morale) -- no owner, fall by 1 u1.building = b update_owners() - set_key("test", 42) process_orders() - assert_equal(3, r.morale) -- new owner, fall by 2 + assert_equal(5, r.morale) -- old owner returns, no reduction + assert_false(r.is_mourning) end function test_morale_alliance() local r = region.create(0, 0, "plain") assert_equal(1, r.morale) - local f1 = faction.create("noreply@eressea.de", "human", "de") + local f1 = faction.create("ma1@eressea.de", "human", "de") local u1 = unit.create(f1, r, 1) u1:add_item("money", 10000) - local f2 = faction.create("noreply@eressea.de", "human", "de") + local f2 = faction.create("ma2@eressea.de", "human", "de") local u2 = unit.create(f2, r, 1) u2:add_item("money", 10000) - local f3 = faction.create("noreply@eressea.de", "human", "de") + local f3 = faction.create("ma3@eressea.de", "human", "de") local u3 = unit.create(f3, r, 1) u3:add_item("money", 10000) @@ -65,27 +70,68 @@ function test_morale_alliance() -- just checking everything's okay after setup. run_a_turn() assert_equal(6, r.morale) + assert_false(r.is_mourning) + -- change owner, new owner is in the same alliance u1.building = nil run_a_turn() assert_equal(4, r.morale) + assert_true(r.is_mourning) + + run_a_turn() + assert_false(r.is_mourning) -- mourning recovers + -- change owner, new owner is not in the same alliance u2.building = nil run_a_turn() assert_equal(0, r.morale) + assert_true(r.is_mourning) + run_a_turn() + assert_false(r.is_mourning) -- mourning recovers +end + +function test_bigger_castle_empty() + local r = region.create(0, 0, "plain") + assert_equal(1, r.morale) + local f1 = faction.create("small1@eressea.de", "human", "de") + local u1 = unit.create(f1, r, 1) + local f2 = faction.create("small2@eressea.de", "human", "de") + local u2 = unit.create(f2, r, 1) + u1:add_item("money", 10000) + + local big = building.create(r, "castle") + big.size = 20 + u1.building = big + + local small = building.create(r, "castle") + small.size = 10 + u2.building = small + + local function run_a_turn() + process_orders() + f1.lastturn=get_turn() + end + + update_owners() + assert_equal(r.owner, u1.faction) + u1.building = nil + update_owners() + assert_equal(r.owner, u2.faction) + assert_equal(0, r.morale) + assert_true(r.is_mourning) + + run_a_turn() + assert_false(r.is_mourning) -- mourning recovers end function test_morale_change() local r = region.create(0, 0, "plain") assert_equal(1, r.morale) - local f1 = faction.create("noreply@eressea.de", "human", "de") + local f1 = faction.create("mchange@eressea.de", "human", "de") local u1 = unit.create(f1, r, 1) u1:add_item("money", 10000) - local f2 = faction.create("noreply@eressea.de", "human", "de") - local u2 = unit.create(f2, r, 1) - u2:add_item("money", 10000) local AVG_STEP = 6 local b = building.create(r, "castle") @@ -95,38 +141,44 @@ function test_morale_change() local function run_a_turn() process_orders() f1.lastturn=get_turn() - f2.lastturn=get_turn() end -- reinhardt-regel: nach 2*AVG_STEP ist moral mindestens einmal gestiegen. update_owners() assert_not_equal(r.owner, nil) + assert_false(r.is_mourning) for i=1,AVG_STEP*2 do run_a_turn() assert_not_equal(r.owner, nil) end assert_not_equal(1, r.morale) + assert_false(r.is_mourning) -- regel: moral ist nie hoeher als 2 punkte ueber burgen-max. for i=1,AVG_STEP*4 do run_a_turn() end assert_equal(4, r.morale) + assert_false(r.is_mourning) -- auch mit herrscher faellt moral um 1 pro woche, wenn moral > burgstufe r.morale = 6 run_a_turn() assert_equal(5, r.morale) + assert_false(r.is_mourning) run_a_turn() assert_equal(4, r.morale) run_a_turn() assert_equal(4, r.morale) -- regel: ohne herrscher fällt die moral jede woche um 1 punkt, bis sie 1 erreicht + assert_false(r.is_mourning) u1.building = nil update_owners() + assert_false(r.is_mourning) run_a_turn() assert_equal(3, r.morale) + assert_false(r.is_mourning) run_a_turn() assert_equal(2, r.morale) run_a_turn() @@ -140,12 +192,12 @@ function test_morale_change() assert_equal(0, r.morale) end -function test_morale_old() +function test_morale_give_command() local r = region.create(0, 0, "plain") assert_equal(1, r.morale) - local f1 = faction.create("first@eressea.de", "human", "de") + local f1 = faction.create("mold1@eressea.de", "human", "de") local u1 = unit.create(f1, r, 1) - local f2 = faction.create("second@eressea.de", "human", "de") + local f2 = faction.create("mold2@eressea.de", "human", "de") local u2 = unit.create(f2, r, 1) local b = building.create(r, "castle") @@ -154,25 +206,20 @@ function test_morale_old() u2.building = b update_owners() assert_equal(1, r.morale) + assert_false(r.is_mourning) r.morale = 5 assert_equal(r.owner, u1.faction) u1:clear_orders() u1:add_order("GIB " .. itoa36(u2.id) .. " KOMMANDO") + process_orders() - u1:clear_orders() assert_equal(u2.faction, r.owner) - assert_equal(3, r.morale) -- 5-MORALE_TRANSFER - for u in r.units do - if u.faction.id==u2.faction.id then - u.building = nil - end - end - update_owners() - assert_equal(r.owner, u1.faction) - assert_equal(0, r.morale) + assert_equal(3, r.morale) -- 5 - MORALE_TRANSFER + assert_true(r.is_mourning) + + u1:clear_orders() + + process_orders() + assert_false(r.is_mourning) -- mourning recovers end -function test_no_uruk() - local f1 = faction.create("noreply@eressea.de", "uruk", "de") - assert_equal(f1.race, "orc") -end diff --git a/scripts/tests/e3/rules.lua b/scripts/tests/e3/rules.lua index 28b14fe10..8e99f083f 100644 --- a/scripts/tests/e3/rules.lua +++ b/scripts/tests/e3/rules.lua @@ -789,3 +789,9 @@ function test_volcanooutbreak_message() assert_not_equal("", msg:render("de")) assert_not_equal("", msg:render("en")) end + +function test_no_uruk() + local f1 = faction.create("noreply@eressea.de", "uruk", "de") + assert_equal(f1.race, "orc") +end + diff --git a/src/bind_region.c b/src/bind_region.c index b7eaea9e7..a944b7c30 100644 --- a/src/bind_region.c +++ b/src/bind_region.c @@ -210,6 +210,14 @@ static int tolua_region_set_morale(lua_State * L) return 0; } +/* region mourning this turn */ +static int tolua_region_get_is_mourning(lua_State * L) +{ + region *r = (region *)tolua_tousertype(L, 1, 0); + lua_pushboolean(L, is_mourning(r, turn+1)); + return 1; +} + static int tolua_region_get_adj(lua_State * L) { region *r = (region *)tolua_tousertype(L, 1, 0); @@ -691,6 +699,7 @@ void tolua_region_open(lua_State * L) tolua_region_set_name); tolua_variable(L, TOLUA_CAST "morale", tolua_region_get_morale, tolua_region_set_morale); + tolua_variable(L, TOLUA_CAST "is_mourning", tolua_region_get_is_mourning, NULL); tolua_variable(L, TOLUA_CAST "info", tolua_region_get_info, tolua_region_set_info); tolua_variable(L, TOLUA_CAST "units", tolua_region_get_units, NULL); diff --git a/src/buildno.h b/src/buildno.h index b6ed94e81..cf5f74906 100644 --- a/src/buildno.h +++ b/src/buildno.h @@ -1,3 +1,3 @@ #define VERSION_MAJOR 3 #define VERSION_MINOR 7 -#define VERSION_BUILD 10 +#define VERSION_BUILD 11 diff --git a/src/kernel/region.c b/src/kernel/region.c index 7e4a3b649..bd227fd8d 100644 --- a/src/kernel/region.c +++ b/src/kernel/region.c @@ -1273,12 +1273,21 @@ struct faction *region_get_owner(const struct region *r) return NULL; } +struct faction *region_get_last_owner(const struct region *r) +{ + assert(rule_region_owners()); + if (r->land && r->land->ownership) { + return r->land->ownership->last_owner; + } + return NULL; +} + struct alliance *region_get_alliance(const struct region *r) { assert(rule_region_owners()); if (r->land && r->land->ownership) { region_owner *own = r->land->ownership; - return own->owner ? own->owner->alliance : own->alliance; + return own->owner ? own->owner->alliance : (own->last_owner? own->last_owner->alliance : NULL); } return NULL; } @@ -1291,16 +1300,14 @@ void region_set_owner(struct region *r, struct faction *owner, int turn) r->land->ownership = malloc(sizeof(region_owner)); assert(region_get_morale(r) == MORALE_DEFAULT); r->land->ownership->owner = NULL; - r->land->ownership->alliance = NULL; + r->land->ownership->last_owner = NULL; r->land->ownership->flags = 0; } r->land->ownership->since_turn = turn; r->land->ownership->morale_turn = turn; assert(r->land->ownership->owner != owner); + r->land->ownership->last_owner = r->land->ownership->owner; r->land->ownership->owner = owner; - if (owner) { - r->land->ownership->alliance = owner->alliance; - } } } @@ -1314,40 +1321,35 @@ faction *update_owners(region * r) if (blargest) { if (!bowner || bowner->size < blargest->size) { /* region owners update? */ - unit *u = building_owner(blargest); + unit *new_owner = building_owner(blargest); f = region_get_owner(r); - if (u == NULL) { + if (new_owner == NULL) { if (f) { region_set_owner(r, NULL, turn); - r->land->ownership->flags |= OWNER_MOURNING; f = NULL; } } - else if (u->faction != f) { + else if (new_owner->faction != f) { if (!r->land->ownership) { /* there has never been a prior owner */ region_set_morale(r, MORALE_DEFAULT, turn); } - else { + else if (f || new_owner->faction != region_get_last_owner(r)) { alliance *al = region_get_alliance(r); - if (al && u->faction->alliance == al) { + if (al && new_owner->faction->alliance == al) { int morale = _max(0, r->land->morale - MORALE_TRANSFER); region_set_morale(r, morale, turn); } else { region_set_morale(r, MORALE_TAKEOVER, turn); - if (f) { - r->land->ownership->flags |= OWNER_MOURNING; - } } } - region_set_owner(r, u->faction, turn); - f = u->faction; + region_set_owner(r, new_owner->faction, turn); + f = new_owner->faction; } } } else if (r->land->ownership && r->land->ownership->owner) { - r->land->ownership->flags |= OWNER_MOURNING; region_set_owner(r, NULL, turn); f = NULL; } @@ -1421,6 +1423,6 @@ int owner_change(const region * r) bool is_mourning(const region * r, int in_turn) { int change = owner_change(r); - return (change == in_turn - 1 - && (r->land->ownership->flags & OWNER_MOURNING)); + return (change == in_turn - 1 && r->land->ownership->last_owner && r->land->ownership->owner + && r->land->ownership->last_owner != r->land->ownership->owner); } diff --git a/src/kernel/region.h b/src/kernel/region.h index b0672e758..64e3a5750 100644 --- a/src/kernel/region.h +++ b/src/kernel/region.h @@ -72,10 +72,9 @@ extern "C" { #define MORALE_AVERAGE 6 /* default average time for morale to change */ #define MORALE_TRANSFER 2 /* points of morale lost when GIVE COMMAND */ -#define OWNER_MOURNING 0x01 typedef struct region_owner { struct faction *owner; - struct alliance *alliance; + struct faction *last_owner; int since_turn; /* turn the region changed owners */ int morale_turn; /* turn when morale has changed most recently */ int flags; diff --git a/src/kernel/save.c b/src/kernel/save.c index 1c78615a7..2f2b1ce29 100644 --- a/src/kernel/save.c +++ b/src/kernel/save.c @@ -490,9 +490,6 @@ static int resolve_owner(variant id, void *address) } } owner->owner = f; - if (f) { - owner->alliance = f->alliance; - } return result; } @@ -511,13 +508,20 @@ static void read_owner(struct gamedata *data, region_owner ** powner) else { owner->flags = 0; } - if (data->version >= OWNER_2_VERSION) { + if (data->version >= OWNER_3_VERSION) { int id; READ_INT(data->store, &id); - owner->alliance = id ? findalliance(id) : NULL; + owner->last_owner = id ? findfaction(id) : NULL; + } else if (data->version >= OWNER_2_VERSION) { + int id; + alliance *a; + READ_INT(data->store, &id); + a = id ? findalliance(id) : NULL; + /* don't know which faction, take the leader */ + owner->last_owner = a? a->_leader : NULL; } else { - owner->alliance = NULL; + owner->last_owner = NULL; } read_reference(owner, data->store, &read_faction_reference, &resolve_owner); *powner = owner; @@ -533,7 +537,7 @@ static void write_owner(struct gamedata *data, region_owner * owner) WRITE_INT(data->store, owner->since_turn); WRITE_INT(data->store, owner->morale_turn); WRITE_INT(data->store, owner->flags); - WRITE_INT(data->store, owner->alliance ? owner->alliance->id : 0); + write_faction_reference(owner->last_owner, data->store); write_faction_reference(owner->owner, data->store); } else { diff --git a/src/kernel/version.h b/src/kernel/version.h index a32cfbe96..81f490f34 100644 --- a/src/kernel/version.h +++ b/src/kernel/version.h @@ -31,8 +31,9 @@ #define JSON_REPORT_VERSION 346 /* bit 3 in f->options flags the json report */ #define EXPLICIT_CURSE_ISNEW_VERSION 347 /* CURSE_ISNEW is not reset in read/write, but in age() */ #define SPELL_LEVEL_VERSION 348 /* f->max_spelllevel gets stored, not calculated */ +#define OWNER_3_VERSION 349 /* regions store last owner, not last alliance */ -#define RELEASE_VERSION SPELL_LEVEL_VERSION /* current datafile */ +#define RELEASE_VERSION OWNER_3_VERSION /* current datafile */ #define MIN_VERSION INTPAK_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 */ From 33d1521bfd5057c59b4ed25d32d0eba3a1e5b622 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Wed, 16 Dec 2015 22:18:44 +0100 Subject: [PATCH 2/9] pass the parent of an attribute into a_age and attrib_type::age --- src/alchemy.c | 3 ++- src/attributes/hate.c | 3 ++- src/attributes/moved.c | 3 ++- src/attributes/movement.c | 3 ++- src/attributes/reduceproduction.c | 17 ++++++++++++++--- src/building_action.c | 5 +++-- src/items/artrewards.c | 3 ++- src/kernel/curse.c | 3 ++- src/kernel/curse.h | 2 +- src/kernel/unit.c | 3 ++- src/kernel/unit.test.c | 6 +++--- src/laws.c | 10 +++++----- src/magic.c | 9 ++++++--- src/magic.h | 2 +- src/modules/arena.c | 3 ++- src/move.c | 3 ++- src/move.test.c | 4 ++-- src/spells.test.c | 6 +++--- src/spells/alp.c | 5 +++-- src/util/attrib.c | 4 ++-- src/util/attrib.h | 4 ++-- src/vortex.c | 7 ++++--- src/wormhole.c | 5 +++-- 23 files changed, 70 insertions(+), 43 deletions(-) diff --git a/src/alchemy.c b/src/alchemy.c index 9042fee9b..377f84d61 100644 --- a/src/alchemy.c +++ b/src/alchemy.c @@ -219,9 +219,10 @@ static void free_potiondelay(attrib * a) free(a->data.v); } -static int age_potiondelay(attrib * a) +static int age_potiondelay(attrib * a, void *owner) { potiondelay *pd = (potiondelay *)a->data.v; + unused_arg(owner); pd->amount = do_potion(pd->u, pd->r, pd->ptype, pd->amount); return AT_AGE_REMOVE; } diff --git a/src/attributes/hate.c b/src/attributes/hate.c index dd228b132..84768944a 100644 --- a/src/attributes/hate.c +++ b/src/attributes/hate.c @@ -28,8 +28,9 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include -static int verify_hate(attrib * a) +static int verify_hate(attrib * a, void *owner) { + unused_arg(owner); if (a->data.v == NULL) { return 0; } diff --git a/src/attributes/moved.c b/src/attributes/moved.c index 781162ea2..b671646c1 100644 --- a/src/attributes/moved.c +++ b/src/attributes/moved.c @@ -24,8 +24,9 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include -static int age_moved(attrib * a) +static int age_moved(attrib * a, void *owner) { + unused_arg(owner); --a->data.i; return a->data.i > 0; } diff --git a/src/attributes/movement.c b/src/attributes/movement.c index beb3998f0..ca8b6fc2f 100644 --- a/src/attributes/movement.c +++ b/src/attributes/movement.c @@ -65,8 +65,9 @@ void set_movement(attrib ** alist, int type) a->data.i |= type; } -static int age_speedup(attrib * a) +static int age_speedup(attrib * a, void *owner) { + unused_arg(owner); if (a->data.sa[0] > 0) { assert(a->data.sa[0] - a->data.sa[1] >= SHRT_MIN); assert(a->data.sa[0] - a->data.sa[1] <= SHRT_MAX); diff --git a/src/attributes/reduceproduction.c b/src/attributes/reduceproduction.c index 4472a5288..ecf9e4b01 100644 --- a/src/attributes/reduceproduction.c +++ b/src/attributes/reduceproduction.c @@ -20,15 +20,26 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include #include "reduceproduction.h" #include +#include +#include +#include #include +#include -static int age_reduceproduction(attrib * a) +static int age_reduceproduction(attrib * a, void *owner) { + region * r = (region *)owner; int reduce = 100 - (5 * --a->data.sa[1]); - if (reduce < 10) + assert(r); + if (reduce < 10) { reduce = 10; + } a->data.sa[0] = (short)reduce; - return (a->data.sa[1] > 0) ? AT_AGE_KEEP : AT_AGE_REMOVE; + if (a->data.sa[1] > 0) { + ADDMSG(&r->msgs, msg_message("reduceproduction", "")); + return AT_AGE_KEEP; + } + return AT_AGE_REMOVE; } attrib_type at_reduceproduction = { diff --git a/src/building_action.c b/src/building_action.c index 940edb2f1..f5cc19bf8 100644 --- a/src/building_action.c +++ b/src/building_action.c @@ -28,12 +28,12 @@ without prior permission by the authors of Eressea. #include typedef struct building_action { - struct building *b; + struct building *b; // TODO: remove, use attribute-owner? char *fname; char *param; } building_action; -static int lc_age(struct attrib *a) +static int lc_age(struct attrib *a, void *owner) { building_action *data = (building_action *)a->data.v; const char *fname = data->fname; @@ -42,6 +42,7 @@ static int lc_age(struct attrib *a) int result = -1; assert(b != NULL); + assert(owner == b); if (fname != NULL) { lua_State *L = (lua_State *)global.vm_state; diff --git a/src/items/artrewards.c b/src/items/artrewards.c index a5aeb64c2..8b6288f61 100644 --- a/src/items/artrewards.c +++ b/src/items/artrewards.c @@ -45,8 +45,9 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #define HORNDURATION 3 #define HORNIMMUNITY 30 -static int age_peaceimmune(attrib * a) +static int age_peaceimmune(attrib * a, void *owner) { + unused_arg(owner); return (--a->data.i > 0) ? AT_AGE_KEEP : AT_AGE_REMOVE; } diff --git a/src/kernel/curse.c b/src/kernel/curse.c index 09fcdb1d1..3cb39ebab 100644 --- a/src/kernel/curse.c +++ b/src/kernel/curse.c @@ -112,11 +112,12 @@ void curse_init(attrib * a) a->data.v = calloc(1, sizeof(curse)); } -int curse_age(attrib * a) +int curse_age(attrib * a, void *owner) { curse *c = (curse *)a->data.v; int result = 0; + unused_arg(owner); c_clearflag(c, CURSE_ISNEW); if (c_flags(c) & CURSE_NOAGE) { diff --git a/src/kernel/curse.h b/src/kernel/curse.h index 143e73d27..263b66125 100644 --- a/src/kernel/curse.h +++ b/src/kernel/curse.h @@ -291,7 +291,7 @@ extern "C" { void curse_init(struct attrib *a); void curse_done(struct attrib *a); - int curse_age(struct attrib *a); + int curse_age(struct attrib *a, void *owner); double destr_curse(struct curse *c, int cast_level, double force); diff --git a/src/kernel/unit.c b/src/kernel/unit.c index 493a3a66f..9f7c6e984 100644 --- a/src/kernel/unit.c +++ b/src/kernel/unit.c @@ -771,10 +771,11 @@ void set_level(unit * u, skill_t sk, int value) sk_set(add_skill(u, sk), value); } -static int leftship_age(struct attrib *a) +static int leftship_age(struct attrib *a, void *owner) { /* must be aged, so it doesn't affect report generation (cansee) */ unused_arg(a); + unused_arg(owner); return AT_AGE_REMOVE; /* remove me */ } diff --git a/src/kernel/unit.test.c b/src/kernel/unit.test.c index 0fd58a55a..010a59d3a 100644 --- a/src/kernel/unit.test.c +++ b/src/kernel/unit.test.c @@ -341,12 +341,12 @@ static void test_age_familiar(CuTest *tc) { CuAssertIntEquals(tc, true, create_newfamiliar(mag, fam)); CuAssertPtrEquals(tc, fam, get_familiar(mag)); CuAssertPtrEquals(tc, mag, get_familiar_mage(fam)); - a_age(&fam->attribs); - a_age(&mag->attribs); + a_age(&fam->attribs, fam); + a_age(&mag->attribs, mag); CuAssertPtrEquals(tc, fam, get_familiar(mag)); CuAssertPtrEquals(tc, mag, get_familiar_mage(fam)); set_number(fam, 0); - a_age(&mag->attribs); + a_age(&mag->attribs, mag); CuAssertPtrEquals(tc, 0, get_familiar(mag)); test_cleanup(); } diff --git a/src/laws.c b/src/laws.c index 3ca95b61f..6912f3b8a 100755 --- a/src/laws.c +++ b/src/laws.c @@ -3096,7 +3096,7 @@ static building *age_building(building * b) } } - a_age(&b->attribs); + a_age(&b->attribs, b); handle_event(b->attribs, "timer", b); if (b->type->age) { @@ -3108,7 +3108,7 @@ static building *age_building(building * b) static void age_region(region * r) { - a_age(&r->attribs); + a_age(&r->attribs, r); handle_event(r->attribs, "timer", r); if (!r->land) @@ -3153,7 +3153,7 @@ static void ageing(void) /* Factions */ for (f = factions; f; f = f->next) { - a_age(&f->attribs); + a_age(&f->attribs, f); handle_event(f->attribs, "timer", f); } @@ -3168,7 +3168,7 @@ static void ageing(void) /* Einheiten */ for (up = &r->units; *up;) { unit *u = *up; - a_age(&u->attribs); + a_age(&u->attribs, u); if (u == *up) handle_event(u->attribs, "timer", u); if (u == *up) @@ -3178,7 +3178,7 @@ static void ageing(void) /* Schiffe */ for (sp = &r->ships; *sp;) { ship *s = *sp; - a_age(&s->attribs); + a_age(&s->attribs, s); if (s == *sp) handle_event(s->attribs, "timer", s); if (s == *sp) diff --git a/src/magic.c b/src/magic.c index 752b0bcd7..814db3a6a 100644 --- a/src/magic.c +++ b/src/magic.c @@ -149,17 +149,19 @@ static void a_writeicastle(const attrib * a, const void *owner, struct storage *store) { icastle_data *data = (icastle_data *)a->data.v; + assert(owner == data->building); WRITE_TOK(store, data->type->_name); WRITE_INT(store, data->building->no); WRITE_INT(store, data->time); } -static int a_ageicastle(struct attrib *a) +static int a_ageicastle(struct attrib *a, void *owner) { icastle_data *data = (icastle_data *)a->data.v; if (data->time <= 0) { - building *b = data->building; + building *b = data->building; // TODO: use owner region *r = b->region; + assert(owner == b); ADDMSG(&r->msgs, msg_message("icastle_dissolve", "building", b)); /* remove_building lets units leave the building */ remove_building(&r->buildings, b); @@ -2388,10 +2390,11 @@ static int read_magician(attrib * a, void *owner, struct storage *store) return AT_READ_OK; } -static int age_unit(attrib * a) +static int age_unit(attrib * a, void *owner) /* if unit is gone or dead, remove the attribute */ { unit *u = (unit *)a->data.v; + unused_arg(owner); return (u != NULL && u->number > 0) ? AT_AGE_KEEP : AT_AGE_REMOVE; } diff --git a/src/magic.h b/src/magic.h index c33d9917e..3a1854cfb 100644 --- a/src/magic.h +++ b/src/magic.h @@ -208,7 +208,7 @@ extern "C" { typedef struct icastle_data { const struct building_type *type; - struct building *building; /* reverse pointer to dissolve the object */ + struct building *building; // TODO: remove, use owner argument int time; } icastle_data; diff --git a/src/modules/arena.c b/src/modules/arena.c index 3b7e7c7f9..6b76a3434 100644 --- a/src/modules/arena.c +++ b/src/modules/arena.c @@ -212,11 +212,12 @@ order * ord) /** * Tempel der Schreie, Demo-Gebäude **/ -static int age_hurting(attrib * a) +static int age_hurting(attrib * a, void *owner) { building *b = (building *)a->data.v; unit *u; int active = 0; + assert(owner == b); if (b == NULL) return AT_AGE_REMOVE; for (u = b->region->units; u; u = u->next) { diff --git a/src/move.c b/src/move.c index 7780329cf..5ec15c913 100644 --- a/src/move.c +++ b/src/move.c @@ -135,9 +135,10 @@ static void shiptrail_finalize(attrib * a) free(a->data.v); } -static int shiptrail_age(attrib * a) +static int shiptrail_age(attrib * a, void *owner) { traveldir *t = (traveldir *)(a->data.v); + unused_arg(owner); t->age--; return (t->age > 0) ? AT_AGE_KEEP : AT_AGE_REMOVE; diff --git a/src/move.test.c b/src/move.test.c index 5c24ca72e..212d94088 100644 --- a/src/move.test.c +++ b/src/move.test.c @@ -287,9 +287,9 @@ static void test_age_trails(CuTest *tc) { move_ship(sh, r1, r2, route); CuAssertPtrNotNull(tc, r1->attribs); - a_age(&r1->attribs); + a_age(&r1->attribs, r1); CuAssertPtrNotNull(tc, r1->attribs); - a_age(&r1->attribs); + a_age(&r1->attribs, r1); CuAssertPtrEquals(tc, 0, r1->attribs); free_regionlist(route); test_cleanup(); diff --git a/src/spells.test.c b/src/spells.test.c index 58886d991..3c773d489 100644 --- a/src/spells.test.c +++ b/src/spells.test.c @@ -42,7 +42,7 @@ static void test_good_dreams(CuTest *tc) { CuAssertTrue(tc, curse && curse->duration > 1); CuAssertTrue(tc, curse->effect == 1); - a_age(&r->attribs); + a_age(&r->attribs, r); CuAssertIntEquals_Msg(tc, "good dreams give +1 to allies", 1, get_modifier(u1, SK_MELEE, 11, r, false)); CuAssertIntEquals_Msg(tc, "good dreams have no effect on non-allies", 0, get_modifier(u2, SK_MELEE, 11, r, false)); free_castorder(&co); @@ -67,7 +67,7 @@ static void test_dreams(CuTest *tc) { sp_gooddreams(&co); sp_baddreams(&co); - a_age(&r->attribs); + a_age(&r->attribs, r); CuAssertIntEquals_Msg(tc, "good dreams in same region as bad dreams", 1, get_modifier(u1, SK_MELEE, 11, r, false)); CuAssertIntEquals_Msg(tc, "bad dreams in same region as good dreams", -1, get_modifier(u2, SK_MELEE, 11, r, false)); @@ -98,7 +98,7 @@ static void test_bad_dreams(CuTest *tc) { CuAssertTrue(tc, curse && curse->duration > 1); CuAssertTrue(tc, curse->effect == -1); - a_age(&r->attribs); + a_age(&r->attribs, r); CuAssertIntEquals_Msg(tc, "bad dreams have no effect on allies", 0, get_modifier(u1, SK_MELEE, 11, r, false)); CuAssertIntEquals_Msg(tc, "bad dreams give -1 to non-allies", -1, get_modifier(u2, SK_MELEE, 11, r, false)); diff --git a/src/spells/alp.c b/src/spells/alp.c index f86695194..d443aa063 100644 --- a/src/spells/alp.c +++ b/src/spells/alp.c @@ -46,7 +46,7 @@ extern const char *directions[]; typedef struct alp_data { unit *mage; - unit *target; + unit *target; // TODO: remove, use attribute-owner? } alp_data; static void alp_init(attrib * a) @@ -59,9 +59,10 @@ static void alp_done(attrib * a) free(a->data.v); } -static int alp_verify(attrib * a) +static int alp_verify(attrib * a, void *owner) { alp_data *ad = (alp_data *)a->data.v; + unused_arg(owner); if (ad->mage && ad->target) return 1; return 0; /* remove the attribute */ diff --git a/src/util/attrib.c b/src/util/attrib.c index 5c92b691e..9db46836a 100644 --- a/src/util/attrib.c +++ b/src/util/attrib.c @@ -252,7 +252,7 @@ attrib *a_new(const attrib_type * at) return a; } -int a_age(attrib ** p) +int a_age(attrib ** p, void *owner) { attrib **ap = p; /* Attribute altern, und die Entfernung (age()==0) eines Attributs @@ -260,7 +260,7 @@ int a_age(attrib ** p) while (*ap) { attrib *a = *ap; if (a->type->age) { - int result = a->type->age(a); + int result = a->type->age(a, owner); assert(result >= 0 || !"age() returned a negative value"); if (result == AT_AGE_REMOVE) { a_remove(p, a); diff --git a/src/util/attrib.h b/src/util/attrib.h index c235fd67a..2703de0cb 100644 --- a/src/util/attrib.h +++ b/src/util/attrib.h @@ -52,7 +52,7 @@ extern "C" { const char *name; void(*initialize) (struct attrib *); void(*finalize) (struct attrib *); - int(*age) (struct attrib *); + int(*age) (struct attrib *, void *owner); /* age returns 0 if the attribute needs to be removed, !=0 otherwise */ void(*write) (const struct attrib *, const void *owner, struct storage *); int(*read) (struct attrib *, void *owner, struct storage *); /* return AT_READ_OK on success, AT_READ_FAIL if attrib needs removal */ @@ -74,7 +74,7 @@ extern "C" { extern void a_removeall(attrib ** a, const attrib_type * at); extern attrib *a_new(const attrib_type * at); - extern int a_age(attrib ** attribs); + extern int a_age(attrib ** attribs, void *owner); extern int a_read(struct storage *store, attrib ** attribs, void *owner); extern void a_write(struct storage *store, const attrib * attribs, const void *owner); diff --git a/src/vortex.c b/src/vortex.c index ab391f012..1d558bb49 100644 --- a/src/vortex.c +++ b/src/vortex.c @@ -66,9 +66,10 @@ static void a_freedirection(attrib * a) free(d); } -static int a_agedirection(attrib * a) +static int a_agedirection(attrib * a, void *owner) { spec_direction *d = (spec_direction *)(a->data.v); + unused_arg(owner); --d->duration; return (d->duration > 0) ? AT_AGE_KEEP : AT_AGE_REMOVE; } @@ -78,7 +79,7 @@ static int a_readdirection(attrib * a, void *owner, struct storage *store) spec_direction *d = (spec_direction *)(a->data.v); char lbuf[32]; - (void)owner; + unused_arg(owner); READ_INT(store, &d->x); READ_INT(store, &d->y); READ_INT(store, &d->duration); @@ -95,7 +96,7 @@ a_writedirection(const attrib * a, const void *owner, struct storage *store) { spec_direction *d = (spec_direction *)(a->data.v); - (void)owner; + unused_arg(owner); WRITE_INT(store, d->x); WRITE_INT(store, d->y); WRITE_INT(store, d->duration); diff --git a/src/wormhole.c b/src/wormhole.c index 421201790..198983344 100644 --- a/src/wormhole.c +++ b/src/wormhole.c @@ -56,7 +56,7 @@ static int cmp_age(const void *v1, const void *v2) } typedef struct wormhole_data { - building *entry; + building *entry; // TODO: remove, use attribute-owner region *exit; } wormhole_data; @@ -70,13 +70,14 @@ static void wormhole_done(struct attrib *a) free(a->data.v); } -static int wormhole_age(struct attrib *a) +static int wormhole_age(struct attrib *a, void *owner) { wormhole_data *data = (wormhole_data *)a->data.v; int maxtransport = data->entry->size; region *r = data->entry->region; unit *u = r->units; + unused_arg(owner); for (; u != NULL && maxtransport != 0; u = u->next) { if (u->building == data->entry) { message *m = NULL; From fc86de85f14ea074d3720ea190d289a366765dce Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Thu, 17 Dec 2015 12:23:07 +0100 Subject: [PATCH 3/9] resolve a TODO, make attribute (and data) a little bit smaller. --- src/building_action.c | 24 +++++++++++++----------- src/kernel/version.h | 3 ++- 2 files changed, 15 insertions(+), 12 deletions(-) diff --git a/src/building_action.c b/src/building_action.c index f5cc19bf8..4b0c21246 100644 --- a/src/building_action.c +++ b/src/building_action.c @@ -28,7 +28,6 @@ without prior permission by the authors of Eressea. #include typedef struct building_action { - struct building *b; // TODO: remove, use attribute-owner? char *fname; char *param; } building_action; @@ -38,11 +37,10 @@ static int lc_age(struct attrib *a, void *owner) building_action *data = (building_action *)a->data.v; const char *fname = data->fname; const char *fparam = data->param; - building *b = data->b; + building *b = (building *)owner; int result = -1; assert(b != NULL); - assert(owner == b); if (fname != NULL) { lua_State *L = (lua_State *)global.vm_state; @@ -94,9 +92,10 @@ lc_write(const struct attrib *a, const void *owner, struct storage *store) building_action *data = (building_action *)a->data.v; const char *fname = data->fname; const char *fparam = data->param; - building *b = data->b; - write_building_reference(b, store); +#if RELEASE_VERSION < ATTRIBOWNER_VERSION + write_building_reference((building *)owner, store); +#endif WRITE_TOK(store, fname); WRITE_TOK(store, fparam ? fparam : NULLSTRING); } @@ -105,13 +104,17 @@ static int lc_read(struct attrib *a, void *owner, struct storage *store) { char name[NAMESIZE]; building_action *data = (building_action *)a->data.v; - int result = - read_reference(&data->b, store, read_building_reference, resolve_building); + building *b = (building *)owner; + int result = 0; + if (global.data_version < ATTRIBOWNER_VERSION) { + result = read_reference(&b, store, read_building_reference, resolve_building); + assert(b == owner); + } READ_TOK(store, name, sizeof(name)); if (strcmp(name, "tunnel_action") == 0) { /* E2: Weltentor has a new module, doesn't need this any longer */ result = 0; - data->b = 0; + b = 0; } else { data->fname = _strdup(name); @@ -120,14 +123,14 @@ static int lc_read(struct attrib *a, void *owner, struct storage *store) if (strcmp(name, "tnnL") == 0) { /* tunnel_action was the old Weltentore, their code has changed. ignore this object */ result = 0; - data->b = 0; + b = 0; } if (strcmp(name, NULLSTRING) == 0) data->param = 0; else { data->param = _strdup(name); } - if (result == 0 && !data->b) { + if (result == 0 && !b) { return AT_READ_FAIL; } return AT_READ_OK; @@ -144,7 +147,6 @@ void building_addaction(building * b, const char *fname, const char *param) { attrib *a = a_add(&b->attribs, a_new(&at_building_action)); building_action *data = (building_action *)a->data.v; - data->b = b; data->fname = _strdup(fname); if (param) { data->param = _strdup(param); diff --git a/src/kernel/version.h b/src/kernel/version.h index 81f490f34..19c564c1e 100644 --- a/src/kernel/version.h +++ b/src/kernel/version.h @@ -32,8 +32,9 @@ #define EXPLICIT_CURSE_ISNEW_VERSION 347 /* CURSE_ISNEW is not reset in read/write, but in age() */ #define SPELL_LEVEL_VERSION 348 /* f->max_spelllevel gets stored, not calculated */ #define OWNER_3_VERSION 349 /* regions store last owner, not last alliance */ +#define ATTRIBOWNER_VERSION 350 /* all attrib_type functions know who owns the attribute */ -#define RELEASE_VERSION OWNER_3_VERSION /* current datafile */ +#define RELEASE_VERSION ATTRIBOWNER_VERSION /* current datafile */ #define MIN_VERSION INTPAK_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 */ From 8054a145cc1d20ca01a26eee1332ddc3aeb2b3ae Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Sat, 20 Feb 2016 18:21:39 +0100 Subject: [PATCH 4/9] hack to read passwords from an external file --- src/kernel/save.c | 23 ++++++++++++++++++++++- src/kernel/version.h | 4 ++-- 2 files changed, 24 insertions(+), 3 deletions(-) diff --git a/src/kernel/save.c b/src/kernel/save.c index 2f2b1ce29..cce5b0a61 100644 --- a/src/kernel/save.c +++ b/src/kernel/save.c @@ -1156,6 +1156,23 @@ void write_spellbook(const struct spellbook *book, struct storage *store) WRITE_TOK(store, "end"); } +char * getpasswd(int fno) { + const char *prefix = itoa36(fno); + size_t len = strlen(prefix); + FILE * F = fopen("passwords.txt", "r"); + char line[80]; + if (F) { + while (!feof(F)) { + fgets(line, sizeof(line), F); + if (line[len+1]==':' && strncmp(prefix, line, len)==0) { + fclose(F); + return _strdup(line+len+1); + } + } + fclose(F); + } + return NULL; +} /** Reads a faction from a file. * This function requires no context, can be called in any state. The * faction may not already exist, however. @@ -1223,7 +1240,11 @@ faction *readfaction(struct gamedata * data) } READ_STR(data->store, name, sizeof(name)); - f->passw = _strdup(name); + if (data->version < CRYPT_VERSION) { + f->passw = _strdup(name); + } else { + f->passw = getpasswd(f->no); + } if (data->version < NOOVERRIDE_VERSION) { READ_STR(data->store, 0, 0); } diff --git a/src/kernel/version.h b/src/kernel/version.h index 19c564c1e..a7a913099 100644 --- a/src/kernel/version.h +++ b/src/kernel/version.h @@ -33,9 +33,9 @@ #define SPELL_LEVEL_VERSION 348 /* f->max_spelllevel gets stored, not calculated */ #define OWNER_3_VERSION 349 /* regions store last owner, not last alliance */ #define ATTRIBOWNER_VERSION 350 /* all attrib_type functions know who owns the attribute */ - +#define CRYPT_VERSION 351 /* passwords are encrypted */ #define RELEASE_VERSION ATTRIBOWNER_VERSION /* current datafile */ #define MIN_VERSION INTPAK_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 */ +#define MAX_VERSION CRYPT_VERSION /* change this if we can need to read the future datafile, and we can do so */ #define STREAM_VERSION 2 /* internal encoding of binary files */ From 1b28beeaa1cb2dba44fa44550a96acf3fbc4bd35 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Sat, 20 Feb 2016 21:42:30 +0100 Subject: [PATCH 5/9] fix off-by-one error when analyzing passwords.txt (crash E3 and E4 today) --- src/buildno.h | 2 +- src/kernel/save.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/buildno.h b/src/buildno.h index cf5f74906..71fc3a0f4 100644 --- a/src/buildno.h +++ b/src/buildno.h @@ -1,3 +1,3 @@ #define VERSION_MAJOR 3 #define VERSION_MINOR 7 -#define VERSION_BUILD 11 +#define VERSION_BUILD 12 diff --git a/src/kernel/save.c b/src/kernel/save.c index cce5b0a61..b8a7cf793 100644 --- a/src/kernel/save.c +++ b/src/kernel/save.c @@ -1164,7 +1164,7 @@ char * getpasswd(int fno) { if (F) { while (!feof(F)) { fgets(line, sizeof(line), F); - if (line[len+1]==':' && strncmp(prefix, line, len)==0) { + if (line[len]==':' && strncmp(prefix, line, len)==0) { fclose(F); return _strdup(line+len+1); } From ca6bc638eddfed6d2c3a3b8856d0039dd4f50567 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Sat, 20 Feb 2016 22:12:13 +0100 Subject: [PATCH 6/9] release version 3.7.13 --- src/buildno.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/buildno.h b/src/buildno.h index 71fc3a0f4..9ae0e517e 100644 --- a/src/buildno.h +++ b/src/buildno.h @@ -1,3 +1,3 @@ #define VERSION_MAJOR 3 #define VERSION_MINOR 7 -#define VERSION_BUILD 12 +#define VERSION_BUILD 13 From 1682b3d583d0348f8e41ca4c786a91d0cebc20cf Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Sat, 20 Feb 2016 22:23:19 +0100 Subject: [PATCH 7/9] fix off-by-one error --- src/buildno.h | 2 +- src/kernel/save.c | 5 ++++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/buildno.h b/src/buildno.h index 9ae0e517e..6b3ae33ae 100644 --- a/src/buildno.h +++ b/src/buildno.h @@ -1,3 +1,3 @@ #define VERSION_MAJOR 3 #define VERSION_MINOR 7 -#define VERSION_BUILD 13 +#define VERSION_BUILD 14 diff --git a/src/kernel/save.c b/src/kernel/save.c index b8a7cf793..e6ef8b8ce 100644 --- a/src/kernel/save.c +++ b/src/kernel/save.c @@ -1156,7 +1156,7 @@ void write_spellbook(const struct spellbook *book, struct storage *store) WRITE_TOK(store, "end"); } -char * getpasswd(int fno) { +static char * getpasswd(int fno) { const char *prefix = itoa36(fno); size_t len = strlen(prefix); FILE * F = fopen("passwords.txt", "r"); @@ -1165,6 +1165,9 @@ char * getpasswd(int fno) { while (!feof(F)) { fgets(line, sizeof(line), F); if (line[len]==':' && strncmp(prefix, line, len)==0) { + size_t slen = strlen(line)-1; + assert(line[slen]=='\n'); + line[slen] = 0; fclose(F); return _strdup(line+len+1); } From 9ac05666eac58d136337b9646fdf14c5a2c9f042 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Sun, 21 Feb 2016 10:10:26 +0100 Subject: [PATCH 8/9] add a test for succesful read/write of password TODO: do this for different datafile versions (BADCRYPT, etc) --- src/kernel/save.c | 33 ++++++++++++++++++++++++++------- src/kernel/save.h | 3 +++ src/kernel/save.test.c | 16 ++++++++++++++++ src/kernel/version.h | 4 ++-- 4 files changed, 47 insertions(+), 9 deletions(-) diff --git a/src/kernel/save.c b/src/kernel/save.c index e6ef8b8ce..40ff63f3d 100644 --- a/src/kernel/save.c +++ b/src/kernel/save.c @@ -1176,6 +1176,30 @@ static char * getpasswd(int fno) { } return NULL; } + +static void read_password(gamedata *data, faction *f) { + char name[128]; + READ_STR(data->store, name, sizeof(name)); + if (data->version == BADCRYPT_VERSION) { + f->passw = getpasswd(f->no); + } + else { + f->passw = _strdup(name); + } +} + +void _test_read_password(gamedata *data, faction *f) { + read_password(data, f); +} + +static void write_password(gamedata *data, const faction *f) { + WRITE_TOK(data->store, (const char *)f->passw); +} + +void _test_write_password(gamedata *data, const faction *f) { + write_password(data, f); +} + /** Reads a faction from a file. * This function requires no context, can be called in any state. The * faction may not already exist, however. @@ -1242,12 +1266,7 @@ faction *readfaction(struct gamedata * data) set_email(&f->email, ""); } - READ_STR(data->store, name, sizeof(name)); - if (data->version < CRYPT_VERSION) { - f->passw = _strdup(name); - } else { - f->passw = getpasswd(f->no); - } + read_password(data, f); if (data->version < NOOVERRIDE_VERSION) { READ_STR(data->store, 0, 0); } @@ -1354,7 +1373,7 @@ void writefaction(struct gamedata *data, const faction * f) WRITE_STR(data->store, (const char *)f->name); WRITE_STR(data->store, (const char *)f->banner); WRITE_STR(data->store, f->email); - WRITE_TOK(data->store, (const char *)f->passw); + write_password(data, f); WRITE_TOK(data->store, locale_name(f->locale)); WRITE_INT(data->store, f->lastorders); WRITE_INT(data->store, f->age); diff --git a/src/kernel/save.h b/src/kernel/save.h index ca364fc9c..cedd5befc 100644 --- a/src/kernel/save.h +++ b/src/kernel/save.h @@ -83,6 +83,9 @@ extern "C" { struct gamedata *gamedata_open(const char *filename, const char *mode); void gamedata_close(struct gamedata *data); + /* test-only functions that give access to internal implementation details (BAD) */ + void _test_write_password(struct gamedata *data, const struct faction *f); + void _test_read_password(struct gamedata *data, struct faction *f); #ifdef __cplusplus } #endif diff --git a/src/kernel/save.test.c b/src/kernel/save.test.c index 403eaa059..7e68079f2 100644 --- a/src/kernel/save.test.c +++ b/src/kernel/save.test.c @@ -59,10 +59,26 @@ static void test_readwrite_unit(CuTest * tc) test_cleanup(); } +static void test_read_password(CuTest *tc) { + const char *path = "test.dat"; + gamedata *data; + faction *f; + f = test_create_faction(0); + faction_setpassword(f, "secret"); + data = gamedata_open(path, "wb"); + _test_write_password(data, f); + gamedata_close(data); + data = gamedata_open(path, "rb"); + _test_read_password(data, f); + gamedata_close(data); + CuAssertTrue(tc, checkpasswd(f, "secret")); +} + CuSuite *get_save_suite(void) { CuSuite *suite = CuSuiteNew(); SUITE_ADD_TEST(suite, test_readwrite_data); SUITE_ADD_TEST(suite, test_readwrite_unit); + SUITE_ADD_TEST(suite, test_read_password); return suite; } diff --git a/src/kernel/version.h b/src/kernel/version.h index a7a913099..c614ccebe 100644 --- a/src/kernel/version.h +++ b/src/kernel/version.h @@ -33,9 +33,9 @@ #define SPELL_LEVEL_VERSION 348 /* f->max_spelllevel gets stored, not calculated */ #define OWNER_3_VERSION 349 /* regions store last owner, not last alliance */ #define ATTRIBOWNER_VERSION 350 /* all attrib_type functions know who owns the attribute */ -#define CRYPT_VERSION 351 /* passwords are encrypted */ +#define BADCRYPT_VERSION 351 /* passwords are encrypted */ #define RELEASE_VERSION ATTRIBOWNER_VERSION /* current datafile */ #define MIN_VERSION INTPAK_VERSION /* minimal datafile we support */ -#define MAX_VERSION CRYPT_VERSION /* change this if we can need to read the future datafile, and we can do so */ +#define MAX_VERSION BADCRYPT_VERSION /* change this if we can need to read the future datafile, and we can do so */ #define STREAM_VERSION 2 /* internal encoding of binary files */ From dd94771ed8a7a3e85cadf7868d42de8f6d6a6279 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Sun, 21 Feb 2016 10:25:18 +0100 Subject: [PATCH 9/9] test password reading and writing for BADCRYPT_VERSION (requires external file) --- src/kernel/save.test.c | 41 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/src/kernel/save.test.c b/src/kernel/save.test.c index 7e68079f2..73fcb10a7 100644 --- a/src/kernel/save.test.c +++ b/src/kernel/save.test.c @@ -5,9 +5,12 @@ #include "unit.h" #include "faction.h" #include "version.h" +#include #include #include +#include + #include static void test_readwrite_data(CuTest * tc) @@ -42,6 +45,8 @@ static void test_readwrite_unit(CuTest * tc) sprintf(path, "%s/%s", datapath(), filename); data = gamedata_open(path, "wb"); + CuAssertPtrNotNull(tc, data); + write_unit(data, u); gamedata_close(data); @@ -49,6 +54,7 @@ static void test_readwrite_unit(CuTest * tc) f = test_create_faction(0); renumber_faction(f, fno); data = gamedata_open(path, "rb"); + CuAssertPtrNotNull(tc, data); u = read_unit(data); gamedata_close(data); @@ -66,12 +72,46 @@ static void test_read_password(CuTest *tc) { f = test_create_faction(0); faction_setpassword(f, "secret"); data = gamedata_open(path, "wb"); + CuAssertPtrNotNull(tc, data); _test_write_password(data, f); gamedata_close(data); data = gamedata_open(path, "rb"); + CuAssertPtrNotNull(tc, data); _test_read_password(data, f); gamedata_close(data); CuAssertTrue(tc, checkpasswd(f, "secret")); + CuAssertIntEquals(tc, 0, remove(path)); +} + +static void test_read_password_external(CuTest *tc) { + const char *path = "test.dat", *pwfile = "passwords.txt"; + gamedata *data; + faction *f; + FILE * F; + + remove(pwfile); + f = test_create_faction(0); + faction_setpassword(f, "secret"); + CuAssertPtrNotNull(tc, f->passw); + data = gamedata_open(path, "wb"); + CuAssertPtrNotNull(tc, data); + WRITE_TOK(data->store, (const char *)f->passw); + WRITE_TOK(data->store, (const char *)f->passw); + gamedata_close(data); + data = gamedata_open(path, "rb"); + CuAssertPtrNotNull(tc, data); + data->version = BADCRYPT_VERSION; + _test_read_password(data, f); + CuAssertPtrEquals(tc, 0, f->passw); + F = fopen(pwfile, "wt"); + fprintf(F, "%s:secret\n", itoa36(f->no)); + fclose(F); + _test_read_password(data, f); + CuAssertPtrNotNull(tc, f->passw); + gamedata_close(data); + CuAssertTrue(tc, checkpasswd(f, "secret")); + CuAssertIntEquals(tc, 0, remove(path)); + CuAssertIntEquals(tc, 0, remove(pwfile)); } CuSuite *get_save_suite(void) @@ -80,5 +120,6 @@ CuSuite *get_save_suite(void) SUITE_ADD_TEST(suite, test_readwrite_data); SUITE_ADD_TEST(suite, test_readwrite_unit); SUITE_ADD_TEST(suite, test_read_password); + SUITE_ADD_TEST(suite, test_read_password_external); return suite; }