Merge branch 'master' of github.com:eressea/core

Conflicts:
	src/kernel/reports.c
This commit is contained in:
Enno Rehling 2013-05-02 03:48:16 +02:00
commit efc7373fb9
25 changed files with 456 additions and 86 deletions

View File

@ -7290,6 +7290,7 @@
<string name="nr_insectfall"> <string name="nr_insectfall">
<text locale="de">Es ist Spätherbst, und diese Woche ist die letzte vor dem Winter, in der Insekten rekrutieren können.</text> <text locale="de">Es ist Spätherbst, und diese Woche ist die letzte vor dem Winter, in der Insekten rekrutieren können.</text>
<text locale="en">It is the last week before winter in which insects can still recruit.</text>
</string> </string>
<string name="nr_owner"> <string name="nr_owner">

View File

@ -45,6 +45,14 @@ function test_process()
assert_equal("function", _G.type(eressea.process.regeneration)) 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_on))
assert_equal("function", _G.type(eressea.process.guard_off)) 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 end
function test_settings() function test_settings()

View File

@ -309,12 +309,13 @@ function test_guard()
local r = region.create(0, 0, "plain") local r = region.create(0, 0, "plain")
local f1 = faction.create("noreply@eressea.de", "human", "de") local f1 = faction.create("noreply@eressea.de", "human", "de")
f1.age = 20 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("sword", 10)
u1:add_item("money", 10) u1:add_item("money", 10)
u1:set_skill("melee", 10) u1:set_skill("melee", 10)
u1:clear_orders() u1:clear_orders()
u1:add_order("NACH O") u1:add_order("NACH O")
u1.name="Kalle Pimp"
local f2 = faction.create("noreply@eressea.de", "human", "de") local f2 = faction.create("noreply@eressea.de", "human", "de")
f2.age = 20 f2.age = 20
@ -329,7 +330,7 @@ function test_guard()
u2:add_item("money", 100) u2:add_item("money", 100)
u3:add_item("money", 100) u3:add_item("money", 100)
process_orders() 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 end
function test_recruit() function test_recruit()
@ -568,6 +569,68 @@ function test_config()
assert_not_equal(nil, config.locales) assert_not_equal(nil, config.locales)
end 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() function test_guard_resources()
-- this is not quite http://bugs.eressea.de/view.php?id=1756 -- this is not quite http://bugs.eressea.de/view.php?id=1756
local r = region.create(0,0, "mountain") local r = region.create(0,0, "mountain")
@ -590,6 +653,7 @@ function test_guard_resources()
process_orders() process_orders()
local iron = u2:get_item("iron") local iron = u2:get_item("iron")
assert_true(iron > 0)
process_orders() process_orders()
assert_equal(iron, u2:get_item("iron")) assert_equal(iron, u2:get_item("iron"))
end end
@ -887,6 +951,7 @@ function setup()
eressea.write_game("free.dat") eressea.write_game("free.dat")
eressea.settings.set("rules.economy.food", "4") -- FOOD_IS_FREE eressea.settings.set("rules.economy.food", "4") -- FOOD_IS_FREE
eressea.settings.set("rules.encounters", "0") eressea.settings.set("rules.encounters", "0")
eressea.settings.set("rules.move.owner_leave", "0")
end end
function test_parser() 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, u:get_potion("peasantblood")) -- unit uses one peasantblood effect
assert_equal(99, u2:get_potion("peasantblood")) -- u2 uses its own effect before u's assert_equal(99, u2:get_potion("peasantblood")) -- u2 uses its own effect before u's
end 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

View File

@ -236,3 +236,31 @@ end
function test_process_guard_off() function test_process_guard_off()
eressea.process.guard_off() eressea.process.guard_off()
end 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

View File

@ -160,6 +160,14 @@ static int tolua_faction_get_flags(lua_State * L)
return 1; 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) static int tolua_faction_get_options(lua_State * L)
{ {
faction *self = (faction *) tolua_tousertype(L, 1, 0); faction *self = (faction *) tolua_tousertype(L, 1, 0);
@ -525,7 +533,7 @@ void tolua_faction_open(lua_State * L)
tolua_faction_set_age); tolua_faction_set_age);
tolua_variable(L, TOLUA_CAST "options", tolua_faction_get_options, tolua_variable(L, TOLUA_CAST "options", tolua_faction_get_options,
tolua_faction_set_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_variable(L, TOLUA_CAST "lastturn", tolua_faction_get_lastturn,
tolua_faction_set_lastturn); tolua_faction_set_lastturn);

View File

@ -2,6 +2,8 @@
#include <platform.h> #include <platform.h>
#include <kernel/types.h> #include <kernel/types.h>
#include <kernel/alliance.h>
#include <kernel/config.h>
#include <kernel/magic.h> #include <kernel/magic.h>
#include <kernel/order.h> #include <kernel/order.h>
#include <kernel/battle.h> #include <kernel/battle.h>
@ -215,6 +217,32 @@ void process_guard_on(void) {
process_cmd(K_GUARD, guard_on_cmd, PROC_LAND_REGION); 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) { void process_guard_off(void) {
process_cmd(K_GUARD, guard_off_cmd, PROC_LAND_REGION); process_cmd(K_GUARD, guard_off_cmd, PROC_LAND_REGION);
} }
@ -247,3 +275,20 @@ void process_maintenance(void) {
maintain_buildings(r, 0); 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();
}
}

View File

@ -37,6 +37,14 @@ void process_give_control(void);
void process_regeneration(void); void process_regeneration(void);
void process_guard_on(void); void process_guard_on(void);
void process_guard_off(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 #ifdef __cplusplus
} }

View File

@ -34,5 +34,13 @@ module eressea {
void process_regeneration @ regeneration(void); /* regen health & aura */ void process_regeneration @ regeneration(void); /* regen health & aura */
void process_guard_on @ guard_on(void); /* GUARD */ void process_guard_on @ guard_on(void); /* GUARD */
void process_guard_off @ guard_off(void); /* GUARD NOT */ 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 */
} }
} }

View File

@ -215,6 +215,9 @@ typedef struct recruitment {
int total, assigned; int total, assigned;
} recruitment; } 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, static recruitment *select_recruitment(request ** rop,
int (*quantify) (const struct race *, int), int *total) 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); 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) if (rc->ec_flags & ECF_REC_ETHEREAL)
return -1; return -1;
if (rc->ec_flags & ECF_REC_HORSES) if (rc->ec_flags & ECF_REC_HORSES)
return -1; return -1;
return (int)(qty * 2 * rc->recruit_multi); return (int)(qty * 2 * rc->recruit_multi);
} }*/
static int horse_recruiters(const struct race *rc, int qty) static int horse_recruiters(const struct race *rc, int qty)
{ {
@ -315,10 +318,12 @@ static int do_recruiting(recruitment * recruits, int available)
recruitment *rec; recruitment *rec;
int recruited = 0; int recruited = 0;
/* try to assign recruits to factions fairly */
while (available > 0) { while (available > 0) {
int n = 0; int n = 0;
int rest, mintotal = INT_MAX; int rest, mintotal = INT_MAX;
/* find smallest request */
for (rec = recruits; rec != NULL; rec = rec->next) { for (rec = recruits; rec != NULL; rec = rec->next) {
int want = rec->total - rec->assigned; int want = rec->total - rec->assigned;
if (want > 0) { if (want > 0) {
@ -334,6 +339,8 @@ static int do_recruiting(recruitment * recruits, int available)
} }
rest = available - mintotal * n; 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) { for (rec = recruits; rec != NULL; rec = rec->next) {
int want = rec->total - rec->assigned; 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) { for (rec = recruits; rec != NULL; rec = rec->next) {
request *req; request *req;
int get = rec->assigned; 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, int afford = get_pooled(u, oldresourcetype[R_SILVER], GET_DEFAULT,
number * rc->recruitcost) / rc->recruitcost; number * rc->recruitcost) / rc->recruitcost;
number = MIN(number, afford); number = MIN(number, afford);
use_pooled(u, oldresourcetype[R_SILVER], GET_DEFAULT,
rc->recruitcost * number);
} }
if (u->number + number > UNIT_MAXSIZE) { if (u->number + number > UNIT_MAXSIZE) {
ADDMSG(&u->faction->msgs, msg_feedback(u, req->ord, "error_unit_size", 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; number = UNIT_MAXSIZE - u->number;
assert(number >= 0); assert(number >= 0);
} }
if (rc->recruitcost) {
use_pooled(u, oldresourcetype[R_SILVER], GET_DEFAULT,
rc->recruitcost * number);
}
add_recruits(u, number, req->qty); add_recruits(u, number, req->qty);
dec = (int)(number * multi); dec = (int)(number * multi);
if ((rc->ec_flags & ECF_REC_ETHEREAL) == 0) { if ((rc->ec_flags & ECF_REC_ETHEREAL) == 0) {
@ -449,7 +459,7 @@ static void expandrecruit(region * r, request * recruitorders)
} }
/* peasant limited: */ /* peasant limited: */
recruits = select_recruitment(&recruitorders, peasant_recruiters, &orc_total); recruits = select_recruitment(&recruitorders, any_recruiters, &orc_total);
if (recruits) { if (recruits) {
int orc_recruited, orc_peasants = rpeasants(r) * 2; int orc_recruited, orc_peasants = rpeasants(r) * 2;
int orc_frac = orc_peasants / RECRUITFRACTION; /* anzahl orks. 2 ork = 1 bauer */ 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: */ /* no limit: */
recruits = select_recruitment(&recruitorders, any_recruiters, &orc_total); recruits = select_recruitment(&recruitorders, any_recruiters, &orc_total);
if (recruits) { if (recruits) {
int recruited, peasants = rpeasants(r); int recruited, peasants = rpeasants(r) * 2;
recruited = do_recruiting(recruits, INT_MAX); recruited = do_recruiting(recruits, INT_MAX);
if (recruited > 0) { if (recruited > 0) {
rsetpeasants(r, peasants - recruited / 2); rsetpeasants(r, (peasants - recruited) / 2);
} }
free_recruitments(recruits); free_recruitments(recruits);
} }

View File

@ -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); u_set_ship(u, sh);
fset(u, UFL_ENTER); fset(u, UFL_ENTER);
} else if (report) {
cmistake(u, ord, 150, MSG_MOVE);
} }
return 1; return 1;
} }
@ -1310,6 +1312,8 @@ int enter_building(unit * u, order * ord, int id, int report)
fset(u, UFL_ENTER); fset(u, UFL_ENTER);
u_set_building(u, b); u_set_building(u, b);
return 1; return 1;
} else if (report) {
cmistake(u, ord, 150, MSG_MOVE);
} }
return 0; 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); 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; region *r = u->region;
unit *u2; unit *u2;
@ -2782,7 +2786,7 @@ int guard_off_cmd(unit * u, struct order *ord)
return 0; return 0;
} }
static int reshow_cmd(unit * u, struct order *ord) int reshow_cmd(unit * u, struct order *ord)
{ {
const char *s; const char *s;
param_t p = NOPARAM; param_t p = NOPARAM;
@ -3711,7 +3715,7 @@ void update_long_order(unit * u)
case K_CAST: case K_CAST:
/* dient dazu, das neben Zaubern kein weiterer Befehl /* dient dazu, das neben Zaubern kein weiterer Befehl
* ausgeführt werden kann, Zaubern ist ein kurzer Befehl */ * ausgeführt werden kann, Zaubern ist ein kurzer Befehl */
set_order(&u->thisorder, NULL); set_order(&u->thisorder, copy_order(ord));
break; break;
default: default:
@ -3868,9 +3872,11 @@ static void remove_exclusive(order ** ordp)
} }
} }
static void defaultorders(void) void defaultorders(void)
{ {
region *r; region *r;
assert(!global.disabled[K_DEFAULT]);
for (r = regions; r; r = r->next) { for (r = regions; r; r = r->next) {
unit *u; unit *u;
for (u = r->units; u; u = u->next) { for (u = r->units; u; u = u->next) {
@ -4055,7 +4061,39 @@ int pay_cmd(unit * u, struct order *ord)
return 0; 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; const char *t;
int n; int n;

View File

@ -50,6 +50,7 @@ extern "C" {
extern int enter_ship(struct unit *u, struct order *ord, int id, int report); extern int enter_ship(struct unit *u, struct order *ord, int id, int report);
extern void new_units(void); extern void new_units(void);
extern void defaultorders(void);
extern void quit(void); extern void quit(void);
extern void monthly_healing(void); extern void monthly_healing(void);
extern void renumber_factions(void); extern void renumber_factions(void);
@ -81,6 +82,11 @@ extern "C" {
extern int contact_cmd(struct unit *u, struct order *ord); extern int contact_cmd(struct unit *u, struct order *ord);
extern int guard_on_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 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 #ifdef __cplusplus
} }

View File

@ -72,9 +72,10 @@ attack_firesword(const troop * at, const struct weapon_type *wtype,
do { do {
dt = select_enemy(fi, 0, 1, SELECT_ADVANCE | SELECT_DISTANCE); dt = select_enemy(fi, 0, 1, SELECT_ADVANCE | SELECT_DISTANCE);
assert(dt.fighter);
--force; --force;
if (dt.fighter) {
killed += terminate(dt, *at, AT_SPELL, damage, 1); killed += terminate(dt, *at, AT_SPELL, damage, 1);
}
} while (force && killed < enemies); } while (force && killed < enemies);
if (casualties) if (casualties)
*casualties = killed; *casualties = killed;

View File

@ -438,7 +438,10 @@ double curse_geteffect(const curse * c)
int curse_geteffect_int(const curse * c) int curse_geteffect_int(const curse * c)
{ {
double effect = curse_geteffect(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; return (int)effect;
} }

View File

@ -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) static int res_changeperson(unit * u, const resource_type * rtype, int delta)
{ {
assert(rtype != NULL || !"not implemented"); assert(rtype != NULL || !"not implemented");
if (u->number + delta >=0) {
scale_number(u, u->number + delta); scale_number(u, u->number + delta);
} else {
scale_number(u, 0);
}
return u->number; return u->number;
} }
@ -1226,6 +1230,10 @@ void test_clear_resources(void)
void register_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_elves_only, "mod_elves_only");
register_function((pf_generic) mod_dwarves_only, "mod_dwarves_only"); register_function((pf_generic) mod_dwarves_only, "mod_dwarves_only");
register_function((pf_generic) res_changeitem, "changeitem"); register_function((pf_generic) res_changeitem, "changeitem");

View File

@ -2,11 +2,52 @@
#include <kernel/types.h> #include <kernel/types.h>
#include <kernel/item.h> #include <kernel/item.h>
#include <kernel/pool.h>
#include <kernel/unit.h>
#include <util/language.h> #include <util/language.h>
#include <util/functions.h>
#include <CuTest.h> #include <CuTest.h>
#include <tests.h> #include <tests.h>
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) void test_resource_type(CuTest * tc)
{ {
struct item_type *itype; struct item_type *itype;
@ -68,6 +109,8 @@ void test_findresourcetype(CuTest * tc)
CuSuite *get_item_suite(void) CuSuite *get_item_suite(void)
{ {
CuSuite *suite = CuSuiteNew(); 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_resource_type);
SUITE_ADD_TEST(suite, test_finditemtype); SUITE_ADD_TEST(suite, test_finditemtype);
SUITE_ADD_TEST(suite, test_findresourcetype); SUITE_ADD_TEST(suite, test_findresourcetype);

View File

@ -2743,6 +2743,7 @@ void magic(void)
continue; continue;
} }
if (u->thisorder != NULL) {
for (ord = u->orders; ord; ord = ord->next) { for (ord = u->orders; ord; ord = ord->next) {
if (get_keyword(ord) == K_CAST) { if (get_keyword(ord) == K_CAST) {
castorder *co = cast_cmd(u, ord); castorder *co = cast_cmd(u, ord);
@ -2755,6 +2756,7 @@ void magic(void)
} }
} }
} }
}
/* Da sich die Aura und Komponenten in der Zwischenzeit verändert /* Da sich die Aura und Komponenten in der Zwischenzeit verändert
* haben können und sich durch vorherige Sprüche das Zaubern * haben können und sich durch vorherige Sprüche das Zaubern

View File

@ -2697,12 +2697,13 @@ void follow_unit(unit * u)
attrib *a2 = a_find(u2->attribs, &at_follow); attrib *a2 = a_find(u2->attribs, &at_follow);
if (a2 != NULL) { if (a2 != NULL) {
unit *u3 = a2->data.v; unit *u3 = a2->data.v;
follow = (u3 && u2->region == u2->region); follow = (u3 && u2->region == u3->region);
} }
} }
if (follow) { if (follow) {
fset(u, UFL_FOLLOWING); fset(u, UFL_FOLLOWING);
fset(u2, UFL_FOLLOWED); fset(u2, UFL_FOLLOWED);
/* FOLLOW unit on a (potentially) moving unit prevents long orders */
set_order(&u->thisorder, NULL); set_order(&u->thisorder, NULL);
} }
} }

View File

@ -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) 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)) if (rtype == oldresourcetype[R_STONE] && (u_race(u)->flags & RCF_STONEGOLEM))
return (u->number * GOLEM_STONE); 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) int change_reservation(unit * u, const resource_type * rtype, int value)
{ {
struct reservation *res, **rp = &u->reservations; reservation *res, **rp = &u->reservations;
if (!value) if (!value)
return 0; return 0;
@ -120,7 +120,7 @@ int change_reservation(unit * u, const resource_type * rtype, int value)
rp = &(*rp)->next; rp = &(*rp)->next;
res = *rp; res = *rp;
if (!res) { if (!res) {
*rp = res = calloc(sizeof(struct reservation), 1); *rp = res = calloc(sizeof(reservation), 1);
res->type = rtype; res->type = rtype;
res->value = value; res->value = value;
} else if (res && res->value + value <= 0) { } 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; 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) while (*rp && (*rp)->type != rtype)
rp = &(*rp)->next; rp = &(*rp)->next;
@ -143,7 +143,7 @@ static int new_set_resvalue(unit * u, const resource_type * rtype, int value)
if (!res) { if (!res) {
if (!value) if (!value)
return 0; return 0;
*rp = res = calloc(sizeof(struct reservation), 1); *rp = res = calloc(sizeof(reservation), 1);
res->type = rtype; res->type = rtype;
res->value = value; res->value = value;
} else if (res && value <= 0) { } 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; 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;
}

View File

@ -54,11 +54,7 @@ extern "C" {
int change_reservation(struct unit *u, const struct resource_type *res, int change_reservation(struct unit *u, const struct resource_type *res,
int value); int value);
int reserve_cmd(struct unit *u, struct order *ord); int set_resvalue(struct unit * u, const struct resource_type * rtype, int value);
/** init_pool
* initialisiert den regionalen Pool.
*/
#ifdef __cplusplus #ifdef __cplusplus
} }

View File

@ -1016,6 +1016,16 @@ void region_setresource(region * r, const resource_type * rtype, int value)
rsetpeasants(r, value); rsetpeasants(r, value);
else if (rtype == rt_find("horse")) else if (rtype == rt_find("horse"))
rsethorses(r, value); 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) { if (r->land && r->land->ownership) {
return r->land->ownership->since_turn; return r->land->ownership->since_turn;
} }
return -1; return INT_MIN;
} }
bool is_mourning(const region * r, int in_turn) bool is_mourning(const region * r, int in_turn)

View File

@ -82,6 +82,10 @@ void terraform_resources(region * r)
{ {
int i; int i;
const terrain_type *terrain = r->terrain; 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) if (terrain->production == NULL)
return; return;
@ -94,10 +98,11 @@ void terraform_resources(region * r)
if (rm->type->rtype == rtype) if (rm->type->rtype == rtype)
break; break;
} }
if (rm) if (rm) {
continue; continue;
}
if (chance(production->chance)) { if (terraform_all || chance(production->chance)) {
add_resource(r, dice_rand(production->startlevel), add_resource(r, dice_rand(production->startlevel),
dice_rand(production->base), dice_rand(production->divisor), dice_rand(production->base), dice_rand(production->divisor),
production->type); production->type);

View File

@ -822,14 +822,18 @@ void leave_building(unit * u)
bool can_leave(unit * u) bool can_leave(unit * u)
{ {
static int gamecookie = -1;
static int rule_leave = -1; static int rule_leave = -1;
if (!u->building) { if (!u->building) {
return true; 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); rule_leave = get_param_int(global.parameters, "rules.move.owner_leave", 0);
} }
if (rule_leave && u->building && u == building_owner(u->building)) { if (rule_leave && u->building && u == building_owner(u->building)) {
return false; return false;
} }

View File

@ -71,6 +71,12 @@ extern "C" {
extern int maxheroes(const struct faction *f); extern int maxheroes(const struct faction *f);
extern int countheroes(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 { typedef struct unit {
struct unit *next; /* needs to be first entry, for region's unitlist */ struct unit *next; /* needs to be first entry, for region's unitlist */
struct unit *nextF; /* nächste Einheit der Partei */ struct unit *nextF; /* nächste Einheit der Partei */
@ -90,11 +96,7 @@ extern "C" {
short skill_size; short skill_size;
struct skill *skills; struct skill *skills;
struct item *items; struct item *items;
struct reservation { reservation *reservations;
struct reservation *next;
const struct resource_type *type;
int value;
} *reservations;
/* orders */ /* orders */
struct order *orders; struct order *orders;

View File

@ -180,15 +180,15 @@ void test_create_world(void)
terrain_type *t_plain, *t_ocean; terrain_type *t_plain, *t_ocean;
region *island[2]; region *island[2];
int i; int i;
item_type * itype; const char * names[] = { "horse", "horse_p", "boat", "boat_p", "iron", "iron_p", "stone", "stone_p" };
const char * names[] = { "horse", "horse_p", "boat", "boat_p" };
make_locale("de"); make_locale("de");
init_resources(); init_resources();
assert(!olditemtype[I_HORSE]); assert(!olditemtype[I_HORSE]);
itype = test_create_itemtype(names); olditemtype[I_HORSE] = test_create_itemtype(names+0);
olditemtype[I_HORSE] = itype; 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 = test_create_terrain("plain", LAND_REGION | FOREST_REGION | WALK_INTO | CAVALRY_REGION);
t_plain->size = 1000; t_plain->size = 1000;

View File

@ -283,7 +283,7 @@ static const char *parse_string(opstack ** stack, const char *in,
if (ic == NULL) if (ic == NULL)
return NULL; return NULL;
c = (char *)opop_v(stack); c = (char *)opop_v(stack);
bytes = (int)strlcpy(oc, c, size); bytes = (int)c?strlcpy(oc, c, size):0;
if (bytes < (int)size) if (bytes < (int)size)
oc += bytes; oc += bytes;
else else