diff --git a/res/de/strings.xml b/res/de/strings.xml
index 3b7b88f43..bb16c92fe 100644
--- a/res/de/strings.xml
+++ b/res/de/strings.xml
@@ -7290,6 +7290,7 @@
Es ist Spätherbst, und diese Woche ist die letzte vor dem Winter, in der Insekten rekrutieren können.
+ It is the last week before winter in which insects can still recruit.
diff --git a/scripts/tests/bindings.lua b/scripts/tests/bindings.lua
index b37606530..189d34769 100755
--- a/scripts/tests/bindings.lua
+++ b/scripts/tests/bindings.lua
@@ -45,6 +45,14 @@ function test_process()
assert_equal("function", _G.type(eressea.process.regeneration))
assert_equal("function", _G.type(eressea.process.guard_on))
assert_equal("function", _G.type(eressea.process.guard_off))
+ assert_equal("function", _G.type(eressea.process.explain))
+ assert_equal("function", _G.type(eressea.process.messages))
+ assert_equal("function", _G.type(eressea.process.reserve))
+ assert_equal("function", _G.type(eressea.process.claim))
+ assert_equal("function", _G.type(eressea.process.follow))
+ assert_equal("function", _G.type(eressea.process.alliance))
+ assert_equal("function", _G.type(eressea.process.idle))
+ assert_equal("function", _G.type(eressea.process.set_default))
end
function test_settings()
diff --git a/scripts/tests/common.lua b/scripts/tests/common.lua
index 3a7193ed0..88dae3080 100755
--- a/scripts/tests/common.lua
+++ b/scripts/tests/common.lua
@@ -309,12 +309,13 @@ function test_guard()
local r = region.create(0, 0, "plain")
local f1 = faction.create("noreply@eressea.de", "human", "de")
f1.age = 20
- local u1 = unit.create(f1, r, 1)
+ local u1 = unit.create(f1, r, 10)
u1:add_item("sword", 10)
u1:add_item("money", 10)
u1:set_skill("melee", 10)
u1:clear_orders()
u1:add_order("NACH O")
+ u1.name="Kalle Pimp"
local f2 = faction.create("noreply@eressea.de", "human", "de")
f2.age = 20
@@ -329,7 +330,7 @@ function test_guard()
u2:add_item("money", 100)
u3:add_item("money", 100)
process_orders()
- assert_equal(r.id, u1.region.id, "unit may not move after combat")
+ assert_equal(r, u1.region, "unit may not move after combat")
end
function test_recruit()
@@ -568,6 +569,68 @@ function test_config()
assert_not_equal(nil, config.locales)
end
+local function _test_create_laen()
+ eressea.settings.set("rules.terraform.all", "1")
+ local r = region.create(0,0, "mountain")
+ local f1 = faction.create("noreply@eressea.de", "human", "de")
+ local u1 = unit.create(f1, r, 1)
+ r:set_resource("laen", 50)
+ return r, u1
+end
+
+function test_laen1()
+ local r, u1 = _test_create_laen()
+
+ u1:add_item("money", 1000)
+ u1:set_skill("mining", 14)
+ u1:clear_orders()
+ u1:add_order("MACHEN Laen")
+
+ process_orders()
+ assert_equal(0, u1:get_item("laen"))
+end
+
+function test_laen2()
+ local r, u1 = _test_create_laen()
+
+ u1:add_item("money", 1000)
+ u1:set_skill("mining", 15)
+ u1:clear_orders()
+ u1:add_order("MACHEN Laen")
+ u1.name = "Laenmeister"
+
+ local b = building.create(r, "mine")
+ b.size = 10
+ u1.building = b
+ local laen = r:get_resource("laen")
+
+ process_orders()
+ init_reports()
+ write_report(u1.faction)
+ assert_equal(laen - 2, r:get_resource("laen"))
+ assert_equal(2, u1:get_item("laen"))
+end
+
+function test_mine()
+ local r = region.create(0,0, "mountain")
+ local f1 = faction.create("noreply@eressea.de", "human", "de")
+ local u1 = unit.create(f1, r, 1)
+
+ u1:add_item("money", 1000)
+ u1:set_skill("mining", 1)
+ u1:clear_orders()
+ u1:add_order("MACHEN Eisen")
+
+ local b = building.create(r, "mine")
+ b.size = 10
+ u1.building = b
+ local iron = r:get_resource("iron")
+
+ process_orders()
+ assert_equal(2, u1:get_item("iron")) -- skill +1
+ assert_equal(iron - 1, r:get_resource("iron")) -- only 1/2 is taken away
+end
+
function test_guard_resources()
-- this is not quite http://bugs.eressea.de/view.php?id=1756
local r = region.create(0,0, "mountain")
@@ -590,6 +653,7 @@ function test_guard_resources()
process_orders()
local iron = u2:get_item("iron")
+ assert_true(iron > 0)
process_orders()
assert_equal(iron, u2:get_item("iron"))
end
@@ -887,6 +951,7 @@ function setup()
eressea.write_game("free.dat")
eressea.settings.set("rules.economy.food", "4") -- FOOD_IS_FREE
eressea.settings.set("rules.encounters", "0")
+ eressea.settings.set("rules.move.owner_leave", "0")
end
function test_parser()
@@ -1171,3 +1236,104 @@ function test_bug_1875_use_own_first()
assert_equal(99, u:get_potion("peasantblood")) -- unit uses one peasantblood effect
assert_equal(99, u2:get_potion("peasantblood")) -- u2 uses its own effect before u's
end
+
+
+function test_bug_1879_follow_unit()
+ local r = region.create(0, 0, "plain")
+ local r1 = region.create(1, 0, "plain")
+ local f = faction.create("noreply@eressea.de", "human", "de")
+ local u1, u2 = two_units(r, f, f)
+ u1:clear_orders()
+ u1:set_skill("magic", 10)
+ u1:add_order("ZAUBERE STUFE 1 Kleine Flüche")
+ u1:add_order("FOLGEN EINHEIT " .. itoa36(u2.id))
+ u2:clear_orders()
+ u2:add_order("NACH o")
+ process_orders()
+ assert_equal(u1.region.id, r1.id)
+ assert_equal(u2.region.id, r1.id)
+end
+
+function test_bug_1870_leave_enter_e2()
+ local r = region.create(0, 0, "plain")
+ local f = faction.create("noreply@eressea.de", "human", "de")
+ local u1, u2 = two_units(r, f, f)
+ local mine = building.create(r, "mine")
+ mine.size = 10
+ u1.building = mine
+
+ local b = building.create(r, "castle")
+ b.size = 10
+ u2.building = b
+
+ u1:clear_orders()
+ u1:add_order("LERNEN Burgenbau ")
+ u1:add_order("BETRETEN BURG " .. itoa36(b.id))
+
+ eressea.settings.set("rules.move.owner_leave", "0")
+ process_orders()
+ assert_equal(u1.building.id, b.id)
+end
+
+function test_bug_1870_leave_enter_e3()
+ local r = region.create(0, 0, "plain")
+ local f = faction.create("noreply@eressea.de", "human", "de")
+ local u1, u2 = two_units(r, f, f)
+ local mine = building.create(r, "mine")
+ mine.size = 10
+ u1.building = mine
+
+ local b = building.create(r, "castle")
+ b.size = 10
+ u2.building = b
+
+ u1:clear_orders()
+ u1:add_order("LERNEN Burgenbau ")
+ u1:add_order("BETRETEN BURG " .. itoa36(b.id))
+
+ eressea.settings.set("rules.move.owner_leave", "1")
+ process_orders()
+ assert_equal(u1.building.id, mine.id)
+end
+
+function test_bug_1795_limit()
+ local r = region.create(0, 0, "plain")
+ local f = faction.create("noreply@eressea.de", "human", "de")
+ local u1 = one_unit(r,f)
+ u1:add_item("money", 100000000)
+ u1:add_order("REKRUTIEREN 9999")
+ r:set_resource("peasant", 2000) -- no fractional growth!
+ local peasants = r:get_resource("peasant")
+ local limit,frac = math.modf(peasants/40) -- one day this should be a parameter
+ local growth = peasants * 0.001
+
+ process_orders()
+
+ assert_equal(limit+1, u1.number, u1.number .. "!=" .. (limit+1))
+ assert_equal(peasants+growth-limit, r:get_resource("peasant"))
+end
+
+function test_bug_1795_demons()
+ local r = region.create(0, 0, "plain")
+ local f = faction.create("noreply@eressea.de", "demon", "de")
+ local u1 = one_unit(r,f)
+ r:set_resource("peasant", 2000)
+ local peasants = r:get_resource("peasant")
+ local limit,frac = math.modf(peasants/40)
+ local growth = peasants * 0.001
+
+ u1:add_item("money", 100000000)
+ u1:add_order("REKRUTIEREN 9999")
+
+ process_orders()
+
+ assert_equal(limit+1, u1.number, u1.number .. "!=" .. (limit+1))
+ assert_equal(peasants+growth, r:get_resource("peasant"))
+end
+
+function test_faction_flags()
+ f = faction.create("noreply@eressea.de", "human", "de")
+ assert_equal(0, f.flags)
+ f.flags = 42
+ assert_equal(42, f.flags)
+end
diff --git a/scripts/tests/orders.lua b/scripts/tests/orders.lua
index ac98a1d1b..a2e568525 100755
--- a/scripts/tests/orders.lua
+++ b/scripts/tests/orders.lua
@@ -236,3 +236,31 @@ end
function test_process_guard_off()
eressea.process.guard_off()
end
+
+function test_process_explain()
+ eressea.process.explain()
+end
+
+function test_process_messages()
+ eressea.process.messages()
+end
+
+function test_process_reserve()
+ eressea.process.reserve()
+end
+
+function test_process_claim()
+ eressea.process.claim()
+end
+
+function test_process_follow()
+ eressea.process.follow()
+end
+
+function test_process_idle()
+ eressea.process.idle()
+end
+
+function test_process_set_default()
+ eressea.process.set_default()
+end
diff --git a/src/bindings/bind_faction.c b/src/bindings/bind_faction.c
index d5efd226c..775cb5ab8 100644
--- a/src/bindings/bind_faction.c
+++ b/src/bindings/bind_faction.c
@@ -160,6 +160,14 @@ static int tolua_faction_get_flags(lua_State * L)
return 1;
}
+static int tolua_faction_set_flags(lua_State * L)
+{
+ faction *self = (faction *) tolua_tousertype(L, 1, 0);
+ int flags = (int)tolua_tonumber(L, 2, self->flags);
+ self->flags = flags;
+ return 1;
+}
+
static int tolua_faction_get_options(lua_State * L)
{
faction *self = (faction *) tolua_tousertype(L, 1, 0);
@@ -525,7 +533,7 @@ void tolua_faction_open(lua_State * L)
tolua_faction_set_age);
tolua_variable(L, TOLUA_CAST "options", tolua_faction_get_options,
tolua_faction_set_options);
- tolua_variable(L, TOLUA_CAST "flags", tolua_faction_get_flags, NULL);
+ tolua_variable(L, TOLUA_CAST "flags", tolua_faction_get_flags, tolua_faction_set_flags);
tolua_variable(L, TOLUA_CAST "lastturn", tolua_faction_get_lastturn,
tolua_faction_set_lastturn);
diff --git a/src/bindings/bind_process.c b/src/bindings/bind_process.c
index 926655e66..83420578b 100755
--- a/src/bindings/bind_process.c
+++ b/src/bindings/bind_process.c
@@ -2,6 +2,8 @@
#include
#include
+#include
+#include
#include
#include
#include
@@ -215,6 +217,32 @@ void process_guard_on(void) {
process_cmd(K_GUARD, guard_on_cmd, PROC_LAND_REGION);
}
+void process_explain(void) {
+ process_cmd(K_RESHOW, reshow_cmd, 0);
+}
+
+void process_reserve(void) {
+ process_cmd(K_RESERVE, reserve_cmd, 0);
+}
+
+void process_claim(void) {
+ process_cmd(K_CLAIM, claim_cmd, 0);
+}
+
+void process_follow(void) {
+ struct region *r;
+ for (r = regions; r; r = r->next) {
+ unit * u;
+ for (u=r->units; u; u=u->next) {
+ follow_unit(u);
+ }
+ }
+}
+
+void process_messages(void) {
+ process_cmd(K_MAIL, mail_cmd, 0);
+}
+
void process_guard_off(void) {
process_cmd(K_GUARD, guard_off_cmd, PROC_LAND_REGION);
}
@@ -247,3 +275,20 @@ void process_maintenance(void) {
maintain_buildings(r, 0);
}
}
+
+void process_alliance(void) {
+ alliance_cmd();
+}
+
+void process_idle(void) {
+ region * r;
+ for (r=regions; r; r=r->next) {
+ auto_work(r);
+ }
+}
+
+void process_set_default(void) {
+ if (!global.disabled[K_DEFAULT]) {
+ defaultorders();
+ }
+}
diff --git a/src/bindings/bind_process.h b/src/bindings/bind_process.h
index 4a9ebc147..767c7eb77 100755
--- a/src/bindings/bind_process.h
+++ b/src/bindings/bind_process.h
@@ -37,6 +37,14 @@ void process_give_control(void);
void process_regeneration(void);
void process_guard_on(void);
void process_guard_off(void);
+void process_explain(void);
+void process_messages(void);
+void process_reserve(void);
+void process_claim(void);
+void process_follow(void);
+void process_alliance(void);
+void process_idle(void);
+void process_set_default(void);
#ifdef __cplusplus
}
diff --git a/src/bindings/process.pkg b/src/bindings/process.pkg
index bf6f4a83c..fb68e3a42 100755
--- a/src/bindings/process.pkg
+++ b/src/bindings/process.pkg
@@ -34,5 +34,13 @@ module eressea {
void process_regeneration @ regeneration(void); /* regen health & aura */
void process_guard_on @ guard_on(void); /* GUARD */
void process_guard_off @ guard_off(void); /* GUARD NOT */
+ void process_explain @ explain(void); /* SHOW */
+ void process_messages @ messages(void); /* MESSAGE */
+ void process_reserve @ reserve(void); /* RESERVE */
+ void process_claim @ claim(void); /* CLAIM */
+ void process_follow @ follow(void); /* FOLLOW */
+ void process_alliance @ alliance(void); /* FOLLOW */
+ void process_idle @ idle(void); /* work.auto */
+ void process_set_default @ set_default(void); /* work.auto */
}
}
diff --git a/src/gamecode/economy.c b/src/gamecode/economy.c
index cbbde59af..236e4fe1c 100644
--- a/src/gamecode/economy.c
+++ b/src/gamecode/economy.c
@@ -215,6 +215,9 @@ typedef struct recruitment {
int total, assigned;
} recruitment;
+/** Creates a list of recruitment structs, one for each faction. Adds every quantifyable request
+ * to the faction's struct and to total.
+ */
static recruitment *select_recruitment(request ** rop,
int (*quantify) (const struct race *, int), int *total)
{
@@ -292,14 +295,14 @@ static int any_recruiters(const struct race *rc, int qty)
return (int)(qty * 2 * rc->recruit_multi);
}
-static int peasant_recruiters(const struct race *rc, int qty)
+/*static int peasant_recruiters(const struct race *rc, int qty)
{
if (rc->ec_flags & ECF_REC_ETHEREAL)
return -1;
if (rc->ec_flags & ECF_REC_HORSES)
return -1;
return (int)(qty * 2 * rc->recruit_multi);
-}
+}*/
static int horse_recruiters(const struct race *rc, int qty)
{
@@ -315,10 +318,12 @@ static int do_recruiting(recruitment * recruits, int available)
recruitment *rec;
int recruited = 0;
+ /* try to assign recruits to factions fairly */
while (available > 0) {
int n = 0;
int rest, mintotal = INT_MAX;
+ /* find smallest request */
for (rec = recruits; rec != NULL; rec = rec->next) {
int want = rec->total - rec->assigned;
if (want > 0) {
@@ -334,6 +339,8 @@ static int do_recruiting(recruitment * recruits, int available)
}
rest = available - mintotal * n;
+ /* assign size of smallest request for everyone if possible; in the end roll dice to assign
+ * small rest */
for (rec = recruits; rec != NULL; rec = rec->next) {
int want = rec->total - rec->assigned;
@@ -350,6 +357,7 @@ static int do_recruiting(recruitment * recruits, int available)
}
}
+ /* do actual recruiting */
for (rec = recruits; rec != NULL; rec = rec->next) {
request *req;
int get = rec->assigned;
@@ -365,8 +373,6 @@ static int do_recruiting(recruitment * recruits, int available)
int afford = get_pooled(u, oldresourcetype[R_SILVER], GET_DEFAULT,
number * rc->recruitcost) / rc->recruitcost;
number = MIN(number, afford);
- use_pooled(u, oldresourcetype[R_SILVER], GET_DEFAULT,
- rc->recruitcost * number);
}
if (u->number + number > UNIT_MAXSIZE) {
ADDMSG(&u->faction->msgs, msg_feedback(u, req->ord, "error_unit_size",
@@ -374,6 +380,10 @@ static int do_recruiting(recruitment * recruits, int available)
number = UNIT_MAXSIZE - u->number;
assert(number >= 0);
}
+ if (rc->recruitcost) {
+ use_pooled(u, oldresourcetype[R_SILVER], GET_DEFAULT,
+ rc->recruitcost * number);
+ }
add_recruits(u, number, req->qty);
dec = (int)(number * multi);
if ((rc->ec_flags & ECF_REC_ETHEREAL) == 0) {
@@ -449,7 +459,7 @@ static void expandrecruit(region * r, request * recruitorders)
}
/* peasant limited: */
- recruits = select_recruitment(&recruitorders, peasant_recruiters, &orc_total);
+ recruits = select_recruitment(&recruitorders, any_recruiters, &orc_total);
if (recruits) {
int orc_recruited, orc_peasants = rpeasants(r) * 2;
int orc_frac = orc_peasants / RECRUITFRACTION; /* anzahl orks. 2 ork = 1 bauer */
@@ -464,10 +474,10 @@ static void expandrecruit(region * r, request * recruitorders)
/* no limit: */
recruits = select_recruitment(&recruitorders, any_recruiters, &orc_total);
if (recruits) {
- int recruited, peasants = rpeasants(r);
+ int recruited, peasants = rpeasants(r) * 2;
recruited = do_recruiting(recruits, INT_MAX);
if (recruited > 0) {
- rsetpeasants(r, peasants - recruited / 2);
+ rsetpeasants(r, (peasants - recruited) / 2);
}
free_recruitments(recruits);
}
diff --git a/src/gamecode/laws.c b/src/gamecode/laws.c
index 433ba025b..bd8eb859f 100755
--- a/src/gamecode/laws.c
+++ b/src/gamecode/laws.c
@@ -1261,9 +1261,11 @@ int enter_ship(unit * u, struct order *ord, int id, int report)
}
}
- if (leave(u, 0)) {
+ if (leave(u, false)) {
u_set_ship(u, sh);
fset(u, UFL_ENTER);
+ } else if (report) {
+ cmistake(u, ord, 150, MSG_MOVE);
}
return 1;
}
@@ -1310,6 +1312,8 @@ int enter_building(unit * u, order * ord, int id, int report)
fset(u, UFL_ENTER);
u_set_building(u, b);
return 1;
+ } else if (report) {
+ cmistake(u, ord, 150, MSG_MOVE);
}
return 0;
}
@@ -2167,7 +2171,7 @@ static void mailfaction(unit * u, int n, struct order *ord, const char *s)
cmistake(u, ord, 66, MSG_MESSAGE);
}
-static int mail_cmd(unit * u, struct order *ord)
+int mail_cmd(unit * u, struct order *ord)
{
region *r = u->region;
unit *u2;
@@ -2782,7 +2786,7 @@ int guard_off_cmd(unit * u, struct order *ord)
return 0;
}
-static int reshow_cmd(unit * u, struct order *ord)
+int reshow_cmd(unit * u, struct order *ord)
{
const char *s;
param_t p = NOPARAM;
@@ -3711,7 +3715,7 @@ void update_long_order(unit * u)
case K_CAST:
/* dient dazu, das neben Zaubern kein weiterer Befehl
* ausgeführt werden kann, Zaubern ist ein kurzer Befehl */
- set_order(&u->thisorder, NULL);
+ set_order(&u->thisorder, copy_order(ord));
break;
default:
@@ -3868,9 +3872,11 @@ static void remove_exclusive(order ** ordp)
}
}
-static void defaultorders(void)
+void defaultorders(void)
{
region *r;
+
+ assert(!global.disabled[K_DEFAULT]);
for (r = regions; r; r = r->next) {
unit *u;
for (u = r->units; u; u = u->next) {
@@ -4055,7 +4061,39 @@ int pay_cmd(unit * u, struct order *ord)
return 0;
}
-static int claim_cmd(unit * u, struct order *ord)
+
+int reserve_cmd(unit * u, struct order *ord)
+{
+ if (u->number > 0 && (urace(u)->ec_flags & GETITEM)) {
+ int use, count;
+ const resource_type *rtype;
+ const char *s;
+
+ init_tokens(ord);
+ skip_token();
+ s = getstrtoken();
+ count = atoip((const char *)s);
+
+ if (count == 0 && findparam(s, u->faction->locale) == P_EACH) {
+ count = getint() * u->number;
+ }
+
+ rtype = findresourcetype(getstrtoken(), u->faction->locale);
+ if (rtype == NULL)
+ return 0;
+
+ set_resvalue(u, rtype, 0); /* make sure the pool is empty */
+ use = use_pooled(u, rtype, GET_DEFAULT, count);
+ if (use) {
+ set_resvalue(u, rtype, use);
+ change_resource(u, rtype, use);
+ return use;
+ }
+ }
+ return 0;
+}
+
+int claim_cmd(unit * u, struct order *ord)
{
const char *t;
int n;
diff --git a/src/gamecode/laws.h b/src/gamecode/laws.h
index 7f96db564..09f7ce5e8 100755
--- a/src/gamecode/laws.h
+++ b/src/gamecode/laws.h
@@ -50,6 +50,7 @@ extern "C" {
extern int enter_ship(struct unit *u, struct order *ord, int id, int report);
extern void new_units(void);
+ extern void defaultorders(void);
extern void quit(void);
extern void monthly_healing(void);
extern void renumber_factions(void);
@@ -81,7 +82,12 @@ extern "C" {
extern int contact_cmd(struct unit *u, struct order *ord);
extern int guard_on_cmd(struct unit *u, struct order *ord);
extern int guard_off_cmd(struct unit *u, struct order *ord);
-
+ extern int reshow_cmd(struct unit *u, struct order *ord);
+ extern int mail_cmd(struct unit *u, struct order *ord);
+ extern int reserve_cmd(struct unit *u, struct order *ord);
+ extern int claim_cmd(struct unit *u, struct order *ord);
+ extern int follow_cmd(struct unit *u, struct order *ord);
+
#ifdef __cplusplus
}
#endif
diff --git a/src/items/weapons.c b/src/items/weapons.c
index 7b817510a..9eb3d8d72 100644
--- a/src/items/weapons.c
+++ b/src/items/weapons.c
@@ -72,9 +72,10 @@ attack_firesword(const troop * at, const struct weapon_type *wtype,
do {
dt = select_enemy(fi, 0, 1, SELECT_ADVANCE | SELECT_DISTANCE);
- assert(dt.fighter);
--force;
- killed += terminate(dt, *at, AT_SPELL, damage, 1);
+ if (dt.fighter) {
+ killed += terminate(dt, *at, AT_SPELL, damage, 1);
+ }
} while (force && killed < enemies);
if (casualties)
*casualties = killed;
diff --git a/src/kernel/curse.c b/src/kernel/curse.c
index 5dfa9c3f1..a903d8bed 100644
--- a/src/kernel/curse.c
+++ b/src/kernel/curse.c
@@ -438,7 +438,10 @@ double curse_geteffect(const curse * c)
int curse_geteffect_int(const curse * c)
{
double effect = curse_geteffect(c);
- assert(effect - (int)effect == 0);
+ if (effect - (int)effect != 0) {
+ log_error("curse has an integer attribute with float value: '%s' = %lf",
+ c->type->cname, effect);
+ }
return (int)effect;
}
diff --git a/src/kernel/item.c b/src/kernel/item.c
index 38571ba08..76ed653d8 100644
--- a/src/kernel/item.c
+++ b/src/kernel/item.c
@@ -73,7 +73,11 @@ static int res_changeaura(unit * u, const resource_type * rtype, int delta)
static int res_changeperson(unit * u, const resource_type * rtype, int delta)
{
assert(rtype != NULL || !"not implemented");
- scale_number(u, u->number + delta);
+ if (u->number + delta >=0) {
+ scale_number(u, u->number + delta);
+ } else {
+ scale_number(u, 0);
+ }
return u->number;
}
@@ -1226,6 +1230,10 @@ void test_clear_resources(void)
void register_resources(void)
{
+ static bool registered = false;
+ if (registered) return;
+ registered = true;
+
register_function((pf_generic) mod_elves_only, "mod_elves_only");
register_function((pf_generic) mod_dwarves_only, "mod_dwarves_only");
register_function((pf_generic) res_changeitem, "changeitem");
diff --git a/src/kernel/item_test.c b/src/kernel/item_test.c
index c59e47d33..c9a144ede 100644
--- a/src/kernel/item_test.c
+++ b/src/kernel/item_test.c
@@ -2,11 +2,52 @@
#include
#include
+#include
+#include
#include
+#include
#include
#include
+static void test_uchange(CuTest * tc, unit * u, const resource_type * rtype) {
+ int n;
+ change_resource(u, rtype, 4);
+ n = get_resource(u, rtype);
+ CuAssertPtrNotNull(tc, rtype->uchange);
+ CuAssertIntEquals(tc, n, rtype->uchange(u, rtype, 0));
+ CuAssertIntEquals(tc, n-3, rtype->uchange(u, rtype, -3));
+ CuAssertIntEquals(tc, n-3, get_resource(u, rtype));
+ CuAssertIntEquals(tc, 0, rtype->uchange(u, rtype, -n));
+}
+
+void test_change_item(CuTest * tc)
+{
+ unit * u;
+
+ test_cleanup();
+ register_resources();
+ init_resources();
+ test_create_world();
+
+ u = test_create_unit(0, 0);
+ test_uchange(tc, u, olditemtype[I_IRON]->rtype);
+}
+
+void test_change_person(CuTest * tc)
+{
+ unit * u;
+
+ test_cleanup();
+
+ register_resources();
+ init_resources();
+ test_create_world();
+
+ u = test_create_unit(0, 0);
+ test_uchange(tc, u, r_unit);
+}
+
void test_resource_type(CuTest * tc)
{
struct item_type *itype;
@@ -68,6 +109,8 @@ void test_findresourcetype(CuTest * tc)
CuSuite *get_item_suite(void)
{
CuSuite *suite = CuSuiteNew();
+ SUITE_ADD_TEST(suite, test_change_item);
+ SUITE_ADD_TEST(suite, test_change_person);
SUITE_ADD_TEST(suite, test_resource_type);
SUITE_ADD_TEST(suite, test_finditemtype);
SUITE_ADD_TEST(suite, test_findresourcetype);
diff --git a/src/kernel/magic.c b/src/kernel/magic.c
index 2ba55455b..ef7bfa5f3 100644
--- a/src/kernel/magic.c
+++ b/src/kernel/magic.c
@@ -2743,13 +2743,15 @@ void magic(void)
continue;
}
- for (ord = u->orders; ord; ord = ord->next) {
- if (get_keyword(ord) == K_CAST) {
- castorder *co = cast_cmd(u, ord);
- fset(u, UFL_LONGACTION | UFL_NOTMOVING);
- if (co) {
- const spell *sp = co->sp;
- add_castorder(&spellranks[sp->rank], co);
+ if (u->thisorder != NULL) {
+ for (ord = u->orders; ord; ord = ord->next) {
+ if (get_keyword(ord) == K_CAST) {
+ castorder *co = cast_cmd(u, ord);
+ fset(u, UFL_LONGACTION | UFL_NOTMOVING);
+ if (co) {
+ const spell *sp = co->sp;
+ add_castorder(&spellranks[sp->rank], co);
+ }
}
}
}
diff --git a/src/kernel/move.c b/src/kernel/move.c
index ed6131d94..8f595dda5 100644
--- a/src/kernel/move.c
+++ b/src/kernel/move.c
@@ -2697,12 +2697,13 @@ void follow_unit(unit * u)
attrib *a2 = a_find(u2->attribs, &at_follow);
if (a2 != NULL) {
unit *u3 = a2->data.v;
- follow = (u3 && u2->region == u2->region);
+ follow = (u3 && u2->region == u3->region);
}
}
if (follow) {
fset(u, UFL_FOLLOWING);
fset(u2, UFL_FOLLOWED);
+ /* FOLLOW unit on a (potentially) moving unit prevents long orders */
set_order(&u->thisorder, NULL);
}
}
diff --git a/src/kernel/pool.c b/src/kernel/pool.c
index 5fdc88e1f..954cdb164 100644
--- a/src/kernel/pool.c
+++ b/src/kernel/pool.c
@@ -96,7 +96,7 @@ int change_resource(unit * u, const resource_type * rtype, int change)
int get_reservation(const unit * u, const resource_type * rtype)
{
- struct reservation *res = u->reservations;
+ reservation *res = u->reservations;
if (rtype == oldresourcetype[R_STONE] && (u_race(u)->flags & RCF_STONEGOLEM))
return (u->number * GOLEM_STONE);
@@ -111,7 +111,7 @@ int get_reservation(const unit * u, const resource_type * rtype)
int change_reservation(unit * u, const resource_type * rtype, int value)
{
- struct reservation *res, **rp = &u->reservations;
+ reservation *res, **rp = &u->reservations;
if (!value)
return 0;
@@ -120,7 +120,7 @@ int change_reservation(unit * u, const resource_type * rtype, int value)
rp = &(*rp)->next;
res = *rp;
if (!res) {
- *rp = res = calloc(sizeof(struct reservation), 1);
+ *rp = res = calloc(sizeof(reservation), 1);
res->type = rtype;
res->value = value;
} else if (res && res->value + value <= 0) {
@@ -133,9 +133,9 @@ int change_reservation(unit * u, const resource_type * rtype, int value)
return res->value;
}
-static int new_set_resvalue(unit * u, const resource_type * rtype, int value)
+int set_resvalue(unit * u, const resource_type * rtype, int value)
{
- struct reservation *res, **rp = &u->reservations;
+ reservation *res, **rp = &u->reservations;
while (*rp && (*rp)->type != rtype)
rp = &(*rp)->next;
@@ -143,7 +143,7 @@ static int new_set_resvalue(unit * u, const resource_type * rtype, int value)
if (!res) {
if (!value)
return 0;
- *rp = res = calloc(sizeof(struct reservation), 1);
+ *rp = res = calloc(sizeof(reservation), 1);
res->type = rtype;
res->value = value;
} else if (res && value <= 0) {
@@ -253,34 +253,3 @@ use_pooled(unit * u, const resource_type * rtype, unsigned int mode, int count)
}
return count - use;
}
-
-int reserve_cmd(unit * u, struct order *ord)
-{
- if (u->number > 0 && (urace(u)->ec_flags & GETITEM)) {
- int use, count;
- const resource_type *rtype;
- const char *s;
-
- init_tokens(ord);
- skip_token();
- s = getstrtoken();
- count = atoip((const char *)s);
-
- if (count == 0 && findparam(s, u->faction->locale) == P_EACH) {
- count = getint() * u->number;
- }
-
- rtype = findresourcetype(getstrtoken(), u->faction->locale);
- if (rtype == NULL)
- return 0;
-
- new_set_resvalue(u, rtype, 0); /* make sure the pool is empty */
- use = use_pooled(u, rtype, GET_DEFAULT, count);
- if (use) {
- new_set_resvalue(u, rtype, use);
- change_resource(u, rtype, use);
- return use;
- }
- }
- return 0;
-}
diff --git a/src/kernel/pool.h b/src/kernel/pool.h
index b6a5e6833..6de15bf3c 100644
--- a/src/kernel/pool.h
+++ b/src/kernel/pool.h
@@ -54,11 +54,7 @@ extern "C" {
int change_reservation(struct unit *u, const struct resource_type *res,
int value);
- int reserve_cmd(struct unit *u, struct order *ord);
-
-/** init_pool
- * initialisiert den regionalen Pool.
- */
+ int set_resvalue(struct unit * u, const struct resource_type * rtype, int value);
#ifdef __cplusplus
}
diff --git a/src/kernel/region.c b/src/kernel/region.c
index c2d5e6587..e22e5ef62 100644
--- a/src/kernel/region.c
+++ b/src/kernel/region.c
@@ -1016,6 +1016,16 @@ void region_setresource(region * r, const resource_type * rtype, int value)
rsetpeasants(r, value);
else if (rtype == rt_find("horse"))
rsethorses(r, value);
+ else {
+ int i;
+ for (i = 0; r->terrain->production[i].type; ++i) {
+ const terrain_production *production = r->terrain->production + i;
+ if (production->type==rtype) {
+ add_resource(r, 1, value, dice_rand(production->divisor), rtype);
+ break;
+ }
+ }
+ }
}
}
@@ -1604,7 +1614,7 @@ int owner_change(const region * r)
if (r->land && r->land->ownership) {
return r->land->ownership->since_turn;
}
- return -1;
+ return INT_MIN;
}
bool is_mourning(const region * r, int in_turn)
diff --git a/src/kernel/resources.c b/src/kernel/resources.c
index 4a3607d7b..5f3c14757 100644
--- a/src/kernel/resources.c
+++ b/src/kernel/resources.c
@@ -82,6 +82,10 @@ void terraform_resources(region * r)
{
int i;
const terrain_type *terrain = r->terrain;
+ static int terraform_all = -1;
+ if (terraform_all<0) {
+ terraform_all = get_param_int(global.parameters, "rules.terraform.all", 0);
+ }
if (terrain->production == NULL)
return;
@@ -94,10 +98,11 @@ void terraform_resources(region * r)
if (rm->type->rtype == rtype)
break;
}
- if (rm)
+ if (rm) {
continue;
-
- if (chance(production->chance)) {
+ }
+
+ if (terraform_all || chance(production->chance)) {
add_resource(r, dice_rand(production->startlevel),
dice_rand(production->base), dice_rand(production->divisor),
production->type);
diff --git a/src/kernel/unit.c b/src/kernel/unit.c
index f1808f780..ff1dfb444 100644
--- a/src/kernel/unit.c
+++ b/src/kernel/unit.c
@@ -822,14 +822,18 @@ void leave_building(unit * u)
bool can_leave(unit * u)
{
+ static int gamecookie = -1;
static int rule_leave = -1;
if (!u->building) {
return true;
}
- if (rule_leave < 0) {
+
+ if (rule_leave < 0 || gamecookie != global.cookie) {
+ gamecookie = global.cookie;
rule_leave = get_param_int(global.parameters, "rules.move.owner_leave", 0);
}
+
if (rule_leave && u->building && u == building_owner(u->building)) {
return false;
}
diff --git a/src/kernel/unit.h b/src/kernel/unit.h
index ebaab56f5..8e09d40f8 100644
--- a/src/kernel/unit.h
+++ b/src/kernel/unit.h
@@ -71,6 +71,12 @@ extern "C" {
extern int maxheroes(const struct faction *f);
extern int countheroes(const struct faction *f);
+ typedef struct reservation {
+ struct reservation *next;
+ const struct resource_type *type;
+ int value;
+ } reservation;
+
typedef struct unit {
struct unit *next; /* needs to be first entry, for region's unitlist */
struct unit *nextF; /* nächste Einheit der Partei */
@@ -90,11 +96,7 @@ extern "C" {
short skill_size;
struct skill *skills;
struct item *items;
- struct reservation {
- struct reservation *next;
- const struct resource_type *type;
- int value;
- } *reservations;
+ reservation *reservations;
/* orders */
struct order *orders;
diff --git a/src/tests.c b/src/tests.c
index dd05c7d93..568e65ac4 100644
--- a/src/tests.c
+++ b/src/tests.c
@@ -180,15 +180,15 @@ void test_create_world(void)
terrain_type *t_plain, *t_ocean;
region *island[2];
int i;
- item_type * itype;
- const char * names[] = { "horse", "horse_p", "boat", "boat_p" };
+ const char * names[] = { "horse", "horse_p", "boat", "boat_p", "iron", "iron_p", "stone", "stone_p" };
make_locale("de");
init_resources();
assert(!olditemtype[I_HORSE]);
- itype = test_create_itemtype(names);
- olditemtype[I_HORSE] = itype;
+ olditemtype[I_HORSE] = test_create_itemtype(names+0);
+ olditemtype[I_IRON] = test_create_itemtype(names+4);
+ olditemtype[I_STONE] = test_create_itemtype(names+6);
t_plain = test_create_terrain("plain", LAND_REGION | FOREST_REGION | WALK_INTO | CAVALRY_REGION);
t_plain->size = 1000;
diff --git a/src/util/translation.c b/src/util/translation.c
index e3493f434..a96f0914f 100644
--- a/src/util/translation.c
+++ b/src/util/translation.c
@@ -283,7 +283,7 @@ static const char *parse_string(opstack ** stack, const char *in,
if (ic == NULL)
return NULL;
c = (char *)opop_v(stack);
- bytes = (int)strlcpy(oc, c, size);
+ bytes = (int)c?strlcpy(oc, c, size):0;
if (bytes < (int)size)
oc += bytes;
else