Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 22 additions & 3 deletions src/monsters.c
Original file line number Diff line number Diff line change
Expand Up @@ -220,23 +220,42 @@ void monsters_desert(struct faction *monsters)

int monster_attacks(unit * monster, bool rich_only)
{
const race *rc_serpent = get_race(RC_SEASERPENT);
int result = -1;

if (monster_can_attack(monster)) {
const race *rc_serpent = get_race(RC_SEASERPENT);
region *r = monster->region;
unit *u2;
int money = 0;
building *b;
int protect = 0;
for (b = r->buildings; b; b = b->next) {
if (b->type->flags & BTF_FORTIFICATION) {
protect += b->size;
}
}

for (u2 = r->units; u2; u2 = u2->next) {
if (u2->faction != monster->faction && cansee(monster->faction, r, u2, 0) && !in_safe_building(u2, monster)) {
int m = get_money(u2);
if (u2->faction != monster->faction && cansee(monster->faction, r, u2, 0)) {
int m;
b = inside_building(u2);

if (b && b != inside_building(monster)) {
if (b->type->flags & BTF_FORTIFICATION) {
continue;
}
else if (protect >= u2->number) {
protect -= u2->number;
continue;
}
}
if (u_race(monster) == rc_serpent) {
/* attack bigger ships only */
if (!u2->ship || u2->ship->type->cargo <= 50000) {
continue;
}
}
m = get_money(u2);
if (!rich_only || m > 0) {
order *ord = monster_attack(monster, u2);
if (ord) {
Expand Down
58 changes: 58 additions & 0 deletions src/monsters.test.c
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

#include "kernel/attrib.h"
#include "kernel/config.h"
#include "kernel/building.h"
#include "kernel/faction.h"
#include "kernel/group.h"
#include "kernel/item.h"
Expand Down Expand Up @@ -123,6 +124,62 @@ static void test_monsters_attack_ocean(CuTest * tc)
test_teardown();
}

static void test_monsters_dont_attack_buildings(CuTest *tc)
{
region *r;
unit *u, *m;
building_type *btype;
building *b;

test_setup();
btype = test_create_buildingtype("castle");
btype->flags |= BTF_FORTIFICATION;
config_set("rules.monsters.attack_chance", "1");
create_monsters(&u, &m);
r = findregion(0, 0);
move_unit(m, r, NULL);
m->flags = UFL_GUARD;
unit_setid(u, 2);

b = test_create_building(r, btype);
b->size = u->number = 5;
u_set_building(u, b);

plan_monsters(m->faction);
CuAssertPtrEquals(tc, NULL, find_order("attack 2", m));

/** second unit, does not fit into the building, can be attacked */
u = test_create_unit(u->faction, r);
unit_setid(u, 3);
u_set_building(u, b);
plan_monsters(m->faction);
CuAssertPtrEquals(tc, NULL, find_order("attack 2", m));
CuAssertPtrNotNull(tc, find_order("attack 3", m));

/** second unit is fully inside a non-fortified building that gets protected */
u->number = b->size;
u_set_building(u, NULL);
b = test_create_building(r, NULL);
b->size = u->number;
u_set_building(u, b);
plan_monsters(m->faction);
CuAssertPtrEquals(tc, NULL, find_order("attack 2", m));
CuAssertPtrEquals(tc, NULL, find_order("attack 3", m));

/** second unit does not fit into the protected building */
++u->number;
plan_monsters(m->faction);
CuAssertPtrEquals(tc, NULL, find_order("attack 2", m));
CuAssertPtrNotNull(tc, find_order("attack 3", m));

/** second unit is fully inside protected building that is too big */
b->size = u->number;
plan_monsters(m->faction);
CuAssertPtrEquals(tc, NULL, find_order("attack 2", m));
CuAssertPtrNotNull(tc, find_order("attack 3", m));

test_teardown();
}
static void test_monsters_waiting(CuTest * tc)
{
unit *u, *m;
Expand Down Expand Up @@ -336,6 +393,7 @@ CuSuite *get_monsters_suite(void)
SUITE_ADD_TEST(suite, test_monsters_hate);
SUITE_ADD_TEST(suite, test_spawn_seaserpent);
SUITE_ADD_TEST(suite, test_monsters_attack_ocean);
SUITE_ADD_TEST(suite, test_monsters_dont_attack_buildings);
SUITE_ADD_TEST(suite, test_seaserpent_piracy);
SUITE_ADD_TEST(suite, test_monsters_waiting);
SUITE_ADD_TEST(suite, test_monsters_attack_not);
Expand Down