]> code.bitgloo.com Git - clyne/gamedev.git/commitdiff
cat is good
authorClyne Sullivan <tullivan99@gmail.com>
Thu, 20 Oct 2016 12:58:57 +0000 (08:58 -0400)
committerClyne Sullivan <tullivan99@gmail.com>
Thu, 20 Oct 2016 12:58:57 +0000 (08:58 -0400)
1  2 
include/entities.hpp.bak
main.cpp
src/engine.cpp
src/entities.cpp.bak

index 945e8c839db96737da9da699e8e10c528eaf8b02,0000000000000000000000000000000000000000..e460a279bb2f1c7aca574e7225152f8dd60e2e24
mode 100644,000000..100644
--- /dev/null
@@@ -1,541 -1,0 +1,542 @@@
 +/* ----------------------------------------------------------------------------
 +** The entity stuffs.
 +**
 +** Entities.
 +** --------------------------------------------------------------------------*/
 +#ifndef ENTITIES_H
 +#define ENTITIES_H
 +#define DEBUG
 +
 +/* ----------------------------------------------------------------------------
 +** Includes section
 +** --------------------------------------------------------------------------*/
 +
 +// local game includes
 +#include <common.hpp>
 +#include <quest.hpp>
 +#include <inventory.hpp>
 +#include <texture.hpp>
 +#include <save_util.hpp>
 +#include <coolarray.hpp>
 +
 +// local library includes
 +#include <tinyxml2.h>
 +using namespace tinyxml2;
 +
 +/* ----------------------------------------------------------------------------
 +** Structures section
 +** --------------------------------------------------------------------------*/
 +
 +/**
 + * An entity type enumerator for identifying entities.
 + */
 +enum _TYPE {
 +      UNKNOWNT = -999, /**< who knows? */
 +      OBJECTT = -2,    /**< an object (Object) */
 +      STRUCTURET,              /**< a structure (Structures *) */
 +      PLAYERT,                 /**< the player (Player *) */
 +      NPCT,                    /**< an NPC (NPC *) */
 +      MERCHT,                  /**< a merchant (Merchant *) */
 +      MOBT                     /**< A mob (Mob *) */
 +};
 +
 +/**
 + * An enumerator for entity gender.
 + */
 +enum GENDER{
 +      MALE,   /**< male */
 +      FEMALE  /**< female */
 +};
 +
 +/**
 + * An enumerator for strcture types.
 + * The subtype of a structure will affect how it is drawn and how it functions.
 + */
 +enum BUILD_SUB{
 +      TOWN_HALL = 0,          /**< a town hall */
 +      HOUSE,                          /**< a generic house */
 +      HOUSE2,                         /**< a generic house of a different style */
 +      HOUSE3,                         /**< a generic house of a different style */
 +      HOUSE4,                         /**< a generic house of a different style */
 +      FOUNTAIN,                       /**< a fountain, creates water particles */
 +      LAMP_POST,                      /**< a lamppost, creates light */
 +      FIRE_PIT,                       /**< a firepit, creates fire particles / light */
 +      STALL_MARKET = 70,      /**< a stall for a merchant */
 +      STALL_TRADER
 +};
 +
 +/**
 + * A structure for tracking potential trades between the player and a merchant.
 + */
 +struct Trade {
 +      // the names of the items up for trade
 +      std::string item[2];
 +      // how much of each item to trade
 +      int quantity[2];
 +
 +      // constructs a trade with the given values
 +      Trade(int qo, std::string o, int qt, std::string t) {
 +              item[0] = o;
 +              item[1] = t;
 +              quantity[0] = qo;
 +              quantity[1] = qt;
 +      }
 +
 +      // creates an empty trade item
 +      Trade(void) {
 +              item[0] = "";
 +              item[1] = "";
 +              quantity[0] = 0;
 +              quantity[1] = 0;
 +      }
 +};
 +typedef struct Trade Trade;
 +
 +/* ----------------------------------------------------------------------------
 +** Variables section
 +** --------------------------------------------------------------------------*/
 +
 +// the size of the player's inventory
 +extern const unsigned int PLAYER_INV_SIZE;
 +// the size of an NPC's inventory
 +extern const unsigned int NPC_INV_SIZE;
 +
 +/* ----------------------------------------------------------------------------
 +** Classes / function prototypes section
 +** --------------------------------------------------------------------------*/
 +
 +// a prototype of the world class, necessary for some function prototypes
 +class World;
 +class IndoorWorld;
 +
 +/**
 + * The light structure, used to store light coordinates and color.
 + */
 +
 +class Light{
 +public:
 +      vec2 loc;               /**< Light location */
 +      Color color;    /**< Light color */
 +      float radius;   /**< Light radius */
 +
 +      bool belongsTo;
 +      Entity *following;
 +
 +      bool flame;
 +      float fireFlicker;
 +      vec2 fireLoc;
 +      Light()
 +      {
 +              loc = vec2(0,0);
 +              color = Color(1.0, 1.0, 1.0);
 +              radius = 0;
 +
 +              belongsTo = false;
 +              following = nullptr;
 +
 +              flame = false;
 +      }
 +
 +      Light(vec2 l, float r, Color c)
 +      {
 +              loc = l;
 +              color = c;
 +              radius = r;
 +
 +              belongsTo = false;
 +              following = nullptr;
 +
 +              flame = false;
 +      }
 +
 +      void follow(Entity *f)
 +      {
 +              following = f;
 +              belongsTo = true;
 +      }
 +
 +      void makeFlame(void)
 +      {
 +              flame = true;
 +      }
 +
 +      void createFromXML(XMLElement *e);
 +};
 +
 +/**
 + * The entity class.
 + * This class contains common functions and variables for all types of
 + * entities, i.e. a common structure.
 + */
 +class Entity{
 +protected:
 +      // an incrementer for invincibility after a hit
 +      unsigned int hitCooldown;
 +
 +      // an incrementer for triggering change of movement with wander()
 +      int ticksToUse;
 +
 +      // entity handles an applied hit (sword) if set true
 +      bool forcedMove;
 +
 +      // if set false, entity will be destroyed
 +      bool alive;
 +
 +      // TODO
 +      float targetx;
 +
 +      // the cooldown display (red overlay)
 +      float hitDuration;
 +
 +      // 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;
 +      float z;
 +
 +      // contains the entity's velocity, in pixels
 +      vec2 vel;
 +
 +      // the entity's width, in pixels
 +      float width;
 +
 +      // the entity's height, in pixels
 +      float height;
 +
 +      // a speed multiplier, applied to velocity
 +      float speed;
 +
 +      // when true player may interact, and the entity's name will be drawn
 +      bool near;
 +
 +      // when true, the entity can move
 +      int canMove;
 +
 +      // tells direction entity is facing
 +      bool right, left;
 +
 +      // tells if the entity is from another world
 +      char outnabout;
 +
 +      // set to 1 if entity is on the ground, 0 if in the air
 +      unsigned char ground;
 +
 +      // the entity's inventory
 +      Inventory *inv;
 +
 +      // the entity's light
 +      Light light;
 +
 +      // the entity's health
 +      float health;
 +
 +      // the most health the entity can have
 +      float maxHealth;
 +
 +      // the type of the entity
 +      _TYPE type;
 +
 +      // the entity's subtype, if applicable
 +      int     subtype;
 +
 +      // the entity's name, randomly generated on spawn
 +      std::string name;
 +
 +      // the entity's gender
 +      GENDER  gender;
 +
 +      // a texture handler for the entity
 +      TextureIterator tex;
 +
 +      // draws the entity to the screen
 +      void draw(void);
 +
 +      // spawns the entity at the given coordinates
 +      void spawn(float, float);
 +
 +      // allows the entity to wander, according to what class is deriving this.
 +      virtual void wander(int){}
 +      virtual void wander(void){}
 +
 +      // allows the entity to interact with the player
 +      virtual void interact(void){}
 +
 +      // causes the entity to move to the given x coordinate
 +      void moveTo(float dest_x);
 +
 +      // causes the entity to follow the one provided
 +      void follow(Entity *e);
 +
 +      // causes the entity to take a player-inflicted hit
 +      void takeHit(unsigned int _health, unsigned int cooldown);
 +
 +      // returns the amount of cool down before next hit
 +      unsigned int coolDown();
 +
 +      // set the cool down
 +      void setCooldown(unsigned int c);
 +
 +      // handles hits if they've been taken
 +      void handleHits(void);
 +
 +      // insures that the entity is dead
 +      void die(void);
 +
 +      // checks if the entity is alive
 +      bool isAlive(void) const;
 +
 +      // checks if the entity is hit in some way
 +      bool isHit(void) const;
 +
 +      // returns true if this entity is near the one provided
 +      bool isNear(const Entity *e);
 +
 +      // 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;
 +      virtual void saveToXML(void) =0;
 +
 +/*    Entity
 +
 +      **
 +       * Forces the given entity to follow this one.
 +       *
 +      void lead(Entity *e, unsigned int how);
 +
 +      **
 +       * Attempts to break free from any following.
 +       *
 +      void unfollow(void);*/
 +
 +      // a common constructor, clears variables
 +      Entity(void);
 +
 +      // frees memory taken by the entity
 +      virtual ~Entity(){}
 +};
 +
 +class Player : public Entity {
 +public:
 +      Entity *ride;
 +      QuestHandler qh;
 +
 +      Player();
 +      ~Player();
 +      void save(void);
 +      void sspawn(float x,float y);
 +      void createFromXML(XMLElement *e, World *w);
 +      void saveToXML(void);
 +};
 +
 +class Structures : public Entity {
 +public:
 +      BUILD_SUB bsubtype;
 +      World *inWorld;
 +      World *insideWorld;
 +      std::string inside;
 +      std::string textureLoc;
 +
 +      GLuint insideTex;
 +
 +      Structures();
 +      ~Structures();
 +
 +      unsigned int spawn(BUILD_SUB, float, float);
 +      void createFromXML(XMLElement *e, World *w);
 +      void saveToXML(void);
 +};
 +
 +
 +class NPC : public Entity {
 +private:
 +      // the number of the random dialog to use
 +      unsigned int randDialog;
 +
 +      unsigned int dialogCount;
 +
 +public:
 +      int dialogIndex;
 +
 +      NPC();
 +      ~NPC();
 +
 +      void drawThingy(void) const;
 +
 +      void addAIFunc(bool preload);
 +
 +      void interact();
 +      void wander(int);
 +      void createFromXML(XMLElement *e, World *w);
 +      void saveToXML(void);
 +};
 +
 +class Merchant : public NPC {
 +public:
 +      std::vector<Trade>trade;
 +      uint currTrade;
 +
 +      std::string text[4];
 +      std::string *toSay;
 +      //greeting
 +      //accept
 +      //deny
 +      //farewell
 +
 +      void interact();
 +      Structures *inside;
 +
 +      Merchant();
 +      ~Merchant();
 +
 +      void wander(int);
 +      void saveToXML(void);
 +};
 +
 +class Object : public Entity{
 +public:
 +      std::string iname;
 +      std::string pickupDialog;
 +      bool questObject = false;
 +
 +      Object();
 +      Object(std::string in,std::string pd);
 +      ~Object();
 +
 +      void reloadTexture(void);
 +
 +      void interact(void);
 +
 +      bool operator==(const Object &o) {
 +              return (name == o.name) && (loc == o.loc);
 +      }
 +      void createFromXML(XMLElement *e, World *w);
 +      void saveToXML(void);
 +};
 +
 +/**
 + * The particle class, handles a single particle.
 + */
 +class Particles{
 +public:
 +      // the location of the particle
 +      vec2 loc;
 +      float zOffset;
 +
 +      // the width of the particle, in pixels
 +      float width;
 +
 +      // the height of the particle, in pixels
 +      float height;
 +
 +      // the velocity of the particle, in pixels
 +      vec2 vel;
 +
 +      // the color of the particle
 +      Color color;
 +
 +      // TODO
 +      vec2 index;
 +
 +      // the amount of milliseconds left for the particle to live
 +      float duration;
 +
 +      // when true, the particle will move
 +      bool canMove;
 +
 +      // TODO
 +      bool fountain;
 +
 +      // when true, the particle will be affected by gravity
 +      bool gravity;
 +
 +      // when true, draws the particle behind structures
 +      bool behind;
 +
 +      // when true, the particle will bounce on impact with ground
 +      bool bounce;
 +
 +      Structures *stu;
 +
 +      Particles(void){}
 +
 +      // creates a particle with the desired characteristics
 +      Particles(float x, float y, float w, float h, float vx, float vy, Color c, float d);
 +
 +      // allows the particle to be destroyed
 +      ~Particles(void){}
 +
 +      // draws the particle
 +      void draw(GLfloat*& p) const;
 +
 +      // updates a particle
 +      void update(float _gravity, float ground_y);
 +
 +      // returns true if the particle should be killed
 +      bool timeUp(void);
 +};
 +
 +#include <mob.hpp>
 +
 +constexpr Object *Objectp(Entity *e) {
 +      return (Object *)e;
 +}
 +
 +constexpr NPC *NPCp(Entity *e) {
 +      return (NPC *)e;
 +}
 +
 +constexpr Structures *Structurep(Entity *e) {
 +      return (Structures *)e;
 +}
 +
 +constexpr Merchant *Merchantp(Entity *e) {
 +      return (Merchant *)e;
 +}
 +
 +#include <entityx/entityx.h>
 +#include <events.hpp>
 +
 +class PlayerSystem : public entityx::System<PlayerSystem>, public entityx::Receiver<PlayerSystem> {
 +private:
 +      Player **m_Player;
 +      bool m_MoveLeft, m_MoveRight;
 +
 +public:
 +      PlayerSystem(Player **p)
 +              : m_Player(p), m_MoveLeft(false), m_MoveRight(false) {}
 +
 +      void update(entityx::EntityManager &en, entityx::EventManager &ev, entityx::TimeDelta dt) override;
 +
 +      void configure(entityx::EventManager &ev);
 +      void receive(const KeyDownEvent &kde);
 +      void receive(const KeyUpEvent &kue);
 +};
 +
++void entityxTest();
 +
 +#endif // ENTITIES_H
 +
 +/**
 +ENTITY TYPES
 +-1 STRUCTURES
 +|->1 Village
 +|->2 Castle
 +|
 +0 PLAYERS
 +|->Player
 +|
 +1 NPCS
 +|->0 Base
 +|->1 Merchant
 +|
 +2 MOBS
 +|->1 Rabbit
 +|->2 Bird
 +**/
diff --cc main.cpp
index 9fa7a55ffb4f975ee72ceb784b2cbda4bcbc646c,85af92531cb930cda3e2651be56132f5245411fb..4b579b25ee88a5c249ee6f6c75efa8697de12f5c
+++ b/main.cpp
@@@ -199,9 -212,24 +199,12 @@@ int main(int argc, char *argv[]
                }
        }
  
 -      // make sure the world was made
 -      if (currentWorld == nullptr)
 -              UserError("Plot twist: The world never existed...?");
 -
        ui::menu::init();
 -      game::events.emit<BGMToggleEvent>(currentWorld->bgm);
 -
 -      game::engine.getSystem<WorldSystem>()->setWorld(currentWorld);
 +//    game::events.emit<BGMToggleEvent>(currentWorld->bgm);
  
 -      // spawn the arena
 -      arena = new Arena();
 -      arena->setStyle("");
 -      arena->setBackground(WorldBGType::Forest);
 -      arena->bgm = "assets/music/embark.wav";
 -
+       //TODO
+       entityxTest();
        // the main loop, in all of its gloriousness..
        std::thread([&]{
                while (game::engine.shouldRun()) {
diff --cc src/engine.cpp
index 3d498d3c193aa40b3fd737deeaee865522302418,3705d4f857015dd8b47f70992c5fb4e472dba6cd..e53a68844acdd1aa0ca077b73a5a7feec24e39a1
@@@ -3,8 -3,10 +3,9 @@@
  #include <config.hpp>
  #include <world.hpp>
  #include <ui.hpp>
 -#include <inventory.hpp>
 -#include <entities.hpp>
 +//#include <inventory.hpp>
  #include <window.hpp>
+ #include <components.hpp>
  
  extern World *currentWorld;
  
@@@ -18,10 -20,12 +19,12 @@@ void Engine::init(void) 
      game::events.subscribe<GameEndEvent>(*this);
  
      systems.add<WindowSystem>();
-     systems.add<InputSystem>();
+     systems.add<RenderSystem>();
+       systems.add<InputSystem>();
 -    systems.add<InventorySystem>();
 +//    systems.add<InventorySystem>();
      systems.add<WorldSystem>();
 -    systems.add<PlayerSystem>(&player);
+       systems.add<MovementSystem>();  
 +//    systems.add<PlayerSystem>(&player);
  
      systems.configure();
  
@@@ -36,8 -42,9 +41,9 @@@ void Engine::render(entityx::TimeDelta 
  void Engine::update(entityx::TimeDelta dt)
  {
      systems.update<InputSystem>(dt);
 -    systems.update<InventorySystem>(dt);
 -    systems.update<PlayerSystem>(dt);
 +//    systems.update<InventorySystem>(dt);
 +//    systems.update<PlayerSystem>(dt);
+       systems.update<MovementSystem>(dt);
        systems.update<WorldSystem>(dt);
  }
  
index e005df5b04d61e30d76bbf75f59eafd53d2b4c8e,0000000000000000000000000000000000000000..25dd37957895cda79fdb788e27d5c3b408445abd
mode 100644,000000..100644
--- /dev/null
@@@ -1,1352 -1,0 +1,1371 @@@
 +#include <entities.hpp>
 +
 +#include <istream>
 +#include <sstream>
 +#include <fstream>
 +
 +#include <ui.hpp>
 +#include <world.hpp>
 +#include <gametime.hpp>
 +#include <brice.hpp>
 +
 +#include <render.hpp>
 +#include <engine.hpp>
 +
 +///NEW
 +#include <components.hpp>
 +#include <entityx/entityx.h>
 +///OLD
 +
 +extern std::istream *names;
 +
 +extern Player *player;                        // main.cpp
 +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;
 +
 +// the size of the player's inventory
 +const unsigned int PLAYER_INV_SIZE = 43;
 +// the size of an NPC's inventory
 +const unsigned int NPC_INV_SIZE = 3;
 +
 +static std::vector<std::string> randomDialog (readFileA("assets/dialog_en-us"));
 +
 +
 +void PlayerSystem::update(entityx::EntityManager &en, entityx::EventManager &ev, entityx::TimeDelta dt)
 +{
 +      (void)en;
 +      (void)ev;
 +      (void)dt;
 +
 +      if (!m_MoveLeft && !m_MoveRight)
 +              (*m_Player)->vel.x = 0;
 +}
 +
 +void PlayerSystem::configure(entityx::EventManager &ev)
 +{
 +      ev.subscribe<KeyDownEvent>(*this);
 +      ev.subscribe<KeyUpEvent>(*this);
 +}
 +
 +extern World  *currentWorldToLeft;
 +extern World  *currentWorldToRight;
 +extern bool gameRunning;
 +extern bool inBattle;
 +
 +void PlayerSystem::receive(const KeyUpEvent &kue)
 +{
 +      auto p = *m_Player;
 +      auto kc = kue.keycode;
 +
 +      if (kc == SDLK_ESCAPE) {
 +              ui::menu::toggle();
 +              p->save();
 +      } else if (kc == getControl(1)) {
 +              m_MoveLeft = false;
 +      } else if (kc == getControl(2)) {
 +              m_MoveRight = false;
 +      } else if (kc == getControl(3) || kc == getControl(4)) {
 +              player->speed = 1;
 +      } else if (kc == getControl(5)) {
 +              if (p->inv->invHover) {
 +                      p->inv->invHover = false;
 +              } else {
 +                      if (!p->inv->selected)
 +                              p->inv->invOpening ^= true;
 +                      else
 +                              p->inv->selected = false;
 +
 +                      p->inv->mouseSel = false;
 +              }
 +
 +              // disable action ui
 +              ui::action::disable();
 +      }
 +}
 +
 +void PlayerSystem::receive(const KeyDownEvent &kde)
 +{
 +      auto p = *m_Player;
 +      auto kc = kde.keycode;
 +
 +      auto worldSwitch = [&](const WorldSwitchInfo& wsi){
 +              player->canMove = false;
 +              ui::toggleBlackFast();
 +              ui::waitForCover();
 +              game::events.emit<BGMToggleEvent>(wsi.first->bgm, wsi.first);
 +              std::tie(currentWorld, player->loc) = wsi; // using p causes segfault
 +              game::engine.getSystem<WorldSystem>()->setWorld(currentWorld);
 +              ui::toggleBlackFast();
 +              ui::waitForUncover();
 +              player->canMove = true; // using p causes segfault
 +      };
 +
 +      if ((kc == SDLK_SPACE) && (game::canJump & p->ground)) {
 +              p->loc.y += HLINES(2);
 +              p->vel.y = .4;
 +              p->ground = false;
 +      }
 +
 +      if (!ui::dialogBoxExists || ui::dialogPassive) {
 +              if (kc == getControl(0)) {
 +                      if (inBattle) {
 +                              std::thread([&](void){
 +                                      auto thing = dynamic_cast<Arena *>(currentWorld)->exitArena(p);
 +                                      if (thing.first != currentWorld)
 +                                              worldSwitch(thing);
 +                              }).detach();
 +                      } else if (!ui::fadeIntensity) {
 +                              std::thread([&](void){
 +                                      auto thing = currentWorld->goInsideStructure(p);
 +                                      if (thing.first != currentWorld)
 +                                              worldSwitch(thing);
 +                              }).detach();
 +                      }
 +              } else if (kc == getControl(1)) {
 +                      if (!ui::fadeEnable) {
 +                              p->vel.x = -PLAYER_SPEED_CONSTANT;
 +                              if (std::stoi(game::getValue("Slow")) == 1)
 +                                      p->vel.x /= 2.0f;
 +                              p->left = m_MoveLeft = true;
 +                              p->right = m_MoveRight = false;
 +                              if (currentWorldToLeft) {
 +                                      std::thread([&](void){
 +                                              auto thing = currentWorld->goWorldLeft(p);
 +                                              if (thing.first != currentWorld)
 +                                                      worldSwitch(thing);
 +                                      }).detach();
 +                              }
 +                      }
 +              } else if (kc == getControl(2)) {
 +                      if (!ui::fadeEnable) {
 +                              p->vel.x = PLAYER_SPEED_CONSTANT;
 +                              if (std::stoi(game::getValue("Slow")) == 1)
 +                                      p->vel.x /= 2.0f;
 +                              p->right = m_MoveRight = true;
 +                              p->left = m_MoveLeft = false;
 +                              if (currentWorldToRight) {
 +                                      std::thread([&](void){
 +                                              auto thing = currentWorld->goWorldRight(p);
 +                                              if (thing.first != currentWorld)
 +                                                      worldSwitch(thing);
 +                                      }).detach();
 +                              }
 +                      }
 +              } else if (kc == getControl(3)) {
 +                      if (game::canSprint)
 +                              p->speed = 2.0f;
 +              } else if (kc == getControl(4)) {
 +                      p->speed = .5;
 +              } else if (kc == getControl(5)) {
 +                      /*static int heyOhLetsGo = 0;
 +
 +                      //edown = true;
 +
 +                      // start hover counter?
 +                      if (!heyOhLetsGo) {
 +                              heyOhLetsGo = game::time::getTickCount();
 +                              p->inv->mouseSel = false;
 +                      }
 +
 +                      // run hover thing
 +                      if (game::time::getTickCount() - heyOhLetsGo >= 2 && !(p->inv->invOpen) && !(p->inv->selected)) {
 +                              p->inv->invHover = true;
 +
 +                              // enable action ui
 +                              ui::action::enable();
 +                      }*/
 +              }
 +      } else if (kc == SDLK_DELETE) {
 +              game::endGame();
 +      } else if (kc == SDLK_t) {
 +              game::time::tick(50);
 +      }
 +}
 +
 +
 +void getRandomName(Entity *e)
 +{
 +      auto names = readFileA("assets/names_en-us");
 +      auto name = names[randGet() % names.size()];
 +
 +      // gender is a binary construct
 +      e->gender = (name[0] == 'm') ? MALE : FEMALE;
 +
 +      e->name = &name[1];
 +}
 +
 +Entity::Entity(void)
 +{
 +      vel = 0;
 +      width = 0;
 +      height = 0;
 +      health = 0;
 +      maxHealth = 0;
 +      outnabout = 0;
 +      targetx = 0.9112001f;
 +
 +      type = UNKNOWNT;
 +
 +      // set flags
 +      alive      = true;
 +      right      = true;
 +      left       = false;
 +      near       = false;
 +      canMove    = true;
 +      ground     = false;
 +      forcedMove = false;
 +      z = 0.0f;
 +
 +      // clear counters
 +      ticksToUse = 0;
 +      hitCooldown = 0;
 +
 +      hitDuration = maxHitDuration = 0;
 +
 +      inv = nullptr;
 +}
 +
 +// spawns the entity you pass to it based off of coords and global entity settings
 +void Entity::spawn(float x, float y)
 +{
 +      loc.x = x;
 +      loc.y = y;
 +
 +      if (health == 0 && maxHealth == 0)
 +              health = maxHealth = 1;
 +
 +      // generate a name
 +      if (type == MOBT)
 +              name = "mob";
 +      else
 +              getRandomName(this);
 +
 +      setCooldown(0);
 +}
 +
 +void Entity::takeHit(unsigned int _health, unsigned int cooldown)
 +{
 +      if (hitCooldown <= 1) {
 +              // modify variables
 +              health = fmax(health - _health, 0);
 +              forcedMove = true;
 +              hitCooldown = cooldown;
 +
 +              hitDuration = maxHitDuration = 350.0f;
 +
 +              // pushback
 +              vel.x = player->left ? -0.5f : 0.5f;
 +              vel.y = 0.2f;
 +      }
 +}
 +
 +unsigned int Entity::coolDown()
 +{
 +      return hitCooldown;
 +}
 +
 +void Entity::setCooldown(unsigned int c)
 +{
 +      hitCooldown = c;
 +}
 +
 +void Entity::handleHits(void)
 +{
 +      hitCooldown = fmax(static_cast<int>(hitCooldown - game::time::getDeltaTime()), 0);
 +      hitDuration = fmax(hitDuration - game::time::getDeltaTime(), 0);
 +
 +      if (!forcedMove)
 +              return;
 +
 +      // reduce knockback
 +      if ((vel.x > 0.0005f) || (vel.x < -0.0005f))
 +              vel.x *= 0.6f;
 +      else
 +              forcedMove = false;
 +}
 +
 +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
 +{
 +      return alive;
 +}
 +
 +bool Entity::isHit(void) const
 +{
 +      return forcedMove;
 +}
 +
 +void Entity::moveTo(float dest_x)
 +{
 +      targetx = dest_x;
 +}
 +
 +Player::Player() : Entity()
 +{
 +      width = HLINES(10);
 +      height = HLINES(16);
 +
 +      type = PLAYERT; //set type to player
 +      subtype = 0;
 +      health = maxHealth = 100;
 +      speed = 1;
 +      canMove = true;
 +
 +      tex = TextureIterator({"assets/player/playerk.png",
 +                                                 "assets/player/playerk1.png",
 +                                                 "assets/player/playerk2.png",
 +                                                 "assets/player/playerk3.png",
 +                                                 "assets/player/playerk4.png",
 +                                                 "assets/player/playerk5.png",
 +                                                 "assets/player/playerk6.png",
 +                                                 "assets/player/playerk7.png",
 +                                                 "assets/player/playerk8.png"
 +                                             });
 +
 +      inv = new Inventory(PLAYER_INV_SIZE);
 +      dim2 tmpDim = Texture::imageDim(tex.getTexturePath(0));
 +      width = HLINES(tmpDim.x/2);
 +      height = HLINES(tmpDim.y/2);
 +
 +      z = -2.0;
 +}
 +
 +Player::~Player()
 +{
 +      delete inv;
 +      delete &tex;
 +}
 +
 +void Player::createFromXML(XMLElement *e, World *w=nullptr)
 +{
 +      (void)e;
 +      (void)w;
 +}
 +
 +void Player::saveToXML(void)
 +{}
 +
 +NPC::NPC() : Entity()
 +{
 +      width = HLINES(10);
 +      height = HLINES(16);
 +
 +      type    = NPCT; //sets type to npc
 +      subtype = 0;
 +
 +      health = maxHealth = 100;
 +
 +      maxHealth = health = 100;
 +      canMove = true;
 +
 +      tex = TextureIterator({"assets/NPC.png"});
 +      inv = new Inventory(NPC_INV_SIZE);
 +
 +      randDialog = randGet() % randomDialog.size();
 +      dialogIndex = 0;
 +      dialogCount = 0;
 +
 +      dim2 tmpDim = Texture::imageDim(tex.getTexturePath(0));
 +      width = HLINES(tmpDim.x/2);
 +      height = HLINES(tmpDim.y/2);
 +}
 +
 +NPC::~NPC()
 +{
 +      delete inv;
 +}
 +
 +void NPC::createFromXML(XMLElement *e, World *w=nullptr)
 +{
 +      std::string npcname;
 +      bool dialog;
 +      unsigned int flooor;
 +
 +      xmle = e;
 +      (void)w;
 +
 +    // spawn at coordinates if desired
 +      E_LOAD_COORDS(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;
 +
 +    // custom health value
 +      E_LOAD_HEALTH;
 +
 +      // movemenet
 +      if (e->QueryBoolAttribute("canMove", &dialog) == XML_NO_ERROR)
 +              canMove = dialog;
 +
 +      // 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()
 +{
 +      width = HLINES(10);
 +      height = HLINES(16);
 +
 +      type    = MERCHT; //sets type to merchant
 +      subtype = 0;
 +
 +      health = maxHealth = 100;
 +
 +      canMove = true;
 +
 +      trade.reserve(100);
 +      currTrade = 0;
 +
 +      inside = nullptr;
 +
 +      //tex = new Texturec(1,"assets/NPC.png");
 +      //inv = new Inventory(NPC_INV_SIZE);
 +      //inv = new Inventory(1);
 +
 +      //randDialog = rand() % RAND_DIALOG_COUNT - 1;
 +      dialogIndex = 0;
 +
 +      dim2 tmpDim = Texture::imageDim(tex.getTexturePath(0));
 +      width = HLINES(tmpDim.x/2);
 +      height = HLINES(tmpDim.y/2);
 +}
 +
 +Merchant::~Merchant()
 +{
 +}
 +
 +void Merchant::saveToXML(void){}
 +
 +Structures::Structures() : Entity()
 +{
 +      type = STRUCTURET;
 +      canMove = false;
 +      health = maxHealth = 1;
 +}
 +
 +Structures::~Structures()
 +{
 +}
 +
 +extern std::string currentXMLRaw;
 +
 +void Structures::createFromXML(XMLElement *e, World *w)
 +{
 +      float spawnx;
 +
 +      if (e->QueryBoolAttribute("alive", &alive) == XML_NO_ERROR && !alive) {
 +              //die();
 +              return;
 +      }
 +
 +      inWorld = w;
 +      inside = e->StrAttribute("inside");
 +
 +      // edge
 +      if (!inside.empty()) {
 +              insideWorld = loadWorldFromXMLNoTakeover(inside);
 +      }
 +
 +      textureLoc = e->StrAttribute("texture");
 +
 +      insideTex = Texture::loadTexture(e->StrAttribute("insideTexture"));
 +
 +      spawn(static_cast<BUILD_SUB>(e->UnsignedAttribute("type")),
 +            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()
 +{
 +      type = OBJECTT;
 +}
 +
 +Object::Object(std::string in, std::string pd)
 +{
 +      iname = in;
 +
 +      pickupDialog = pd;
 +      questObject = !pd.empty();
 +
 +      type = OBJECTT;
 +      width  = getItemWidth(in);
 +      height = getItemHeight(in);
 +
 +      tex = TextureIterator({getItemTexturePath(in)});
 +}
 +
 +Object::~Object()
 +{
 +}
 +
 +void Object::createFromXML(XMLElement *e, World *w=nullptr)
 +{
 +      (void)e;
 +      (void)w;
 +}
 +
 +void Object::saveToXML(void)
 +{}
 +
 +void Object::reloadTexture(void)
 +{
 +      tex = TextureIterator({getItemTexturePath(iname)});
 +      width  = getItemWidth(iname);
 +      height = getItemHeight(iname);
 +}
 +
 +bool Entity::isNear(const Entity *e) {
 +      return (e != nullptr) ? (pow(e->loc.x - loc.x, 2) + pow(e->loc.y - loc.y, 2) <= pow(HLINES(40), 2)) : false;
 +}
 +
 +void NPC::drawThingy(void) const
 +{
 +      if (dialogCount) {
 +              const auto w = width / 3;
 +              GLfloat tex_coord[] = {
 +                      0, 0, 1, 0, 1, 1,
 +                      1, 1, 0, 1, 0, 0
 +              };
 +              const GLfloat c[4] = {
 +                      loc.x + w, loc.y + height, loc.x + w * 2, loc.y + height + w
 +              };
 +              GLfloat coords[] = {
 +                      c[0], c[1], z, c[2], c[1], z, c[2], c[3], z,
 +                      c[2], c[3], z, c[0], c[3], z, c[0], c[1], z
 +              };
 +
 +              // TODO use texture made for this
 +              static GLuint thingyColor = Texture::genColor(Color(236, 238, 15));
 +
 +              Render::worldShader.use();
 +              Render::worldShader.enable();
 +
 +              glBindTexture(GL_TEXTURE_2D, thingyColor);
 +
 +              glVertexAttribPointer(Render::worldShader.coord, 3, GL_FLOAT, GL_FALSE, 0, coords);
 +              glVertexAttribPointer(Render::worldShader.tex, 2, GL_FLOAT, GL_FALSE, 0, tex_coord);
 +              glDrawArrays(GL_TRIANGLES, 0, 6);
 +
 +              Render::worldShader.disable();
 +              Render::worldShader.unuse();
 +      }
 +}
 +
 +void Entity::draw(void)
 +{
 +      GLfloat tex_coord[] = {0.0, 0.0,
 +                                                 1.0, 0.0,
 +                                                 1.0, 1.0,
 +
 +                                                 1.0, 1.0,
 +                                                 0.0, 1.0,
 +                                                 0.0, 0.0};
 +
 +      GLfloat tex_coordL[] = {1.0, 0.0,
 +                                                      0.0, 0.0,
 +                                                      0.0, 1.0,
 +
 +                                                      0.0, 1.0,
 +                                                      1.0, 1.0,
 +                                                      1.0, 0.0};
 +
 +      GLfloat coords[] = {loc.x, loc.y, z,
 +                                              loc.x + width, loc.y, z,
 +                                              loc.x + width, loc.y + height, z,
 +
 +                                              loc.x + width, loc.y + height, z,
 +                                              loc.x, loc.y + height, z,
 +                                              loc.x, loc.y, z};
 +
 +
 +      glActiveTexture(GL_TEXTURE0);
 +
 +      if (!alive)
 +              return;
 +
 +      if (type == NPCT) {
 +              NPCp(this)->drawThingy();
 +
 +              if (gender == MALE)
 +                      glColor3ub(255, 255, 255);
 +              else if (gender == FEMALE)
 +                      glColor3ub(255, 105, 180);
 +      } else if (type == MOBT) {
 +              if (Mobp(this)->rider != nullptr) {
 +                      Mobp(this)->rider->loc.x = loc.x + width * 0.25f;
 +              Mobp(this)->rider->loc.y = loc.y + height - HLINES(5);
 +              Mobp(this)->rider->vel.y = .12;
 +                      Mobp(this)->rider->z     = z + 0.01;
 +          }
 +      }
 +      switch(type) {
 +      case PLAYERT:
 +              static int texState = 0;
 +              if (speed && !(game::time::getTickCount() % ((2.0f/speed) < 1 ? 1 : (int)((float)2.0f/(float)speed)))) {
 +                      if (++texState == 9)
 +                              texState = 1;
 +                      glActiveTexture(GL_TEXTURE0);
 +                      tex(texState);
 +              }
 +              if (!ground) {
 +                      glActiveTexture(GL_TEXTURE0);
 +                      tex(0);
 +              } else if (vel.x) {
 +                      glActiveTexture(GL_TEXTURE0);
 +                      tex(texState);
 +              } else {
 +                      glActiveTexture(GL_TEXTURE0);
 +                      tex(0);
 +              }
 +              break;
 +      case MOBT:
 +              if (!Mobp(this)->bindTex())
 +                      goto NOPE;
 +              break;
 +      case STRUCTURET:
 +              /* fall through */
 +      default:
 +              glActiveTexture(GL_TEXTURE0);
 +              tex(0);
 +              break;
 +      }
 +
 +      Render::worldShader.use();
 +      // make the entity hit flash red
 +      if (maxHitDuration-hitDuration) {
 +              float flashAmt = 1-(hitDuration/maxHitDuration);
 +              glUniform4f(Render::worldShader.uniform[WU_tex_color], 1.0, flashAmt, flashAmt, 1.0);
 +      }
 +
 +      glUniform1i(Render::worldShader.uniform[WU_texture], 0);
 +      Render::worldShader.enable();
 +
 +      glVertexAttribPointer(Render::worldShader.coord, 3, GL_FLOAT, GL_FALSE, 0, coords);
 +      if (left)
 +              glVertexAttribPointer(Render::worldShader.tex, 2, GL_FLOAT, GL_FALSE, 0 ,tex_coordL);
 +      else
 +              glVertexAttribPointer(Render::worldShader.tex, 2, GL_FLOAT, GL_FALSE, 0 ,tex_coord);
 +      glDrawArrays(GL_TRIANGLES, 0, 6);
 +
 +      glUniform4f(Render::worldShader.uniform[WU_tex_color], 1.0, 1.0, 1.0, 1.0);
 +NOPE:
 +if (near && type != MOBT)
 +      ui::putStringCentered(loc.x+width/2,loc.y-ui::fontSize-game::HLINE/2,name);
 +if (health != maxHealth) {
 +
 +      static GLuint frontH = Texture::genColor(Color(255,0,0));
 +      static GLuint backH =  Texture::genColor(Color(150,0,0));
 +      glUniform1i(Render::worldShader.uniform[WU_texture], 0);
 +
 +      GLfloat coord_back[] = {
 +              loc.x,                  loc.y + height,                               z + 0.1f,
 +              loc.x + width,  loc.y + height,                               z + 0.1f,
 +              loc.x + width,  loc.y + height + game::HLINE * 2, z + 0.1f,
 +
 +              loc.x + width,  loc.y + height + game::HLINE * 2, z + 0.1f,
 +              loc.x,                  loc.y + height + game::HLINE * 2, z + 0.1f,
 +              loc.x,                  loc.y + height,                               z + 0.1f,
 +      };
 +
 +      GLfloat coord_front[] = {
 +              loc.x,                                      loc.y + height,                   z,
 +              loc.x + health / maxHealth * width, loc.y + height,                   z,
 +              loc.x + health / maxHealth * width, loc.y + height + game::HLINE * 2, z,
 +
 +              loc.x + health / maxHealth * width, loc.y + height + game::HLINE * 2, z,
 +              loc.x,                              loc.y + height + game::HLINE * 2, z,
 +              loc.x,                              loc.y + height,                   z,
 +      };
 +
 +      glBindTexture(GL_TEXTURE_2D, backH);
 +      GLfloat tex[] = { 0.0, 0.0,
 +                                        1.0, 0.0,
 +                                        1.0, 1.0,
 +
 +                                        1.0, 1.0,
 +                                        0.0, 1.0,
 +                                        0.0, 0.0,
 +      };
 +      glVertexAttribPointer(Render::worldShader.coord, 3, GL_FLOAT, GL_FALSE, 0, coord_back);
 +      glVertexAttribPointer(Render::worldShader.tex, 2, GL_FLOAT, GL_FALSE, 0, tex);
 +      glDrawArrays(GL_TRIANGLES, 0, 6);
 +
 +      glBindTexture(GL_TEXTURE_2D, frontH);
 +      glVertexAttribPointer(Render::worldShader.coord, 3, GL_FLOAT, GL_FALSE, 0, coord_front);
 +      glVertexAttribPointer(Render::worldShader.tex, 2, GL_FLOAT, GL_FALSE, 0, tex);
 +      glDrawArrays(GL_TRIANGLES, 0, 6);
 +}
 +
 +Render::worldShader.disable();
 +Render::worldShader.unuse();
 +}
 +
 +/**
 + * Handles NPC movement, usually just random walking.
 + */
 +
 +void NPC::
 +wander(int timeRun)
 +{
 +      static int direction;
 +
 +      if (forcedMove)
 +              return;
 +
 +      if (hitCooldown)
 +              hitCooldown--;
 +
 +      if (targetx != 0.9112001f) {
 +              if (loc.x > targetx + HLINES(5))
 +                      vel.x = HLINES(-0.018);
 +              else if (loc.x < targetx - HLINES(5))
 +                      vel.x = HLINES(0.018);
 +              else {
 +                      targetx = 0.9112001f;
 +                      vel.x = 0;
 +              }
 +      } else if (ticksToUse == 0) {
 +              ticksToUse = timeRun;
 +
 +              vel.x = HLINES(0.008);
 +              direction = (randGet() % 3 - 1);
 +
 +              if (direction == 0)
 +                      ticksToUse *= 2;
 +
 +              vel.x *= direction;
 +      }
 +
 +      if (vel.x < 0)
 +              currentWorld->goWorldLeft(this);
 +
 +      ticksToUse--;
 +}
 +
 +void NPC::addAIFunc(bool preload)
 +{
 +      if (preload)
 +              aipreload.push_back(this);
 +      else
 +              ++dialogCount;
 +}
 +
 +extern int commonAIFunc(NPC *speaker);
 +
 +void NPC::interact() { //have the npc's interact back to the player
 +      std::thread([this]{
 +              std::vector<XMLElement *> dopt;
 +              XMLDocument *xml;
 +              XMLElement *exml,*oxml;
 +
 +              static unsigned int oldidx = 9999;
 +              const char *ptr;
 +              std::string nname;
 +              unsigned int idx;
 +              bool stop;
 +              float tgt = 0.12345678f;
 +              bool pmove = true, advance = false;
 +
 +              loc.y += 5;
 +
 +              // freeze the npc, face the player
 +              canMove = false;
 +              left    = (player->loc.x < loc.x);
 +              right   = !left;
 +
 +              // if there's actual scripted stuff to do, do it
 +              if (dialogCount && dialogIndex != 9999) {
 +                      // load the XML file and find the dialog tags
 +                      if (outnabout == 0) {
 +                              xml = &currentXMLDoc;
 +                      } else if (outnabout < 0) {
 +                              xml = new XMLDocument();
 +                              xml->LoadFile((xmlFolder + currentWorld->getToLeft()).c_str());
 +                      } else {
 +                              xml = new XMLDocument();
 +                              xml->LoadFile((xmlFolder + currentWorld->getToRight()).c_str());
 +                      }
 +
 +COMMONAIFUNC:
 +                      idx = 0;
 +                      stop = false;
 +                      exml = xml->FirstChildElement("Dialog");
 +
 +                      // search for the dialog block associated with this npc
 +                      while (exml->StrAttribute("name") != name)
 +                              exml = exml->NextSiblingElement();
 +
 +                      // search for the desired text block
 +                      exml = exml->FirstChildElement();
 +                      do {
 +                              if (std::string("text") == exml->Name() && exml->UnsignedAttribute("id") == (unsigned)dialogIndex)
 +                                      break;
 +                      } while ((exml = exml->NextSiblingElement()));
 +
 +                      // handle quest tags
 +                      if ((oxml = exml->FirstChildElement("quest"))) {
 +                              std::string qname;
 +
 +                              // iterate through all quest tags
 +                              do {
 +                                      // assign quest
 +                                      if (!(qname = oxml->StrAttribute("assign")).empty())
 +                                              player->qh.assign(qname, oxml->StrAttribute("desc"), (oxml->GetText() == nullptr) ? "" : oxml->GetText());
 +
 +                                      // check / finish quest
 +                                      else if (!(qname = oxml->StrAttribute("check")).empty()) {
 +                                              if (player->qh.hasQuest(qname) && player->qh.finish(qname)) {
 +                                                      // QuestHandler::finish() did all the work..
 +                                                      break;
 +                                              } else {
 +                                                      // run error dialog
 +                                                      oldidx = dialogIndex;
 +                                                      dialogIndex = oxml->UnsignedAttribute("fail");
 +                                                      goto COMMONAIFUNC;
 +                                              }
 +                                      }
 +                              } while((oxml = oxml->NextSiblingElement("quest")));
 +                      }
 +
 +                      // handle give tags
 +                      if ((oxml = exml->FirstChildElement("give"))) {
 +                              do player->inv->addItem(oxml->Attribute("id"), oxml->UnsignedAttribute("count"));
 +                              while ((oxml = oxml->NextSiblingElement("give")));
 +                      }
 +
 +                      // handle take tags
 +                      if ((oxml = exml->FirstChildElement("take"))) {
 +                              do player->inv->takeItem(oxml->Attribute("id"), oxml->UnsignedAttribute("count"));
 +                              while ((oxml = oxml->NextSiblingElement()));
 +                      }
 +
 +                      // handle movement directs
 +                      if ((oxml = exml->FirstChildElement("gotox"))) {
 +                              moveTo((tgt = std::stoi(oxml->GetText())));
 +                              if (oxml->QueryBoolAttribute("playerMove", &pmove) != XML_NO_ERROR)
 +                                      pmove = true;
 +                              if (oxml->QueryBoolAttribute("advance", &advance) != XML_NO_ERROR)
 +                                      advance = false;
 +                      }
 +
 +                      // handle attribute setting
 +                      if ((oxml = exml->FirstChildElement("set"))) {
 +                              do game::setValue(oxml->StrAttribute("id"), oxml->StrAttribute("value"));
 +                              while ((oxml = oxml->NextSiblingElement()));
 +                              game::briceUpdate();
 +                      }
 +
 +                      // asdlfkj
 +
 +                      auto txml = exml->FirstChildElement("content");
 +                      if (txml == nullptr)
 +                              goto OTHERSTUFF;
 +
 +                      ptr = txml->GetText() - 1;
 +                      while (*++ptr && isspace(*ptr));
 +
 +                      // handle dialog options
 +                      if ((oxml = exml->FirstChildElement("option"))) {
 +                              std::string optstr;
 +
 +                              // convert option strings to a colon-separated format
 +                              do {
 +                                      // append the next option
 +                                      optstr.append(std::string(":") + oxml->Attribute("text"));
 +
 +                                      // save the associated XMLElement
 +                                      dopt.push_back(oxml);
 +                              } while ((oxml = oxml->NextSiblingElement()));
 +
 +                              // run the dialog stuff
 +                              ui::dialogBox(name, optstr, false, ptr);
 +                              ui::waitForDialog();
 +
 +                              if (ui::dialogOptChosen)
 +                                      exml = dopt[ui::dialogOptChosen - 1];
 +
 +                              dopt.clear();
 +                      }
 +
 +                      // optionless dialog
 +                      else {
 +                              ui::dialogBox(name, "", false, ptr);
 +                              ui::waitForDialog();
 +                      }
 +
 +OTHERSTUFF:
 +
 +                      // trigger other npcs if desired
 +                      if (!(nname = exml->StrAttribute("call")).empty()) {
 +                              NPC *n = dynamic_cast<NPC *>(*std::find_if(std::begin(currentWorld->entity), std::end(currentWorld->entity), [nname](Entity *e) {
 +                                      return (e->type == NPCT && e->name == nname);
 +                              }));
 +
 +                              if (exml->QueryUnsignedAttribute("callid", &idx) == XML_NO_ERROR) {
 +                                      n->dialogIndex = idx;
 +                                      n->addAIFunc(false);
 +                              }
 +                      }
 +
 +                      if (tgt != 0.12345678f) {
 +                              stop = canMove;
 +                              canMove = true;
 +                              while (targetx != 0.9112001f) {
 +                                      if (!pmove)
 +                                              player->speed = 0;
 +                              }
 +                              if (!pmove) {
 +                                      pmove = true;
 +                                      player->speed = 1;
 +                              }
 +                              canMove = stop;
 +                      }
 +
 +                      // handle potential following dialogs
 +                      if ((idx = exml->UnsignedAttribute("nextid"))) {
 +                              dialogIndex = idx;
 +
 +                              // stop talking
 +                              if (exml->QueryBoolAttribute("stop", &stop) == XML_NO_ERROR && stop) {
 +                                      dialogIndex = 9999;
 +                                      dialogCount--;
 +                              }
 +
 +                              // pause, allow player to click npc to continue
 +                              else if (exml->QueryBoolAttribute("pause", &stop) == XML_NO_ERROR && stop) {
 +                                      //return 1;
 +                              }
 +
 +                              // instantly continue
 +                              else {
 +                                      goto COMMONAIFUNC;
 +                              }
 +                      }
 +
 +                      // advance if desired
 +                      else if (advance) {
 +                              goto COMMONAIFUNC;
 +                      }
 +
 +                      // stop talking
 +                      else {
 +                              // error text?
 +                              if (oldidx != 9999) {
 +                                      dialogIndex = oldidx;
 +                                      oldidx = 9999;
 +                              } else {
 +                                      dialogIndex = 9999;
 +                                      dialogCount--;
 +                              }
 +                      }
 +              } else {
 +                      ui::dialogBox(name, "", false, randomDialog[randDialog]);
 +              }
 +
 +              ui::waitForDialog();
 +              canMove = true;
 +      }).detach();
 +}
 +
 +void Merchant::wander(int timeRun) {
 +      static int direction;
 +
 +      if (forcedMove)
 +              return;
 +
 +      if (ticksToUse == 0) {
 +              ticksToUse = timeRun;
 +
 +              vel.x = HLINES(0.008);
 +              direction = (randGet() % 3 - 1);
 +
 +              if (direction == 0)
 +                      ticksToUse *= 2;
 +
 +              vel.x *= direction;
 +      }
 +
 +      if (vel.x < 0)
 +              currentWorld->goWorldLeft(this);
 +      if (inside != nullptr) {
 +              loc.y = inside->loc.y + HLINES(2);
 +              vel.y = GRAVITY_CONSTANT * 5;
 +              if (loc.x <= inside->loc.x + HLINES(5))
 +                      loc.x = inside->loc.x + HLINES(5);
 +              else if (loc.x + width >= inside->loc.x + inside->width - HLINES(5))
 +                      loc.x = inside->loc.x + inside->width - width - HLINES(5);
 +      }
 +      ticksToUse--;
 +}
 +
 +void Merchant::interact() {
 +      std::thread([this]{
 +              ui::merchantBox(name.c_str(), trade[currTrade], ":Accept:Good-Bye", false, toSay->c_str());
 +              ui::waitForDialog();
 +
 +              // handle normal dialog options
 +              switch (ui::dialogOptChosen) {
 +              // Accept
 +              case 1:
 +                      if (!(player->inv->takeItem(trade[currTrade].item[1], trade[currTrade].quantity[1]))) {
 +                              player->inv->addItem(trade[currTrade].item[0],trade[currTrade].quantity[0]);
 +                              toSay = &text[1];
 +                              interact();
 +                      } else {
 +                              toSay = &text[2];
 +                              interact();
 +                      }
 +                      break;
 +
 +              // Good-bye
 +              case 2:
 +                      break;
 +
 +              default:
 +                      break;
 +              }
 +
 +              // handle merchant-specific dialog options
 +              switch (ui::merchOptChosen) {
 +              // left arrow
 +              case 1:
 +                      if (currTrade)
 +                              currTrade--;
 +                      ui::dontTypeOut();
 +                      interact(); // TODO should we nest like this?
 +                      break;
 +
 +              // right arrow
 +              case 2:
 +                      if (currTrade < trade.size() - 1)
 +                              currTrade++;
 +                      ui::dontTypeOut();
 +                      interact();
 +                      break;
 +
 +              default:
 +                      break;
 +              toSay = &text[0];
 +              }
 +      }).detach();
 +}
 +
 +void Object::interact(void) {
 +      std::thread([this]{
 +              if(questObject && alive){
 +                      ui::dialogBox(player->name, ":Yes:No", false, pickupDialog);
 +                      ui::waitForDialog();
 +                      if (ui::dialogOptChosen == 1) {
 +                              player->inv->addItem(iname, 1);
 +                              alive = false;
 +                      }
 +              }else{
 +                      alive = false;
 +                      player->inv->addItem(iname, 1);
 +              }
 +      }).detach();
 +}
 +
 +bool Entity::isInside(vec2 coord) const {
 +      return coord.x >= loc.x &&
 +                 coord.x <= loc.x + width &&
 +                 coord.y >= loc.y     &&
 +             coord.y <= loc.y + height;
 +}
 +
 +/*
 + *    This spawns the structures
 + *
 + * Structures::spawn          This allows us to spawn buildings and large amounts of entities with it.
 + *                                                    Passed are the type and x and y coordinates. These set the x and y coords
 + *                                                    of the structure being spawned, the type pass just determines what rules to follow
 + *                                                    when spawing the structure and entities. In theory this function can also spawn
 + *                                                    void spawn points for large amounts of entities. This would allow for the spawn
 + *                                                    point to have non-normal traits so it could be invisible or invincible...
 +*/
 +
 +unsigned int Structures::spawn(BUILD_SUB sub, float x, float y) {
 +      loc.x = x;
 +      loc.y = y;
 +      type = STRUCTURET;
 +
 +      alive = true;
 +      canMove = false;
 +
 +      bsubtype = sub;
 +      dim2 dim;
 +
 +      z = 1.0;
 +      /*
 +       *      tempN is the amount of entities that will be spawned in the village. Currently the village
 +       *      will spawn bewteen 2 and 7 villagers for the starting hut.
 +      */
 +
 +      //unsigned int tempN = (randGet() % 5 + 2);
 +
 +      if (textureLoc.empty())
 +              textureLoc = inWorld->getSTextureLocation(sub);
 +
 +      switch(sub) {
 +              case STALL_MARKET:
 +                      tex = TextureIterator({ textureLoc });
 +                      dim = Texture::imageDim(textureLoc);
 +                      width = HLINES(dim.x/2);
 +                      height = HLINES(dim.y/2);
 +                      break;
 +              default:
 +                      tex = TextureIterator({ textureLoc });
 +                      dim = Texture::imageDim(textureLoc);
 +                      width = HLINES(dim.x/2);
 +                      height = HLINES(dim.y/2);
 +                      inv = NULL;
 +                      break;
 +      }
 +
 +      return 0;
 +}
 +
 +/*Particles::Particles(const Structures *&s, vec2 vell, Color c, float d, )
 +{
 +
 +}*/
 +
 +Particles::Particles(float x, float y, float w, float h, float vx, float vy, Color c, float d)
 +{
 +      loc = vec2 {x, y};
 +      vel = vec2 {vx, vy};
 +      width = w;
 +      height = h;
 +      color = c;
 +      duration = d;
 +      gravity = true;
 +      fountain = false;
 +      behind = false;
 +      bounce = false;
 +      index = Texture::getIndex(c);
 +      zOffset = ((rand()%20)-10)/1000.0f;
 +      stu = nullptr;
 +}
 +
 +void Particles::draw(GLfloat*& p) const
 +{
 +      vec2 tc = vec2(0.25f * index.x, 0.125f * (8.0f - index.y));
 +
 +      float z = (behind ? 2.0f : 0.9f) + zOffset;
 +
 +      // lower left
 +    *(p++) = loc.x;
 +    *(p++) = loc.y;
 +    *(p++) = z;
 +
 +      *(p++) = tc.x;
 +      *(p++) = tc.y;
 +
 +      // lower right
 +    *(p++) = loc.x + width;
 +    *(p++) = loc.y;
 +    *(p++) = z;
 +
 +      *(p++) = tc.x;
 +      *(p++) = tc.y;
 +
 +      // upper right
 +    *(p++) = loc.x + width;
 +    *(p++) = loc.y + height;
 +    *(p++) = z;
 +
 +      *(p++) = tc.x;
 +      *(p++) = tc.y;
 +
 +      // upper right
 +    *(p++) = loc.x + width;
 +    *(p++) = loc.y + height;
 +    *(p++) = z;
 +
 +      *(p++) = tc.x;
 +      *(p++) = tc.y;
 +
 +      // upper left
 +    *(p++) = loc.x;
 +    *(p++) = loc.y + height;
 +    *(p++) = z;
 +
 +      *(p++) = tc.x;
 +    *(p++) = tc.y;
 +
 +      // lower left
 +    *(p++) = loc.x;
 +    *(p++) = loc.y;
 +    *(p++) = z;
 +
 +    *(p++) = tc.x;
 +    *(p++) = tc.y;
 +}
 +
 +void Particles::update(float _gravity, float ground_y)
 +{
 +      auto delta = game::time::getDeltaTime();
 +
 +      // handle ground collision
 +      if (loc.y < ground_y) {
 +              loc.y = ground_y;
 +
 +              // handle bounce
 +              if (bounce) {
 +                      vel.y *= -0.2f;
 +                      vel.x /= 4.0f;
 +              } else {
 +                      vel = 0.0f;
 +                      canMove = false;
 +              }
 +      }
 +
 +      // handle gravity
 +      else if (gravity && vel.y > -1.0f) {
 +              vel.y -= _gravity * delta;
 +      }
 +
 +      // handle lifetime
 +      duration -= delta;
 +}
 +
 +bool Particles::timeUp(void)
 +{
 +      return !(duration > 0);
 +}
 +
 +void Player::save(void) {
 +      std::string data;
 +      std::ofstream out (xmlFolder + ".main.dat", std::ios::out | std::ios::binary);
 +      std::cout<<"Saving player data..."<<std::endl;
 +      data.append(std::to_string((int)loc.x) + "\n");
 +      data.append(std::to_string((int)loc.y) + "\n");
 +      data.append(std::to_string((int)health) + "\n");
 +      data.append(std::to_string((int)maxHealth) + "\n");
 +      data.append(std::to_string((int)game::time::getTickCount()) + "\n");
 +
 +      data.append("qwer\n");
 +      data.append(std::to_string((int)inv->Items.size()) + "\n");
 +      for(auto &i : inv->Items) {
 +              if(i.second)
 +                      data.append(std::to_string(uint(i.second)) + "\n" + i.first->name + "\n");
 +      }
 +      data.append("qwer\n");
 +
 +      data.append(std::string(currentXML.data() + 4) + "\n");
 +
 +      data.append("dOnE\0");
 +      out.write(data.data(),data.size());
 +      out.close();
 +}
 +
 +void Player::sspawn(float x,float y) {
 +      unsigned int i;
 +      int count;
 +      std::ifstream in (xmlFolder + ".main.dat", std::ios::in | std::ios::binary);
 +      spawn(x,y);
 +
 +      if (in.good()) {
 +              std::istringstream data;
 +              std::string ddata;
 +              std::streampos len;
 +
 +              in.seekg(0,std::ios::end);
 +              len = in.tellg();
 +              in.seekg(0,std::ios::beg);
 +
 +              std::vector<char> buf (len,'\0');
 +              in.read(buf.data(),buf.size());
 +
 +              data.rdbuf()->pubsetbuf(buf.data(),buf.size());
 +
 +              std::getline(data,ddata);
 +              loc.x = std::stoi(ddata);
 +              std::getline(data,ddata);
 +              loc.y = std::stoi(ddata);
 +              std::getline(data,ddata);
 +              health = std::stoi(ddata);
 +              std::getline(data,ddata);
 +              maxHealth = std::stoi(ddata);
 +              std::getline(data,ddata);
 +              game::time::tick(std::stoi(ddata));
 +
 +              std::getline(data,ddata);
 +              std::getline(data,ddata);
 +
 +              for (i = std::stoi(ddata);i;i--) {
 +                      std::getline(data,ddata);
 +                      if (ddata == "qwer")
 +                              break;
 +                      count = std::stoi(ddata);
 +
 +                      std::getline(data,ddata);
 +                      if (ddata == "qwer")
 +                              break;
 +                      inv->addItem(ddata, (uint)count);
 +              }
 +
 +              std::getline(data,ddata);
 +              currentWorld = loadWorldFromXMLNoSave(ddata);
 +
 +              in.close();
 +      }
 +}
++
++
++//NEW
++void entityxTest(void)
++{
++      entityx::Entity e = game::entities.create();
++      e.assign<Position>(100.0f, 100.0f);
++      e.assign<Direction>(0.0f, 0.0f);
++      
++      e = game::entities.create();
++      e.assign<Position>(0.0f, 100.0f);
++      e.assign<Direction>(-0.01f, 0.0f);
++      e.assign<Visible>(-.2f);
++      auto sprite_h = e.assign<Sprite>();
++      sprite_h->addSpriteSegment(SpriteData(game::sprite_l.loadSprite("assets/cat.png"),
++                                                                                vec2(0, 0),
++                                                                                vec2(19, 15)),
++                                                                                vec2(0, 0));
++}