]> code.bitgloo.com Git - clyne/gamedev.git/commitdiff
entitys can modify xml
authorClyne Sullivan <tullivan99@gmail.com>
Tue, 31 May 2016 12:49:48 +0000 (08:49 -0400)
committerClyne Sullivan <tullivan99@gmail.com>
Tue, 31 May 2016 12:49:48 +0000 (08:49 -0400)
14 files changed:
Changelog
assets/dialog_en-us [new file with mode: 0644]
brice.dat
include/common.hpp
include/entities.hpp
include/mob.hpp
include/world.hpp
main.cpp
src/common.cpp
src/entities.cpp
src/mob.cpp
src/ui.cpp
src/world.cpp
xml/playerSpawnHill1.xml

index c81def97b153c9bd9640c9e29a72a075a9851f3e..1dd6ef30bee988684d82acc9b0da1cf45b9d34f6 100644 (file)
--- a/Changelog
+++ b/Changelog
        - fixed grass squishing
        - player sits on cat better
        - world shading is good-er
+
+5/31/2016:
+==========
+
+       - fixed name generation-er
+       - move random dialogs to file
+       - entitys can modify their XMLs
+       - 'alive' XML attribute works
+       - lighting's pretty neat
diff --git a/assets/dialog_en-us b/assets/dialog_en-us
new file mode 100644 (file)
index 0000000..dfe7b03
--- /dev/null
@@ -0,0 +1,15 @@
+What a beautiful day it is.
+Have you ever went fast? I have.
+I heard if you complete a quest, you'll get a special reward.
+How much wood could a woodchuck chuck if a woodchuck could chuck wood?
+I don't think anyone has ever been able to climb up that hill.
+If you ever see a hole in the ground, watch out; it could mean the end for you.
+Did you know this game has over 5000 lines of code? I didn't. I didn't even know I was in a game until now...
+HELP MY CAPS LOCK IS STUCK
+You know, if anyone ever asked me who I wanted to be when I grow up, I would say Abby Ross.
+I want to have the wallpaper in our house changed. It doesn't really fit the environment.
+Frig.
+The sine of theta equals the opposite over the hypotenuese.
+Did you know the developers spelt brazier as brazzier.
+What's a bagel? I don't know because I'm mormon
+
index bda8adcb6642decd7a089554d88b1583f814346b..4bfeac60c203b4b22f8a89cba605f469d3bf47d2 100644 (file)
--- a/brice.dat
+++ b/brice.dat
@@ -1,5 +1,5 @@
 2
-canSprint
-1
 canJump
 1
+canSprint
+1
index 934ede5f91222037f8e2d3a3d60a7a4911ac8703..4fa74d767e3d501ee18beced298b9921cfc422f8 100644 (file)
@@ -265,6 +265,8 @@ void strVectorSortAlpha(std::vector<std::string> *v);
 
 // reads the given file into a buffer and returns a pointer to the buffer
 const char *readFile(const char *path);
+std::string readFile(const std::string& path);
+std::vector<std::string> readFileA(const std::string& path);
 
 // aborts the program, printing the given error
 void UserError(std::string reason);
index ca4ef2b7a7473403867d5f628db5e1562fa88b82..5a8e19b96b12cf85af0f893c5b36da1b9f5ad907 100644 (file)
 #include <inventory.hpp>
 #include <texture.hpp>
 
+// local library includes
+#include <tinyxml2.h>
+using namespace tinyxml2;
+
 /* ----------------------------------------------------------------------------
 ** Structures section
 ** --------------------------------------------------------------------------*/
@@ -187,6 +191,10 @@ protected:
 
        // the max cooldown display
        float maxHitDuration;
+
+       // the entity's XML element, for saving/loading stuff
+       XMLElement *xmle;
+
 public:
        // contains the entity's coordinates, in pixels
        vec2 loc;
@@ -235,7 +243,7 @@ public:
        int     subtype;
 
        // the entity's name, randomly generated on spawn
-       char *name;
+       std::string name;
 
        // the entity's gender
        GENDER  gender;
@@ -289,6 +297,9 @@ public:
        // returns true if the coordinate is within the entity
        bool isInside(vec2 coord) const;
 
+       // constructs the entity with an XML thing-thang
+       virtual void createFromXML(XMLElement *e, World *w=nullptr) =0;
+
        // a common constructor, clears variables
        Entity(void);
 
@@ -296,7 +307,7 @@ public:
        virtual ~Entity(){}
 };
 
-class Player : public Entity{
+class Player : public Entity {
 public:
        Entity *ride;
        QuestHandler qh;
@@ -305,9 +316,10 @@ public:
        ~Player();
        void save(void);
        void sspawn(float x,float y);
+       void createFromXML(XMLElement *e, World *w);
 };
 
-class Structures : public Entity{
+class Structures : public Entity {
 public:
        BUILD_SUB bsubtype;
        World *inWorld;
@@ -318,6 +330,7 @@ public:
        ~Structures();
 
        unsigned int spawn(BUILD_SUB, float, float);
+       void createFromXML(XMLElement *e, World *w);
 };
 
 
@@ -340,6 +353,7 @@ public:
 
        virtual void interact();
        virtual void wander(int);
+       void createFromXML(XMLElement *e, World *w);
 };
 
 class Merchant : public NPC {
@@ -379,8 +393,9 @@ public:
        void interact(void);
 
        bool operator==(const Object &o) {
-               return !strcmp(name, o.name) && (loc == o.loc);
+               return (name == o.name) && (loc == o.loc);
        }
+       void createFromXML(XMLElement *e, World *w);
 };
 
 /**
@@ -414,6 +429,8 @@ public:
        void makeFlame(void){
                flame = true;
        }
+       
+       void createFromXML(XMLElement *e);
 };
 
 #include <mob.hpp>
index 4425159d7558d8c0c0f607c11e22b4556784742a..450cf69262d737e1a93c09d61b78d6c9cc5df8b0 100644 (file)
@@ -20,6 +20,7 @@ using Drop = std::tuple<std::string, unsigned int, float>;
 
 class Mob : public Entity {
 protected:
+       XMLElement *xmle;
        std::forward_list<Drop> drop;
 
     unsigned int actCounter;
@@ -41,7 +42,6 @@ public:
        virtual void onDeath(void);
 
     virtual bool bindTex(void) =0;
-    virtual void createFromXML(const XMLElement *e) =0;
 };
 
 constexpr Mob *Mobp(Entity *e) {
@@ -59,7 +59,7 @@ public:
     void act(void);
        void onHit(unsigned int);
     bool bindTex(void);
-    void createFromXML(const XMLElement *e);
+    void createFromXML(XMLElement *e, World *w) final;
 };
 
 class Door : public Mob {
@@ -69,7 +69,7 @@ public:
     void act(void);
        void onHit(unsigned int);
     bool bindTex(void);
-    void createFromXML(const XMLElement *e);
+    void createFromXML(XMLElement *e, World *w) final;
 };
 
 class Cat : public Mob {
@@ -79,7 +79,7 @@ public:
     void act(void);
        void onHit(unsigned int);
     bool bindTex(void);
-    void createFromXML(const XMLElement *e);
+       void createFromXML(XMLElement *e, World *w) final;
 };
 
 class Rabbit : public Mob {
@@ -89,7 +89,7 @@ public:
     void act(void);
        void onHit(unsigned int);
     bool bindTex(void);
-    void createFromXML(const XMLElement *e);
+    void createFromXML(XMLElement *e, World *w) final;
 };
 
 class Bird : public Mob {
@@ -101,7 +101,7 @@ public:
     void act(void);
        void onHit(unsigned int);
     bool bindTex(void);
-    void createFromXML(const XMLElement *e);
+    void createFromXML(XMLElement *e, World *w) final;
 };
 
 class Trigger : public Mob {
@@ -114,7 +114,7 @@ public:
     void act(void);
        void onHit(unsigned int);
     bool bindTex(void);
-    void createFromXML(const XMLElement *e);
+    void createFromXML(XMLElement *e, World *w) final;
 };
 
 #endif // MOB_H_
index ce50244175c2bd30b98cbd1decc39df6e77b2d66..f6a432de2900c17506c3240827ae628b117efec7 100644 (file)
@@ -15,7 +15,7 @@
  * This enum contains all different possibilities for world backgrounds; used
  * in World::setBackground() to select the appropriate images.
  */
-enum class WorldBGType : unsigned char {
+enum class WorldBGType : unsigned int {
        Forest,         /**< A forest theme. */
        WoodHouse       /**< An indoor wooden house theme. */
 };
@@ -465,14 +465,14 @@ public:
 
        void addMob(Mob *m, vec2 coord);
 
-       void addNPC(float x, float y);
+       void addNPC(NPC *n);
 
        void addObject(std::string in, std::string pickupDialog, float x, float y);
 
        void addParticle(float x, float y, float w, float h, float vx, float vy, Color color, int dur);
        void addParticle(float x, float y, float w, float h, float vx, float vy, Color color, int dur, unsigned char flags);
 
-       void addStructure(BUILD_SUB subtype, float x, float y, std::string tex, std::string inside);
+       void addStructure(Structures *s);
 
        Village *addVillage(std::string name, World *world);
 };
@@ -548,6 +548,12 @@ public:
        WorldSwitchInfo exitArena(Player *p);
 };
 
+/**
+ * Constructs an XML object for accessing/modifying the current world's XML
+ * file.
+ */
+const XMLDocument& loadWorldXML(void);
+
 /**
  * Loads the player into the world created by the given XML file. If a world is
  * already loaded it will be saved before the transition is made.
@@ -560,8 +566,16 @@ World *loadWorldFromXML(std::string path);
  */
 World *loadWorldFromXMLNoSave(std::string path);
 
+/**
+ * Loads a world using a pointer to the current world (used for loading adjacent
+ * worlds that have already been read into memory.
+ */
 World *loadWorldFromPtr(World *ptr);
 
+/**
+ * Casts a normal world to an indoor world, to access IndoorWorld-exclusive
+ * elements.
+ */
 constexpr IndoorWorld *Indoorp(World *w)
 {
     return (IndoorWorld *)w;
index 66cf12c4c5609cb57ab3ea142880945b64c1a79f..dc586df9b5d128c21268afa4740271e62d675c60 100644 (file)
--- a/main.cpp
+++ b/main.cpp
@@ -226,33 +226,38 @@ int main(int argc, char *argv[]){
        // load mouse texture, and other inventory textures
        mouseTex = Texture::loadTexture("assets/mouse.png");
 
-       // read in all XML file names in the folder
-       std::vector<std::string> xmlFiles;
+       // spawn the player
+       player = new Player();
+       player->sspawn(0,100);
+
+       // get a world
        if (xmlFolder.empty())
                xmlFolder = "xml/";
-       if (getdir(std::string("./" + xmlFolder).c_str(), xmlFiles))
-               UserError("Error reading XML files!!!");
-
-       // alphabetically sort files
-       strVectorSortAlpha(&xmlFiles);
-
-       // load the first valid XML file for the world
-       for (const auto &xf : xmlFiles) {
-               if (xf[0] != '.' && strcmp(&xf[xf.size() - 3], "dat")){
-                       // read it in
-                       std::cout << "File to load: " << xf << '\n';
-                       currentWorld = loadWorldFromXML(xf);
-                       break;
+
+       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!!!");
+
+               // alphabetically sort files
+               strVectorSortAlpha(&xmlFiles);
+
+               // load the first valid XML file for the world
+               for (const auto &xf : xmlFiles) {
+                       if (xf[0] != '.' && strcmp(&xf[xf.size() - 3], "dat")){
+                               // read it in
+                               std::cout << "File to load: " << xf << '\n';
+                               currentWorld = loadWorldFromXML(xf);
+                               break;
+                       }
                }
        }
 
        // make sure the world was made
-       if (currentWorld == NULL)
+       if (currentWorld == nullptr)
                UserError("Plot twist: The world never existed...?");
 
-       // spawn the player
-       player = new Player();
-       player->sspawn(0,100);
        ui::menu::init();
        currentWorld->bgmPlay(nullptr);
 
@@ -385,7 +390,7 @@ void render() {
         * Call the world's draw function, drawing the player, the world, the background, and entities. Also
         * draw the player's inventory if it exists.
         */
-       //player->near = true; // allow player's name to be drawn
+       player->near = true; // allow player's name to be drawn
        currentWorld->draw(player);
 
        // draw the player's inventory
index c643174d6eeae38803e23e124f76a1aeb7dca5a4..bb1ad1ee1f5df24adaac09180f07940863086411 100644 (file)
@@ -174,6 +174,39 @@ const char *readFile(const char *path)
        return buf;
 }
 
+std::string readFile(const std::string& path)
+{
+       std::ifstream in (path, std::ios::in);
+       std::string buffer;
+
+       if (!in.is_open())
+               UserError("Error reading file " + path);
+
+       in.seekg(0, in.end);
+       buffer.reserve(in.tellg());
+       in.seekg(0, in.beg);
+       in.read(&buffer[0], buffer.size());
+
+       in.close();
+       return buffer;
+}
+
+std::vector<std::string> readFileA(const std::string& path)
+{
+       std::ifstream in (path, std::ios::in);
+       std::vector<std::string> lines;
+       std::string line;
+
+       if (!in.is_open())
+               UserError("Error reading file " + path);
+
+       while(std::getline(in, line))
+               lines.push_back(line);
+
+       in.close();
+       return lines;
+}
+
 void UserError(std::string reason)
 {
     std::cout << "User error: " << reason << "!\n";
index 550748a583b88bbbc94044966815ad031f0c0e99..18c91ed6671a51639d041c5ab01dc5126c222056 100644 (file)
@@ -15,6 +15,7 @@ extern World *currentWorld;           // main.cpp
 extern unsigned int loops;             // main.cpp
 
 extern std::string xmlFolder;
+extern XMLDocument currentXMLDoc;
 
 // a dynamic array of pointers to the NPC's that are being assigned the preloads
 std::vector<NPC *> aipreload;
@@ -24,52 +25,17 @@ const unsigned int PLAYER_INV_SIZE = 43;
 // the size of an NPC's inventory
 const unsigned int NPC_INV_SIZE = 3;
 
-static const unsigned int RAND_DIALOG_COUNT = 14;
-const char *randomDialog[RAND_DIALOG_COUNT] = {
-       "What a beautiful day it is.",
-       "Have you ever went fast? I have.",
-       "I heard if you complete a quest, you'll get a special reward.",
-       "How much wood could a woodchuck chuck if a woodchuck could chuck wood?",
-       "I don\'t think anyone has ever been able to climb up that hill.",
-       "If you ever see a hole in the ground, watch out; it could mean the end for you.",
-       "Did you know this game has over 5000 lines of code? I didn\'t. I didn't even know I was in a game until now...",
-       "HELP MY CAPS LOCK IS STUCK",
-       "You know, if anyone ever asked me who I wanted to be when I grow up, I would say Abby Ross.",
-       "I want to have the wallpaper in our house changed. It doesn\'t really fit the environment.",
-       "Frig.",
-       "The sine of theta equals the opposite over the hdaypotenuese.",
-       "Did you know the developers spelt brazier as brazzier.",
-       "What's a bagel? I don't know because I'm mormon"
-};
-
-void randGetomName(Entity *e)
-{
-       unsigned int tempNum,max=0;
-       char *bufs;
-
-       std::ifstream names ("assets/names_en-us",std::ios::in);
-
-       names.seekg(0,names.beg);
-
-       bufs = new char[32];
-
-       for(;!names.eof();max++)
-               names.getline(bufs,32);
+static std::vector<std::string> randomDialog (readFileA("assets/dialog_en-us"));
 
-       tempNum = rand() % max;
-       names.seekg(0,names.beg);
-
-       for(unsigned int i=0;i<tempNum;i++)
-               names.getline(bufs,32);
-
-       names.close();
+void getRandomName(Entity *e)
+{
+       auto names = readFileA("assets/names_en-us");
+       auto name = names[randGet() % names.size()];
 
        // gender is a binary construct
-       e->gender = (bufs[0] == 'm') ? MALE : FEMALE;
-
-       strcpy(e->name, bufs + 1);
+       e->gender = (name[0] == 'm') ? MALE : FEMALE;
 
-       delete[] bufs;
+       e->name = &name[1];
 }
 
 Entity::Entity(void)
@@ -101,7 +67,6 @@ Entity::Entity(void)
        hitDuration = maxHitDuration = 0;
 
        inv = nullptr;
-       name = nullptr;
 }
 
 // spawns the entity you pass to it based off of coords and global entity settings
@@ -114,11 +79,10 @@ void Entity::spawn(float x, float y)
                health = maxHealth = 1;
 
        // generate a name
-       name = new char[32];
        if (type == MOBT)
-               strncpy(name, "mob", 3);
+               name = "mob";
        else
-               randGetomName(this);
+               getRandomName(this);
 
        setCooldown(0);
 }
@@ -168,6 +132,11 @@ void Entity::die(void)
 {
        alive = false;
        health = 0;
+
+       if (xmle) {
+               xmle->SetAttribute("alive", false);
+               currentXMLDoc.SaveFile(currentXML.c_str(), false);
+       }
 }
 
 bool Entity::isAlive(void) const
@@ -218,7 +187,12 @@ Player::Player() : Entity()
 Player::~Player()
 {
        delete inv;
-       delete[] name;
+}
+
+void Player::createFromXML(XMLElement *e, World *w=nullptr)
+{
+       (void)e;
+       (void)w;
 }
 
 NPC::NPC() : Entity()
@@ -237,7 +211,7 @@ NPC::NPC() : Entity()
        tex = TextureIterator({"assets/NPC.png"});
        inv = new Inventory(NPC_INV_SIZE);
 
-       randDialog = rand() % RAND_DIALOG_COUNT - 1;
+       randDialog = randGet() % randomDialog.size();
        dialogIndex = 0;
        dialogCount = 0;
 
@@ -249,7 +223,42 @@ NPC::NPC() : Entity()
 NPC::~NPC()
 {
        delete inv;
-       delete[] name;
+}
+
+void NPC::createFromXML(XMLElement *e, World *w=nullptr)
+{
+       std::string npcname;
+       bool dialog;
+       float spawnx, Xhealth;
+       unsigned int flooor;
+
+    // spawn at coordinates if desired
+       if (e->QueryFloatAttribute("x", &spawnx) == XML_NO_ERROR)
+               spawn(spawnx, 100);
+       else
+               spawn(0, 100);
+
+    // name override
+       if (!(npcname = e->StrAttribute("name")).empty())
+               name = npcname;
+
+    // dialog enabling
+       dialog = false;
+       if (e->QueryBoolAttribute("hasDialog", &dialog) == XML_NO_ERROR && dialog)
+               addAIFunc(false);
+       else
+        dialogIndex = 9999;
+
+
+    if (/*Indoor && */e->QueryUnsignedAttribute("floor", &flooor) == XML_NO_ERROR)
+        Indoorp(w)->moveToFloor(this, flooor);
+
+    // custom health value
+    if (e->QueryFloatAttribute("health", &Xhealth) == XML_NO_ERROR) {
+        health = maxHealth = Xhealth;
+       }
+
+       xmle = e;
 }
 
 Merchant::Merchant() : NPC()
@@ -283,8 +292,6 @@ Merchant::Merchant() : NPC()
 
 Merchant::~Merchant()
 {
-       //delete inv;
-       delete[] name;
 }
 
 Structures::Structures() : Entity()
@@ -295,7 +302,19 @@ Structures::Structures() : Entity()
 
 Structures::~Structures()
 {
-       delete[] name;
+}
+
+void Structures::createFromXML(XMLElement *e, World *w)
+{
+       float spawnx;
+
+       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),
+             100);
 }
 
 Object::Object()
@@ -319,7 +338,12 @@ Object::Object(std::string in, std::string pd)
 
 Object::~Object()
 {
-       delete[] name;
+}
+
+void Object::createFromXML(XMLElement *e, World *w=nullptr)
+{      
+       (void)e;
+       (void)w;
 }
 
 void Object::reloadTexture(void)
@@ -773,7 +797,7 @@ void Merchant::wander(int timeRun) {
 
 void Merchant::interact() {
        std::thread([this]{
-               ui::merchantBox(name, trade[currTrade], ":Accept:Good-Bye", false, toSay->c_str());
+               ui::merchantBox(name.c_str(), trade[currTrade], ":Accept:Good-Bye", false, toSay->c_str());
                ui::waitForDialog();
 
                // handle normal dialog options
index d6df3fd8071b26d40fcaf4c1ecba74eb1fe2646d..526d7b102808e4bc383526f45153376957444806 100644 (file)
@@ -10,6 +10,7 @@ Mob::Mob(void)
     type = MOBT;
        inv = nullptr;
     rider = nullptr;
+       xmle = nullptr;
     canMove = true;
        loc = 0;
 }
@@ -53,8 +54,9 @@ bool Page::bindTex(void)
     return true;
 }
 
-void Page::createFromXML(const XMLElement *e)
+void Page::createFromXML(XMLElement *e, World *w=nullptr)
 {
+       (void)w;
     float Xlocx;
     if (e->QueryFloatAttribute("x", &Xlocx) == XML_NO_ERROR)
         loc.x = Xlocx;
@@ -91,8 +93,9 @@ bool Door::bindTex(void)
     return true;
 }
 
-void Door::createFromXML(const XMLElement *e)
+void Door::createFromXML(XMLElement *e, World *w=nullptr)
 {
+       (void)w;
     float Xlocx;
     if (e->QueryFloatAttribute("x", &Xlocx) == XML_NO_ERROR)
         loc.x = Xlocx;
@@ -148,8 +151,9 @@ bool Cat::bindTex(void)
     return true;
 }
 
-void Cat::createFromXML(const XMLElement *e)
+void Cat::createFromXML(XMLElement *e, World *w=nullptr)
 {
+       (void)w;
     float Xlocx;
     if (e->QueryFloatAttribute("x", &Xlocx) == XML_NO_ERROR)
         loc.x = Xlocx;
@@ -203,15 +207,19 @@ bool Rabbit::bindTex(void)
     return true;
 }
 
-void Rabbit::createFromXML(const XMLElement *e)
+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)
+    if (e->QueryBoolAttribute("aggressive", &aggressive) != XML_NO_ERROR) {
         aggressive = false;
+       }
+
+       xmle = e;
 }
 
 Bird::Bird(void) : Mob()
@@ -257,8 +265,9 @@ bool Bird::bindTex(void)
     return true;
 }
 
-void Bird::createFromXML(const XMLElement *e)
+void Bird::createFromXML(XMLElement *e, World *w=nullptr)
 {
+       (void)w;
     float Xlocx, Xhealth;
     if (e->QueryFloatAttribute("x", &Xlocx) == XML_NO_ERROR)
         loc.x = Xlocx;
@@ -333,8 +342,9 @@ bool Trigger::bindTex(void)
     return false;
 }
 
-void Trigger::createFromXML(const XMLElement *e)
+void Trigger::createFromXML(XMLElement *e, World *w=nullptr)
 {
+       (void)w;
     float Xlocx;
     if (e->QueryFloatAttribute("x", &Xlocx) == XML_NO_ERROR)
         loc.x = Xlocx;
@@ -344,7 +354,6 @@ void Trigger::createFromXML(const XMLElement *e)
 Mob::~Mob()
 {
        delete inv;
-       delete[] name;
 }
 
 extern World *currentWorld;
index 7ae444cb74b3f78c5811881aa783d8be22e87c04..5a7ada16d5fd2d787cead407a4ed86f9107b9b25 100644 (file)
@@ -1408,7 +1408,9 @@ EXIT:
                                        if (debug)
                                                posFlag ^= true;
                                        else {
-                                               currentWorld->addStructure(FIRE_PIT, player->loc.x, player->loc.y, "", "");
+                                               auto s = new Structures();
+                                               s->spawn(FIRE_PIT, player->loc.x, player->loc.y);
+                                               currentWorld->addStructure(s);
                                                currentWorld->addLight({player->loc.x + SCREEN_WIDTH/2, player->loc.y},{1.0f,1.0f,1.0f});
                                                //currentWorld->getLastLight()->follow(currentWorld->build.back());
                                                currentWorld->getLastLight()->makeFlame();
index 2ecccecd12e593e9716967762de74cb7bd290d6e..f13c3b7f7cc08b4670380309f5f62942f450975f 100644 (file)
@@ -8,6 +8,7 @@
 #include <algorithm>
 #include <sstream>
 #include <fstream>
+#include <memory>
 
 // local game headers
 #include <ui.hpp>
@@ -317,7 +318,7 @@ void World::drawBackgrounds(void)
        if (worldShade > 0) {
 
                auto xcoord = offset.x * 0.9f;
-               
+
                for (auto &s : star) {
                        *(si++) = s.x + xcoord;
                        *(si++) = s.y,
@@ -497,17 +498,17 @@ void World::draw(Player *p)
     pOffset = (offset.x + p->width / 2 - worldStart) / HLINE;
 
     // only draw world within player vision
-    iStart = static_cast<int>(fmax(pOffset - (SCREEN_WIDTH / 2 / HLINE) - GROUND_HILLINESS, 0));
+    iStart = std::clamp(static_cast<int>(pOffset - (SCREEN_WIDTH / 2 / HLINE) - GROUND_HILLINESS),
+                           0, static_cast<int>(lineCount));
        iEnd = std::clamp(static_cast<int>(pOffset + (SCREEN_WIDTH / 2 / HLINE)),
-                      static_cast<int>(GROUND_HILLINESS),
-                      static_cast<int>(worldData.size()));
+                      0, static_cast<int>(lineCount));
 
     // draw the dirt
     bgTex++;
     std::vector<std::pair<vec2,vec3>> c;
 
     for (int i = iStart; i < iEnd; i++) {
-        if (worldData[i].groundHeight <= 0) {
+        if (worldData[i].groundHeight <= 0) { // TODO holes (andy)
             worldData[i].groundHeight = GROUND_HEIGHT_MINIMUM - 1;
             glColor4ub(0, 0, 0, 255);
         } else {
@@ -1069,6 +1070,9 @@ getSTextureLocation(unsigned int index) const
 vec2 World::
 getStructurePos(int index)
 {
+       if (build.empty())
+               return vec2 {0, 0};
+
     if (index < 0)
         return build.back()->loc;
     else if ((unsigned)index >= build.size())
@@ -1431,13 +1435,9 @@ WorldSwitchInfo World::goInsideStructure(Player *p)
 }
 
 void World::
-addStructure(BUILD_SUB sub, float x,float y, std::string tex, std::string inside)
+addStructure(Structures *s)
 {
-       build.push_back(new Structures());
-       build.back()->inWorld = this;
-       build.back()->textureLoc = tex;
-       build.back()->spawn(sub, x, y);
-       build.back()->inside = inside;
+       build.push_back(s);
        entity.push_back(build.back());
 }
 
@@ -1457,11 +1457,9 @@ void World::addMob(Mob *m, vec2 coord)
 }
 
 void World::
-addNPC(float x, float y)
+addNPC(NPC *n)
 {
-       npc.push_back(new NPC());
-       npc.back()->spawn(x, y);
-
+       npc.push_back(n);
        entity.push_back(npc.back());
 }
 
@@ -1897,37 +1895,63 @@ World *loadWorldFromPtr(World *ptr)
 /**
  * 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;
+       XMLDocument *_currentXMLDoc;
+       std::string _currentXML,
+                   _currentXMLRaw;
+
        XMLElement *wxml;
        XMLElement *vil;
 
        World *tmp;
-       float spawnx, randx;
-       bool dialog,Indoor;
-    unsigned int flooor;
+       Entity *newEntity;
+       float spawnx;
+       bool Indoor;
 
        const char *ptr;
        std::string name, sptr;
 
     // no file? -> no world
     if (path.empty())
-        return NULL;
+        return nullptr;
 
-    currentXML = std::string(xmlFolder + path);
-       currentXMLDoc.LoadFile(currentXML.c_str());
+    _currentXML = xmlFolder + path;
+       _currentXMLRaw = readFile(_currentXML.c_str());
+
+       // create a temporary XMLDocument if this isn't the main world
+       if (!loadedLeft && !loadedRight)
+               _currentXMLDoc = &currentXMLDoc;
+       else
+               _currentXMLDoc = new XMLDocument();
+
+       // parse the file
+       if (_currentXMLDoc->Parse(_currentXMLRaw.data()) != XML_NO_ERROR)
+               UserError("XML Error: Failed to parse file (not your fault though..?)");
 
     // attempt to load a <World> tag
-       if ((wxml = currentXMLDoc.FirstChildElement("World"))) {
+       if ((wxml = _currentXMLDoc->FirstChildElement("World"))) {
                wxml = wxml->FirstChildElement();
-               vil = currentXMLDoc.FirstChildElement("World")->FirstChildElement("village");
+               vil = _currentXMLDoc->FirstChildElement("World")->FirstChildElement("village");
                tmp = new World();
         Indoor = false;
        }
 
     // attempt to load an <IndoorWorld> tag
-    else if ((wxml = currentXMLDoc.FirstChildElement("IndoorWorld"))) {
+    else if ((wxml = _currentXMLDoc->FirstChildElement("IndoorWorld"))) {
                wxml = wxml->FirstChildElement();
                vil = NULL;
                tmp = new IndoorWorld();
@@ -1936,10 +1960,11 @@ XMLDocument currentXMLDoc;
 
     // error: can't load a world...
     else
-        UserError("XML Error: Cannot find a <World> or <IndoorWorld> tag in " + currentXML + "!");
+        UserError("XML Error: Cannot find a <World> or <IndoorWorld> tag in " + _currentXML + "!");
 
     // iterate through world tags
        while (wxml) {
+               newEntity = nullptr;
                name = wxml->Name();
 
         // world linkage
@@ -1951,10 +1976,12 @@ XMLDocument currentXMLDoc;
 
                 // load the left world if it isn't
                 if (!loadedLeft) {
-                    loadedLeft = true;
+                    loadedRight = true;
                     currentWorldToLeft = loadWorldFromXMLNoSave(ptr);
-                    loadedLeft = false;
-                }
+                    loadedRight = false;
+                } else {
+                                       currentWorldToLeft = nullptr;
+                               }
                        }
 
             // links world to the right
@@ -1963,10 +1990,12 @@ XMLDocument currentXMLDoc;
 
                 // load the right world if it isn't
                 if (!loadedRight) {
-                    loadedRight = true;
+                                       loadedLeft = true;
                     currentWorldToRight = loadWorldFromXMLNoSave(ptr);
-                    loadedRight = false;
-                }
+                    loadedLeft = false;
+                               } else {
+                                       currentWorldToRight = nullptr;
+                               }
                        }
 
                        // tells what world is outside, if in a structure
@@ -1975,7 +2004,7 @@ XMLDocument currentXMLDoc;
 
             // error, invalid link tag
             else
-                UserError("XML Error: Invalid <link> tag in " + currentXML + "!");
+                UserError("XML Error: Invalid <link> tag in " + _currentXML + "!");
 
                }
 
@@ -1985,9 +2014,10 @@ XMLDocument currentXMLDoc;
                        tmp->setStyle(wxml->StrAttribute("folder"));
 
             // set background folder
-            if (wxml->QueryUnsignedAttribute("background", &flooor) != XML_NO_ERROR)
-                UserError("XML Error: No background given in <style> in " + currentXML + "!");
-                       tmp->setBackground((WorldBGType)flooor);
+                       unsigned int bgt;
+            if (wxml->QueryUnsignedAttribute("background", &bgt) != XML_NO_ERROR)
+                UserError("XML Error: No background given in <style> in " + _currentXML + "!");
+                       tmp->setBackground(static_cast<WorldBGType>(bgt));
 
             // set BGM file
             tmp->setBGM(wxml->StrAttribute("bgm"));
@@ -2000,112 +2030,99 @@ XMLDocument currentXMLDoc;
                                tmp->generate(wxml->UnsignedAttribute("width"));
             else {
                 if (Indoor)
-                    UserError("XML Error: <generation> tags can't be in <IndoorWorld> tags (in " + currentXML + ")!");
+                    UserError("XML Error: <generation> tags can't be in <IndoorWorld> tags (in " + _currentXML + ")!");
                 else
-                    UserError("XML Error: Invalid <generation> tag in " + currentXML + "!");
+                    UserError("XML Error: Invalid <generation> tag in " + _currentXML + "!");
             }
                }
 
         // mob creation
-         else if (name == "rabbit") {
-             tmp->addMob(new Rabbit(), vec2 {0, 0});
-             tmp->getLastMob()->createFromXML(wxml);
-         } else if (name == "bird") {
-             tmp->addMob(new Bird(), vec2 {0, 0});
-             tmp->getLastMob()->createFromXML(wxml);
-         } else if (name == "trigger") {
-             tmp->addMob(new Trigger(), vec2 {0, 0});
-             tmp->getLastMob()->createFromXML(wxml);
-         } else if (name == "door") {
-             tmp->addMob(new Door(), vec2 {0, 0});
-             tmp->getLastMob()->createFromXML(wxml);
-         } else if (name == "page") {
-             tmp->addMob(new Page(), vec2 {0, 0});
-             tmp->getLastMob()->createFromXML(wxml);
-         } else if (name == "cat") {
-             tmp->addMob(new Cat(), vec2 {0, 0});
-             tmp->getLastMob()->createFromXML(wxml);
-         }
+        else if (name == "rabbit") {
+            newEntity = new Rabbit();
+        } else if (name == "bird") {
+            newEntity = new Bird();
+        } else if (name == "trigger") {
+               newEntity = new Trigger();
+        } else if (name == "door") {
+            newEntity = new Door();
+        } else if (name == "page") {
+            newEntity = new Page();
+        } else if (name == "cat") {
+            newEntity = new Cat();
+        }
 
         // npc creation
         else if (name == "npc") {
-                       const char *npcname;
-
-            // spawn at coordinates if desired
-                       if (wxml->QueryFloatAttribute("x", &spawnx) == XML_NO_ERROR)
-                               tmp->addNPC(spawnx, 100);
-                       else
-                               tmp->addNPC(0, 100);
-
-            // name override
-                       if ((npcname = wxml->Attribute("name"))) {
-                delete[] tmp->npc.back()->name;
-                               tmp->npc.back()->name = new char[strlen(npcname) + 1];
-                               strcpy(tmp->npc.back()->name, npcname);
-                       }
-
-            // dialog enabling
-                       dialog = false;
-                       if (wxml->QueryBoolAttribute("hasDialog", &dialog) == XML_NO_ERROR && dialog) {
-                               tmp->npc.back()->addAIFunc(false);
-                       } else
-                tmp->npc.back()->dialogIndex = 9999;
-
-            if (Indoor && wxml->QueryUnsignedAttribute("floor", &flooor) == XML_NO_ERROR)
-                Indoorp(tmp)->moveToFloor(tmp->npc.back(), flooor);
-
-            // custom health value
-            if (wxml->QueryFloatAttribute("health", &spawnx) == XML_NO_ERROR)
-                tmp->npc.back()->health = tmp->npc.back()->maxHealth = spawnx;
+                       newEntity = new NPC();
                }
 
         // structure creation
         else if (name == "structure") {
-                       tmp->addStructure((BUILD_SUB) wxml->UnsignedAttribute("type"),
-                                                          wxml->QueryFloatAttribute("x", &spawnx) != XML_NO_ERROR ?
-                                                              randGet() % tmp->getTheWidth() / 2.0f : spawnx,
-                                                          100,
-                                                          wxml->StrAttribute("texture"),
-                                                          wxml->StrAttribute("inside")
-               );
-               } else if (name == "hill") {
+                       newEntity = new Structures();
+               }
+
+               // hill creation
+               else if (name == "hill") {
                        tmp->addHill(ivec2 { wxml->IntAttribute("peakx"), wxml->IntAttribute("peaky") }, wxml->UnsignedAttribute("width"));
-               } else if (name == "time") {
+               }
+               
+               // time setting
+               else if (name == "time") {
             game::time::setTickCount(std::stoi(wxml->GetText()));
-        } else if (Indoor && name == "floor") {
+        }
+               
+               // floor adding
+               else if (Indoor && name == "floor") {
             if (wxml->QueryFloatAttribute("start",&spawnx) == XML_NO_ERROR)
                 Indoorp(tmp)->addFloor(wxml->UnsignedAttribute("width"), spawnx);
             else
                 Indoorp(tmp)->addFloor(wxml->UnsignedAttribute("width"));
         }
 
+               if (newEntity != nullptr) {
+                       bool alive = true;
+                       if (wxml->QueryBoolAttribute("alive", &alive) != XML_NO_ERROR || alive) {
+                               newEntity->createFromXML(wxml, tmp);
+
+                               switch (newEntity->type) {
+                               case NPCT:
+                                       tmp->addNPC(dynamic_cast<NPC *>(newEntity));
+                                       break;
+                               case MOBT:
+                                       tmp->addMob(dynamic_cast<Mob *>(newEntity), vec2 {0, 0});
+                                       break;
+                               case STRUCTURET:
+                                       tmp->addStructure(dynamic_cast<Structures *>(newEntity));
+                                       break;
+                               default:
+                                       break;
+                               }
+                       }
+               }
+
         spawnx = 0;
                wxml = wxml->NextSiblingElement();
        }
 
        Village *vptr;
+       Structures *s;
 
        if (vil) {
                vptr = tmp->addVillage(vil->StrAttribute("name"), tmp);
                vil = vil->FirstChildElement();
        }
 
-       std::cout << currentXML << ' ' << tmp->build.size() << '\n';
-
        while(vil) {
                name = vil->Name();
-               randx = 0;
 
                /**
                 *      READS DATA ABOUT STRUCTURE CONTAINED IN VILLAGE
                 */
 
                if (name == "structure") {
-                       tmp->addStructure((BUILD_SUB)vil->UnsignedAttribute("type"),
-                                                          vil->QueryFloatAttribute("x", &spawnx) != XML_NO_ERROR ? randx : spawnx,
-                                                          100,
-                                                          vil->StrAttribute("texture"),
-                                                          vil->StrAttribute("inside"));
+                       s = new Structures();
+                       s->createFromXML(vil, tmp);
+                       tmp->addStructure(s);
                } else if (name == "stall") {
             sptr = vil->StrAttribute("type");
 
@@ -2113,23 +2130,17 @@ XMLDocument currentXMLDoc;
             if (sptr == "market") {
 
                 // create a structure and a merchant, and pair them
-                tmp->addStructure(STALL_MARKET,
-                                   vil->QueryFloatAttribute("x", &spawnx) != XML_NO_ERROR ? randx : spawnx,
-                                   100,
-                                                              vil->StrAttribute("texture"),
-                                                              vil->StrAttribute("inside")
-                   );
+                               s = new Structures();
+                               s->createFromXML(vil, tmp);
+                               tmp->addStructure(s);
                                tmp->addMerchant(0, 100, true);
             }
 
             // handle traders
             else if (sptr == "trader") {
-                               tmp->addStructure(STALL_TRADER,
-                                                              vil->QueryFloatAttribute("x", &spawnx) != XML_NO_ERROR ? randx : spawnx,
-                                                              100,
-                                                              vil->StrAttribute("texture"),
-                                                              vil->StrAttribute("inside")
-                   );
+                               s = new Structures();
+                               s->createFromXML(vil, tmp);
+                               tmp->addStructure(s);
                        }
 
             // loop through buy/sell/trade tags
@@ -2185,12 +2196,19 @@ XMLDocument currentXMLDoc;
                vil = vil->NextSiblingElement();
        }
 
-       std::ifstream dat (((std::string)currentXML + ".dat").data());
+       std::ifstream dat ((_currentXML + ".dat").data());
        if (dat.good()) {
                dat.close();
                tmp->load();
        }
 
+       if (!loadedLeft && !loadedRight) {
+               currentXML = _currentXML;
+               currentXMLRaw = _currentXMLRaw;
+       } else {
+               delete _currentXMLDoc;
+       }
+
        return tmp;
 }
 
index 7be0e08d4f8072dd155ee7fcd7b4dd140d391209..13fa3dba03731c318e97b2fdc29ee6fbc6ace463 100644 (file)
@@ -1,39 +1,33 @@
 <?xml version="1.0"?>
 <World>
-       <style background="0" bgm="assets/music/embark.wav" folder="assets/style/classic/" />
-       <generation type="Random" width="500" />
-       <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 />
-
-       <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" />
-
-       <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">
-                       <text>
-                               <greet>Welcome to Smithy's! What would you like to purchase today?</greet>
-                               <accept>Thanks!</accept>
-                               <deny>Come back with more money to get this item!</deny>
-                               <leave>Have a great day, and watch out for my rabbit Mr. Cuddles, he might try to attack you.</leave>
-                       </text>
-                       <trade quantity="420" item="Dank MayMay" quantity1="1" item1="Wood Sword"/>
-                       <trade quantity="666" item="Wood Sword" quantity1="420" item1="Dank MayMay"/>
-               </stall>
-       </village>
+    <style background="0" bgm="assets/music/embark.wav" folder="assets/style/classic/"/>
+    <generation type="Random" width="500"/>
+    <link right="playerSpawnHill2.xml"/>
+    <time>12000</time>
+    <hill peakx="0" peaky="1000" width="50"/>
+    <rabbit x="300" aggressive="false" health="100" alive="0"/>
+    <bird y="500"/>
+    <cat/>
+    <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"/>
+    <village name="Big Dave&apos;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">
+            <text>
+                <greet>Welcome to Smithy's! What would you like to purchase today?</greet>
+                <accept>Thanks!</accept>
+                <deny>Come back with more money to get this item!</deny>
+                <leave>Have a great day, and watch out for my rabbit Mr. Cuddles, he might try to attack you.</leave>
+            </text>
+            <trade quantity="420" item="Dank MayMay" quantity1="1" item1="Wood Sword"/>
+            <trade quantity="666" item="Wood Sword" quantity1="420" item1="Dank MayMay"/>
+        </stall>
+    </village>
 </World>
 
 <Trigger id="Test">It was a dark and stormy night...
@@ -42,49 +36,39 @@ And it wasn't stormy.
 ...</Trigger>
 
 <Dialog name="Ralph">
-
-       <text id="0" nextid="1">
+    <text id="0" nextid="1">
                Hello there! My name is Ralph.
-               <gotox>300</gotox>
-       </text>
-
-       <text id="1" nextid="2" call="Johnny" callid="0" pause="true" >
+                       <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" >
+    <text id="2">
                Niice.
-               <quest check="Your First Quest" fail="3" />
-       </text>
-
-       <text id="3">
+                       <quest check="Your First Quest" fail="3"/></text>
+    <text id="3">
                Go check out Johnny. He's cool.
        </text>
 </Dialog>
 
 <Dialog name="Johnny">
-       <text id="0" nextid="1" pause="true" >
+    <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>
-
-       <text id="1" nextid="1" pause="true" >
+    </text>
+    <text id="1" nextid="1" pause="true">
                Broooooooooooooo...
        </text>
 </Dialog>
 
 <Dialog name="Big Dave">
-       <text id="0" pause="true">
+    <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>