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