]> code.bitgloo.com Git - clyne/gamedev.git/commitdiff
more world rewriting
authorClyne Sullivan <tullivan99@gmail.com>
Thu, 21 Apr 2016 22:44:47 +0000 (18:44 -0400)
committerClyne Sullivan <tullivan99@gmail.com>
Thu, 21 Apr 2016 22:44:47 +0000 (18:44 -0400)
Makefile
include/common.hpp
include/entities.hpp
include/world.hpp
src/ui_action.cpp
src/world.cpp

index 6abc13f259fa27544c2b328dc11ee849635eb130..dd1267f6aef05a5adb7d0b344fdcbf4f6c6c423f 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -12,7 +12,7 @@ ifeq ($(TARGET_OS),win32)
               -lSDL2main -lSDL2 -lSDL2_image -lSDL2_mixer -lfreetype
 endif
 
-CXXFLAGS = -m$(TARGET_BITS) -std=c++1z
+CXXFLAGS = -m$(TARGET_BITS) -std=c++17
 CXXINC   = -Iinclude -Iinclude/freetype
 CXXWARN  = -Wall -Wextra -Werror -pedantic-errors
 
index a7ad6ec2a9bd8d5adcfb24c6884a62f90a01cf19..83350d330450940ee66560f17c6193e536ea0466 100644 (file)
@@ -86,10 +86,15 @@ typedef struct {
        int y;
 } ivec2;
 
-typedef struct {
+struct _vec2 {
        float x;
        float y;
-} vec2;
+
+       bool operator==(const _vec2 &v) {
+               return (x == v.x) && (y == v.y);
+       }
+};
+typedef struct _vec2 vec2;
 
 typedef struct {
        float x;
index 6cd573120972881aabba713c81aa27ae0e68266e..f38a5fef1bcc0bb7f8fdd73d33880bf81c4c7675 100644 (file)
@@ -13,7 +13,6 @@
 #define NPCp(n)                        ((NPC *)n)
 #define Structurep(n)  ((Structures *)n)
 #define Mobp(n)                        ((Mob *)n)
-#define Objectp(n)             ((Object *)n)
 
 #define PLAYER_INV_SIZE        43      // The size of the player's inventory
 #define NPC_INV_SIZE   3       // Size of an NPC's inventory
@@ -275,7 +274,54 @@ public:
        void reloadTexture(void);
 
        void interact(void);
+
+       bool operator==(const Object &o) {
+               return !strcmp(name, o.name) && (loc == o.loc);
+       }
+};
+
+/**
+ * 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(vec2 l, Color c, float r){
+               loc = l;
+               color = c;
+               radius = r;
+
+               belongsTo = false;
+               following = nullptr;
+
+               flame = false;
+       }
+
+       void makeFlame(void){
+               flame = true;
+       }
+
+       void follow(Entity *f){
+               following=f;
+               belongsTo = true;
+       }
 };
+
+constexpr Object *Objectp(Entity *e) {
+       return (Object *)e;
+}
+
 #endif // ENTITIES_H
 
 /**
index 5608acc20941bad6a3aa21ebf465aebc57a4260e..dcd047b7a7cce7c4f55dc9b9275b2d43b6212ede 100644 (file)
@@ -1,43 +1,29 @@
-/** @file world.h
- * @brief The world system.
- *
- * This file contains the classes and variables necessary to create an in-game
- * world.
- */
-
+/* ----------------------------------------------------------------------------
+** The world stuffs.
+**
+** This file contains the classes and variables necessary to create an in-game
+** world... "and stuffs".
+** --------------------------------------------------------------------------*/
 #ifndef WORLD_H
 #define WORLD_H
 
+/* ----------------------------------------------------------------------------
+** Includes section
+** --------------------------------------------------------------------------*/
+
+// 'local' game includes
 #include <common.hpp>
 #include <entities.hpp>
 
-#define GROUND_HEIGHT_INITIAL   80
-#define GROUND_HEIGHT_MINIMUM   60
-#define GROUND_HEIGHT_MAXIMUM   110
-#define GROUND_HILLINESS        10
-
-#define PLAYER_SPEED_CONSTANT 0.15f
-
-/**
- * Gravity thing
- */
-
-#define GRAVITY_CONSTANT        0.001f
-
-/**
- * Defines how many game ticks it takes for a day to elapse.
- */
-
-#define DAY_CYCLE 12000
-
-#define Indoorp(x) ((IndoorWorld *)x)
+/* ----------------------------------------------------------------------------
+** Structures section
+** --------------------------------------------------------------------------*/
 
 /**
  * The background type enum.
  * This enum contains all different possibilities for world backgrounds; used
  * in World::setBackground() to select the appropriate images.
  */
-
 enum class WorldBGType : unsigned char {
        Forest,         /**< A forest theme. */
        WoodHouse       /**< An indoor wooden house theme. */
@@ -48,7 +34,6 @@ enum class WorldBGType : unsigned char {
  * This enum contains every type of weather currently implemented in the game.
  * Weather is set by the world somewhere.
  */
-
 enum class WorldWeather : unsigned char {
        Sunny = 0,      /**< Sunny/daytime */
        Dark,           /**< Nighttime */
@@ -61,7 +46,6 @@ enum class WorldWeather : unsigned char {
  * This structure is used to store the world's ground, stored in vertical
  * lines. Dirt color and grass properties are also kept track of here.
  */
-
 typedef struct {
     bool          grassUnpressed;
     float         grassHeight[2];
@@ -69,70 +53,36 @@ typedef struct {
     unsigned char groundColor;
 } WorldData;
 
-/**
- * A value used by World::draw() for shading, ranges from -50 to 50 depending
- * on the current time of day.
- */
+/* ----------------------------------------------------------------------------
+** Variables section
+** --------------------------------------------------------------------------*/
 
+// affects brightness of world elements when drawn
 extern int worldShade;
 
-/**
- * The path to the currently loaded XML file.
- */
-
+// the path to the currently loaded XML file.
 extern std::string currentXML;
 
-// prototype so Village can reference it
-class World;
-
-/**
- * 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(vec2 l, Color c, float r){
-               loc = l;
-               color = c;
-               radius = r;
+// defines how many game ticks it takes for a day to elapse
+extern const unsigned int DAY_CYCLE;
 
-               belongsTo = false;
-               following = nullptr;
+// velocity of player when moved by user
+extern const float PLAYER_SPEED_CONSTANT;
 
-               flame = false;
-       }
-
-       void makeFlame(void){
-               flame = true;
-       }
-
-       void follow(Entity *f){
-               following=f;
-               belongsTo = true;
-       }
-};
+// maximum pull of gravity in one game tick
+extern const float GRAVITY_CONSTANT;
 
+/* ----------------------------------------------------------------------------
+** Classes / function prototypes section
+** --------------------------------------------------------------------------*/
 
 /**
  * The village class, used to group structures into villages.
  */
-
 class Village {
 public:
        std::string name;
-       vec2 start;
-       vec2 end;
+       vec2 start, end;
        bool in;
 
        Village(const char *meme, World *w);
@@ -142,277 +92,160 @@ public:
 /**
  * The world class. This class does everything a world should do.
  */
-
 class World {
 protected:
 
-       /**
-        * The line array.
-        *
-        * This array is created through 'new' in World::generate(), with an amount
-        * of elements provided by the function.
-        */
-
-        std::vector<WorldData> worldData;
-
-       /**
-        * Starting x coordinate.
-        *
-        * This x value is the point at which line[0] should reside, can be used to
-        * calculate the width of the world.
-        */
-
-       int worldStart;
-
-       /**
-        * Handle physics for a single entity.
-        *
-        * This function handles gravity and death for an entity. The public version
-        * of this, World::detect(), handles all entities in the world as well as
-        * the player. World::singleDetect() should never be used outside of
-        * World::detect(), which is why it is declared private.
-        */
-
-       virtual void singleDetect(Entity *e);
-
-       /**
-        * Empties all entity vectors.
-        *
-        * Each entity vector is iterated through, calling delete for each entry.
-        * Once all specific vectors are cleared, the general entity vector is
-        * emptied of the pointers to those other vectors. This function should only
-        * be called in World's destructor, as there shouldn't be another reason to
-        * call this function.
-        */
-
-       void deleteEntities(void);
-
-       /**
-        * Number of lines in the world.
-        *
-        * While this number is helpful for knowing the world's width, it is kept
-        * private for security reasons. To compensate for this,
-        * World::getTheWidth() is provided (see below).
-        */
+       // an array of all the world's ground data
+       std::vector<WorldData> worldData;
 
+       // the size of `worldData`
        unsigned int lineCount;
 
-       /**
-        * An array of star coordinates.
-        */
-
-       std::vector<vec2> star;
-
-       /**
-        * The Texturec object that holds the background sprites for this world.
-        */
+       // the left-most (negative) coordinate of the worldStart
+       int worldStart;
 
+       // holds / handles textures for background elements
        Texturec *bgTex;
 
-       /**
-        * Defines the set of background images that should be used for this world.
-        */
-
+       // defines what type of background is being used
        WorldBGType bgType;
 
-       /**
-        * The Mix_Music object that holds the background soundtrack for the world.
-        */
-
+       // an SDL_mixer object for the world's BGM
        Mix_Music *bgmObj;
 
-       /**
-        * The file path of the song wished to be loaded by bgmObj.
-        */
-
+       // the pathname of the loaded BGM
        std::string bgm;
 
-       std::vector<std::string> bgFiles;
-       std::vector<std::string> bgFilesIndoors;
-
-       /**
-        * The filename of the XML file for the world to the left; NULL if no world
-        * is present.
-        */
-
+       // XML file names of worlds to the left and right, empty if nonexistant
        std::string toLeft;
-
-       /**
-        * The filename of the XML file for the world to the right; NULL if no world
-        * is present.
-        */
-
        std::string toRight;
 
-       /**
-        * Vector of all building textures for the current world style
-        */
-
+       // structure texture file paths
        std::vector<std::string> sTexLoc;
 
+       // TODO
+       std::vector<std::string> bgFiles;
+       std::vector<std::string> bgFilesIndoors;
+
+       // an array of star coordinates
+       std::vector<vec2> star;
+
+       // entity vectors
        std::vector<Light>        light;
-       std::vector<Village>      village;
-       std::vector<Particles>    particles;
-       std::vector<Object>           object;
        std::vector<Mob *>        mob;
+       std::vector<Object>           object;
+       std::vector<Particles>    particles;
        std::vector<Structures *> build;
+       std::vector<Village>      village;
 
-public:
-
-       Light *getLastLight(void);
-       Mob   *getLastMob(void);
-       Entity *getNearInteractable(Entity e);
-       vec2 getStructurePos(int index);
-
-       std::string getSTextureLocation(unsigned int index) const;
-
-       /**
-        * These handle accessing/modifying pathnames for worlds linked to the left
-        * and right of this one.
-        */
-
-       std::string setToLeft(std::string file);
-       std::string setToRight(std::string file);
+       // handles death, gravity, etc. for a single entity
+       virtual void singleDetect(Entity *e);
 
-       std::string getToLeft(void) const;
-       std::string getToRight(void) const;
+       // frees entities and clears vectors that contain them
+       void deleteEntities(void);
 
-       /**
-        * A vector of pointers to every NPC, Structure, Mob, and Object in this
-        * world.
-        */
+public:
 
+       // entity vectors that need to be public because we're based
        std::vector<Entity *> entity;
-       std::vector<NPC *> npc;
-       std::vector<Merchant *> merchant;
 
-       /**
-        * NULLifies pointers and allocates necessary memory. This should be
-        * followed by some combination of setBackground(), setBGM(), or
-        * generate().
-        */
+       std::vector<NPC *>      npc;
+       std::vector<Merchant *> merchant;
 
+       // the world constructor, prepares variables
        World(void);
 
-       /**
-        * Frees resources taken by the world.
-        */
-
+       // destructor, frees used memory
        virtual ~World(void);
 
-       void     addLight(vec2 xy, Color color);
-       void     addMerchant(float x, float y, bool housed);
-       void     addMob(int type,float x,float y);
-       void     addMob(int t,float x,float y,void (*hey)(Mob *));
-       void     addNPC(float x,float y);
-       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 d);
-       void     addParticle(float x, float y, float w, float h, float vx, float vy, Color color, int d, unsigned char flags);
-       void     addStructure(BUILD_SUB subtype,float x,float y, std::string tex, std::string inside);
-       Village *addVillage(std::string name, World *world);
+       // generates a world of the specified width
+       void generate(unsigned int width);
 
-       /**
-        * Updates the coordinates of everything in the world that has coordinates
-        * and a velocity. The provided delta time is used for smoother updating.
-        */
+       // draws everything to the screen
+       virtual void draw(Player *p);
 
-       void update(Player *p, unsigned int delta);
+       // handles collisions/death of player and all entities
+       void detect(Player *p);
 
-       /**
-        * Generate a world of the provided width. Worlds are drawn centered on the
-        * y-axis, so the reachable coordinates on the world would be from negative
-        * half-width to positive half-width.
-        */
+       // updates entities, moving them and such
+       void update(Player *p, unsigned int delta);
 
-       void generate(unsigned int width);
+       // gets the world's width in TODO
+       int getTheWidth(void) const;
 
-       /**
-        * Sets the background theme, collecting the required textures into a
-        * Texturec object.
-        */
+       // gets a pointer to the most recently added light
+       Light *getLastLight(void);
 
-       void setBackground(WorldBGType bgt);
+       // gets a pointer to the most recently added mob
+       Mob *getLastMob(void);
 
-       /**
-        * Sets the background music for the world, required for the world to be
-        * playable.
-        */
+       // gets the nearest interactable entity to the given one
+       Entity *getNearInteractable(Entity &e);
 
-       void setBGM(std::string path);
+       // gets the coordinates of the `index`th structure
+       vec2 getStructurePos(int index);
 
-       /**
-        *      Sets the worlds style folder
-        */
+       // gets the texture path of the `index`th structure
+       std::string getSTextureLocation(unsigned int index) const;
 
-       void setStyle(std::string pre);
+       // saves the world's data to an XML file
+       void save(void);
 
-       /**
-        * Plays/stops this world's BGM. If `prev` is not NULL, that world's BGM
-        * will be faded out followed by the fading in of this world's BGM.
-        */
+       // attempts to load world data from an XML file
+       void load(void);
 
+       // plays/pauses the world's music, according to if a new world is being entered
        void bgmPlay(World *prev) const;
 
-       /**
-        * Draw the world and entities based on the player's coordinates.
-        */
-
-       virtual void draw(Player *p);
+       // sets and loads the specified BGM
+       void setBGM(std::string path);
 
-       /**
-        * Handles collision between the entities and the world, as well as entity
-        * death.
-        */
+       // sets the world's background theme
+       void setBackground(WorldBGType bgt);
 
-       void detect(Player *p);
+       // sets the folder to collect entity textures from
+       void setStyle(std::string pre);
 
-       /**
-        * Attempts to let the player enter the left-linked world specified by
-        * `toLeft`. Returns the world to the left if the movement is possible,
-        * otherwise returns this world.
-        */
+       // sets / gets pathnames of XML files for worlds to the left and right
+       std::string setToLeft(std::string file);
+       std::string setToRight(std::string file);
+       std::string getToLeft(void) const;
+       std::string getToRight(void) const;
 
+       // attempts to enter the left/right adjacent world, returning either that world or this
        World *goWorldLeft(Player *p);
-       bool   goWorldLeft(NPC *e);
-
-       /**
-        * Attempts to let the player enter the right-linked world specified by
-        * `toRight`. Returns the world to the right if the movement is possible,
-        * otherwise returns this world.
-        */
-
        World *goWorldRight(Player *p);
 
-       /**
-        * This function looks for any structure the player is standing in front of
-        * that also have an inside world. Returns the inside world if those
-        * conditions are met, otherwise returns this world.
-        */
+       // attempts to move an NPC to the left adjacent world, returning true on success
+       bool goWorldLeft(NPC *e);
 
+       // attempts to enter a structure that the player would be standing in front of
        World *goInsideStructure(Player *p);
 
-       /**
-        * Adds a hole between the specified y coordinates. If the player falls in
-        * this hole the game will exit.
-        */
-
+       // adds a hole at the specified start and end x-coordinates
        void addHole(unsigned int start,unsigned int end);
 
-       /**
-        * Adds a hill to the world, given the peak's coordinates and how wide the
-        * hill can be.
-        */
-
+       // adds a hill that peaks at the given coordinate and is `width` HLINEs wide
        void addHill(ivec2 peak, unsigned int width);
 
-       /**
-        * Gets the world's width.
-        */
+       // functions to add entities to the world
+       void addLight(vec2 xy, Color color);
 
-       int getTheWidth(void) const;
+       void addMerchant(float x, float y, bool housed);
 
-       void save(void);
-       void load(void);
+       void addMob(int type, float x, float y);
+       void addMob(int type, float x, float y, void (*hey)(Mob *));
+
+       void addNPC(float x, float y);
+
+       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);
+
+       Village *addVillage(std::string name, World *world);
 };
 
 /*
@@ -502,4 +335,9 @@ World *loadWorldFromXMLNoSave(std::string path);
 
 World *loadWorldFromPtr(World *ptr);
 
+constexpr IndoorWorld *Indoorp(World *w)
+{
+    return (IndoorWorld *)w;
+}
+
 #endif // WORLD_H
index 66fea19fbf402099a768575111ac4710036f0172..a7bb36bbbfbe659137d438e3e669fcb250620618 100644 (file)
@@ -1,5 +1,8 @@
 #include <ui_action.hpp>
 
+#define ACTION_PROLOUGE { actioning = true; }
+#define ACTION_EPILOUGE { actioning = false; actionHover = 0; }
+
 extern World *currentWorld;
 extern Player *player;
 extern bool inBattle;
@@ -19,7 +22,7 @@ static std::vector<void (*)(void)> actionFunc = {
     nullptr,
 };
 
-static bool actionToggle = false;
+static bool actionToggle = false, actioning = false;
 static unsigned int actionHover = 0;
 static Entity *nearEntity = nullptr, *lastEntity = nullptr;
 
@@ -42,7 +45,6 @@ namespace ui {
 
         // draws the action ui
         void draw(vec2 loc) {
-            static bool second = false;
             unsigned int i = 1;
             float y = loc.y;
 
@@ -60,28 +62,21 @@ namespace ui {
             } else if (nearEntity != lastEntity) {
                 if (lastEntity != nullptr)
                     lastEntity->canMove = true;
-                lastEntity = nearEntity;;
+                lastEntity = nearEntity;
             }
 
             if (make) {
+                while(actioning);
+
                 if (!actionHover) {
                     make = false;
                     return;
                 }
 
-                if (!second)
-                    second = true;
-                else {
-                    second = false;
-                    return;
-                }
-
                 if (actionFunc[actionHover - 1] != nullptr)
                     std::thread(actionFunc[actionHover - 1]).detach();
 
                 actionHover = 0;
-                make = false;
-                return;
             } else {
                 nearEntity->canMove = false;
                 ui::drawBox(vec2 {loc.x - HLINES(11), loc.y}, vec2 {loc.x + HLINES(12), loc.y + actionText.size() * HLINES(8)});
@@ -106,12 +101,15 @@ namespace ui {
                 actionHover = 0;
 
             ui::setFontColor(255, 255, 255, 255);
+            make = false;
         }
     }
 }
 
 void actionAttack(void)
 {
+    ACTION_PROLOUGE;
+
     auto m = currentWorld->getNearInteractable(*player);
 
     if (m->type == MOBT) {
@@ -129,14 +127,20 @@ void actionAttack(void)
     } else {
         ui::dialogBox(player->name, "", false, "%s doesn't appear to be in the mood for fighting...", m->name);
     }
+
+    ACTION_EPILOUGE;
 }
 
 void actionAction(void)
 {
+    ACTION_PROLOUGE;
+
     auto e = currentWorld->getNearInteractable(*player);
 
     if (e->type == NPCT) {
         if (!NPCp(e)->aiFunc.empty())
             e->interact();
     }
+
+    ACTION_EPILOUGE;
 }
index df6c556a42db68dd4bb48320f018e84ce7020c94..baf3080c58e57cda15533aae1809eed29bc83b40 100644 (file)
@@ -1,54 +1,74 @@
+#include <world.hpp>
+
+/* ----------------------------------------------------------------------------
+** Includes section
+** --------------------------------------------------------------------------*/
+
+// standard library headers
 #include <algorithm>
 #include <sstream>
 
-#include <world.hpp>
+// local game headers
 #include <ui.hpp>
 
+// local library headers
 #include <tinyxml2.h>
 using namespace tinyxml2;
 
-/**
- * Defines how many HLINEs tall a blade of grass can be.
- */
+/* ----------------------------------------------------------------------------
+** Macros section
+** --------------------------------------------------------------------------*/
 
-#define GRASS_HEIGHT            4
-
-/**
- * Defines the height of the floor in an IndoorWorld.
- */
+// defines grass height in HLINEs
+#define GRASS_HEIGHT 4
 
+// indoor world constants
 #define INDOOR_FLOOR_THICKNESS      50
 #define INDOOR_FLOOR_HEIGHTT        400
 
-extern Player *player;                                         // main.cpp?
-extern World  *currentWorld;                           // main.cpp
-extern World  *currentWorldToLeft;                     // main.cpp
-extern World  *currentWorldToRight;                    // main.cpp
-extern int     commonAIFunc(NPC *);                    // entities.cpp
-extern void    commonTriggerFunc(Mob *);       // gameplay.cpp
-extern void    commonPageFunc(Mob *);          // gameplay.cpp
-extern bool    inBattle;
+/* ----------------------------------------------------------------------------
+** Variables section
+** --------------------------------------------------------------------------*/
 
+// external variables
+extern Player      *player;                                    // main.cpp?
+extern World       *currentWorld;                      // main.cpp
+extern World       *currentWorldToLeft;                // main.cpp
+extern World       *currentWorldToRight;       // main.cpp
+extern bool         inBattle;               // ui.cpp?
 extern unsigned int tickCount;                         // main.cpp
+extern std::string  xmlFolder;
 
-extern std::string xmlFolder;
 
+// externally referenced in main.cpp
+const unsigned int DAY_CYCLE = 12000;
 int worldShade = 0;
 
-std::string currentXML;
-
-std::vector<std::string> inside;               // tracks indoor worlds
+// externally referenced in entities.cpp
+const float PLAYER_SPEED_CONSTANT = 0.150f;
+const float GRAVITY_CONSTANT      = 0.001f;
 
-std::vector<World *>     battleNest;   // tracks arenas
-std::vector<vec2>        battleNestLoc;        // keeps arena locations
+// ground-generating constants
+static const float GROUND_HEIGHT_INITIAL =  80.0f;
+static const float GROUND_HEIGHT_MINIMUM =  60.0f;
+static const float GROUND_HEIGHT_MAXIMUM = 110.0f;
+static const float GROUND_HILLINESS      =  10.0f;
 
-/**
- * Contains the current weather, used in many other places/files.
- */
+// the path of the currently loaded XML file, externally referenced in places
+std::string currentXML;
 
+// contains the current world's weather, extern'd in ui.cpp, main.cpp, ..?
 WorldWeather weather = WorldWeather::Sunny;
 
-const std::string bgPaths[2][9]={
+// keeps track of pathnames of XML file'd worlds the player has left to enter structures
+std::vector<std::string> inside;
+
+// keeps track of information of worlds the player has left to enter arenas
+static std::vector<World *> battleNest;
+static std::vector<vec2>    battleNestLoc;
+
+// pathnames of images for world themes
+static const std::string bgPaths[][9] = {
     {"bg.png",                                 // Daytime background
      "bgn.png",                                        // Nighttime background
      "bgFarMountain.png",              // Furthest layer
@@ -68,7 +88,8 @@ const std::string bgPaths[2][9]={
      "bgWoodTile.png"}
 };
 
-const std::string buildPaths[] = {
+// pathnames of structure textures
+static const std::string buildPaths[] = {
     "townhall.png",
        "house1.png",
     "house2.png",
@@ -79,102 +100,66 @@ const std::string buildPaths[] = {
        "brazzier.png"
 };
 
-/**
- * Constants used for layer drawing in World::draw(), releated to transparency.
- */
-
-const float bgDraw[4][3]={
+// alpha-related values used for world drawing? nobody knows...
+static const float bgDraw[4][3]={
        { 100, 240, 0.6  },
        { 150, 250, 0.4  },
        { 200, 255, 0.25 },
        { 255, 255, 0.1  }
 };
 
-/**
- * Sets the desired theme for the world's background.
- *
- * The images chosen for the background layers are selected depending on the
- * world's background type.
- */
-
-void World::
-setBackground(WorldBGType bgt)
-{
-    // load textures with a limit check
-       switch ((bgType = bgt)) {
-       case WorldBGType::Forest:
-               bgTex = new Texturec(bgFiles);
-               break;
-
-       case WorldBGType::WoodHouse:
-               bgTex = new Texturec(bgFilesIndoors);
-               break;
+/* ----------------------------------------------------------------------------
+** Functions section
+** --------------------------------------------------------------------------*/
 
-    default:
-        UserError("Invalid world background type");
-        break;
-       }
-}
+// externs
+extern int  commonAIFunc(NPC *);               // gameplay.cpp
+extern void commonTriggerFunc(Mob *);  // gameplay.cpp
+extern void commonPageFunc(Mob *);             // gameplay.cpp
 
 /**
- * Sets the world's style.
- *
- * The world's style will determine what sprites are used for things like\
- * generic structures.
+ * Creates a world object.
+ * Note that all this does is nullify a pointer...
  */
-
-void World::
-setStyle(std::string pre)
+World::
+World(void)
 {
-    unsigned int i;
-
-    // get folder prefix
-       std::string prefix = pre.empty() ? "assets/style/classic/" : pre;
-
-       for (i = 0; i < arrAmt(buildPaths); i++)
-               sTexLoc.push_back(prefix + buildPaths[i]);
-
-       prefix += "bg/";
-
-       for (i = 0; i < arrAmt(bgPaths[0]); i++)
-               bgFiles.push_back(prefix + bgPaths[0][i]);
-
-       for (i = 0; i < arrAmt(bgPaths[1]); i++)
-               bgFilesIndoors.push_back(prefix + bgPaths[1][i]);
+    bgmObj = nullptr;
 }
 
 /**
- * Creates a world object.
- *
- * Note that all this does is nullify pointers, to prevent as much disaster as
- * possible. Functions like setBGM(), setStyle() and generate() should be called
- * before the World is actually put into use.
+ * The world destructor.
+ * This will free objects used by the world itself, then free the vectors of
+ * entity-related objects.
  */
-
 World::
-World(void)
+~World(void)
 {
-    bgmObj = NULL;
+    // SDL2_mixer's object
+       if (bgmObj != nullptr)
+               Mix_FreeMusic(bgmObj);
+
+       delete bgTex;
+       deleteEntities();
 }
 
 /**
  * The entity vector destroyer.
- *
  * This function will free all memory used by all entities, and then empty the
  * vectors they were stored in.
  */
-
 void World::
 deleteEntities(void)
 {
     // free mobs
-    while(!mob.empty()){
+    while (!mob.empty()) {
                delete mob.back();
                mob.pop_back();
        }
 
-       merchant.clear();
-       while(!npc.empty()){
+    // free npcs
+       merchant.clear(); // TODO
+       while (!npc.empty()) {
                delete npc.back();
                npc.pop_back();
        }
@@ -187,52 +172,28 @@ deleteEntities(void)
 
     // free objects
        object.clear();
-
-    // clear entity array
-       entity.clear();
-
     // free particles
        particles.clear();
-
     // clear light array
        light.clear();
-
     // free villages
        village.clear();
-}
-
-/**
- * The world destructor.
- *
- * This will free objects used by the world itself, then free the vectors of
- * entity-related objects.
- */
-
-World::
-~World(void)
-{
-    // sdl2_mixer's object
-       if(bgmObj)
-               Mix_FreeMusic(bgmObj);
-
-       delete bgTex;
-       deleteEntities();
+    // clear entity array
+       entity.clear();
 }
 
 /**
  * Generates a world of the specified width.
- *
- * This will mainly populate the WorldData array, mostly preparing the World
+ * This will mainly populate the WorldData array, preparing most of the world
  * object for usage.
  */
-
 void World::
 generate(unsigned int width)
 {
     // iterator for `for` loops
        std::vector<WorldData>::iterator wditer;
 
-    // see below for description
+    // see below for description/usage
     float geninc = 0;
 
     // check for valid width
@@ -240,7 +201,7 @@ generate(unsigned int width)
         UserError("Invalid world dimensions");
 
     // allocate space for world
-    worldData = std::vector<WorldData> (width + GROUND_HILLINESS, WorldData { false, {0,0}, 0, 0 });
+    worldData = std::vector<WorldData> (width + GROUND_HILLINESS, WorldData { false, {0, 0}, 0, 0 });
     lineCount = worldData.size();
 
     // prepare for generation
@@ -248,7 +209,7 @@ generate(unsigned int width)
     wditer = worldData.begin();
 
     // give every GROUND_HILLINESSth entry a groundHeight value
-    for(unsigned int i = GROUND_HILLINESS; i < worldData.size(); i += GROUND_HILLINESS, wditer += GROUND_HILLINESS)
+    for (unsigned i = GROUND_HILLINESS; i < worldData.size(); i += GROUND_HILLINESS, wditer += GROUND_HILLINESS)
         worldData[i].groundHeight = (*wditer).groundHeight + (randGet() % 8 - 4);
 
     // create slopes from the points that were just defined, populate the rest of the WorldData structure
@@ -257,23 +218,22 @@ generate(unsigned int width)
         if ((*wditer).groundHeight && wditer + GROUND_HILLINESS < worldData.end())
                        // wditer + GROUND_HILLINESS can go out of bounds (invalid read)
             geninc = ((*(wditer + GROUND_HILLINESS)).groundHeight - (*wditer).groundHeight) / (float)GROUND_HILLINESS;
-        else
+        else {
             (*wditer).groundHeight = (*(wditer - 1)).groundHeight + geninc;
 
+            if ((*wditer).groundHeight < GROUND_HEIGHT_MINIMUM)
+                (*wditer).groundHeight = GROUND_HEIGHT_MINIMUM;
+            else if ((*wditer).groundHeight > GROUND_HEIGHT_MAXIMUM)
+                (*wditer).groundHeight = GROUND_HEIGHT_MAXIMUM;
+        }
+
         (*wditer).groundColor    = randGet() % 32 / 8;
         (*wditer).grassUnpressed = true;
         (*wditer).grassHeight[0] = (randGet() % 16) / 3 + 2;
         (*wditer).grassHeight[1] = (randGet() % 16) / 3 + 2;
 
-        // bound checks
-        if ((*wditer).groundHeight < GROUND_HEIGHT_MINIMUM)
-            (*wditer).groundHeight = GROUND_HEIGHT_MINIMUM;
-        else if ((*wditer).groundHeight > GROUND_HEIGHT_MAXIMUM)
-                       (*wditer).groundHeight = GROUND_HEIGHT_MAXIMUM;
-
                if((*wditer).groundHeight <= 0)
                        (*wditer).groundHeight = GROUND_HEIGHT_MINIMUM;
-
     }
 
     // define x-coordinate of world's leftmost 'line'
@@ -287,108 +247,18 @@ generate(unsigned int width)
        }
 }
 
-/**
- * Updates all entity and player coordinates with their velocities.
- *
- * Also handles music fading, although that could probably be placed elsewhere.
- */
-
-void World::
-update(Player *p, unsigned int delta)
-{
-    // update player coords
-       p->loc.y += p->vel.y                     * delta;
-       p->loc.x +=(p->vel.x * p->speed) * delta;
-
-       if (p->loc.y > 5000)
-        UserError("Too high for me m8.");
-
-       // update entity coords
-       for (auto &e : entity) {
-
-        // dont let structures move?
-               if (e->type != STRUCTURET && e->canMove) {
-                       e->loc.x += e->vel.x * delta;
-            e->loc.y += e->vel.y * delta;
-
-            // update boolean directions
-                       if (e->vel.x < 0)
-                e->left = true;
-                       else if (e->vel.x > 0)
-                e->left = false;
-               } else if (e->vel.y < 0)
-            e->loc.y += e->vel.y * delta;
-       }
-    // iterate through particles
-    particles.erase(std::remove_if(particles.begin(), particles.end(), [&delta](Particles &part){return part.kill(delta);}), particles.end());
-    for (auto part = particles.begin(); part != particles.end(); part++) {
-               if ((*part).canMove) {
-                       (*part).loc.y += (*part).vel.y * delta;
-                       (*part).loc.x += (*part).vel.x * delta;
-
-                       for (auto &b : build) {
-                               if (b->bsubtype == FOUNTAIN) {
-                                       if ((*part).loc.x >= b->loc.x && (*part).loc.x <= b->loc.x + b->width) {
-                                               if ((*part).loc.y <= b->loc.y + b->height * .25)
-                                                       particles.erase(part);
-
-                                       }
-                               }
-                       }
-               }
-       }
-
-    // handle music fades
-       if (ui::dialogImportant) {
-               //Mix_FadeOutMusic(2000);
-       } else if(!Mix_PlayingMusic())
-               Mix_FadeInMusic(bgmObj,-1,2000);
-}
-
-/**
- * Set the world's BGM.
- *
- * This will load a sound file to be played while the player is in this world.
- * If no file is found, no music should play.
- */
-
-void World::
-setBGM(std::string path)
-{
-       if(!path.empty())
-               bgmObj = Mix_LoadMUS((bgm = path).c_str());
-}
-
-/**
- * Toggle play/stop of the background music.
- *
- * If new music is to be played a crossfade will occur, otherwise... uhm.
- */
-
-void World::
-bgmPlay(World *prev) const
-{
-       if (prev) {
-               if (bgm != prev->bgm) {
-            // new world, new music
-                       Mix_FadeOutMusic(800);
-                       Mix_PlayMusic(bgmObj, -1);
-               }
-       } else {
-        // first call
-               Mix_FadeOutMusic(800);
-               Mix_PlayMusic(bgmObj, -1);
-       }
-}
-
 /**
  * The world draw function.
- *
  * This function will draw the background layers, entities, and player to the
  * screen.
  */
+void World::
+draw(Player *p)
+{
+    const ivec2 backgroundOffset = ivec2 {
+        (int)(SCREEN_WIDTH / 2), (int)(SCREEN_HEIGHT / 2)
+    };
 
-void World::draw(Player *p){
     // iterators
     int i, iStart, iEnd;
 
@@ -401,134 +271,105 @@ void World::draw(Player *p){
     // world width in pixels
        int width = worldData.size() * HLINE;
 
+    // used for alpha values of background textures
+    int alpha;
+
        // shade value for GLSL
-       float shadeAmbient = -worldShade / 50.0f + 0.5f; // -0.5f to 1.5f
-       if (shadeAmbient < 0)
-               shadeAmbient = 0;
-       else if (shadeAmbient > 0.9f)
-               shadeAmbient = 1;
+       float shadeAmbient = fmax(0, -worldShade / 50.0f + 0.5f); // 0 to 1.5f
 
-       /*
-     * Draw background images.
-     */
+       if (shadeAmbient > 0.9f)
+               shadeAmbient = 1.0f;
 
+       // draw background images.
        glEnable(GL_TEXTURE_2D);
 
        // the sunny wallpaper is faded with the night depending on tickCount
-
        bgTex->bind(0);
-    int alpha;
-    switch(weather) {
-    case WorldWeather::Snowy:
-        alpha = 150;
-        break;
-    case WorldWeather::Rain:
-        alpha = 0;
-        break;
+    switch (weather) {
+    case WorldWeather::Snowy : alpha = 150; break;
+    case WorldWeather::Rain  : alpha = 0;   break;
     default:
         alpha = 255 - worldShade * 4;
         break;
     }
-       safeSetColorA(255, 255, 255, alpha);
 
+       safeSetColorA(255, 255, 255, alpha);
        glBegin(GL_QUADS);
-               glTexCoord2i(0, 0); glVertex2i(offset.x - SCREEN_WIDTH/2-5, offset.y + SCREEN_HEIGHT/2);
-               glTexCoord2i(1, 0); glVertex2i(offset.x + SCREEN_WIDTH/2+5, offset.y + SCREEN_HEIGHT/2);
-               glTexCoord2i(1, 1); glVertex2i(offset.x + SCREEN_WIDTH/2+5, offset.y - SCREEN_HEIGHT/2);
-               glTexCoord2i(0, 1); glVertex2i(offset.x - SCREEN_WIDTH/2-5, offset.y - SCREEN_HEIGHT/2);
+               glTexCoord2i(0, 0); glVertex2i(offset.x - backgroundOffset.x - 5, offset.y + backgroundOffset.y);
+               glTexCoord2i(1, 0); glVertex2i(offset.x + backgroundOffset.x + 5, offset.y + backgroundOffset.y);
+               glTexCoord2i(1, 1); glVertex2i(offset.x + backgroundOffset.x + 5, offset.y - backgroundOffset.y);
+               glTexCoord2i(0, 1); glVertex2i(offset.x - backgroundOffset.x - 5, offset.y - backgroundOffset.y);
        glEnd();
 
        bgTex->bindNext();
        safeSetColorA(255, 255, 255, !alpha ? 255 : worldShade * 4);
-
        glBegin(GL_QUADS);
-        glTexCoord2i(0, 0); glVertex2i(offset.x - SCREEN_WIDTH/2-5, offset.y + SCREEN_HEIGHT/2);
-        glTexCoord2i(1, 0); glVertex2i(offset.x + SCREEN_WIDTH/2+5, offset.y + SCREEN_HEIGHT/2);
-        glTexCoord2i(1, 1); glVertex2i(offset.x + SCREEN_WIDTH/2+5, offset.y - SCREEN_HEIGHT/2);
-        glTexCoord2i(0, 1); glVertex2i(offset.x - SCREEN_WIDTH/2-5, offset.y - SCREEN_HEIGHT/2);
+        glTexCoord2i(0, 0); glVertex2i(offset.x - backgroundOffset.x - 5, offset.y + backgroundOffset.y);
+        glTexCoord2i(1, 0); glVertex2i(offset.x + backgroundOffset.x + 5, offset.y + backgroundOffset.y);
+        glTexCoord2i(1, 1); glVertex2i(offset.x + backgroundOffset.x + 5, offset.y - backgroundOffset.y);
+        glTexCoord2i(0, 1); glVertex2i(offset.x - backgroundOffset.x - 5, offset.y - backgroundOffset.y);
        glEnd();
 
        glDisable(GL_TEXTURE_2D);
 
        // draw the stars if the time deems it appropriate
-
-       //if ((((weather == WorldWeather::Dark) & (tickCount % DAY_CYCLE)) < DAY_CYCLE / 2)   ||
-       //    (((weather == WorldWeather::Sunny) & (tickCount % DAY_CYCLE)) > DAY_CYCLE * .75)){
        if (worldShade > 0) {
-
                safeSetColorA(255, 255, 255, 255 - (getRand() % 30 - 15));
 
-               for (i = 0; i < 100; i++) {
-                       glRectf(star[i].x + offset.x * .9,
-                                       star[i].y,
-                                       star[i].x + offset.x * .9 + HLINE,
-                                       star[i].y + HLINE
-                                       );
-               }
+        auto xcoord = offset.x * 0.9f;
+               for (auto &s : star)
+                       glRectf(s.x + xcoord, s.y, s.x + xcoord + HLINE, s.y + HLINE);
        }
 
        // draw remaining background items
-
        glEnable(GL_TEXTURE_2D);
 
        bgTex->bindNext();
        safeSetColorA(150 + shadeBackground * 2, 150 + shadeBackground * 2, 150 + shadeBackground * 2, 255);
-
-       glBegin(GL_QUADS);
+       glBegin(GL_QUADS); {
+        auto xcoord = width / 2 * -1 + offset.x * 0.85f;
                for (i = 0; i <= (int)(worldData.size() * HLINE / 1920); i++) {
-                       glTexCoord2i(0, 1); glVertex2i(width / 2 * -1 + (1920 * i) + offset.x * .85, GROUND_HEIGHT_MINIMUM);
-                       glTexCoord2i(1, 1); glVertex2i(width / 2 * -1 + (1920 * (i + 1)) + offset.x * .85, GROUND_HEIGHT_MINIMUM);
-                       glTexCoord2i(1, 0); glVertex2i(width / 2 * -1 + (1920 * (i + 1)) + offset.x * .85, GROUND_HEIGHT_MINIMUM + 1080);
-                       glTexCoord2i(0, 0); glVertex2i(width / 2 * -1 + (1920 * i) + offset.x * .85, GROUND_HEIGHT_MINIMUM + 1080);
+                       glTexCoord2i(0, 1); glVertex2i(1920 * i       + xcoord, GROUND_HEIGHT_MINIMUM);
+            glTexCoord2i(1, 1); glVertex2i(1920 * (i + 1) + xcoord, GROUND_HEIGHT_MINIMUM);
+                       glTexCoord2i(1, 0); glVertex2i(1920 * (i + 1) + xcoord, GROUND_HEIGHT_MINIMUM + 1080);
+                       glTexCoord2i(0, 0); glVertex2i(1920 * i       + xcoord, GROUND_HEIGHT_MINIMUM + 1080);
                }
-       glEnd();
+       glEnd();
 
        for (i = 0; i < 4; i++) {
                bgTex->bindNext();
-               safeSetColorA(bgDraw[i][0] + shadeBackground * 2, bgDraw[i][0] + shadeBackground * 2, bgDraw[i][0] + shadeBackground * 2, bgDraw[i][1]);
-
-               glBegin(GL_QUADS);
-                       for(int j = worldStart; j <= -worldStart; j += 600){
-                               glTexCoord2i(0, 1); glVertex2i(j        + offset.x * bgDraw[i][2], GROUND_HEIGHT_MINIMUM);
-                               glTexCoord2i(1, 1); glVertex2i((j + 600) + offset.x * bgDraw[i][2], GROUND_HEIGHT_MINIMUM);
-                               glTexCoord2i(1, 0); glVertex2i((j + 600) + offset.x * bgDraw[i][2], GROUND_HEIGHT_MINIMUM + 400);
-                               glTexCoord2i(0, 0); glVertex2i(j        + offset.x * bgDraw[i][2], GROUND_HEIGHT_MINIMUM + 400);
+               safeSetColorA(bgDraw[i][0] + shadeBackground * 2,
+                      bgDraw[i][0] + shadeBackground * 2,
+                      bgDraw[i][0] + shadeBackground * 2,
+                      bgDraw[i][1]
+                      );
+               glBegin(GL_QUADS); {
+            auto xcoord = offset.x * bgDraw[i][2];
+                       for (int j = worldStart; j <= -worldStart; j += 600) {
+                glTexCoord2i(0, 1); glVertex2i(j       + xcoord, GROUND_HEIGHT_MINIMUM);
+                               glTexCoord2i(1, 1); glVertex2i(j + 600 + xcoord, GROUND_HEIGHT_MINIMUM);
+                               glTexCoord2i(1, 0); glVertex2i(j + 600 + xcoord, GROUND_HEIGHT_MINIMUM + 400);
+                               glTexCoord2i(0, 0); glVertex2i(j       + xcoord, GROUND_HEIGHT_MINIMUM + 400);
                        }
-               glEnd();
+               glEnd();
        }
 
        glDisable(GL_TEXTURE_2D);
 
-       // draw black under backgrounds
-
+       // draw black under backgrounds (y-coordinate)
        glColor3ub(0, 0, 0);
        glRectf(worldStart, GROUND_HEIGHT_MINIMUM, -worldStart, 0);
 
-       pOffset = (offset.x + p->width / 2 - worldStart) / HLINE;
-
-    /*
-     * Prepare for world ground drawing.
-     */
-
-       // only draw world within player vision
-
-       if ((iStart = pOffset - (SCREEN_WIDTH / 2 / HLINE) - GROUND_HILLINESS) < 0)
-               iStart = 0;
-
-       if ((iEnd = pOffset + (SCREEN_WIDTH / 2 / HLINE) + GROUND_HILLINESS + HLINE) > (int)worldData.size())
-               iEnd = worldData.size();
-       else if (iEnd < GROUND_HILLINESS)
-               iEnd = GROUND_HILLINESS;
-
        // draw particles and buildings
-
     glActiveTexture(GL_TEXTURE0);
     glBindTexture(GL_TEXTURE_2D, colorIndex);
-
     glUniform1i(glGetUniformLocation(shaderProgram, "sampler"), 0);
     glUseProgram(shaderProgram);
 
-    std::for_each(particles.begin(), particles.end(), [](Particles part) { if (part.behind) part.draw(); });
+    std::for_each(std::begin(particles), std::end(particles), [](Particles &p) {
+        if (p.behind)
+            p.draw();
+    });
 
     glUseProgram(0);
 
@@ -544,27 +385,26 @@ void World::draw(Player *p){
         b->draw();
     }
 
-       // draw light elements?
-
-       glEnable(GL_TEXTURE_2D);
-
-       glActiveTexture(GL_TEXTURE0);
-       bgTex->bindNext();
-
-    for(auto &l : light){
-        if(l.belongsTo){
+    for (auto &l : light) {
+        if (l.belongsTo) {
             l.loc.x = l.following->loc.x + SCREEN_WIDTH/2;
             l.loc.y = l.following->loc.y;
         }
-        if(l.flame){
+
+        if (l.flame) {
             l.fireFlicker = .9+((rand()%2)/10.0f);
             l.fireLoc.x = l.loc.x + (rand()%2-1)*3;
             l.fireLoc.y = l.loc.y + (rand()%2-1)*3;
-        }else{
+        } else {
             l.fireFlicker = 1.0f;
         }
     }
 
+    // draw light elements
+    glEnable(GL_TEXTURE_2D);
+    glActiveTexture(GL_TEXTURE0);
+    bgTex->bindNext();
+
     std::unique_ptr<GLfloat[]> pointArrayBuf = std::make_unique<GLfloat[]> (2 * (light.size()));
        auto pointArray = pointArrayBuf.get();
     GLfloat flameArray[64];
@@ -598,101 +438,90 @@ void World::draw(Player *p){
         glUniform1fv(glGetUniformLocation(shaderProgram,"fireFlicker"), light.size(),flameArray);
        }
 
-    /*
-     * Draw the dirt.
-     */
-
-       glBegin(GL_QUADS);
+    // get the line that the player is currently standing on
+    pOffset = (offset.x + p->width / 2 - worldStart) / HLINE;
 
-        // faulty
-        /*glTexCoord2i(0 ,0);glVertex2i(pOffset - (SCREEN_WIDTH / 1.5),0);
-        glTexCoord2i(64,0);glVertex2i(pOffset + (SCREEN_WIDTH / 1.5),0);
-        glTexCoord2i(64,1);glVertex2i(pOffset + (SCREEN_WIDTH / 1.5),GROUND_HEIGHT_MINIMUM);
-        glTexCoord2i(0 ,1);glVertex2i(pOffset - (SCREEN_WIDTH / 1.5),GROUND_HEIGHT_MINIMUM);*/
+    // only draw world within player vision
+    iStart = (int)fmax(pOffset - (SCREEN_WIDTH / 2 / HLINE) - GROUND_HILLINESS, 0);
+    iEnd   = (int)fmin(pOffset + (SCREEN_WIDTH / 2 / HLINE) + GROUND_HILLINESS + HLINE, worldData.size());
+    iEnd = (int)fmax(iEnd, GROUND_HILLINESS);
 
+    // draw the dirt
+       glBegin(GL_QUADS);
+        //std::for_each(std::begin(worldData) + iStart, std::begin(worldData) + iEnd, [&](WorldData wd) {
         for (i = iStart; i < iEnd; i++) {
-            if (worldData[i].groundHeight <= 0) {
-                worldData[i].groundHeight = GROUND_HEIGHT_MINIMUM - 1;
+            auto wd = worldData[i];
+            if (wd.groundHeight <= 0) {
+                wd.groundHeight = GROUND_HEIGHT_MINIMUM - 1;
                 glColor4ub(0, 0, 0, 255);
-            } else
+            } else {
                 safeSetColorA(150, 150, 150, 255);
+            }
 
-            glTexCoord2i(0, 0); glVertex2i(worldStart + i * HLINE         , worldData[i].groundHeight - GRASS_HEIGHT);
-            glTexCoord2i(1, 0); glVertex2i(worldStart + i * HLINE + HLINE , worldData[i].groundHeight - GRASS_HEIGHT);
-
-            glTexCoord2i(1, (int)(worldData[i].groundHeight / 64) + worldData[i].groundColor); glVertex2i(worldStart + i * HLINE + HLINE, 0);
-            glTexCoord2i(0, (int)(worldData[i].groundHeight / 64) + worldData[i].groundColor); glVertex2i(worldStart + i * HLINE             , 0);
-
-            if (worldData[i].groundHeight == GROUND_HEIGHT_MINIMUM - 1)
-                worldData[i].groundHeight = 0;
-        }
+            int ty = wd.groundHeight / 64 + wd.groundColor;
+            glTexCoord2i(0, 0);  glVertex2i(worldStart + i * HLINE         , wd.groundHeight - GRASS_HEIGHT);
+            glTexCoord2i(1, 0);  glVertex2i(worldStart + i * HLINE + HLINE , wd.groundHeight - GRASS_HEIGHT);
+            glTexCoord2i(1, ty); glVertex2i(worldStart + i * HLINE + HLINE, 0);
+            glTexCoord2i(0, ty); glVertex2i(worldStart + i * HLINE           , 0);
 
+            if (wd.groundHeight == GROUND_HEIGHT_MINIMUM - 1)
+                wd.groundHeight = 0;
+        }//);
        glEnd();
 
        glUseProgram(0);
        glDisable(GL_TEXTURE_2D);
 
-       /*
-        *      Draw the grass/the top of the ground.
-        */
-
+       // draw the grass
        glEnable(GL_TEXTURE_2D);
-
        glActiveTexture(GL_TEXTURE0);
        bgTex->bindNext();
-
        glUseProgram(shaderProgram);
        glUniform1i(glGetUniformLocation(shaderProgram, "sampler"), 0);
+    safeSetColorA(255, 255, 255, 255);
 
-       float cgh[2];
-       for (i = iStart; i < iEnd - GROUND_HILLINESS; i++) {
-
-               // load the current line's grass values
-               if (worldData[i].groundHeight)
-                       memcpy(cgh, worldData[i].grassHeight, 2 * sizeof(float));
-               else
-                       memset(cgh, 0 , 2 * sizeof(float));
+       for (i = iStart; i < iEnd; i++) {
+        auto wd = worldData[i];
+        auto gh = wd.grassHeight;
 
                // flatten the grass if the player is standing on it.
-               if(!worldData[i].grassUnpressed){
-                       cgh[0] /= 4;
-                       cgh[1] /= 4;
+               if (!worldData[i].grassUnpressed) {
+                       gh[0] /= 4;
+                       gh[1] /= 4;
                }
 
                // actually draw the grass.
-
-               safeSetColorA(255, 255, 255, 255);
-
-               glBegin(GL_QUADS);
-                       glTexCoord2i(0, 0); glVertex2i(worldStart + i * HLINE            , worldData[i].groundHeight + cgh[0]);
-                       glTexCoord2i(1, 0); glVertex2i(worldStart + i * HLINE + HLINE / 2, worldData[i].groundHeight + cgh[0]);
-                       glTexCoord2i(1, 1); glVertex2i(worldStart + i * HLINE + HLINE / 2, worldData[i].groundHeight - GRASS_HEIGHT);
-                       glTexCoord2i(0, 1); glVertex2i(worldStart + i * HLINE               , worldData[i].groundHeight - GRASS_HEIGHT);
-                       glTexCoord2i(0, 0); glVertex2i(worldStart + i * HLINE + HLINE / 2, worldData[i].groundHeight + cgh[1]);
-                       glTexCoord2i(1, 0); glVertex2i(worldStart + i * HLINE + HLINE    , worldData[i].groundHeight + cgh[1]);
-                       glTexCoord2i(1, 1); glVertex2i(worldStart + i * HLINE + HLINE    , worldData[i].groundHeight - GRASS_HEIGHT);
-                       glTexCoord2i(0, 1); glVertex2i(worldStart + i * HLINE + HLINE / 2, worldData[i].groundHeight - GRASS_HEIGHT);
-               glEnd();
+        if (wd.groundHeight) {
+               glBegin(GL_QUADS);
+                       glTexCoord2i(0, 0); glVertex2i(worldStart + i * HLINE            , wd.groundHeight + gh[0]);
+                       glTexCoord2i(1, 0); glVertex2i(worldStart + i * HLINE + HLINE / 2, wd.groundHeight + gh[0]);
+                       glTexCoord2i(1, 1); glVertex2i(worldStart + i * HLINE + HLINE / 2, wd.groundHeight - GRASS_HEIGHT);
+                       glTexCoord2i(0, 1); glVertex2i(worldStart + i * HLINE                , wd.groundHeight - GRASS_HEIGHT);
+                       glTexCoord2i(0, 0); glVertex2i(worldStart + i * HLINE + HLINE / 2, wd.groundHeight + gh[1]);
+                       glTexCoord2i(1, 0); glVertex2i(worldStart + i * HLINE + HLINE    , wd.groundHeight + gh[1]);
+                       glTexCoord2i(1, 1); glVertex2i(worldStart + i * HLINE + HLINE    , wd.groundHeight - GRASS_HEIGHT);
+                       glTexCoord2i(0, 1); glVertex2i(worldStart + i * HLINE + HLINE / 2, wd.groundHeight - GRASS_HEIGHT);
+               glEnd();
+        }
        }
 
        glUseProgram(0);
        glDisable(GL_TEXTURE_2D);
 
-       /*
-     * Draw remaining entities.
-     */
-
-
+       // draw particles
     glActiveTexture(GL_TEXTURE0);
     glBindTexture(GL_TEXTURE_2D, colorIndex);
-
     glUniform1i(glGetUniformLocation(shaderProgram, "sampler"), 0);
     glUseProgram(shaderProgram);
 
-       std::for_each(particles.begin(), particles.end(), [](Particles part) { if (!part.behind) part.draw(); });
+       for (auto &p : particles) {
+        if (!p.behind)
+            p.draw();
+    }
 
     glUseProgram(0);
 
+    // draw remaining entities
        for (auto &n : npc) {
                if (n->type != MERCHT)
             n->draw();
@@ -704,108 +533,76 @@ void World::draw(Player *p){
        for (auto &o : object)
                o.draw();
 
-    /*
-     * Handle grass-squishing.
-     */
-
-       // calculate the line that the player is on
-       int ph = (p->loc.x + p->width / 2 - worldStart) / HLINE;
-
        // flatten grass under the player if the player is on the ground
        if (p->ground) {
-               for (i = 0; i < (int)(worldData.size() - GROUND_HILLINESS); i++)
-                       worldData[i].grassUnpressed = !(i < ph + 6 && i > ph - 6);
+               for (i = 0; i < (int)worldData.size(); i++)
+                       worldData[i].grassUnpressed = !(i < pOffset + 6 && i > pOffset - 6);
        } else {
-               for (i = 0; i < (int)(worldData.size() - GROUND_HILLINESS); i++)
+               for (i = 0; i < (int)worldData.size(); i++)
                        worldData[i].grassUnpressed = true;
        }
 
-       /*
-     * Draw the player.
-     */
-
+    // draw the player
        p->draw();
 }
 
 /**
  * Handles physics and such for a single entity.
- *
  * This function is kept private, as World::detect() should be used instead to
  * handle stuffs for all entities at once.
  */
-
 void World::
 singleDetect(Entity *e)
 {
        std::string killed;
-       unsigned int i,j;
+       unsigned int i;
        int l;
 
-       /*
-        *      Kill any dead entities.
-       */
-
+       // kill dead entities
        if (e->alive && e->health <= 0) {
+        // die
         e->alive = false;
         e->health = 0;
+
+        // delete the entity
                for (i = 0; i < entity.size(); i++) {
                        if (entity[i] == e){
                                switch (e->type) {
                                case STRUCTURET:
                                        killed = "structure";
-                                       for(j=0;j<build.size();j++){
-                                               if(build[j]==e){
-                                                       delete build[j];
-                                                       build.erase(build.begin()+j);
-                                                       break;
-                                               }
-                                       }
-                                       break;
-                               case NPCT:
+                    build.erase(std::find(std::begin(build), std::end(build), e));
+                    break;
+                case NPCT:
                                        killed = "NPC";
-                                       for(j=0;j<npc.size();j++){
-                                               if(npc[j]==e){
-                                                       delete npc[j];
-                                                       npc.erase(npc.begin()+j);
-                                                       break;
-                                               }
-                                       }
+                                       npc.erase(std::find(std::begin(npc), std::end(npc), e));
                                        break;
                                case MOBT:
                                        killed = "mob";
-                                       /*for(j=0;j<mob.size();j++){
-                                               if(mob[j]==e){
-                                                       delete mob[j];
-                                                       mob.erase(mob.begin()+j);
-                                                       break;
-                                               }
-                                       }*/
+                    // TODO
                                        break;
                                case OBJECTT:
                                        killed = "object";
-                    for (auto o = std::begin(object); o != std::end(object); o++) {
-                        if (&(*o) == e) {
-                            object.erase(o);
-                            break;
-                        }
-                    }
+                    object.erase(std::find(std::begin(object), std::end(object), *Objectp(e)));
                                        break;
                                default:
                                        break;
                                }
+
                                std::cout << "Killed a " << killed << "..." << std::endl;
-                               entity.erase(entity.begin()+i);
+                               entity.erase(entity.begin() + i);
                                return;
                        }
                }
+
+        // exit on player death
                std::cout << "RIP " << e->name << "." << std::endl;
                exit(0);
        }
 
-       // handle only living entities
+       // collision / gravity: handle only living entities
        if (e->alive) {
 
-        // forced movement gravity
+        // forced movement gravity (sword hits)
         if (e->forcedMove) {
             if (e->vel.x > .0005 || e->vel.x < -.0005)
                 e->vel.x *= .6;
@@ -813,25 +610,21 @@ singleDetect(Entity *e)
                 e->forcedMove = false;
         }
 
-               if (e->type == MOBT && Mobp(e)->subtype == MS_TRIGGER)
+               if (e->subtype == MS_TRIGGER)
                        return;
 
                // calculate the line that this entity is currently standing on
-               l = (e->loc.x + e->width / 2 - worldStart) / HLINE;
-               if (l < 0)
-            l = 0;
-               i = l;
-               if (i > lineCount - 1)
-            i = lineCount - 1;
+               l = (int)fmax((e->loc.x + e->width / 2 - worldStart) / HLINE, 0);
+               l = (int)fmin(l, lineCount - 1);
 
                // if the entity is under the world/line, pop it back to the surface
-               if (e->loc.y < worldData[i].groundHeight) {
+               if (e->loc.y < worldData[l].groundHeight) {
             int dir = e->vel.x < 0 ? -1 : 1;
-            if (i + (dir * 2) < worldData.size() && worldData[i + (dir * 2)].groundHeight - 30 > worldData[i + dir].groundHeight) {
-                e->loc.x -= (PLAYER_SPEED_CONSTANT + 2.7) * e->speed * 2 * dir;
+            if (l + (dir * 2) < (int)worldData.size() && worldData[l + (dir * 2)].groundHeight - 30 > worldData[l + dir].groundHeight) {
+                e->loc.x -= (PLAYER_SPEED_CONSTANT + 2.7f) * e->speed * 2 * dir;
                 e->vel.x = 0;
             } else {
-                e->loc.y = worldData[i].groundHeight - .001 * deltaTime;
+                e->loc.y = worldData[l].groundHeight - 0.001f * deltaTime;
                        e->ground = true;
                        e->vel.y = 0;
             }
@@ -840,26 +633,23 @@ singleDetect(Entity *e)
 
         // handle gravity if the entity is above the line
         else {
-
                        if (e->type == STRUCTURET) {
-                               e->loc.y = worldData[i].groundHeight;
+                               e->loc.y = worldData[l].groundHeight;
                                e->vel.y = 0;
                                e->ground = true;
                                return;
-                       } else if (e->vel.y > -2)
+                       } else if (e->vel.y > -2) {
                 e->vel.y -= GRAVITY_CONSTANT * deltaTime;
+            }
                }
 
-               /*
-                *      Insure that the entity doesn't fall off either edge of the world.
-               */
-
-               if(e->loc.x < worldStart){                                                                                              // Left bound
-                       e->vel.x=0;
-                       e->loc.x=(float)worldStart + HLINE / 2;
-               }else if(e->loc.x + e->width + HLINE > worldStart + worldStart * -2){   // Right bound
-                       e->vel.x=0;
-                       e->loc.x=worldStart + worldStart * -2 - e->width - HLINE;
+               // insure that the entity doesn't fall off either edge of the world.
+               if (e->loc.x < worldStart) {
+                       e->vel.x = 0;
+                       e->loc.x = worldStart + HLINE / 2;
+               } else if (e->loc.x + e->width + HLINE > worldStart + worldStart * -2) {
+                       e->vel.x = 0;
+                       e->loc.x = worldStart + worldStart * -2 - e->width - HLINE;
                }
        }
 }
@@ -871,7 +661,6 @@ singleDetect(Entity *e)
  * currently in a vector of this world. Particles and village entrance/exiting
  * are also handled here.
  */
-
 void World::
 detect(Player *p)
 {
@@ -886,16 +675,9 @@ detect(Player *p)
 
     // handle particles
        for (auto &part : particles) {
-
                // get particle's current world line
-               l = (part.loc.x + part.width / 2 - worldStart) / HLINE;
-
-               if (l < 0)
-                       l = 0;
-
-               if (l > (int)(lineCount - 1))
-                       l = lineCount - 1;
-
+               l = (int)fmax((part.loc.x + part.width / 2 - worldStart) / HLINE, 0);
+        l = (int)fmin(lineCount - 1, l);
                part.update(GRAVITY_CONSTANT, worldData[l].groundHeight);
        }
 
@@ -913,11 +695,9 @@ detect(Player *p)
                                                        { 0, 0, 255 },                                                                          // RGB color
                                                        2500                                                                                            // duration (ms)
                                                        );
-
                                particles.back().fountain = true;
                        }
                        break;
-
                case FIRE_PIT:
                        for(unsigned int r = (randGet() % 20) + 11; r--;) {
                                addParticle(randGet() % (int)(b->width / 2) + b->loc.x + b->width / 4,  // x
@@ -929,12 +709,10 @@ detect(Player *p)
                                                        { 255, 0, 0 },                                                                                          // RGB color
                                                        400                                                                                                                     // duration (ms)
                                                        );
-
                                particles.back().gravity = false;
                                particles.back().behind  = true;
                        }
                        break;
-
                default:
                        break;
                }
@@ -942,175 +720,352 @@ detect(Player *p)
 
        // draws the village welcome message if the player enters the village bounds
        for (auto &v : village) {
-               if (p->loc.x > v.start.x && p->loc.x < v.end.x) {
-                       if (!v.in) {
-                               ui::passiveImportantText(5000, "Welcome to %s", v.name.c_str());
-                               v.in = true;
-                       }
-               } else
+               if (p->loc.x > v.start.x && p->loc.x < v.end.x && !v.in) {
+                       ui::passiveImportantText(5000, "Welcome to %s", v.name.c_str());
+                       v.in = true;
+               } else {
                        v.in = false;
+        }
        }
 }
 
-void World::addStructure(BUILD_SUB sub, float x,float y, std::string tex, std::string inside){
-       build.push_back(new Structures());
-       build.back()->inWorld = this;
-       build.back()->textureLoc = tex;
-
-       build.back()->spawn(sub,x,y);
-
-       build.back()->inside = inside;
-
-       entity.push_back(build.back());
-}
-
-Village *World::
-addVillage(std::string name, World *world)
+/**
+ * Updates all entity and player coordinates with their velocities.
+ * Also handles music fading, although that could probably be placed elsewhere.
+ */
+void World::
+update(Player *p, unsigned int delta)
 {
-    village.emplace_back(name.c_str(), world);
-    return &village.back();
-}
-
-void World::addMob(int t,float x,float y){
-       mob.push_back(new Mob(t));
-       mob.back()->spawn(x,y);
-
-       entity.push_back(mob.back());
-}
-
-void World::addMob(int t,float x,float y,void (*hey)(Mob *)){
-       mob.push_back(new Mob(t));
-       mob.back()->spawn(x,y);
-       mob.back()->hey = hey;
-
-       entity.push_back(mob.back());
-}
-
-void World::addNPC(float x,float y){
-       npc.push_back(new NPC());
-       npc.back()->spawn(x,y);
-
-       entity.push_back(npc.back());
-}
-
-void World::addMerchant(float x, float y, bool housed){
-       merchant.push_back(new Merchant());
-       merchant.back()->spawn(x,y);
-
-    if (housed)
-        merchant.back()->inside = build.back();
+    // update player coords
+       p->loc.y += p->vel.y                     * delta;
+       p->loc.x +=(p->vel.x * p->speed) * delta;
 
-       npc.push_back(merchant.back());
-       entity.push_back(npc.back());
-}
+    // handle high-ness
+       if (p->loc.y > 5000)
+        UserError("Too high for me m8.");
 
-void World::addObject(std::string in, std::string p, float x, float y){
-       object.emplace_back(in, p);
-       object.back().spawn(x, y);
+       // update entity coords
+       for (auto &e : entity) {
+        // dont let structures move?
+               if (e->type != STRUCTURET && e->canMove) {
+                       e->loc.x += e->vel.x * delta;
+            e->loc.y += e->vel.y * delta;
 
-       entity.push_back(&object.back());
-}
+            // update boolean directions
+            e->left = e->vel.x ? (e->vel.x < 0) : e->left;
+               } else if (e->vel.y < 0) {
+            e->loc.y += e->vel.y * delta;
+        }
+       }
+    // iterate through particles
+    particles.erase(std::remove_if(particles.begin(), particles.end(), [&delta](Particles &part){
+                        return part.kill(delta);
+                    }),
+                    particles.end());
 
-void World::
-addParticle(float x, float y, float w, float h, float vx, float vy, Color color, int d)
-{
-       particles.emplace_back(x, y, w, h, vx, vy, color, d);
-       particles.back().canMove = true;
-}
+    for (auto part = particles.begin(); part != particles.end(); part++) {
+        auto pa = *part;
+
+               if (pa.canMove) {
+                       (*part).loc.y += pa.vel.y * delta;
+                       (*part).loc.x += pa.vel.x * delta;
+
+            if (std::any_of(std::begin(build), std::end(build), [pa](Structures *s) {
+                    return (s->bsubtype == FOUNTAIN) &&
+                           (pa.loc.x >= s->loc.x) && (pa.loc.x <= s->loc.x + s->width) &&
+                           (pa.loc.y <= s->loc.y + s->height * 0.25f);
+                })) {
+                particles.erase(part);
+            }
+               }
+       }
 
-void World::
-addParticle(float x, float y, float w, float h, float vx, float vy, Color color, int d, unsigned char flags)
-{
-       particles.emplace_back(x, y, w, h, vx, vy, color, d);
-       particles.back().canMove = true;
-    particles.back().gravity = flags & (1 << 0);
-    particles.back().bounce  = flags & (1 << 1);
+    // handle music fades
+       if (!Mix_PlayingMusic())
+               Mix_FadeInMusic(bgmObj, -1, 2000);
 }
 
-void World::
-addLight(vec2 loc, Color color)
+/**
+ * Get's the world's width in pixels.
+ */
+int World::
+getTheWidth(void) const
 {
-       if (light.size() < 64)
-        light.push_back(Light(loc, color, 1));
+       return (worldStart * -2);
 }
 
+/**
+ * Get a pointer to the most recently created light.
+ * Meant to be non-constant.
+ */
 Light *World::
 getLastLight(void)
 {
     return &light.back();
 }
 
+/**
+ * Get a pointer to the most recently created mob.
+ * Meant to be non-constant.
+ */
 Mob *World::
 getLastMob(void)
 {
     return mob.back();
 }
 
+/**
+ * Get the interactable entity that is closest to the entity provided.
+ */
 Entity *World::
-getNearInteractable(Entity e)
+getNearInteractable(Entity &e)
 {
-    for (auto &n : entity) {
-        if (n->type == MOBT || n->type == NPCT || n->type == MERCHT) {
-            if (e.isNear(*n) && (e.left ? n->loc.x < e.loc.x : n->loc.x > e.loc.x))
-                return n;
-        }
-    }
+    auto n = std::find_if(std::begin(entity), std::end(entity), [&](Entity *&a) {
+        return ((a->type == MOBT) || (a->type == NPCT) || a->type == MERCHT) &&
+               e.isNear(*a) && (e.left ? (a->loc.x < e.loc.x) : (a->loc.x > e.loc.x));
+    });
 
-    return nullptr;
+    return n == std::end(entity) ? nullptr : *n;
 }
 
+/**
+ * Get the file path for the `index`th building.
+ */
 std::string World::
 getSTextureLocation(unsigned int index) const
 {
-    if (index > sTexLoc.size())
-        return "";
-
-    return sTexLoc[ index ];
+    return index < sTexLoc.size() ? sTexLoc[ index ] : "";
 }
 
+/**
+ * Get the coordinates of the `index`th building, with -1 meaning the last building.
+ */
 vec2 World::
 getStructurePos(int index)
 {
     if (index < 0)
         return build.back()->loc;
     else if ((unsigned)index >= build.size())
-        return vec2{0, 0};
+        return vec2 {0, 0};
 
     return build[index]->loc;
 }
 
+/**
+ * Saves world data to a file.
+ */
+void World::save(void){
+       std::string data;
+       std::string save = currentXML + ".dat";
+       std::ofstream out (save, std::ios::out | std::ios::binary);
+
+       std::cout << "Saving to " << save << " ..." << '\n';
+
+    // save npcs
+       for (auto &n : npc) {
+               data.append(std::to_string(n->dialogIndex) + "\n");
+               data.append(std::to_string((int)n->loc.x) + "\n");
+               data.append(std::to_string((int)n->loc.y) + "\n");
+       }
+
+    // save structures
+       for (auto &b : build) {
+               data.append(std::to_string((int)b->loc.x) + "\n");
+               data.append(std::to_string((int)b->loc.y) + "\n");
+       }
+
+    // save mobs
+       for (auto &m : mob) {
+               data.append(std::to_string((int)m->loc.x) + "\n");
+               data.append(std::to_string((int)m->loc.y) + "\n");
+               data.append(std::to_string((int)m->alive) + "\n");
+       }
+
+    // wrap up
+       data.append("dOnE\0");
+       out.write(data.data(), data.size());
+       out.close();
+}
+
+void World::load(void){
+       std::string save, data, line;
+       const char *filedata;
+
+       save = currentXML + ".dat";
+       filedata = readFile(save.c_str());
+       data = filedata;
+       std::istringstream iss (data);
+
+       for(auto &n : npc){
+               std::getline(iss,line);
+               if(line == "dOnE")return;
+               if((n->dialogIndex = std::stoi(line)) != 9999)
+                       n->addAIFunc(commonAIFunc,false);
+               else n->clearAIFunc();
+
+               std::getline(iss,line);
+               if(line == "dOnE")return;
+               n->loc.x = std::stoi(line);
+               std::getline(iss,line);
+               if(line == "dOnE")return;
+               n->loc.y = std::stoi(line);
+       }
+
+       for(auto &b : build){
+               std::getline(iss,line);
+               if(line == "dOnE")return;
+               b->loc.x = std::stoi(line);
+               std::getline(iss,line);
+               if(line == "dOnE")return;
+               b->loc.y = std::stoi(line);
+       }
+
+       for(auto &m : mob){
+               std::getline(iss,line);
+               if(line == "dOnE")return;
+               m->loc.x = std::stoi(line);
+               std::getline(iss,line);
+               if(line == "dOnE")return;
+               m->loc.y = std::stoi(line);
+               std::getline(iss,line);
+               if(line == "dOnE")return;
+               m->alive = std::stoi(line);
+       }
+
+       while(std::getline(iss,line)){
+               if(line == "dOnE")
+                       break;
+       }
+
+       delete[] filedata;
+}
+
+/**
+ * Toggle play/stop of the background music.
+ * If new music is to be played a crossfade will occur, otherwise... uhm.
+ */
+void World::
+bgmPlay(World *prev) const
+{
+       if (prev) {
+        if (bgm != prev->bgm) {
+                   // new world, new music
+                   Mix_FadeOutMusic(800);
+                   Mix_PlayMusic(bgmObj, -1);
+        }
+        // sucks to be here
+       } else {
+        // first call
+               Mix_FadeOutMusic(800);
+               Mix_PlayMusic(bgmObj, -1);
+       }
+}
+
+/**
+ * Set the world's BGM.
+ * This will load a sound file to be played while the player is in this world.
+ * If no file is found, no music should play.
+ */
+void World::
+setBGM(std::string path)
+{
+       if (!path.empty())
+               bgmObj = Mix_LoadMUS((bgm = path).c_str());
+}
+
+/**
+ * Sets the desired theme for the world's background.
+ * The images chosen for the background layers are selected depending on the
+ * world's background type.
+ */
+void World::
+setBackground(WorldBGType bgt)
+{
+    // load textures with a limit check
+       switch ((bgType = bgt)) {
+       case WorldBGType::Forest:
+               bgTex = new Texturec(bgFiles);
+               break;
+       case WorldBGType::WoodHouse:
+               bgTex = new Texturec(bgFilesIndoors);
+               break;
+    default:
+        UserError("Invalid world background type");
+        break;
+       }
+}
+
+/**
+ * Sets the world's style.
+ * The world's style will determine what sprites are used for things like\
+ * generic structures.
+ */
+void World::
+setStyle(std::string pre)
+{
+    // get folder prefix
+       std::string prefix = pre.empty() ? "assets/style/classic/" : pre;
+
+    for_each(std::begin(buildPaths), std::end(buildPaths), [this, prefix](std::string s){
+        sTexLoc.push_back(prefix + s);
+    });
+
+    prefix += "bg/";
+
+    for_each(std::begin(bgPaths[0]), std::end(bgPaths[0]), [this, prefix](std::string s){
+        bgFiles.push_back(prefix + s);
+    });
+    for_each(std::begin(bgPaths[1]), std::end(bgPaths[1]), [this, prefix](std::string s){
+        bgFilesIndoors.push_back(prefix + s);
+    });
+}
+
+/**
+ * Pretty self-explanatory.
+ */
 std::string World::
 setToLeft(std::string file)
 {
     return (toLeft = file);
 }
 
+/**
+ * Pretty self-explanatory.
+ */
 std::string World::
 setToRight(std::string file)
 {
        return (toRight = file);
 }
 
+/**
+ * Pretty self-explanatory.
+ */
 std::string World::
 getToLeft(void) const
 {
     return toLeft;
 }
 
+/**
+ * Pretty self-explanatory.
+ */
 std::string World::
 getToRight(void) const
 {
     return toRight;
 }
 
+/**
+ * Attempts to go to the left world, returning either that world or itself.
+ */
 World *World::
 goWorldLeft(Player *p)
 {
        World *tmp;
 
     // check if player is at world edge
-       if(!toLeft.empty() && p->loc.x < worldStart + HLINE * 15.0f) {
-
+       if (!toLeft.empty() && p->loc.x < worldStart + HLINE * 15.0f) {
         // load world (`toLeft` conditional confirms existance)
            tmp = loadWorldFromPtr(currentWorldToLeft);
 
@@ -1124,24 +1079,9 @@ goWorldLeft(Player *p)
        return this;
 }
 
-bool World::
-goWorldLeft(NPC *e)
-{
-       // check if entity is at world edge
-       if(!toLeft.empty() && e->loc.x < worldStart + HLINE * 15.0f) {
-
-        currentWorldToLeft->addNPC(e->loc.x,e->loc.y);
-        e->alive = false;
-
-               currentWorldToLeft->npc.back()->loc.x = 0;
-               currentWorldToLeft->npc.back()->loc.y = GROUND_HEIGHT_MAXIMUM;
-
-               return true;
-       }
-
-       return false;
-}
-
+/**
+ * Attempts to go to the right world, returning either that world or itself.
+ */
 World *World::
 goWorldRight(Player *p)
 {
@@ -1159,6 +1099,29 @@ goWorldRight(Player *p)
        return this;
 }
 
+/**
+ * Acts like goWorldLeft(), but takes an NPC; returning true on success.
+ */
+bool World::
+goWorldLeft(NPC *e)
+{
+       // check if entity is at world edge
+       if(!toLeft.empty() && e->loc.x < worldStart + HLINE * 15.0f) {
+        currentWorldToLeft->addNPC(e->loc.x,e->loc.y);
+        e->alive = false;
+
+               currentWorldToLeft->npc.back()->loc.x = 0;
+               currentWorldToLeft->npc.back()->loc.y = GROUND_HEIGHT_MAXIMUM;
+
+               return true;
+       }
+
+       return false;
+}
+
+/**
+ * Attempts to enter a building that the player is standing in front of.
+ */
 World *World::
 goInsideStructure(Player *p)
 {
@@ -1167,21 +1130,20 @@ goInsideStructure(Player *p)
 
        if (inside.empty()) {
                for (auto &b : build) {
-                       if (p->loc.x            > b->loc.x            &&
-                            p->loc.x + p->width < b->loc.x + b->width) {
-
+                       if (p->loc.x > b->loc.x && p->loc.x + p->width < b->loc.x + b->width) {
                 if (b->inside.empty())
                     return this;
 
+                // +size cuts folder prefix
                                inside.push_back(currentXML.c_str() + xmlFolder.size());
-
                                tmp = loadWorldFromXML(b->inside);
 
+                // make the fade, as we let it fade back the worlds should be switched
                                ui::toggleBlackFast();
                                ui::waitForCover();
                                ui::toggleBlackFast();
 
-                glClearColor(0,0,0,1);
+                glClearColor(0, 0, 0, 1);
 
                                return tmp;
                        }
@@ -1195,12 +1157,10 @@ goInsideStructure(Player *p)
 
                                ui::toggleBlackFast();
                                ui::waitForCover();
-
                                p->loc.x = b->loc.x + (b->width / 2);
-
                                ui::toggleBlackFast();
 
-                glClearColor(1,1,1,1);
+                glClearColor(1, 1, 1, 1);
 
                                return tmp;
                        }
@@ -1210,6 +1170,88 @@ goInsideStructure(Player *p)
        return this;
 }
 
+void World::addStructure(BUILD_SUB sub, float x,float y, std::string tex, std::string inside){
+       build.push_back(new Structures());
+       build.back()->inWorld = this;
+       build.back()->textureLoc = tex;
+
+       build.back()->spawn(sub,x,y);
+
+       build.back()->inside = inside;
+
+       entity.push_back(build.back());
+}
+
+Village *World::
+addVillage(std::string name, World *world)
+{
+    village.emplace_back(name.c_str(), world);
+    return &village.back();
+}
+
+void World::addMob(int t,float x,float y){
+       mob.push_back(new Mob(t));
+       mob.back()->spawn(x,y);
+
+       entity.push_back(mob.back());
+}
+
+void World::addMob(int t,float x,float y,void (*hey)(Mob *)){
+       mob.push_back(new Mob(t));
+       mob.back()->spawn(x,y);
+       mob.back()->hey = hey;
+
+       entity.push_back(mob.back());
+}
+
+void World::addNPC(float x,float y){
+       npc.push_back(new NPC());
+       npc.back()->spawn(x,y);
+
+       entity.push_back(npc.back());
+}
+
+void World::addMerchant(float x, float y, bool housed){
+       merchant.push_back(new Merchant());
+       merchant.back()->spawn(x,y);
+
+    if (housed)
+        merchant.back()->inside = build.back();
+
+       npc.push_back(merchant.back());
+       entity.push_back(npc.back());
+}
+
+void World::addObject(std::string in, std::string p, float x, float y){
+       object.emplace_back(in, p);
+       object.back().spawn(x, y);
+
+       entity.push_back(&object.back());
+}
+
+void World::
+addParticle(float x, float y, float w, float h, float vx, float vy, Color color, int d)
+{
+       particles.emplace_back(x, y, w, h, vx, vy, color, d);
+       particles.back().canMove = true;
+}
+
+void World::
+addParticle(float x, float y, float w, float h, float vx, float vy, Color color, int d, unsigned char flags)
+{
+       particles.emplace_back(x, y, w, h, vx, vy, color, d);
+       particles.back().canMove = true;
+    particles.back().gravity = flags & (1 << 0);
+    particles.back().bounce  = flags & (1 << 1);
+}
+
+void World::
+addLight(vec2 loc, Color color)
+{
+       if (light.size() < 64)
+        light.push_back(Light(loc, color, 1));
+}
+
 void World::
 addHole(unsigned int start, unsigned int end)
 {
@@ -1244,95 +1286,6 @@ addHill(const ivec2 peak, const unsigned int width)
        }
 }
 
-int World::
-getTheWidth(void) const
-{
-       return worldStart * -2;
-}
-
-void World::save(void){
-       std::string data;
-
-       std::string save = (std::string)currentXML + ".dat";
-       std::ofstream out (save,std::ios::out | std::ios::binary);
-
-       std::cout<<"Saving to "<<save<<" ..."<<std::endl;
-
-       for(auto &n : npc){
-               data.append(std::to_string(n->dialogIndex) + "\n");
-               data.append(std::to_string((int)n->loc.x) + "\n");
-               data.append(std::to_string((int)n->loc.y) + "\n");
-       }
-
-       for(auto &b : build){
-               data.append(std::to_string((int)b->loc.x) + "\n");
-               data.append(std::to_string((int)b->loc.y) + "\n");
-       }
-
-       for(auto &m : mob){
-               data.append(std::to_string((int)m->loc.x) + "\n");
-               data.append(std::to_string((int)m->loc.y) + "\n");
-               data.append(std::to_string((int)m->alive) + "\n");
-       }
-
-       data.append("dOnE\0");
-       out.write(data.c_str(),data.size());
-       out.close();
-}
-
-void World::load(void){
-       std::string save,data,line;
-       const char *filedata;
-
-       save = std::string(currentXML + ".dat");
-       filedata = readFile(save.c_str());
-       data = filedata;
-       std::istringstream iss (data);
-
-       for(auto &n : npc){
-               std::getline(iss,line);
-               if(line == "dOnE")return;
-               if((n->dialogIndex = std::stoi(line)) != 9999)
-                       n->addAIFunc(commonAIFunc,false);
-               else n->clearAIFunc();
-
-               std::getline(iss,line);
-               if(line == "dOnE")return;
-               n->loc.x = std::stoi(line);
-               std::getline(iss,line);
-               if(line == "dOnE")return;
-               n->loc.y = std::stoi(line);
-       }
-
-       for(auto &b : build){
-               std::getline(iss,line);
-               if(line == "dOnE")return;
-               b->loc.x = std::stoi(line);
-               std::getline(iss,line);
-               if(line == "dOnE")return;
-               b->loc.y = std::stoi(line);
-       }
-
-       for(auto &m : mob){
-               std::getline(iss,line);
-               if(line == "dOnE")return;
-               m->loc.x = std::stoi(line);
-               std::getline(iss,line);
-               if(line == "dOnE")return;
-               m->loc.y = std::stoi(line);
-               std::getline(iss,line);
-               if(line == "dOnE")return;
-               m->alive = std::stoi(line);
-       }
-
-       while(std::getline(iss,line)){
-               if(line == "dOnE")
-                       break;
-       }
-
-       delete[] filedata;
-}
-
 float getIndoorWorldFloorHeight(void)
 {
     return INDOOR_FLOOR_HEIGHTT + INDOOR_FLOOR_THICKNESS;