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));