From a9a9777190086bd2ce2aa54e20a1101509614463 Mon Sep 17 00:00:00 2001
From: Clyne Sullivan <tullivan99@gmail.com>
Date: Tue, 29 Mar 2016 08:48:52 -0400
Subject: began reworking indoors

---
 Changelog                          |  22 ++++
 Makefile                           |   2 +-
 include/Quest.h                    |  72 -------------
 include/Texture.h                  | 103 ------------------
 include/common.h                   |   3 +-
 include/config.h                   |  16 ++-
 include/entities.h                 |   6 +-
 include/inventory.h                |   2 +-
 include/quest.h                    |  66 ++++++++++++
 include/texture.h                  | 103 ++++++++++++++++++
 include/world.h                    |  13 ++-
 main.cpp                           |   6 +-
 src/Quest.cpp                      |  72 -------------
 src/Texture.cpp                    | 215 -------------------------------------
 src/config.cpp                     | 101 +++++++++--------
 src/gameplay.cpp                   |   6 +-
 src/inventory.cpp                  |   4 +-
 src/quest.cpp                      |  69 ++++++++++++
 src/texture.cpp                    | 215 +++++++++++++++++++++++++++++++++++++
 src/ui.cpp                         |  29 +++--
 src/world.cpp                      | 170 ++++++++++++++---------------
 xml/playerSpawnHill1.xml           |   2 +-
 xml/playerSpawnHill1_Building1.xml |   7 +-
 23 files changed, 670 insertions(+), 634 deletions(-)
 delete mode 100644 include/Quest.h
 delete mode 100644 include/Texture.h
 create mode 100644 include/quest.h
 create mode 100644 include/texture.h
 delete mode 100644 src/Quest.cpp
 delete mode 100644 src/Texture.cpp
 create mode 100644 src/quest.cpp
 create mode 100644 src/texture.cpp

diff --git a/Changelog b/Changelog
index 1a54ec3..00ba578 100644
--- a/Changelog
+++ b/Changelog
@@ -821,3 +821,25 @@
 	- found brazzier glitch
 	- merchants inside stalls
 	- z renders????
+
+3/25/2016:
+==========
+
+	- relocated detect() to main loop, better thing handling now
+	- implemented rain, snow
+	- added weather to debug overlay thing
+
+3/28/2016:
+==========
+
+	- fixed bug with quest assignment
+	- made file names consistent
+	- namespace'd config stuff
+	- began work on improving rendering stuff
+
+3/29/2016:
+==========
+
+	- prevented structures from moving
+	- began making indoor worlds good
+	- inventory slots are actually being used
diff --git a/Makefile b/Makefile
index 4c56fb6..c8b09e3 100644
--- 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++14
+CXXFLAGS = -m$(TARGET_BITS) -std=c++1z
 CXXINC   = -Iinclude -Iinclude/freetype
 CXXWARN  = -Wall -Wextra -Werror -pedantic-errors
 
diff --git a/include/Quest.h b/include/Quest.h
deleted file mode 100644
index 8b1e142..0000000
--- a/include/Quest.h
+++ /dev/null
@@ -1,72 +0,0 @@
-/** @file Quest.h
- * @brief The quest handling system.
- * 
- * This file contains Quest and QuestHandler, used to manage quests inside the
- * game.
- */
- 
-#ifndef QUEST_H
-#define QUEST_H
-
-#include <cstring>
-
-#include <common.h>
-#include <inventory.h>
-
-/**
- * When defined, DEBUG allows extra messages to be printed to the terminal for
- * debugging purposes.
- */
-
-#define DEBUG
-
-struct need_t {
-	std::string name;
-	int n;
-};
-
-typedef struct {
-	std::string title;
-	std::string desc;
-	struct item_t reward;
-	std::vector<struct need_t> need;
-} Quest;
-
-/**
- * The Quest Handler class.
- * 
- * This class handles quests, including the assigning, dropping, and completing
- * of the quests.
- */
-
-class QuestHandler {
-public:
-	std::vector<Quest>current;
-	
-	/**
-	 * Adds a quest to the current quest vector by its title.
-	 */
-	
-	int assign(std::string title,std::string desc,std::string req);
-	
-	/**
-	 * Drops a quest through its title.
-	 */
-	
-	int drop(std::string title);
-	
-	/**
-	 * Finishes a quest through it's title, also giving a pointer to the Entity
-	 * that gave the quest originally.
-	 */
-	
-	int finish(std::string t);
-	
-	/**
-	 * Returns true if this handler is currently taking the quest.
-	 */
-	
-	bool hasQuest(std::string t);
-};
-
-#endif // QUEST_H
diff --git a/include/Texture.h b/include/Texture.h
deleted file mode 100644
index 816a8bf..0000000
--- a/include/Texture.h
+++ /dev/null
@@ -1,103 +0,0 @@
-/** @file Texture.h
- * @brief Defines a method for loading textures.
- * 
- * This file gives facilities for easily loading and binding textures.
- */
-
-#ifndef TEXTURE_H
-#define TEXTURE_H
-
-#include <common.h>
-
-/**
- * When defined, DEBUG allows extra messages to be printed to the terminal for
- * debugging purposes.
- */
-
-#define DEBUG
-
-/**
- * Texture functions are given a namespace for better organization.
- */
-
-namespace Texture {
-	
-	/**
-	 * Loads a texture from the given file name, returning the GLuint used for
-	 * later referencing of the texture.
-	 */
-	
-	GLuint loadTexture(std::string fileName);
-	
-	void freeTextures(void);
-	
-	void initColorIndex();
-	vec2 getIndex(Color c);
-	dim2 imageDim(std::string fileName);
-}
-
-/**
- * The Texturec class.
- * 
- * This class can handle an array of textures and allows easy binding of those
- * textures.
- */
-
-class Texturec{
-private:
-
-	/**
-	 * Contains the index in the image array of the currently loaded texture.
-	 */
-
-	unsigned int texState;
-	
-public:
-
-	/**
-	 * Contains an array of the GLuints returned from Texture::loadTexture().
-	 */
-
-	std::vector<GLuint> image;
-	
-	/**
-	 * Populates the image array from a list of strings, with each string as a
-	 * separate argument.
-	 */
-	
-	Texturec(uint amt, ...);
-	
-	/**
-	 * Populates the image array from an array of strings.
-	 */
-	
-	Texturec(uint amt,const char **paths);
-	Texturec(std::vector<std::string>vec);
-	Texturec( std::initializer_list<std::string> l );
-	
-	/**
-	 * Frees memory taken by the image array.
-	 */
-	
-	~Texturec();
-	
-	/**
-	 * Binds the next texture in the array, incrementing texState.
-	 */
-	
-	void bindNext();
-	
-	/**
-	 * Binds the previous texture in the array, decrementing texState.
-	 */
-	
-	void bindPrev();
-	
-	/**
-	 * Binds the texture with the provided index.
-	 */
-	
-	void bind(unsigned int);
-};
-
-#endif //TEXTURE_H
diff --git a/include/common.h b/include/common.h
index 6f453b0..216dc01 100644
--- a/include/common.h
+++ b/include/common.h
@@ -117,7 +117,7 @@ typedef col Color;
  * Define the game's name (displayed in the window title).
  */
 
-#define GAME_NAME		"Independent Study v.0.6 alpha - NOW WITH more c++"
+#define GAME_NAME		"Independent Study v0.7 alpha - NOW WITH lights and snow and stuff"
 
 /**
  * The desired width of the game window.
@@ -176,6 +176,7 @@ extern float VOLUME_SFX;
  */
 
 #define DEBUG_printf( message, ...) DEBUG_prints(__FILE__, __LINE__, message, __VA_ARGS__ )
+#define C(x)						std::cout << x << std::endl;
 
 /**
  * Defines pi for calculations that need it.
diff --git a/include/config.h b/include/config.h
index 4d56d9c..e2f7239 100644
--- a/include/config.h
+++ b/include/config.h
@@ -1,14 +1,10 @@
 #ifndef CONFIG_H
 #define CONFIG_H
 
-#include <iostream>
-#include <SDL2/SDL_mixer.h>
-#include <tinyxml2.h>
+namespace config {
+    void read( void );
+    void update( void );
+    void save( void );
+}
 
-void readConfig(void);
-
-void updateConfig(void);
-
-void saveConfig();
-
-#endif //CONFIG_H
\ No newline at end of file
+#endif //CONFIG_H
diff --git a/include/entities.h b/include/entities.h
index 1250708..f455726 100644
--- a/include/entities.h
+++ b/include/entities.h
@@ -2,9 +2,9 @@
 #define ENTITIES_H
 
 #include <common.h>
-#include <Quest.h>
+#include <quest.h>
 #include <inventory.h>
-#include <Texture.h>
+#include <texture.h>
 
 #include <sstream>
 
@@ -14,7 +14,7 @@
 #define Structurep(n)	((Structures *)n)
 #define Mobp(n)			((Mob *)n)
 
-#define PLAYER_INV_SIZE	30	// The size of the player's inventory
+#define PLAYER_INV_SIZE	43	// The size of the player's inventory
 #define NPC_INV_SIZE	3	// Size of an NPC's inventory
 
 enum _TYPE {
diff --git a/include/inventory.h b/include/inventory.h
index 7369642..08a145e 100644
--- a/include/inventory.h
+++ b/include/inventory.h
@@ -4,7 +4,7 @@
 #include <common.h>
 #include <string.h>
 
-#include <Texture.h>
+#include <texture.h>
 
 #define DEBUG
 
diff --git a/include/quest.h b/include/quest.h
new file mode 100644
index 0000000..4da38bf
--- /dev/null
+++ b/include/quest.h
@@ -0,0 +1,66 @@
+/** @file Quest.h
+ * @brief The quest handling system.
+ *
+ * This file contains Quest and QuestHandler, used to manage quests inside the
+ * game.
+ */
+
+#ifndef QUEST_H
+#define QUEST_H
+
+#include <string>
+
+#include <inventory.h>
+
+/**
+ * When defined, DEBUG allows extra messages to be printed to the terminal for
+ * debugging purposes.
+ */
+
+#define DEBUG
+
+typedef struct {
+	std::string title;
+	std::string desc;
+	struct item_t reward;
+	std::vector<std::pair<std::string,int>> need;
+} Quest;
+
+/**
+ * The Quest Handler class.
+ *
+ * This class handles quests, including the assigning, dropping, and completing
+ * of the quests.
+ */
+
+class QuestHandler {
+public:
+	std::vector<Quest>current;
+
+	/**
+	 * Adds a quest to the current quest vector by its title.
+	 */
+
+	int assign(std::string title,std::string desc,std::string req);
+
+	/**
+	 * Drops a quest through its title.
+	 */
+
+	int drop(std::string title);
+
+	/**
+	 * Finishes a quest through it's title, also giving a pointer to the Entity
+	 * that gave the quest originally.
+	 */
+
+	int finish(std::string t);
+
+	/**
+	 * Returns true if this handler is currently taking the quest.
+	 */
+
+	bool hasQuest(std::string t);
+};
+
+#endif // QUEST_H
diff --git a/include/texture.h b/include/texture.h
new file mode 100644
index 0000000..816a8bf
--- /dev/null
+++ b/include/texture.h
@@ -0,0 +1,103 @@
+/** @file Texture.h
+ * @brief Defines a method for loading textures.
+ * 
+ * This file gives facilities for easily loading and binding textures.
+ */
+
+#ifndef TEXTURE_H
+#define TEXTURE_H
+
+#include <common.h>
+
+/**
+ * When defined, DEBUG allows extra messages to be printed to the terminal for
+ * debugging purposes.
+ */
+
+#define DEBUG
+
+/**
+ * Texture functions are given a namespace for better organization.
+ */
+
+namespace Texture {
+	
+	/**
+	 * Loads a texture from the given file name, returning the GLuint used for
+	 * later referencing of the texture.
+	 */
+	
+	GLuint loadTexture(std::string fileName);
+	
+	void freeTextures(void);
+	
+	void initColorIndex();
+	vec2 getIndex(Color c);
+	dim2 imageDim(std::string fileName);
+}
+
+/**
+ * The Texturec class.
+ * 
+ * This class can handle an array of textures and allows easy binding of those
+ * textures.
+ */
+
+class Texturec{
+private:
+
+	/**
+	 * Contains the index in the image array of the currently loaded texture.
+	 */
+
+	unsigned int texState;
+	
+public:
+
+	/**
+	 * Contains an array of the GLuints returned from Texture::loadTexture().
+	 */
+
+	std::vector<GLuint> image;
+	
+	/**
+	 * Populates the image array from a list of strings, with each string as a
+	 * separate argument.
+	 */
+	
+	Texturec(uint amt, ...);
+	
+	/**
+	 * Populates the image array from an array of strings.
+	 */
+	
+	Texturec(uint amt,const char **paths);
+	Texturec(std::vector<std::string>vec);
+	Texturec( std::initializer_list<std::string> l );
+	
+	/**
+	 * Frees memory taken by the image array.
+	 */
+	
+	~Texturec();
+	
+	/**
+	 * Binds the next texture in the array, incrementing texState.
+	 */
+	
+	void bindNext();
+	
+	/**
+	 * Binds the previous texture in the array, decrementing texState.
+	 */
+	
+	void bindPrev();
+	
+	/**
+	 * Binds the texture with the provided index.
+	 */
+	
+	void bind(unsigned int);
+};
+
+#endif //TEXTURE_H
diff --git a/include/world.h b/include/world.h
index 0b87134..f730715 100644
--- a/include/world.h
+++ b/include/world.h
@@ -165,7 +165,7 @@ protected:
 	 * World::detect(), which is why it is declared private.
 	 */
 
-	void singleDetect( Entity *e );
+	virtual void singleDetect( Entity *e );
 
 	/**
 	 * Empties all entity vectors.
@@ -386,7 +386,7 @@ public:
 	 * half-width to positive half-width.
 	 */
 
-	virtual void generate(unsigned int width);
+	void generate(unsigned int width);
 
 	/**
 	 * Sets the background theme, collecting the required textures into a
@@ -482,11 +482,18 @@ public:
  */
 
 class IndoorWorld : public World {
+private:
+
+	std::vector<std::vector<float>> floor;
+
+	void singleDetect( Entity *e );
+
 public:
 	IndoorWorld(void);
 	~IndoorWorld(void);
 
-	void generate(unsigned int width);	// Generates a flat world of width 'width'
+	void addFloor( unsigned int width );
+
 	void draw(Player *p);				// Draws the world (ignores layers)
 };
 
diff --git a/main.cpp b/main.cpp
index f4a0005..4140ac7 100644
--- a/main.cpp
+++ b/main.cpp
@@ -243,8 +243,10 @@ int main(int argc, char *argv[]){
 		std::cout << "SDL_mixer could not initialize! Error: " << Mix_GetError() << std::endl;
 		return -1;
 	}
+
 	Mix_AllocateChannels(8);
-	updateConfig();
+
+	config::update();
 
 	// Run Mix_Quit when main returns
 	atexit(Mix_Quit);
@@ -253,7 +255,7 @@ int main(int argc, char *argv[]){
 	 * Load saved settings into the game (see config/settings.xml)
 	 */
 
-	readConfig();
+	config::read();
 
 	/*
 	 *	Create a window for SDL to draw to. Most parameters are the default, except for the
diff --git a/src/Quest.cpp b/src/Quest.cpp
deleted file mode 100644
index 8f3c33b..0000000
--- a/src/Quest.cpp
+++ /dev/null
@@ -1,72 +0,0 @@
-#include <algorithm>
-
-#include <Quest.h>
-#include <entities.h>
-
-extern Player *player;
-
-int QuestHandler::assign(std::string title,std::string desc,std::string req){
-	Quest tmp;
-	char *tok;
-	
-	tmp.title = title;
-	tmp.desc = desc;
-
-	std::unique_ptr<char[]> buf (new char[req.size()]);
-
-	strcpy(buf.get(),req.c_str());
-	tok = strtok(buf.get(),"\n\r\t,");
-	tmp.need.push_back({"\0",0});
-	
-	while(tok){
-		if(tmp.need.back().name != "\0"){
-			tmp.need.back().n = atoi(tok);
-			tmp.need.push_back({"\0",0});
-		}else
-			tmp.need.back().name = tok;
-		
-		tok = strtok(NULL,"\n\r\t,");
-	}
-	
-	tmp.need.pop_back();
-	current.push_back(tmp);
-
-	return 0;
-}
-
-int QuestHandler::drop(std::string title){
-	current.erase( std::remove_if( current.begin(),
-								   current.end(),
-								   [&](Quest q){ return q.title == title; }),
-				   current.end() );
-	
-	return 0;
-}
-
-int QuestHandler::finish(std::string t){
-	for ( auto c = current.begin(); c != current.end(); c++ ) {
-		if ( (*c).title == t ) {
-			for ( auto &n : (*c).need ) {
-				if ( player->inv->hasItem( n.name ) < n.n )
-					return 0;
-			}
-			
-			for ( auto &n : (*c).need )
-				player->inv->takeItem( n.name, n.n );
-			
-			current.erase( c );
-			return 1;
-		}
-	}
-	
-	return 0;
-}
-
-bool QuestHandler::hasQuest(std::string t){
-	for ( auto &c : current ) {
-		if ( c.title == t )
-			return true;
-	}
-	
-	return false;
-}
diff --git a/src/Texture.cpp b/src/Texture.cpp
deleted file mode 100644
index 1ae5567..0000000
--- a/src/Texture.cpp
+++ /dev/null
@@ -1,215 +0,0 @@
-#include <algorithm>
-#include <string>
-
-#include <Texture.h>
-
-/**
- * A structure for keeping track of loaded textures.
- */
-
-typedef struct {
-	std::string name;	/**< The file path of the texture.		*/
-	GLuint tex;			/**< The GLuint for the loaded texture. */
-	dim2 dim;			/**< The dimensions of the texture.		*/
-} texture_t;
-
-struct index_t {
-	Color color;
-	int indexx;
-	int indexy;
-};
-
-/**
- * A vector of all loaded textures.
- *
- * Should a texture be asked to be loaded twice, loadTexture() can reference
- * this array and reuse GLuint's to save memory.
- */
-
-static std::vector<texture_t> LoadedTexture;
-
-namespace Texture{
-	Color pixels[8][4];
-
-	GLuint loadTexture(std::string fileName){
-		SDL_Surface *image;
-		GLuint object = 0;
-
-		// check if texture is already loaded
-		for(auto &t : LoadedTexture){
-			if(t.name == fileName){
-
-#ifdef DEBUG
-				DEBUG_printf("Reusing loaded texture for %s\n", fileName.c_str());
-#endif // DEBUG
-
-				return t.tex;
-			}
-		}
-
-		// load SDL_surface of texture
-		if(!(image = IMG_Load(fileName.c_str())))
-			return 0;
-
-#ifdef DEBUG
-		DEBUG_printf("Loaded image file: %s\n", fileName.c_str());
-#endif // DEBUG
-
-		/*
-		 * Load texture through OpenGL.
-		 */
-
-		glGenTextures(1,&object);				// Turns "object" into a texture
-		glBindTexture(GL_TEXTURE_2D,object);	// Binds "object" to the top of the stack
-		glPixelStoref(GL_UNPACK_ALIGNMENT,1);
-
-		glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);	// Sets the "min" filter
-		glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);	// The the "max" filter of the stack
-
-		glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); // Wrap the texture to the matrix
-		glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); //
-
-		glTexImage2D(GL_TEXTURE_2D,  // Sets the texture to the image file loaded above
-					 0,
-					 GL_RGBA,
-					 image->w,
-					 image->h,
-					 0,
-					 GL_RGBA,
-					 GL_UNSIGNED_BYTE,
-					 image->pixels
-					 );
-
-		// add texture to LoadedTexture
-		LoadedTexture.push_back(texture_t{fileName,object,{image->w,image->h}});
-
-		// free the SDL_Surface
-		SDL_FreeSurface(image);
-
-		return object;
-	}
-
-	dim2 imageDim(std::string fileName){
-		for(auto &t : LoadedTexture){
-			if(t.name == fileName)
-				return t.dim;
-		}
-		return {0,0};
-	}
-
-	void freeTextures(void){
-		while(!LoadedTexture.empty()){
-			glDeleteTextures(1, &LoadedTexture.back().tex);
-			LoadedTexture.pop_back();
-		}
-	}
-
-	#define CINDEX_WIDTH (8*4*3)
-	void initColorIndex(){
-		unsigned int i;
-		GLubyte *buffer;
-		GLfloat *bufferf;
-
-		buffer  = new GLubyte[CINDEX_WIDTH];
-		bufferf = new GLfloat[CINDEX_WIDTH];
-
-		colorIndex = loadTexture("assets/colorIndex.png");
-		glActiveTexture(GL_TEXTURE0);
-		glBindTexture(GL_TEXTURE_2D, colorIndex);
-		glGetTexImage(GL_TEXTURE_2D, 0, GL_RGB, GL_UNSIGNED_BYTE, buffer);
-
-		for(i = 0; i < CINDEX_WIDTH; i++)
-			bufferf[i] = (float)buffer[i] / 255.0f;
-
-		i = 0;
-		for(unsigned int y = 0; y < 8; y++){
-			for(unsigned int x = 0; x < 4; x++){
-					if(i >= CINDEX_WIDTH){
-						delete[] buffer;
-						delete[] bufferf;
-						return;
-					}
-					pixels[y][x].red = buffer[i++];
-					pixels[y][x].green = buffer[i++];
-					pixels[y][x].blue = buffer[i++];
-			}
-		}
-		delete[] buffer;
-		delete[] bufferf;
-	}
-
-	//sqrt((255-145)^2+(90-145)^2+(0-0)^2);
-	std::vector<index_t>ind;
-	vec2 getIndex(Color c){
-		for(auto &i : ind){
-			if(c.red == i.color.red && c.green == i.color.green && c.blue == i.color.blue){
-				//std::cout << float(i.indexy) << "," << float(i.indexx) << std::endl;
-				return {float(i.indexx), float(i.indexy)};
-			}
-		}
-		uint buf[2];
-		float buff = 999;
-		float shit = 999;
-		for(uint y = 0; y < 8; y++){
-			for(uint x = 0; x < 4; x++){
-				//std::cout << y << "," << x << ":" << pixels[y][x].red << "," << pixels[y][x].green << "," << pixels[y][x].blue << std::endl;
-				buff = sqrt(pow((pixels[y][x].red-	c.red),  2)+
-							pow((pixels[y][x].green-c.green),2)+
-							pow((pixels[y][x].blue-	c.blue), 2));
-				//std::cout << buff << std::endl;
-				if(buff < shit){
-					shit = buff;
-					buf[0] = y;
-					buf[1] = x;
-				}
-				//
-				//std::cout << shit << std::endl;
-			}
-		}
-		ind.push_back({c, (int)buf[1], (int)buf[0]});
-		//std::cout << float(buf[1]) << ", " << float(buf[0]) << std::endl;
-		return {float(buf[1]),float(buf[0])};
-	}
-}
-
-Texturec::Texturec(uint amt, ...){
-	va_list fNames;
-	texState = 0;
-	va_start(fNames, amt);
-	for(unsigned int i = 0; i < amt; i++)
-		image.push_back( Texture::loadTexture(va_arg(fNames, char *)) );
-	va_end(fNames);
-}
-
-Texturec::Texturec( std::initializer_list<std::string> l )
-{
-	texState = 0;
-	std::for_each( l.begin(), l.end(), [&](std::string s){ image.push_back( Texture::loadTexture( s ) ); });
-}
-
-Texturec::Texturec(std::vector<std::string>v){
-	texState = 0;
-	std::for_each( v.begin(), v.end(), [&](std::string s){ image.push_back( Texture::loadTexture( s ) ); });
-}
-
-Texturec::Texturec(uint amt,const char **paths){
-	texState = 0;
-	for(unsigned int i = 0; i < amt; i++)
-		image.push_back( Texture::loadTexture(paths[i]) );
-}
-
-Texturec::~Texturec(){
-}
-
-void Texturec::bind(unsigned int bn){
-	texState = bn;
-	glBindTexture(GL_TEXTURE_2D,image[(int)texState]);
-}
-
-void Texturec::bindNext(){
-	bind(++texState);
-}
-
-void Texturec::bindPrev(){
-	bind(--texState);
-}
diff --git a/src/config.cpp b/src/config.cpp
index 45bab3f..e076528 100644
--- a/src/config.cpp
+++ b/src/config.cpp
@@ -1,5 +1,10 @@
 #include <config.h>
 
+#include <iostream>
+
+#include <SDL2/SDL_mixer.h>
+
+#include <tinyxml2.h>
 #include <ui.h>
 
 using namespace tinyxml2;
@@ -17,55 +22,57 @@ XMLDocument xml;
 XMLElement *scr;
 XMLElement *vol;
 
-void readConfig(){
-	unsigned int uval;
-	float fval;
-	bool bval;
-
-	xml.LoadFile("config/settings.xml");
-	scr = xml.FirstChildElement("screen");
-	
-	if(scr->QueryUnsignedAttribute("width",&uval) == XML_NO_ERROR)
-		SCREEN_WIDTH = uval;
-	else SCREEN_WIDTH = 1280;
-	if(scr->QueryUnsignedAttribute("height",&uval) == XML_NO_ERROR)
-		SCREEN_HEIGHT = uval;
-	else SCREEN_HEIGHT = 800;
-	if(scr->QueryBoolAttribute("fullscreen",&bval) == XML_NO_ERROR)
-		FULLSCREEN = bval;
-	else FULLSCREEN = false;
-	if(xml.FirstChildElement("hline")->QueryUnsignedAttribute("size",&uval) == XML_NO_ERROR)
-		HLINE = uval;
-	else HLINE = 3;
-
-	vol = xml.FirstChildElement("volume");
-	
-	if(vol->FirstChildElement("master")->QueryFloatAttribute("volume",&fval) == XML_NO_ERROR)
-		VOLUME_MASTER = fval;
-	else VOLUME_MASTER = 50;
-	if(vol->FirstChildElement("music")->QueryFloatAttribute("volume",&fval) == XML_NO_ERROR)
-		VOLUME_MUSIC = fval;
-	else VOLUME_MUSIC = 50;
-	if(vol->FirstChildElement("sfx")->QueryFloatAttribute("volume",&fval) == XML_NO_ERROR)
-		VOLUME_SFX = fval;
-	else VOLUME_SFX = 50;
-		
-	ui::initFonts();
-	ui::setFontFace(xml.FirstChildElement("font")->Attribute("path"));
-	updateConfig();
-}
+namespace config {
 
-void updateConfig(){
+	void read( void ) {
+		unsigned int uval;
+		float fval;
+		bool bval;
 
-	Mix_Volume(0,VOLUME_MASTER);
-	Mix_Volume(1,VOLUME_SFX * (VOLUME_MASTER/100.0f));
-	Mix_VolumeMusic(VOLUME_MUSIC * (VOLUME_MASTER/100.0f));
-}
+		xml.LoadFile("config/settings.xml");
+		scr = xml.FirstChildElement("screen");
+
+		if(scr->QueryUnsignedAttribute("width",&uval) == XML_NO_ERROR)
+			SCREEN_WIDTH = uval;
+		else SCREEN_WIDTH = 1280;
+		if(scr->QueryUnsignedAttribute("height",&uval) == XML_NO_ERROR)
+			SCREEN_HEIGHT = uval;
+		else SCREEN_HEIGHT = 800;
+		if(scr->QueryBoolAttribute("fullscreen",&bval) == XML_NO_ERROR)
+			FULLSCREEN = bval;
+		else FULLSCREEN = false;
+		if(xml.FirstChildElement("hline")->QueryUnsignedAttribute("size",&uval) == XML_NO_ERROR)
+			HLINE = uval;
+		else HLINE = 3;
+
+		vol = xml.FirstChildElement("volume");
+
+		if(vol->FirstChildElement("master")->QueryFloatAttribute("volume",&fval) == XML_NO_ERROR)
+			VOLUME_MASTER = fval;
+		else VOLUME_MASTER = 50;
+		if(vol->FirstChildElement("music")->QueryFloatAttribute("volume",&fval) == XML_NO_ERROR)
+			VOLUME_MUSIC = fval;
+		else VOLUME_MUSIC = 50;
+		if(vol->FirstChildElement("sfx")->QueryFloatAttribute("volume",&fval) == XML_NO_ERROR)
+			VOLUME_SFX = fval;
+		else VOLUME_SFX = 50;
+
+		ui::initFonts();
+		ui::setFontFace(xml.FirstChildElement("font")->Attribute("path"));
+		config::update();
+	}
+
+	void update( void ) {
+		Mix_Volume(0,VOLUME_MASTER);
+		Mix_Volume(1,VOLUME_SFX * (VOLUME_MASTER/100.0f));
+		Mix_VolumeMusic(VOLUME_MUSIC * (VOLUME_MASTER/100.0f));
+	}
 
-void saveConfig(){
-	vol->FirstChildElement("master")->SetAttribute("volume",VOLUME_MASTER);
-	vol->FirstChildElement("music")->SetAttribute("volume",VOLUME_MUSIC);
-	vol->FirstChildElement("sfx")->SetAttribute("volume", VOLUME_SFX);
+	void save( void ) {
+		vol->FirstChildElement("master")->SetAttribute("volume",VOLUME_MASTER);
+		vol->FirstChildElement("music")->SetAttribute("volume",VOLUME_MUSIC);
+		vol->FirstChildElement("sfx")->SetAttribute("volume", VOLUME_SFX);
 
-	xml.SaveFile("config/settings.xml", false);
+		xml.SaveFile("config/settings.xml", false);
+	}
 }
diff --git a/src/gameplay.cpp b/src/gameplay.cpp
index 075aec3..3c98461 100644
--- a/src/gameplay.cpp
+++ b/src/gameplay.cpp
@@ -212,13 +212,13 @@ CONT:
 void commonPageFunc( Mob *callee )
 {
 	static bool lock = false;
-	
+
 	if ( !lock ) {
 		lock = true;
-		
+
 		ui::drawPage( callee->heyid );
 		ui::waitForDialog();
-		
+
 		callee->alive = false;
 		lock = false;
 	}
diff --git a/src/inventory.cpp b/src/inventory.cpp
index 7ba5909..d9ff756 100644
--- a/src/inventory.cpp
+++ b/src/inventory.cpp
@@ -9,9 +9,8 @@ extern Player *player;
 extern GLuint invUI;
 static float hangle = 0.0f;
 static bool swing = false;
-//static float xc,yc;
 static vec2 itemLoc;
-static const unsigned char numSlot = 7;
+static const unsigned int numSlot = 2000;
 Mix_Chunk* swordSwing;
 
 static std::vector<Item *> itemMap;
@@ -190,7 +189,6 @@ void Inventory::setSelectionDown(){
 
 void Inventory::draw(void){
 	static unsigned int lop = 0;
-	//const unsigned int numSlot = 7;
 	static std::vector<int>dfp(numSlot);
 	static std::vector<Ray>iray(numSlot);
 	static std::vector<vec2>curCoord(numSlot);
diff --git a/src/quest.cpp b/src/quest.cpp
new file mode 100644
index 0000000..ba35c40
--- /dev/null
+++ b/src/quest.cpp
@@ -0,0 +1,69 @@
+#include <algorithm>
+
+#include <quest.h>
+#include <entities.h>
+
+extern Player *player;
+
+int QuestHandler::assign(std::string title,std::string desc,std::string req){
+	Quest tmp;
+	char *tok;
+
+	tmp.title = title;
+	tmp.desc = desc;
+
+	tok = strtok( &req[0], "\n\r\t," );
+	tmp.need.emplace_back( "", 0 );
+
+	while ( tok ) {
+		if ( !tmp.need.back().first.empty() ) {
+			tmp.need.back().second = atoi( tok );
+			tmp.need.emplace_back( "", 0 );
+		} else
+			tmp.need.back().first = tok;
+
+		tok = strtok( NULL, "\n\r\t," );
+	}
+
+	tmp.need.pop_back();
+	current.push_back( tmp );
+
+	return 0;
+}
+
+int QuestHandler::drop(std::string title){
+	current.erase( std::remove_if( current.begin(),
+								   current.end(),
+								   [&](Quest q){ return q.title == title; }),
+				   current.end() );
+
+	return 0;
+}
+
+int QuestHandler::finish(std::string t){
+	for ( auto c = current.begin(); c != current.end(); c++ ) {
+		if ( (*c).title == t ) {
+			for ( auto &n : (*c).need ) {
+				if ( player->inv->hasItem( n.first ) < n.second )
+					return 0;
+			}
+
+			for ( auto &n : (*c).need )
+				player->inv->takeItem( n.first, n.second );
+
+			current.erase( c );
+			return 1;
+		}
+	}
+
+	return 0;
+}
+
+bool QuestHandler::hasQuest(std::string t){
+	for ( auto &c : current ) {
+		if ( c.title == t )
+			return true;
+	}
+
+	return false;
+}
diff --git a/src/texture.cpp b/src/texture.cpp
new file mode 100644
index 0000000..35d7b80
--- /dev/null
+++ b/src/texture.cpp
@@ -0,0 +1,215 @@
+#include <algorithm>
+#include <string>
+
+#include <texture.h>
+
+/**
+ * A structure for keeping track of loaded textures.
+ */
+
+typedef struct {
+	std::string name;	/**< The file path of the texture.		*/
+	GLuint tex;			/**< The GLuint for the loaded texture. */
+	dim2 dim;			/**< The dimensions of the texture.		*/
+} texture_t;
+
+struct index_t {
+	Color color;
+	int indexx;
+	int indexy;
+};
+
+/**
+ * A vector of all loaded textures.
+ *
+ * Should a texture be asked to be loaded twice, loadTexture() can reference
+ * this array and reuse GLuint's to save memory.
+ */
+
+static std::vector<texture_t> LoadedTexture;
+
+namespace Texture{
+	Color pixels[8][4];
+
+	GLuint loadTexture(std::string fileName){
+		SDL_Surface *image;
+		GLuint object = 0;
+
+		// check if texture is already loaded
+		for(auto &t : LoadedTexture){
+			if(t.name == fileName){
+
+#ifdef DEBUG
+				DEBUG_printf("Reusing loaded texture for %s\n", fileName.c_str());
+#endif // DEBUG
+
+				return t.tex;
+			}
+		}
+
+		// load SDL_surface of texture
+		if(!(image = IMG_Load(fileName.c_str())))
+			return 0;
+
+#ifdef DEBUG
+		DEBUG_printf("Loaded image file: %s\n", fileName.c_str());
+#endif // DEBUG
+
+		/*
+		 * Load texture through OpenGL.
+		 */
+
+		glGenTextures(1,&object);				// Turns "object" into a texture
+		glBindTexture(GL_TEXTURE_2D,object);	// Binds "object" to the top of the stack
+		glPixelStoref(GL_UNPACK_ALIGNMENT,1);
+
+		glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);	// Sets the "min" filter
+		glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);	// The the "max" filter of the stack
+
+		glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); // Wrap the texture to the matrix
+		glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); //
+
+		glTexImage2D(GL_TEXTURE_2D,  // Sets the texture to the image file loaded above
+					 0,
+					 GL_RGBA,
+					 image->w,
+					 image->h,
+					 0,
+					 GL_RGBA,
+					 GL_UNSIGNED_BYTE,
+					 image->pixels
+					 );
+
+		// add texture to LoadedTexture
+		LoadedTexture.push_back(texture_t{fileName,object,{image->w,image->h}});
+
+		// free the SDL_Surface
+		SDL_FreeSurface(image);
+
+		return object;
+	}
+
+	dim2 imageDim(std::string fileName){
+		for(auto &t : LoadedTexture){
+			if(t.name == fileName)
+				return t.dim;
+		}
+		return {0,0};
+	}
+
+	void freeTextures(void){
+		while(!LoadedTexture.empty()){
+			glDeleteTextures(1, &LoadedTexture.back().tex);
+			LoadedTexture.pop_back();
+		}
+	}
+
+	#define CINDEX_WIDTH (8*4*3)
+	void initColorIndex(){
+		unsigned int i;
+		GLubyte *buffer;
+		GLfloat *bufferf;
+
+		buffer  = new GLubyte[CINDEX_WIDTH];
+		bufferf = new GLfloat[CINDEX_WIDTH];
+
+		colorIndex = loadTexture("assets/colorIndex.png");
+		glActiveTexture(GL_TEXTURE0);
+		glBindTexture(GL_TEXTURE_2D, colorIndex);
+		glGetTexImage(GL_TEXTURE_2D, 0, GL_RGB, GL_UNSIGNED_BYTE, buffer);
+
+		for(i = 0; i < CINDEX_WIDTH; i++)
+			bufferf[i] = (float)buffer[i] / 255.0f;
+
+		i = 0;
+		for(unsigned int y = 0; y < 8; y++){
+			for(unsigned int x = 0; x < 4; x++){
+					if(i >= CINDEX_WIDTH){
+						delete[] buffer;
+						delete[] bufferf;
+						return;
+					}
+					pixels[y][x].red = buffer[i++];
+					pixels[y][x].green = buffer[i++];
+					pixels[y][x].blue = buffer[i++];
+			}
+		}
+		delete[] buffer;
+		delete[] bufferf;
+	}
+
+	//sqrt((255-145)^2+(90-145)^2+(0-0)^2);
+	std::vector<index_t>ind;
+	vec2 getIndex(Color c){
+		for(auto &i : ind){
+			if(c.red == i.color.red && c.green == i.color.green && c.blue == i.color.blue){
+				//std::cout << float(i.indexy) << "," << float(i.indexx) << std::endl;
+				return {float(i.indexx), float(i.indexy)};
+			}
+		}
+		uint buf[2];
+		float buff = 999;
+		float shit = 999;
+		for(uint y = 0; y < 8; y++){
+			for(uint x = 0; x < 4; x++){
+				//std::cout << y << "," << x << ":" << pixels[y][x].red << "," << pixels[y][x].green << "," << pixels[y][x].blue << std::endl;
+				buff = sqrt(pow((pixels[y][x].red-	c.red),  2)+
+							pow((pixels[y][x].green-c.green),2)+
+							pow((pixels[y][x].blue-	c.blue), 2));
+				//std::cout << buff << std::endl;
+				if(buff < shit){
+					shit = buff;
+					buf[0] = y;
+					buf[1] = x;
+				}
+				//
+				//std::cout << shit << std::endl;
+			}
+		}
+		ind.push_back({c, (int)buf[1], (int)buf[0]});
+		//std::cout << float(buf[1]) << ", " << float(buf[0]) << std::endl;
+		return {float(buf[1]),float(buf[0])};
+	}
+}
+
+Texturec::Texturec(uint amt, ...){
+	va_list fNames;
+	texState = 0;
+	va_start(fNames, amt);
+	for(unsigned int i = 0; i < amt; i++)
+		image.push_back( Texture::loadTexture(va_arg(fNames, char *)) );
+	va_end(fNames);
+}
+
+Texturec::Texturec( std::initializer_list<std::string> l )
+{
+	texState = 0;
+	std::for_each( l.begin(), l.end(), [&](std::string s){ image.push_back( Texture::loadTexture( s ) ); });
+}
+
+Texturec::Texturec(std::vector<std::string>v){
+	texState = 0;
+	std::for_each( v.begin(), v.end(), [&](std::string s){ image.push_back( Texture::loadTexture( s ) ); });
+}
+
+Texturec::Texturec(uint amt,const char **paths){
+	texState = 0;
+	for(unsigned int i = 0; i < amt; i++)
+		image.push_back( Texture::loadTexture(paths[i]) );
+}
+
+Texturec::~Texturec(){
+}
+
+void Texturec::bind(unsigned int bn){
+	texState = bn;
+	glBindTexture(GL_TEXTURE_2D,image[(int)texState]);
+}
+
+void Texturec::bindNext(){
+	bind(++texState);
+}
+
+void Texturec::bindPrev(){
+	bind(--texState);
+}
diff --git a/src/ui.cpp b/src/ui.cpp
index c646458..69fe1bf 100644
--- a/src/ui.cpp
+++ b/src/ui.cpp
@@ -99,7 +99,7 @@ static GLuint pageTex = 0;
 void Menu::gotoParent(){
 	if(parent == NULL){
 		currentMenu = NULL;
-		updateConfig();
+		config::update();
 	}else{
 		currentMenu = parent;
 	}
@@ -881,8 +881,8 @@ namespace ui {
 		dialogBoxExists = false;
 		currentMenu = NULL;
 		gameRunning = false;
-		updateConfig();
-		saveConfig();
+		config::update();
+		config::save();
 	}
 
 	menuItem createButton(vec2 l, dim2 d, Color c, const char* t, menuFunc f){
@@ -955,7 +955,7 @@ namespace ui {
 
 	void drawMenu(Menu *menu){
 		setFontSize(24);
-		updateConfig();
+		config::update();
 		SDL_Event e;
 
 		mouse.x=premouse.x+offset.x-(SCREEN_WIDTH/2);
@@ -1311,13 +1311,20 @@ EXIT:
 				if ( ( e.button.button & SDL_BUTTON_LEFT ) && !dialogBoxExists )
 					player->inv->usingi = true;
 
-				for ( auto &e : currentWorld->entity ) {
-					if( mouse.x > e->loc.x && mouse.x < e->loc.x + e->width &&
-						mouse.y > e->loc.y && mouse.y < e->loc.y + e->height ) {
-						e->vel.y = .05;
-						fr = mouse;
-						ig = e;
-						break;
+				if( mouse.x > player->loc.x && mouse.x < player->loc.x + player->width &&
+					mouse.y > player->loc.y && mouse.y < player->loc.y + player->height ) {
+					player->vel.y = .05;
+					fr = mouse;
+					ig = player;
+				} else {
+					for ( auto &e : currentWorld->entity ) {
+						if( mouse.x > e->loc.x && mouse.x < e->loc.x + e->width &&
+							mouse.y > e->loc.y && mouse.y < e->loc.y + e->height ) {
+							e->vel.y = .05;
+							fr = mouse;
+							ig = e;
+							break;
+						}
 					}
 				}
 
diff --git a/src/world.cpp b/src/world.cpp
index d8fd2d3..623c1c2 100644
--- a/src/world.cpp
+++ b/src/world.cpp
@@ -17,7 +17,8 @@ using namespace tinyxml2;
  * Defines the height of the floor in an IndoorWorld.
  */
 
-#define INDOOR_FLOOR_HEIGHT     100
+#define INDOOR_FLOOR_THICKNESS      50
+#define INDOOR_FLOOR_HEIGHTT        400
 
 /**
  * Gravity thing
@@ -316,21 +317,19 @@ update( Player *p, unsigned int delta )
 
 	// update entity coords
 	for ( auto &e : entity ) {
-		e->loc.y += e->vel.y * delta;
 
         // dont let structures move?
-        if ( e->type == STRUCTURET )
-            e->canMove = true;
-
-		if ( e->canMove ) {
+		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());
@@ -1250,41 +1249,63 @@ IndoorWorld::~IndoorWorld(void){
 	deleteEntities();
 }
 
-void IndoorWorld::generate(unsigned int width){		// Generates a flat area of width 'width'
-	lineCount=width+GROUND_HILLINESS;			// Sets line count to the desired width plus GEN_INC to remove incorrect line calculations.
-	if(lineCount<=0)abort();
+void IndoorWorld::
+addFloor( unsigned int width )
+{
+    if ( floor.empty() )
+        generate( width );
+    floor.emplace_back( width, floor.size() * INDOOR_FLOOR_HEIGHTT + INDOOR_FLOOR_THICKNESS );
+}
 
-	worldData = std::vector<WorldData> (lineCount, WorldData { false, {0,0}, INDOOR_FLOOR_HEIGHT, 0 });
+void IndoorWorld::
+singleDetect( Entity *e )
+{
+    if ( !e->alive )
+        return;
+    if ( e->type == MOBT && Mobp(e)->subtype == MS_TRIGGER )
+        return;
+
+    for ( auto &f : floor ) {
+        if ( f[0] + INDOOR_FLOOR_HEIGHTT < e->loc.y ) {
+            C("floor");
+            if ( e->loc.y < f[0] ) {
+                e->loc.y = f[0];
+                e->vel.y = 0;
+                e->ground = true;
+            } else if ( e->vel.y > -2 )
+                e->vel.y -= GRAVITY_CONSTANT * deltaTime;
+            break;
+        }
+    }
+
+    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;
+    }
 
-	worldStart = (width - GROUND_HILLINESS) * HLINE / 2 * -1;
 }
 
-void IndoorWorld::draw(Player *p){
-	unsigned int i,ie;
-	//int j,x,v_offset;
+void IndoorWorld::
+draw( Player *p )
+{
+	unsigned int i;
 	int x;
 
-	/*
-	 *	Draw the background.
-	*/
-
-	//glEnable(GL_TEXTURE_2D);
-
-    for(auto &l : light){
-        if(l.belongsTo){
-            l.loc.x = l.following->loc.x + SCREEN_WIDTH/2;
+    // draw lights
+    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){
-            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;
-
-            //std::cout << l.fireLoc.x << "," << l.fireLoc.y << std::endl;
-            //std::cout << l.loc.x << "," << l.loc.y << std::endl << std::endl;
-        }else{
+        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
             l.fireFlicker = 1.0f;
-        }
     }
 
     std::unique_ptr<GLfloat[]> pointArrayBuf = std::make_unique<GLfloat[]> (2 * (light.size()));
@@ -1301,9 +1322,8 @@ void IndoorWorld::draw(Player *p){
         }
 	}
 
-    for(i = 0; i < light.size(); i++){
+    for(i = 0; i < light.size(); i++)
         flameArray[i] = light[i].fireFlicker;
-    }
 
 	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
 	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
@@ -1312,7 +1332,7 @@ void IndoorWorld::draw(Player *p){
 	glUniform1i(glGetUniformLocation(shaderProgram, "sampler"), 0);
 	glUniform1f(glGetUniformLocation(shaderProgram, "amb"    ), 0.02f + light.size()/50.0f);
 
-	if ( light.size() == 0)
+	if ( light.empty() )
 		glUniform1i(glGetUniformLocation(shaderProgram, "numLight"), 0);
 	else {
 		glUniform1i (glGetUniformLocation(shaderProgram, "numLight"     ), light.size());
@@ -1321,53 +1341,38 @@ void IndoorWorld::draw(Player *p){
         glUniform1fv(glGetUniformLocation(shaderProgram, "fireFlicker"), light.size(), flameArray);
 	}
 
-    //delete[] flameArray;
-
 	bgTex->bind(0);
 	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); //for the s direction
 	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); //for the t direction
 	glColor4ub(255,255,255,255);
 
-	glBegin(GL_QUADS);
-			glTexCoord2i(0,1);							     glVertex2i( worldStart - SCREEN_WIDTH / 2,0);
-			glTexCoord2i((-worldStart*2+SCREEN_WIDTH)/512,1);glVertex2i(-worldStart + SCREEN_WIDTH / 2,0);
-			glTexCoord2i((-worldStart*2+SCREEN_WIDTH)/512,0);glVertex2i(-worldStart + SCREEN_WIDTH / 2,SCREEN_HEIGHT);
-			glTexCoord2i(0,0);							     glVertex2i( worldStart - SCREEN_WIDTH / 2,SCREEN_HEIGHT);
-	glEnd();
-
-	glUseProgram(0);
-	//glDisable(GL_TEXTURE_2D);
-
-	/*
-	 *	Calculate the starting and ending points to draw the ground from.
-	*/
-
-	/*v_offset = (p->loc.x - x_start) / HLINE;
-	j = v_offset - (SCREEN_WIDTH / 2 / HLINE) - GEN_INC;
-	if(j < 0)j = 0;
-	i = j;
-
-	ie = v_offset + (SCREEN_WIDTH / 2 / HLINE) - GEN_INC;
-	if(ie > lineCount)ie = lineCount;*/
+    glBegin(GL_QUADS);
+        glTexCoord2i(0,1);							     glVertex2i( worldStart - SCREEN_WIDTH / 2,0);
+		glTexCoord2i((-worldStart*2+SCREEN_WIDTH)/512,1);glVertex2i(-worldStart + SCREEN_WIDTH / 2,0);
+		glTexCoord2i((-worldStart*2+SCREEN_WIDTH)/512,0);glVertex2i(-worldStart + SCREEN_WIDTH / 2,SCREEN_HEIGHT);
+		glTexCoord2i(0,0);							     glVertex2i( worldStart - SCREEN_WIDTH / 2,SCREEN_HEIGHT);
+    glEnd();
 
-	i = 0;
-	ie = lineCount;
+    glUseProgram(0);
 
 	/*
 	 *	Draw the ground.
 	*/
-	glUseProgram(shaderProgram);
-	glUniform1i(glGetUniformLocation(shaderProgram, "sampler"), 0);
-	glBegin(GL_QUADS);
-		for(;i < ie - GROUND_HILLINESS;i++){
-			safeSetColor(150,100,50);
-
-			x = worldStart + i * HLINE;
-			glVertex2i(x		,worldData[i].groundHeight);
-			glVertex2i(x + HLINE,worldData[i].groundHeight);
-			glVertex2i(x + HLINE,worldData[i].groundHeight - 50);
-			glVertex2i(x		,worldData[i].groundHeight - 50);
-		}
+
+	glUseProgram( shaderProgram );
+	glUniform1i( glGetUniformLocation(shaderProgram, "sampler"), 0 );
+	glBegin( GL_QUADS );
+        safeSetColor( 150, 100, 50 );
+        for ( auto &f : floor ) {
+            i = 0;
+    		for ( h : f ) {
+    			x = worldStart + i++ * HLINE;
+    			glVertex2i( x        , h                          );
+    			glVertex2i( x + HLINE, h                          );
+    			glVertex2i( x + HLINE, h - INDOOR_FLOOR_THICKNESS );
+    			glVertex2i( x        , h - INDOOR_FLOOR_THICKNESS );
+    		}
+        }
 	glEnd();
 	glUseProgram(0);
 
@@ -1533,14 +1538,9 @@ loadWorldFromXMLNoSave( std::string path ) {
 			tmp->setBackground((WorldBGType)wxml->UnsignedAttribute("background"));
 			tmp->setBGM(wxml->StrAttribute("bgm"));
 		} else if ( name == "generation" ) {
-			if(!strcmp(wxml->Attribute("type"),"Random")){
-				if(Indoor)
-					((IndoorWorld *)tmp)->generate(wxml->UnsignedAttribute("width"));
-				else {
-
-					tmp->generate(wxml->UnsignedAttribute("width"));
-				}
-			}else if(Indoor)
+			if ( !Indoor && !strcmp(wxml->Attribute("type"),"Random") )
+				tmp->generate(wxml->UnsignedAttribute("width"));
+			else if ( Indoor )
 				abort();
 		} else if ( name == "mob" ) {
 			unsigned int type;
@@ -1588,9 +1588,11 @@ loadWorldFromXMLNoSave( std::string path ) {
 			tmp->mob.back()->heyid = wxml->Attribute("id");
 		} else if ( name == "hill" ) {
 			tmp->addHill( ivec2 { wxml->IntAttribute("peakx"), wxml->IntAttribute("peaky") }, wxml->UnsignedAttribute("width") );
-		} else if ( name == "time") {
-      tickCount = std::stoi( wxml->GetText() );
-    }
+		} else if ( name == "time" ) {
+            tickCount = std::stoi( wxml->GetText() );
+        } else if ( Indoor && name == "floor" ) {
+            ((IndoorWorld *)tmp)->addFloor( wxml->UnsignedAttribute("width") );
+        }
 
 		wxml = wxml->NextSiblingElement();
 	}
diff --git a/xml/playerSpawnHill1.xml b/xml/playerSpawnHill1.xml
index d3b5db4..a67a932 100644
--- a/xml/playerSpawnHill1.xml
+++ b/xml/playerSpawnHill1.xml
@@ -18,7 +18,7 @@
 
 	<village name="Scrub Lawd">
 		<structure type="0" x="-300" inside="playerSpawnHill1_Building1.xml"/>
-		<structure type="5" x="-500" inside="playerSpawnHill1_Building1.xml"/>
+		<structure type="5" x="-500" />
 		<stall type="market" texture="assets/style/classic/stall.png">
 			<buy item="Dank MayMay" cost="420"/>
 			<sell item="Dank MayMay" cost="666"/>
diff --git a/xml/playerSpawnHill1_Building1.xml b/xml/playerSpawnHill1_Building1.xml
index f0c8a21..8fad154 100644
--- a/xml/playerSpawnHill1_Building1.xml
+++ b/xml/playerSpawnHill1_Building1.xml
@@ -1,9 +1,12 @@
 <?xml version="1.0"?>
 <IndoorWorld>
 	<style background="1" bgm="assets/music/theme_jazz.wav" />
-	<generation type="Random" width="300" />
 
-	<npc name="Bob" hasDialog="true" />
+	<floor width="300">
+		<npc name="Bob" hasDialog="true" />
+	</floor>
+
+	<floor width="200" />
 
 </IndoorWorld>
 
-- 
cgit v1.2.3