Adds test/monplace.lua to test placing monsters using the Lua direct monster creation binding (does not exercise all the map code).
Allow choosing what tests to run with "crawl -test test1,test2".
QAXFREFPBXN7YIBORITM2TAGA4QYF43XMSCLWW2BHONZFGEGMRUQC
TY33BSNJWG6DYLBARYXL72GPP7MZRA3QTG3A6H2OVUKW5QK7TH3AC
UXAYLVZCSKTOC23AZORWJBQWYXKWC6QD2FPV2DRG7G6J5S7U2QLAC
C25ULNTKMNOXT72ERWSFQZQW5E2OIM3TOGAAA33Z7EZQMZHRS2MAC
QLV7Y2LTDKTVMYFLM7UCNRUXU6PC5535XV6UE27N56AHHIGXEIWAC
SVY2PTCLXR3KNPQAWXVXTTGCC5DR334HOAKHYO3VDDRWM2BWMALAC
K2CS6TCX2NDVL2ASEHGP4J4K4IJ6FP3ANNKTSIWVG43HPYSBX6ZQC
RPOZZWKG5GLPHVZZ7ZKMKS64ZMV2LDCQSARBJFJ6FZOTOKCQO7FAC
55PFDYPVE6JVGDYPCFUE4XS2523PVSV4CSIFRW6A2GGX4I6VWRWQC
AUXHSGS4EFOPZ6TVZYWNVOUDO7NYKUKE3HBKGQQWTALSVFOE3HAAC
FSD7GIK3YLZXWLEH37BU6KV3IUCFGXPQL6IZ7H65YWNRBEKDBX5AC
2WWSPLCXLSMBGTXUC33EQ5YBOA5IBFSMJSTZ2TU6HZIMZZWZJWGAC
S6ZETU2X3HBTKBDL2KTAMCNPMPGHEZO2JGMILIWETWC7XXRS5RYQC
X5OHFTHRXTI5KHFIYFJ6DB3W5MY3JUJKNTL4HF37MKABYNCOBOZAC
3FBKOX4Y5QYPMBOCSAMHNZXCY7Z75YDQDL4EJZHZIGDXL7RMZ7TAC
3IMZJEIBQTRXX5OLN7NUZ3QSGNVH2VPVTBDESVVWXIYURTHF3VXAC
ZNMT5CZHP2FC4HTLNA7KYEDGFBXSCUE5QHJOALVPE6RDPHSEDXRQC
K7J2IGELTIQL5KAMBV62MFVIVMEZEWCOLZ7GHFXHYPANYIF7BRZAC
AVEOSLDREJHWFZE6ULAWGQPDT24YX4OAOGL7YAUCFVRGHCS22UCAC
-- Monster placement tests.
local place = dgn.point(20, 20)
local function place_monster_on(x, y, monster, feature)
dgn.grid(place.x, place.y, feature)
return dgn.create_monster(x, y, monster)
end
local function assert_place_monster_on(monster, feature)
dgn.dismiss_monsters()
crawl.mpr("Placing " .. monster .. " on " .. feature)
assert(place_monster_on(place.x, place.y, monster, feature),
"Could not place monster " .. monster .. " on " .. feature)
end
assert_place_monster_on("quokka", "floor")
assert_place_monster_on("necrophage", "altar_zin")
assert_place_monster_on("rat", "shallow water")
-- [ds] One wonders why due has this morbid fetish involving flying
-- skulls and lava...
assert_place_monster_on("flying skull", "lava")
assert_place_monster_on("rock worm", "rock_wall")
// Make all of the monster's original equipment disappear, unless it's a fixed
// artefact or unrand artefact.
static void _vanish_orig_eq(monsters* mons)
{
for (int i = 0; i < NUM_MONSTER_SLOTS; ++i)
{
if (mons->inv[i] == NON_ITEM)
continue;
item_def &item(mitm[mons->inv[i]]);
if (!is_valid_item(item))
continue;
if (item.orig_place != 0 || item.orig_monnum != 0
|| !item.inscription.empty()
|| is_unrandom_artefact(item)
|| (item.flags & (ISFLAG_DROPPED | ISFLAG_THROWN | ISFLAG_NOTED_GET
| ISFLAG_BEEN_IN_INV) ) )
{
continue;
}
item.flags |= ISFLAG_SUMMONED;
}
}
int dismiss_monsters(std::string pattern) {
// Make all of the monsters' original equipment disappear unless "keepitem"
// is found in the regex (except for fixed arts and unrand arts).
const bool keep_item = strip_tag(pattern, "keepitem");
// Dismiss by regex
text_pattern tpat(pattern);
int ndismissed = 0;
for (int mon = 0; mon < MAX_MONSTERS; mon++)
{
monsters *monster = &menv[mon];
if (monster->alive() &&
(tpat.empty() || tpat.matches(monster->name(DESC_PLAIN, true))))
{
if (!keep_item)
_vanish_orig_eq(monster);
monster_die(monster, KILL_DISMISSED, NON_MONSTER, false, true);
++ndismissed;
}
}
return (ndismissed);
}
}
// Make all of the monster's original equipment disappear, unless it's a fixed
// artefact or unrand artefact.
static void _vanish_orig_eq(monsters* mons)
{
for (int i = 0; i < NUM_MONSTER_SLOTS; ++i)
{
if (mons->inv[i] == NON_ITEM)
continue;
item_def &item(mitm[mons->inv[i]]);
if (!is_valid_item(item))
continue;
if (item.orig_place != 0 || item.orig_monnum != 0
|| !item.inscription.empty()
|| is_unrandom_artefact(item)
|| (item.flags & (ISFLAG_DROPPED | ISFLAG_THROWN | ISFLAG_NOTED_GET
| ISFLAG_BEEN_IN_INV) ) )
{
continue;
}
item.flags |= ISFLAG_SUMMONED;
}
// Make all of the monsters' original equipment disappear unless "keepitem"
// is found in the regex (except for fixed arts and unrand arts).
bool keep_item = false;
if (strstr(buf, "keepitem") != NULL)
{
std::string str = replace_all(buf, "keepitem", "");
trim_string(str);
strcpy(buf, str.c_str());
keep_item = true;
}
// Dismiss all
if (buf[0] == '\0' || force_all)
{
// Genocide... "unsummon" all the monsters from the level.
for (int mon = 0; mon < MAX_MONSTERS; mon++)
{
monsters *monster = &menv[mon];
if (monster->alive())
{
if (!keep_item)
_vanish_orig_eq(monster);
monster_die(monster, KILL_DISMISSED, NON_MONSTER, false, true);
}
}
// If it was turned off turn autopickup back on.
dismiss_monsters(buf);
// If it was turned off turn autopickup back on if all monsters went away.
if (!*buf)
return;
}
// Dismiss by regex
text_pattern tpat(buf);
for (int mon = 0; mon < MAX_MONSTERS; mon++)
{
monsters *monster = &menv[mon];
if (monster->alive() && tpat.matches(monster->name(DESC_PLAIN, true)))
{
if (!keep_item)
_vanish_orig_eq(monster);
monster_die(monster, KILL_DISMISSED, NON_MONSTER, false, true);
}
}
}
bool is_test_selected(const std::string &testname)
{
if (crawl_state.tests_selected.empty())
return (true);
for (int i = 0, size = crawl_state.tests_selected.size();
i < size; ++i)
{
const std::string &phrase(crawl_state.tests_selected[i]);
if (testname.find(phrase) != std::string::npos)
return (true);
}
return (false);