diff --git a/rsrc/schemas/scenario.xsd b/rsrc/schemas/scenario.xsd
index 65ca6957..406d40f1 100644
--- a/rsrc/schemas/scenario.xsd
+++ b/rsrc/schemas/scenario.xsd
@@ -57,10 +57,10 @@
-
-
-
-
+
+
+
+
diff --git a/src/boe.dlgutil.cpp b/src/boe.dlgutil.cpp
index ea47a75d..5756bee6 100644
--- a/src/boe.dlgutil.cpp
+++ b/src/boe.dlgutil.cpp
@@ -1398,7 +1398,6 @@ void tip_of_day() {
static void put_scen_info(cDialog& me) {
unsigned int i;
std::ostringstream sout;
- const char *ratings[] = {"G","PG","R","NC-17"};
const char *difficulty[] = {"Low","Medium","High","Very High"};
for(i = 0; i < 3; i++) {
@@ -1415,7 +1414,7 @@ static void put_scen_info(cDialog& me) {
sout << '.' << int(scen_headers[store_scen_page_on * 3 + i].ver[1]);
sout << '.' << int(scen_headers[store_scen_page_on * 3 + i].ver[2]);
sout << " - | Difficulty: " << difficulty[scen_headers[store_scen_page_on * 3 + i].difficulty];
- sout << ", Rating: " << ratings[scen_headers[store_scen_page_on * 3 + i].rating];
+ sout << ", Rating: " << scen_headers[store_scen_page_on * 3 + i].rating;
sout << " |" << scen_headers[store_scen_page_on * 3 + i].who1;
sout << " |" << scen_headers[store_scen_page_on * 3 + i].who2;
me["desc" + n].setText(sout.str());
diff --git a/src/classes/estreams.cpp b/src/classes/estreams.cpp
index 6e508c0c..b0aeb6c9 100644
--- a/src/classes/estreams.cpp
+++ b/src/classes/estreams.cpp
@@ -631,3 +631,18 @@ std::istream& operator>> (std::istream& in, eAttitude& att) {
in.setstate(std::ios::failbit);
return in;
}
+
+// MARK: eContentRating
+
+cEnumLookup rating_strs = {"G", "PG", "R", "NC-17"};
+
+std::ostream& operator<< (std::ostream& out, eContentRating rating) {
+ writeEnum(out, rating, rating_strs, "docile");
+ return out;
+}
+
+std::istream& operator>> (std::istream& in, eContentRating& rating) {
+ if(!readEnum(in, rating, rating_strs, eContentRating::G))
+ in.setstate(std::ios::failbit);
+ return in;
+}
diff --git a/src/classes/scenario.cpp b/src/classes/scenario.cpp
index f3c5fb2d..758ee502 100644
--- a/src/classes/scenario.cpp
+++ b/src/classes/scenario.cpp
@@ -69,7 +69,7 @@ cScenario::cScenario() {
where_start.x = 24;
where_start.y = 24;
out_start = where_start;
- rating = 0;
+ rating = eContentRating::G;
difficulty = 0;
intro_pic = intro_mess_pic = 0;
adjust_diff = true;
@@ -133,7 +133,7 @@ void cScenario::append(legacy::scenario_data_type& old){
special_items[i].flags = old.special_items[i];
special_items[i].special = old.special_item_special[i];
}
- rating = old.rating;
+ rating = eContentRating(old.rating);
// TODO: Is this used anywhere?
uses_custom_graphics = old.uses_custom_graphics;
for(i = 0; i < 30; i++) {
diff --git a/src/classes/scenario.hpp b/src/classes/scenario.hpp
index ea2c1811..04d9d425 100644
--- a/src/classes/scenario.hpp
+++ b/src/classes/scenario.hpp
@@ -72,7 +72,8 @@ public:
std::vector special_items;
std::vector quests;
std::vector shops;
- short rating,uses_custom_graphics;
+ short uses_custom_graphics;
+ eContentRating rating;
std::vector custom_graphics;
std::vector scen_monsters;
std::array boats;
@@ -122,4 +123,7 @@ public:
~cScenario();
};
+std::istream& operator>> (std::istream& in, eContentRating& rating);
+std::ostream& operator<< (std::ostream& out, eContentRating rating);
+
#endif
diff --git a/src/classes/simpletypes.hpp b/src/classes/simpletypes.hpp
index b1eeba52..93b75315 100644
--- a/src/classes/simpletypes.hpp
+++ b/src/classes/simpletypes.hpp
@@ -38,6 +38,8 @@ inline eDirection& operator++ (eDirection& me, int) {
else return me = (eDirection)(1 + (int)me);
}
+enum eContentRating {G, PG, R, NC17};
+
enum class eQuestStatus {AVAILABLE, STARTED, COMPLETED, FAILED};
enum class eMainStatus {
diff --git a/src/scenedit/scen.fileio.cpp b/src/scenedit/scen.fileio.cpp
index 30937faa..cb382d22 100644
--- a/src/scenedit/scen.fileio.cpp
+++ b/src/scenedit/scen.fileio.cpp
@@ -138,12 +138,7 @@ void writeScenarioToXml(ticpp::Printer&& data, cScenario& scenario) {
}
data.CloseElement("text");
data.OpenElement("ratings");
- switch(scenario.rating) {
- case 0: data.PushElement("content", "g"); break;
- case 1: data.PushElement("content", "pg"); break;
- case 2: data.PushElement("content", "r"); break;
- case 3: data.PushElement("content", "nc17"); break;
- }
+ data.PushElement("content", scenario.rating);
data.PushElement("difficulty", scenario.difficulty + 1);
data.CloseElement("ratings");
data.OpenElement("flags");
diff --git a/src/tools/fileio_scen.cpp b/src/tools/fileio_scen.cpp
index 4c79805f..c15e4547 100644
--- a/src/tools/fileio_scen.cpp
+++ b/src/tools/fileio_scen.cpp
@@ -653,6 +653,7 @@ void readScenarioFromXml(ticpp::Document&& data, cScenario& scenario) {
} else if(type == "icon") {
// TODO: This element can have some attributes on it.
elem->GetText(&scenario.intro_pic);
+ scenario.intro_mess_pic = scenario.intro_pic;
} else if(type == "id") {
elem->GetText(&scenario.campaign_id, false);
} else if(type == "version") {
@@ -689,12 +690,7 @@ void readScenarioFromXml(ticpp::Document&& data, cScenario& scenario) {
} else if(type == "ratings") {
Element* content = elem->FirstChildElement("content");
Element* difficulty = elem->FirstChildElement("difficulty");
- content->GetText(&val);
- if(val == "g") scenario.rating = 0;
- else if(val == "pg") scenario.rating = 1;
- else if(val == "r") scenario.rating = 2;
- else if(val == "nc17") scenario.rating = 3;
- else throw xBadVal("content", xBadVal::CONTENT, val, content->Row(), content->Column(), fname);
+ content->GetText(&scenario.rating);
difficulty->GetText(&scenario.difficulty);
if(scenario.difficulty < 1 || scenario.difficulty > 4)
throw xBadVal("difficulty", xBadVal::CONTENT, std::to_string(scenario.difficulty), difficulty->Row(),difficulty->Column(), fname);
diff --git a/test/enums.cpp b/test/enums.cpp
index b7601bd2..d5918493 100644
--- a/test/enums.cpp
+++ b/test/enums.cpp
@@ -59,4 +59,5 @@ TEST_CASE("Enum text conversions") {
test_enum(LIGHT_NORMAL, "lit", LIGHT_NONE, "none");
test_enum(eTalkNode::REGULAR, "reg", eTalkNode::JOB_BANK, "jobs", eTalkNode::SELL_WEAPONS, "sell-weap", eTalkNode::CALL_SCEN_SPEC, "call-global");
test_enum(eAttitude::DOCILE, "docile", eAttitude::HOSTILE_B, "hostile-b");
+ test_enum(eContentRating::G, "G", eContentRating::NC17, "NC-17");
}
diff --git a/test/files/scenario/bad_format.xml b/test/files/scenario/bad_format.xml
index 71c7f0c2..8f1042e6 100644
--- a/test/files/scenario/bad_format.xml
+++ b/test/files/scenario/bad_format.xml
@@ -15,7 +15,7 @@
Welcome to the test scenario!
- r
+ R
3
diff --git a/test/files/scenario/bad_graphics1.xml b/test/files/scenario/bad_graphics1.xml
index e25ab94c..e90caeb0 100644
--- a/test/files/scenario/bad_graphics1.xml
+++ b/test/files/scenario/bad_graphics1.xml
@@ -15,7 +15,7 @@
Welcome to the test scenario!
- r
+ R
3
diff --git a/test/files/scenario/bad_graphics2.xml b/test/files/scenario/bad_graphics2.xml
index 7655e185..7c706711 100644
--- a/test/files/scenario/bad_graphics2.xml
+++ b/test/files/scenario/bad_graphics2.xml
@@ -15,7 +15,7 @@
Welcome to the test scenario!
- r
+ R
3
diff --git a/test/files/scenario/bad_graphics3.xml b/test/files/scenario/bad_graphics3.xml
index ea1c4a00..83675163 100644
--- a/test/files/scenario/bad_graphics3.xml
+++ b/test/files/scenario/bad_graphics3.xml
@@ -15,7 +15,7 @@
Welcome to the test scenario!
- r
+ R
3
diff --git a/test/files/scenario/bad_graphics4.xml b/test/files/scenario/bad_graphics4.xml
index d8ceb48a..99ebc3dd 100644
--- a/test/files/scenario/bad_graphics4.xml
+++ b/test/files/scenario/bad_graphics4.xml
@@ -15,7 +15,7 @@
Welcome to the test scenario!
- r
+ R
3
diff --git a/test/files/scenario/bad_graphics5.xml b/test/files/scenario/bad_graphics5.xml
index 12d19218..dc4504ba 100644
--- a/test/files/scenario/bad_graphics5.xml
+++ b/test/files/scenario/bad_graphics5.xml
@@ -15,7 +15,7 @@
Welcome to the test scenario!
- r
+ R
3
diff --git a/test/files/scenario/bad_rating.xml b/test/files/scenario/bad_rating.xml
new file mode 100644
index 00000000..1ec01f3d
--- /dev/null
+++ b/test/files/scenario/bad_rating.xml
@@ -0,0 +1,21 @@
+
+
+ Test Scenario
+ 0
+ campaign
+ 2.6.7
+ en-US
+
+ BoE Test Suite
+ nowhere@example.com
+
+
+ Teaser 1
+ Teaser 2
+ Welcome to the test scenario!
+
+
+ Q
+ 3
+
+
diff --git a/test/files/scenario/extra_teaser.xml b/test/files/scenario/extra_teaser.xml
index 3fc3a650..eceef835 100644
--- a/test/files/scenario/extra_teaser.xml
+++ b/test/files/scenario/extra_teaser.xml
@@ -16,7 +16,7 @@
Welcome to the test scenario!
- r
+ R
3
diff --git a/test/files/scenario/intro_overflow.xml b/test/files/scenario/intro_overflow.xml
index e3a32a15..78bc7c3d 100644
--- a/test/files/scenario/intro_overflow.xml
+++ b/test/files/scenario/intro_overflow.xml
@@ -21,7 +21,7 @@
- r
+ R
3
diff --git a/test/files/scenario/minimal.xml b/test/files/scenario/minimal.xml
new file mode 100644
index 00000000..a531bac7
--- /dev/null
+++ b/test/files/scenario/minimal.xml
@@ -0,0 +1,45 @@
+
+
+ Test Scenario
+ 7
+ campaign
+ 2.6.7
+ en-US
+
+ BoE Test Suite
+ nowhere@example.com
+
+
+ Teaser 1
+ Teaser 2
+
+
+
+ R
+ 3
+
+
+ true
+ false
+ false
+
+
+ oboe
+ 2.5.3
+
+
+
+ 3
+ 2
+ 1
+ 7
+
+
+
+
+
+ 2
+
+ 0
+
+
diff --git a/test/files/scenario/missing_editor.xml b/test/files/scenario/missing_editor.xml
index fa902762..3097bbe4 100644
--- a/test/files/scenario/missing_editor.xml
+++ b/test/files/scenario/missing_editor.xml
@@ -15,7 +15,7 @@
Welcome to the test scenario!
- r
+ R
3
diff --git a/test/files/scenario/missing_flags.xml b/test/files/scenario/missing_flags.xml
index 3c4f5cca..9ce74a4b 100644
--- a/test/files/scenario/missing_flags.xml
+++ b/test/files/scenario/missing_flags.xml
@@ -15,7 +15,7 @@
Welcome to the test scenario!
- r
+ R
3
diff --git a/test/files/scenario/missing_game.xml b/test/files/scenario/missing_game.xml
index 3a7634fb..c3bd5c14 100644
--- a/test/files/scenario/missing_game.xml
+++ b/test/files/scenario/missing_game.xml
@@ -15,7 +15,7 @@
Welcome to the test scenario!
- r
+ R
3
diff --git a/test/files/scenario/special_item.xml b/test/files/scenario/special_item.xml
new file mode 100644
index 00000000..51b2dfa8
--- /dev/null
+++ b/test/files/scenario/special_item.xml
@@ -0,0 +1,45 @@
+
+
+ Test Scenario
+ 0
+ campaign
+ 2.6.7
+ en-US
+
+ BoE Test Suite
+ nowhere@example.com
+
+
+
+ R
+ 3
+
+
+ true
+ false
+ false
+
+
+ oboe
+ 2.0.0
+
+
+
+ 0
+ 0
+ 0
+ 7
+
+
+
+
+ My Special Item
+
+
+
+
+ 2
+
+ 0
+
+
diff --git a/test/scen_read.cpp b/test/scen_read.cpp
index 9a72e389..7d3b2b20 100644
--- a/test/scen_read.cpp
+++ b/test/scen_read.cpp
@@ -63,6 +63,11 @@ TEST_CASE("Loading a new-format scenario record") {
doc = xmlDocFromStream(fin, "missing_rating.xml");
REQUIRE_THROWS_AS(readScenarioFromXml(move(doc), scen), Exception);
}
+ SECTION("When the scenario content rating is invalid") {
+ fin.open("files/scenario/bad_rating.xml");
+ doc = xmlDocFromStream(fin, "bad_rating.xml");
+ REQUIRE_THROWS_AS(readScenarioFromXml(move(doc), scen), Exception);
+ }
SECTION("When there are too many teaser strings") {
fin.open("files/scenario/extra_teaser.xml");
doc = xmlDocFromStream(fin, "extra_teaser.xml");
@@ -115,4 +120,50 @@ TEST_CASE("Loading a new-format scenario record") {
REQUIRE_THROWS_AS(readScenarioFromXml(move(doc), scen), xBadVal);
}
}
+ SECTION("With the minimal required data") {
+ fin.open("files/scenario/minimal.xml");
+ doc = xmlDocFromStream(fin, "minimal.xml");
+ REQUIRE_NOTHROW(readScenarioFromXml(move(doc), scen));
+ CHECK(scen.scen_name == "Test Scenario");
+ CHECK(scen.intro_pic == 7);
+ CHECK(scen.campaign_id == "campaign");
+ CHECK(scen.format.prog_make_ver[0] == 2);
+ CHECK(scen.format.prog_make_ver[1] == 5);
+ CHECK(scen.format.prog_make_ver[2] == 3);
+ CHECK(scen.format.ver[0] == 2);
+ CHECK(scen.format.ver[1] == 6);
+ CHECK(scen.format.ver[2] == 7);
+ // TODO: Check language
+ CHECK(scen.contact_info[0] == "BoE Test Suite");
+ CHECK(scen.contact_info[1] == "nowhere@example.com");
+ CHECK(scen.who_wrote[0] == "Teaser 1");
+ CHECK(scen.who_wrote[1] == "Teaser 2");
+ CHECK(scen.intro_mess_pic == 7);
+ CHECK(scen.intro_strs[0] == "Welcome!!! To the test scenario!");
+ CHECK(scen.rating == eContentRating::R);
+ CHECK(scen.difficulty == 2); // Difficulty is 3, but it's stored as 2 (0-3 instead of 1-4)
+ CHECK(scen.adjust_diff == true);
+ CHECK(scen.is_legacy == false);
+ CHECK(scen.uses_custom_graphics == false);
+ CHECK(scen.towns.size() == 3);
+ CHECK(scen.outdoors.width() == 2);
+ CHECK(scen.outdoors.height() == 1);
+ 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));
+ CHECK(scen.default_ground == 2);
+ CHECK(scen.last_out_edited == loc(0,0));
+ CHECK(scen.last_town_edited == 0);
+ }
+ SECTION("With a special item") {
+ fin.open("files/scenario/special_item.xml");
+ doc = xmlDocFromStream(fin, "special_item.xml");
+ REQUIRE_NOTHROW(readScenarioFromXml(move(doc), scen));
+ CHECK(scen.special_items.size() == 1);
+ CHECK(scen.special_items[0].name == "My Special Item");
+ CHECK(scen.special_items[0].descr == "Special Item -- Description!");
+ CHECK(scen.special_items[0].flags == 0);
+ CHECK(scen.special_items[0].special == -1);
+ }
}
diff --git a/test/scen_write.cpp b/test/scen_write.cpp
index 0c978dbf..d7abaf59 100644
--- a/test/scen_write.cpp
+++ b/test/scen_write.cpp
@@ -50,7 +50,7 @@ TEST_CASE("Saving a scenario record") {
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 = 2;
+ scen.rating = eContentRating::R;
scen.difficulty = 2;
scen.which_town_start = 7;
scen.where_start = {24,28};
@@ -72,7 +72,7 @@ TEST_CASE("Saving a scenario record") {
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 == 2);
+ CHECK(scen.rating == eContentRating::R);
CHECK(scen.difficulty == 2);
CHECK(scen.which_town_start == 7);
CHECK(scen.where_start == loc(24,28));