]> code.bitgloo.com Git - clyne/gamedev.git/commitdiff
complete world rewrite -- edgy
authorClyne Sullivan <tullivan99@gmail.com>
Mon, 29 Feb 2016 02:02:08 +0000 (21:02 -0500)
committerClyne Sullivan <tullivan99@gmail.com>
Mon, 29 Feb 2016 02:02:08 +0000 (21:02 -0500)
include/common.h
include/world.h
main.cpp
src/common.cpp
src/gameplay.cpp
src/ui.cpp
src/world.cpp

index 6ba6f03b7b6417ad1cd7c5d4436ea809d661b97d..08f0392b702dc7b505e28183b515df25693a56e2 100644 (file)
@@ -148,6 +148,9 @@ extern float VOLUME_SFX;
 
 #define getRand() rand()
 
+#define randGet     rand
+#define randInit    srand
+
 /**
  * Included in common.h is a prototype for DEBUG_prints, which writes a formatted
  * string to the console containing the callee's file and line number. This macro simplifies
@@ -227,4 +230,6 @@ int strCreateFunc(const char *equ);
 template<typename N, size_t s>
 size_t arrAmt(N (&)[s]){return s;}
 
+void UserError(std::string reason);
+
 #endif // COMMON_H
index c0668655eb103f073960b80397579f0bf572e741..f60c181a28dedd0311767d15779f154fe345ccab 100644 (file)
 #include <common.h>
 #include <entities.h>
 
-/**
- * Defines at what interval y values should be calculated for the array 'line'.
- */
-
-#define GEN_INC 10
-
-/**
- * Defines the lowest possible y value for a world line.
- */
-
-#define GEN_MIN  80
-
-/**
- * Defines the highest possible y value for a randomly generated world line.
- */
-
-#define GEN_MAX  110
+#define GROUND_HEIGHT_INITIAL   80
+#define GROUND_HEIGHT_MINIMUM   60
+#define GROUND_HEIGHT_MAXIMUM   110
 
+#define GROUND_HILLINESS        10
 
 /**
  * Defines how many game ticks it takes for a day to elapse.
@@ -44,7 +31,7 @@
 
 typedef enum {
        BG_FOREST,              /**< A forest theme. */
-       BG_WOODHOUSE    /**< An indoor wooden house theme. */
+       BG_WOODHOUSE,   /**< An indoor wooden house theme. */
 } WORLD_BG_TYPE;
 
 /**
@@ -74,12 +61,12 @@ typedef struct {
  * lines. Dirt color and grass properties are also kept track of here.
  */
 
-typedef struct line_t {
-       float y;                                /**< Height of this vertical line */
-       bool gs;                                /**< Show grass */
-       float gh[2];                    /**< Height of glass (2 blades per line) */
-       unsigned char color;    /**< Lightness of dirt (brown) */
-} line_t;
+typedef struct {
+    bool          grassUnpressed;
+    int           grassHeight[2];
+    float         groundHeight;
+    unsigned char groundColor;
+} WorldData;
 
 class World;
 
@@ -149,7 +136,7 @@ protected:
         * of elements provided by the function.
         */
         
-       struct line_t *line;
+       std::vector<WorldData> worldData;
        
        /**
         * Starting x coordinate.
@@ -157,7 +144,7 @@ protected:
         * calculate the width of the world.
         */
        
-       int x_start;
+       int worldStart;
        
        /**
         * Handle physics for a single entity.
@@ -193,7 +180,7 @@ protected:
         * An array of star coordinates.
         */
        
-       vec2 *star;
+       std::vector<vec2> star;
        
        /**
         * The Texturec object that holds the background sprites for this world.
@@ -308,7 +295,7 @@ public:
         * generate().
         */
        
-       World(void);
+       World( void );
        
        /**
         * Frees resources taken by the world.
@@ -388,14 +375,6 @@ public:
        
        virtual void generate(unsigned int width);
        
-       /**
-        * Generates a world of the provided width using the given function to
-        * determine ground coordinates. The given y coordinates from the function
-        * are limited to a certain range, most likely from GEN_MIN to 2000.
-        */
-       
-       void generateFunc(unsigned int width,float(*func)(float));
-       
        /**
         * Sets the background theme, collecting the required textures into a
         * Texturec object.
@@ -477,12 +456,6 @@ public:
        void load(void);
 };
 
-/*
- *     Gets a good base y value for background rendering.
-*/
-
-float worldGetYBase(World *w);
-
 /*
  *     IndoorWorld - Indoor settings stored in a World class ;)
  */
index fa08beb68e647f45bb1223111cc8b2c94e6bf60b..abea57823766a9a96e185dde234fff104f6d2f1d 100644 (file)
--- a/main.cpp
+++ b/main.cpp
@@ -77,12 +77,6 @@ World        *currentWorld = NULL;
 
 Player         *player;
 
-/**
- * Tells if player is currently inside a world entered through a Structure.
- */
-
-extern bool worldInside;
-
 /**
  * TODO
  */
@@ -450,7 +444,7 @@ void mainLoop(void){
                                                currentTime = 0,        //
                                                prevPrevTime= 0;        //
        World *prev;
-       
+    
        if(!currentTime)                                                // Initialize currentTime if it hasn't been
                currentTime=millis();
        
@@ -471,12 +465,12 @@ void mainLoop(void){
 
        prev = currentWorld;
        ui::handleEvents();
-       
+    
        if(prev != currentWorld){
                currentWorld->bgmPlay(prev);
                ui::dialogBoxExists = false;
        }
-       
+    
        if(prevPrevTime + MSEC_PER_TICK <= currentTime){
                logic();
                prevPrevTime = currentTime;
@@ -485,9 +479,9 @@ void mainLoop(void){
        /*
         * Update player and entity coordinates.
         */
-       
+     
        currentWorld->update(player,deltaTime);
-       
+    
        /*
         * Update debug variables if necessary
         */
@@ -499,7 +493,6 @@ void mainLoop(void){
                fps=1000/deltaTime;
        else if(!(debugDiv%10))
                debugY = player->loc.y;
-
 MENU:
        render();
 }
@@ -521,7 +514,7 @@ void render(){
        
        if(currentWorld->getTheWidth() < (int)SCREEN_WIDTH){
                offset.x = 0;
-       }else if(!worldInside){
+       }else{
                if(player->loc.x - SCREEN_WIDTH/2 < currentWorld->getTheWidth() * -0.5f)
                        offset.x = ((currentWorld->getTheWidth() * -0.5f) + SCREEN_WIDTH / 2) + player->width / 2;
                if(player->loc.x + player->width + SCREEN_WIDTH/2 > currentWorld->getTheWidth() *  0.5f)
@@ -628,11 +621,6 @@ void render(){
        player->inv->draw();
 
        /*
-<<<<<<< HEAD
-        *      Here we draw a black overlay if it's been requested.
-       */
-
-        /*
         * Here we draw a black overlay if it's been requested.
         */
        
index 01c87794532b8cda73071a696c1f9993f6df9895..6dc2c46816fa61b6b2c1c59ddf3e3f3174f7c239 100644 (file)
@@ -95,6 +95,13 @@ const char *readFile(const char *path){
        return buf;
 }
 
+void
+UserError( std::string reason )
+{
+    std::cout << "User error: " << reason << "!" << std::endl;
+    abort();
+}
+
 /*int strCreateFunc(const char *equ){
        static unsigned int size;
        static char *filebuf;
index e3c117115310c005afae15feab07677057e7257e..d983804d86870aabfa60d20115df2ae9dc3e7c4b 100644 (file)
@@ -283,12 +283,12 @@ void initEverything(void){
                        /*
                         * Read in the XML file.
                         */
-                       
+               
                        currentWorld = loadWorldFromXML(xmlFiles[i].c_str());
                        break;
                }
        }
-
+       
        pauseMenu.items.push_back(ui::createParentButton({-256/2,0},{256,75},{0.0f,0.0f,0.0f}, "Resume"));
        pauseMenu.items.push_back(ui::createChildButton({-256/2,-100},{256,75},{0.0f,0.0f,0.0f}, "Options"));
        pauseMenu.items.push_back(ui::createButton({-256/2,-200},{256,75},{0.0f,0.0f,0.0f}, "Save and Quit", ui::quitGame));
index d66c1706c9a6c306a13803afdb435e6b7c04c6c1..6e616a7576908df733b0307d68b55843c1c4d6e4 100644 (file)
 #include <ui.h>
 
-/**
- * A macro for easier SDL key reading
- */
+/*
+ *     Create a macro to easily access SDL keypresses
+*/
 
 #define SDL_KEY e.key.keysym.sym
 
+extern std::vector<menuItem>optionsMenu;
+
+extern SDL_Window *window;
+
 /*
- * Important to have..
- */
+ *     External references for updating player coords / current world.
+*/
 
-extern SDL_Window      *window;
-extern Player          *player;
-extern World           *currentWorld;
-extern bool                     gameRunning;
+extern Player *player;
+extern World  *currentWorld;
 
 /*
- * NPC AI functions are given to the NPCs within UI loops.
- */
+ *     In the case of dialog, some NPC quests can be preloaded so that they aren't assigned until
+ *     the dialog box closes. Reference variables for that here.
+*/
 
 extern std::vector<int (*)(NPC *)> AIpreload;
 extern std::vector<NPC *> AIpreaddr;
 
 /*
- * Variables and objects used with the FreeType library and font rendering.
- */
-
-#define FT_CHAR_COUNT  93
+ *     Pressing ESC or closing the window will set this to false.
+*/
 
-typedef struct {
-       GLuint  tex;    /**< OpenGL texture object                               */
-       ivec2   wh;             /**< Width and height of the character   */
-       ivec2   bl;             /**< Offset for drawing the character?   */
-       ivec2   ad;             /**< Number of pixels to advance cursor. */
-} FT_Tex;
+extern bool gameRunning;
 
-static FT_Tex ftmap16[FT_CHAR_COUNT],
-                         ftmap24[FT_CHAR_COUNT],
-                         *ftmapptr;
+/*
+ *     Freetype variables, and a GLuint for referencing rendered letters.
+*/
 
 static FT_Library   ftl;
 static FT_Face      ftf;
+static GLuint       ftex[93];
+static vec2                    ftexwh[93];
+static vec2                    ftexbl[93];
+static vec2                    ftexad[93];
+
 static unsigned char fontColor[3] = {255,255,255};
 
 /*
  *     Variables for dialog boxes / options.
- */
+*/
 
-static char                     dialogBoxText[512];
-static char                    *dialogOptText[4];
-static float            dialogOptLoc[4][3];
+static char dialogBoxText[512];
+static char *dialogOptText[4];
+static float dialogOptLoc[4][3];
 static unsigned char dialogOptCount = 0;
-static bool                     typeOutDone = true;
-static int                      dialogPassiveTime = 0;
-
-/*
- * Menu-related objects
- */
+static bool typeOutDone = true;
 
-extern Menu *currentMenu;
+extern MenucurrentMenu;
 extern Menu pauseMenu;
 
-/**
- * The sound made when displaying characters with dialogBox or importantText.
- */
 
 static Mix_Chunk *dialogClick;
 
-/*
- * Other sounds
- */
-
-Mix_Chunk *battleStart;
-Mix_Chunk *sanic;
-
-/**
- * A reference to the main loop function for functions like waitForCover().
- */
-
 extern void mainLoop(void);
 
 /*
- * Overlay variables
- */
+ *     Toggled by pressing 'q', disables some controls when true.
+*/
 
 bool fadeEnable = false;
-bool fadeWhite  = false;
-bool fadeFast   = false;
-
+bool fadeWhite = false;
+bool fadeFast = false;
 unsigned int fadeIntensity = 0;
 
-/**
- * Set to true when the player is in a battle area (i.e. currentWorld points to
- * an Arena).
- */
-
 bool inBattle = false;
+Mix_Chunk *battleStart;
 
-
+Mix_Chunk *sanic;
 
 void Menu::gotoParent(){
-       if(!parent){
+       if(parent == NULL){
                currentMenu = NULL;
                updateConfig();
-       }else
+       }else{
                currentMenu = parent;
+       }
 }
 
 void Menu::gotoChild(){
-       if(!child)
+       if(child == NULL){
                currentMenu = NULL;
-       else
+       }else{
                currentMenu = child;
+       }
 }
 
-static vec2 premouse={0,0};
-
 namespace ui {
        
-       /**
-        * The current position of the mouse.
-        */
+       /*
+        *      Mouse coordinates.
+       */
        
        vec2 mouse;
+       static vec2 premouse={0,0};             
 
-       /**
-        * If true, debug information will be drawn to the screen.
-        */
-       
-       bool debug = false;
-       
-       /**
-        * If true, lines should be drawn to the player when the debug menu is open.
-        */
+       /*
+        *      Variety of keydown bools
+       */
+       bool edown;
+
+       /*
+        *      Debugging flags.
+       */
        
+       bool debug=false;
        bool posFlag=false;
-       
-       /**
-        * If true, the player will be able to move when the current dialog box is
-        * displayed.
-        */
-       
        bool dialogPassive = false;
+       int dialogPassiveTime = 0;
 
-       /**
-        * When set to true the dialog box will attempt to display.
-        */
        
-       bool dialogBoxExists = false;
-       
-       /**
-        * When set to true the text will display as 'important' text.
-        */
+       /*
+        *      Dialog stuff that needs to be 'public'.
+       */
        
+       bool dialogBoxExists = false;
        bool dialogImportant = false;
-       
-       /**
-        * Contains the last chosen dialog option.
-        */
-       
        unsigned char dialogOptChosen = 0;
        
-       /**
-        * Determines how many characters can be displayed in a dialog box before
-        * a new line is required.
-        */
-       
        unsigned int textWrapLimit = 110;
        
-       /**
-        * The current font size.
-        * 
-        * DO NOT change this directly, use setFontSize() instead.
-        */
+       /*
+        *      Current font size. Changing this WILL NOT change the font size, see setFontSize() for
+        *      actual font size changing.
+       */
        
        unsigned int fontSize;
 
-       /**
-        * Initializes the Freetype library, and other UI related variables.
-        */
+       /*
+        *      Initialises the Freetype library, and sets a font size.
+       */
 
        void initFonts(void){
-               
-               // init the FreeType library
                if(FT_Init_FreeType(&ftl)){
-                       std::cout<<"Error! Couldn't initialize the FreeType library."<<std::endl;
+                       std::cout<<"Error! Couldn't initialize freetype."<<std::endl;
                        abort();
                }
-               
-               fontSize = 16;
-               
-               //ftmap16 = new FT_Tex[FT_CHAR_COUNT];
-               //ftmap24 = new FT_Tex[FT_CHAR_COUNT];
-               
-               memset(&ftmap16, 0, FT_CHAR_COUNT * sizeof(FT_Tex));
-               memset(&ftmap24, 0, FT_CHAR_COUNT * sizeof(FT_Tex));
-               
+               fontSize=0;
+               memset(&ftex,0,93*sizeof(GLuint));
 #ifdef DEBUG
                DEBUG_printf("Initialized FreeType2.\n",NULL);
 #endif // DEBUG
-
-               /*
-                * Load UI related sounds.
-                */
-
                dialogClick = Mix_LoadWAV("assets/sounds/click.wav");
                battleStart = Mix_LoadWAV("assets/sounds/frig.wav");
-               sanic           = Mix_LoadWAV("assets/sounds/sanic.wav");
+               sanic = Mix_LoadWAV("assets/sounds/sanic.wav");
+               //Mix_Volume(1,50);
        }
        
-       /**
-        * Frees resources taken by the UI facilities
-        */
-       
        void destroyFonts(void){
-               //delete[] ftmap16;
-               //delete[] ftmap24;
-               
                FT_Done_Face(ftf);
                FT_Done_FreeType(ftl);
                
@@ -225,118 +163,92 @@ namespace ui {
                Mix_FreeChunk(sanic);
        }
        
-       /**
-        * Sets a new font face to use (*.ttf).
-        */
+       /*
+        *      Sets a new font family to use (*.ttf).
+       */
        
        void setFontFace(const char *ttf){
-               std::unique_ptr<uint8_t[]> rgbaBuf;
-               size_t rgbaBufSize, ftsize;
-               unsigned int i,j;
-               FT_Error fte;
-               
-               if((fte = FT_New_Face(ftl,ttf,0,&ftf))){
-                       std::cout<<"Error! Couldn't open "<<ttf<<" (Error "<<fte<<")."<<std::endl;
+               if(FT_New_Face(ftl,ttf,0,&ftf)){
+                       std::cout<<"Error! Couldn't open "<<ttf<<"."<<std::endl;
                        abort();
                }
-               
 #ifdef DEBUG
                DEBUG_printf("Using font %s\n",ttf);
 #endif // DEBUG
-
+       }
+       
+       /*
+        *      Sets a new font size (default: 12).
+       */
+       
+       void setFontSize(unsigned int size){
+               unsigned int i,j;
+               char *buf;
+               
+               fontSize=size;
+               FT_Set_Pixel_Sizes(ftf,0,fontSize);
+               
                /*
-                * Load the font in the two sizes we use, 16px and 24px.
-                */
+                *      Pre-render 'all' the characters.
+               */
                
-               ftmapptr = ftmap16;
-               ftsize = 16;
-
-               do{
-                       FT_Set_Pixel_Sizes(ftf, 0, ftsize);
-                       
-                       // allocate texture space
-                       for(i=0; i < FT_CHAR_COUNT; i++)
-                               glGenTextures(1, &ftmapptr[i].tex);
-                       
-                       // Load all characters we expect to use
-                       for(i=33; i<126; i++){
-                       
-                               // Load the bitmap for the current character.
-                               if(FT_Load_Char(ftf,i,FT_LOAD_RENDER)){
-                                       std::cout<<"Error! Unsupported character "<<(char)i<<" ("<<i<<")."<<std::endl;
-                                       abort();
-                               }
-                               
-                               /*
-                                * Set up the OpenGL texture thing.
-                                */
-                       
-                               glBindTexture(GL_TEXTURE_2D, ftmapptr[i-33].tex);
-                               
-                               glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S                , GL_CLAMP_TO_EDGE);
-                               glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T                , GL_CLAMP_TO_EDGE);
-                               glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER    , GL_LINEAR              );
-                               glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER    , GL_LINEAR              );
-                               
-                               glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
-                       
-                               /*
-                                * Convert the bitmap font given to us from FreeType into an RGBA
-                                * format, for ease of drawing.
-                                */
-                       
-                               rgbaBuf.reset(new uint8_t [(rgbaBufSize = ftf->glyph->bitmap.width * ftf->glyph->bitmap.rows * 4)]);
-                               rgbaBufSize /= 4;
+               glDeleteTextures(93,ftex);      //      delete[] any already-rendered textures
+               glGenTextures(93,ftex);         //      Generate new texture name/locations?
+               
+               for(i=33;i<126;i++){
+               
+                       /*
+                        *      Load the character from the font family file.
+                       */
+               
+                       if(FT_Load_Char(ftf,i,FT_LOAD_RENDER)){
+                               std::cout<<"Error! Unsupported character "<<(char)i<<" ("<<i<<")."<<std::endl;
+                               abort();
+                       }
                        
-                               // populate the buffer
-                               for(j=0; j < rgbaBufSize; j++){
-                                       rgbaBuf[j * 4] = rgbaBuf[j * 4 + 1] = rgbaBuf[j * 4 + 2] = 255;
-                                       rgbaBuf[j * 4 + 3] = ftf->glyph->bitmap.buffer[j] ? 255 : 0;
-                               }
-                               
-                               // save important character information
-                               ftmapptr[i-33].wh = { (int)ftf->glyph->bitmap.width, (int)ftf->glyph->bitmap.rows };
-                               ftmapptr[i-33].bl = { ftf->glyph->bitmap_left,            ftf->glyph->bitmap_top       };
-                               ftmapptr[i-33].ad = { ftf->glyph->advance.x >> 6,         ftf->glyph->advance.y >> 6   };
+                       /*
+                        *      Transfer the character's bitmap (?) to a texture for rendering.
+                       */
+               
+                       glBindTexture(GL_TEXTURE_2D,ftex[i-33]);
+                       glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S         ,GL_CLAMP_TO_EDGE);
+                       glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T         ,GL_CLAMP_TO_EDGE);
+                       glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER     ,GL_LINEAR               );
+                       glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER     ,GL_LINEAR               );
+                       glPixelStorei(GL_UNPACK_ALIGNMENT,1);
+               
+                       /*
+                        *      The just-created texture will render red-on-black if we don't do anything to it, so
+                        *      here we create a buffer 4 times the size and transform the texture into an RGBA array,
+                        *      making it white-on-black.
+                       */
                        
-                               // do the thing
-                               glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, ftf->glyph->bitmap.width, ftf->glyph->bitmap.rows, 0, GL_RGBA, GL_UNSIGNED_BYTE, rgbaBuf.get());
-                               rgbaBuf.reset();
-                       }
-
-                       // repeat for 24px, or exit
-                       if(ftmapptr == ftmap16){
-                               ftmapptr = ftmap24;
-                               ftsize = 24;
-                       }else{
-                               break;
+                       buf = new char[ftf->glyph->bitmap.width * ftf->glyph->bitmap.rows * 4];
+               
+                       for(j=0;j<ftf->glyph->bitmap.width*ftf->glyph->bitmap.rows;j++){
+                               buf[j*4  ]=255;//fontColor[0];
+                               buf[j*4+1]=255;//fontColor[1];
+                               buf[j*4+2]=255;//fontColor[2];
+                               buf[j*4+3]=ftf->glyph->bitmap.buffer[j] ? 255 : 0;
+                               //buf[j*4+3]=ftf->glyph->bitmap.buffer[j];
                        }
                        
-               }while(1);
-
-               setFontSize(16);
-       }
-       
-       /**
-        * Sets a new font size and renders the necessary characters (default font
-        * size: 16; 24 for importantText).
-        */
-       
-       void setFontSize(unsigned int size){
-               switch((fontSize = size)){
-               case 24:
-                       ftmapptr = ftmap24;
-                       break;
-               default:
-               case 16:
-                       ftmapptr = ftmap16;
-                       break;
+                       ftexwh[i-33].x=ftf->glyph->bitmap.width;
+                       ftexwh[i-33].y=ftf->glyph->bitmap.rows;
+                       ftexbl[i-33].x=ftf->glyph->bitmap_left;
+                       ftexbl[i-33].y=ftf->glyph->bitmap_top;
+                       ftexad[i-33].x=ftf->glyph->advance.x>>6;
+                       ftexad[i-33].y=ftf->glyph->advance.y>>6;
+               
+                       glTexImage2D(GL_TEXTURE_2D,0,GL_RGBA,ftf->glyph->bitmap.width,ftf->glyph->bitmap.rows,0,GL_RGBA,GL_UNSIGNED_BYTE,buf);  
+                       
+                       delete[] buf;   //free(buf);
                }
        }
        
-       /**
-        * Set a color for font rendering (default: white).
-        */
+       /*
+        *      Set a color for font rendering (default: white).
+       */
        
        void setFontColor(unsigned char r,unsigned char g,unsigned char b){
                fontColor[0]=r;
@@ -344,472 +256,429 @@ namespace ui {
                fontColor[2]=b;
        }
        
-       /**
-        * Draws a character at the specified coordinates, aborting if the character is undrawable.
-        */
+       /*
+        *      Draws a character at the specified coordinates, aborting if the character is unknown.
+       */
        
-       ivec2 putChar(float x,float y,char c){
-               ivec2 c1,c2;
+       vec2 putChar(float xx,float yy,char c){
+               vec2 c1,c2;
 
-               // calculate coordinates
-               c1 = { (int)floor(x) + ftmapptr[c-33].bl.x,
-                      (int)floor(y) + ftmapptr[c-33].bl.y };
-               c2 = ftmapptr[c-33].wh;
+               int x = xx, y = yy;
+                               
+               /*
+                *      Get the width and height of the rendered character.
+               */
+               
+               c1={(float)floor(x)+ftexbl[c-33].x,
+                   (float)floor(y)+ftexbl[c-33].y};
+               c2=ftexwh[c-33];
                
                /*
-                *      Draw the character
-                */
+                *      Draw the character:
+               */
                
                glEnable(GL_TEXTURE_2D);
-               glBindTexture(GL_TEXTURE_2D, ftmapptr[c-33].tex);
-               
+               glBindTexture(GL_TEXTURE_2D,ftex[c-33]);
                glPushMatrix();
                glTranslatef(0,-c2.y,0);
-               
                glBegin(GL_QUADS);
-                       glColor3ub(fontColor[0], fontColor[1], fontColor[2]);
-                       
-                       glTexCoord2f(0, 1); glVertex2f(c1.x       , c1.y           );
-                       glTexCoord2f(1, 1); glVertex2f(c1.x + c2.x, c1.y           );
-                       glTexCoord2f(1, 0); glVertex2f(c1.x + c2.x, c1.y + c2.y);
-                       glTexCoord2f(0, 0); glVertex2f(c1.x       , c1.y + c2.y);
-                       
+                       glColor3ub(fontColor[0],fontColor[1],fontColor[2]);
+                       glTexCoord2f(0,1);glVertex2f(c1.x     ,c1.y             );
+                       glTexCoord2f(1,1);glVertex2f(c1.x+c2.x,c1.y             );
+                       glTexCoord2f(1,0);glVertex2f(c1.x+c2.x,c1.y+c2.y);
+                       glTexCoord2f(0,0);glVertex2f(c1.x     ,c1.y+c2.y);
                glEnd();
-               
                glPopMatrix();
                glDisable(GL_TEXTURE_2D);
-
-               // return the number of pixels the cursor should move
-               return ftmapptr[c-33].ad;
+               
+               /*
+                * return the width.
+               */
+               
+               return ftexad[c-33];//(vec2){c2.x,ftexad[c-33].y};
        }
        
-       /**
-        * Draw a string at the specified coordinates.
-        */
+       /*
+        *      Draw a string at the specified coordinates.
+       */
        
        float putString(const float x,const float y,const char *s){
-               unsigned int i = 0;
-               ivec2 add;
-               vec2 off = { (float)floor(x), (float)floor(y) };
+               unsigned int i=0;
+               float xo=x,yo=y;
+               vec2 add;
                
                /*
                 *      Loop on each character:
-                */
+               */
                
                do{
-                       // wrap text if necessary
-                       if(i && (i / (float)textWrapLimit == i / textWrapLimit)){
-                               off.y -= fontSize * 1.05;
-                               off.x = x;
-                               
-                               // skip a space if it's there since we just newline'd
+                       if(i && ((i / 110.0) == (i / 110))){
+                               yo-=fontSize*1.05;
+                               xo=x;
                                if(s[i] == ' ')
                                        i++;
                        }
-                       
-                       // handle newlines
                        if(s[i] == '\n'){
-                               off.y -= fontSize * 1.05;
-                               off.x  = x;
-
-                       // (TODO) handle carriage returns and tabs
+                               yo-=fontSize*1.05;
+                               xo=x;
                        }else if(s[i] == '\r' || s[i] == '\t'){
-
-                       // handle spaces
-                       }else if(s[i]==' '){
-                               off.x += fontSize / 2;
-                               
-                       // handle backspaces
-                       }else if(s[i]=='\b'){
-                               off.x -= add.x;
-
-                       // handle everything else
+                       /*if(s[i] == '\n'){
+                               yo-=fontSize*1.05;
+                               xo=x;
+                       */}else if(s[i]==' '){  //      Handle spaces
+                               xo+=fontSize/2;
+                       }else if(s[i]=='\b'){   //      Handle backspaces?
+                               xo-=add.x;
                        }else{
-                               add = putChar(off.x, off.y, s[i]);
-                               off.x += add.x;
-                               off.y += add.y;
+                               add=putChar(floor(xo),floor(yo),s[i]);
+                               xo+=add.x;
+                               yo+=add.y;
                        }
-                       
                }while(s[++i]);
                
-               // return string width
-               return off.x;
+               return xo;      // i.e. the string width
        }
        
-       /**
-        * Print a string center-aligned on the specified coordinate.
-        */
-       
        float putStringCentered(const float x,const float y,const char *s){
                unsigned int i = 0;
                float width = 0;
                
-               /*
-                * Calculate the string's width by cycling through each character.
-                */
-               
                do{
-                       // handle newlines
-                       if(s[i]=='\n'){
-
-                       // handle spaces
-                       }else if(s[i]==' '){
-                               width += fontSize / 2;
-
-                       // handle backspaces
-                       }else if(s[i]=='\b'){
-
-                       // handle everything else
-                       }else
-                               width += ftmapptr[i].wh.x + fontSize * .1;
-
+                       if(s[i]=='\n'){                 //      Handle newlines
+                               // TODO
+                       }else if(s[i]==' '){    //      Handle spaces
+                               width+=fontSize/2;
+                       }else if(s[i]=='\b'){   //      Handle backspaces?
+                               // Why?
+                               // Cuz
+                       }else{
+                               width+=ftexwh[i].x+fontSize*.1;
+                       }
                }while(s[++i]);
-
-               // print the string
-               return putString(floor(x - width / 2), y, s);
+               
+               putString(floor(x-width/2),y,s);
+               return width;
        }
        
-       /**
-        * Draw a string in a typewriter-esque fashion.
-        * 
-        * This function is expected to be called as it is rendered, slowly allowing
-        * more characters to be drawn as it is looped on. Only one call to this
-        * function can be handled at a time.
-        */
-
-       static char *typeOutStr = NULL;
+       /*
+        *      Draw a string in a typewriter-esque fashion. Each letter is rendered as calls are made
+        *      to this function. Passing a different string to the function will reset the counters.
+       */
+
+       static char *ret = NULL;
        char *typeOut(char *str){
-               static unsigned int sinc=0,     //      Acts as a delayer for the space between each character.
+               static unsigned int sinc,       //      Acts as a delayer for the space between each character.
                                                        linc=0, //      Contains the number of letters that should be drawn.
                                                        size=0; //      Contains the full size of the current string.
-
-               // allocate memory for the string if necessary
-               if(!typeOutStr){
-                       typeOutStr = new char[512];
-                       memset(typeOutStr, 0, 512 * sizeof(char));
+               //static char *ret = NULL;
+               
+               /*
+                *      Create a well-sized buffer if we haven't yet.
+               */
+               
+               if(!ret){
+                       ret = new char[512];    //(char *)calloc(512,sizeof(char));
+                       memset(ret,0,512*sizeof(char));
                }
                
                /*
                 *      Reset values if a new string is being passed.
-                */
+               */
                
-               if(strncmp(typeOutStr, str, linc - 1)){
-                       memset(typeOutStr, 0, 512);             // Zero the buffer
-                       size = strlen(str);                             // Set the new target string size
-                       linc = 0;                                               // Reset the incrementers
-                       sinc = 1;                                               //
+               if(strncmp(ret,str,linc-1)){
+                       memset(ret,0,512);              //      Zero the buffer
+                       size=strlen(str);               //      Set the new target string size
+                       linc=0;                                 //      Reset the incrementers
+                       sinc=1;
                        typeOutDone = false;
                }
                
                /*
                 *      Draw the next letter if necessary.
-                */
+               */
                
                if(typeOutDone)
                        return str;
-               else if(++sinc == 2){
-                       sinc = 0;
+               else if(++sinc==2){
+                       sinc=0;
                        
-                       // add next character to output string
-                       strncpy(typeOutStr + linc,str + linc, 1);
+                       strncpy(ret+linc,str+linc,1);   //      Get next character
                        
-                       if(linc < size)
+                       if(linc<size)
                                linc++;
                        else
                                typeOutDone = true;
                }
-
-               // return the string
-               return typeOutStr;
+               
+               return ret;             //      The buffered string.
        }
        
-       /**
-        * Draw a formatted string to the specified coordinates.
-        */
+       /*
+        *      Draw a formatted string to the specified coordinates.
+       */
        
        float putText(const float x,const float y,const char *str,...){
                va_list args;
-               std::unique_ptr<char[]> buf (new char[512]);
+               char *buf;
+               float width;
+               
+               /*
+                *      Create a wimpy buffer.
+               */
+               
+               buf = new char[512];    //(char *)calloc(128,sizeof(char));
+               memset(buf,0,512*sizeof(char));
                
-               // create the formatted string
-               va_start(args, str);
-               vsnprintf(buf.get(), 512, str, args);
+               /*
+                *      Handle the formatted string, printing it to the buffer.
+               */
+               
+               va_start(args,str);
+               vsnprintf(buf,512,str,args);
                va_end(args);
                
-               return putString(x, y, buf.get());
+               /*
+                *      Draw the string, free resources, return the width of the string.
+               */
+               
+               width=putString(x,y,buf);
+               delete[] buf;   //free(buf);
+               
+               return width;
        }
-       
-       /**
-        * Prints a character dialog box.
-        * 
-        * This function sets up the variables necessary to draw a dialog box. If
-        * `opt` contains a valid string, options will be printed with the dialog
-        * box. If the box is passive, the player will be allowed to move while it
-        * is being displayed.
-        */
-       
        void dialogBox(const char *name,const char *opt,bool passive,const char *text,...){
                va_list dialogArgs;
-               size_t len;
+               unsigned int len;
+               char *sopt,*soptbuf;
                
                dialogPassive = passive;
                
-               // clear the buffer
-               memset(dialogBoxText, '\0', 512);
+               /*
+                *      Set up the text buffer.
+               */
+               
+               memset(dialogBoxText,0,512);
+               
+               /*
+                *      Get the text ready for rendering.
+               */
                
-               // create the string
-               strcpy(dialogBoxText, name);
-               strcat(dialogBoxText, ": ");
+               len=strlen(name);
+               strcpy(dialogBoxText    ,name);
+               strcpy(dialogBoxText+len,": ");
+               len+=2;
                
-               len=strlen(dialogBoxText);
                va_start(dialogArgs,text);
-               vsnprintf(dialogBoxText + len, 512 - len, text, dialogArgs);
+               vsnprintf(dialogBoxText+len,512-len,text,dialogArgs);
                va_end(dialogArgs);
                                
-               // free old option text
+               /*
+                *      Set up option text.
+               */
+               
                while(dialogOptCount){
                        if(dialogOptText[dialogOptCount]){
-                               delete[] dialogOptText[dialogOptCount];
+                               delete[] dialogOptText[dialogOptCount]; //free(dialogOptText[dialogOptCount]);
                                dialogOptText[dialogOptCount] = NULL;
                        }
-                       
                        dialogOptCount--;
                };
 
+               dialogOptCount = 0;
                dialogOptChosen = 0;
-               memset(&dialogOptLoc, 0, sizeof(float) * 12);
+               memset(&dialogOptLoc,0,sizeof(float)*12);
                
-               // handle options if desired
-               if(opt){
-                       std::unique_ptr<char[]> soptbuf (new char[strlen(opt) + 1]);
-                       char *sopt = strtok(soptbuf.get(), ":");
-
-                       // cycle through options
-                       while(sopt){
-                               strcpy( (dialogOptText[dialogOptCount++] = new char[strlen(sopt) + 1]), sopt);
-                               sopt = strtok(NULL,":");
+               if(opt != NULL){
+                       
+                       soptbuf = new char[strlen(opt)+1];
+                       strcpy(soptbuf,opt);
+                       
+                       sopt=strtok(soptbuf,":");
+                       while(sopt != NULL){
+                               dialogOptText[dialogOptCount] = new char[strlen(sopt)+1];       //(char *)malloc(strlen(sopt));
+                               strcpy(dialogOptText[dialogOptCount++],sopt);
+                               sopt=strtok(NULL,":");
                        }
+                       
+                       delete[] soptbuf;
+
                }
                
-               // allow box to be displayed
+               /*
+                *      Tell draw() that the box is ready. 
+               */
+               
                dialogBoxExists = true;
                dialogImportant = false;
                
-               // kill the string created by typeOut if it contains something
-               if(typeOutStr)
-                       *typeOutStr = '\0';
+               if(ret)
+                       ret[0] = '\0';
        }
-       
-       /**
-        * Wait for a dialog box to be dismissed.
-        */
-       
        void waitForDialog(void){
                do{
                        mainLoop();
                }while(ui::dialogBoxExists);
        }
-       
-       /**
-        * Wait for the screen to be fully covered through toggle___().
-        */
-       
        void waitForCover(void){
                do{
                        mainLoop();
                }while(fadeIntensity < 255);
                fadeIntensity = 255;
        }
-       
-       /**
-        * Prepare formatted 'important' string for drawing.
-        * 
-        * "Important" text will display in a bigger font size at the center of the
-        * screen. Usually accompanied by a cover from toggle___() and limits on
-        * player controls.
-        */
-       
+       void waitForNothing(unsigned int ms){
+               unsigned int target = millis() + ms;
+               do{
+                       mainLoop();
+               }while(millis() < target);
+       }
        void importantText(const char *text,...){
                va_list textArgs;
 
-               // clear dialog buffer (we share the same)
-               memset(dialogBoxText, '\0', 512);
+               //if(!player->ground)return;
+
+               memset(dialogBoxText,0,512);
 
-               // format the string
                va_start(textArgs,text);
-               vsnprintf(dialogBoxText, 512, text, textArgs);
+               vsnprintf(dialogBoxText,512,text,textArgs);
                va_end(textArgs);
 
-               // set draw flags
                dialogBoxExists = true;
                dialogImportant = true;
+               //toggleBlack();
        }
-       
-       /**
-        * Draw a passive 'important' text for a certain duration.
-        */
-       
        void passiveImportantText(int duration, const char *text,...){
                va_list textArgs;
 
-               // clear buffer
-               memset(dialogBoxText, '\0', 512);
+               //if(!player->ground)return;
+
+               memset(dialogBoxText,0,512);
 
-               // format the string
                va_start(textArgs,text);
-               vsnprintf(dialogBoxText, 512, text, textArgs);
+               vsnprintf(dialogBoxText,512,text,textArgs);
                va_end(textArgs);
 
-               // set draw flags
                dialogBoxExists = true;
                dialogImportant = true;
                dialogPassive = true;
                dialogPassiveTime = duration;
        }
 
-       /**
-        * Draws all UI-related elements to the screen.
-        */
 
        void draw(void){
                unsigned char i;
                float x,y,tmp;
                char *rtext;
                
-               // handle dialog box / important text
                if(dialogBoxExists){
                        
-                       rtext = typeOut(dialogBoxText);
+                       rtext=typeOut(dialogBoxText);
                        
                        if(dialogImportant){
-                               setFontColor(255, 255, 255);
-                               
-                               // handle timeout
-                               if(dialogPassive && (dialogPassiveTime -= deltaTime) <= 0){
-                                       dialogPassive = false;
-                                       dialogImportant = false;
-                                       dialogBoxExists = false;
+                               setFontColor(255,255,255);
+                               if(dialogPassive){
+                                       dialogPassiveTime -= deltaTime;
+                                       if(dialogPassiveTime < 0){
+                                               dialogPassive = false;
+                                               dialogImportant = false;
+                                               dialogBoxExists = false;
+                                       }
                                }
-                               
-                               // draw text
                                if(fadeIntensity == 255 || dialogPassive){
                                        setFontSize(24);
-                                       putStringCentered(offset.x, offset.y, rtext);
+                                       putStringCentered(offset.x,offset.y,rtext);
                                        setFontSize(16);
                                }
-                       }else{ // normal dialog box
-                               x =  offset.x - SCREEN_WIDTH  / 2  + HLINE * 8;
-                               y = (offset.y + SCREEN_HEIGHT / 2) - HLINE * 8;
+                       }else{
+                       
+                               x=offset.x-SCREEN_WIDTH/2+HLINE*8;
+                               y=(offset.y+SCREEN_HEIGHT/2)-HLINE*8;
                        
-                               // draw white border
-                               glColor3ub(255, 255, 255);
+                       
+                               glColor3ub(255,255,255);
                                glBegin(GL_LINE_STRIP);
-                                       glVertex2f(x - 1                                                        , y + 1                                         );
-                                       glVertex2f(x + 1 + SCREEN_WIDTH - HLINE * 16, y + 1                                             );
-                                       glVertex2f(x + 1 + SCREEN_WIDTH - HLINE * 16, y - 1 - SCREEN_HEIGHT / 4 );
-                                       glVertex2f(x - 1                                                        , y - 1 - SCREEN_HEIGHT / 4 );
-                                       glVertex2f(x                                                            , y + 1                                         );
+                                       glVertex2f(x-1                                          ,y+1);
+                                       glVertex2f(x+1+SCREEN_WIDTH-HLINE*16,y+1);
+                                       glVertex2f(x+1+SCREEN_WIDTH-HLINE*16,y-1-SCREEN_HEIGHT/4);
+                                       glVertex2f(x-1                                          ,y-1-SCREEN_HEIGHT/4);
+                                       glVertex2f(x                                            ,y+1);
                                glEnd();
                        
-                               // draw black box
-                               glColor3ub(0, 0, 0);
-                               glRectf(x, y, x + SCREEN_WIDTH - HLINE * 16, y - SCREEN_HEIGHT / 4);
+                               glColor3ub(0,0,0);
+                               glRectf(x,y,x+SCREEN_WIDTH-HLINE*16,y-SCREEN_HEIGHT/4);
                        
-                               // draw typeOut'd text
-                               putString(x + HLINE, y - fontSize - HLINE, (rtext = typeOut(dialogBoxText)));
+                               rtext=typeOut(dialogBoxText);
                        
-                               // draw / handle dialog options if they exist
-                               for(i = 0; i < dialogOptCount; i++){
-                                       setFontColor(255, 255, 255);
-                                       
-                                       // draw option
-                                       tmp = putStringCentered(offset.x, dialogOptLoc[i][1], dialogOptText[i]);
-                                       
-                                       // get coordinate information on option
+                               putString(x+HLINE,y-fontSize-HLINE,rtext);
+                       
+                               for(i=0;i<dialogOptCount;i++){
+                                       setFontColor(255,255,255);
+                                       tmp = putStringCentered(offset.x,dialogOptLoc[i][1],dialogOptText[i]);
                                        dialogOptLoc[i][2] = offset.x + tmp;
                                        dialogOptLoc[i][0] = offset.x - tmp;
                                        dialogOptLoc[i][1] = y - SCREEN_HEIGHT / 4 + (fontSize + HLINE) * (i + 1);
-                                       
-                                       // make text yellow if the mouse hovers over the text
-                                       if(mouse.x > dialogOptLoc[i][0] && mouse.x < dialogOptLoc[i][2] &&
-                                          mouse.y > dialogOptLoc[i][1] && mouse.y < dialogOptLoc[i][1] + 16 ){
-                                                 setFontColor(255, 255, 0);
-                                                 putStringCentered(offset.x, dialogOptLoc[i][1], dialogOptText[i]);
+                                       if(mouse.x > dialogOptLoc[i][0] &&
+                                          mouse.x < dialogOptLoc[i][2] &&
+                                          mouse.y > dialogOptLoc[i][1] &&
+                                          mouse.y < dialogOptLoc[i][1] + 16 ){ // fontSize
+                                                 setFontColor(255,255,0);
+                                                 putStringCentered(offset.x,dialogOptLoc[i][1],dialogOptText[i]);
                                        }
                                }
-                               
-                               setFontColor(255, 255, 255);
+                               setFontColor(255,255,255);
                        }
                        
-                       // make click for each character update
-                       if(strcmp(rtext, dialogBoxText))
-                               Mix_PlayChannel(1, dialogClick, 0);
-                       
-               }
-               
-               // draw information stuffs
-               if(!fadeIntensity){
+                       if(strcmp(rtext,dialogBoxText)){
+                               Mix_PlayChannel(1,dialogClick,0);
+                       }
                        
+               }if(!fadeIntensity){
                        vec2 hub = {
-                               (offset.x + SCREEN_WIDTH  / 2) - fontSize * 10,
-                               (offset.y + SCREEN_HEIGHT / 2) - fontSize
+                               (SCREEN_WIDTH/2+offset.x)-fontSize*10,
+                               (offset.y+SCREEN_HEIGHT/2)-fontSize
                        };
                        
-                       // health text
-                       putText(hub.x,
-                                       hub.y,
-                                       "Health: %.0f/%.0f",
-                                       player->health > 0 ? player->health : 0,
-                                       player->maxHealth
-                                       );
-
-                       // health bar
+                       putText(hub.x,hub.y,"Health: %u/%u",player->health>0?(unsigned)player->health:0,
+                                                                                               (unsigned)player->maxHealth
+                                                                                               );
                        if(player->alive){
-                               hub.y -= fontSize * 1.15;
-                               
-                               glColor3ub(150, 0, 0);
+                               glColor3ub(150,0,0);
+                               hub.y-=fontSize*1.15;
                                glRectf(hub.x,
                                                hub.y,
-                                               hub.x + 150,
-                                               hub.y + 12
-                                               );
-                                               
+                                               hub.x+150,
+                                               hub.y+12);
                                glColor3ub(255,0,0);
                                glRectf(hub.x,
                                                hub.y,
-                                               hub.x + (player->health / player->maxHealth * 150),
-                                               hub.y + 12
-                                               );
+                                               hub.x+(player->health/player->maxHealth * 150),
+                                               hub.y+12);
                        }
                        
-                       // inventory
+                       /*
+                        *      Lists all of the quests the player is currently taking.
+                       */
+                       
                        if(player->inv->invOpen){
                                hub.y = player->loc.y + fontSize * 8;
-                               hub.x = player->loc.x;
+                               hub.x = player->loc.x;// + player->width / 2;
                                
-                               putStringCentered(hub.x, hub.y, "Current Quests:");
+                               putStringCentered(hub.x,hub.y,"Current Quests:");
                                
-                               for(auto &q : player->qh.current)
-                                       putStringCentered(hub.x, (hub.y -= fontSize * 1.15), q.title.c_str());
+                               for(auto &c : player->qh.current){
+                                       hub.y -= fontSize * 1.15;
+                                       putStringCentered(hub.x,hub.y,c.title.c_str());
+                               }       
                        }
                }
        }
 
-       /**
-        * Safely exits the game.
-        */
-
        void quitGame(){
-               // clean menu stuff
+               dialogBoxExists = false;
                currentMenu = NULL;
                delete[] currentMenu;
-               
-               // save options
+               gameRunning = false;
                updateConfig();
                saveConfig();
-               
-               // tell main loop to exit
-               gameRunning = false;
        }
        
        menuItem createButton(vec2 l, dim2 d, Color c, const char* t, menuFunc f){
@@ -1136,38 +1005,33 @@ namespace ui {
                fclose(bmp);
        }
 
-       /**
-        * Handles dialog box closing, option selecting and stuff.
-        */
-
        void dialogAdvance(void){
                unsigned char i;
-               
-               // if typeOut hasn't finished, tell it to then try again
                if(!typeOutDone){
                        typeOutDone = true;
                        return;
                }
 
-               // check for selected option
-               for(i = 0; i < dialogOptCount; i++){
-                       if(mouse.x > dialogOptLoc[i][0] && mouse.x < dialogOptLoc[i][2] &&
-                          mouse.y > dialogOptLoc[i][1] && mouse.y < dialogOptLoc[i][1] + 16 ){
+               for(i=0;i<dialogOptCount;i++){
+                       if(mouse.x > dialogOptLoc[i][0] &&
+                          mouse.x < dialogOptLoc[i][2] &&
+                          mouse.y > dialogOptLoc[i][1] &&
+                          mouse.y < dialogOptLoc[i][1] + 16 ){ // fontSize
                                dialogOptChosen = i + 1;
-                               break;
+                               goto DONE;
                        }
                }
-               
-               // handle important text
+DONE:
                if(dialogImportant){
                        dialogImportant = false;
                        setFontSize(16);
+                       //toggleBlack();
                }
+               /*if(ui::fontSize != 16)
+                       setFontSize(16);*/
 
-               // kill the dialog box
                dialogBoxExists = false;
        }
-       
        void handleEvents(void){
                static bool left=true,right=false;
                static int heyOhLetsGo = 0;
@@ -1308,6 +1172,7 @@ namespace ui {
                                                if(debug)posFlag ^= true;
                                                break;
                                        case SDLK_e:
+                                               edown=true;
                                                if(!heyOhLetsGo){
                                                        heyOhLetsGo = loops;
                                                        player->inv->mouseSel = false;
@@ -1355,6 +1220,7 @@ namespace ui {
                                        player->speed = 1;
                                        break;
                                case SDLK_e:
+                                       edown=false;
                                        if(player->inv->invHover){
                                                player->inv->invHover = false;
                                        }else{
@@ -1427,46 +1293,25 @@ namespace ui {
                }
        }
        
-       /**
-        * Toggle a slow fade to/from black.
-        */
-       
        void toggleBlack(void){
                fadeEnable ^= true;
                fadeWhite = false;
                fadeFast = false;
        }
-       
-       /**
-        * Toggle a fast fade to/from black.
-        */
-       
        void toggleBlackFast(void){
                fadeEnable ^= true;
                fadeWhite = false;
                fadeFast = true;
        }
-       
-       /**
-        * Toggle a slow fade to/from white.
-        */
-       
        void toggleWhite(void){
                fadeEnable ^= true;
                fadeWhite = true;
                fadeFast = false;
        }
-       
-       /**
-        * Toggle a fast fade to/from white. This should only be used for battle
-        * initiations, so the 'battle start' sound is played as well.
-        */
-       
        void toggleWhiteFast(void){
                fadeEnable ^= true;
                fadeWhite = true;
                fadeFast = true;
-               
-               Mix_PlayChannel(1, battleStart, 0);
+               Mix_PlayChannel(1,battleStart,0);
        }
 }
index eb9f12ec699fe2daeea2d76d5d6ccc1eae2382d5..57b5ff587ee709899812113d491510d89d515fd4 100644 (file)
 #include <world.h>
 #include <ui.h>
 
-#define getWidth(w) ((w->lineCount-GEN_INC)*HLINE)     // Calculates the width of world 'w'
+/**
+ * Defines how many HLINEs tall a blade of grass can be.
+ */
 
-#define GEN_INIT 60
+#define GRASS_HEIGHT            4
 
-#define GRASS_HEIGHT 4                         // Defines how long the grass layer of a line should be in multiples of HLINE.
+/**
+ * Defines the height of the floor in an IndoorWorld.
+ */
 
+#define INDOOR_FLOOR_HEIGHT     100
 
-#define DRAW_Y_OFFSET 50               // Defines how many pixels each layer should be offset from each other on the y axis when drawn.
-#define DRAW_SHADE       30            // Defines a shade increment for draw()
-
-#define INDOOR_FLOOR_HEIGHT 100 // Defines how high the base floor of an IndoorWorld should be
-
-bool worldInside = false;              // True if player is inside a structure
+/**
+ * Contains the current weather, used in many other places/files.
+ */
 
 WEATHER weather = SUNNY;
 
-
 const std::string bgPaths[2][9]={
-                                                                  {"bg.png",                                   // Daytime background
-                                                                       "bgn.png",                                      // Nighttime background
-                                                                       "bgFarMountain.png",            // Furthest layer
-                                                                       "forestTileFar.png",            // Furthest away Tree Layer
-                                                                       "forestTileBack.png",           // Closer layer
-                                                                       "forestTileMid.png",            // Near layer
-                                                                       "forestTileFront.png",          // Closest layer
-                                                                       "dirt.png",                                     // Dirt
-                                                                       "grass.png"},                           // Grass
-                                                                  {"bgWoodTile.png",
-                                                                       "bgWoodTile.png",
-                                                                       "bgWoodTile.png",
-                                                                       "bgWoodTile.png",
-                                                                       "bgWoodTile.png",
-                                                                       "bgWoodTile.png",
-                                                                       "bgWoodTile.png",
-                                                                       "bgWoodTile.png"}
+    {"bg.png",                                 // Daytime background
+     "bgn.png",                                        // Nighttime background
+     "bgFarMountain.png",              // Furthest layer
+     "forestTileFar.png",              // Furthest away Tree Layer
+     "forestTileBack.png",             // Closer layer
+     "forestTileMid.png",              // Near layer
+     "forestTileFront.png",            // Closest layer
+     "dirt.png",                               // Dirt
+     "grass.png"},                             // Grass
+    {"bgWoodTile.png",
+     "bgWoodTile.png",
+     "bgWoodTile.png",
+     "bgWoodTile.png",
+     "bgWoodTile.png",
+     "bgWoodTile.png",
+     "bgWoodTile.png",
+     "bgWoodTile.png"}
 };
 
-const std::string buildPaths[] = {     "townhall.png",
-                                                                       "house1.png", 
-                                                                       "house2.png", 
-                                                                       "house1.png", 
-                                                                       "house1.png", 
-                                                                       "fountain1.png",
-                                                                       "lampPost1.png",
-                                                                       "brazzier.png"};
+const std::string buildPaths[] = {
+    "townhall.png",
+       "house1.png", 
+    "house2.png", 
+    "house1.png", 
+    "house1.png", 
+    "fountain1.png",
+    "lampPost1.png",
+       "brazzier.png"
+};
+
+/**
+ * Constants used for layer drawing in World::draw(), releated to transparency.
+ */
 
 const float bgDraw[4][3]={
-       {100,240,.6 },
-       {150,250,.4 },
-       {200,255,.25},
-       {255,255,.1}
+       { 100, 240, 0.6  },
+       { 150, 250, 0.4  },
+       { 200, 255, 0.25 },
+       { 255, 255, 0.1  }
 };
 
-float worldGetYBase(World *w){
-//     World *tmp = w;
-       float base = GEN_MIN;
-/*     while(tmp->infront){
-               tmp = tmp->infront;
-               base -= DRAW_Y_OFFSET;
-       }*/
-       if(!w)return 0;
-       return base;
-}
-
-void World::setBackground(WORLD_BG_TYPE bgt){
-       bgType = bgt;
-       switch(bgt){
+/**
+ * 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( WORLD_BG_TYPE bgt )
+{
+    // load textures with a limit check
+       switch ( (bgType = bgt) ) {
        case BG_FOREST:
-               bgTex = new Texturec(bgFiles);
+               bgTex = new Texturec( bgFiles );
                break;
+        
        case BG_WOODHOUSE:
-               bgTex = new Texturec(bgFilesIndoors);
+               bgTex = new Texturec( bgFilesIndoors );
                break;
+
+    default:
+        UserError( "Invalid world background type" );
+        break;
        }
 }
 
-void World::setStyle(const char* pre){
+/**
+ * Sets the world's style.
+ * 
+ * The world's style will determine what sprites are used for things like\
+ * generic structures.
+ */
+
+void World::
+setStyle( const char *pre )
+{
+    unsigned int i;
+    
+    // get folder prefix
        std::string prefix = pre ? pre : "assets/style/classic/";
-       for(uint i = 0; i < arrAmt(buildPaths);i++){
-               sTexLoc.push_back(prefix);
-               sTexLoc.back() += buildPaths[i];
-               //std::cout << sTexLoc.back() << std::endl;
-       }
+    
+       for ( i = 0; i < arrAmt(buildPaths); i++ )
+               sTexLoc.push_back( prefix + buildPaths[i] );
+               
        prefix += "bg/";
-       for(uint i = 0; i < arrAmt(bgPaths[0]);i++){
-               bgFiles.push_back(prefix);
-               bgFiles.back() += bgPaths[0][i];
-               //std::cout << bgFiles.back() << std::endl;
-       }
-       for(uint i = 0; i < arrAmt(bgPaths[1]);i++){
-               bgFilesIndoors.push_back(prefix);
-               bgFilesIndoors.back() += bgPaths[1][i];
-               //std::cout << bgFilesIndoors.back() << std::endl;
-       }
+    
+       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] );
 }
 
-World::World(void){
-       
+/**
+ * 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.
+ */
+
+World::
+World( void )
+{
+    // nullify strings
        bgm = NULL;
        bgmObj = NULL;
-               
-       toLeft =
-       toRight = NULL; 
-       
-       /*
-        *      Allocate and clear an array for star coordinates.
-       */
-       
-       star = new vec2[100];
-       memset(star,0,100 * sizeof(vec2));
+    
+       toLeft = NULL;
+       toRight = NULL;
 }
 
-void World::deleteEntities(void){
-       while(!mob.empty()){
+/**
+ * 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() ) {
                delete mob.back();
                mob.pop_back();
        }
-       while(!npc.empty()){
+    
+    // free npcs
+       while ( !npc.empty() ) {
                delete npc.back();
                npc.pop_back();
        }
-       while(!build.empty()){
+    
+    // free structures
+       while ( !build.empty() ) {
                delete build.back();
                build.pop_back();
        }
-       while(!object.empty()){
+    
+    // free objects
+       while ( !object.empty() ) {
                delete object.back();
                object.pop_back();
        }
-       while(!entity.empty()){
+    
+    // clear entity array
+       while ( !entity.empty() ) {
                entity.pop_back();
        }
-       while(!particles.empty()){
+    
+    // free particles
+       while ( !particles.empty() ) {
                delete particles.back();
                particles.pop_back();
        }
-       while(!light.empty()){
+    
+    // clear light array
+       while ( !light.empty() )
                light.pop_back();
-       }
-       while(!village.empty()){
+
+    // free villages
+       while ( !village.empty() ) {
                delete village.back();
                village.pop_back();
        }
        
 }
 
-World::~World(void){
-       /*if(behind != NULL)
-               delete behind;*/
-       
+/**
+ * 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);
+    
+    // bgm path
        if(bgm)
                delete[] bgm;
+
        delete bgTex;
-       delete[] star;
-       delete[] line;
        
        delete[] toLeft;
        delete[] toRight;
@@ -165,633 +216,463 @@ World::~World(void){
        deleteEntities();
 }
 
-void World::generate(unsigned int width){      // Generates the world and sets all variables contained in the World class.
-       unsigned int i;
-       float inc;
-       
-       /*
-        *      Calculate the world's real width. The current form of generation fails to generate
-        *      the last GEN_INC lines, so we offset those making the real real width what was passed
-        *      to this function.
-        * 
-        *      Abort if the width is invalid.
-        * 
-       */
-       
-       if(width <= 0)
-               abort();
-               
-       lineCount = (width + GEN_INC) / HLINE;
-       
-       /*
-        *      Allocate enough memory for the world to be stored.
-       */
-       
-       line = new struct line_t[lineCount];
-       memset(line,0,lineCount * sizeof(struct line_t));
-       
-       /*
-        *      Set an initial y to base generation off of, as generation references previous lines.
-       */
-       
-       line[0].y = GEN_INIT;
-       
-       /*
-        *      Populate every GEN_INCth line structure. The remaining lines will be based off of these.
-       */
-       
-       for(i = GEN_INC;i < lineCount;i += GEN_INC){
-               
-               /*
-                *      Generate a y value, ensuring it stays within a reasonable range.
-               */
-               
-               line[i].y = rand() % 8 - 4 + line[i - GEN_INC].y;       // Add +/- 4 to the previous line
-               
-                        if(line[i].y < GEN_MIN)line[i].y = GEN_MIN;    // Minimum bound
-               else if(line[i].y > GEN_MAX)line[i].y = GEN_MAX;        // Maximum bound
-               
-       }
-       
-       /*
-        *      Generate values for the remaining lines here.
-       */
-       
-       for(i = 0;i < lineCount - GEN_INC;i++){
-               
-               /*
-                *      Every GEN_INCth line calculate the slope between the current line and the one
-                *      GEN_INC lines before it. This value is then divided into an increment that is
-                *      added to lines between these two points resulting in a smooth slope.
-                * 
-               */
-               
-               if(!(i % GEN_INC))
-                       
-                       inc = (line[i + GEN_INC].y - line[i].y) / (float)GEN_INC;
-                       
-               /*
-                *      Add the increment to create the smooth slope.
-               */
-                       
-               else line[i].y = line[i - 1].y + inc;
-               
-               /*
-                *      Generate a color value for the line. This will be referenced in World->draw(),
-                *      by setting an RGB value of color (red), color - 50 (green), color - 100 (blue).
-               */
-               
-               line[i].color = rand() % 32 / 8; // 100 to 120
-
-               /*
-                *      Each line has two 'blades' of grass, here we generate random heights for them.
-               */
-               
-               line[i].gh[0] = (getRand() % 16) / 3.5 + 2;     // Not sure what the range resolves to here...
-               line[i].gh[1] = (getRand() % 16) / 3.5 + 2;     //
-               
-               line[i].gs = true;                                                      // Show the blades of grass (modified by the player)
-               
-       }
-       
-       /*
-        *      Calculate the x coordinate to start drawing this world from so that it is centered at (0,0).
-       */
-       
-       x_start = 0 - getWidth(this) / 2;
-       
-       /*
-        *      Assign coordinates for the stars, seen at nighttime.
-       */
-       
-       for(i = 0;i < 100;i++){
-               star[i].x = getRand() % getTheWidth() - getTheWidth() / 2;
-               star[i].y = getRand() % SCREEN_HEIGHT + 100;
-       }
+/**
+ * Generates a world of the specified width.
+ * 
+ * This will mainly populate the WorldData array, mostly preparing the World
+ * object for usage.
+ */
+
+void World::
+generate( unsigned int width )
+{      
+    // iterator for `for` loops
+       std::vector<WorldData>::iterator wditer;
+    
+    // see below for description
+    float geninc = 0;
+    
+    // check for valid width
+    if ( (int)width <= 0 )
+        UserError("Invalid world dimensions");
+
+    // allocate space for world
+    worldData = std::vector<WorldData> (width + GROUND_HILLINESS, (WorldData) { false, {0,0}, 0, 0 });
+    lineCount = worldData.size();
+    
+    // prepare for generation
+    worldData.front().groundHeight = GROUND_HEIGHT_INITIAL;
+    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)
+        worldData[i].groundHeight = (*wditer).groundHeight + (randGet() % 12 - 6);
+
+    // create slopes from the points that were just defined, populate the rest of the WorldData structure
+    
+    for(wditer = worldData.begin(); wditer != worldData.end(); wditer++){
+        if ((*wditer).groundHeight)
+            geninc = ( (*(wditer + GROUND_HILLINESS)).groundHeight - (*wditer).groundHeight ) / (float)GROUND_HILLINESS;
+        else
+            (*wditer).groundHeight = (*(wditer - 1)).groundHeight + geninc;
+
+        (*wditer).groundColor    = randGet() % 32 / 8;
+        (*wditer).grassUnpressed = true;
+        (*wditer).grassHeight[0] = (randGet() % 16) / 3 + 2;
+        (*wditer).grassHeight[1] = (randGet() % 16) / 3 + 2;
+        
+        // dirty fix for bug -- please fix the bug
+        if( (*wditer).groundHeight <= 0 )
+            (*wditer).groundHeight = (*(wditer - 1)).groundHeight;
+    }
+    
+    // define x-coordinate of world's leftmost 'line'
+    worldStart = (width - GROUND_HILLINESS) * HLINE / 2 * -1;
+       
+    // create empty star array, should be filled here as well...
+       star = std::vector<vec2> (100, (vec2) { 0, 0 } );
 }
 
-void World::generateFunc(unsigned int width,float(*func)(float)){
-       unsigned int i;
-       
-       /*
-        *      Check for a valid width.
-       */
-       
-       if((lineCount = width) <= 0)
-               abort();
-       
-       /*
-        *      Allocate memory for the line array.
-       */
-       
-       line = new struct line_t[lineCount];
-       memset(line,0,lineCount*sizeof(struct line_t));
-       
-       /*
-        *      Populate entries in the line array, using `func` to get y values.
-       */
-       
-       for(i = 0;i < lineCount;i++){
-               line[i].y = func(i);
-               
-               if(line[i].y <    0)line[i].y = 0;              // Minimum bound
-               if(line[i].y > 2000)line[i].y = 2000;   // Maximum bound
-               
-               line[i].color = rand() % 20 + 100;
-               
-               line[i].gh[0] = (getRand() % 16) / 3.5 + 2;
-               line[i].gh[1] = (getRand() % 16) / 3.5 + 2;
-               
-               line[i].gs = true;
-       }
-       
-       x_start = 0 - getWidth(this) / 2;
-       
-       for(i = 0;i < 100;i++){
-               star[i].x = getRand() % getTheWidth() - getTheWidth() / 2;
-               star[i].y = getRand() % SCREEN_HEIGHT + 100;
-       }
-}
+/**
+ * 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 the player's coordinates.
-       */
-       
+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;
        
-       /*
-        *      Update coordinates of all entities except for structures.
-       */
-
-       for(auto &e : entity){
+       // update entity coords
+       for ( auto &e : entity ) {
                e->loc.y += e->vel.y * delta;
                
-               if(e->type != STRUCTURET && e->canMove){
+        // dont let structures move?
+               if ( e->type != STRUCTURET && e->canMove ) {
                        e->loc.x += e->vel.x * delta;
                        
-                       if(e->vel.x < 0)e->left = true;
-                       else if(e->vel.x > 0)e->left = false;
+            // update boolean directions
+                       if ( e->vel.x < 0 )
+                e->left = true;
+                       else if ( e->vel.x > 0 )
+                e->left = false;
                }
        }
 
-       for(unsigned int i=0;i<particles.size();i++){
-               if(particles[i]->kill(deltaTime)){
-                       delete particles[i];
-                       particles.erase(particles.begin()+i);
-               }else if(particles[i]->canMove){
-                       particles[i]->loc.y += particles[i]->vely * deltaTime;
-                       particles[i]->loc.x += particles[i]->velx * deltaTime;
-
-                       for(auto &b : build){
-                               if(b->bsubtype==FOUNTAIN){
-                                       if(particles[i]->loc.x >= b->loc.x && particles[i]->loc.x <= b->loc.x + b->width){
-                                               if(particles[i]->loc.y <= b->loc.y + b->height * .25){
-                                                       delete particles[i];
-                                                       particles.erase(particles.begin()+i);
-                                               }
-                                       }
-                               }
-                       }
-               }
-       }
-       
-       if(ui::dialogImportant){
+    // iterate through particles
+    for ( std::vector<Particles *>::iterator pi = particles.begin(); pi != particles.end(); pi++ ) {
+        if ( (*pi)->kill(delta) ) {
+            //delete[] (*pi);
+            particles.erase(pi);
+        } else if ( (*pi)->canMove ) {
+            (*pi)->loc.x += (*pi)->velx * delta;
+            (*pi)->loc.y += (*pi)->vely * delta;
+            
+            for ( auto &b : build ) {
+                if ( b->subtype == FOUNTAIN ) {
+                    if ( (*pi)->loc.x >= b->loc.x && (*pi)->loc.x <= b->loc.x + b->width ) {
+                        if ( (*pi)->loc.y <= b->loc.y + b->height * 0.25f ) {
+                            //delete[] (*pi);
+                            particles.erase(pi);
+                        }
+                    }
+                }
+            }
+        }
+    }
+       
+    // handle music fades
+       if ( ui::dialogImportant )
                Mix_FadeOutMusic(2000);
-       }else if(!Mix_PlayingMusic()){
+       else if( !Mix_PlayingMusic() )
                Mix_FadeInMusic(bgmObj,-1,2000);
-       }
 }
 
-void World::setBGM(std::string path){
-       bgm = new char[path.size() + 1];
-       strcpy(bgm,path.c_str());
-       bgmObj = Mix_LoadMUS(bgm);
+/**
+ * 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 )
+{
+       bgmObj = Mix_LoadMUS( strcpy( (bgm = new char[ path.size() + 1 ]), path.c_str()) );
 }
 
-void World::bgmPlay(World *prev){
-       if(prev){
-               if(bgm != prev->bgm){
-                       Mix_FadeOutMusic(800);
-                       //Mix_VolumeMusic(50);
-                       Mix_PlayMusic(bgmObj,-1);       // Loop infinitely
+/**
+ * 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 )
+{
+       if ( prev ) {
+               if ( bgm != prev->bgm ) {
+            // new world, new music
+                       Mix_FadeOutMusic( 800 );
+                       Mix_PlayMusic( bgmObj, -1 );
                }
-       }else{
-               Mix_FadeOutMusic(800);
-               //Mix_VolumeMusic(50);
-               Mix_PlayMusic(bgmObj,-1);       // Loop infinitely
+       } else {
+        // first call
+               Mix_FadeOutMusic( 800 );
+               Mix_PlayMusic( bgmObj, -1 );
        }
 }
 
-int worldShade = 0;
+/**
+ * Variables used by World::draw().
+ * @{
+ */
 
 extern vec2 offset;
 extern unsigned int tickCount;
 
-void World::draw(Player *p){
-       static float yoff=DRAW_Y_OFFSET;        // Initialize stuff
-       static int shade,bgshade;
-       static World *current=this;
-       unsigned int i;
-       int is,ie,v_offset,cx_start,width;
-       struct line_t *cline;
-       float base;
-       
-       bgshade = worldShade << 1; // *2
-       base = worldGetYBase(this);
+int worldShade = 0;
+
+/**
+ * @}
+ */
+
+/**
+ * The world draw function.
+ * 
+ * This function will draw the background layers, entities, and player to the
+ * screen.
+ */
+
+void World::
+draw( Player *p )
+{
+    // iterators
+    int i, iStart, iEnd;
+    
+    // shade value for draws -- may be unnecessary
+       int shadeBackground = worldShade;
+    
+    // player's offset in worldData[]
+       int pOffset;
+    
+    // world width in pixels
+       int width = worldData.size() * HLINE;
        
        /*
-        *      Draw the background images in the appropriate order.
-       */
+     * Draw background images.
+     */
        
-//LLLOOP:
-       /*if(current->infront){
-               current=current->infront;
-               goto LLLOOP;
-       }*/
+       glEnable( GL_TEXTURE_2D );
        
-       if(current->x_start < SCREEN_WIDTH * -.5 )
-               cx_start = current->x_start * 1.5;
-       else
-               cx_start = (int)(SCREEN_WIDTH * -.5);
-               
-       width = (-cx_start) << 1;
+       // the sunny wallpaper is faded with the night depending on tickCount
        
-       glEnable(GL_TEXTURE_2D);
-
-       bgTex->bind(0);
-       safeSetColorA(255,255,255,255 - worldShade * 4);
-       glBegin(GL_QUADS);
-               glTexCoord2i(0,0);glVertex2i( cx_start,SCREEN_HEIGHT);
-               glTexCoord2i(1,0);glVertex2i(-cx_start,SCREEN_HEIGHT);
-               glTexCoord2i(1,1);glVertex2i(-cx_start,0);
-               glTexCoord2i(0,1);glVertex2i( cx_start,0);
+       bgTex->bind( 0 );
+       safeSetColorA( 255, 255, 255, 255 - worldShade * 4 );
+       
+       glBegin( GL_QUADS );
+               glTexCoord2i( 0, 0 ); glVertex2i(  worldStart, SCREEN_HEIGHT );
+               glTexCoord2i( 1, 0 ); glVertex2i( -worldStart, SCREEN_HEIGHT );
+               glTexCoord2i( 1, 1 ); glVertex2i( -worldStart, 0 );
+               glTexCoord2i( 0, 1 ); glVertex2i(  worldStart, 0 );
        glEnd();
 
        bgTex->bindNext();
-       safeSetColorA(255,255,255,worldShade * 4);      
-       glBegin(GL_QUADS);
-               glTexCoord2i(0,0);glVertex2i( cx_start,SCREEN_HEIGHT);
-               glTexCoord2i(1,0);glVertex2i(-cx_start,SCREEN_HEIGHT);
-               glTexCoord2i(1,1);glVertex2i(-cx_start,0);
-               glTexCoord2i(0,1);glVertex2i( cx_start,0);
+       safeSetColorA( 255, 255, 255, worldShade * 4 );
+       
+       glBegin( GL_QUADS );
+               glTexCoord2i( 0, 0 ); glVertex2i(  worldStart, SCREEN_HEIGHT );
+               glTexCoord2i( 1, 0 ); glVertex2i( -worldStart, SCREEN_HEIGHT );
+               glTexCoord2i( 1, 1 ); glVertex2i( -worldStart, 0 );
+               glTexCoord2i( 0, 1 ); glVertex2i(  worldStart, 0 );
        glEnd();
-       glDisable(GL_TEXTURE_2D);
-
-       /*
-        *      Draws stars if it is an appropriate time of day for them.
-       */
+       
+       glDisable( GL_TEXTURE_2D );
+       
+       // draw the stars if the time deems it appropriate
+       
+       if (((( weather == DARK  ) & ( tickCount % DAY_CYCLE )) < DAY_CYCLE / 2)   ||
+           ((( weather == SUNNY ) & ( tickCount % DAY_CYCLE )) > DAY_CYCLE * .75) ){
 
-       if((((weather==DARK )&(tickCount%DAY_CYCLE))<DAY_CYCLE/2)   ||
-          (((weather==SUNNY)&(tickCount%DAY_CYCLE))>DAY_CYCLE*.75) ){
-                  
-               if(tickCount % DAY_CYCLE){      // The above if statement doesn't check for exact midnight.
+               if (tickCount % DAY_CYCLE) {    // The above if statement doesn't check for exact midnight.
                                
-                       safeSetColorA(255,255,255,bgshade + getRand() % 30 - 15);
-                       for(i = 0; i < 100; i++){
-                               glRectf(star[i].x+offset.x*.9,
+                       safeSetColorA( 255, 255, 255, shadeBackground + 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
+                                               star[i].x + offset.x * .9 + HLINE,
+                                               star[i].y + HLINE
                                                );
                        }
-                       
                }
        }
-
        
-       glEnable(GL_TEXTURE_2D);
-
-       /*
-        *      Draw the mountains.
-       */
-       bgTex->bindNext();
-       safeSetColorA(150-bgshade,150-bgshade,150-bgshade,220);
+       // draw remaining background items
        
-       glBegin(GL_QUADS);
-               for(int i = 0; i <= width/1920; i++){
-                       glTexCoord2i(0,1);glVertex2i(width/-2+(1920*i    )+offset.x*.85,base);
-                       glTexCoord2i(1,1);glVertex2i(width/-2+(1920*(i+1))+offset.x*.85,base);
-                       glTexCoord2i(1,0);glVertex2i(width/-2+(1920*(i+1))+offset.x*.85,base+1080);
-                       glTexCoord2i(0,0);glVertex2i(width/-2+(1920*i    )+offset.x*.85,base+1080);
+       glEnable( GL_TEXTURE_2D );
+       
+       bgTex->bindNext();
+       safeSetColorA( 150 - shadeBackground, 150 - shadeBackground, 150 - shadeBackground, 220 );
+       
+       glBegin( GL_QUADS );
+               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 );
                }
        glEnd();
        
-       /*
-        *      Draw four layers of trees.
-       */
-
-       for(i = 0; i < 4; i++){
+       for ( i = 0; i < 4; i++ ) {
                bgTex->bindNext();
-               safeSetColorA(bgDraw[i][0]-bgshade,bgDraw[i][0]-bgshade,bgDraw[i][0]-bgshade,bgDraw[i][1]);
-       
-               glBegin(GL_QUADS);
-                       for(int j = cx_start; j <= -cx_start; j += 600){
-                               glTexCoord2i(0,1);glVertex2i( j     +offset.x*bgDraw[i][2],base);
-                               glTexCoord2i(1,1);glVertex2i((j+600)+offset.x*bgDraw[i][2],base);
-                               glTexCoord2i(1,0);glVertex2i((j+600)+offset.x*bgDraw[i][2],base+400);
-                               glTexCoord2i(0,0);glVertex2i( j     +offset.x*bgDraw[i][2],base+400);
+               safeSetColorA( bgDraw[i][0] - shadeBackground, bgDraw[i][0] - shadeBackground, bgDraw[i][0] - shadeBackground, 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 );
                        }
                glEnd();
        }
        
-       glDisable(GL_TEXTURE_2D);
+       glDisable( GL_TEXTURE_2D );
        
-       glColor3ub(0,0,0);
-       glRectf(cx_start,GEN_MIN,-cx_start,0);
+       // draw black under backgrounds
        
-       /*
-        *      World drawing is done recursively, meaning that this function jumps
-        *      back as many 'layers' as it can and then draws, eventually coming
-        *      back to the initial or 'root' layer. LOOP1 does the recursion back
-        *      to the furthest behind layer, modifying shade and y offsets as it
-        *      does.
-        * 
-       */
+       glColor3ub( 0, 0, 0 );
+       glRectf( worldStart, GROUND_HEIGHT_MINIMUM, -worldStart, 0 );
        
-       current=this;
-       shade=worldShade;
+       pOffset = (offset.x + p->width / 2 - worldStart) / HLINE;
        
-//LOOP1:
+    /*
+     * Prepare for world ground drawing.
+     */
+    
+       // only draw world within player vision
+    
+       if ((iStart = pOffset - (SCREEN_WIDTH / 2 / HLINE) - GROUND_HILLINESS) < 0)
+               iStart = 0;
 
-       //if(current->behind){
-               
-               /*
-                *      Add to the y offset and shade values (explained further below)
-                *      and recurse.
-                * 
-               */
-               
-               /*yoff+=DRAW_Y_OFFSET;
-               shade+=DRAW_SHADE;
-               current=current->behind;
-               goto LOOP1;
-       }*/
+       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
        
-       /*
-        *      Here is where the actual world drawing begins. A goto is made to
-        *      LOOP2 once the current layer is drawn and the function shifts to
-        *      draw the next closest layer.
-       */
+       for ( auto &part : particles ) {
+               if ( part->behind )
+                       part->draw();
+       }
        
-//LOOP2:
-
-       /*
-        *      Calculate the offset in the line array that the player is (or would)
-        *      currently be on. This function then calculates reasonable values for
-        *      the 'for' loop below that draws the layer.
-       */
+       for ( auto &b : build )
+               b->draw();
 
-       v_offset=(offset.x + p->width / 2 - current->x_start) / HLINE;
+       // draw light elements?
        
-       // is -> i start
+       glEnable( GL_TEXTURE_2D );
+    
+       glActiveTexture( GL_TEXTURE0 );
+       bgTex->bindNext();
        
-       is=v_offset - (SCREEN_WIDTH / 2 / HLINE) - GEN_INC;
-       if(is<0)is=0;                                                                                           // Minimum bound
+       GLfloat pointArray[ light.size() + (int)p->light ][2];
        
-       // ie -> i end
+       for ( i = 0; i < (int)light.size(); i++ ) {
+               pointArray[i][0] = light[i].loc.x - offset.x;
+               pointArray[i][1] = light[i].loc.y;
+       }
        
-       ie=v_offset + (SCREEN_WIDTH / 2 / HLINE) + GEN_INC + HLINE; 
-       if(ie>(int)current->lineCount)ie=current->lineCount;            // Maximum bound
-       else if(ie < GEN_INC)ie = GEN_INC;
+       glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT );
+       glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT );
        
-       /*
-        *      Make more direct variables for quicker referencing.
-       */
+       glUseProgram( shaderProgram );
+       glUniform1i( glGetUniformLocation( shaderProgram, "sampler"), 0);
+       glUniform1f( glGetUniformLocation( shaderProgram, "amb"    ), 0.5f );
        
-       cline   =current->line;
-       cx_start=current->x_start;
+       if ( p->light ) {
+               pointArray[light.size() + 1][0] = (float)( p->loc.x + SCREEN_WIDTH / 2 );
+               pointArray[light.size() + 1][1] = (float)( p->loc.y );
+       }
        
-       /*
-        *      Invert shading if desired.
-       */
+       if ( light.size() + (int)p->light == 0)
+               glUniform1i( glGetUniformLocation( shaderProgram, "numLight"), 0);
+       else {
+               glUniform1i ( glGetUniformLocation( shaderProgram, "numLight"     ), light.size() + (int)p->light );
+               glUniform2fv( glGetUniformLocation( shaderProgram, "lightLocation"), light.size() + (int)p->light, (GLfloat *)&pointArray ); 
+               glUniform3f ( glGetUniformLocation( shaderProgram, "lightColor"   ), 1.0f, 1.0f, 1.0f );
+       }
        
-       shade*=-1;
+    /*
+     * Draw the dirt?
+     */
+    
+       glBegin( GL_QUADS );
        
-       /*
-        *      Draw structures. We draw structures behind the dirt/grass so that the building's
-        *      corners don't stick out.
-       */
+        // 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);*/
 
-       for(auto &part : particles){
-               if(part->behind)
-               part->draw();
-       }
-       for(auto &b : current->build){
-               b->draw();
-       }       
-       /*
-        *      Draw the layer up until the grass portion, which is done later.
-       */
-
-       bool hey=false;
-       glEnable(GL_TEXTURE_2D);
-       glActiveTexture(GL_TEXTURE0);
-       bgTex->bindNext();
+        for ( i = iStart; i < iEnd; i++ ) {
+            if ( !worldData[i].groundHeight ) {
+                worldData[i].groundHeight = GROUND_HEIGHT_MINIMUM;
+                glColor4ub( 0, 0, 0, 255 );
+            } else
+                safeSetColorA( 150, 150, 150, 255 );
 
-       GLfloat pointArray[light.size() + (int)p->light][2];
-       for(uint w = 0; w < light.size(); w++){
-               pointArray[w][0] = light[w].loc.x - offset.x;
-               pointArray[w][1] = light[w].loc.y;
-       }
-       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
-       glUseProgram(shaderProgram);
-       glUniform1i(glGetUniformLocation(shaderProgram, "sampler"), 0);
-       glUniform1f(glGetUniformLocation(shaderProgram, "amb"), float(shade+50.0f)/100.0f);
-       if(p->light){
-               //glUniform1i(glGetUniformLocation(shaderProgram, "numLight"), 1);
-               //glUniform2f(glGetUniformLocation(shaderProgram, "lightLocation"), p->loc.x - offset.x+SCREEN_WIDTH/2, p->loc.y);
-               //glUniform3f(glGetUniformLocation(shaderProgram, "lightColor"), 1.0f,1.0f,1.0f);
-               pointArray[light.size()+1][0] = (float)(p->loc.x + SCREEN_WIDTH/2);
-               pointArray[light.size()+1][1] = (float)(p->loc.y);
-       }
-       if(light.size()+(int)p->light == 0){
-               glUniform1i(glGetUniformLocation(shaderProgram, "numLight"), 0);
-       }else{
-               glUniform1i (glGetUniformLocation(shaderProgram, "numLight"),      light.size()+(int)p->light);
-               glUniform2fv(glGetUniformLocation(shaderProgram, "lightLocation"), light.size()+(int)p->light, (GLfloat *)&pointArray); 
-               glUniform3f (glGetUniformLocation(shaderProgram, "lightColor"),    1.0f,1.0f,1.0f);
-       }
-
-       glBegin(GL_QUADS);
+            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 )
+                worldData[i].groundHeight = 0;
+        }
        
-       glTexCoord2i(0 ,0);glVertex2i(v_offset - (SCREEN_WIDTH / 1.5),0);
-       glTexCoord2i(64,0);glVertex2i(v_offset + (SCREEN_WIDTH / 1.5),0);
-       glTexCoord2i(64,1);glVertex2i(v_offset + (SCREEN_WIDTH / 1.5),base);
-       glTexCoord2i(0 ,1);glVertex2i(v_offset - (SCREEN_WIDTH / 1.5),base);
-       
-       for(i=is;i<(unsigned)ie-GEN_INC;i++){
-               cline[i].y+=(yoff-DRAW_Y_OFFSET);                                                                                                                       // Add the y offset
-               if(!cline[i].y){
-                       cline[i].y=base;
-                       hey=true;
-                       glColor4ub(0,0,0,255);
-               }else safeSetColorA(150+shade*2,150+shade*2,150+shade*2,255);
-               glTexCoord2i(0,0);                                                                      glVertex2i(cx_start+i*HLINE      ,cline[i].y-GRASS_HEIGHT);
-               glTexCoord2i(1,0);                                                                      glVertex2i(cx_start+i*HLINE+HLINE,cline[i].y-GRASS_HEIGHT);
-               glTexCoord2i(1,(int)(cline[i].y/64)+cline[i].color);glVertex2i(cx_start+i*HLINE+HLINE,0);
-               glTexCoord2i(0,(int)(cline[i].y/64)+cline[i].color);glVertex2i(cx_start+i*HLINE          ,0);
-               cline[i].y-=(yoff-DRAW_Y_OFFSET);                                                                                                                       // Restore the line's y value
-               if(hey){
-                       hey=false;
-                       cline[i].y=0;
-               }
-       }
        glEnd();
+    
        glUseProgram(0);
        glDisable(GL_TEXTURE_2D);
-       /*
-        *      Draw grass on every line.
-       */
        
-       float cgh[2];
+       /*
+        *      Draw the grass/the top of the ground.
+        */
 
-       glEnable(GL_TEXTURE_2D);
-       glActiveTexture(GL_TEXTURE0);
+       glEnable( GL_TEXTURE_2D );
+    
+       glActiveTexture( GL_TEXTURE0 );
        bgTex->bindNext();
-       glUseProgram(shaderProgram);
-       glUniform1i(glGetUniformLocation(shaderProgram, "sampler"), 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
-       //glBegin(GL_QUADS);
+       
+       glUseProgram( shaderProgram );
+       glUniform1i( glGetUniformLocation( shaderProgram, "sampler"), 0);
 
-       for(i=is;i<(unsigned)ie-GEN_INC;i++){
-               
-               /*
-                *      Load the current line's grass values
-               */
-               
-               if(cline[i].y)memcpy(cgh,cline[i].gh,2*sizeof(float));
-               else              memset(cgh,0                  ,2*sizeof(float));
-               
-               
-               
-               /*
-                *      Flatten the grass if the player is standing on it.
-               */
+       float cgh[2];
+       for ( i = iStart; i < iEnd - GROUND_HILLINESS; i++ ) {
                
-               if(!cline[i].gs){
-                       cgh[0]/=4;
-                       cgh[1]/=4;
+               // 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 ));
+                       
+               // flatten the grass if the player is standing on it.
+               if( !worldData[i].grassUnpressed ){
+                       cgh[0] /= 4;
+                       cgh[1] /= 4;
                }
                
-               /*
-                *      Actually draw the grass.
-               */
+               // actually draw the grass.
                
-               cline[i].y+=(yoff-DRAW_Y_OFFSET);
-               safeSetColorA(255,255,255,255);
-               glBegin(GL_QUADS);
-               glTexCoord2i(0,0);glVertex2i(cx_start+i*HLINE        ,cline[i].y+cgh[0]);
-               glTexCoord2i(1,0);glVertex2i(cx_start+i*HLINE+HLINE/2,cline[i].y+cgh[0]);
-               glTexCoord2i(1,1);glVertex2i(cx_start+i*HLINE+HLINE/2,cline[i].y-GRASS_HEIGHT);
-               glTexCoord2i(0,1);glVertex2i(cx_start+i*HLINE            ,cline[i].y-GRASS_HEIGHT);
-               glEnd();
-
-               glBegin(GL_QUADS);
-               glTexCoord2i(0,0);glVertex2i(cx_start+i*HLINE+HLINE/2,cline[i].y+cgh[1]);
-               glTexCoord2i(1,0);glVertex2i(cx_start+i*HLINE+HLINE  ,cline[i].y+cgh[1]);
-               glTexCoord2i(1,1);glVertex2i(cx_start+i*HLINE+HLINE  ,cline[i].y-GRASS_HEIGHT);
-               glTexCoord2i(0,1);glVertex2i(cx_start+i*HLINE+HLINE/2,cline[i].y-GRASS_HEIGHT);
+               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();
-
-               cline[i].y-=(yoff-DRAW_Y_OFFSET);
        }
-       //glEnd();
+
        glUseProgram(0);
        glDisable(GL_TEXTURE_2D);
 
        /*
-        *      Draw non-structure entities.
-       */
-       for(auto &part : particles){if(!part->behind)part->draw();}
-       for(auto &n : current->npc){
-               n->loc.y+=(yoff-DRAW_Y_OFFSET);
-               n->draw();
-               n->loc.y-=(yoff-DRAW_Y_OFFSET);
-       }
-       for(auto &m : current->mob){
-               m->loc.y+=(yoff-DRAW_Y_OFFSET);
-               m->draw();
-               m->loc.y-=(yoff-DRAW_Y_OFFSET);
-       }
-       for(auto &o : current->object){
-               if(o->alive){
-                       o->loc.y+=(yoff-DRAW_Y_OFFSET);
-                       o->draw();
-                       o->loc.y-=(yoff-DRAW_Y_OFFSET);
-               }
-       }
-       
-       /*
-        *      If we're drawing the closest/last world, handle and draw the player.
-       */
+     * Draw remaining entities.
+     */
        
-       if(current==this){
-               
-               /*
-                *      Calculate the line that the player is on
-               */
-               
-               unsigned int ph = (p->loc.x + p->width / 2 - x_start) / HLINE;
-               
-               /*
-                *      If the player is on the ground, flatten the grass where the player is standing
-                *      by setting line.gs to false.
-               */
-               
-               if(p->ground==1){
-                       for(i=0;i<lineCount-GEN_INC;i++){
-                               if(i < ph + 6 && 
-                                  i > ph - 6 )
-                                       cline[i].gs=false;
-                               else cline[i].gs=true;
-                       }
-               }else{
-                       for(i=0;i<lineCount-GEN_INC;i++){
-                               cline[i].gs=true;
-                       }
-               }
-               
-               /*
-                *      Draw the player.
-               */
-               
-               p->draw();
-               
+       for ( auto &part : particles ) {
+               if( !part->behind )
+                       part->draw();
        }
        
-       /*
-        *      Restore the inverted shading if it was inverted above.
-       */
-       
-       shade*=-1;
+       for ( auto &n : npc )
+               n->draw();
+
+       for ( auto &m : mob )
+               m->draw();
+
+       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 );
+       } else {
+               for ( i = 0; i < (int)(worldData.size() - GROUND_HILLINESS); i++ )
+                       worldData[i].grassUnpressed = true;
+       }
+
        /*
-        *      Draw the next closest world if it exists.
-       */
-       
-       /*if(current->infront){
-               yoff  -= DRAW_Y_OFFSET;
-               shade -= DRAW_SHADE;
-               
-               current=current->infront;
-               goto LOOP2;
-               
-       }else{*/
-               
-               /*
-                *      If finished, reset the yoff and shade variables for the next call.
-               */
-               
-               yoff=DRAW_Y_OFFSET;
-               shade=0;
-       //}
+     * Draw the player.
+     */
+     
+       p->draw();
 }
 
+/*
+ * TODO
+ */
+
 void World::singleDetect(Entity *e){
        unsigned int i,j;
        int l;
@@ -858,7 +739,7 @@ void World::singleDetect(Entity *e){
        /*
         *      Handle only living entities.
        */
-       
+    
        if(e->alive){
          
                if(e->type == MOBT && Mobp(e)->subtype == MS_TRIGGER)return;
@@ -867,7 +748,7 @@ void World::singleDetect(Entity *e){
                 *      Calculate the line that this entity is currently standing on.
                */
                
-               l=(e->loc.x + e->width / 2 - x_start) / HLINE;
+               l=(e->loc.x + e->width / 2 - worldStart) / HLINE;
                if(l < 0) l=0;
                i = l;
                if(i > lineCount-1) i=lineCount-1;
@@ -876,39 +757,11 @@ void World::singleDetect(Entity *e){
                 *      If the entity is under the world/line, pop it back to the surface.
                */
                
-               if(e->loc.y < line[i].y){
-                       
-                       /*
-                        *      Check that the entity isn't trying to run through a wall.
-                       */
-                       
-                       //if(e->loc.y + e->height > line[i-(int)e->width/2/HLINE].y &&
-                        //  e->loc.y + e->height > line[i+(int)e->width/2/HLINE].y ){
-                       
-                               e->loc.y=line[i].y - .001 * deltaTime;
-                               e->ground=true;
-                               e->vel.y=0;
-                               
-                       //}else{
-                               
-                               /*
-                                *      Push the entity out of the wall if it's trying to go through it.
-                               */
-                               
-                               /*do{
-                                       e->loc.x+=.001 * e->vel.x>0?-1:1;
-                                       
-                                       l=(e->loc.x - e->width / 2 - x_start) / HLINE;
-                                       if(l < 0){
-                                               std::cout<<"push kill lol "<<e->type<<std::endl;
-                                               e->alive = false; return; }
-                                       i = l;
-                                       if(i > lineCount-1){
-                                               std::cout<<"push kill lol "<<e->type<<std::endl;
-                                               e->alive = false; return; }
-                               }while(line[i].y>e->loc.y+ e->height);
-                               
-                       }*/
+               if ( e->loc.y < worldData[i].groundHeight ) {
+
+                       e->loc.y= worldData[i].groundHeight - .001 * deltaTime;
+                       e->ground=true;
+                       e->vel.y=0;
                
                /*
                 *      Handle gravity if the entity is above the line.
@@ -917,7 +770,7 @@ void World::singleDetect(Entity *e){
                }else{
                        
                        if(e->type == STRUCTURET && e->loc.y > 2000){
-                               e->loc.y = line[i].y;
+                               e->loc.y = worldData[i].groundHeight;
                                e->vel.y = 0;
                                e->ground = true;
                                return;
@@ -929,46 +782,41 @@ void World::singleDetect(Entity *e){
                 *      Insure that the entity doesn't fall off either edge of the world.
                */
 
-               if(e->loc.x < x_start){                                                                                         // Left bound
+               if(e->loc.x < worldStart){                                                                                              // Left bound
                        
                        e->vel.x=0;
-                       e->loc.x=(float)x_start + HLINE / 2;
+                       e->loc.x=(float)worldStart + HLINE / 2;
                        
-               }else if(e->loc.x + e->width + HLINE > x_start + getWidth(this)){       // Right bound
+               }else if(e->loc.x + e->width + HLINE > worldStart + worldStart * -2){   // Right bound
                        
                        e->vel.x=0;
-                       e->loc.x=x_start + getWidth(this) - e->width - HLINE;
+                       e->loc.x=worldStart + worldStart * -2 - e->width - HLINE;
                        
                }
        }
 }
 
-void World::detect(Player *p){
-       
-       /*
-        *      Handle the player. 
-       */
+void World::
+detect( Player *p )
+{
        
-       //auto pl = std::async(&World::singleDetect,this,p);
-       std::thread(&World::singleDetect,this, p).detach();
+       // handle the player
+       std::thread( &World::singleDetect, this, p).detach();
                
-       /*
-        *      Handle all remaining entities in this world. 
-       */
-       
-//LOOOOP:
-       for(auto &e : entity)
+    // handle other entities
+       for ( auto &e : entity )
                std::thread(&World::singleDetect,this,e).detach();
-               //hey->singleDetect(e);
-       for(auto &part : particles){
+        
+    // handle particles
+       for ( auto &part : particles ) {
                int l;
                unsigned int i;
-               l=(part->loc.x + part->width / 2 - x_start) / HLINE;
+               l=(part->loc.x + part->width / 2 - worldStart) / HLINE;
                if(l < 0) l=0;
                i = l;
                if(i > lineCount-1) i=lineCount-1;
-               if(part->loc.y < line[i].y){
-                       part->loc.y = line[i].y;
+               if(part->loc.y < worldData[i].groundHeight){
+                       part->loc.y = worldData[i].groundHeight;
                        part->vely = 0;
                        part->velx = 0;
                        part->canMove = false;
@@ -1095,27 +943,6 @@ void World::addLight(vec2 loc, Color color){
        }
 }
 
-/*void World::removeObject(Object i){
-       object.delete[](i);
-}*/
-
-/*
- *     The rest of these functions are explained well enough in world.h ;)
-*/
-
-/*void World::addLayer(unsigned int width){
-       if(behind){
-               behind->addLayer(width);
-               return;
-       }
-       behind=new World();
-       behind->generate(width);
-       behind->infront=this;
-       behind->star=star;
-       behind->bgmObj=bgmObj;
-       behind->bgTex=bgTex;
-}*/
-
 NPC *World::getAvailableNPC(void){
        for(auto &n : npc){
                if(n->aiFunc.empty())
@@ -1143,13 +970,20 @@ char *World::setToRight(const char *file){
        return toRight;
 }
 
-World *World::goWorldLeft(Player *p){
+World *World::
+goWorldLeft( Player *p )
+{
        World *tmp;
-       if(toLeft && p->loc.x < x_start + (int)HLINE * 15){
+    
+    // check if player is at world edge
+       if(toLeft && p->loc.x < worldStart + HLINE * 15.0f){
+        
+        // load world (`toLeft` conditional confirms existance)
                tmp = loadWorldFromXML(toLeft);
                
-               p->loc.x = -tmp->x_start - HLINE * 10;
-               p->loc.y =  tmp->line[tmp->lineCount - 1].y;
+        // adjust player location
+               p->loc.x = tmp->worldStart - HLINE * -10.0f;
+               p->loc.y = tmp->worldData[tmp->lineCount - 1].groundHeight;
                
                return tmp;
        }
@@ -1159,31 +993,17 @@ World *World::goWorldLeft(Player *p){
 World *World::goWorldRight(Player *p){
        World *tmp;
        
-       if(toRight && p->loc.x + p->width > -x_start - HLINE * 15){
+       if(toRight && p->loc.x + p->width > -worldStart - HLINE * 15){
                tmp = loadWorldFromXML(toRight);
                
-               p->loc.x = tmp->x_start + (int)HLINE * 10;
-               p->loc.y = tmp->line[0].y;
+               p->loc.x = tmp->worldStart + HLINE * 10;
+               p->loc.y = GROUND_HEIGHT_MINIMUM;
                
                return tmp;
        }
        return this;
 }
 
-/*World *World::goWorldBack(Player *p){
-       if(behind&&p->loc.x>(int)(0-getWidth(behind)/2)&&p->loc.x<getWidth(behind)/2){
-               return behind;
-       }
-       return this;
-}
-
-World *World::goWorldFront(Player *p){
-       if(infront&&p->loc.x>(int)(0-getWidth(infront)/2)&&p->loc.x<getWidth(infront)/2){
-               return infront;
-       }
-       return this;
-}*/
-
 std::vector<char *>inside;
 World *World::goInsideStructure(Player *p){
        World *tmp;
@@ -1228,18 +1048,12 @@ World *World::goInsideStructure(Player *p){
 void World::addHole(unsigned int start,unsigned int end){
        unsigned int i;
        for(i=start;i<end;i++){
-               line[i].y=0;
+               worldData[i].groundHeight = 0;
        }
 }
 
 int World::getTheWidth(void){
-       World *hey=this;
-/*LOOP:
-       if(hey->infront){
-               hey=hey->infront;
-               goto LOOP;
-       }*/
-       return -hey->x_start*2;
+       return worldStart * -2;
 }
 
 void World::save(void){
@@ -1336,26 +1150,17 @@ IndoorWorld::IndoorWorld(void){
 
 IndoorWorld::~IndoorWorld(void){
        delete bgTex;
-       delete[] star;
-       delete[] line;
        
        deleteEntities();
 }
 
 void IndoorWorld::generate(unsigned int width){                // Generates a flat area of width 'width'
-       unsigned int i;                                         // Used for 'for' loops 
-       lineCount=width+GEN_INC;                        // Sets line count to the desired width plus GEN_INC to remove incorrect line calculations.
+       lineCount=width+GROUND_HILLINESS;                       // Sets line count to the desired width plus GEN_INC to remove incorrect line calculations.
        if(lineCount<=0)abort();
        
-       line = new struct line_t[lineCount];    //(struct line_t *)calloc(lineCount,sizeof(struct line_t));     // Allocate memory for the array 'line'
-       memset(line,0,lineCount*sizeof(struct line_t));
+       worldData = std::vector<WorldData> (lineCount, (WorldData) { false, {0,0}, INDOOR_FLOOR_HEIGHT, 0 });
        
-       for(i=0;i<lineCount;i++){                       // Indoor areas don't have to be directly on the ground (i.e. 0)...
-               line[i].y=INDOOR_FLOOR_HEIGHT;
-       }
-       //behind=infront=NULL;                                          // Set pointers to other worlds to NULL
-       //toLeft=toRight=NULL;                                          // to avoid accidental calls to goWorld... functions
-       x_start=0-getWidth(this)/2+GEN_INC/2*HLINE;     // Calculate x_start (explained in world.h)
+       worldStart = (width - GROUND_HILLINESS) * HLINE / 2 * -1;
 }
 
 void IndoorWorld::draw(Player *p){
@@ -1394,13 +1199,11 @@ void IndoorWorld::draw(Player *p){
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); //for the t direction
        glColor4ub(255,255,255,255);
        
-       glBegin(GL_QUADS);      
-               //for(j = x_start - SCREEN_WIDTH / 2;j < -x_start + SCREEN_WIDTH / 2; j += 512){
-                       glTexCoord2i(0,1);                                                        glVertex2i( x_start - SCREEN_WIDTH / 2,0);
-                       glTexCoord2i((-x_start*2+SCREEN_WIDTH)/512,1);glVertex2i(-x_start + SCREEN_WIDTH / 2,0);
-                       glTexCoord2i((-x_start*2+SCREEN_WIDTH)/512,0);glVertex2i(-x_start + SCREEN_WIDTH / 2,SCREEN_HEIGHT);
-                       glTexCoord2i(0,0);                                                        glVertex2i( x_start - SCREEN_WIDTH / 2,SCREEN_HEIGHT);
-               //}
+       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);
@@ -1427,14 +1230,14 @@ void IndoorWorld::draw(Player *p){
        glUseProgram(shaderProgram);
        glUniform1i(glGetUniformLocation(shaderProgram, "sampler"), 0);
        glBegin(GL_QUADS);
-               for(;i < ie - GEN_INC;i++){
+               for(;i < ie - GROUND_HILLINESS;i++){
                        safeSetColor(150,100,50);
                        
-                       x = x_start + i * HLINE;
-                       glVertex2i(x            ,line[i].y);
-                       glVertex2i(x + HLINE,line[i].y);
-                       glVertex2i(x + HLINE,line[i].y - 50);
-                       glVertex2i(x            ,line[i].y - 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);
                }
        glEnd();
        glUseProgram(0);
@@ -1467,15 +1270,10 @@ Arena::Arena(World *leave,Player *p,Mob *m){
        
        battleNest.push_back(leave);
        battleNestLoc.push_back(p->loc);
-       
-       star = new vec2[100];
-       memset(star,0,100 * sizeof(vec2));
 }
 
 Arena::~Arena(void){
        delete bgTex;
-       delete[] star;
-       delete[] line;
 
        deleteEntities();
 }
@@ -1551,12 +1349,14 @@ World *loadWorldFromXMLNoSave(const char *path){
        
        while(wxml){
                name = wxml->Name();
+               
                if(!strcmp(name,"link")){
                        if((ptr = wxml->Attribute("left")))
                                tmp->setToLeft(ptr);
                        else if((ptr = wxml->Attribute("right")))
                                tmp->setToRight(ptr);
-                       else abort();
+                       else
+                               abort();
                }else if(!strcmp(name,"style")){
                        tmp->setStyle(wxml->Attribute("folder"));
                        tmp->setBackground((WORLD_BG_TYPE)wxml->UnsignedAttribute("background"));
@@ -1565,20 +1365,19 @@ World *loadWorldFromXMLNoSave(const char *path){
                        if(!strcmp(wxml->Attribute("type"),"Random")){
                                if(Indoor)
                                        ((IndoorWorld *)tmp)->generate(wxml->UnsignedAttribute("width"));
-                               else
+                               else {
+                                       
                                        tmp->generate(wxml->UnsignedAttribute("width"));
-                       }else if(Indoor){
+                               }
+                       }else if(Indoor)
                                abort();
-                       }
                }else if(!strcmp(name,"mob")){
                        unsigned int type;
-                       
                        type = wxml->UnsignedAttribute("type");
                        if(wxml->QueryFloatAttribute("x",&spawnx) != XML_NO_ERROR)
-                               tmp->addMob(type,getRand() % tmp->getTheWidth() / 2,100);
+                               tmp->addMob(type,0,100);
                        else
                                tmp->addMob(type,spawnx,wxml->FloatAttribute("y"));
-                               
                        if(wxml->QueryBoolAttribute("aggressive",&dialog) == XML_NO_ERROR)
                                tmp->mob.back()->aggressive = dialog;
                        
@@ -1586,7 +1385,7 @@ World *loadWorldFromXMLNoSave(const char *path){
                        const char *npcname;
 
                        if(wxml->QueryFloatAttribute("x",&spawnx) != XML_NO_ERROR)
-                               tmp->addNPC(getRand() % tmp->getTheWidth() / 2.0f,100);
+                               tmp->addNPC(0,100);
                        else
                                tmp->addNPC(spawnx,wxml->FloatAttribute("y"));
                        
@@ -1630,7 +1429,7 @@ World *loadWorldFromXMLNoSave(const char *path){
 
        while(vil){
                name = vil->Name();
-               randx = getRand() % tmp->getTheWidth() - (tmp->getTheWidth() / 2.0f);
+               randx = 0;
 
                /**
                 *      READS DATA ABOUT STRUCTURE CONTAINED IN VILLAGE