Merge branch 'master' into develop

Conflicts:
	src/move.c
This commit is contained in:
Enno Rehling 2015-11-25 13:25:36 +01:00
commit 677f7eac0a
5 changed files with 301 additions and 17 deletions

View file

@ -179,6 +179,7 @@ target_link_libraries(eressea
) )
set(TESTS_SRC set(TESTS_SRC
monsters.test.c
donations.test.c donations.test.c
wormhole.test.c wormhole.test.c
alchemy.test.c alchemy.test.c

View file

@ -788,7 +788,7 @@ void plan_monsters(faction * f)
setstatus(u, ST_FIGHT); setstatus(u, ST_FIGHT);
/* all monsters fight */ /* all monsters fight */
} }
if (attacking && is_guard(u, GUARD_TAX)) { if (attacking && (!r->land || is_guard(u, GUARD_TAX))) {
monster_attacks(u); monster_attacks(u);
} }
/* units with a plan to kill get ATTACK orders: */ /* units with a plan to kill get ATTACK orders: */

275
src/monsters.test.c Normal file
View file

@ -0,0 +1,275 @@
#include <platform.h>
#include <stdlib.h>
#include <kernel/config.h>
#include <kernel/faction.h>
#include <kernel/item.h>
#include <kernel/order.h>
#include <kernel/race.h>
#include <kernel/region.h>
#include <kernel/terrain.h>
#include <kernel/unit.h>
#include "monster.h"
#include "guard.h"
#include "skill.h"
#include <util/language.h>
#include <CuTest.h>
#include <tests.h>
#include <assert.h>
#include <stdio.h>
#include <string.h>
extern void plan_monsters(struct faction *f);
static void init_language(void)
{
struct locale* lang;
int i;
lang = get_or_create_locale("de");
locale_setstring(lang, "skill::unarmed", "Waffenloser Kampf");
locale_setstring(lang, "keyword::attack", "ATTACKIERE");
locale_setstring(lang, "keyword::study", "LERNE");
locale_setstring(lang, "keyword::tax", "TREIBE");
locale_setstring(lang, "keyword::loot", "PLUENDERE");
locale_setstring(lang, "keyword::piracy", "PIRATERIE");
locale_setstring(lang, "keyword::guard", "BEWACHE");
locale_setstring(lang, "keyword::move", "NACH");
locale_setstring(lang, "keyword::message", "BOTSCHAFT");
locale_setstring(lang, "REGION", "REGION");
locale_setstring(lang, "east", "O");
for (i = 0; i < MAXKEYWORDS; ++i) {
if (!locale_getstring(lang, mkname("keyword", keywords[i])))
locale_setstring(lang, mkname("keyword", keywords[i]), keywords[i]);
}
for (i = 0; i < MAXSKILLS; ++i) {
if (!locale_getstring(lang, mkname("skill", skillnames[i])))
locale_setstring(lang, mkname("skill", skillnames[i]), skillnames[i]);
}
init_keywords(lang);
init_skills(lang);
}
static order *find_order(const char *expected, const unit *unit)
{
char cmd[32];
order *order;
for (order = unit->orders; order; order = order->next) {
if (strcmp(expected, get_command(order, cmd, sizeof(cmd))) == 0) {
return order;
}
}
return NULL;
}
static void create_monsters(faction **player, faction **monsters, region **r, unit **u, unit **m) {
race* rc;
test_cleanup();
init_language();
test_create_world();
*player = test_create_faction(NULL);
*monsters = get_or_create_monsters();
assert(rc_find((*monsters)->race->_name));
rc = rc_get_or_create((*monsters)->race->_name);
fset(rc, RCF_UNARMEDGUARD);
fset(rc, RCF_NPC);
fset(*monsters, FFL_NOIDLEOUT);
assert(fval(*monsters, FFL_NPC) && fval((*monsters)->race, RCF_UNARMEDGUARD) && fval((*monsters)->race, RCF_NPC) && fval(*monsters, FFL_NOIDLEOUT));
(*monsters)->locale = default_locale;
*r = findregion(0, 0);
*u = test_create_unit(*player, *r);
unit_setid(*u, 1);
*m = test_create_unit(*monsters, *r);
}
static void test_monsters_attack(CuTest * tc)
{
faction *f, *f2;
region *r;
unit *u, *m;
create_monsters(&f, &f2, &r, &u, &m);
guard(m, GUARD_TAX);
set_param(&global.parameters, "rules.monsters.attack_chance", "1");
plan_monsters(f2);
CuAssertPtrNotNull(tc, find_order("ATTACKIERE 1", m));
test_cleanup();
}
static void test_monsters_attack_ocean(CuTest * tc)
{
faction *f, *f2;
region *r;
unit *u, *m;
create_monsters(&f, &f2, &r, &u, &m);
r = findregion(-1, 0);
u = test_create_unit(u->faction, r);
unit_setid(u, 2);
m = test_create_unit(m->faction, r);
assert(!m->region->land);
set_param(&global.parameters, "rules.monsters.attack_chance", "1");
plan_monsters(f2);
CuAssertPtrNotNull(tc, find_order("ATTACKIERE 2", m));
test_cleanup();
}
extern int monster_attacks(unit * monster, bool respect_buildings, bool rich_only);
static void test_monsters_waiting(CuTest * tc)
{
faction *f, *f2;
region *r;
unit *u, *m;
create_monsters(&f, &f2, &r, &u, &m);
guard(m, GUARD_TAX);
fset(m, UFL_ISNEW);
// FIXME: monster_attacks(m, false, false);
CuAssertPtrEquals(tc, 0, find_order("ATTACKIERE 1", m));
test_cleanup();
}
static void test_seaserpent_piracy(CuTest * tc)
{
faction *f, *f2;
region *r;
unit *u, *m;
race *rc;
create_monsters(&f, &f2, &r, &u, &m);
r = findregion(-1, 0);
u = test_create_unit(u->faction, r);
unit_setid(u, 2);
m = test_create_unit(m->faction, r);
u_setrace(m, rc = test_create_race("seaserpent"));
assert(!m->region->land);
fset(m, UFL_MOVED);
// fset(rc, RCF_ATTACK_MOVED);
set_param(&global.parameters, "rules.monsters.attack_chance", "1");
plan_monsters(f2);
CuAssertPtrNotNull(tc, find_order("PIRATERIE", m));
CuAssertPtrNotNull(tc, find_order("ATTACKIERE 2", m));
test_cleanup();
}
static void test_monsters_attack_not(CuTest * tc)
{
faction *f, *f2;
region *r;
unit *u, *m;
create_monsters(&f, &f2, &r, &u, &m);
guard(m, GUARD_TAX);
guard(u, GUARD_TAX);
set_param(&global.parameters, "rules.monsters.attack_chance", "0");
plan_monsters(f2);
CuAssertPtrEquals(tc, 0, find_order("ATTACKIERE 1", m));
test_cleanup();
}
static void test_dragon_attacks_the_rich(CuTest * tc)
{
faction *f, *f2;
region *r;
unit *u, *m;
const item_type *i_silver;
init_language();
create_monsters(&f, &f2, &r, &u, &m);
guard(m, GUARD_TAX);
set_level(m, SK_WEAPONLESS, 10);
rsetmoney(r, 1);
rsetmoney(findregion(1, 0), 0);
i_silver = it_find("money");
assert(i_silver);
i_change(&u->items, i_silver, 5000);
set_param(&global.parameters, "rules.monsters.attack_chance", "0.00001");
plan_monsters(f2);
CuAssertPtrNotNull(tc, find_order("ATTACKIERE 1", m));
CuAssertPtrNotNull(tc, find_order("PLUENDERE", m));
test_cleanup();
}
static void test_dragon_moves(CuTest * tc)
{
faction *f, *f2;
region *r;
unit *u, *m;
create_monsters(&f, &f2, &r, &u, &m);
rsetpeasants(r, 0);
rsetmoney(r, 0);
rsetmoney(findregion(1, 0), 1000);
set_level(m, SK_WEAPONLESS, 10);
set_param(&global.parameters, "rules.monsters.attack_chance", ".0");
plan_monsters(f2);
CuAssertPtrNotNull(tc, find_order("NACH O", m));
test_cleanup();
}
static void test_monsters_learn_exp(CuTest * tc)
{
faction *f, *f2;
region *r;
unit *u, *m;
skill* sk;
create_monsters(&f, &f2, &r, &u, &m);
set_param(&global.parameters, "study.from_use", "1");
u_setrace(u, u_race(m));
produceexp(u, SK_MELEE, u->number);
sk = unit_skill(u, SK_MELEE);
CuAssertTrue(tc, !sk);
produceexp(m, SK_MELEE, u->number);
sk = unit_skill(m, SK_MELEE);
CuAssertTrue(tc, sk && (sk->level > 0 || (sk->level == 0 && sk->weeks > 0)));
test_cleanup();
}
CuSuite *get_monsters_suite(void)
{
CuSuite *suite = CuSuiteNew();
SUITE_ADD_TEST(suite, test_monsters_attack);
SUITE_ADD_TEST(suite, test_monsters_attack_ocean);
DISABLE_TEST(suite, test_seaserpent_piracy);
DISABLE_TEST(suite, test_monsters_waiting);
SUITE_ADD_TEST(suite, test_monsters_attack_not);
SUITE_ADD_TEST(suite, test_dragon_attacks_the_rich);
DISABLE_TEST(suite, test_dragon_moves);
DISABLE_TEST(suite, test_monsters_learn_exp);
return suite;
}

View file

@ -1729,6 +1729,9 @@ sail(unit * u, order * ord, bool move_on_land, region_list ** routep)
faction *f = u->faction; faction *f = u->faction;
region *next_point = NULL; region *next_point = NULL;
int error; int error;
double damage_storm = config_get_flt("rules.ship.damage_storm", 0.02);
bool storms_enabled = config_get_int("rules.ship.storms", 1) != 0;
int lighthouse_div = config_get_int("rules.storm.lighthouse.divisor", 0);
const char *token = getstrtoken(); const char *token = getstrtoken();
if (routep) if (routep)
@ -1780,7 +1783,6 @@ sail(unit * u, order * ord, bool move_on_land, region_list ** routep)
if (!flying_ship(sh)) { if (!flying_ship(sh)) {
int stormchance = 0; int stormchance = 0;
int reason; int reason;
bool storms_enabled = config_get_int("rules.ship.storms", 1) != 0;
if (storms_enabled) { if (storms_enabled) {
int stormyness; int stormyness;
gamedate date; gamedate date;
@ -1790,9 +1792,8 @@ sail(unit * u, order * ord, bool move_on_land, region_list ** routep)
/* storms should be the first thing we do. */ /* storms should be the first thing we do. */
stormchance = stormyness / shipspeed(sh, u); stormchance = stormyness / shipspeed(sh, u);
if (check_leuchtturm(next_point, NULL)) { if (check_leuchtturm(next_point, NULL)) {
int param = config_get_int("rules.lighthous.stormchancedevisor", 0); if (lighthouse_div > 0) {
if (param > 0) { stormchance /= lighthouse_div;
stormchance /= param;
} }
else { else {
stormchance = 0; stormchance = 0;
@ -1825,6 +1826,12 @@ sail(unit * u, order * ord, bool move_on_land, region_list ** routep)
ADDMSG(&f->msgs, msg_message("storm", "ship region sink", ADDMSG(&f->msgs, msg_message("storm", "ship region sink",
sh, current_point, sh->damage >= sh->size * DAMAGE_SCALE)); sh, current_point, sh->damage >= sh->size * DAMAGE_SCALE));
damage_ship(sh, damage_storm);
if (sh->damage >= sh->size * DAMAGE_SCALE) {
/* ship sinks, end journey here */
break;
}
next_point = rnext; next_point = rnext;
/* these values need to be updated if next_point changes (due to storms): */ /* these values need to be updated if next_point changes (due to storms): */
tnext = next_point->terrain; tnext = next_point->terrain;

View file

@ -118,6 +118,7 @@ int RunAllTests(int argc, char *argv[])
ADD_SUITE(give); ADD_SUITE(give);
ADD_SUITE(laws); ADD_SUITE(laws);
ADD_SUITE(market); ADD_SUITE(market);
ADD_SUITE(monsters);
ADD_SUITE(move); ADD_SUITE(move);
ADD_SUITE(piracy); ADD_SUITE(piracy);
ADD_SUITE(stealth); ADD_SUITE(stealth);