More read/write tests for town and outdoors, including maps/dialogue
Fixes: - For towns, the "has tavern" flag was not saved or loaded - Outdoor roads were not saved or loaded - For outdoor encounters, the "can't flee" and "forced" flags were not loaded, and "forced" was not saved --> These two flags have also been separated in the code
This commit is contained in:
@@ -22,6 +22,7 @@
|
|||||||
</xs:element>
|
</xs:element>
|
||||||
</xs:sequence>
|
</xs:sequence>
|
||||||
<xs:attribute name="can-flee" type="bool" default="true"/>
|
<xs:attribute name="can-flee" type="bool" default="true"/>
|
||||||
|
<xs:attribute name="force" type="bool" default="false"/>
|
||||||
</xs:complexType>
|
</xs:complexType>
|
||||||
<xs:element name="sector">
|
<xs:element name="sector">
|
||||||
<xs:complexType>
|
<xs:complexType>
|
||||||
|
|||||||
@@ -95,6 +95,7 @@
|
|||||||
<xs:element name="strong-barriers" minOccurs="0" type="bool"/>
|
<xs:element name="strong-barriers" minOccurs="0" type="bool"/>
|
||||||
<xs:element name="defy-mapping" minOccurs="0" type="bool"/>
|
<xs:element name="defy-mapping" minOccurs="0" type="bool"/>
|
||||||
<xs:element name="defy-scrying" minOccurs="0" type="bool"/>
|
<xs:element name="defy-scrying" minOccurs="0" type="bool"/>
|
||||||
|
<xs:element name="tavern" minOccurs="0" type="bool"/>
|
||||||
</xs:all>
|
</xs:all>
|
||||||
</xs:complexType>
|
</xs:complexType>
|
||||||
</xs:element>
|
</xs:element>
|
||||||
|
|||||||
@@ -1498,7 +1498,7 @@ void handle_monster_actions(bool& need_redraw, bool& need_reprint) {
|
|||||||
create_wand_monst();
|
create_wand_monst();
|
||||||
for(int i = 0; i < 10; i++)
|
for(int i = 0; i < 10; i++)
|
||||||
if(univ.party.out_c[i].exists)
|
if(univ.party.out_c[i].exists)
|
||||||
if((adjacent(univ.party.p_loc,univ.party.out_c[i].m_loc) || univ.party.out_c[i].what_monst.cant_flee >= 10)
|
if((adjacent(univ.party.p_loc,univ.party.out_c[i].m_loc) || univ.party.out_c[i].what_monst.forced)
|
||||||
&& univ.party.in_boat < 0 && !flying()) {
|
&& univ.party.in_boat < 0 && !flying()) {
|
||||||
store_wandering_special = univ.party.out_c[i].what_monst;
|
store_wandering_special = univ.party.out_c[i].what_monst;
|
||||||
if(handle_wandering_specials(0,0))
|
if(handle_wandering_specials(0,0))
|
||||||
@@ -1584,7 +1584,7 @@ void initiate_outdoor_combat(short i) {
|
|||||||
|
|
||||||
// Is combat too easy?
|
// Is combat too easy?
|
||||||
if((univ.party.get_level() > ((out_enc_lev_tot(i) * 5) / 3) ) && (out_enc_lev_tot(i) < 200)
|
if((univ.party.get_level() > ((out_enc_lev_tot(i) * 5) / 3) ) && (out_enc_lev_tot(i) < 200)
|
||||||
&& (univ.party.out_c[i].what_monst.cant_flee % 10 != 1)) {
|
&& !univ.party.out_c[i].what_monst.cant_flee) {
|
||||||
add_string_to_buf("Combat: Monsters fled!");
|
add_string_to_buf("Combat: Monsters fled!");
|
||||||
univ.party.out_c[i].exists = false;
|
univ.party.out_c[i].exists = false;
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -117,6 +117,7 @@ cOutdoors::cOutdoors(cScenario& scenario) : scenario(&scenario) {
|
|||||||
for(j = 0; j < 48; j++) {
|
for(j = 0; j < 48; j++) {
|
||||||
terrain[i][j] = scenario.default_ground;
|
terrain[i][j] = scenario.default_ground;
|
||||||
special_spot[i][j] = false;
|
special_spot[i][j] = false;
|
||||||
|
roads[i][j] = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
for(i = 0; i < 4; i++) {
|
for(i = 0; i < 4; i++) {
|
||||||
@@ -134,7 +135,8 @@ void cOutdoors::cWandering::append(legacy::out_wandering_type old){
|
|||||||
spec_on_meet = old.spec_on_meet;
|
spec_on_meet = old.spec_on_meet;
|
||||||
spec_on_win = old.spec_on_win;
|
spec_on_win = old.spec_on_win;
|
||||||
spec_on_flee = old.spec_on_flee;
|
spec_on_flee = old.spec_on_flee;
|
||||||
cant_flee = old.cant_flee;
|
cant_flee = old.cant_flee % 10 == 1;
|
||||||
|
forced = old.cant_flee >= 10;
|
||||||
end_spec1 = old.end_spec1;
|
end_spec1 = old.end_spec1;
|
||||||
end_spec2 = old.end_spec2;
|
end_spec2 = old.end_spec2;
|
||||||
}
|
}
|
||||||
@@ -157,7 +159,7 @@ void cOutdoors::cWandering::writeTo(std::ostream& file, std::string prefix) cons
|
|||||||
file << prefix << "MEET " << spec_on_meet << '\n';
|
file << prefix << "MEET " << spec_on_meet << '\n';
|
||||||
file << prefix << "WIN " << spec_on_win << '\n';
|
file << prefix << "WIN " << spec_on_win << '\n';
|
||||||
file << prefix << "FLEE " << spec_on_flee << '\n';
|
file << prefix << "FLEE " << spec_on_flee << '\n';
|
||||||
file << prefix << "FLAGS " << cant_flee << '\n';
|
file << prefix << "FLAGS " << cant_flee << ' ' << forced << '\n';
|
||||||
file << prefix << "SDF " << end_spec1 << ' ' << end_spec2 << '\n';
|
file << prefix << "SDF " << end_spec1 << ' ' << end_spec2 << '\n';
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -182,7 +184,7 @@ void cOutdoors::cWandering::readFrom(std::istream& file){
|
|||||||
else if(cur == "FLEE")
|
else if(cur == "FLEE")
|
||||||
sin >> spec_on_flee;
|
sin >> spec_on_flee;
|
||||||
else if(cur == "FLAGS")
|
else if(cur == "FLAGS")
|
||||||
sin >> cant_flee;
|
sin >> cant_flee >> forced;
|
||||||
else if(cur == "SDF")
|
else if(cur == "SDF")
|
||||||
sin >> end_spec1 >> end_spec2;
|
sin >> end_spec1 >> end_spec2;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -40,8 +40,9 @@ public:
|
|||||||
public:
|
public:
|
||||||
std::array<mon_num_t,7> monst;
|
std::array<mon_num_t,7> monst;
|
||||||
std::array<mon_num_t,3> friendly;
|
std::array<mon_num_t,3> friendly;
|
||||||
short spec_on_meet,spec_on_win,spec_on_flee,cant_flee;
|
short spec_on_meet,spec_on_win,spec_on_flee;
|
||||||
short end_spec1,end_spec2;
|
short end_spec1,end_spec2;
|
||||||
|
bool cant_flee, forced;
|
||||||
|
|
||||||
bool isNull();
|
bool isNull();
|
||||||
void append(legacy::out_wandering_type old);
|
void append(legacy::out_wandering_type old);
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ protected:
|
|||||||
public:
|
public:
|
||||||
class cWandering { // formerly wandering_type
|
class cWandering { // formerly wandering_type
|
||||||
public:
|
public:
|
||||||
mon_num_t monst[4];
|
std::array<mon_num_t,4> monst;
|
||||||
|
|
||||||
bool isNull();
|
bool isNull();
|
||||||
void append(legacy::wandering_type old);
|
void append(legacy::wandering_type old);
|
||||||
|
|||||||
@@ -92,6 +92,7 @@ template<> void ticpp::Printer::PushElement(std::string tagName, cMonster::cAtta
|
|||||||
template<> void ticpp::Printer::PushElement(std::string tagName, cOutdoors::cWandering enc, bool) {
|
template<> void ticpp::Printer::PushElement(std::string tagName, cOutdoors::cWandering enc, bool) {
|
||||||
OpenElement(tagName);
|
OpenElement(tagName);
|
||||||
PushAttribute("can-flee", !enc.cant_flee);
|
PushAttribute("can-flee", !enc.cant_flee);
|
||||||
|
PushAttribute("force", enc.forced);
|
||||||
for(size_t i = 0; i < enc.monst.size(); i++) {
|
for(size_t i = 0; i < enc.monst.size(); i++) {
|
||||||
PushElement("monster", enc.monst[i]);
|
PushElement("monster", enc.monst[i]);
|
||||||
}
|
}
|
||||||
@@ -719,6 +720,8 @@ void writeTownToXml(ticpp::Printer&& data, cTown& town) {
|
|||||||
data.PushElement("defy-scrying", true);
|
data.PushElement("defy-scrying", true);
|
||||||
if(town.is_hidden)
|
if(town.is_hidden)
|
||||||
data.PushElement("hidden", true);
|
data.PushElement("hidden", true);
|
||||||
|
if(town.has_tavern)
|
||||||
|
data.PushElement("tavern", true);
|
||||||
data.CloseElement("flags");
|
data.CloseElement("flags");
|
||||||
for(int i = 0; i < town.wandering.size(); i++) {
|
for(int i = 0; i < town.wandering.size(); i++) {
|
||||||
if(town.wandering[i].isNull()) continue;
|
if(town.wandering[i].isNull()) continue;
|
||||||
@@ -849,6 +852,8 @@ map_data buildOutMapData(location which, cScenario& scenario) {
|
|||||||
terrain.set(x, y, sector.terrain[x][y]);
|
terrain.set(x, y, sector.terrain[x][y]);
|
||||||
if(sector.special_spot[x][y])
|
if(sector.special_spot[x][y])
|
||||||
terrain.addFeature(x, y, eMapFeature::FIELD, SPECIAL_SPOT);
|
terrain.addFeature(x, y, eMapFeature::FIELD, SPECIAL_SPOT);
|
||||||
|
if(sector.roads[x][y])
|
||||||
|
terrain.addFeature(x, y, eMapFeature::FIELD, SPECIAL_ROAD);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for(size_t i = 0; i < sector.special_locs.size(); i++) {
|
for(size_t i = 0; i < sector.special_locs.size(); i++) {
|
||||||
|
|||||||
@@ -520,8 +520,8 @@ static void put_out_wand_in_dlog(cDialog& me, short which, const cOutdoors::cWan
|
|||||||
// TODO: Wait a second, if 0 is no monster, does that mean it's impossible to use monster 0? Should 1 be subtracted here?
|
// TODO: Wait a second, if 0 is no monster, does that mean it's impossible to use monster 0? Should 1 be subtracted here?
|
||||||
else me[id].setText(scenario.scen_monsters[wand.friendly[i]].m_name);
|
else me[id].setText(scenario.scen_monsters[wand.friendly[i]].m_name);
|
||||||
}
|
}
|
||||||
dynamic_cast<cLed&>(me["no-flee"]).setState(wand.cant_flee % 10 == 1 ? led_red : led_off);
|
dynamic_cast<cLed&>(me["no-flee"]).setState(wand.cant_flee ? led_red : led_off);
|
||||||
dynamic_cast<cLed&>(me["forced"]).setState(wand.cant_flee >= 10 ? led_red : led_off);
|
dynamic_cast<cLed&>(me["forced"]).setState(wand.forced ? led_red : led_off);
|
||||||
me["onmeet"].setTextToNum(wand.spec_on_meet);
|
me["onmeet"].setTextToNum(wand.spec_on_meet);
|
||||||
me["onwin"].setTextToNum(wand.spec_on_win);
|
me["onwin"].setTextToNum(wand.spec_on_win);
|
||||||
me["onflee"].setTextToNum(wand.spec_on_flee);
|
me["onflee"].setTextToNum(wand.spec_on_flee);
|
||||||
@@ -536,11 +536,8 @@ static void save_out_wand(cDialog& me, short which, cOutdoors::cWandering& wand,
|
|||||||
wand.end_spec1 = me["endx"].getTextAsNum();
|
wand.end_spec1 = me["endx"].getTextAsNum();
|
||||||
wand.end_spec2 = me["endy"].getTextAsNum();
|
wand.end_spec2 = me["endy"].getTextAsNum();
|
||||||
|
|
||||||
wand.cant_flee = 0;
|
wand.forced = dynamic_cast<cLed&>(me["forced"]).getState() != led_off;
|
||||||
if(dynamic_cast<cLed&>(me["forced"]).getState() != led_off)
|
wand.cant_flee = dynamic_cast<cLed&>(me["no-flee"]).getState() != led_off;
|
||||||
wand.cant_flee += 10;
|
|
||||||
if(dynamic_cast<cLed&>(me["no-flee"]).getState() != led_off)
|
|
||||||
wand.cant_flee += 1;
|
|
||||||
|
|
||||||
switch(mode) {
|
switch(mode) {
|
||||||
case 0:
|
case 0:
|
||||||
|
|||||||
@@ -1501,6 +1501,17 @@ void readOutdoorsFromXml(ticpp::Document&& data, cOutdoors& out) {
|
|||||||
auto& enc_list = type == "encounter" ? out.special_enc : out.wandering;
|
auto& enc_list = type == "encounter" ? out.special_enc : out.wandering;
|
||||||
int num_hostile = 0, num_friendly = 0;
|
int num_hostile = 0, num_friendly = 0;
|
||||||
Iterator<Attribute> attr;
|
Iterator<Attribute> attr;
|
||||||
|
for(attr = attr.begin(elem.Get()); attr != attr.end(); attr++) {
|
||||||
|
std::string name, strval;
|
||||||
|
attr->GetName(&name);
|
||||||
|
attr->GetValue(&strval);
|
||||||
|
bool val = strval == "true";
|
||||||
|
if(name == "can-flee")
|
||||||
|
enc_list[count].cant_flee = !val;
|
||||||
|
else if(name == "force")
|
||||||
|
enc_list[count].forced = val;
|
||||||
|
else throw xBadAttr(type, name, attr->Row(), attr->Column(), fname);
|
||||||
|
}
|
||||||
Iterator<Element> enc;
|
Iterator<Element> enc;
|
||||||
for(enc = enc.begin(elem.Get()); enc != enc.end(); enc++) {
|
for(enc = enc.begin(elem.Get()); enc != enc.end(); enc++) {
|
||||||
std::string type;
|
std::string type;
|
||||||
@@ -1656,6 +1667,10 @@ void readTownFromXml(ticpp::Document&& data, cTown*& town, cScenario& scen) {
|
|||||||
flag->GetText(&val);
|
flag->GetText(&val);
|
||||||
if(val == "true")
|
if(val == "true")
|
||||||
town->defy_scrying = true;
|
town->defy_scrying = true;
|
||||||
|
} else if(type == "tavern") {
|
||||||
|
flag->GetText(&val);
|
||||||
|
if(val == "true")
|
||||||
|
town->has_tavern = true;
|
||||||
} else throw xBadNode(type, flag->Row(), flag->Column(), fname);
|
} else throw xBadNode(type, flag->Row(), flag->Column(), fname);
|
||||||
}
|
}
|
||||||
} else if(type == "wandering") {
|
} else if(type == "wandering") {
|
||||||
@@ -1891,6 +1906,8 @@ void loadOutMapData(map_data&& data, location which, cScenario& scen) {
|
|||||||
case eMapFeature::FIELD:
|
case eMapFeature::FIELD:
|
||||||
if(feat.second == SPECIAL_SPOT)
|
if(feat.second == SPECIAL_SPOT)
|
||||||
out.special_spot[x][y] = true;
|
out.special_spot[x][y] = true;
|
||||||
|
else if(feat.second == SPECIAL_ROAD)
|
||||||
|
out.roads[x][y] = true;
|
||||||
else throw xMapParseError(map_out_bad_field, feat.second, y, x, data.file);
|
else throw xMapParseError(map_out_bad_field, feat.second, y, x, data.file);
|
||||||
break;
|
break;
|
||||||
case eMapFeature::SIGN:
|
case eMapFeature::SIGN:
|
||||||
|
|||||||
@@ -3,4 +3,5 @@
|
|||||||
0&9,0&10,0&11,0&12
|
0&9,0&10,0&11,0&12
|
||||||
0&13,0&14,0&15,0&16
|
0&13,0&14,0&15,0&16
|
||||||
0&17,0&18,0&19,0&20
|
0&17,0&18,0&19,0&20
|
||||||
0&21,0&22,0&23,0&24
|
0&21,0&22,0&23,0&24
|
||||||
|
0&25
|
||||||
5
test/files/maps/fields_out.map
Normal file
5
test/files/maps/fields_out.map
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
1,2,3,4,5
|
||||||
|
6,7,8,9,10
|
||||||
|
11,12,13&9,14,15
|
||||||
|
16,17,18&25,19,20
|
||||||
|
21,22,23&25,24,25
|
||||||
@@ -1,5 +1,3 @@
|
|||||||
<sector boes="2.0.0">
|
<sector boes="2.0.0">
|
||||||
<encounter>
|
<encounter bad='no'/>
|
||||||
<monster human='false'/>
|
|
||||||
</encounter>
|
|
||||||
</sector>
|
</sector>
|
||||||
5
test/files/outdoor/encounter_bad_monst_attr.xml
Normal file
5
test/files/outdoor/encounter_bad_monst_attr.xml
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
<sector boes="2.0.0">
|
||||||
|
<encounter>
|
||||||
|
<monster human='false'/>
|
||||||
|
</encounter>
|
||||||
|
</sector>
|
||||||
26
test/files/outdoor/full.xml
Normal file
26
test/files/outdoor/full.xml
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
<sector boes="2.0.0">
|
||||||
|
<name>Test Sector</name>
|
||||||
|
<comment>Hello World!</comment>
|
||||||
|
<sound>birds</sound>
|
||||||
|
<encounter can-flee='false' force='true'>
|
||||||
|
<monster>12</monster>
|
||||||
|
<monster friendly='true'>15</monster>
|
||||||
|
<onmeet>90</onmeet>
|
||||||
|
<onwin>92</onwin>
|
||||||
|
<onflee>84</onflee>
|
||||||
|
<sdf x='202' y='19'/>
|
||||||
|
</encounter>
|
||||||
|
<wandering can-flee='false' force='true'>
|
||||||
|
<monster>12</monster>
|
||||||
|
<monster friendly='true'>15</monster>
|
||||||
|
<onmeet>90</onmeet>
|
||||||
|
<onwin>92</onwin>
|
||||||
|
<onflee>84</onflee>
|
||||||
|
<sdf x='202' y='19'/>
|
||||||
|
</wandering>
|
||||||
|
<sign id='7'>The best sign ever!</sign>
|
||||||
|
<area top='4' left='8' bottom='9' right='12'>
|
||||||
|
<![CDATA[Some random area Amazing!]]>
|
||||||
|
</area>
|
||||||
|
<string id='9'>A random special string</string>
|
||||||
|
</sector>
|
||||||
4
test/files/outdoor/sound.xml
Normal file
4
test/files/outdoor/sound.xml
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
<sector boes="2.0.0">
|
||||||
|
<name>Test Sector</name>
|
||||||
|
<sound>42</sound>
|
||||||
|
</sector>
|
||||||
37
test/files/talk/full.xml
Normal file
37
test/files/talk/full.xml
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
<dialogue boes="2.0.0">
|
||||||
|
<personality id='0'>
|
||||||
|
<title>Billy Kumquat</title>
|
||||||
|
<look>You see a small boy juggling fruit.</look>
|
||||||
|
<name>"I'm Billy Kumquat!"</name>
|
||||||
|
<job>"I juggle!"</job>
|
||||||
|
<unknown>"No clue!"</unknown>
|
||||||
|
</personality>
|
||||||
|
<node for='0'>
|
||||||
|
<keyword>jugg</keyword>
|
||||||
|
<type>reg</type>
|
||||||
|
<text>"It's fun!"</text>
|
||||||
|
</node>
|
||||||
|
<node for='0'>
|
||||||
|
<keyword>info</keyword>
|
||||||
|
<type>buy-sdf</type>
|
||||||
|
<param>1</param>
|
||||||
|
<param>2</param>
|
||||||
|
<param>3</param>
|
||||||
|
<text>"There's a treasure hidden in the old tree!"</text>
|
||||||
|
<text>"For a gold piece I'll tell you something interesting!"</text>
|
||||||
|
</node>
|
||||||
|
<node for='0'>
|
||||||
|
<keyword>purc</keyword>
|
||||||
|
<type>shop</type>
|
||||||
|
<param>0</param>
|
||||||
|
<param>4</param>
|
||||||
|
<text>Billy Kumquat's Oddest Fruit</text>
|
||||||
|
</node>
|
||||||
|
<node for='0'>
|
||||||
|
<keyword>kumq</keyword>
|
||||||
|
<type>quest</type>
|
||||||
|
<param>5</param>
|
||||||
|
<text>"I'll reward you if you find me some bigger kumquats!"</text>
|
||||||
|
<text>"Thanks for finding the bigger kumquats!"</text>
|
||||||
|
</node>
|
||||||
|
</dialogue>
|
||||||
6
test/files/town/dup_onenter_condition.xml
Normal file
6
test/files/town/dup_onenter_condition.xml
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
<town boes="2.0.0">
|
||||||
|
<size>32</size>
|
||||||
|
<name>Hello World</name>
|
||||||
|
<onenter condition='alive'>1</onenter>
|
||||||
|
<onenter condition='alive'>2</onenter>
|
||||||
|
</town>
|
||||||
56
test/files/town/full.xml
Normal file
56
test/files/town/full.xml
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
<town boes="2.0.0">
|
||||||
|
<size>32</size>
|
||||||
|
<name>Test Town</name>
|
||||||
|
<comment>This is a silly little comment.</comment>
|
||||||
|
<bounds top='4' left='4' right='28' bottom='28'/>
|
||||||
|
<difficulty>1</difficulty>
|
||||||
|
<lighting>lit</lighting>
|
||||||
|
<onenter condition='alive'>12</onenter>
|
||||||
|
<onenter condition='dead'>13</onenter>
|
||||||
|
<exit dir='n' x='4' y='16'/>
|
||||||
|
<onexit dir='n'>52</onexit>
|
||||||
|
<onoffend>42</onoffend>
|
||||||
|
<timer freq='100'>15</timer>
|
||||||
|
<flags>
|
||||||
|
<chop day='18' event='4' kills='50000'/>
|
||||||
|
<hidden>true</hidden>
|
||||||
|
<strong-barriers>true</strong-barriers>
|
||||||
|
<defy-mapping>true</defy-mapping>
|
||||||
|
<defy-scrying>true</defy-scrying>
|
||||||
|
<tavern>true</tavern>
|
||||||
|
</flags>
|
||||||
|
<wandering>
|
||||||
|
<monster>40</monster>
|
||||||
|
<monster>41</monster>
|
||||||
|
<monster>42</monster>
|
||||||
|
<monster>43</monster>
|
||||||
|
</wandering>
|
||||||
|
<sign id='1'>This is a sample sign.</sign>
|
||||||
|
<string id='7'>Here is a town string.</string>
|
||||||
|
<item id='2'>
|
||||||
|
<type>120</type>
|
||||||
|
<mod>2</mod>
|
||||||
|
<charges>17</charges>
|
||||||
|
<always>true</always>
|
||||||
|
<property>true</property>
|
||||||
|
<contained>true</contained>
|
||||||
|
</item>
|
||||||
|
<creature id='12'>
|
||||||
|
<type>140</type>
|
||||||
|
<attitude>hostile-b</attitude>
|
||||||
|
<mobility>1</mobility>
|
||||||
|
<sdf x='12' y='13'/>
|
||||||
|
<encounter>50</encounter>
|
||||||
|
<time type='after-event'>
|
||||||
|
<day>17</day>
|
||||||
|
<event>14</event>
|
||||||
|
</time>
|
||||||
|
<face>142</face>
|
||||||
|
<personality>1</personality>
|
||||||
|
<onkill>80</onkill>
|
||||||
|
<ontalk>81</ontalk>
|
||||||
|
</creature>
|
||||||
|
<area top='14' left='16' bottom='20' right='22'>
|
||||||
|
<![CDATA[This is a sample area description.]]>
|
||||||
|
</area>
|
||||||
|
</town>
|
||||||
@@ -98,6 +98,17 @@ TEST_CASE("Loading map data from file") {
|
|||||||
CHECK(map.getFeatures(2, 5) == test);
|
CHECK(map.getFeatures(2, 5) == test);
|
||||||
test[0].second = BARRIER_CAGE;
|
test[0].second = BARRIER_CAGE;
|
||||||
CHECK(map.getFeatures(3, 5) == test);
|
CHECK(map.getFeatures(3, 5) == test);
|
||||||
|
test[0].second = SPECIAL_ROAD;
|
||||||
|
CHECK(map.getFeatures(0, 6) == test);
|
||||||
|
}
|
||||||
|
SECTION("With fields outdoors") {
|
||||||
|
fin.open("files/maps/fields_out.map");
|
||||||
|
map = load_map(fin, false, "fields_out.map");
|
||||||
|
test.emplace_back(make_pair(eMapFeature::FIELD, SPECIAL_SPOT));
|
||||||
|
CHECK(map.getFeatures(2, 2) == test);
|
||||||
|
test[0].second = SPECIAL_ROAD;
|
||||||
|
CHECK(map.getFeatures(2, 3) == test);
|
||||||
|
CHECK(map.getFeatures(2, 4) == test);
|
||||||
}
|
}
|
||||||
SECTION("With town entrance") {
|
SECTION("With town entrance") {
|
||||||
fin.open("files/maps/towns_out.map");
|
fin.open("files/maps/towns_out.map");
|
||||||
@@ -215,7 +226,6 @@ TEST_CASE("Interpreting loaded map data") {
|
|||||||
fin.open("files/maps/fields.map");
|
fin.open("files/maps/fields.map");
|
||||||
map = load_map(fin, true, "fields.map");
|
map = load_map(fin, true, "fields.map");
|
||||||
loadTownMapData(move(map), 0, scen);
|
loadTownMapData(move(map), 0, scen);
|
||||||
REQUIRE(scen.towns[0]->preset_fields.size() == 24);
|
|
||||||
static const std::map<eFieldType, location> check = {
|
static const std::map<eFieldType, location> check = {
|
||||||
{WALL_FORCE, {0,0}}, {WALL_FIRE, {1,0}}, {FIELD_ANTIMAGIC, {2,0}}, {CLOUD_STINK, {3,0}},
|
{WALL_FORCE, {0,0}}, {WALL_FIRE, {1,0}}, {FIELD_ANTIMAGIC, {2,0}}, {CLOUD_STINK, {3,0}},
|
||||||
{WALL_ICE, {0,1}}, {WALL_BLADES, {1,1}}, {CLOUD_SLEEP, {2,1}}, {OBJECT_BLOCK, {3,1}},
|
{WALL_ICE, {0,1}}, {WALL_BLADES, {1,1}}, {CLOUD_SLEEP, {2,1}}, {OBJECT_BLOCK, {3,1}},
|
||||||
@@ -223,7 +233,10 @@ TEST_CASE("Interpreting loaded map data") {
|
|||||||
{BARRIER_FIRE, {0,3}}, {BARRIER_FORCE, {1,3}}, {FIELD_QUICKFIRE, {2,3}}, {SFX_SMALL_BLOOD, {3,3}},
|
{BARRIER_FIRE, {0,3}}, {BARRIER_FORCE, {1,3}}, {FIELD_QUICKFIRE, {2,3}}, {SFX_SMALL_BLOOD, {3,3}},
|
||||||
{SFX_MEDIUM_BLOOD, {0,4}}, {SFX_LARGE_BLOOD, {1,4}}, {SFX_SMALL_SLIME, {2,4}}, {SFX_LARGE_SLIME, {3,4}},
|
{SFX_MEDIUM_BLOOD, {0,4}}, {SFX_LARGE_BLOOD, {1,4}}, {SFX_SMALL_SLIME, {2,4}}, {SFX_LARGE_SLIME, {3,4}},
|
||||||
{SFX_ASH, {0,5}}, {SFX_BONES, {1,5}}, {SFX_RUBBLE, {2,5}}, {BARRIER_CAGE, {3,5}},
|
{SFX_ASH, {0,5}}, {SFX_BONES, {1,5}}, {SFX_RUBBLE, {2,5}}, {BARRIER_CAGE, {3,5}},
|
||||||
|
{SPECIAL_ROAD, {0,6}},
|
||||||
};
|
};
|
||||||
|
CAPTURE(check.size());
|
||||||
|
REQUIRE(scen.towns[0]->preset_fields.size() == check.size());
|
||||||
set<eFieldType> found;
|
set<eFieldType> found;
|
||||||
for(const auto& fld : scen.towns[0]->preset_fields) {
|
for(const auto& fld : scen.towns[0]->preset_fields) {
|
||||||
if(found.count(fld.type))
|
if(found.count(fld.type))
|
||||||
@@ -237,6 +250,14 @@ TEST_CASE("Interpreting loaded map data") {
|
|||||||
if(found.size() != check.size())
|
if(found.size() != check.size())
|
||||||
FAIL("Error: A field is missing!");
|
FAIL("Error: A field is missing!");
|
||||||
}
|
}
|
||||||
|
SECTION("With fields outdoors") {
|
||||||
|
fin.open("files/maps/fields_out.map");
|
||||||
|
map = load_map(fin, false, "fields_out.map");
|
||||||
|
loadOutMapData(move(map), loc(0,0), scen);
|
||||||
|
CHECK(scen.outdoors[0][0]->special_spot[2][2]);
|
||||||
|
CHECK(scen.outdoors[0][0]->roads[2][3]);
|
||||||
|
CHECK(scen.outdoors[0][0]->roads[2][4]);
|
||||||
|
}
|
||||||
SECTION("With town entrance") {
|
SECTION("With town entrance") {
|
||||||
fin.open("files/maps/towns_out.map");
|
fin.open("files/maps/towns_out.map");
|
||||||
map = load_map(fin, false, "towns_out.map");
|
map = load_map(fin, false, "towns_out.map");
|
||||||
|
|||||||
@@ -106,6 +106,15 @@ TEST_CASE("Saving map data to file") {
|
|||||||
test[0].second = OBJECT_BLOCK;
|
test[0].second = OBJECT_BLOCK;
|
||||||
CHECK(map.getFeatures(3, 3) == test);
|
CHECK(map.getFeatures(3, 3) == test);
|
||||||
}
|
}
|
||||||
|
SECTION("With fields outdoors") {
|
||||||
|
map.addFeature(0, 0, eMapFeature::FIELD, SPECIAL_SPOT);
|
||||||
|
map.addFeature(1, 1, eMapFeature::FIELD, SPECIAL_ROAD);
|
||||||
|
in_and_out("fields outdoors", map, false);
|
||||||
|
test.emplace_back(make_pair(eMapFeature::FIELD, SPECIAL_SPOT));
|
||||||
|
CHECK(map.getFeatures(0, 0) == test);
|
||||||
|
test[0].second = SPECIAL_ROAD;
|
||||||
|
CHECK(map.getFeatures(1, 1) == test);
|
||||||
|
}
|
||||||
SECTION("With town entrance") {
|
SECTION("With town entrance") {
|
||||||
map.addFeature(0, 0, eMapFeature::TOWN, 4);
|
map.addFeature(0, 0, eMapFeature::TOWN, 4);
|
||||||
in_and_out("town entry loc", map, false);
|
in_and_out("town entry loc", map, false);
|
||||||
@@ -249,6 +258,13 @@ TEST_CASE("Building map data") {
|
|||||||
if(found.size() != check.size())
|
if(found.size() != check.size())
|
||||||
FAIL("Error: A field is missing!");
|
FAIL("Error: A field is missing!");
|
||||||
}
|
}
|
||||||
|
SECTION("With fields outdoors") {
|
||||||
|
scen.outdoors[0][0]->special_spot[0][0] = true;
|
||||||
|
scen.outdoors[0][0]->roads[1][1] = true;
|
||||||
|
in_and_out(scen, false);
|
||||||
|
CHECK(scen.outdoors[0][0]->special_spot[0][0]);
|
||||||
|
CHECK(scen.outdoors[0][0]->roads[1][1]);
|
||||||
|
}
|
||||||
SECTION("With town entrance") {
|
SECTION("With town entrance") {
|
||||||
scen.outdoors[0][0]->city_locs.emplace_back(5, 6, 7);
|
scen.outdoors[0][0]->city_locs.emplace_back(5, 6, 7);
|
||||||
in_and_out(scen, false);
|
in_and_out(scen, false);
|
||||||
|
|||||||
@@ -19,6 +19,9 @@ using namespace ticpp;
|
|||||||
extern Document xmlDocFromStream(istream& stream, string name);
|
extern Document xmlDocFromStream(istream& stream, string name);
|
||||||
extern void readOutdoorsFromXml(Document&& data, cOutdoors& out);
|
extern void readOutdoorsFromXml(Document&& data, cOutdoors& out);
|
||||||
|
|
||||||
|
bool operator==(const cOutdoors::cWandering& lhs, const cOutdoors::cWandering& rhs);
|
||||||
|
ostream& operator<<(ostream& out, const cOutdoors::cWandering& enc);
|
||||||
|
|
||||||
TEST_CASE("Loading an outdoor section definition") {
|
TEST_CASE("Loading an outdoor section definition") {
|
||||||
ifstream fin;
|
ifstream fin;
|
||||||
cScenario scen;
|
cScenario scen;
|
||||||
@@ -66,11 +69,16 @@ TEST_CASE("Loading an outdoor section definition") {
|
|||||||
doc = xmlDocFromStream(fin, "encounter_too_many_monst.xml");
|
doc = xmlDocFromStream(fin, "encounter_too_many_monst.xml");
|
||||||
REQUIRE_THROWS_AS(readOutdoorsFromXml(move(doc), sector), xBadNode);
|
REQUIRE_THROWS_AS(readOutdoorsFromXml(move(doc), sector), xBadNode);
|
||||||
}
|
}
|
||||||
SECTION("When an encounter monster has an invalid attribute") {
|
SECTION("When an encounter has an invalid attribute") {
|
||||||
fin.open("files/outdoor/encounter_bad_attr.xml");
|
fin.open("files/outdoor/encounter_bad_attr.xml");
|
||||||
doc = xmlDocFromStream(fin, "encounter_bad_attr.xml");
|
doc = xmlDocFromStream(fin, "encounter_bad_attr.xml");
|
||||||
REQUIRE_THROWS_AS(readOutdoorsFromXml(move(doc), sector), xBadAttr);
|
REQUIRE_THROWS_AS(readOutdoorsFromXml(move(doc), sector), xBadAttr);
|
||||||
}
|
}
|
||||||
|
SECTION("When an encounter monster has an invalid attribute") {
|
||||||
|
fin.open("files/outdoor/encounter_bad_monst_attr.xml");
|
||||||
|
doc = xmlDocFromStream(fin, "encounter_bad_monst_attr.xml");
|
||||||
|
REQUIRE_THROWS_AS(readOutdoorsFromXml(move(doc), sector), xBadAttr);
|
||||||
|
}
|
||||||
SECTION("When there are too many encounters") {
|
SECTION("When there are too many encounters") {
|
||||||
fin.open("files/outdoor/encounter_too_many.xml");
|
fin.open("files/outdoor/encounter_too_many.xml");
|
||||||
doc = xmlDocFromStream(fin, "encounter_too_many.xml");
|
doc = xmlDocFromStream(fin, "encounter_too_many.xml");
|
||||||
@@ -82,4 +90,66 @@ TEST_CASE("Loading an outdoor section definition") {
|
|||||||
REQUIRE_NOTHROW(readOutdoorsFromXml(move(doc), sector));
|
REQUIRE_NOTHROW(readOutdoorsFromXml(move(doc), sector));
|
||||||
CHECK(sector.out_name == "Test Sector");
|
CHECK(sector.out_name == "Test Sector");
|
||||||
}
|
}
|
||||||
|
SECTION("With an arbitrary ambient sound") {
|
||||||
|
fin.open("files/outdoor/sound.xml");
|
||||||
|
doc = xmlDocFromStream(fin, "sound.xml");
|
||||||
|
REQUIRE_NOTHROW(readOutdoorsFromXml(move(doc), sector));
|
||||||
|
CHECK(sector.ambient_sound == AMBIENT_CUSTOM);
|
||||||
|
CHECK(sector.out_sound == 42);
|
||||||
|
}
|
||||||
|
SECTION("With all possible data") {
|
||||||
|
cOutdoors::cWandering refEncounter;
|
||||||
|
refEncounter.monst[0] = 12;
|
||||||
|
refEncounter.friendly[0] = 15;
|
||||||
|
refEncounter.spec_on_meet = 90;
|
||||||
|
refEncounter.spec_on_win = 92;
|
||||||
|
refEncounter.spec_on_flee = 84;
|
||||||
|
refEncounter.end_spec1 = 202;
|
||||||
|
refEncounter.end_spec2 = 19;
|
||||||
|
refEncounter.cant_flee = true;
|
||||||
|
refEncounter.forced = true;
|
||||||
|
fin.open("files/outdoor/full.xml");
|
||||||
|
doc = xmlDocFromStream(fin, "full.xml");
|
||||||
|
REQUIRE_NOTHROW(readOutdoorsFromXml(move(doc), sector));
|
||||||
|
CHECK(sector.comment == "Hello World!");
|
||||||
|
CHECK(sector.ambient_sound == AMBIENT_BIRD);
|
||||||
|
CHECK(sector.special_enc[0] == refEncounter);
|
||||||
|
CHECK(sector.wandering[0] == refEncounter);
|
||||||
|
REQUIRE(sector.sign_locs.size() >= 8);
|
||||||
|
CHECK(sector.sign_locs[7].text == "The best sign ever!");
|
||||||
|
REQUIRE(sector.info_rect.size() >= 1);
|
||||||
|
CHECK(sector.info_rect[0].descr == "Some random area Amazing!");
|
||||||
|
REQUIRE(sector.spec_strs.size() >= 10);
|
||||||
|
CHECK(sector.spec_strs[9] == "A random special string");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator==(const cOutdoors::cWandering& lhs, const cOutdoors::cWandering& rhs) {
|
||||||
|
if(lhs.monst != rhs.monst) return false;
|
||||||
|
if(lhs.friendly != rhs.friendly) return false;
|
||||||
|
if(lhs.spec_on_meet != rhs.spec_on_meet) return false;
|
||||||
|
if(lhs.spec_on_win != rhs.spec_on_win) return false;
|
||||||
|
if(lhs.spec_on_flee != rhs.spec_on_flee) return false;
|
||||||
|
if(lhs.cant_flee != rhs.cant_flee) return false;
|
||||||
|
if(lhs.forced != rhs.forced) return false;
|
||||||
|
if(lhs.end_spec1 != rhs.end_spec1) return false;
|
||||||
|
if(lhs.end_spec2 != rhs.end_spec2) return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
ostream& operator<<(ostream& out, const cOutdoors::cWandering& enc) {
|
||||||
|
out << "Encounter {";
|
||||||
|
out << "hostile = ";
|
||||||
|
for(auto i : enc.monst)
|
||||||
|
out << i << ' ';
|
||||||
|
out << ", friendly = ";
|
||||||
|
for(auto i : enc.friendly)
|
||||||
|
out << i << ' ';
|
||||||
|
out << ", on-meet = " << enc.spec_on_meet << " , ";
|
||||||
|
out << "on-win = " << enc.spec_on_win << " , ";
|
||||||
|
out << "on-flee = " << enc.spec_on_flee << " , ";
|
||||||
|
out << "can-flee = " << !enc.cant_flee << " , ";
|
||||||
|
out << "forced = " << enc.forced << " , ";
|
||||||
|
out << "sdf = (" << enc.end_spec1 << ',' << enc.end_spec2 << ")}";
|
||||||
|
return out;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,6 +19,9 @@ extern Document xmlDocFromStream(istream& stream, string name);
|
|||||||
extern void readOutdoorsFromXml(Document&& data, cOutdoors& out);
|
extern void readOutdoorsFromXml(Document&& data, cOutdoors& out);
|
||||||
extern void writeOutdoorsToXml(ticpp::Printer&& data, cOutdoors& sector);
|
extern void writeOutdoorsToXml(ticpp::Printer&& data, cOutdoors& sector);
|
||||||
|
|
||||||
|
extern bool operator==(const cOutdoors::cWandering& lhs, const cOutdoors::cWandering& rhs);
|
||||||
|
extern ostream& operator<<(ostream& out, const cOutdoors::cWandering& enc);
|
||||||
|
|
||||||
static void in_and_out(string name, cOutdoors& out, cScenario& scen) {
|
static void in_and_out(string name, cOutdoors& out, cScenario& scen) {
|
||||||
string fpath = "junk/out_";
|
string fpath = "junk/out_";
|
||||||
fpath += name;
|
fpath += name;
|
||||||
@@ -45,4 +48,47 @@ TEST_CASE("Saving an outdoors sector") {
|
|||||||
in_and_out("basic", out, scen);
|
in_and_out("basic", out, scen);
|
||||||
CHECK(out.out_name == "The Outdoors Test");
|
CHECK(out.out_name == "The Outdoors Test");
|
||||||
}
|
}
|
||||||
|
SECTION("With some optional information") {
|
||||||
|
out.comment = "Let's make a comment about comments.";
|
||||||
|
out.ambient_sound = AMBIENT_DRIP;
|
||||||
|
out.sign_locs.emplace_back(0,0,"Guantanamo - 14 mi.");
|
||||||
|
out.info_rect.emplace_back(0,0,1,1,"The heart of the wilderness");
|
||||||
|
out.spec_strs.emplace_back("Something happened!");
|
||||||
|
in_and_out("optional", out, scen);
|
||||||
|
CHECK(out.comment == "Let's make a comment about comments.");
|
||||||
|
CHECK(out.ambient_sound == AMBIENT_DRIP);
|
||||||
|
REQUIRE(out.sign_locs.size() >= 1);
|
||||||
|
CHECK(out.sign_locs[0].text == "Guantanamo - 14 mi.");
|
||||||
|
REQUIRE(out.info_rect.size() >= 1);
|
||||||
|
CHECK(out.info_rect[0].descr == "The heart of the wilderness");
|
||||||
|
REQUIRE(out.spec_strs.size() >= 1);
|
||||||
|
CHECK(out.spec_strs[0] == "Something happened!");
|
||||||
|
}
|
||||||
|
SECTION("With some encounters") {
|
||||||
|
cOutdoors::cWandering spec, wand;
|
||||||
|
|
||||||
|
spec.monst[3] = 42;
|
||||||
|
spec.monst[5] = 12;
|
||||||
|
spec.spec_on_meet = 15;
|
||||||
|
spec.spec_on_win = 12;
|
||||||
|
spec.spec_on_flee = 9;
|
||||||
|
spec.cant_flee = true;
|
||||||
|
spec.forced = true;
|
||||||
|
|
||||||
|
wand.monst[2] = 80;
|
||||||
|
wand.monst[6] = 90;
|
||||||
|
wand.friendly[1] = 12;
|
||||||
|
wand.end_spec1 = 210;
|
||||||
|
wand.end_spec2 = 22;
|
||||||
|
|
||||||
|
REQUIRE(out.special_enc.size() >= 1);
|
||||||
|
out.special_enc[0] = spec;
|
||||||
|
REQUIRE(out.wandering.size() >= 1);
|
||||||
|
out.wandering[0] = wand;
|
||||||
|
in_and_out("encounters", out, scen);
|
||||||
|
REQUIRE(out.special_enc.size() >= 1);
|
||||||
|
CHECK(out.special_enc[0] == spec);
|
||||||
|
REQUIRE(out.wandering.size() >= 1);
|
||||||
|
CHECK(out.wandering[0] == wand);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -121,4 +121,35 @@ TEST_CASE("Loading a town dialogue definition") {
|
|||||||
CHECK(talk.people[0].name == "\"I'm Billy Kumquat!\"");
|
CHECK(talk.people[0].name == "\"I'm Billy Kumquat!\"");
|
||||||
CHECK(talk.people[0].job == "\"I juggle!\"");
|
CHECK(talk.people[0].job == "\"I juggle!\"");
|
||||||
}
|
}
|
||||||
|
SECTION("A full personality with several nodes") {
|
||||||
|
fin.open("files/talk/full.xml");
|
||||||
|
doc = xmlDocFromStream(fin, "full.xml");
|
||||||
|
REQUIRE_NOTHROW(readDialogueFromXml(move(doc), talk, 0));
|
||||||
|
CHECK(talk.people[0].dunno == "\"No clue!\"");
|
||||||
|
REQUIRE(talk.talk_nodes.size() == 4);
|
||||||
|
CHECK(talk.talk_nodes[0].personality == 0);
|
||||||
|
CHECK(string(talk.talk_nodes[0].link1, 4) == "jugg");
|
||||||
|
CHECK(talk.talk_nodes[0].type == eTalkNode::REGULAR);
|
||||||
|
CHECK(talk.talk_nodes[0].str1 == "\"It's fun!\"");
|
||||||
|
CHECK(talk.talk_nodes[1].personality == 0);
|
||||||
|
CHECK(string(talk.talk_nodes[1].link1, 4) == "info");
|
||||||
|
CHECK(talk.talk_nodes[1].type == eTalkNode::BUY_SDF);
|
||||||
|
CHECK(talk.talk_nodes[1].extras[0] == 1);
|
||||||
|
CHECK(talk.talk_nodes[1].extras[1] == 2);
|
||||||
|
CHECK(talk.talk_nodes[1].extras[2] == 3);
|
||||||
|
CHECK(talk.talk_nodes[1].str1 == "\"There's a treasure hidden in the old tree!\"");
|
||||||
|
CHECK(talk.talk_nodes[1].str2 == "\"For a gold piece I'll tell you something interesting!\"");
|
||||||
|
CHECK(talk.talk_nodes[2].personality == 0);
|
||||||
|
CHECK(string(talk.talk_nodes[2].link1, 4) == "purc");
|
||||||
|
CHECK(talk.talk_nodes[2].type == eTalkNode::SHOP);
|
||||||
|
CHECK(talk.talk_nodes[2].extras[0] == 0);
|
||||||
|
CHECK(talk.talk_nodes[2].extras[1] == 4);
|
||||||
|
CHECK(talk.talk_nodes[2].str1 == "Billy Kumquat's Oddest Fruit");
|
||||||
|
CHECK(talk.talk_nodes[3].personality == 0);
|
||||||
|
CHECK(string(talk.talk_nodes[3].link1, 4) == "kumq");
|
||||||
|
CHECK(talk.talk_nodes[3].type == eTalkNode::RECEIVE_QUEST);
|
||||||
|
CHECK(talk.talk_nodes[3].extras[0] == 5);
|
||||||
|
CHECK(talk.talk_nodes[3].str1 == "\"I'll reward you if you find me some bigger kumquats!\"");
|
||||||
|
CHECK(talk.talk_nodes[3].str2 == "\"Thanks for finding the bigger kumquats!\"");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -49,5 +49,48 @@ TEST_CASE("Saving dialogue") {
|
|||||||
CHECK(talk.people[0].name == "\"My name is John Smith. How do you do?\"");
|
CHECK(talk.people[0].name == "\"My name is John Smith. How do you do?\"");
|
||||||
CHECK(talk.people[0].job == "\"Isn't it obvious? I test things!\"");
|
CHECK(talk.people[0].job == "\"Isn't it obvious? I test things!\"");
|
||||||
}
|
}
|
||||||
|
SECTION("With some nodes") {
|
||||||
|
talk.people[0].dunno = "\"I have no idea.\"";
|
||||||
|
talk.talk_nodes.resize(4);
|
||||||
|
strncpy(talk.talk_nodes[0].link1, "sell", 4);
|
||||||
|
talk.talk_nodes[0].type = eTalkNode::SELL_ITEMS;
|
||||||
|
talk.talk_nodes[0].str1 = "\"Ah, you have unwanted items? Never fear, I can take those off your hands!\"";
|
||||||
|
strncpy(talk.talk_nodes[1].link1, "iden", 4);
|
||||||
|
talk.talk_nodes[1].type = eTalkNode::IDENTIFY;
|
||||||
|
talk.talk_nodes[1].extras[0] = 10;
|
||||||
|
talk.talk_nodes[1].str1 = "\"Yes, I can identify your items for a mere 10 gold per item!\"";
|
||||||
|
strncpy(talk.talk_nodes[2].link1, "test", 4);
|
||||||
|
talk.talk_nodes[2].type = eTalkNode::RECEIVE_QUEST;
|
||||||
|
talk.talk_nodes[2].extras[0] = 4;
|
||||||
|
talk.talk_nodes[2].str1 = "\"Yes! In fact, you can help me to test things!\"";
|
||||||
|
talk.talk_nodes[2].str2 = "\"Thanks for the help!\"";
|
||||||
|
strncpy(talk.talk_nodes[3].link1, "boat", 4);
|
||||||
|
talk.talk_nodes[3].type = eTalkNode::BUY_SHIP;
|
||||||
|
talk.talk_nodes[3].extras[0] = 0;
|
||||||
|
talk.talk_nodes[3].extras[1] = 5;
|
||||||
|
talk.talk_nodes[3].extras[2] = 1;
|
||||||
|
talk.talk_nodes[3].str1 = "\"You need a boat? Then you are in luck! I just happen to have a boat!\"";
|
||||||
|
in_and_out("full", talk);
|
||||||
|
CHECK(talk.people[0].dunno == "\"I have no idea.\"");
|
||||||
|
REQUIRE(talk.talk_nodes.size() == 4);
|
||||||
|
CHECK(string(talk.talk_nodes[0].link1, 4) == "sell");
|
||||||
|
CHECK(talk.talk_nodes[0].type == eTalkNode::SELL_ITEMS);
|
||||||
|
CHECK(talk.talk_nodes[0].str1 == "\"Ah, you have unwanted items? Never fear, I can take those off your hands!\"");
|
||||||
|
CHECK(string(talk.talk_nodes[1].link1, 4) == "iden");
|
||||||
|
CHECK(talk.talk_nodes[1].type == eTalkNode::IDENTIFY);
|
||||||
|
CHECK(talk.talk_nodes[1].extras[0] == 10);
|
||||||
|
CHECK(talk.talk_nodes[1].str1 == "\"Yes, I can identify your items for a mere 10 gold per item!\"");
|
||||||
|
CHECK(string(talk.talk_nodes[2].link1, 4) == "test");
|
||||||
|
CHECK(talk.talk_nodes[2].type == eTalkNode::RECEIVE_QUEST);
|
||||||
|
CHECK(talk.talk_nodes[2].extras[0] == 4);
|
||||||
|
CHECK(talk.talk_nodes[2].str1 == "\"Yes! In fact, you can help me to test things!\"");
|
||||||
|
CHECK(talk.talk_nodes[2].str2 == "\"Thanks for the help!\"");
|
||||||
|
CHECK(string(talk.talk_nodes[3].link1, 4) == "boat");
|
||||||
|
CHECK(talk.talk_nodes[3].type == eTalkNode::BUY_SHIP);
|
||||||
|
CHECK(talk.talk_nodes[3].extras[0] == 0);
|
||||||
|
CHECK(talk.talk_nodes[3].extras[1] == 5);
|
||||||
|
CHECK(talk.talk_nodes[3].extras[2] == 1);
|
||||||
|
CHECK(talk.talk_nodes[3].str1 == "\"You need a boat? Then you are in luck! I just happen to have a boat!\"");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -51,6 +51,11 @@ TEST_CASE("Loading a town definition") {
|
|||||||
doc = xmlDocFromStream(fin, "size_not_first.xml");
|
doc = xmlDocFromStream(fin, "size_not_first.xml");
|
||||||
REQUIRE_THROWS_AS(readTownFromXml(move(doc), town, scen), xBadNode);
|
REQUIRE_THROWS_AS(readTownFromXml(move(doc), town, scen), xBadNode);
|
||||||
}
|
}
|
||||||
|
SECTION("When the size is invalid") {
|
||||||
|
fin.open("files/town/bad_size.xml");
|
||||||
|
doc = xmlDocFromStream(fin, "bad_size.xml");
|
||||||
|
REQUIRE_THROWS_AS(readTownFromXml(move(doc), town, scen), xBadVal);
|
||||||
|
}
|
||||||
SECTION("When there is an invalid toplevel node") {
|
SECTION("When there is an invalid toplevel node") {
|
||||||
fin.open("files/town/bad_toplevel.xml");
|
fin.open("files/town/bad_toplevel.xml");
|
||||||
doc = xmlDocFromStream(fin, "bad_toplevel.xml");
|
doc = xmlDocFromStream(fin, "bad_toplevel.xml");
|
||||||
@@ -66,6 +71,11 @@ TEST_CASE("Loading a town definition") {
|
|||||||
doc = xmlDocFromStream(fin, "bad_onenter_condition.xml");
|
doc = xmlDocFromStream(fin, "bad_onenter_condition.xml");
|
||||||
REQUIRE_THROWS_AS(readTownFromXml(move(doc), town, scen), xBadVal);
|
REQUIRE_THROWS_AS(readTownFromXml(move(doc), town, scen), xBadVal);
|
||||||
}
|
}
|
||||||
|
SECTION("When the onenter condition is duplicated") {
|
||||||
|
fin.open("files/town/dup_onenter_condition.xml");
|
||||||
|
doc = xmlDocFromStream(fin, "dup_onenter_condition.xml");
|
||||||
|
REQUIRE_THROWS_AS(readTownFromXml(move(doc), town, scen), xBadVal);
|
||||||
|
}
|
||||||
SECTION("When the onexit direction is invalid") {
|
SECTION("When the onexit direction is invalid") {
|
||||||
fin.open("files/town/bad_onexit_dir.xml");
|
fin.open("files/town/bad_onexit_dir.xml");
|
||||||
doc = xmlDocFromStream(fin, "bad_onexit_dir.xml");
|
doc = xmlDocFromStream(fin, "bad_onexit_dir.xml");
|
||||||
@@ -126,6 +136,61 @@ TEST_CASE("Loading a town definition") {
|
|||||||
CHECK(town->difficulty == 1);
|
CHECK(town->difficulty == 1);
|
||||||
CHECK(town->lighting_type == LIGHT_NORMAL);
|
CHECK(town->lighting_type == LIGHT_NORMAL);
|
||||||
}
|
}
|
||||||
|
SECTION("With all possible data") {
|
||||||
|
fin.open("files/town/full.xml");
|
||||||
|
doc = xmlDocFromStream(fin, "full.xml");
|
||||||
|
REQUIRE_NOTHROW(readTownFromXml(move(doc), town, scen));
|
||||||
|
CHECK(town->comment[0] == "This is a silly little comment.");
|
||||||
|
CHECK(town->spec_on_entry == 12);
|
||||||
|
CHECK(town->spec_on_entry_if_dead == 13);
|
||||||
|
CHECK(town->exit_locs[0] == loc(4,16));
|
||||||
|
CHECK(town->exit_specs[0] == 52);
|
||||||
|
CHECK(town->spec_on_hostile == 42);
|
||||||
|
CHECK(town->town_chop_time == 18);
|
||||||
|
CHECK(town->town_chop_key == 4);
|
||||||
|
CHECK(town->max_num_monst == 50000);
|
||||||
|
CHECK(town->is_hidden);
|
||||||
|
CHECK(town->strong_barriers);
|
||||||
|
CHECK(town->has_tavern);
|
||||||
|
CHECK(town->defy_mapping);
|
||||||
|
CHECK(town->defy_scrying);
|
||||||
|
REQUIRE(town->timers.size() >= 1);
|
||||||
|
CHECK(town->timers[0].node_type == 2);
|
||||||
|
CHECK(town->timers[0].node == 15);
|
||||||
|
CHECK(town->timers[0].time == 100);
|
||||||
|
REQUIRE(town->wandering.size() >= 1);
|
||||||
|
CHECK(town->wandering[0].monst[0] == 40);
|
||||||
|
CHECK(town->wandering[0].monst[1] == 41);
|
||||||
|
CHECK(town->wandering[0].monst[2] == 42);
|
||||||
|
CHECK(town->wandering[0].monst[3] == 43);
|
||||||
|
REQUIRE(town->sign_locs.size() >= 2);
|
||||||
|
CHECK(town->sign_locs[1].text == "This is a sample sign.");
|
||||||
|
REQUIRE(town->spec_strs.size() >= 8);
|
||||||
|
CHECK(town->spec_strs[7] == "Here is a town string.");
|
||||||
|
REQUIRE(town->preset_items.size() >= 3);
|
||||||
|
CHECK(town->preset_items[2].code == 120);
|
||||||
|
CHECK(town->preset_items[2].ability == 2);
|
||||||
|
CHECK(town->preset_items[2].charges == 17);
|
||||||
|
CHECK(town->preset_items[2].always_there);
|
||||||
|
CHECK(town->preset_items[2].property);
|
||||||
|
CHECK(town->preset_items[2].contained);
|
||||||
|
REQUIRE(town->creatures.size() >= 13);
|
||||||
|
CHECK(town->creatures[12].number == 140);
|
||||||
|
CHECK(town->creatures[12].start_attitude == eAttitude::HOSTILE_B);
|
||||||
|
CHECK(town->creatures[12].mobility == 1);
|
||||||
|
CHECK(town->creatures[12].spec1 == 12);
|
||||||
|
CHECK(town->creatures[12].spec2 == 13);
|
||||||
|
CHECK(town->creatures[12].spec_enc_code == 50);
|
||||||
|
CHECK(town->creatures[12].time_flag == eMonstTime::APPEAR_WHEN_EVENT);
|
||||||
|
CHECK(town->creatures[12].monster_time == 17);
|
||||||
|
CHECK(town->creatures[12].time_code == 14);
|
||||||
|
CHECK(town->creatures[12].facial_pic == 142);
|
||||||
|
CHECK(town->creatures[12].personality == 1);
|
||||||
|
CHECK(town->creatures[12].special_on_kill == 80);
|
||||||
|
CHECK(town->creatures[12].special_on_talk == 81);
|
||||||
|
REQUIRE(town->room_rect.size() >= 1);
|
||||||
|
CHECK(town->room_rect[0].descr == "This is a sample area description.");
|
||||||
|
}
|
||||||
|
|
||||||
delete town;
|
delete town;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -50,5 +50,107 @@ TEST_CASE("Saving a town") {
|
|||||||
CHECK(town->in_town_rect == rect(2,3,30,29));
|
CHECK(town->in_town_rect == rect(2,3,30,29));
|
||||||
CHECK(town->difficulty == 1);
|
CHECK(town->difficulty == 1);
|
||||||
CHECK(town->lighting_type == LIGHT_NONE);
|
CHECK(town->lighting_type == LIGHT_NONE);
|
||||||
|
CHECK_FALSE(town->has_tavern);
|
||||||
|
CHECK_FALSE(town->defy_scrying);
|
||||||
|
}
|
||||||
|
SECTION("With lots of optional information") {
|
||||||
|
town->comment[2] = "Try a comment!";
|
||||||
|
town->spec_on_entry = 42;
|
||||||
|
town->spec_on_entry_if_dead = 19;
|
||||||
|
town->spec_on_hostile = 47;
|
||||||
|
town->exit_specs[0] = 16;
|
||||||
|
town->exit_locs[0] = {24,2};
|
||||||
|
town->town_chop_time = 25;
|
||||||
|
town->town_chop_key = 6;
|
||||||
|
town->max_num_monst = 100000;
|
||||||
|
town->is_hidden = town->has_tavern = true;
|
||||||
|
town->defy_scrying = town->defy_mapping = true;
|
||||||
|
town->strong_barriers = true;
|
||||||
|
REQUIRE(town->timers.size() >= 1);
|
||||||
|
town->timers[0].node = 12;
|
||||||
|
town->timers[0].time = 2500;
|
||||||
|
REQUIRE(town->wandering.size() >= 1);
|
||||||
|
town->wandering[0].monst = {7,8,9,10};
|
||||||
|
town->sign_locs.emplace_back(0,0,"Sign #4279816");
|
||||||
|
town->spec_strs.emplace_back("Something! With extra spaces!");
|
||||||
|
town->room_rect.emplace_back(0,0,1,1,"Unknown Area . . .");
|
||||||
|
in_and_out("optional", town, scen);
|
||||||
|
CHECK(town->comment[2] == "Try a comment!");
|
||||||
|
CHECK(town->spec_on_entry == 42);
|
||||||
|
CHECK(town->spec_on_entry_if_dead == 19);
|
||||||
|
CHECK(town->spec_on_hostile == 47);
|
||||||
|
CHECK(town->exit_specs[0] == 16);
|
||||||
|
CHECK(town->exit_locs[0] == loc(24,2));
|
||||||
|
CHECK(town->town_chop_time == 25);
|
||||||
|
CHECK(town->town_chop_key == 6);
|
||||||
|
CHECK(town->max_num_monst == 100000);
|
||||||
|
CHECK(town->is_hidden);
|
||||||
|
CHECK(town->strong_barriers);
|
||||||
|
CHECK(town->has_tavern);
|
||||||
|
CHECK(town->defy_mapping);
|
||||||
|
CHECK(town->defy_scrying);
|
||||||
|
REQUIRE(town->timers.size() >= 1);
|
||||||
|
CHECK(town->timers[0].node_type == 2);
|
||||||
|
CHECK(town->timers[0].node == 12);
|
||||||
|
CHECK(town->timers[0].time == 2500);
|
||||||
|
REQUIRE(town->wandering.size() >= 1);
|
||||||
|
CHECK(town->wandering[0].monst[0] == 7);
|
||||||
|
CHECK(town->wandering[0].monst[1] == 8);
|
||||||
|
CHECK(town->wandering[0].monst[2] == 9);
|
||||||
|
CHECK(town->wandering[0].monst[3] == 10);
|
||||||
|
REQUIRE(town->sign_locs.size() >= 1);
|
||||||
|
CHECK(town->sign_locs[0].text == "Sign #4279816");
|
||||||
|
REQUIRE(town->spec_strs.size() >= 1);
|
||||||
|
CHECK(town->spec_strs[0] == "Something! With extra spaces!");
|
||||||
|
REQUIRE(town->room_rect.size() >= 1);
|
||||||
|
CHECK(town->room_rect[0].descr == "Unknown Area . . .");
|
||||||
|
}
|
||||||
|
SECTION("With a preset item") {
|
||||||
|
town->preset_items.emplace_back();
|
||||||
|
town->preset_items.back().code = 52;
|
||||||
|
town->preset_items.back().ability = 9;
|
||||||
|
town->preset_items.back().charges = 102;
|
||||||
|
town->preset_items.back().always_there = true;
|
||||||
|
town->preset_items.back().property = true;
|
||||||
|
town->preset_items.back().contained = true;
|
||||||
|
in_and_out("item", town, scen);
|
||||||
|
REQUIRE(town->preset_items.size() >= 1);
|
||||||
|
CHECK(town->preset_items[0].code == 52);
|
||||||
|
CHECK(town->preset_items[0].ability == 9);
|
||||||
|
CHECK(town->preset_items[0].charges == 102);
|
||||||
|
CHECK(town->preset_items[0].always_there);
|
||||||
|
CHECK(town->preset_items[0].property);
|
||||||
|
CHECK(town->preset_items[0].contained);
|
||||||
|
}
|
||||||
|
SECTION("With a townsperson") {
|
||||||
|
town->creatures.emplace_back();
|
||||||
|
town->creatures.back().number = 60;
|
||||||
|
town->creatures.back().start_attitude = eAttitude::DOCILE;
|
||||||
|
town->creatures.back().mobility = 1;
|
||||||
|
town->creatures.back().spec1 = 17;
|
||||||
|
town->creatures.back().spec2 = 4;
|
||||||
|
town->creatures.back().spec_enc_code = 3;
|
||||||
|
town->creatures.back().time_flag = eMonstTime::DISAPPEAR_WHEN_EVENT;
|
||||||
|
town->creatures.back().time_code = 5;
|
||||||
|
town->creatures.back().monster_time = 16;
|
||||||
|
town->creatures.back().facial_pic = 56;
|
||||||
|
town->creatures.back().personality = 8;
|
||||||
|
town->creatures.back().special_on_kill = 9;
|
||||||
|
town->creatures.back().special_on_talk = 12;
|
||||||
|
in_and_out("townsperson", town, scen);
|
||||||
|
REQUIRE(town->creatures.size() >= 1);
|
||||||
|
CHECK(town->creatures[0].number == 60);
|
||||||
|
CHECK(town->creatures[0].start_attitude == eAttitude::DOCILE);
|
||||||
|
CHECK(town->creatures[0].mobility == 1);
|
||||||
|
CHECK(town->creatures[0].spec1 == 17);
|
||||||
|
CHECK(town->creatures[0].spec2 == 4);
|
||||||
|
CHECK(town->creatures[0].spec_enc_code == 3);
|
||||||
|
CHECK(town->creatures[0].time_flag == eMonstTime::DISAPPEAR_WHEN_EVENT);
|
||||||
|
CHECK(town->creatures[0].monster_time == 16);
|
||||||
|
CHECK(town->creatures[0].time_code == 5);
|
||||||
|
CHECK(town->creatures[0].facial_pic == 56);
|
||||||
|
CHECK(town->creatures[0].personality == 8);
|
||||||
|
CHECK(town->creatures[0].special_on_kill == 9);
|
||||||
|
CHECK(town->creatures[0].special_on_talk == 12);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user