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 */