Implement writing town to XML

This commit is contained in:
2015-01-22 21:35:50 -05:00
parent 5e21b8d4be
commit ac4441f33e
12 changed files with 259 additions and 69 deletions

View File

@@ -38,13 +38,23 @@
</xs:simpleType>
</xs:element>
<xs:element name="name" type="xs:string"/>
<xs:element name="comment" type="xs:string" minOccurs="0" maxOccurs="3"/>
<xs:element name="bounds">
<xs:complexType>
<xs:attributeGroup ref="rect"/>
</xs:complexType>
</xs:element>
<xs:element name="difficulty" type="xs:integer"/>
<xs:element name="lighting" type="xs:integer"/>
<xs:element name="lighting">
<xs:simpleType>
<xs:restriction base="xs:string">
<xs:enumeration value="lit"/>
<xs:enumeration value="dark"/>
<xs:enumeration value="drains"/>
<xs:enumeration value="none"/>
</xs:restriction>
</xs:simpleType>
</xs:element>
<xs:element name="onenter" minOccurs="0" maxOccurs="2">
<xs:complexType>
<xs:simpleContent>
@@ -81,7 +91,7 @@
<xs:complexType>
<xs:simpleContent>
<xs:extension base="xs:integer">
<xs:attribute name="at" type="xs:integer" use="required"/>
<xs:attribute name="freq" type="xs:integer" use="required"/>
</xs:extension>
</xs:simpleContent>
</xs:complexType>
@@ -91,11 +101,12 @@
<xs:all>
<xs:element name="chop" minOccurs="0">
<xs:complexType>
<xs:attribute name="day" type="xs:integer"/>
<xs:attribute name="event" type="xs:integer"/>
<xs:attribute name="kills" type="xs:integer"/>
<xs:attribute name="day" type="xs:integer" use="required"/>
<xs:attribute name="event" type="xs:integer" use="required"/>
<xs:attribute name="kills" type="xs:integer" use="required"/>
</xs:complexType>
</xs:element>
<xs:element name="hidden" 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-scrying" minOccurs="0" type="bool"/>
@@ -127,11 +138,11 @@
</xs:simpleContent>
</xs:complexType>
</xs:element>
<xs:element name="fields">
<xs:element name="string">
<xs:complexType>
<xs:simpleContent>
<xs:extension base="xs:integer">
<xs:attributeGroup ref="point"/>
<xs:extension base="xs:string">
<xs:attribute name="id" type="xs:integer"/>
</xs:extension>
</xs:simpleContent>
</xs:complexType>
@@ -139,28 +150,25 @@
<xs:element name="item">
<xs:complexType>
<xs:all>
<xs:element name="id" type="xs:integer"/>
<xs:element name="type" type="xs:integer"/>
<xs:element name="mod" type="xs:integer" minOccurs="0"/>
<xs:element name="charges" type="xs:integer" minOccurs="0"/>
<xs:element name="always" type="bool" minOccurs="0"/>
<xs:element name="property" type="bool" minOccurs="0"/>
<xs:element name="contained" type="bool" minOccurs="0"/>
</xs:all>
<xs:attributeGroup ref="point"/>
<xs:attribute name="id" type="xs:integer"/>
</xs:complexType>
</xs:element>
<xs:element name="creature">
<xs:complexType>
<xs:all>
<xs:element name="id" type="xs:integer"/>
<xs:element name="type" type="xs:integer"/>
<xs:element name="attitude" type="xs:integer"/>
<xs:element name="mobility" type="xs:integer"/>
<xs:element name="sdf" minOccurs="0">
<xs:complexType>
<xs:simpleContent>
<xs:extension base="xs:integer">
<xs:attributeGroup ref="point"/>
</xs:extension>
</xs:simpleContent>
<xs:attributeGroup ref="point"/>
</xs:complexType>
</xs:element>
<xs:element name="encounter" type="xs:integer" minOccurs="0"/>
@@ -169,14 +177,28 @@
<xs:sequence>
<xs:element name="param" maxOccurs="2" type="xs:integer"/>
</xs:sequence>
<xs:attribute name="type" type="xs:integer"/>
<xs:attribute name="type">
<xs:simpleType>
<xs:restriction base="xs:string">
<xs:enumeration value="always"/>
<xs:enumeration value="after-day"/>
<xs:enumeration value="until-day"/>
<xs:enumeration value="travel-a"/>
<xs:enumeration value="travel-b"/>
<xs:enumeration value="travel-c"/>
<xs:enumeration value="after-event"/>
<xs:enumeration value="until-event"/>
<xs:enumeration value="after-chop"/>
</xs:restriction>
</xs:simpleType>
</xs:attribute>
</xs:complexType>
</xs:element>
<xs:element name="face" type="xs:integer" minOccurs="0"/>
<xs:element name="personality" type="xs:integer" minOccurs="0"/>
<xs:element name="onkill" type="xs:integer" minOccurs="0"/>
</xs:all>
<xs:attributeGroup ref="point"/>
<xs:attribute name="id" type="xs:integer"/>
</xs:complexType>
</xs:element>
<xs:element name="description">

View File

@@ -8,7 +8,7 @@
<difficulty>1</difficulty>
<!-- Town's lighting type -->
<lighting>0</lighting>
<lighting>lit</lighting>
<!-- Entry specials; omitting condition is equivalent to ="alive" -->
<onenter>12</onenter>
@@ -28,20 +28,17 @@
</wandering>
<sign id="0">This is a sample sign!</sign>
<!-- these code both fields and sfx -->
<fields x="25" y="17">128</fields><!-- fields.h, bitmask thing -->
<!-- preset items -->
<item x="12" y="13">
<id>17</id>
<item id='17'>
<type>17</type>
<property>true</property>
<charges>3</charges>
</item>
<!-- preset creatures -->
<creature x="15" y="32">
<id>12</id>
<creature id='12'>
<type>12</type>
<personality>0</personality>
<attitude>0</attitude>
<mobility>1</mobility>

View File

@@ -3222,8 +3222,8 @@ void ifthen_spec(eSpecCtx which_mode,cSpecial cur_node,short cur_spec_type,
break;
}
i = 0;
for(j = spec.ex1b; j < std::min(spec.ex2b, univ.town->max_dim()); j++)
for(k = spec.ex1a; k < std::min(spec.ex2a, univ.town->max_dim()); k++) {
for(j = spec.ex1b; j < min(spec.ex2b, univ.town->max_dim()); j++)
for(k = spec.ex1a; k < min(spec.ex2a, univ.town->max_dim()); k++) {
switch(eFieldType(spec.m1)) {
// These values are not allowed
case SPECIAL_EXPLORED: case SPECIAL_SPOT: case FIELD_DISPEL: case FIELD_SMASH: break;

View File

@@ -168,7 +168,7 @@ public:
unsigned long id;
mon_num_t number;
short active, attitude;
unsigned char start_attitude;
unsigned int start_attitude;
location start_loc, cur_loc;
unsigned short mobility;
eMonstTime time_flag;

View File

@@ -298,38 +298,38 @@ cTinyTown::cTinyTown(cScenario& scenario, bool init_strings) : cTown(scenario, i
init_start();
}
short cBigTown::max_dim() const {
size_t cBigTown::max_dim() const {
return 64;
}
short cMedTown::max_dim() const {
size_t cMedTown::max_dim() const {
return 48;
}
short cTinyTown::max_dim() const {
size_t cTinyTown::max_dim() const {
return 32;
}
short cBigTown::max_monst() const {
size_t cBigTown::max_monst() const {
return 60;
}
short cMedTown::max_monst() const {
size_t cMedTown::max_monst() const {
return 40;
}
short cTinyTown::max_monst() const {
size_t cTinyTown::max_monst() const {
return 30;
}
short cBigTown::max_items() const {
size_t cBigTown::max_items() const {
return 64;
}
short cMedTown::max_items() const {
size_t cMedTown::max_items() const {
return 64;
}
short cTinyTown::max_items() const {
size_t cTinyTown::max_items() const {
return 64;
}

View File

@@ -32,9 +32,9 @@ public:
ter_num_t& terrain(size_t x, size_t y);
cCreature& creatures(size_t i);
unsigned char& lighting(size_t i, size_t r);
short max_dim() const;
short max_monst() const;
short max_items() const;
size_t max_dim() const;
size_t max_monst() const;
size_t max_items() const;
explicit cBigTown(cScenario& scenario, bool init_strings = false);
void writeTerrainTo(std::ostream& file);
@@ -51,9 +51,9 @@ public:
ter_num_t& terrain(size_t x, size_t y);
cCreature& creatures(size_t i);
unsigned char& lighting(size_t i, size_t r);
short max_dim() const;
short max_monst() const;
short max_items() const;
size_t max_dim() const;
size_t max_monst() const;
size_t max_items() const;
explicit cMedTown(cScenario& scenario, bool init_strings = false);
void writeTerrainTo(std::ostream& file);
@@ -70,9 +70,9 @@ public:
ter_num_t& terrain(size_t x, size_t y);
cCreature& creatures(size_t i);
unsigned char& lighting(size_t i, size_t r);
short max_dim() const;
short max_monst() const;
short max_items() const;
size_t max_dim() const;
size_t max_monst() const;
size_t max_items() const;
explicit cTinyTown(cScenario& scenario, bool init_strings = false);
void writeTerrainTo(std::ostream& file);

View File

@@ -33,14 +33,14 @@ unsigned char& cBigTemplTown::lighting(size_t i, size_t r){
return _lighting[i][r];
}
short cBigTemplTown::max_dim() const {
size_t cBigTemplTown::max_dim() const {
return 0; // not sure what they are yet.
}
short cBigTemplTown::max_monst() const {
size_t cBigTemplTown::max_monst() const {
return 30;
}
short cBigTemplTown::max_items() const {
size_t cBigTemplTown::max_items() const {
return 64;
}

View File

@@ -45,9 +45,9 @@ public:
ter_num_t& terrain(size_t x, size_t y);
cCreature& creatures(size_t i);
unsigned char& lighting(size_t i, size_t r);
short max_dim() const;
short max_monst() const;
short max_items() const;
size_t max_dim() const;
size_t max_monst() const;
size_t max_items() const;
void writeTerrainTo(std::ostream& file);
void readTerrainFrom(std::istream& file);
explicit cBigTemplTown(cScenario& scenario, bool init_strings = false);
@@ -62,9 +62,9 @@ public:
ter_num_t& terrain(size_t x, size_t y);
cCreature& creatures(size_t i);
unsigned char& lighting(size_t i, size_t r);
short max_dim() const;
short max_monst() const;
short max_items() const;
size_t max_dim() const;
size_t max_monst() const;
size_t max_items() const;
void writeTerrainTo(std::ostream& file);
void readTerrainFrom(std::istream& file);
explicit cMedTemplTown(cScenario& scenario, bool init_strings = false);
@@ -79,9 +79,9 @@ public:
ter_num_t& terrain(size_t x, size_t y);
cCreature& creatures(size_t i);
unsigned char& lighting(size_t i, size_t r);
short max_dim() const;
short max_monst() const;
short max_items() const;
size_t max_dim() const;
size_t max_monst() const;
size_t max_items() const;
void writeTerrainTo(std::ostream& file);
void readTerrainFrom(std::istream& file);
explicit cTinyTemplTown(cScenario& scenario, bool init_strings = false);

View File

@@ -13,6 +13,7 @@
#include "classes.h"
#include "oldstructs.h"
#include "mathutil.hpp"
void cTown::append(legacy::big_tr_type&, int){}
void cTown::append(legacy::ave_tr_type&, int){}
@@ -234,8 +235,8 @@ void cTown::set_up_lights() {
l.y = j;
rad = scenario.ter_types[this->terrain(i,j)].light_radius;
if(rad > 0) {
for(where.x = std::max(0,i - rad); where.x < std::min(this->max_dim(),short(i + rad + 1)); where.x++)
for(where.y = std::max(0,j - rad); where.y < std::min(this->max_dim(),short(j + rad + 1)); where.y++)
for(where.x = std::max(0,i - rad); where.x < min(this->max_dim(),short(i + rad + 1)); where.x++)
for(where.y = std::max(0,j - rad); where.y < min(this->max_dim(),short(j + rad + 1)); where.y++)
if(!where_lit[where.x][where.y] && dist(where,l) <= rad && can_see(l,where,get_obscurity) < 5)
where_lit[where.x][where.y] = true;
}
@@ -264,3 +265,23 @@ short cTown::light_obscurity(short x,short y) {
return 1;
return 0;
}
std::ostream& operator<< (std::ostream& out, eLighting light) {
switch(light) {
case LIGHT_NORMAL: out << "lit"; break;
case LIGHT_DARK: out << "dark"; break;
case LIGHT_DRAINS: out << "drains"; break;
case LIGHT_NONE: out << "none"; break;
}
return out;
}
std::istream& operator>> (std::istream& in, eLighting& light) {
std::string key;
if(key == "lit") light = LIGHT_NORMAL;
else if(key == "dark") light = LIGHT_DARK;
else if(key == "drains") light = LIGHT_DRAINS;
else if(key == "none") light = LIGHT_NONE;
else in.fail();
return in;
}

View File

@@ -53,7 +53,7 @@ public:
public:
location loc;
short code,ability;
unsigned char charges;
unsigned int charges;
bool always_there, property, contained;
void append(legacy::preset_item_type old);
@@ -77,13 +77,13 @@ public:
location exit_locs[4];
short exit_specs[4];
rectangle in_town_rect;
cItem preset_items[64];
std::array<cItem,64> preset_items;
short max_num_monst;
std::vector<cField> preset_fields;
short spec_on_entry,spec_on_entry_if_dead;
short spec_on_hostile;
short timer_spec_times[8];
short timer_specs[8];
std::array<short,8> timer_spec_times;
std::array<short,8> timer_specs;
std::array<cSpecial,100> specials;
bool strong_barriers : 1;
bool defy_mapping : 1;
@@ -107,9 +107,9 @@ public:
virtual ter_num_t& terrain(size_t x, size_t y) = 0;
virtual cCreature& creatures(size_t i) = 0;
virtual unsigned char& lighting(size_t i, size_t r) = 0;
virtual short max_dim() const = 0;
virtual short max_monst() const = 0;
virtual short max_items() const = 0;
virtual size_t max_dim() const = 0;
virtual size_t max_monst() const = 0;
virtual size_t max_items() const = 0;
void init_start();
void set_up_lights();
short light_obscurity(short x,short y); // Obscurity function used for calculating lighting
@@ -120,4 +120,7 @@ public:
virtual void readTerrainFrom(std::istream& file) = 0;
};
std::ostream& operator<< (std::ostream& out, eLighting light);
std::istream& operator>> (std::istream& in, eLighting& light);
#endif

View File

@@ -24,7 +24,7 @@ void Printer::CloseElement(std::string tagName) {
if(openElements.empty())
throw std::out_of_range("No elements left to close!");
if(tagName != openElements.top()->Value())
throw std::logic_error("Mismatched closing tag!");
throw std::logic_error("Mismatched closing tag! (Expected " + openElements.top()->Value() + ")");
Element* top = openElements.top();
openElements.pop();
PushNode(top);

View File

@@ -61,6 +61,15 @@ template<> void ticpp::Printer::PushElement(std::string tagName, location pos) {
CloseElement(tagName);
}
template<> void ticpp::Printer::PushElement(std::string tagName, rectangle rect) {
OpenElement(tagName);
PushAttribute("top", rect.top);
PushAttribute("left", rect.left);
PushAttribute("bottom", rect.bottom);
PushAttribute("right", rect.right);
CloseElement(tagName);
}
template<> void ticpp::Printer::PushElement(std::string tagName, cMonster::cAttack attack) {
OpenElement(tagName);
PushAttribute("type", attack.type);
@@ -507,6 +516,143 @@ void writeOutdoorsToXml(ticpp::Printer&& data, cOutdoors& sector) {
data.CloseElement("sector");
}
void writeTownToXml(ticpp::Printer&& data, cTown& town) {
static const char directions[] = {'n', 'w', 's', 'e'};
data.OpenElement("town");
data.PushAttribute("boes", scenario.format_ed_version());
data.PushElement("size", town.max_dim());
data.PushElement("name", town.town_name);
for(size_t i = 0; i < town.comment.size(); i++) {
if(!town.comment[i].empty())
data.PushElement("comment", town.comment[i]);
}
data.PushElement("bounds", town.in_town_rect);
data.PushElement("difficulty", town.difficulty);
data.PushElement("lighting", town.lighting_type);
if(town.spec_on_entry >= 0) {
data.OpenElement("onenter");
data.PushAttribute("condition", "alive");
data.PushText(town.spec_on_entry);
data.CloseElement("onenter");
}
if(town.spec_on_entry_if_dead >= 0) {
data.OpenElement("onenter");
data.PushAttribute("condition", "dead");
data.PushText(town.spec_on_entry_if_dead);
data.CloseElement("onenter");
}
for(int i = 0; i < 4; i++) {
if(town.exit_locs[i].x >= 0 && town.exit_locs[i].y >= 0) {
data.OpenElement("exit");
data.PushAttribute("dir", directions[i]);
data.PushAttribute("x", town.exit_locs[i].x);
data.PushAttribute("y", town.exit_locs[i].y);
data.CloseElement("exit");
}
}
for(int i = 0; i < 4; i++) {
if(town.exit_specs[i] >= 0) {
data.OpenElement("onexit");
data.PushAttribute("dir", directions[i]);
data.PushText(town.exit_specs[i]);
data.CloseElement("onexit");
}
}
if(town.spec_on_hostile >= 0)
data.PushElement("onoffend", town.spec_on_hostile);
for(size_t i = 0; i < town.timer_spec_times.size() && i < town.timer_specs.size(); i++) {
data.OpenElement("timer");
data.PushAttribute("freq", town.timer_spec_times[i]);
data.PushText(town.timer_specs[i]);
data.CloseElement("timer");
}
data.OpenElement("flags");
if(town.town_chop_time > 0) {
data.OpenElement("chop");
data.PushAttribute("day", town.town_chop_time);
data.PushAttribute("event", town.town_chop_key);
data.PushAttribute("kills", town.max_num_monst);
data.CloseElement("chop");
}
if(town.strong_barriers)
data.PushElement("strong-barriers", true);
if(town.defy_mapping)
data.PushElement("defy-mapping", true);
if(town.defy_scrying)
data.PushElement("defy-scrying", true);
if(town.is_hidden)
data.PushElement("hidden", true);
data.CloseElement("flags");
for(int i = 0; i < 4; i++) {
if(town.wandering[i].isNull()) continue;
data.OpenElement("wandering");
for(int j = 0; j < 4; j++) {
if(j == 0 || town.wandering[i].monst[j] > 0)
data.PushElement("monster", town.wandering[i].monst[j]);
}
data.CloseElement("wandering");
}
for(size_t i = 0; i < town.preset_items.size(); i++) {
data.OpenElement("item");
data.PushAttribute("id", i);
data.PushElement("type", town.preset_items[i].code);
if(town.preset_items[i].ability >= 0)
data.PushElement("mod", town.preset_items[i].ability);
if(town.preset_items[i].charges > 0)
data.PushElement("charges", town.preset_items[i].charges);
if(town.preset_items[i].always_there)
data.PushElement("always", true);
if(town.preset_items[i].property)
data.PushElement("property", true);
if(town.preset_items[i].contained)
data.PushElement("contained", true);
data.CloseElement("item");
}
for(size_t i = 0; i < town.max_monst(); i++) {
data.OpenElement("creature");
data.PushAttribute("id", i);
cCreature& preset = town.creatures(i);
data.PushElement("type", preset.number);
data.PushElement("attitude", preset.start_attitude);
data.PushElement("mobility", preset.mobility);
data.PushElement("personality", preset.personality);
data.PushElement("face", preset.facial_pic);
if(preset.spec1 >= 0 && preset.spec2 >= 0)
data.PushElement("sdf", loc(preset.spec1, preset.spec2));
if(preset.spec_enc_code > 0)
data.PushElement("encounter", preset.spec_enc_code);
if(preset.special_on_kill >= 0)
data.PushElement("onkill", preset.special_on_kill);
if(preset.time_flag != eMonstTime::ALWAYS) {
data.OpenElement("time");
data.PushAttribute("type", preset.time_flag);
data.PushElement("param", preset.monster_time);
data.PushElement("param", preset.time_code);
data.CloseElement("time");
}
data.CloseElement("creature");
}
for(auto& area : town.room_rect) {
if(!area.descr.empty() && area.top < area.bottom && area.left < area.right)
data.PushElement("description", area);
}
for(size_t i = 0; i < town.sign_strs.size(); i++) {
if(town.sign_strs[i].empty()) continue;
data.OpenElement("sign");
data.PushAttribute("id", i);
data.PushText(town.sign_strs[i]);
data.CloseElement("sign");
}
for(size_t i = 0; i < town.spec_strs.size(); i++) {
if(town.spec_strs[i].empty()) continue;
data.OpenElement("string");
data.PushAttribute("id", i);
data.PushText(town.spec_strs[i]);
data.CloseElement("string");
}
data.CloseElement("town");
}
void save_scenario(fs::path toFile) {
// TODO: I'm not certain 1.0.0 is the correct version here?
scenario.format.prog_make_ver[0] = 1;
@@ -561,6 +707,7 @@ void save_scenario(fs::path toFile) {
std::string file_basename = 't' + std::to_string(i);
// First the main data.
std::ostream& town = scen_file.newFile("scenario/towns/" + file_basename + ".xml");
writeTownToXml(ticpp::Printer(file_basename + ".xml", town), *scenario.towns[i]);
// Then the map.
std::ostream& town_map = scen_file.newFile("scenario/towns/" + file_basename + ".map");