diff --git a/core/res/messages.xml b/core/res/messages.xml
index e87c4900f..37b5acafa 100644
--- a/core/res/messages.xml
+++ b/core/res/messages.xml
@@ -8305,14 +8305,6 @@
"Meeoooooow..."
-
-
-
-
- "Die Götter segnen $unit($unit) mit der richtigen Rasse."
- "The gods are blessing $unit($unit) with the correct race."
-
-
diff --git a/s/runtests b/s/runtests
index 35934997b..bacceca0e 100755
--- a/s/runtests
+++ b/s/runtests
@@ -18,4 +18,5 @@ fi
$ROOT/$BIN_DIR/eressea/test_eressea
cd $ROOT
$ROOT/$BIN_DIR/eressea/eressea -v0 scripts/runtests.lua
+grep ERROR eressea.log
cd $OLDWPD
diff --git a/scripts/tests/e3a.lua b/scripts/tests/e3a.lua
index d37cae476..4ddeddc1c 100644
--- a/scripts/tests/e3a.lua
+++ b/scripts/tests/e3a.lua
@@ -429,7 +429,7 @@ function test_canoe_passes_through_land()
end
function test_give_50_percent_of_money()
- local r = region.create(0, 0, "plain")
+ local r = region.create(0, 0, "plain")
local u1 = unit.create(faction.create("noreply@eressea.de", "human", "de"), r, 1)
local u2 = unit.create(faction.create("noreply@eressea.de", "orc", "de"), r, 1)
u1.faction.age = 10
diff --git a/se/eressea.vpj b/se/eressea.vpj
index 8f9b39b6c..78271d8af 100644
--- a/se/eressea.vpj
+++ b/se/eressea.vpj
@@ -246,6 +246,7 @@
+
@@ -403,6 +404,7 @@
+
diff --git a/se/tests.vpj b/se/tests.vpj
index 9f4e1362e..f40c0151c 100644
--- a/se/tests.vpj
+++ b/se/tests.vpj
@@ -246,6 +246,7 @@
+
diff --git a/src/bind_region.c b/src/bind_region.c
index 7606a266d..5db39b6fc 100644
--- a/src/bind_region.c
+++ b/src/bind_region.c
@@ -62,6 +62,22 @@ static int tolua_region_get_id(lua_State * L)
return 1;
}
+static int tolua_region_get_blocked(lua_State * L)
+{
+ region *self = (region *)tolua_tousertype(L, 1, 0);
+ lua_pushboolean(L, (self->flags&RF_BLOCKED)!=0);
+ return 1;
+}
+
+static int tolua_region_set_blocked(lua_State * L)
+{
+ region *self = (region *)tolua_tousertype(L, 1, 0);
+ bool flag = !!tolua_toboolean(L, 2, 1);
+ if (flag) self->flags |= BLD_WORKING;
+ else self->flags &= ~BLD_WORKING;
+ return 0;
+}
+
static int tolua_region_get_x(lua_State * L)
{
region *self = (region *) tolua_tousertype(L, 1, 0);
@@ -652,6 +668,9 @@ void tolua_region_open(lua_State * L)
tolua_function(L, TOLUA_CAST "destroy", tolua_region_destroy);
tolua_function(L, TOLUA_CAST "__tostring", tolua_region_tostring);
+ /* flags */
+ tolua_variable(L, TOLUA_CAST "blocked", tolua_region_get_blocked, tolua_region_set_blocked);
+
tolua_variable(L, TOLUA_CAST "id", tolua_region_get_id, NULL);
tolua_variable(L, TOLUA_CAST "x", tolua_region_get_x, NULL);
tolua_variable(L, TOLUA_CAST "y", tolua_region_get_y, NULL);
diff --git a/src/build.h b/src/build.h
index 768ebf8c4..252ef3b18 100644
--- a/src/build.h
+++ b/src/build.h
@@ -1,3 +1,3 @@
#define VERSION_MAJOR 3
#define VERSION_MINOR 0
-#define VERSION_BUILD 677
+#define VERSION_BUILD 678
diff --git a/src/economy.c b/src/economy.c
index 79ca4022c..fb70e4e13 100644
--- a/src/economy.c
+++ b/src/economy.c
@@ -372,13 +372,19 @@ static int do_recruiting(recruitment * recruits, int available)
use_pooled(u, get_resourcetype(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) {
- recruited += dec;
+ if (u->number == 0 && fval(u, UFL_DEAD)) {
+ /* unit is empty, dead, and cannot recruit */
+ number = 0;
}
+ if (number > 0) {
+ add_recruits(u, number, req->qty);
+ dec = (int)(number * multi);
+ if ((rc->ec_flags & ECF_REC_ETHEREAL) == 0) {
+ recruited += dec;
+ }
- get -= dec;
+ get -= dec;
+ }
}
}
return recruited;
@@ -390,8 +396,7 @@ static void feedback_give_not_allowed(unit * u, order * ord)
""));
}
-static bool check_give(unit * u, unit * u2, const item_type * itype,
- int mask)
+static bool can_give(const unit * u, const unit * u2, const item_type * itype, int mask)
{
if (u2) {
if (u->faction != u2->faction) {
@@ -700,6 +705,13 @@ int give_control_cmd(unit * u, order * ord)
return 0;
}
+message *check_give(const unit *u, const unit *u2, order * ord) {
+ if (!can_give(u, u2, NULL, GIVE_ALLITEMS)) {
+ return msg_feedback(u, ord, "feedback_give_forbidden", "");
+ }
+ return 0;
+}
+
static void give_cmd(unit * u, order * ord)
{
region *r = u->region;
@@ -709,6 +721,7 @@ static void give_cmd(unit * u, order * ord)
const item_type *itype;
param_t p;
plane *pl;
+ message *msg;
init_tokens(ord);
skip_token();
@@ -729,9 +742,10 @@ static void give_cmd(unit * u, order * ord)
return;
}
- if (!check_give(u, u2, NULL, GIVE_ALLITEMS)) {
- feedback_give_not_allowed(u, ord);
- return;
+ msg = check_give(u, u2, ord);
+ if (msg) {
+ ADDMSG(&u->faction->msgs, msg);
+ return;
}
/* Damit Tarner nicht durch die Fehlermeldung enttarnt werden können */
@@ -773,7 +787,7 @@ static void give_cmd(unit * u, order * ord)
msg_feedback(u, ord, "race_nogive", "race", u_race(u)));
return;
}
- if (!check_give(u, u2, NULL, GIVE_HERBS)) {
+ if (!can_give(u, u2, NULL, GIVE_HERBS)) {
feedback_give_not_allowed(u, ord);
return;
}
@@ -831,7 +845,7 @@ static void give_cmd(unit * u, order * ord)
else if (p == P_ANY) {
const char *s;
- if (!check_give(u, u2, NULL, GIVE_ALLITEMS)) {
+ if (!can_give(u, u2, NULL, GIVE_ALLITEMS)) {
feedback_give_not_allowed(u, ord);
return;
}
@@ -888,7 +902,7 @@ static void give_cmd(unit * u, order * ord)
if (itype != NULL) {
item *i = *i_find(&u->items, itype);
if (i != NULL) {
- if (check_give(u, u2, itype, 0)) {
+ if (can_give(u, u2, itype, 0)) {
n = i->number - get_reservation(u, itype->rtype);
give_item(n, itype, u, u2, ord);
} else {
@@ -941,7 +955,7 @@ static void give_cmd(unit * u, order * ord)
itype = finditemtype(s, u->faction->locale);
if (itype != NULL) {
- if (check_give(u, u2, itype, 0)) {
+ if (can_give(u, u2, itype, 0)) {
give_item(n, itype, u, u2, ord);
} else {
feedback_give_not_allowed(u, ord);
@@ -2747,6 +2761,24 @@ static int max_skill(region * r, faction * f, skill_t sk)
return w;
}
+message * check_steal(const unit * u, struct order *ord) {
+ plane *pl;
+
+ if (fval(u_race(u), RCF_NOSTEAL)) {
+ return msg_feedback(u, ord, "race_nosteal", "race", u_race(u));
+ }
+
+ if (fval(u->region->terrain, SEA_REGION) && u_race(u) != get_race(RC_AQUARIAN)) {
+ return msg_feedback(u, ord, "error_onlandonly", "");
+ }
+
+ pl = rplane(u->region);
+ if (pl && fval(pl, PFL_NOATTACK)) {
+ return msg_feedback(u, ord, "error270", "");
+ }
+ return 0;
+}
+
static void steal_cmd(unit * u, struct order *ord, request ** stealorders)
{
const resource_type *rring = get_resourcetype(R_RING_OF_NIMBLEFINGER);
@@ -2756,27 +2788,15 @@ static void steal_cmd(unit * u, struct order *ord, request ** stealorders)
unit *u2 = NULL;
region *r = u->region;
faction *f = NULL;
- plane *pl;
+ message * msg;
assert(skill_enabled(SK_PERCEPTION) && skill_enabled(SK_STEALTH));
- if (!fval(u_race(u), RCF_CANSTEAL)) {
- ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "race_nosteal", "race",
- u_race(u)));
- return;
+ msg = check_steal(u, ord);
+ if (msg) {
+ ADDMSG(&u->faction->msgs, msg);
+ return;
}
-
- if (fval(r->terrain, SEA_REGION) && u_race(u) != get_race(RC_AQUARIAN)) {
- ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "error_onlandonly", ""));
- return;
- }
-
- pl = rplane(r);
- if (pl && fval(pl, PFL_NOATTACK)) {
- cmistake(u, ord, 270, MSG_INCOME);
- return;
- }
-
init_tokens(ord);
skip_token();
id = read_unitid(u->faction, r);
diff --git a/src/economy.h b/src/economy.h
index 8b44df380..4ee69ea4b 100644
--- a/src/economy.h
+++ b/src/economy.h
@@ -57,6 +57,9 @@ extern "C" {
extern int give_control_cmd(struct unit *u, struct order *ord);
extern void give_control(struct unit * u, struct unit * u2);
+ struct message * check_steal(const struct unit * u, struct order *ord);
+ struct message * check_give(const struct unit * u, const struct unit * u2, struct order *ord);
+
#ifdef __cplusplus
}
#endif
diff --git a/src/economy.test.c b/src/economy.test.c
index 61294b1da..395f97a84 100644
--- a/src/economy.test.c
+++ b/src/economy.test.c
@@ -1,61 +1,173 @@
#include
+#include
#include
#include "economy.h"
+#include
#include
+#include
#include
#include
#include
+#include
#include
#include
static void test_give_control_building(CuTest * tc)
{
- unit *u1, *u2;
- building *b;
- struct faction *f;
- region *r;
+ unit *u1, *u2;
+ building *b;
+ struct faction *f;
+ region *r;
- test_cleanup();
- test_create_world();
- f = test_create_faction(0);
- r = findregion(0, 0);
- b = test_create_building(r, 0);
- u1 = test_create_unit(f, r);
- u_set_building(u1, b);
- u2 = test_create_unit(f, r);
- u_set_building(u2, b);
- CuAssertPtrEquals(tc, u1, building_owner(b));
- give_control(u1, u2);
- CuAssertPtrEquals(tc, u2, building_owner(b));
+ test_cleanup();
+ test_create_world();
+ f = test_create_faction(0);
+ r = findregion(0, 0);
+ b = test_create_building(r, 0);
+ u1 = test_create_unit(f, r);
+ u_set_building(u1, b);
+ u2 = test_create_unit(f, r);
+ u_set_building(u2, b);
+ CuAssertPtrEquals(tc, u1, building_owner(b));
+ give_control(u1, u2);
+ CuAssertPtrEquals(tc, u2, building_owner(b));
+ test_cleanup();
}
static void test_give_control_ship(CuTest * tc)
{
- unit *u1, *u2;
- ship *sh;
- struct faction *f;
- region *r;
+ unit *u1, *u2;
+ ship *sh;
+ struct faction *f;
+ region *r;
- test_cleanup();
- test_create_world();
- f = test_create_faction(0);
- r = findregion(0, 0);
- sh = test_create_ship(r, 0);
- u1 = test_create_unit(f, r);
- u_set_ship(u1, sh);
- u2 = test_create_unit(f, r);
- u_set_ship(u2, sh);
- CuAssertPtrEquals(tc, u1, ship_owner(sh));
- give_control(u1, u2);
- CuAssertPtrEquals(tc, u2, ship_owner(sh));
+ test_cleanup();
+ test_create_world();
+ f = test_create_faction(0);
+ r = findregion(0, 0);
+ sh = test_create_ship(r, 0);
+ u1 = test_create_unit(f, r);
+ u_set_ship(u1, sh);
+ u2 = test_create_unit(f, r);
+ u_set_ship(u2, sh);
+ CuAssertPtrEquals(tc, u1, ship_owner(sh));
+ give_control(u1, u2);
+ CuAssertPtrEquals(tc, u2, ship_owner(sh));
+ test_cleanup();
+}
+
+struct steal {
+ struct unit *u;
+ struct region *r;
+ struct faction *f;
+};
+
+static void setup_steal(struct steal *env, terrain_type *ter, race *rc) {
+ env->r = test_create_region(0, 0, ter);
+ env->f = test_create_faction(rc);
+ env->u = test_create_unit(env->f, env->r);
+}
+
+static void test_steal_okay(CuTest * tc) {
+ struct steal env;
+ race *rc;
+ terrain_type *ter;
+
+ test_cleanup();
+ ter = test_create_terrain("plain", LAND_REGION);
+ rc = test_create_race("human");
+ rc->flags = 0;
+ setup_steal(&env, ter, rc);
+ CuAssertPtrEquals(tc, 0, check_steal(env.u, 0));
+ test_cleanup();
+}
+
+static void test_steal_nosteal(CuTest * tc) {
+ struct steal env;
+ race *rc;
+ terrain_type *ter;
+ message *msg;
+
+ test_cleanup();
+ ter = test_create_terrain("plain", LAND_REGION);
+ rc = test_create_race("human");
+ rc->flags = RCF_NOSTEAL;
+ setup_steal(&env, ter, rc);
+ CuAssertPtrNotNull(tc, msg = check_steal(env.u, 0));
+ msg_release(msg);
+ test_cleanup();
+}
+
+static void test_steal_ocean(CuTest * tc) {
+ struct steal env;
+ race *rc;
+ terrain_type *ter;
+ message *msg;
+
+ test_cleanup();
+ ter = test_create_terrain("ocean", SEA_REGION);
+ rc = test_create_race("human");
+ setup_steal(&env, ter, rc);
+ CuAssertPtrNotNull(tc, msg = check_steal(env.u, 0));
+ msg_release(msg);
+ test_cleanup();
+}
+
+struct give {
+ struct unit *src, *dst;
+ struct region *r;
+ struct faction *f1, *f2;
+};
+
+static void setup_give(struct give *env) {
+ terrain_type *ter = test_create_terrain("plain", LAND_REGION);
+ env->r = test_create_region(0, 0, ter);
+ env->src = test_create_unit(env->f1, env->r);
+ env->dst = test_create_unit(env->f2, env->r);
+}
+
+static void test_give_okay(CuTest * tc) {
+ struct give env;
+ struct race * rc;
+
+ test_cleanup();
+ rc = test_create_race("human");
+ env.f2 = env.f1 = test_create_faction(rc);
+ setup_give(&env);
+
+ set_param(&global.parameters, "rules.give", "0");
+ CuAssertPtrEquals(tc, 0, check_give(env.src, env.dst, 0));
+ test_cleanup();
+}
+
+static void test_give_denied_by_rules(CuTest * tc) {
+ struct give env;
+ struct race * rc;
+ struct message *msg;
+
+ test_cleanup();
+ rc = test_create_race("human");
+ env.f1 = test_create_faction(rc);
+ env.f2 = test_create_faction(rc);
+ setup_give(&env);
+
+ set_param(&global.parameters, "rules.give", "0");
+ CuAssertPtrNotNull(tc, msg=check_give(env.src, env.dst, 0));
+ msg_release(msg);
+ test_cleanup();
}
CuSuite *get_economy_suite(void)
{
- CuSuite *suite = CuSuiteNew();
- SUITE_ADD_TEST(suite, test_give_control_building);
- SUITE_ADD_TEST(suite, test_give_control_ship);
- return suite;
+ CuSuite *suite = CuSuiteNew();
+ SUITE_ADD_TEST(suite, test_give_control_building);
+ SUITE_ADD_TEST(suite, test_give_control_ship);
+ SUITE_ADD_TEST(suite, test_steal_okay);
+ SUITE_ADD_TEST(suite, test_steal_ocean);
+ SUITE_ADD_TEST(suite, test_steal_nosteal);
+ SUITE_ADD_TEST(suite, test_give_okay);
+ SUITE_ADD_TEST(suite, test_give_denied_by_rules);
+ return suite;
}
diff --git a/src/eressea.c b/src/eressea.c
index 16e9763f3..4900693a3 100755
--- a/src/eressea.c
+++ b/src/eressea.c
@@ -49,11 +49,10 @@ void game_done(void)
void game_init(void)
{
- kernel_init();
+ kernel_init();
register_triggers();
register_xmas();
- register_reports();
register_nr();
register_cr();
diff --git a/src/give.c b/src/give.c
index bacae343f..3a47957dc 100644
--- a/src/give.c
+++ b/src/give.c
@@ -95,21 +95,19 @@ static bool limited_give(const item_type * type)
int give_quota(const unit * src, const unit * dst, const item_type * type,
int n)
{
- static float divisor = -1;
+ float divisor;
- if (divisor == 0 || !limited_give(type)) {
+ if (!limited_give(type)) {
return n;
}
if (dst && src && src->faction != dst->faction) {
- if (divisor < 0) {
divisor = get_param_flt(global.parameters, "rules.items.give_divisor", 1);
assert(divisor == 0 || divisor >= 1);
- }
- if (divisor >= 1) {
- /* predictable > correct: */
- int x = (int)(n / divisor);
- return x;
- }
+ if (divisor >= 1) {
+ /* predictable > correct: */
+ int x = (int)(n / divisor);
+ return x;
+ }
}
return n;
}
diff --git a/src/kernel/battle.c b/src/kernel/battle.c
index d678dfa7c..9b9319bb6 100644
--- a/src/kernel/battle.c
+++ b/src/kernel/battle.c
@@ -2661,6 +2661,7 @@ static void aftermath(battle * b)
int dead = dead_fighters(df);
int sum_hp = 0;
int n;
+ int flags = 0;
for (n = 0; n != df->alive; ++n) {
if (df->person[n].hp > 0) {
@@ -2669,11 +2670,16 @@ static void aftermath(battle * b)
}
snumber += du->number;
if (relevant) {
- int flags = UFL_LONGACTION | UFL_NOTMOVING;
+ flags = UFL_LONGACTION | UFL_NOTMOVING;
if (du->status == ST_FLEE) {
flags -= UFL_NOTMOVING;
}
- fset(du, flags);
+ }
+ if (df->alive == 0) {
+ flags |= UFL_DEAD;
+ }
+ if (flags) {
+ fset(du, flags);
}
if (sum_hp + df->run.hp < du->hp) {
/* someone on the ship got damaged, damage the ship */
@@ -4057,70 +4063,6 @@ static bool start_battle(region * r, battle ** bp)
return fighting;
}
-static void battle_stats(FILE * F, battle * b)
-{
- typedef struct stat_info {
- struct stat_info *next;
- const weapon_type *wtype;
- int level;
- int number;
- } stat_info;
- side *s;
-
- for (s = b->sides; s != b->sides + b->nsides; ++s) {
- fighter *df;
- stat_info *stats = NULL, *stat;
-
- for (df = s->fighters; df; df = df->next) {
- unit *du = df->unit;
- troop dt;
- stat_info *slast = NULL;
-
- dt.fighter = df;
- for (dt.index = 0; dt.index != du->number; ++dt.index) {
- weapon *wp = preferred_weapon(dt, true);
- int level = wp ? wp->attackskill : 0;
- const weapon_type *wtype = wp ? wp->type : NULL;
- stat_info **slist = &stats;
-
- if (slast && slast->wtype == wtype && slast->level == level) {
- ++slast->number;
- continue;
- }
- while (*slist && (*slist)->wtype != wtype) {
- slist = &(*slist)->next;
- }
- while (*slist && (*slist)->wtype == wtype && (*slist)->level > level) {
- slist = &(*slist)->next;
- }
- stat = *slist;
- if (stat == NULL || stat->wtype != wtype || stat->level != level) {
- stat = (stat_info*)calloc(1, sizeof(stat_info));
- stat->wtype = wtype;
- stat->level = level;
- stat->next = *slist;
- *slist = stat;
- }
- slast = stat;
- ++slast->number;
- }
- }
-
- fprintf(F, "##STATS## Heer %u - %s:\n", army_index(s),
- factionname(s->faction));
- for (stat = stats; stat != NULL; stat = stat->next) {
- fprintf(F, "%s %u : %u\n",
- stat->wtype ? stat->wtype->itype->rtype->_name[0] : "none", stat->level,
- stat->number);
- }
- while (stats) {
- stat_info *stat = stats;
- stats = stat->next;
- free(stat);
- }
- }
-}
-
/** execute one round of attacks
* fig->fighting is used to determine who attacks, not fig->alive, since
* the latter may be influenced by attacks that already took place.
@@ -4289,9 +4231,6 @@ void do_battle(region * r)
b->has_tactics_turn = false;
}
- if (b->region->flags & RF_COMBATDEBUG)
- battle_stats(bdebug, b);
-
/* PRECOMBATSPELLS */
do_combatmagic(b, DO_PRECOMBATSPELL);
diff --git a/src/kernel/config.c b/src/kernel/config.c
index 4d0fcacfa..01fb7a7ee 100644
--- a/src/kernel/config.c
+++ b/src/kernel/config.c
@@ -46,6 +46,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
#include "plane.h"
#include "pool.h"
#include "race.h"
+#include "reports.h"
#include "region.h"
#include "save.h"
#include "ship.h"
@@ -2744,8 +2745,13 @@ void attrib_init(void)
void kernel_init(void)
{
- attrib_init();
- translation_init();
+ register_reports();
+ if (!mt_find("missing_message")) {
+ mt_register(mt_new_va("missing_message", "name:string", 0));
+ mt_register(mt_new_va("missing_feedback", "unit:unit", "region:region", "command:order", "name:string", 0));
+ }
+ attrib_init();
+ translation_init();
}
static order * defaults[MAXLOCALES];
diff --git a/src/kernel/jsonconf.c b/src/kernel/jsonconf.c
index a73936afd..829e93113 100644
--- a/src/kernel/jsonconf.c
+++ b/src/kernel/jsonconf.c
@@ -106,8 +106,9 @@ static void json_maintenance_i(cJSON *json, maintenance *mt) {
mt->flags = json_flags(child, flags);
}
else {
- log_error_n("maintenance contains unknown attribute %s", child->string);
+ log_error_n("maintenance contains unknown array %s", child->string);
}
+ break;
default:
log_error_n("maintenance contains unknown attribute %s", child->string);
}
@@ -325,15 +326,19 @@ static void json_ship(cJSON *json, ship_type *st) {
static void json_race(cJSON *json, race *rc) {
cJSON *child;
const char *flags[] = {
- "playerrace", "killpeasants", "scarepeasants",
- "cansteal", "moverandom", "cannotmove",
+ "npc", "killpeasants", "scarepeasants",
+ "nosteal", "moverandom", "cannotmove",
"learn", "fly", "swim", "walk", "nolearn",
"noteach", "horse", "desert",
"illusionary", "absorbpeasants", "noheal",
"noweapons", "shapeshift", "", "undead", "dragon",
"coastal", "", "cansail", 0
};
- if (json->type!=cJSON_Object) {
+ const char *ecflags[] = {
+ "", "giveitem", "giveperson",
+ "giveunit", "getitem", 0
+ };
+ if (json->type != cJSON_Object) {
log_error_n("race %s is not a json object: %d", json->string, json->type);
return;
}
@@ -380,6 +385,7 @@ static void json_race(cJSON *json, race *rc) {
case cJSON_Array:
if (strcmp(child->string, "flags")==0) {
rc->flags = json_flags(child, flags);
+ rc->ec_flags = json_flags(child, ecflags);
}
break;
}
diff --git a/src/kernel/jsonconf.test.c b/src/kernel/jsonconf.test.c
index 932b88ac0..5083f8e73 100644
--- a/src/kernel/jsonconf.test.c
+++ b/src/kernel/jsonconf.test.c
@@ -16,29 +16,41 @@
#include
#include
-static void check_flag(CuTest *tc, const char *name, int flag) {
+static const struct race * race_with_flag(const char * name) {
char data[1024];
- const struct race *rc;
cJSON *json;
sprintf(data, "{\"races\" : { \"orc\": { \"speed\" : 1, \"flags\" : [ \"%s\"] }}}", name);
json = cJSON_Parse(data);
free_races();
json_config(json);
- rc = rc_find("orc");
+ return rc_find("orc");
+}
+
+static void check_ec_flag(CuTest *tc, const char *name, int flag) {
+ const struct race *rc = race_with_flag(name);
+ CuAssertPtrNotNull(tc, rc);
+ CuAssertIntEquals(tc, flag, rc->ec_flags);
+}
+
+static void check_flag(CuTest *tc, const char *name, int flag) {
+ const struct race *rc = race_with_flag(name);
CuAssertPtrNotNull(tc, rc);
CuAssertIntEquals(tc, flag, rc->flags);
- CuAssertDblEquals(tc, 1.0f, rc->speed, 0.0f);
}
static void test_flags(CuTest *tc) {
- check_flag(tc, "playerrace", RCF_PLAYERRACE);
+ check_flag(tc, "npc", RCF_NPC);
check_flag(tc, "scarepeasants", RCF_SCAREPEASANTS);
- check_flag(tc, "cansteal", RCF_CANSTEAL);
+ check_flag(tc, "nosteal", RCF_NOSTEAL);
check_flag(tc, "noheal", RCF_NOHEAL);
check_flag(tc, "undead", RCF_UNDEAD);
check_flag(tc, "dragon", RCF_DRAGON);
check_flag(tc, "fly", RCF_FLY);
+ check_ec_flag(tc, "getitem", GETITEM);
+ check_ec_flag(tc, "giveitem", GIVEITEM);
+ check_ec_flag(tc, "giveperson", GIVEPERSON);
+ check_ec_flag(tc, "giveunit", GIVEUNIT);
test_cleanup();
}
@@ -56,7 +68,7 @@ static void test_races(CuTest * tc)
"\"capacity\" : 4,"
"\"hp\" : 5,"
"\"ac\" : 6,"
- "\"flags\" : [ \"playerrace\", \"walk\", \"undead\" ]"
+ "\"flags\" : [ \"npc\", \"walk\", \"undead\" ]"
"}}}";
cJSON *json = cJSON_Parse(data);
const struct race *rc;
@@ -70,7 +82,7 @@ static void test_races(CuTest * tc)
CuAssertPtrNotNull(tc, races);
rc = rc_find("orc");
CuAssertPtrNotNull(tc, rc);
- CuAssertIntEquals(tc, RCF_PLAYERRACE|RCF_WALK|RCF_UNDEAD, rc->flags);
+ CuAssertIntEquals(tc, RCF_NPC|RCF_WALK|RCF_UNDEAD, rc->flags);
CuAssertStrEquals(tc, "1d4", rc->def_damage);
CuAssertDblEquals(tc, 1.0, rc->magres, 0.0);
CuAssertDblEquals(tc, 2.0, rc->maxaura, 0.0);
diff --git a/src/kernel/race.h b/src/kernel/race.h
index 3f83e6a53..62793bb12 100644
--- a/src/kernel/race.h
+++ b/src/kernel/race.h
@@ -183,11 +183,11 @@ extern "C" {
const struct weapon_type *);
void free_races(void);
-/* Flags */
-#define RCF_PLAYERRACE (1<<0) /* can be played by a player. */
-#define RCF_KILLPEASANTS (1<<1) /* Töten Bauern. Dämonen werden nicht über dieses Flag, sondern in randenc() behandelt. */
-#define RCF_SCAREPEASANTS (1<<2)
-#define RCF_CANSTEAL (1<<3)
+/* Flags. Do not reorder these without changing json_race() in jsonconf.c */
+#define RCF_NPC (1<<0) /* cannot be the race for a player faction (and other limits?) */
+#define RCF_KILLPEASANTS (1<<1) /* a monster that eats peasants */
+#define RCF_SCAREPEASANTS (1<<2) /* a monster that scares peasants out of the hex */
+#define RCF_NOSTEAL (1<<3) /* this race has high stealth, but is not allowed to steal */
#define RCF_MOVERANDOM (1<<4)
#define RCF_CANNOTMOVE (1<<5)
#define RCF_LEARN (1<<6) /* Lernt automatisch wenn struct faction == 0 */
@@ -238,7 +238,7 @@ extern "C" {
#define omniscient(f) ((f)->race==get_race(RC_ILLUSION) || (f)->race==get_race(RC_TEMPLATE))
-#define playerrace(rc) (fval((rc), RCF_PLAYERRACE))
+#define playerrace(rc) (!fval((rc), RCF_NPC))
#define dragonrace(rc) ((rc) == get_race(RC_FIREDRAGON) || (rc) == get_race(RC_DRAGON) || (rc) == get_race(RC_WYRM) || (rc) == get_race(RC_BIRTHDAYDRAGON))
#define humanoidrace(rc) (fval((rc), RCF_UNDEAD) || (rc)==get_race(RC_DRACOID) || playerrace(rc))
#define illusionaryrace(rc) (fval(rc, RCF_ILLUSIONARY))
diff --git a/src/kernel/region.h b/src/kernel/region.h
index d427dd5f2..1e5493ad3 100644
--- a/src/kernel/region.h
+++ b/src/kernel/region.h
@@ -27,41 +27,38 @@ extern "C" {
#include "direction.h"
/* FAST_CONNECT: regions are directly connected to neighbours, saves doing
- a hash-access each time a neighbour is needed */
+ a hash-access each time a neighbour is needed, 6 extra pointers per hex */
#define FAST_CONNECT
-#define RF_CHAOTIC (1<<0)
-#define RF_MALLORN (1<<1)
-#define RF_BLOCKED (1<<2)
+#define RF_CHAOTIC (1<<0) /* persistent */
+#define RF_MALLORN (1<<1) /* persistent */
+#define RF_BLOCKED (1<<2) /* persistent */
-#define RF_BLOCK_NORTHWEST (1<<3)
-#define RF_BLOCK_NORTHEAST (1<<4)
-#define RF_BLOCK_EAST (1<<5)
-#define RF_BLOCK_SOUTHEAST (1<<6)
-#define RF_BLOCK_SOUTHWEST (1<<7)
-#define RF_BLOCK_WEST (1<<8)
+#define RF_UNUSED_3 (1<<3)
+#define RF_UNUSED_4 (1<<4)
+#define RF_UNUSED_5 (1<<5)
+#define RF_UNUSED_6 (1<<6)
+#define RF_UNUSED_7 (1<<7)
+#define RF_UNUSED_8 (1<<8)
-#define RF_ENCOUNTER (1<<9)
-#define RF_MIGRATION (1<<10)
-#define RF_UNUSED_1 (1<<11)
-#define RF_ORCIFIED (1<<12)
-#define RF_CURSED (1<<13)
+#define RF_ENCOUNTER (1<<9) /* persistent */
+#define RF_MAPPER_HIGHLIGHT (1<<10)
+#define RF_LIGHTHOUSE (1<<11) /* this region may contain a lighthouse */
+#define RF_ORCIFIED (1<<12) /* persistent */
+#define RF_MIGRATION (1<<13)
- /* debug flags */
-#define RF_COMBATDEBUG (1<<14)
-#define RF_MAPPER_HIGHLIGHT (1<<14) /* only used by mapper, not stored */
-#define RF_LIGHTHOUSE (1<<15) /* this region may contain a lighthouse */
+#define RF_UNUSED_14 (1<<14)
+#define RF_UNUSED_15 (1<<15)
+#define RF_UNUSED_16 (1<<16)
#define RF_SELECT (1<<17)
#define RF_MARK (1<<18)
-
-/* flags that speed up attribute access: */
#define RF_TRAVELUNIT (1<<19)
-#define RF_GUARDED (1<<20)
+#define RF_GUARDED (1<<20) /* persistent */
#define RF_ALL 0xFFFFFF
-#define RF_SAVEMASK (RF_GUARDED|RF_CHAOTIC|RF_MALLORN|RF_BLOCKED|RF_BLOCK_NORTHWEST|RF_BLOCK_NORTHEAST|RF_BLOCK_EAST|RF_BLOCK_SOUTHEAST|RF_BLOCK_SOUTHWEST|RF_BLOCK_WEST|RF_ENCOUNTER|RF_ORCIFIED)
+#define RF_SAVEMASK (RF_CHAOTIC|RF_MALLORN|RF_BLOCKED|RF_ENCOUNTER|RF_ORCIFIED|RF_GUARDED)
struct message;
struct message_list;
struct rawmaterial;
diff --git a/src/kernel/unit.c b/src/kernel/unit.c
index ae2d9018c..55e5e4a91 100644
--- a/src/kernel/unit.c
+++ b/src/kernel/unit.c
@@ -1214,8 +1214,8 @@ bool has_skill(const unit * u, skill_t sk)
static int item_invis(const unit *u) {
const struct resource_type *rring = get_resourcetype(R_RING_OF_INVISIBILITY);
const struct resource_type *rsphere = get_resourcetype(R_SPHERE_OF_INVISIBILITY);
- return i_get(u->items, rring->itype)
- + i_get(u->items, rsphere->itype) * 100;
+ return (rring ? i_get(u->items, rring->itype) : 0)
+ + (rsphere ? i_get(u->items, rsphere->itype) * 100 : 0);
}
static int item_modification(const unit * u, skill_t sk, int val)
diff --git a/src/kernel/unit.h b/src/kernel/unit.h
index 0826fb786..4c232da5e 100644
--- a/src/kernel/unit.h
+++ b/src/kernel/unit.h
@@ -30,7 +30,7 @@ extern "C" {
struct item;
struct sc_mage;
-#define UFL_DEBUG (1<<0)
+#define UFL_DEAD (1<<0)
#define UFL_ISNEW (1<<1) /* 2 */
#define UFL_LONGACTION (1<<2) /* 4 */
#define UFL_OWNER (1<<3) /* 8 */
diff --git a/src/kernel/xmlreader.c b/src/kernel/xmlreader.c
index 3d5c962eb..3832c9bb1 100644
--- a/src/kernel/xmlreader.c
+++ b/src/kernel/xmlreader.c
@@ -1668,12 +1668,12 @@ static int parse_races(xmlDocPtr doc)
rc->at_bonus = (char)xml_ivalue(node, "attackmodifier", 0);
rc->df_bonus = (char)xml_ivalue(node, "defensemodifier", 0);
- if (xml_bvalue(node, "playerrace", false))
- rc->flags |= RCF_PLAYERRACE;
+ if (!xml_bvalue(node, "playerrace", false))
+ rc->flags |= RCF_NPC;
if (xml_bvalue(node, "scarepeasants", false))
rc->flags |= RCF_SCAREPEASANTS;
- if (xml_bvalue(node, "cansteal", true))
- rc->flags |= RCF_CANSTEAL;
+ if (!xml_bvalue(node, "cansteal", true))
+ rc->flags |= RCF_NOSTEAL;
if (xml_bvalue(node, "cansail", true))
rc->flags |= RCF_CANSAIL;
if (xml_bvalue(node, "cannotmove", false))
diff --git a/src/test_eressea.c b/src/test_eressea.c
index 2b0fbee53..f93f88e48 100644
--- a/src/test_eressea.c
+++ b/src/test_eressea.c
@@ -1,7 +1,10 @@
+#include
+#include
#include
#include
#include
+
CuSuite *get_tests_suite(void);
CuSuite *get_callback_suite(void);
CuSuite *get_jsonconf_suite(void);
@@ -39,6 +42,7 @@ int RunAllTests(void)
int flags = log_flags;
log_flags = LOG_FLUSH | LOG_CPERROR;
+ kernel_init();
/* self-test */
CuSuiteAddSuite(suite, get_tests_suite());
diff --git a/src/tests.c b/src/tests.c
index 00e8db540..abe9b085a 100644
--- a/src/tests.c
+++ b/src/tests.c
@@ -25,7 +25,6 @@
struct race *test_create_race(const char *name)
{
race *rc = rc_get_or_create(name);
- rc->flags |= RCF_PLAYERRACE;
rc->maintenance = 10;
return rc;
}
diff --git a/src/util/language.c b/src/util/language.c
index 601be6245..f5e98797b 100644
--- a/src/util/language.c
+++ b/src/util/language.c
@@ -189,8 +189,7 @@ void locale_setstring(locale * lang, const char *key, const char *value)
const char *locale_name(const locale * lang)
{
- assert(lang);
- return lang->name;
+ return lang ? lang->name : "(null)";
}
char *mkname_buf(const char *space, const char *name, char *buffer)
diff --git a/tests/init.lua b/tests/init.lua
index 2d10882db..a5c198203 100644
--- a/tests/init.lua
+++ b/tests/init.lua
@@ -1,4 +1,5 @@
-- new tests 2014-06-11
+require "tests.pool"
require "tests.settings"
require "tests.config"
require "tests.locale"
@@ -8,3 +9,4 @@ require "tests.castles"
require "tests.spells"
require "tests.movement"
require "tests.ships"
+require "tests.pool"
diff --git a/tests/pool.lua b/tests/pool.lua
new file mode 100644
index 000000000..eb687363a
--- /dev/null
+++ b/tests/pool.lua
@@ -0,0 +1,74 @@
+require "lunit"
+
+module("tests.eressea.pool", package.seeall, lunit.testcase )
+
+function setup()
+ eressea.free_game()
+ eressea.config.reset();
+ eressea.settings.set("rules.economy.food", "0")
+ eressea.settings.set("nmr.removenewbie", "0")
+ eressea.settings.set("nmr.timeout", "0")
+ conf = [[{
+ "races": {
+ "human" : { "flags" : [ "giveitem", "getitem" ] }
+ },
+ "terrains" : {
+ "plain": { "flags" : [ "land" ] }
+ },
+ "keywords" : {
+ "de" : {
+ "give" : "GIB",
+ "contact" : "KONTAKTIERE"
+ }
+ },
+ "strings" : {
+ "de" : {
+ "money" : "Silber"
+ }
+ }
+ }]]
+
+ assert(eressea.config.parse(conf)==0)
+end
+
+function test_give_nopool()
+ local r = region.create(1, 1, "plain")
+ local f = faction.create("test@example.com", "human", "de")
+ local u1 = unit.create(f, r, 1)
+ local u2 = unit.create(f, r, 1)
+ u1:add_item("money", 100)
+ u1:add_order("GIB " .. itoa36(u2.id) .. " 50 SILBER")
+ process_orders()
+ assert_equal(50, u1:get_item("money"))
+ assert_equal(50, u2:get_item("money"))
+end
+
+function test_give_from_faction()
+ local r = region.create(1, 1, "plain")
+ local f = faction.create("test@example.com", "human", "de")
+ local u1 = unit.create(f, r, 1)
+ local u2 = unit.create(f, r, 1)
+ local u3 = unit.create(f, r, 1)
+ u1:add_item("money", 50)
+ u2:add_item("money", 50)
+ u1:add_order("GIB " .. itoa36(u3.id) .. " 100 SILBER")
+ process_orders()
+ assert_equal(0, u1:get_item("money"))
+ assert_equal(0, u2:get_item("money"))
+ assert_equal(100, u3:get_item("money"))
+end
+
+function test_give_divisor()
+ eressea.settings.set("rules.items.give_divisor", 2)
+ local r = region.create(1, 1, "plain")
+ local f1 = faction.create("test@example.com", "human", "de")
+ local f2 = faction.create("test@example.com", "human", "de")
+ local u1 = unit.create(f1, r, 1)
+ local u2 = unit.create(f2, r, 1)
+ u2:add_order("KONTAKTIERE " .. itoa36(u1.id))
+ u1:add_item("money", 100)
+ u1:add_order("GIB " .. itoa36(u2.id) .. " 100 SILBER")
+ process_orders()
+ assert_equal(0, u1:get_item("money"))
+ assert_equal(50, u2:get_item("money"))
+end