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