- found bugs in quest handling...
- making lights and stars n stuff goood
- story??? art??? music???
+
+6/8/2016:
+=========
+
+ - entity stats are saved within the XML files, .dat's are gone
+ - game is overall better
+ - following lights, good lights
+ - good
#include <quest.hpp>
#include <inventory.hpp>
#include <texture.hpp>
+#include <save_util.hpp>
// local library includes
#include <tinyxml2.h>
// constructs the entity with an XML thing-thang
virtual void createFromXML(XMLElement *e, World *w=nullptr) =0;
+ virtual void saveToXML(void) =0;
// a common constructor, clears variables
Entity(void);
void save(void);
void sspawn(float x,float y);
void createFromXML(XMLElement *e, World *w);
+ void saveToXML(void);
};
class Structures : public Entity {
unsigned int spawn(BUILD_SUB, float, float);
void createFromXML(XMLElement *e, World *w);
+ void saveToXML(void);
};
void addAIFunc(bool preload);
- virtual void interact();
- virtual void wander(int);
+ void interact();
+ void wander(int);
void createFromXML(XMLElement *e, World *w);
+ void saveToXML(void);
};
class Merchant : public NPC {
~Merchant();
void wander(int);
+ void saveToXML(void);
};
class Object : public Entity{
return (name == o.name) && (loc == o.loc);
}
void createFromXML(XMLElement *e, World *w);
+ void saveToXML(void);
};
/**
#include <entities.hpp>
#include <gametime.hpp>
#include <ui.hpp>
+#include <save_util.hpp>
// local library headers
#include <tinyxml2.h>
void onHit(unsigned int);
bool bindTex(void);
void createFromXML(XMLElement *e, World *w) final;
+ void saveToXML(void) final;
};
class Door : public Mob {
void onHit(unsigned int);
bool bindTex(void);
void createFromXML(XMLElement *e, World *w) final;
+ void saveToXML(void) final;
};
class Cat : public Mob {
void onHit(unsigned int);
bool bindTex(void);
void createFromXML(XMLElement *e, World *w) final;
+ void saveToXML(void) final;
};
class Rabbit : public Mob {
void onHit(unsigned int);
bool bindTex(void);
void createFromXML(XMLElement *e, World *w) final;
+ void saveToXML(void) final;
};
class Bird : public Mob {
void onHit(unsigned int);
bool bindTex(void);
void createFromXML(XMLElement *e, World *w) final;
+ void saveToXML(void) final;
};
class Trigger : public Mob {
void onHit(unsigned int);
bool bindTex(void);
void createFromXML(XMLElement *e, World *w) final;
+ void saveToXML(void) final;
};
#endif // MOB_H_
--- /dev/null
+#ifndef SAVE_UTIL_H_
+#define SAVE_UTIL_H_
+
+/*
+ * Save macros.
+ */
+
+#define E_SAVE_COORDS { xmle->SetAttribute("x", loc.x); xmle->SetAttribute("y", loc.y); }
+
+#define E_SAVE_HEALTH xmle->SetAttribute("health", health);
+
+/*
+ * Load macos.
+ */
+
+#define E_LOAD_COORDS(yy) { float n; \
+ if (xmle->QueryFloatAttribute("x", &n) == XML_NO_ERROR) \
+ spawn(n, yy); \
+ else \
+ spawn(xmle->FloatAttribute("spawnx"), 100); \
+ \
+ if (xmle->QueryFloatAttribute("y", &n) == XML_NO_ERROR) \
+ loc.y = n; }
+
+#define E_LOAD_HEALTH { float n; \
+ \
+ if (xmle->QueryFloatAttribute("maxHealth", &n) != XML_NO_ERROR) \
+ maxHealth = 1; \
+ \
+ if (xmle->QueryFloatAttribute("health", &n) == XML_NO_ERROR) \
+ health = n; \
+ else \
+ health = maxHealth; }
+
+
+#endif // SAVE_UTIL_H_
// saves the world's data to an XML file
void save(void);
- // attempts to load world data from an XML file
- void load(void);
-
// plays/pauses the world's music, according to if a new world is being entered
void bgmPlay(World *prev) const;
** MAIN ************************************************************************
********************************************************************************/
-int main(int argc, char *argv[]){
+int main(int argc, char *argv[])
+{
static SDL_GLContext mainGLContext = NULL;
+ static bool worldReset = false;
// handle command line arguments
if (argc > 1) {
for (const auto &s : args) {
if (s == "--reset" || s == "-r")
- system("rm -f xml/*.dat");
+ worldReset = true;
}
}
if (xmlFolder.empty())
xmlFolder = "xml/";
- if (currentWorld == nullptr) {
- // read in all XML file names in the folder
- std::vector<std::string> xmlFiles;
- if (getdir(std::string("./" + xmlFolder).c_str(), xmlFiles))
- UserError("Error reading XML files!!!");
+ // read in all XML file names in the folder
+ std::vector<std::string> xmlFiles;
+ if (getdir(std::string("./" + xmlFolder).c_str(), xmlFiles))
+ UserError("Error reading XML files!!!");
+
+ // alphabetically sort files
+ strVectorSortAlpha(&xmlFiles);
+
+ if (worldReset) {
+ for (const auto &xf : xmlFiles) {
+ if (xf[0] != '.') {
+ XMLDocument xmld;
+ xmld.LoadFile(xf.c_str());
+
+ auto xmle = xmld.FirstChildElement("World");
+
+ if (xmle == nullptr)
+ xmle = xmld.FirstChildElement("IndoorWorld");
+
+ if (xmle == nullptr)
+ continue;
- // alphabetically sort files
- strVectorSortAlpha(&xmlFiles);
+ xmle = xmle->FirstChildElement();
+ std::cout << xmle->Name() << '\n';
+ while (xmle) {
+ xmle->DeleteAttribute("x");
+ xmle->DeleteAttribute("y");
+ xmle->DeleteAttribute("health");
+ xmle->DeleteAttribute("alive");
+ xmle->DeleteAttribute("dindex");
+ xmle = xmle->NextSiblingElement();
+ }
+ xmld.SaveFile(xf.c_str(), false);
+ }
+ }
+ }
+ if (currentWorld == nullptr) {
+
// load the first valid XML file for the world
for (const auto &xf : xmlFiles) {
- if (xf[0] != '.' && strcmp(&xf[xf.size() - 3], "dat")){
+ if (xf[0] != '.') {
// read it in
std::cout << "File to load: " << xf << '\n';
currentWorld = loadWorldFromXML(xf);
(void)w;
}
+void Player::saveToXML(void)
+{}
+
NPC::NPC() : Entity()
{
width = HLINES(10);
{
std::string npcname;
bool dialog;
- float spawnx, Xhealth;
unsigned int flooor;
+ xmle = e;
+
// spawn at coordinates if desired
- if (e->QueryFloatAttribute("x", &spawnx) == XML_NO_ERROR)
- spawn(spawnx, 100);
- else
- spawn(0, 100);
+ E_LOAD_COORDS(100);
// name override
if (!(npcname = e->StrAttribute("name")).empty())
Indoorp(w)->moveToFloor(this, flooor);
// custom health value
- if (e->QueryFloatAttribute("health", &Xhealth) == XML_NO_ERROR) {
- health = maxHealth = Xhealth;
- }
+ E_LOAD_HEALTH;
- xmle = e;
+ // dialog index
+ if (e->QueryUnsignedAttribute("dindex", &flooor) == XML_NO_ERROR)
+ dialogIndex = flooor;
+}
+
+void NPC::saveToXML(void)
+{
+ E_SAVE_HEALTH;
+ E_SAVE_COORDS;
+ xmle->SetAttribute("dindex", dialogIndex);
}
Merchant::Merchant() : NPC()
{
}
+void Merchant::saveToXML(void){}
+
Structures::Structures() : Entity()
{
canMove = false;
{
float spawnx;
+ if (e->QueryBoolAttribute("alive", &alive) == XML_NO_ERROR && !alive) {
+ die();
+ return;
+ }
+
inWorld = w;
inside = e->StrAttribute("inside");
textureLoc = e->StrAttribute("texture");
spawn(static_cast<BUILD_SUB>(e->UnsignedAttribute("type")),
- e->QueryFloatAttribute("x", &spawnx) == XML_NO_ERROR ? spawnx : (randGet() % w->getTheWidth() / 2.0f),
+ e->QueryFloatAttribute("spawnx", &spawnx) == XML_NO_ERROR ? spawnx : (randGet() % w->getTheWidth() / 2.0f),
100);
+
+ xmle = e;
+}
+
+void Structures::saveToXML(void)
+{
+ xmle->SetAttribute("alive", alive);
}
Object::Object()
(void)w;
}
+void Object::saveToXML(void)
+{}
+
void Object::reloadTexture(void)
{
tex = TextureIterator({getItemTexturePath(iname)});
cId = e->StrAttribute("cid");
cValue = e->StrAttribute("cvalue");
+
+ xmle = e;
}
+void Page::saveToXML(void)
+{}
+
Door::Door(void) : Mob()
{
ridable = false;
loc.x = Xlocx;
}
+void Door::saveToXML(void)
+{}
+
Cat::Cat(void) : Mob()
{
ridable = true;
void Cat::createFromXML(XMLElement *e, World *w=nullptr)
{
(void)w;
- float Xlocx;
- if (e->QueryFloatAttribute("x", &Xlocx) == XML_NO_ERROR)
- loc.x = Xlocx;
+ float spawnc;
+
+ if (e->QueryFloatAttribute("x", &spawnc) == XML_NO_ERROR)
+ loc.x = spawnc;
+ else
+ loc.x = e->FloatAttribute("spawnx");
+
+ if (e->QueryFloatAttribute("y", &spawnc) == XML_NO_ERROR)
+ loc.y = spawnc;
+
+ xmle = e;
+}
+
+void Cat::saveToXML(void)
+{
+ E_SAVE_COORDS;
+ xmle->SetAttribute("alive", alive);
}
Rabbit::Rabbit(void) : Mob()
void Rabbit::createFromXML(XMLElement *e, World *w=nullptr)
{
(void)w;
- float Xlocx, Xhealth;
- if (e->QueryFloatAttribute("x", &Xlocx) == XML_NO_ERROR)
- loc.x = Xlocx;
- if (e->QueryFloatAttribute("health", &Xhealth) == XML_NO_ERROR)
- maxHealth = health = Xhealth;
- if (e->QueryBoolAttribute("aggressive", &aggressive) != XML_NO_ERROR) {
- aggressive = false;
- }
+ float spawnc;
xmle = e;
+
+ if (e->QueryFloatAttribute("x", &spawnc) == XML_NO_ERROR)
+ loc.x = spawnc;
+ else
+ loc.x = e->FloatAttribute("spawnx");
+
+ if (e->QueryFloatAttribute("y", &spawnc) == XML_NO_ERROR)
+ loc.y = spawnc;
+
+ E_LOAD_HEALTH;
+
+ if (e->QueryBoolAttribute("aggressive", &aggressive) != XML_NO_ERROR)
+ aggressive = false;
+}
+
+void Rabbit::saveToXML(void)
+{
+ E_SAVE_HEALTH;
}
Bird::Bird(void) : Mob()
{
(void)w;
float Xlocx, Xhealth;
- if (e->QueryFloatAttribute("x", &Xlocx) == XML_NO_ERROR)
- loc.x = Xlocx;
- if (e->QueryFloatAttribute("health", &Xhealth) == XML_NO_ERROR)
- maxHealth = health = Xhealth;
- if (e->QueryFloatAttribute("y", &initialY) != XML_NO_ERROR)
- initialY = 300;
+
+ xmle = e;
+
+ if (e->QueryFloatAttribute("x", &Xlocx) == XML_NO_ERROR)
+ loc.x = Xlocx;
+ if (e->QueryFloatAttribute("y", &initialY) != XML_NO_ERROR)
+ initialY = 300;
+
+ E_LOAD_HEALTH;
+
if (e->QueryBoolAttribute("aggressive", &aggressive) != XML_NO_ERROR)
aggressive = false;
}
+void Bird::saveToXML(void)
+{
+ E_SAVE_COORDS;
+ E_SAVE_HEALTH;
+}
+
Trigger::Trigger(void) : Mob()
{
ridable = false;
id = e->StrAttribute("id");
}
+void Trigger::saveToXML(void)
+{}
+
Mob::~Mob()
{
delete inv;
{ 255, 255, 0.1 }
};
+static std::string currentXMLRaw;
+XMLDocument currentXMLDoc;
+
/* ----------------------------------------------------------------------------
** Functions section
** --------------------------------------------------------------------------*/
vec2 World::
getStructurePos(int index)
{
- if (build.empty())
+ if (build.empty() || (unsigned)index >= build.size())
return vec2 {0, 0};
if (index < 0)
return build.back()->loc;
- else if ((unsigned)index >= build.size())
- return vec2 {0, 0};
return build[index]->loc;
}
-template<typename T>
-void appVal(const T &x, std::string &str)
-{
- str.append(std::to_string(static_cast<int>(x)) + "\n");
-}
-
/**
* Saves world data to a file.
*/
-void World::save(void){
- std::string data;
- std::string save = currentXML + ".dat";
- std::ofstream out (save, std::ios::out | std::ios::binary);
-
- std::cout << "Saving to " << save << " ..." << '\n';
-
- // save npcs
- for (auto &n : npc) {
- appVal(n->dialogIndex, data);
- appVal(n->loc.x, data);
- appVal(n->loc.y, data);
- }
-
- // save structures
- for (auto &b : build) {
- appVal(b->loc.x, data);
- appVal(b->loc.y, data);
- }
-
- // save mobs
- for (auto &m : mob) {
- appVal(m->loc.x, data);
- appVal(m->loc.y, data);
- appVal(m->isAlive(), data);
- }
-
- // wrap up
- data.append("dOnE\0");
- out.write(data.data(), data.size());
- out.close();
-}
-
-template<typename T>
-bool getVal(T &x, std::istringstream &iss)
+void World::save(void)
{
- std::string str;
- std::getline(iss, str);
+ for (const auto &e : entity)
+ e->saveToXML();
- if (str == "dOnE")
- return false;
-
- x = std::stoi(str);
- return true;
-}
-
-void World::load(void){
- std::string save, data, line;
- const char *filedata;
-
- save = currentXML + ".dat";
- filedata = readFile(save.c_str());
- data = filedata;
- std::istringstream iss (data);
-
- for(auto &n : npc){
- if (!getVal(n->dialogIndex, iss)) return;
- if (n->dialogIndex != 9999)
- n->addAIFunc(false);
-
- if (!getVal(n->loc.x, iss)) return;
- if (!getVal(n->loc.y, iss)) return;
- }
-
- for(auto &b : build){
- if (!getVal(b->loc.x, iss)) return;
- if (!getVal(b->loc.y, iss)) return;
- }
-
- bool alive = true;
- for(auto &m : mob){
- if (!getVal(m->loc.x, iss)) return;
- if (!getVal(m->loc.y, iss)) return;
- if (!getVal(alive, iss)) return;
- if (!alive)
- m->die();
- }
-
- while (std::getline(iss,line)) {
- if(line == "dOnE")
- break;
- }
-
- delete[] filedata;
+ currentXMLDoc.SaveFile(currentXML.c_str(), false);
}
/**
* Loads a world from the given XML file.
*/
-static std::string currentXMLRaw;
-XMLDocument currentXMLDoc;
-
-const XMLDocument& loadWorldXML(void)
-{
- static XMLDocument xml;
- if (xml.Parse(currentXMLRaw.data()) != XML_NO_ERROR)
- UserError("XML Error: Failed to parse file (not your fault though..?)");
-
- return xml;
-}
-
World *
loadWorldFromXMLNoSave(std::string path) {
XMLDocument *_currentXMLDoc;
if (!loadedLeft && !loadedRight) {
currentXML = _currentXML;
currentXMLRaw = _currentXMLRaw;
-
- std::ifstream dat ((_currentXML + ".dat").data());
- if (dat.good()) {
- dat.close();
- tmp->load();
- }
} else {
delete _currentXMLDoc;
}
<link right="playerSpawnHill2.xml"/>
<time>12000</time>
<hill peakx="0" peaky="1000" width="50"/>
- <rabbit x="300" aggressive="false" health="100"/>
- <bird y="500"/>
- <cat/>
+ <rabbit spawnx="300" aggressive="false" maxHealth="100" health="32"/>
+ <bird spawny="500" x="379.1998" y="254.95029" health="1"/>
+ <cat x="0" y="67.996956" alive="1"/>
<!--<trigger x="-300" id="Test"/>-->
- <npc name="Ralph" hasDialog="true" x="300"/>
- <npc name="Johnny" hasDialog="false" x="300"/>
- <npc name="Big Dave" hasDialog="true" x="300"/>
- <page x="-200" id="assets/pages/gootaGoFast.png" cid="canSprint" cvalue="1"/>
- <page x="-500" id="assets/pages/gootaJump.png" cid="canJump" cvalue="1"/>
+ <npc name="Ralph" hasDialog="true" spawnx="300" health="1" x="-96.279839" y="66.496941" dindex="2"/>
+ <npc name="Johnny" hasDialog="false" spawnx="300" health="1" x="824.5191" y="71.996918" dindex="0"/>
+ <npc name="Big Dave" hasDialog="true" spawnx="300" health="1" x="235.77779" y="63.396919" dindex="9999"/>
+ <page spawnx="-200" id="assets/pages/gootaGoFast.png" cid="canSprint" cvalue="1"/>
+ <page spawnx="-500" id="assets/pages/gootaJump.png" cid="canJump" cvalue="1"/>
<village name="Big Dave's bagel emporium! The greatest place on earth!">
- <structure type="0" x="-300" inside="playerSpawnHill1_Building1.xml"/>
- <structure type="5" x="-500"/>
- <stall type="market" texture="assets/style/classic/stall.png">
+ <structure type="0" spawnx="-300" inside="playerSpawnHill1_Building1.xml" alive="1"/>
+ <structure type="5" spawnx="-500" alive="1"/>
+ <stall type="market" texture="assets/style/classic/stall.png" alive="1">
<text>
<greet>Welcome to Smithy's! What would you like to purchase today?</greet>
<accept>Thanks!</accept>
<Dialog name="Ralph">
<text id="0" nextid="1">
Hello there! My name is Ralph.
- <gotox>300</gotox>
+ <gotox>300</gotox>
</text>
<text id="1" nextid="2" call="Johnny" callid="0" pause="true">
You should go talk to my friend Johnny. He's a pretty chill dude.
</text>
<text id="2">
Niice.
- <quest check="Your First Quest" fail="3"/></text>
+ <quest check="Your First Quest" fail="3"/></text>
<text id="3">
Go check out Johnny. He's cool.
</text>
<Dialog name="Johnny">
<text id="0" nextid="1" pause="true">
Sup bro! Have a quest. To complete it, just go talk to Ralph again.
- <quest assign="Your First Quest">
+ <quest assign="Your First Quest">
Dank MayMay,2
Wood Sword,1
</quest>
<text id="0" pause="true">
Hey friend! It's dangerous out there, here take these!
Wait, promise you'll stop by my stand in the local market!
- <give id="Wood Sword" count="1"/>
- <give id="Hunters Bow" count="1"/>
- <give id="Crude Arrow" count="110"/>
- <give id="Fried Chicken" count="1"/>
- </text>
+ <give id="Wood Sword" count="1"/> <give id="Hunters Bow" count="1"/> <give id="Crude Arrow" count="110"/> <give id="Fried Chicken" count="1"/></text>
</Dialog>