The limit of 3 saved item rectangles has been removed - you can now add as many as you want. However, the 1 per town limit is now strictly enforced. The saved item rectangle is now shown with a cyan border when editing town.
302 lines
14 KiB
C++
302 lines
14 KiB
C++
|
|
#include <fstream>
|
|
#include <iostream>
|
|
#include "tinyprint.h"
|
|
#include "dialogxml/dialogs/dialog.hpp"
|
|
#include "catch.hpp"
|
|
#include "scenario/scenario.hpp"
|
|
#include "scenario/town.hpp"
|
|
#include "fileio/resmgr/res_strings.hpp"
|
|
|
|
using namespace std;
|
|
using namespace ticpp;
|
|
|
|
extern Document xmlDocFromStream(istream& stream, string name);
|
|
extern void readScenarioFromXml(Document&& data, cScenario& scenario);
|
|
extern void writeScenarioToXml(Printer&& data, cScenario& scenario);
|
|
|
|
static void in_and_out(string name, cScenario& scen) {
|
|
string fpath = "junk/";
|
|
fpath += name;
|
|
fpath += ".xml";
|
|
ofstream fout;
|
|
fout.exceptions(ios::badbit);
|
|
fout.open(fpath);
|
|
writeScenarioToXml(Printer(name, fout), scen);
|
|
fout.close();
|
|
// Reconstruct the scenario, to ensure that it doesn't just pass due to old data still being around
|
|
scen.~cScenario();
|
|
new(&scen) cScenario();
|
|
ifstream fin;
|
|
fin.exceptions(ios::badbit);
|
|
fin.open(fpath);
|
|
readScenarioFromXml(xmlDocFromStream(fin, name), scen);
|
|
}
|
|
|
|
// NOTE: The test cases in this file are written with the implicit assumption that the read routines are trustworthy.
|
|
// In other words, they depend on the test cases in scen_read.cpp.
|
|
|
|
TEST_CASE("Saving a scenario record") {
|
|
cScenario scen;
|
|
scen.reset_version();
|
|
scen.format.ver[0] = 2;
|
|
scen.format.ver[1] = 6;
|
|
scen.format.ver[2] = 7;
|
|
scenario_header_flags vers = scen.format;
|
|
scen.scen_name = "Test Scenario";
|
|
scen.intro_pic = 0;
|
|
scen.campaign_id = "campaign";
|
|
scen.teaser_text[0] = "Teaser 1";
|
|
scen.teaser_text[1] = "Teaser 2";
|
|
scen.contact_info[0] = "BoE Test Suite";
|
|
scen.contact_info[1] = "nowhere@example.com";
|
|
scen.intro_strs[0] = "Welcome to the test scenario!";
|
|
scen.rating = eContentRating::R;
|
|
scen.difficulty = 2;
|
|
scen.which_town_start = 7;
|
|
scen.where_start = {24,28};
|
|
scen.out_sec_start = {1,3};
|
|
scen.out_start = {12, 21};
|
|
SECTION("With basic header data") {
|
|
in_and_out("basic", scen);
|
|
CHECK(scen.format.prog_make_ver[0] == vers.prog_make_ver[0]);
|
|
CHECK(scen.format.prog_make_ver[1] == vers.prog_make_ver[1]);
|
|
CHECK(scen.format.prog_make_ver[2] == vers.prog_make_ver[2]);
|
|
CHECK(scen.format.ver[0] == vers.ver[0]);
|
|
CHECK(scen.format.ver[1] == vers.ver[1]);
|
|
CHECK(scen.format.ver[2] == vers.ver[2]);
|
|
CHECK(scen.scen_name == "Test Scenario");
|
|
CHECK(scen.intro_pic == 0);
|
|
CHECK(scen.campaign_id == "campaign");
|
|
CHECK(scen.teaser_text[0] == "Teaser 1");
|
|
CHECK(scen.teaser_text[1] == "Teaser 2");
|
|
CHECK(scen.contact_info[0] == "BoE Test Suite");
|
|
CHECK(scen.contact_info[1] == "nowhere@example.com");
|
|
CHECK(scen.intro_strs[0] == "Welcome to the test scenario!");
|
|
CHECK(scen.rating == eContentRating::R);
|
|
CHECK(scen.difficulty == 2);
|
|
CHECK(scen.which_town_start == 7);
|
|
CHECK(scen.where_start == loc(24,28));
|
|
CHECK(scen.out_sec_start == loc(1,3));
|
|
CHECK(scen.out_start == loc(12,21));
|
|
}
|
|
SECTION("With some towns and sectors") {
|
|
scen.addTown(AREA_SMALL);
|
|
scen.addTown(AREA_MEDIUM);
|
|
scen.addTown(AREA_LARGE);
|
|
scen.outdoors.resize(2,5);
|
|
in_and_out("town§or", scen);
|
|
CHECK(scen.towns.size() == 3);
|
|
CHECK(scen.outdoors.width() == 2);
|
|
CHECK(scen.outdoors.height() == 5);
|
|
}
|
|
SECTION("With some optional header data") {
|
|
REQUIRE(scen.town_mods.size() >= 1); // A safety valve for if I ever make this array dynamic
|
|
scen.town_mods[0] = loc(12,9);
|
|
scen.town_mods[0].spec = 4;
|
|
scen.store_item_rects[5] = rect(1,2,3,4);
|
|
REQUIRE(scen.scenario_timers.size() >= 1); // A safety valve for if I ever make this array dynamic
|
|
scen.scenario_timers[0].node = 3;
|
|
scen.scenario_timers[0].node_type = eSpecCtxType::OUTDOOR;
|
|
scen.scenario_timers[0].time = 30000;
|
|
scen.spec_strs.push_back("This is a sample special string!");
|
|
scen.journal_strs.push_back("This is a sample journal string!");
|
|
in_and_out("optional", scen);
|
|
CHECK(scen.town_mods[0] == loc(12,9));
|
|
CHECK(scen.town_mods[0].spec == 4);
|
|
CHECK(scen.store_item_rects[5] == rect(1,2,3,4));
|
|
CHECK(scen.scenario_timers[0].node == 3);
|
|
CHECK(scen.scenario_timers[0].node_type == eSpecCtxType::SCEN); // This is inferred by the fact that it's in the scenario file
|
|
CHECK(scen.scenario_timers[0].time == 30000);
|
|
REQUIRE(scen.spec_strs.size() == 1);
|
|
CHECK(scen.spec_strs[0] == "This is a sample special string!");
|
|
REQUIRE(scen.journal_strs.size() == 1);
|
|
CHECK(scen.journal_strs[0] == "This is a sample journal string!");
|
|
}
|
|
SECTION("With a special item") {
|
|
scen.special_items.emplace_back();
|
|
scen.special_items[0].flags = 11;
|
|
scen.special_items[0].special = 2;
|
|
scen.special_items[0].name = "Test Special Item";
|
|
scen.special_items[0].descr = "This is a special item description!";
|
|
in_and_out("special item", scen);
|
|
REQUIRE(scen.special_items.size() == 1);
|
|
CHECK(scen.special_items[0].flags == 11);
|
|
CHECK(scen.special_items[0].special == 2);
|
|
CHECK(scen.special_items[0].name == "Test Special Item");
|
|
CHECK(scen.special_items[0].descr == "This is a special item description!");
|
|
}
|
|
SECTION("With a quest") {
|
|
scen.quests.resize(3);
|
|
scen.quests[0].deadline_is_relative = true;
|
|
scen.quests[0].auto_start = true;
|
|
scen.quests[0].bank1 = 2;
|
|
scen.quests[0].deadline = 12;
|
|
scen.quests[0].event = 3;
|
|
scen.quests[0].xp = 5200;
|
|
scen.quests[0].name = "Test Quest";
|
|
scen.quests[0].descr = "This is a quest description! It has an absolute deadline which is waived by an event, and an XP reward. It's also in a job bank.";
|
|
scen.quests[1].auto_start = true;
|
|
scen.quests[1].gold = 220;
|
|
scen.quests[1].name = "Test Quest 2";
|
|
scen.quests[1].descr = "This is another quest description! It has no deadline, and a monetary reward.";
|
|
scen.quests[2].deadline_is_relative = true;
|
|
scen.quests[2].deadline = 12;
|
|
scen.quests[2].bank2 = 4;
|
|
scen.quests[2].name = "Test Quest 3";
|
|
scen.quests[2].descr = "And now another quest description! This one has a relative deadline and no reward, but it's in a job bank.";
|
|
in_and_out("quest", scen);
|
|
REQUIRE(scen.quests.size() == 3);
|
|
CHECK(scen.quests[0].deadline_is_relative);
|
|
CHECK(scen.quests[0].auto_start);
|
|
CHECK(scen.quests[0].bank1 == 2);
|
|
CHECK(scen.quests[0].deadline == 12);
|
|
CHECK(scen.quests[0].event == 3);
|
|
CHECK(scen.quests[0].xp == 5200);
|
|
CHECK(scen.quests[0].name == "Test Quest");
|
|
CHECK_FALSE(scen.quests[1].deadline_is_relative);
|
|
CHECK(scen.quests[1].auto_start);
|
|
CHECK(scen.quests[1].gold == 220);
|
|
CHECK(scen.quests[1].name == "Test Quest 2");
|
|
CHECK(scen.quests[2].deadline_is_relative);
|
|
CHECK_FALSE(scen.quests[2].auto_start);
|
|
CHECK(scen.quests[2].deadline == 12);
|
|
CHECK(scen.quests[2].bank1 == 4); // bank2 moves into bank1
|
|
CHECK(scen.quests[2].bank2 == -1);
|
|
CHECK(scen.quests[2].name == "Test Quest 3");
|
|
}
|
|
SECTION("With a shop") {
|
|
// Loading/building shops requires strings to be available
|
|
// Here we fetch them from the rsrc dir, rather than the data dir
|
|
ResMgr::strings.pushPath("../rsrc/strings");
|
|
cItem dummy_item(ITEM_POTION);
|
|
scen.shops.resize(3);
|
|
scen.shops[0] = cShop(SHOP_JUNK);
|
|
scen.shops[1] = cShop(SHOP_HEALING);
|
|
scen.shops[2].setName("The Test Shop");
|
|
scen.shops[2].setType(eShopType::NORMAL);
|
|
scen.shops[2].setPrompt(eShopPrompt::SHOPPING);
|
|
scen.shops[2].setFace(17);
|
|
scen.shops[2].addItem(1, dummy_item, 0);
|
|
scen.shops[2].addItem(2, dummy_item, 5, 10);
|
|
scen.shops[2].addSpecial(eShopItemType::ALCHEMY, 3);
|
|
scen.shops[2].addSpecial(eShopItemType::CLASS, 4);
|
|
scen.shops[2].addSpecial(eShopItemType::CURE_ACID);
|
|
scen.shops[2].addSpecial(eShopItemType::CURE_POISON);
|
|
scen.shops[2].addSpecial(eShopItemType::MAGE_SPELL, 5);
|
|
scen.shops[2].addSpecial(eShopItemType::PRIEST_SPELL, 6);
|
|
scen.shops[2].addSpecial(eShopItemType::REMOVE_CURSE);
|
|
scen.shops[2].addSpecial(eShopItemType::SKILL, 7);
|
|
scen.shops[2].addSpecial(eShopItemType::TREASURE, 0);
|
|
scen.shops[2].addSpecial("Magic!", "This is magic!", 24, 100, 12, 1);
|
|
in_and_out("shops", scen);
|
|
REQUIRE(scen.shops.size() == 3);
|
|
REQUIRE(scen.shops[0].size() == 10);
|
|
CHECK(scen.shops[0].getName() == "Magic Shop");
|
|
CHECK(scen.shops[0].getType() == eShopType::RANDOM);
|
|
CHECK(scen.shops[0].getPrompt() == eShopPrompt::SHOPPING);
|
|
CHECK(scen.shops[0].getFace() == 0);
|
|
CHECK(scen.shops[0].getItem(0).type == eShopItemType::TREASURE);
|
|
CHECK(scen.shops[0].getItem(0).item.item_level == 1);
|
|
CHECK(scen.shops[0].getItem(4).item.item_level == 2);
|
|
CHECK(scen.shops[0].getItem(7).item.item_level == 3);
|
|
CHECK(scen.shops[0].getItem(9).item.item_level == 4);
|
|
REQUIRE(scen.shops[1].size() == 9);
|
|
CHECK(scen.shops[1].getName() == "Healing");
|
|
CHECK(scen.shops[1].getType() == eShopType::ALLOW_DEAD);
|
|
CHECK(scen.shops[1].getPrompt() == eShopPrompt::HEALING);
|
|
CHECK(scen.shops[1].getFace() == 41);
|
|
CHECK(scen.shops[1].getItem(0).type == eShopItemType::HEAL_WOUNDS);
|
|
CHECK(scen.shops[1].getItem(1).type == eShopItemType::CURE_POISON);
|
|
CHECK(scen.shops[1].getItem(2).type == eShopItemType::CURE_DISEASE);
|
|
CHECK(scen.shops[1].getItem(3).type == eShopItemType::CURE_PARALYSIS);
|
|
CHECK(scen.shops[1].getItem(4).type == eShopItemType::CURE_DUMBFOUNDING);
|
|
CHECK(scen.shops[1].getItem(5).type == eShopItemType::REMOVE_CURSE);
|
|
CHECK(scen.shops[1].getItem(6).type == eShopItemType::DESTONE);
|
|
CHECK(scen.shops[1].getItem(7).type == eShopItemType::RAISE_DEAD);
|
|
CHECK(scen.shops[1].getItem(8).type == eShopItemType::RESURRECT);
|
|
REQUIRE(scen.shops[2].size() == 12);
|
|
CHECK(scen.shops[2].getName() == "The Test Shop");
|
|
CHECK(scen.shops[2].getType() == eShopType::NORMAL);
|
|
CHECK(scen.shops[2].getPrompt() == eShopPrompt::SHOPPING);
|
|
CHECK(scen.shops[2].getFace() == 17);
|
|
CHECK(scen.shops[2].getItem(0).type == eShopItemType::ITEM);
|
|
CHECK(scen.shops[2].getItem(0).index == 1);
|
|
CHECK(scen.shops[2].getItem(0).quantity == 0);
|
|
CHECK(scen.shops[2].getItem(1).type == eShopItemType::OPT_ITEM);
|
|
CHECK(scen.shops[2].getItem(1).index == 2);
|
|
CHECK(scen.shops[2].getItem(1).quantity == 10005);
|
|
CHECK(scen.shops[2].getItem(2).type == eShopItemType::ALCHEMY);
|
|
CHECK(scen.shops[2].getItem(2).item.item_level == 3);
|
|
CHECK(scen.shops[2].getItem(3).type == eShopItemType::CLASS);
|
|
CHECK(scen.shops[2].getItem(3).item.special_class == 4);
|
|
CHECK(scen.shops[2].getItem(4).type == eShopItemType::CURE_ACID);
|
|
CHECK(scen.shops[2].getItem(5).type == eShopItemType::CURE_POISON);
|
|
CHECK(scen.shops[2].getItem(6).type == eShopItemType::MAGE_SPELL);
|
|
CHECK(scen.shops[2].getItem(6).item.item_level == 5);
|
|
CHECK(scen.shops[2].getItem(7).type == eShopItemType::PRIEST_SPELL);
|
|
CHECK(scen.shops[2].getItem(7).item.item_level == 6);
|
|
CHECK(scen.shops[2].getItem(8).type == eShopItemType::REMOVE_CURSE);
|
|
CHECK(scen.shops[2].getItem(9).type == eShopItemType::SKILL);
|
|
CHECK(scen.shops[2].getItem(9).item.item_level == 7);
|
|
CHECK(scen.shops[2].getItem(10).type == eShopItemType::TREASURE);
|
|
CHECK(scen.shops[2].getItem(10).item.item_level == 0);
|
|
CHECK(scen.shops[2].getItem(11).type == eShopItemType::CALL_SPECIAL);
|
|
CHECK(scen.shops[2].getItem(11).quantity == 1);
|
|
CHECK(scen.shops[2].getItem(11).item.value == 12);
|
|
CHECK(scen.shops[2].getItem(11).item.item_level == 100);
|
|
CHECK(scen.shops[2].getItem(11).item.graphic_num == 24);
|
|
CHECK(scen.shops[2].getItem(11).item.full_name == "Magic!");
|
|
CHECK(scen.shops[2].getItem(11).item.desc == "This is magic!");
|
|
ResMgr::strings.popPath();
|
|
}
|
|
SECTION("With some empty strings, none are stripped") {
|
|
scen.spec_strs.resize(12);
|
|
scen.spec_strs[3] = "Hello World!";
|
|
scen.spec_strs[9] = "Goodbye World!";
|
|
scen.journal_strs.resize(19);
|
|
scen.journal_strs[7] = "My best journal!";
|
|
scen.intro_strs[4] = "Another intro string!";
|
|
in_and_out("empty strings", scen);
|
|
REQUIRE(scen.spec_strs.size() == 12);
|
|
CHECK(scen.spec_strs[3] == "Hello World!");
|
|
CHECK(scen.spec_strs[9] == "Goodbye World!");
|
|
REQUIRE(scen.journal_strs.size() == 19);
|
|
CHECK(scen.journal_strs[7] == "My best journal!");
|
|
CHECK(scen.intro_strs[4] == "Another intro string!");
|
|
}
|
|
SECTION("Whitespace is collapsed in short strings but not in long strings") {
|
|
scen.scen_name = "Test Scenario with extra spaces";
|
|
scen.teaser_text[0] = "Teaser the first!";
|
|
scen.teaser_text[1] = " Teaser the second ! ";
|
|
scen.spec_strs.push_back(" ");
|
|
scen.spec_strs.push_back(" What is this... ?");
|
|
scen.journal_strs.push_back(" Do not collapse this journal.");
|
|
scen.intro_strs[1] = "An intro string! With extra spaces!";
|
|
scen.special_items.emplace_back();
|
|
scen.special_items[0].name = "A special space-filled item!";
|
|
scen.special_items[0].descr = "A special item... with extra spaces!";
|
|
scen.quests.emplace_back();
|
|
scen.quests[0].name = "A quest filled with spaces... ";
|
|
scen.quests[0].descr = "A quest... with extra spaces!";
|
|
scen.snd_names.push_back("A sound full of spaces!");
|
|
in_and_out("whitespace", scen);
|
|
CHECK(scen.scen_name == "Test Scenario with extra spaces");
|
|
CHECK(scen.teaser_text[0] == "Teaser the first!");
|
|
CHECK(scen.teaser_text[1] == "Teaser the second !");
|
|
REQUIRE(scen.spec_strs.size() == 2);
|
|
CHECK(scen.spec_strs[0] == " ");
|
|
CHECK(scen.spec_strs[1] == " What is this... ?");
|
|
REQUIRE(scen.journal_strs.size() == 1);
|
|
CHECK(scen.journal_strs[0] == " Do not collapse this journal.");
|
|
CHECK(scen.intro_strs[1] == "An intro string! With extra spaces!");
|
|
REQUIRE(scen.special_items.size() == 1);
|
|
CHECK(scen.special_items[0].name == "A special space-filled item!");
|
|
CHECK(scen.special_items[0].descr == "A special item... with extra spaces!");
|
|
REQUIRE(scen.quests.size() == 1);
|
|
CHECK(scen.quests[0].name == "A quest filled with spaces...");
|
|
CHECK(scen.quests[0].descr == "A quest... with extra spaces!");
|
|
CHECK(scen.snd_names[0] == "A sound full of spaces!");
|
|
}
|
|
}
|