2015-11-17 02:07:46 +01:00
|
|
|
#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>
|
2017-09-09 15:24:50 +02:00
|
|
|
#include <kernel/region.h>
|
|
|
|
#include <kernel/ship.h>
|
2015-11-17 02:07:46 +01:00
|
|
|
#include <kernel/terrain.h>
|
|
|
|
#include <kernel/unit.h>
|
|
|
|
|
2016-08-31 16:43:02 +02:00
|
|
|
#include "monsters.h"
|
2015-11-17 02:07:46 +01:00
|
|
|
#include "guard.h"
|
2016-05-31 01:49:37 +02:00
|
|
|
#include "reports.h"
|
2015-11-17 02:07:46 +01:00
|
|
|
#include "skill.h"
|
2016-03-08 14:09:22 +01:00
|
|
|
#include "study.h"
|
2015-11-17 02:07:46 +01:00
|
|
|
|
2018-09-29 11:37:17 +02:00
|
|
|
#include <kernel/attrib.h>
|
2015-11-17 02:07:46 +01:00
|
|
|
#include <util/language.h>
|
2016-05-31 01:49:37 +02:00
|
|
|
#include <util/message.h>
|
|
|
|
#include <util/nrmessage.h>
|
2015-11-17 02:07:46 +01:00
|
|
|
|
2018-04-22 19:04:09 +02:00
|
|
|
#include <attributes/hate.h>
|
|
|
|
|
2015-11-17 02:07:46 +01:00
|
|
|
#include <CuTest.h>
|
|
|
|
#include <tests.h>
|
|
|
|
#include <assert.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <string.h>
|
|
|
|
|
|
|
|
extern void plan_monsters(struct faction *f);
|
2017-06-18 14:20:01 +02:00
|
|
|
extern int monster_attacks(unit * monster, bool rich_only);
|
2015-11-17 02:07:46 +01:00
|
|
|
|
2017-10-08 17:07:42 +02:00
|
|
|
static order *find_order(const char *expected, const unit *u)
|
2015-11-17 02:07:46 +01:00
|
|
|
{
|
|
|
|
char cmd[32];
|
2016-03-23 23:06:45 +01:00
|
|
|
order *ord;
|
2017-10-08 17:07:42 +02:00
|
|
|
for (ord = u->orders; ord; ord = ord->next) {
|
|
|
|
if (strcmp(expected, get_command(ord, u->faction->locale, cmd, sizeof(cmd))) == 0) {
|
2016-03-23 23:06:45 +01:00
|
|
|
return ord;
|
2015-11-17 02:07:46 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2017-09-09 15:24:50 +02:00
|
|
|
static void create_monsters(unit **up, unit **um) {
|
2015-11-17 02:07:46 +01:00
|
|
|
race* rc;
|
2016-03-23 23:06:45 +01:00
|
|
|
region *r;
|
2017-09-09 15:24:50 +02:00
|
|
|
faction *fp, *fm;
|
2015-11-17 02:07:46 +01:00
|
|
|
|
2018-05-18 19:58:49 +02:00
|
|
|
mt_create_va(mt_new("dragon_growl", NULL),
|
|
|
|
"dragon:unit", "number:int", "target:region", "growl:string", MT_NEW_END);
|
2016-03-23 23:06:45 +01:00
|
|
|
test_create_horse();
|
|
|
|
default_locale = test_create_locale();
|
2017-09-09 15:24:50 +02:00
|
|
|
fp = test_create_faction(NULL);
|
2018-05-10 22:00:23 +02:00
|
|
|
|
2017-09-09 15:24:50 +02:00
|
|
|
fm = get_or_create_monsters();
|
2018-05-10 22:00:23 +02:00
|
|
|
fset(fm, FFL_NOIDLEOUT);
|
|
|
|
assert(fval(fm, FFL_NPC));
|
|
|
|
assert(fval(fm, FFL_NOIDLEOUT));
|
|
|
|
|
2017-09-09 15:24:50 +02:00
|
|
|
assert(rc_find(fm->race->_name));
|
|
|
|
rc = rc_get_or_create(fm->race->_name);
|
2018-05-10 22:00:23 +02:00
|
|
|
fset(rc, RCF_UNARMEDGUARD|RCF_DRAGON);
|
|
|
|
assert(!fval(fm->race, RCF_PLAYABLE));
|
2015-11-17 02:07:46 +01:00
|
|
|
|
2016-06-10 20:55:27 +02:00
|
|
|
test_create_region(-1, 0, test_create_terrain("ocean", SEA_REGION | SWIM_INTO | FLY_INTO));
|
2016-03-23 23:06:45 +01:00
|
|
|
test_create_region(1, 0, 0);
|
2018-01-14 09:38:26 +01:00
|
|
|
r = test_create_region(0, 0, NULL);
|
2015-11-17 02:07:46 +01:00
|
|
|
|
2017-09-09 15:24:50 +02:00
|
|
|
*up = test_create_unit(fp, r);
|
|
|
|
unit_setid(*up, 1);
|
|
|
|
*um = test_create_unit(fm, r);
|
|
|
|
unit_setstatus(*um, ST_FIGHT);
|
2015-11-17 02:07:46 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
static void test_monsters_attack(CuTest * tc)
|
|
|
|
{
|
|
|
|
unit *u, *m;
|
|
|
|
|
2017-12-27 19:58:39 +01:00
|
|
|
test_setup();
|
2017-09-09 15:24:50 +02:00
|
|
|
create_monsters(&u, &m);
|
2016-10-31 07:45:06 +01:00
|
|
|
setguard(m, true);
|
2015-11-17 02:07:46 +01:00
|
|
|
|
2015-11-25 14:25:04 +01:00
|
|
|
config_set("rules.monsters.attack_chance", "1");
|
2015-11-17 02:07:46 +01:00
|
|
|
|
2017-09-09 15:24:50 +02:00
|
|
|
plan_monsters(m->faction);
|
2015-11-17 02:07:46 +01:00
|
|
|
|
2016-03-23 23:06:45 +01:00
|
|
|
CuAssertPtrNotNull(tc, find_order("attack 1", m));
|
2017-12-27 19:58:39 +01:00
|
|
|
test_teardown();
|
2015-11-17 02:07:46 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
static void test_monsters_attack_ocean(CuTest * tc)
|
|
|
|
{
|
|
|
|
region *r;
|
|
|
|
unit *u, *m;
|
|
|
|
|
2017-12-27 19:58:39 +01:00
|
|
|
test_setup();
|
2017-09-09 15:24:50 +02:00
|
|
|
create_monsters(&u, &m);
|
2017-02-18 21:15:14 +01:00
|
|
|
r = findregion(-1, 0); /* ocean */
|
2015-11-17 02:07:46 +01:00
|
|
|
u = test_create_unit(u->faction, r);
|
|
|
|
unit_setid(u, 2);
|
|
|
|
m = test_create_unit(m->faction, r);
|
|
|
|
assert(!m->region->land);
|
|
|
|
|
2015-11-25 14:25:04 +01:00
|
|
|
config_set("rules.monsters.attack_chance", "1");
|
2015-11-17 02:07:46 +01:00
|
|
|
|
2017-09-09 15:24:50 +02:00
|
|
|
plan_monsters(m->faction);
|
2015-11-17 02:07:46 +01:00
|
|
|
|
2016-03-23 23:06:45 +01:00
|
|
|
CuAssertPtrNotNull(tc, find_order("attack 2", m));
|
2017-12-27 19:58:39 +01:00
|
|
|
test_teardown();
|
2015-11-17 02:07:46 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
static void test_monsters_waiting(CuTest * tc)
|
|
|
|
{
|
|
|
|
unit *u, *m;
|
|
|
|
|
2017-12-27 19:58:39 +01:00
|
|
|
test_setup();
|
2017-09-09 15:24:50 +02:00
|
|
|
create_monsters(&u, &m);
|
2016-10-31 07:45:06 +01:00
|
|
|
setguard(m, true);
|
2015-11-17 02:07:46 +01:00
|
|
|
fset(m, UFL_ISNEW);
|
2017-06-18 14:20:01 +02:00
|
|
|
monster_attacks(m, false);
|
2018-10-14 11:47:59 +02:00
|
|
|
CuAssertPtrEquals(tc, NULL, find_order("attack 1", m));
|
2017-12-27 19:58:39 +01:00
|
|
|
test_teardown();
|
2015-11-17 02:07:46 +01:00
|
|
|
}
|
|
|
|
|
2015-11-24 16:12:33 +01:00
|
|
|
static void test_seaserpent_piracy(CuTest * tc)
|
2015-11-17 12:06:12 +01:00
|
|
|
{
|
|
|
|
region *r;
|
|
|
|
unit *u, *m;
|
|
|
|
race *rc;
|
2017-09-09 15:24:50 +02:00
|
|
|
ship_type * stype;
|
2015-11-17 12:06:12 +01:00
|
|
|
|
2017-12-27 19:58:39 +01:00
|
|
|
test_setup();
|
2017-09-09 15:24:50 +02:00
|
|
|
create_monsters(&u, &m);
|
|
|
|
stype = test_create_shiptype("yacht");
|
2017-02-18 21:15:14 +01:00
|
|
|
r = findregion(-1, 0); /* ocean */
|
2015-11-17 12:06:12 +01:00
|
|
|
u = test_create_unit(u->faction, r);
|
2017-09-09 15:24:50 +02:00
|
|
|
u->ship = test_create_ship(r, stype);
|
2015-11-17 12:06:12 +01:00
|
|
|
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);
|
|
|
|
|
2015-11-25 14:25:04 +01:00
|
|
|
config_set("rules.monsters.attack_chance", "1");
|
2015-11-17 12:06:12 +01:00
|
|
|
|
2017-09-09 15:24:50 +02:00
|
|
|
stype->cargo = 50000;
|
|
|
|
plan_monsters(m->faction);
|
2016-03-23 23:06:45 +01:00
|
|
|
CuAssertPtrNotNull(tc, find_order("piracy", m));
|
2017-09-09 15:24:50 +02:00
|
|
|
CuAssertPtrEquals(tc, NULL, find_order("attack 2", m));
|
|
|
|
stype->cargo = 50001;
|
|
|
|
plan_monsters(m->faction);
|
2016-03-23 23:06:45 +01:00
|
|
|
CuAssertPtrNotNull(tc, find_order("attack 2", m));
|
2017-12-27 19:58:39 +01:00
|
|
|
test_teardown();
|
2015-11-17 12:06:12 +01:00
|
|
|
}
|
|
|
|
|
2015-11-17 02:07:46 +01:00
|
|
|
static void test_monsters_attack_not(CuTest * tc)
|
|
|
|
{
|
|
|
|
unit *u, *m;
|
|
|
|
|
2017-12-27 19:58:39 +01:00
|
|
|
test_setup();
|
2017-09-09 15:24:50 +02:00
|
|
|
create_monsters(&u, &m);
|
2015-11-17 02:07:46 +01:00
|
|
|
|
2016-10-31 07:45:06 +01:00
|
|
|
setguard(m, true);
|
|
|
|
setguard(u, true);
|
2015-11-17 02:07:46 +01:00
|
|
|
|
2015-11-25 14:25:04 +01:00
|
|
|
config_set("rules.monsters.attack_chance", "0");
|
2015-11-17 02:07:46 +01:00
|
|
|
|
2017-09-09 15:24:50 +02:00
|
|
|
plan_monsters(m->faction);
|
2015-11-17 02:07:46 +01:00
|
|
|
|
2018-10-14 11:47:59 +02:00
|
|
|
CuAssertPtrEquals(tc, NULL, find_order("attack 1", m));
|
2017-12-27 19:58:39 +01:00
|
|
|
test_teardown();
|
2015-11-17 02:07:46 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
static void test_dragon_attacks_the_rich(CuTest * tc)
|
|
|
|
{
|
|
|
|
unit *u, *m;
|
|
|
|
const item_type *i_silver;
|
|
|
|
|
2017-12-27 19:58:39 +01:00
|
|
|
test_setup();
|
2017-09-09 15:24:50 +02:00
|
|
|
create_monsters(&u, &m);
|
2016-03-23 23:06:45 +01:00
|
|
|
init_resources();
|
2015-11-17 02:07:46 +01:00
|
|
|
|
2016-10-31 07:45:06 +01:00
|
|
|
setguard(m, true);
|
2015-11-17 02:07:46 +01:00
|
|
|
set_level(m, SK_WEAPONLESS, 10);
|
|
|
|
|
2016-03-23 23:06:45 +01:00
|
|
|
rsetmoney(findregion(0, 0), 1);
|
2015-11-17 02:07:46 +01:00
|
|
|
rsetmoney(findregion(1, 0), 0);
|
|
|
|
i_silver = it_find("money");
|
|
|
|
assert(i_silver);
|
|
|
|
i_change(&u->items, i_silver, 5000);
|
|
|
|
|
2015-11-25 14:25:04 +01:00
|
|
|
config_set("rules.monsters.attack_chance", "0.00001");
|
2015-11-17 02:07:46 +01:00
|
|
|
|
2017-09-09 15:24:50 +02:00
|
|
|
plan_monsters(m->faction);
|
2016-03-23 23:06:45 +01:00
|
|
|
CuAssertPtrNotNull(tc, find_order("attack 1", m));
|
|
|
|
CuAssertPtrNotNull(tc, find_order("loot", m));
|
2017-12-27 19:58:39 +01:00
|
|
|
test_teardown();
|
2015-11-17 02:07:46 +01:00
|
|
|
}
|
|
|
|
|
2016-05-31 01:49:37 +02:00
|
|
|
extern void random_growl(const unit *u, region *tr, int rand);
|
|
|
|
|
2015-11-17 02:07:46 +01:00
|
|
|
static void test_dragon_moves(CuTest * tc)
|
|
|
|
{
|
|
|
|
region *r;
|
|
|
|
unit *u, *m;
|
2016-05-31 01:49:37 +02:00
|
|
|
struct message *msg;
|
2015-11-17 02:07:46 +01:00
|
|
|
|
2017-12-27 19:58:39 +01:00
|
|
|
test_setup();
|
2017-09-09 15:24:50 +02:00
|
|
|
create_monsters(&u, &m);
|
2016-03-23 23:06:45 +01:00
|
|
|
rsetmoney(findregion(1, 0), 1000);
|
2017-02-18 21:15:14 +01:00
|
|
|
r = findregion(0, 0); /* plain */
|
2015-11-17 02:07:46 +01:00
|
|
|
rsetpeasants(r, 0);
|
|
|
|
rsetmoney(r, 0);
|
|
|
|
|
|
|
|
set_level(m, SK_WEAPONLESS, 10);
|
2015-11-25 14:25:04 +01:00
|
|
|
config_set("rules.monsters.attack_chance", ".0");
|
2015-11-17 02:07:46 +01:00
|
|
|
|
2017-09-09 15:24:50 +02:00
|
|
|
plan_monsters(m->faction);
|
2016-03-23 23:06:45 +01:00
|
|
|
CuAssertPtrNotNull(tc, find_order("move east", m));
|
2016-05-31 01:49:37 +02:00
|
|
|
|
|
|
|
random_growl(m, findregion(1, 0), 3);
|
|
|
|
|
|
|
|
msg = test_get_last_message(r->msgs);
|
2016-06-11 13:47:38 +02:00
|
|
|
assert_message(tc, msg, "dragon_growl", 4);
|
|
|
|
assert_pointer_parameter(tc, msg, 0, m);
|
|
|
|
assert_int_parameter(tc, msg, 1, 1);
|
|
|
|
assert_pointer_parameter(tc, msg, 2, findregion(1,0));
|
|
|
|
assert_string_parameter(tc, msg, 3, "growl3");
|
2016-05-31 01:49:37 +02:00
|
|
|
|
2017-12-27 19:58:39 +01:00
|
|
|
test_teardown();
|
2015-11-17 02:07:46 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
static void test_monsters_learn_exp(CuTest * tc)
|
|
|
|
{
|
|
|
|
unit *u, *m;
|
|
|
|
skill* sk;
|
|
|
|
|
2017-12-27 19:58:39 +01:00
|
|
|
test_setup();
|
2017-09-09 15:24:50 +02:00
|
|
|
create_monsters(&u, &m);
|
2016-03-24 22:31:07 +01:00
|
|
|
config_set("study.produceexp", "30");
|
2015-11-17 02:07:46 +01:00
|
|
|
|
|
|
|
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)));
|
|
|
|
|
2017-12-27 19:58:39 +01:00
|
|
|
test_teardown();
|
2015-11-17 02:07:46 +01:00
|
|
|
}
|
|
|
|
|
2016-08-31 16:43:02 +02:00
|
|
|
static void test_spawn_seaserpent(CuTest *tc) {
|
|
|
|
region *r;
|
|
|
|
unit *u;
|
|
|
|
faction *f;
|
2016-08-31 16:47:36 +02:00
|
|
|
race *rc;
|
2017-12-27 19:58:39 +01:00
|
|
|
test_setup();
|
2016-08-31 16:47:36 +02:00
|
|
|
rc = test_create_race("seaserpent");
|
2018-05-10 22:00:23 +02:00
|
|
|
rc->flags &= ~RCF_PLAYABLE;
|
2018-01-14 09:38:26 +01:00
|
|
|
r = test_create_region(0, 0, NULL);
|
|
|
|
f = test_create_faction(NULL);
|
2016-08-31 16:43:02 +02:00
|
|
|
u = spawn_seaserpent(r, f);
|
|
|
|
CuAssertPtrNotNull(tc, u);
|
2018-05-10 22:00:23 +02:00
|
|
|
CuAssertPtrEquals(tc, NULL, u->_name);
|
2017-12-27 19:58:39 +01:00
|
|
|
test_teardown();
|
2016-08-31 16:43:02 +02:00
|
|
|
}
|
|
|
|
|
2018-04-22 19:04:09 +02:00
|
|
|
static void test_monsters_hate(CuTest *tc) {
|
|
|
|
unit *mu, *tu;
|
|
|
|
order *ord;
|
|
|
|
char buffer[32];
|
|
|
|
const struct locale *lang;
|
|
|
|
|
|
|
|
test_setup();
|
|
|
|
tu = test_create_unit(test_create_faction(NULL), test_create_plain(1, 0));
|
|
|
|
mu = test_create_unit(get_monsters(), test_create_plain(0, 0));
|
|
|
|
lang = mu->faction->locale;
|
|
|
|
a_add(&mu->attribs, make_hate(tu));
|
|
|
|
plan_monsters(mu->faction);
|
|
|
|
CuAssertPtrNotNull(tc, mu->orders);
|
|
|
|
for (ord = mu->orders; ord; ord = ord->next) {
|
|
|
|
if (K_MOVE == getkeyword(ord)) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
CuAssertPtrNotNull(tc, ord);
|
|
|
|
CuAssertIntEquals(tc, K_MOVE, getkeyword(ord));
|
|
|
|
CuAssertStrEquals(tc, "move east", get_command(ord, lang, buffer, sizeof(buffer)));
|
|
|
|
test_teardown();
|
|
|
|
}
|
|
|
|
|
2015-11-17 02:07:46 +01:00
|
|
|
CuSuite *get_monsters_suite(void)
|
|
|
|
{
|
|
|
|
CuSuite *suite = CuSuiteNew();
|
|
|
|
SUITE_ADD_TEST(suite, test_monsters_attack);
|
2018-04-22 19:04:09 +02:00
|
|
|
SUITE_ADD_TEST(suite, test_monsters_hate);
|
2016-08-31 16:43:02 +02:00
|
|
|
SUITE_ADD_TEST(suite, test_spawn_seaserpent);
|
2015-11-17 02:07:46 +01:00
|
|
|
SUITE_ADD_TEST(suite, test_monsters_attack_ocean);
|
2015-12-01 22:01:28 +01:00
|
|
|
SUITE_ADD_TEST(suite, test_seaserpent_piracy);
|
2015-11-25 14:53:29 +01:00
|
|
|
SUITE_ADD_TEST(suite, test_monsters_waiting);
|
2015-11-17 02:07:46 +01:00
|
|
|
SUITE_ADD_TEST(suite, test_monsters_attack_not);
|
|
|
|
SUITE_ADD_TEST(suite, test_dragon_attacks_the_rich);
|
2015-11-25 14:53:29 +01:00
|
|
|
SUITE_ADD_TEST(suite, test_dragon_moves);
|
|
|
|
SUITE_ADD_TEST(suite, test_monsters_learn_exp);
|
2015-11-17 02:07:46 +01:00
|
|
|
return suite;
|
|
|
|
}
|