Files
oboe/test/monst_legacy.cpp

762 lines
32 KiB
C++

//
// monst_legacy.cpp
// BoE
//
// Created by Celtic Minstrel on 15-09-30.
//
//
#include "catch.hpp"
#include "universe/creature.hpp"
#include "oldstructs.hpp"
TEST_CASE("Converting monsters from legacy scenarios") {
// Some of the data in this struct is unused in scenarios.
// (It's only used in saved games.)
legacy::monster_record_type old_monst = {
0, 5, "Test Monster",
50, 50, 25, 25,
8, 10,
{108, 212, 306},
2, 1, 3, 4, 4, 2, 1, 0, 0, 3, 0, 0,
50, 50,
142, 75,
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
0, 0x44, 1, 1, 0, 0,
2, 1, 52, 0, 0, 0,
21,
};
cMonster new_monst;
SECTION("Basic monster") {
new_monst.import_legacy(old_monst);
CHECK(new_monst.level == 5);
CHECK(new_monst.m_name == "Test Monster");
CHECK(new_monst.m_health == 50);
CHECK(new_monst.armor == 8);
CHECK(new_monst.skill == 10);
CHECK(new_monst.m_type == eRace::IMPORTANT);
CHECK(new_monst.speed == 4);
CHECK(new_monst.mu == 2);
CHECK(new_monst.cl == 1);
CHECK(new_monst.treasure == 3);
CHECK(new_monst.corpse_item == 142);
CHECK(new_monst.corpse_item_chance == 75);
CHECK(new_monst.x_width == 1);
CHECK(new_monst.y_width == 1);
CHECK(new_monst.default_attitude == eAttitude::FRIENDLY);
CHECK(new_monst.default_facial_pic == 51);
CHECK(new_monst.picture_num == 21);
CHECK(new_monst.summon_type == 1);
CHECK(new_monst.ambient_sound == snd_num_t(-1));
CHECK(new_monst.see_spec == -1);
CHECK_FALSE(new_monst.mindless);
CHECK_FALSE(new_monst.invuln);
CHECK_FALSE(new_monst.invisible);
CHECK_FALSE(new_monst.guard);
// Attacks
CHECK(new_monst.a[0].dice == 1);
CHECK(new_monst.a[0].sides == 8);
CHECK(new_monst.a[0].type == eMonstMelee::BITE);
CHECK(new_monst.a[1].dice == 2);
CHECK(new_monst.a[1].sides == 12);
CHECK(new_monst.a[1].type == eMonstMelee::CLAW);
CHECK(new_monst.a[2].dice == 3);
CHECK(new_monst.a[2].sides == 6);
CHECK(new_monst.a[2].type == eMonstMelee::CLAW);
// Immunities
CHECK(new_monst.resist[eDamageType::WEAPON] == 100);
CHECK(new_monst.resist[eDamageType::MAGIC] == 100);
CHECK(new_monst.resist[eDamageType::FIRE] == 50);
CHECK(new_monst.resist[eDamageType::COLD] == 100);
CHECK(new_monst.resist[eDamageType::POISON] == 50);
CHECK(new_monst.resist[eDamageType::UNDEAD] == 100);
CHECK(new_monst.resist[eDamageType::DEMON] == 100);
CHECK(new_monst.resist[eDamageType::UNBLOCKABLE] == 100);
CHECK(new_monst.resist[eDamageType::SPECIAL] == 100);
// Abilities (should have none)
CHECK(new_monst.abil.size() == 0);
}
SECTION("With breath weapons") {
old_monst.breath = 12;
SECTION("Fire") {
old_monst.breath_type = 0;
new_monst.import_legacy(old_monst);
REQUIRE(new_monst.abil.size() == 1);
REQUIRE(new_monst.abil[eMonstAbil::DAMAGE2].active);
CHECK(new_monst.abil[eMonstAbil::DAMAGE2].gen.type == eMonstGen::BREATH);
CHECK(new_monst.abil[eMonstAbil::DAMAGE2].gen.pic == 13);
CHECK(new_monst.abil[eMonstAbil::DAMAGE2].gen.strength == 12);
CHECK(new_monst.abil[eMonstAbil::DAMAGE2].gen.range == 8);
CHECK(new_monst.abil[eMonstAbil::DAMAGE2].gen.odds == 375);
CHECK(new_monst.abil[eMonstAbil::DAMAGE2].gen.dmg == eDamageType::FIRE);
}
SECTION("Cold") {
old_monst.breath_type = 1;
new_monst.import_legacy(old_monst);
REQUIRE(new_monst.abil.size() == 1);
REQUIRE(new_monst.abil[eMonstAbil::DAMAGE2].active);
CHECK(new_monst.abil[eMonstAbil::DAMAGE2].gen.type == eMonstGen::BREATH);
CHECK(new_monst.abil[eMonstAbil::DAMAGE2].gen.pic == 6);
CHECK(new_monst.abil[eMonstAbil::DAMAGE2].gen.strength == 12);
CHECK(new_monst.abil[eMonstAbil::DAMAGE2].gen.range == 8);
CHECK(new_monst.abil[eMonstAbil::DAMAGE2].gen.odds == 375);
CHECK(new_monst.abil[eMonstAbil::DAMAGE2].gen.dmg == eDamageType::COLD);
}
SECTION("Electricity") {
old_monst.breath_type = 2;
new_monst.import_legacy(old_monst);
REQUIRE(new_monst.abil.size() == 1);
REQUIRE(new_monst.abil[eMonstAbil::DAMAGE2].active);
CHECK(new_monst.abil[eMonstAbil::DAMAGE2].gen.type == eMonstGen::BREATH);
CHECK(new_monst.abil[eMonstAbil::DAMAGE2].gen.pic == 8);
CHECK(new_monst.abil[eMonstAbil::DAMAGE2].gen.strength == 12);
CHECK(new_monst.abil[eMonstAbil::DAMAGE2].gen.range == 8);
CHECK(new_monst.abil[eMonstAbil::DAMAGE2].gen.odds == 375);
CHECK(new_monst.abil[eMonstAbil::DAMAGE2].gen.dmg == eDamageType::MAGIC);
}
SECTION("Darkness") {
old_monst.breath_type = 3;
new_monst.import_legacy(old_monst);
REQUIRE(new_monst.abil.size() == 1);
REQUIRE(new_monst.abil[eMonstAbil::DAMAGE2].active);
CHECK(new_monst.abil[eMonstAbil::DAMAGE2].gen.type == eMonstGen::BREATH);
CHECK(new_monst.abil[eMonstAbil::DAMAGE2].gen.pic == 8);
CHECK(new_monst.abil[eMonstAbil::DAMAGE2].gen.strength == 12);
CHECK(new_monst.abil[eMonstAbil::DAMAGE2].gen.range == 8);
CHECK(new_monst.abil[eMonstAbil::DAMAGE2].gen.odds == 375);
CHECK(new_monst.abil[eMonstAbil::DAMAGE2].gen.dmg == eDamageType::UNBLOCKABLE);
}
}
SECTION("With poison") {
old_monst.poison = 8;
new_monst.import_legacy(old_monst);
REQUIRE(new_monst.abil.size() == 1);
REQUIRE(new_monst.abil[eMonstAbil::STATUS2].active);
CHECK(new_monst.abil[eMonstAbil::STATUS2].gen.type == eMonstGen::TOUCH);
CHECK(new_monst.abil[eMonstAbil::STATUS2].gen.strength == 8);
CHECK(new_monst.abil[eMonstAbil::STATUS2].gen.odds == 1000);
CHECK(new_monst.abil[eMonstAbil::STATUS2].gen.stat == eStatus::POISON);
}
SECTION("With primary abilities") {
SECTION("Throws Darts") {
old_monst.spec_skill = 1;
new_monst.import_legacy(old_monst);
REQUIRE(new_monst.abil.size() == 1);
REQUIRE(new_monst.abil[eMonstAbil::MISSILE].active);
CHECK(new_monst.abil[eMonstAbil::MISSILE].missile.type == eMonstMissile::DART);
CHECK(new_monst.abil[eMonstAbil::MISSILE].missile.pic == 1);
CHECK(new_monst.abil[eMonstAbil::MISSILE].missile.dice == 1);
CHECK(new_monst.abil[eMonstAbil::MISSILE].missile.sides == 7);
CHECK(new_monst.abil[eMonstAbil::MISSILE].missile.skill == 2);
CHECK(new_monst.abil[eMonstAbil::MISSILE].missile.range == 6);
CHECK(new_monst.abil[eMonstAbil::MISSILE].missile.odds == 500);
}
SECTION("Shoots Arrows") {
old_monst.spec_skill = 2;
new_monst.import_legacy(old_monst);
REQUIRE(new_monst.abil.size() == 1);
REQUIRE(new_monst.abil[eMonstAbil::MISSILE].active);
CHECK(new_monst.abil[eMonstAbil::MISSILE].missile.type == eMonstMissile::ARROW);
CHECK(new_monst.abil[eMonstAbil::MISSILE].missile.pic == 3);
CHECK(new_monst.abil[eMonstAbil::MISSILE].missile.dice == 2);
CHECK(new_monst.abil[eMonstAbil::MISSILE].missile.sides == 7);
CHECK(new_monst.abil[eMonstAbil::MISSILE].missile.skill == 4);
CHECK(new_monst.abil[eMonstAbil::MISSILE].missile.range == 8);
CHECK(new_monst.abil[eMonstAbil::MISSILE].missile.odds == 750);
}
SECTION("Throws Spears") {
old_monst.spec_skill = 3;
new_monst.import_legacy(old_monst);
REQUIRE(new_monst.abil.size() == 1);
REQUIRE(new_monst.abil[eMonstAbil::MISSILE].active);
CHECK(new_monst.abil[eMonstAbil::MISSILE].missile.type == eMonstMissile::SPEAR);
CHECK(new_monst.abil[eMonstAbil::MISSILE].missile.pic == 5);
CHECK(new_monst.abil[eMonstAbil::MISSILE].missile.dice == 3);
CHECK(new_monst.abil[eMonstAbil::MISSILE].missile.sides == 7);
CHECK(new_monst.abil[eMonstAbil::MISSILE].missile.skill == 6);
CHECK(new_monst.abil[eMonstAbil::MISSILE].missile.range == 8);
CHECK(new_monst.abil[eMonstAbil::MISSILE].missile.odds == 625);
}
SECTION("Throws Rocks 4-24") {
old_monst.spec_skill = 4;
new_monst.import_legacy(old_monst);
REQUIRE(new_monst.abil.size() == 1);
REQUIRE(new_monst.abil[eMonstAbil::MISSILE].active);
CHECK(new_monst.abil[eMonstAbil::MISSILE].missile.type == eMonstMissile::BOULDER);
CHECK(new_monst.abil[eMonstAbil::MISSILE].missile.pic == 12);
CHECK(new_monst.abil[eMonstAbil::MISSILE].missile.dice == 4);
CHECK(new_monst.abil[eMonstAbil::MISSILE].missile.sides == 7);
CHECK(new_monst.abil[eMonstAbil::MISSILE].missile.skill == 8);
CHECK(new_monst.abil[eMonstAbil::MISSILE].missile.range == 10);
CHECK(new_monst.abil[eMonstAbil::MISSILE].missile.odds == 625);
}
SECTION("Throws Rocks 5-30") {
old_monst.spec_skill = 5;
new_monst.import_legacy(old_monst);
REQUIRE(new_monst.abil.size() == 1);
REQUIRE(new_monst.abil[eMonstAbil::MISSILE].active);
CHECK(new_monst.abil[eMonstAbil::MISSILE].missile.type == eMonstMissile::BOULDER);
CHECK(new_monst.abil[eMonstAbil::MISSILE].missile.pic == 12);
CHECK(new_monst.abil[eMonstAbil::MISSILE].missile.dice == 6);
CHECK(new_monst.abil[eMonstAbil::MISSILE].missile.sides == 7);
CHECK(new_monst.abil[eMonstAbil::MISSILE].missile.skill == 12);
CHECK(new_monst.abil[eMonstAbil::MISSILE].missile.range == 10);
CHECK(new_monst.abil[eMonstAbil::MISSILE].missile.odds == 500);
}
SECTION("Throws Rocks 6-36") {
old_monst.spec_skill = 6;
new_monst.import_legacy(old_monst);
REQUIRE(new_monst.abil.size() == 1);
REQUIRE(new_monst.abil[eMonstAbil::MISSILE].active);
CHECK(new_monst.abil[eMonstAbil::MISSILE].missile.type == eMonstMissile::BOULDER);
CHECK(new_monst.abil[eMonstAbil::MISSILE].missile.pic == 12);
CHECK(new_monst.abil[eMonstAbil::MISSILE].missile.dice == 8);
CHECK(new_monst.abil[eMonstAbil::MISSILE].missile.sides == 7);
CHECK(new_monst.abil[eMonstAbil::MISSILE].missile.skill == 16);
CHECK(new_monst.abil[eMonstAbil::MISSILE].missile.range == 10);
CHECK(new_monst.abil[eMonstAbil::MISSILE].missile.odds == 500);
}
SECTION("Throws Razordisks") {
old_monst.spec_skill = 7;
new_monst.import_legacy(old_monst);
REQUIRE(new_monst.abil.size() == 1);
REQUIRE(new_monst.abil[eMonstAbil::MISSILE].active);
CHECK(new_monst.abil[eMonstAbil::MISSILE].missile.type == eMonstMissile::RAZORDISK);
CHECK(new_monst.abil[eMonstAbil::MISSILE].missile.pic == 7);
CHECK(new_monst.abil[eMonstAbil::MISSILE].missile.dice == 7);
CHECK(new_monst.abil[eMonstAbil::MISSILE].missile.sides == 7);
CHECK(new_monst.abil[eMonstAbil::MISSILE].missile.skill == 14);
CHECK(new_monst.abil[eMonstAbil::MISSILE].missile.range == 8);
CHECK(new_monst.abil[eMonstAbil::MISSILE].missile.odds == 625);
}
SECTION("Petrification Ray") {
old_monst.spec_skill = 8;
new_monst.import_legacy(old_monst);
REQUIRE(new_monst.abil.size() == 1);
REQUIRE(new_monst.abil[eMonstAbil::PETRIFY].active);
CHECK(new_monst.abil[eMonstAbil::PETRIFY].gen.type == eMonstGen::GAZE);
CHECK(new_monst.abil[eMonstAbil::PETRIFY].gen.strength == 25);
CHECK(new_monst.abil[eMonstAbil::PETRIFY].gen.range == 6);
CHECK(new_monst.abil[eMonstAbil::PETRIFY].gen.odds == 625);
}
SECTION("Spell Point Drain Ray") {
old_monst.spec_skill = 9;
new_monst.import_legacy(old_monst);
REQUIRE(new_monst.abil.size() == 1);
REQUIRE(new_monst.abil[eMonstAbil::DRAIN_SP].active);
CHECK(new_monst.abil[eMonstAbil::DRAIN_SP].gen.type == eMonstGen::GAZE);
CHECK(new_monst.abil[eMonstAbil::DRAIN_SP].gen.strength == 50);
CHECK(new_monst.abil[eMonstAbil::DRAIN_SP].gen.range == 8);
CHECK(new_monst.abil[eMonstAbil::DRAIN_SP].gen.odds == 625);
}
SECTION("Heat Ray") {
old_monst.spec_skill = 10;
new_monst.import_legacy(old_monst);
REQUIRE(new_monst.abil.size() == 1);
REQUIRE(new_monst.abil[eMonstAbil::RAY_HEAT].active);
CHECK(new_monst.abil[eMonstAbil::RAY_HEAT].special.extra1 == 6);
CHECK(new_monst.abil[eMonstAbil::RAY_HEAT].special.extra2 == 625);
CHECK(new_monst.abil[eMonstAbil::RAY_HEAT].special.extra3 == 7);
}
SECTION("Invisible") {
old_monst.spec_skill = 11;
new_monst.import_legacy(old_monst);
CHECK(new_monst.abil.size() == 0);
CHECK(new_monst.invisible);
}
SECTION("Splits When Hit") {
old_monst.spec_skill = 12;
new_monst.import_legacy(old_monst);
REQUIRE(new_monst.abil.size() == 1);
REQUIRE(new_monst.abil[eMonstAbil::SPLITS].active);
CHECK(new_monst.abil[eMonstAbil::SPLITS].special.extra1 == 1000);
CHECK(new_monst.amorphous);
}
SECTION("Mindless") {
old_monst.spec_skill = 13;
new_monst.import_legacy(old_monst);
CHECK(new_monst.abil.size() == 0);
CHECK(new_monst.mindless);
}
SECTION("Breathes Stinking Clouds") {
old_monst.spec_skill = 14;
new_monst.import_legacy(old_monst);
REQUIRE(new_monst.abil.size() == 1);
REQUIRE(new_monst.abil[eMonstAbil::FIELD].active);
CHECK(new_monst.abil[eMonstAbil::FIELD].gen.type == eMonstGen::BREATH);
CHECK(new_monst.abil[eMonstAbil::FIELD].gen.pic == 12);
CHECK(new_monst.abil[eMonstAbil::FIELD].gen.strength == PAT_SINGLE);
CHECK(new_monst.abil[eMonstAbil::FIELD].gen.range == 6);
CHECK(new_monst.abil[eMonstAbil::FIELD].gen.odds == 375);
CHECK(new_monst.abil[eMonstAbil::FIELD].gen.fld == CLOUD_STINK);
}
SECTION("Icy Touch") {
old_monst.spec_skill = 15;
new_monst.import_legacy(old_monst);
REQUIRE(new_monst.abil.size() == 1);
REQUIRE(new_monst.abil[eMonstAbil::DAMAGE].active);
CHECK(new_monst.abil[eMonstAbil::DAMAGE].gen.type == eMonstGen::TOUCH);
CHECK(new_monst.abil[eMonstAbil::DAMAGE].gen.strength == 3);
CHECK(new_monst.abil[eMonstAbil::DAMAGE].gen.odds == 667);
CHECK(new_monst.abil[eMonstAbil::DAMAGE].gen.dmg == eDamageType::COLD);
}
SECTION("Experience Draining Touch") {
old_monst.spec_skill = 16;
new_monst.import_legacy(old_monst);
REQUIRE(new_monst.abil.size() == 1);
REQUIRE(new_monst.abil[eMonstAbil::DRAIN_XP].active);
CHECK(new_monst.abil[eMonstAbil::DRAIN_XP].gen.type == eMonstGen::TOUCH);
CHECK(new_monst.abil[eMonstAbil::DRAIN_XP].gen.strength == 150);
CHECK(new_monst.abil[eMonstAbil::DRAIN_XP].gen.odds == 0);
}
SECTION("Icy and Draining Touch") {
old_monst.spec_skill = 17;
new_monst.import_legacy(old_monst);
REQUIRE(new_monst.abil.size() == 2);
REQUIRE(new_monst.abil[eMonstAbil::DAMAGE].active);
CHECK(new_monst.abil[eMonstAbil::DAMAGE].gen.type == eMonstGen::TOUCH);
CHECK(new_monst.abil[eMonstAbil::DAMAGE].gen.strength == 3);
CHECK(new_monst.abil[eMonstAbil::DAMAGE].gen.odds == 667);
CHECK(new_monst.abil[eMonstAbil::DAMAGE].gen.dmg == eDamageType::COLD);
REQUIRE(new_monst.abil[eMonstAbil::DRAIN_XP].active);
CHECK(new_monst.abil[eMonstAbil::DRAIN_XP].gen.type == eMonstGen::TOUCH);
CHECK(new_monst.abil[eMonstAbil::DRAIN_XP].gen.strength == 150);
CHECK(new_monst.abil[eMonstAbil::DRAIN_XP].gen.odds == 0);
}
SECTION("Slowing Touch") {
old_monst.spec_skill = 18;
new_monst.import_legacy(old_monst);
REQUIRE(new_monst.abil.size() == 1);
REQUIRE(new_monst.abil[eMonstAbil::STUN].active);
CHECK(new_monst.abil[eMonstAbil::STUN].gen.type == eMonstGen::TOUCH);
CHECK(new_monst.abil[eMonstAbil::STUN].gen.strength == 2);
CHECK(new_monst.abil[eMonstAbil::STUN].gen.odds == 667);
CHECK(new_monst.abil[eMonstAbil::STUN].gen.stat == eStatus::HASTE_SLOW);
}
SECTION("Shoots Web") {
old_monst.spec_skill = 19;
new_monst.import_legacy(old_monst);
REQUIRE(new_monst.abil.size() == 1);
REQUIRE(new_monst.abil[eMonstAbil::MISSILE_WEB].active);
CHECK(new_monst.abil[eMonstAbil::MISSILE_WEB].special.extra1 == 4);
CHECK(new_monst.abil[eMonstAbil::MISSILE_WEB].special.extra2 == 375);
}
SECTION("Good Archer") {
old_monst.spec_skill = 20;
new_monst.import_legacy(old_monst);
REQUIRE(new_monst.abil.size() == 1);
REQUIRE(new_monst.abil[eMonstAbil::MISSILE].active);
CHECK(new_monst.abil[eMonstAbil::MISSILE].missile.type == eMonstMissile::RAPID_ARROW);
CHECK(new_monst.abil[eMonstAbil::MISSILE].missile.pic == 3);
CHECK(new_monst.abil[eMonstAbil::MISSILE].missile.dice == 8);
CHECK(new_monst.abil[eMonstAbil::MISSILE].missile.sides == 7);
CHECK(new_monst.abil[eMonstAbil::MISSILE].missile.skill == 16);
CHECK(new_monst.abil[eMonstAbil::MISSILE].missile.range == 10);
CHECK(new_monst.abil[eMonstAbil::MISSILE].missile.odds == 875);
}
SECTION("Steals Food") {
old_monst.spec_skill = 21;
new_monst.import_legacy(old_monst);
REQUIRE(new_monst.abil.size() == 1);
REQUIRE(new_monst.abil[eMonstAbil::STEAL_FOOD].active);
CHECK(new_monst.abil[eMonstAbil::STEAL_FOOD].gen.type == eMonstGen::TOUCH);
CHECK(new_monst.abil[eMonstAbil::STEAL_FOOD].gen.strength == 10);
CHECK(new_monst.abil[eMonstAbil::STEAL_FOOD].gen.odds == 667);
}
SECTION("Permanent Martyr's Shield") {
old_monst.spec_skill = 22;
new_monst.import_legacy(old_monst);
REQUIRE(new_monst.abil.size() == 1);
REQUIRE(new_monst.abil[eMonstAbil::MARTYRS_SHIELD].active);
CHECK(new_monst.abil[eMonstAbil::MARTYRS_SHIELD].special.extra1 == 1000);
CHECK(new_monst.abil[eMonstAbil::MARTYRS_SHIELD].special.extra2 == 100);
}
SECTION("Paralysis Ray") {
old_monst.spec_skill = 23;
new_monst.import_legacy(old_monst);
REQUIRE(new_monst.abil.size() == 1);
REQUIRE(new_monst.abil[eMonstAbil::STATUS].active);
CHECK(new_monst.abil[eMonstAbil::STATUS].gen.type == eMonstGen::RAY);
CHECK(new_monst.abil[eMonstAbil::STATUS].gen.strength == 100);
CHECK(new_monst.abil[eMonstAbil::STATUS].gen.range == 6);
CHECK(new_monst.abil[eMonstAbil::STATUS].gen.odds == 750);
CHECK(new_monst.abil[eMonstAbil::STATUS].gen.stat == eStatus::PARALYZED);
}
SECTION("Dumbfounding Touch") {
old_monst.spec_skill = 24;
new_monst.import_legacy(old_monst);
REQUIRE(new_monst.abil.size() == 1);
REQUIRE(new_monst.abil[eMonstAbil::STATUS].active);
CHECK(new_monst.abil[eMonstAbil::STATUS].gen.type == eMonstGen::TOUCH);
CHECK(new_monst.abil[eMonstAbil::STATUS].gen.strength == 2);
CHECK(new_monst.abil[eMonstAbil::STATUS].gen.odds == 1000);
CHECK(new_monst.abil[eMonstAbil::STATUS].gen.stat == eStatus::DUMB);
}
SECTION("Disease Touch") {
old_monst.spec_skill = 25;
new_monst.import_legacy(old_monst);
REQUIRE(new_monst.abil.size() == 1);
REQUIRE(new_monst.abil[eMonstAbil::STATUS].active);
CHECK(new_monst.abil[eMonstAbil::STATUS].gen.type == eMonstGen::TOUCH);
CHECK(new_monst.abil[eMonstAbil::STATUS].gen.strength == 6);
CHECK(new_monst.abil[eMonstAbil::STATUS].gen.odds == 667);
CHECK(new_monst.abil[eMonstAbil::STATUS].gen.stat == eStatus::DISEASE);
}
SECTION("Absorbs Spells") {
old_monst.spec_skill = 26;
new_monst.import_legacy(old_monst);
REQUIRE(new_monst.abil.size() == 1);
REQUIRE(new_monst.abil[eMonstAbil::ABSORB_SPELLS].active);
CHECK(new_monst.abil[eMonstAbil::ABSORB_SPELLS].special.extra1 == 1000);
CHECK(new_monst.abil[eMonstAbil::ABSORB_SPELLS].special.extra2 == 3);
}
SECTION("Web Touch") {
old_monst.spec_skill = 27;
new_monst.import_legacy(old_monst);
REQUIRE(new_monst.abil.size() == 1);
REQUIRE(new_monst.abil[eMonstAbil::STATUS].active);
CHECK(new_monst.abil[eMonstAbil::STATUS].gen.type == eMonstGen::TOUCH);
CHECK(new_monst.abil[eMonstAbil::STATUS].gen.strength == 5);
CHECK(new_monst.abil[eMonstAbil::STATUS].gen.odds == 1000);
CHECK(new_monst.abil[eMonstAbil::STATUS].gen.stat == eStatus::WEBS);
}
SECTION("Sleep Touch") {
old_monst.spec_skill = 28;
new_monst.import_legacy(old_monst);
REQUIRE(new_monst.abil.size() == 1);
REQUIRE(new_monst.abil[eMonstAbil::STATUS].active);
CHECK(new_monst.abil[eMonstAbil::STATUS].gen.type == eMonstGen::TOUCH);
CHECK(new_monst.abil[eMonstAbil::STATUS].gen.strength == 6);
CHECK(new_monst.abil[eMonstAbil::STATUS].gen.odds == 1000);
CHECK(new_monst.abil[eMonstAbil::STATUS].gen.stat == eStatus::ASLEEP);
}
SECTION("Paralysis Touch") {
old_monst.spec_skill = 29;
new_monst.import_legacy(old_monst);
REQUIRE(new_monst.abil.size() == 1);
REQUIRE(new_monst.abil[eMonstAbil::STATUS].active);
CHECK(new_monst.abil[eMonstAbil::STATUS].gen.type == eMonstGen::TOUCH);
CHECK(new_monst.abil[eMonstAbil::STATUS].gen.strength == 500);
CHECK(new_monst.abil[eMonstAbil::STATUS].gen.odds == 0);
CHECK(new_monst.abil[eMonstAbil::STATUS].gen.stat == eStatus::PARALYZED);
}
SECTION("Petrification Touch") {
old_monst.spec_skill = 30;
new_monst.import_legacy(old_monst);
REQUIRE(new_monst.abil.size() == 1);
REQUIRE(new_monst.abil[eMonstAbil::PETRIFY].active);
CHECK(new_monst.abil[eMonstAbil::PETRIFY].gen.type == eMonstGen::TOUCH);
CHECK(new_monst.abil[eMonstAbil::PETRIFY].gen.strength == 25);
CHECK(new_monst.abil[eMonstAbil::PETRIFY].gen.odds == 0);
}
SECTION("Acid Touch") {
old_monst.spec_skill = 31;
new_monst.import_legacy(old_monst);
REQUIRE(new_monst.abil.size() == 1);
REQUIRE(new_monst.abil[eMonstAbil::STATUS].active);
CHECK(new_monst.abil[eMonstAbil::STATUS].gen.type == eMonstGen::TOUCH);
CHECK(new_monst.abil[eMonstAbil::STATUS].gen.strength == 2);
CHECK(new_monst.abil[eMonstAbil::STATUS].gen.odds == 1000);
CHECK(new_monst.abil[eMonstAbil::STATUS].gen.stat == eStatus::ACID);
}
SECTION("Breathes Sleep Clouds") {
old_monst.spec_skill = 32;
new_monst.import_legacy(old_monst);
REQUIRE(new_monst.abil.size() == 1);
REQUIRE(new_monst.abil[eMonstAbil::FIELD].active);
CHECK(new_monst.abil[eMonstAbil::FIELD].gen.type == eMonstGen::BREATH);
CHECK(new_monst.abil[eMonstAbil::FIELD].gen.pic == 0);
CHECK(new_monst.abil[eMonstAbil::FIELD].gen.strength == PAT_RAD2);
CHECK(new_monst.abil[eMonstAbil::FIELD].gen.range == 8);
CHECK(new_monst.abil[eMonstAbil::FIELD].gen.odds == 750);
CHECK(new_monst.abil[eMonstAbil::FIELD].gen.fld == CLOUD_SLEEP);
}
SECTION("Acid Spit") {
old_monst.spec_skill = 33;
new_monst.import_legacy(old_monst);
REQUIRE(new_monst.abil.size() == 1);
REQUIRE(new_monst.abil[eMonstAbil::STATUS].active);
CHECK(new_monst.abil[eMonstAbil::STATUS].gen.type == eMonstGen::SPIT);
CHECK(new_monst.abil[eMonstAbil::STATUS].gen.pic == 0);
CHECK(new_monst.abil[eMonstAbil::STATUS].gen.strength == 6);
CHECK(new_monst.abil[eMonstAbil::STATUS].gen.range == 6);
CHECK(new_monst.abil[eMonstAbil::STATUS].gen.odds == 500);
CHECK(new_monst.abil[eMonstAbil::STATUS].gen.stat == eStatus::ACID);
}
SECTION("Shoots Spines") {
old_monst.spec_skill = 34;
new_monst.import_legacy(old_monst);
REQUIRE(new_monst.abil.size() == 1);
REQUIRE(new_monst.abil[eMonstAbil::MISSILE].active);
CHECK(new_monst.abil[eMonstAbil::MISSILE].missile.type == eMonstMissile::SPINE);
CHECK(new_monst.abil[eMonstAbil::MISSILE].missile.pic == 5);
CHECK(new_monst.abil[eMonstAbil::MISSILE].missile.dice == 6);
CHECK(new_monst.abil[eMonstAbil::MISSILE].missile.sides == 7);
CHECK(new_monst.abil[eMonstAbil::MISSILE].missile.skill == 12);
CHECK(new_monst.abil[eMonstAbil::MISSILE].missile.range == 9);
CHECK(new_monst.abil[eMonstAbil::MISSILE].missile.odds == 625);
}
SECTION("Death Touch") {
old_monst.spec_skill = 35;
new_monst.import_legacy(old_monst);
REQUIRE(new_monst.abil.size() == 1);
REQUIRE(new_monst.abil[eMonstAbil::KILL].active);
CHECK(new_monst.abil[eMonstAbil::KILL].gen.type == eMonstGen::TOUCH);
CHECK(new_monst.abil[eMonstAbil::KILL].gen.strength == 2);
CHECK(new_monst.abil[eMonstAbil::KILL].gen.odds == 667);
}
SECTION("Invulnerable") {
old_monst.spec_skill = 36;
new_monst.import_legacy(old_monst);
CHECK(new_monst.abil.size() == 0);
CHECK(new_monst.invuln);
}
SECTION("Guard") {
old_monst.spec_skill = 37;
new_monst.import_legacy(old_monst);
CHECK(new_monst.abil.size() == 0);
CHECK(new_monst.guard);
}
}
SECTION("With secondary abilities") {
old_monst.radiate_2 = 50;
SECTION("Radiate Fire Fields") {
old_monst.radiate_1 = 1;
new_monst.import_legacy(old_monst);
REQUIRE(new_monst.abil.size() == 1);
REQUIRE(new_monst.abil[eMonstAbil::RADIATE].active);
CHECK(new_monst.abil[eMonstAbil::RADIATE].radiate.type == WALL_FIRE);
CHECK(new_monst.abil[eMonstAbil::RADIATE].radiate.chance == 50);
CHECK(new_monst.abil[eMonstAbil::RADIATE].radiate.pat == PAT_SQ);
}
SECTION("Radiate Ice Fields") {
old_monst.radiate_1 = 2;
new_monst.import_legacy(old_monst);
REQUIRE(new_monst.abil.size() == 1);
REQUIRE(new_monst.abil[eMonstAbil::RADIATE].active);
CHECK(new_monst.abil[eMonstAbil::RADIATE].radiate.type == WALL_ICE);
CHECK(new_monst.abil[eMonstAbil::RADIATE].radiate.chance == 50);
CHECK(new_monst.abil[eMonstAbil::RADIATE].radiate.pat == PAT_SQ);
}
SECTION("Radiate Shock Fields") {
old_monst.radiate_1 = 3;
new_monst.import_legacy(old_monst);
REQUIRE(new_monst.abil.size() == 1);
REQUIRE(new_monst.abil[eMonstAbil::RADIATE].active);
CHECK(new_monst.abil[eMonstAbil::RADIATE].radiate.type == WALL_FORCE);
CHECK(new_monst.abil[eMonstAbil::RADIATE].radiate.chance == 50);
CHECK(new_monst.abil[eMonstAbil::RADIATE].radiate.pat == PAT_SQ);
}
SECTION("Radiate Antimagic Fields") {
old_monst.radiate_1 = 4;
new_monst.import_legacy(old_monst);
REQUIRE(new_monst.abil.size() == 1);
REQUIRE(new_monst.abil[eMonstAbil::RADIATE].active);
CHECK(new_monst.abil[eMonstAbil::RADIATE].radiate.type == FIELD_ANTIMAGIC);
CHECK(new_monst.abil[eMonstAbil::RADIATE].radiate.chance == 50);
CHECK(new_monst.abil[eMonstAbil::RADIATE].radiate.pat == PAT_SQ);
}
SECTION("Radiate Sleep Fields") {
old_monst.radiate_1 = 5;
new_monst.import_legacy(old_monst);
REQUIRE(new_monst.abil.size() == 1);
REQUIRE(new_monst.abil[eMonstAbil::RADIATE].active);
CHECK(new_monst.abil[eMonstAbil::RADIATE].radiate.type == CLOUD_SLEEP);
CHECK(new_monst.abil[eMonstAbil::RADIATE].radiate.chance == 50);
CHECK(new_monst.abil[eMonstAbil::RADIATE].radiate.pat == PAT_SQ);
}
SECTION("Radiate Stink Fields") {
old_monst.radiate_1 = 6;
new_monst.import_legacy(old_monst);
REQUIRE(new_monst.abil.size() == 1);
REQUIRE(new_monst.abil[eMonstAbil::RADIATE].active);
CHECK(new_monst.abil[eMonstAbil::RADIATE].radiate.type == CLOUD_STINK);
CHECK(new_monst.abil[eMonstAbil::RADIATE].radiate.chance == 50);
CHECK(new_monst.abil[eMonstAbil::RADIATE].radiate.pat == PAT_SQ);
}
SECTION("Summon 5% chance") {
old_monst.radiate_1 = 10;
new_monst.import_legacy(old_monst);
REQUIRE(new_monst.abil.size() == 1);
REQUIRE(new_monst.abil[eMonstAbil::SUMMON].active);
CHECK(new_monst.abil[eMonstAbil::SUMMON].summon.type == eMonstSummon::TYPE);
CHECK(new_monst.abil[eMonstAbil::SUMMON].summon.what == 50);
CHECK(new_monst.abil[eMonstAbil::SUMMON].summon.min == 1);
CHECK(new_monst.abil[eMonstAbil::SUMMON].summon.max == 1);
CHECK(new_monst.abil[eMonstAbil::SUMMON].summon.len == 130);
CHECK(new_monst.abil[eMonstAbil::SUMMON].summon.chance == 50);
}
SECTION("Summon 20% chance") {
old_monst.radiate_1 = 11;
new_monst.import_legacy(old_monst);
REQUIRE(new_monst.abil.size() == 1);
REQUIRE(new_monst.abil[eMonstAbil::SUMMON].active);
CHECK(new_monst.abil[eMonstAbil::SUMMON].summon.type == eMonstSummon::TYPE);
CHECK(new_monst.abil[eMonstAbil::SUMMON].summon.what == 50);
CHECK(new_monst.abil[eMonstAbil::SUMMON].summon.min == 1);
CHECK(new_monst.abil[eMonstAbil::SUMMON].summon.max == 1);
CHECK(new_monst.abil[eMonstAbil::SUMMON].summon.len == 130);
CHECK(new_monst.abil[eMonstAbil::SUMMON].summon.chance == 200);
}
SECTION("Summon 50% chance") {
old_monst.radiate_1 = 12;
new_monst.import_legacy(old_monst);
REQUIRE(new_monst.abil.size() == 1);
REQUIRE(new_monst.abil[eMonstAbil::SUMMON].active);
CHECK(new_monst.abil[eMonstAbil::SUMMON].summon.type == eMonstSummon::TYPE);
CHECK(new_monst.abil[eMonstAbil::SUMMON].summon.what == 50);
CHECK(new_monst.abil[eMonstAbil::SUMMON].summon.min == 1);
CHECK(new_monst.abil[eMonstAbil::SUMMON].summon.max == 1);
CHECK(new_monst.abil[eMonstAbil::SUMMON].summon.len == 130);
CHECK(new_monst.abil[eMonstAbil::SUMMON].summon.chance == 500);
}
SECTION("Death Triggers Scenario Special") {
old_monst.radiate_1 = 15;
new_monst.import_legacy(old_monst);
REQUIRE(new_monst.abil.size() == 1);
REQUIRE(new_monst.abil[eMonstAbil::DEATH_TRIGGER].active);
CHECK(new_monst.abil[eMonstAbil::DEATH_TRIGGER].special.extra1 == 50);
}
}
SECTION("With multiple abilities") {
SECTION("Poison and acid touch") {
old_monst.poison = 8;
old_monst.spec_skill = 31;
new_monst.import_legacy(old_monst);
REQUIRE(new_monst.abil.size() == 2);
CHECK(new_monst.abil[eMonstAbil::STATUS].active);
CHECK(new_monst.abil[eMonstAbil::STATUS2].active);
}
SECTION("Poison and stun") {
old_monst.poison = 8;
old_monst.spec_skill = 18;
new_monst.import_legacy(old_monst);
REQUIRE(new_monst.abil.size() == 2);
CHECK(new_monst.abil[eMonstAbil::STATUS2].active);
CHECK(new_monst.abil[eMonstAbil::STUN].active);
}
SECTION("Fire breath and icy+draining touch") {
old_monst.breath = 8;
old_monst.breath_type = 1;
old_monst.spec_skill = 17;
new_monst.import_legacy(old_monst);
REQUIRE(new_monst.abil.size() == 3);
CHECK(new_monst.abil[eMonstAbil::DAMAGE].active);
CHECK(new_monst.abil[eMonstAbil::DAMAGE2].active);
CHECK(new_monst.abil[eMonstAbil::DRAIN_XP].active);
}
}
}
TEST_CASE("Converting placed monsters from legacy scenarios") {
legacy::creature_start_type old_monst = {12, 1, {4,4}, 1, 0, 0, 0, 5, 7, 8, 0, 0, 13, 9, 27};
cTownperson new_monst;
SECTION("Basic info") {
new_monst.import_legacy(old_monst);
CHECK(new_monst.number == 12);
CHECK(new_monst.start_attitude == eAttitude::HOSTILE_A);
CHECK(new_monst.start_loc == loc(4,4));
CHECK(new_monst.mobility == 1);
CHECK(new_monst.spec1 == 5);
CHECK(new_monst.spec2 == 7);
CHECK(new_monst.spec_enc_code == 8);
CHECK(new_monst.personality == 13);
CHECK(new_monst.special_on_kill == 9);
CHECK(new_monst.facial_pic == 26);
}
SECTION("With time flag") {
old_monst.monster_time = 17;
old_monst.time_code = 19;
SECTION("Appear on day") {
old_monst.time_flag = 1;
new_monst.import_legacy(old_monst);
CHECK(new_monst.time_flag == eMonstTime::APPEAR_ON_DAY);
}
SECTION("Disappear on day") {
old_monst.time_flag = 2;
new_monst.import_legacy(old_monst);
CHECK(new_monst.time_flag == eMonstTime::DISAPPEAR_ON_DAY);
}
SECTION("Sometimes A") {
old_monst.time_flag = 4;
new_monst.import_legacy(old_monst);
CHECK(new_monst.time_flag == eMonstTime::SOMETIMES_A);
}
SECTION("Sometimes B") {
old_monst.time_flag = 5;
new_monst.import_legacy(old_monst);
CHECK(new_monst.time_flag == eMonstTime::SOMETIMES_B);
}
SECTION("Sometimes C") {
old_monst.time_flag = 6;
new_monst.import_legacy(old_monst);
CHECK(new_monst.time_flag == eMonstTime::SOMETIMES_C);
}
SECTION("Appear when event") {
old_monst.time_flag = 7;
new_monst.import_legacy(old_monst);
CHECK(new_monst.time_flag == eMonstTime::APPEAR_WHEN_EVENT);
}
SECTION("Disappear when event") {
old_monst.time_flag = 8;
new_monst.import_legacy(old_monst);
CHECK(new_monst.time_flag == eMonstTime::DISAPPEAR_WHEN_EVENT);
}
CHECK(new_monst.monster_time == 17);
CHECK(new_monst.time_code == 19);
}
}
TEST_CASE("Converting monsters from legacy saves") {
legacy::monster_record_type old_monst_base = {
0, 5, "Test Monster",
45, 50, 20, 25,
8, 10,
{108, 212, 306},
2, 1, 3, 4, 2, 2, 1, 0, 0, 3, 0, 0,
40, 50,
142, 75,
{0, 0, 5, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0},
0, 0x44, 1, 1, 0, 0,
2, 1, 52, 0, 0, 0,
21,
};
legacy::creature_start_type old_monst_start = {12, 1, {4,4}, 1, 0, 0, 0, 0, 0, 0, 0, 0, 13, 0, 27};
legacy::creature_data_type old_monst = {1, 3, 11, 0, {7,8}, old_monst_base, 0, 0, old_monst_start};
cCreature new_monst;
SECTION("Basic info") {
new_monst.import_legacy(old_monst);
CHECK(new_monst.m_name == "Test Monster");
CHECK(new_monst.health == 45);
CHECK(new_monst.m_health == 50);
CHECK(new_monst.mp == 20);
CHECK(new_monst.max_mp == 25);
CHECK(new_monst.morale == 40);
CHECK(new_monst.m_morale == 50);
CHECK(new_monst.ap == 2);
CHECK(new_monst.direction == DIR_N);
CHECK(new_monst.status[eStatus::POISON] == 5);
CHECK(new_monst.status[eStatus::WEBS] == 7);
CHECK(new_monst.number == 12);
CHECK(new_monst.active == 1);
CHECK(new_monst.attitude == eAttitude::HOSTILE_B);
CHECK(new_monst.cur_loc == loc(7,8));
CHECK(new_monst.mobility == 1);
}
SECTION("Summoned by party") {
old_monst.summoned = 20;
new_monst.import_legacy(old_monst);
CHECK(new_monst.summon_time == 20);
CHECK(new_monst.party_summoned);
}
SECTION("Summoned by monster") {
old_monst.summoned = 120;
new_monst.import_legacy(old_monst);
CHECK(new_monst.summon_time == 20);
CHECK_FALSE(new_monst.party_summoned);
}
}