]> code.bitgloo.com Git - clyne/gamedev.git/commitdiff
Work on merchants and yer mum
authordrumsetmonkey <abelleisle@roadrunner.com>
Tue, 1 Mar 2016 13:00:55 +0000 (08:00 -0500)
committerdrumsetmonkey <abelleisle@roadrunner.com>
Tue, 1 Mar 2016 13:00:55 +0000 (08:00 -0500)
1  2 
assets/style/classic/stall.png
include/common.h
include/entities.h
include/threadpool.h
include/ui.h
include/world.h
main.cpp
src/entities.cpp
src/threadpool.cpp
src/ui.cpp
src/world.cpp

index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..1ac9844addb947366f55d685036e07a18d1a9256
new file mode 100644 (file)
Binary files differ
Simple merge
index 6c8e6586b1b96719683d0c77fc3f2d76c2f29d72,926eeae4b8bc4b26f8ddd1e703c915bf0aa1847c..545f0a4dfc8cb5e52dc2d33a9b677bacd51fe5f1
@@@ -47,11 -47,9 +47,29 @@@ enum BUILD_SUB
        HOUSE4 = 4,
        FOUNTAIN = 5,
        LAMP_POST = 6,
 -      FIRE_PIT = 7
 +      FIRE_PIT = 7,
 +      STALL_MARKET = 70,
 +      STALL_TRADER = 71
 +};
 +
++class BuySell{
++public:
++      int member;
++      union{
++              struct{
++                      std::string item1;
++                      std::string item2;
++              }trade;
++              struct{
++                      enum type{BUY,SELL};
++                      std::string item;
++                      int price;
++              }cost;
++      };
++      BuySell(){}
++      ~BuySell(){}
+ };
  class World;
  
  class Particles{
@@@ -197,26 -195,6 +215,15 @@@ public
        void wander(int);
  };
  
-       union BSINV{
-               struct EQUAL{
-                       std::string item1;
-                       std::string item2;
-               };
-               struct COST{
-                       std::string item;
-                       int price;
-               };
-       };
-       std::vector<BSINV>bsinv;
 +class Merchant : public NPC{
 +public:
++      std::vector<BuySell>bsinv;
 +      void interact();
 +
 +      Merchant();
 +      ~Merchant();
 +};
 +
  class Structures : public Entity{
  public:
        BUILD_SUB bsubtype;
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..c34167398c0436a7cb1cc514d25d80e260e40f0d
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,53 @@@
++#ifndef THREADPOOL_H
++#define THREADPOOL_H
++
++#include <vector>
++#include <queue>
++#include <thread>
++#include <mutex>
++#include <condition_variable>
++#include <iostream>
++#include <unistd.h>
++
++using namespace std;
++
++class ThreadPool
++{
++public:
++
++    // Constructor.
++    ThreadPool(int threads);
++
++    // Destructor.
++    ~ThreadPool();
++
++    // Adds task to a task queue.
++    void Enqueue(function<void()> f);
++
++    // Shut down the pool.
++    void ShutDown();
++
++private:
++    // Thread pool storage.
++    vector<thread> threadPool;
++
++    // Queue to keep track of incoming tasks.
++    queue<function<void()>> tasks;
++
++    // Task queue mutex.
++    mutex tasksMutex;
++
++    // Condition variable.
++    condition_variable condition;
++
++    // Indicates that pool needs to be shut down.
++    bool terminate;
++
++    // Indicates that pool has been terminated.
++    bool stopped;
++
++    // Function that will be invoked by our threads.
++    void Invoke();
++};
++
++#endif //THRE
diff --cc include/ui.h
index 04995705005612fd8f0e48056342bbf919856c7c,3e4fc8a32b25fac02ab2badc31ad8326159b297c..667a58159f43b65fbe9dc44d541fb1f631e826a7
@@@ -22,7 -22,7 +22,6 @@@ typedef void(*menuFunc)()
  struct menuItem{
        int member;
        union{
--
                struct{
                        vec2 loc;
                        dim2 dim;
@@@ -30,7 -30,7 +29,6 @@@
                        const char* text;
                        menuFunc func;
                }button;
--
                struct{
                        vec2 loc;
                        dim2 dim;
@@@ -148,7 -148,6 +146,8 @@@ namespace ui 
        */
        
        void dialogBox(const char *name,const char *opt,bool passive,const char *text,...);
-       void merchantBox(const char *name,const char *opt,bool passive,const char *text,...);
++      void merchantBox(const char *name, std::vector<BuySell> *items, const char *opt,bool passive,const char *text,...);
++      void merchantBox();
        void waitForDialog(void);
        
        /*
diff --cc include/world.h
index 7338097c83cc9b68e9e7a1109c89d87a0fcebbbd,56f1577200f4684ecd391ad82df19fc4b40f722f..228defa5b9f2d29e326c5b4cb3da78c32f4dccff
@@@ -81,28 -81,56 +81,58 @@@ typedef struct line_t 
        unsigned char color;    /**< Lightness of dirt (brown) */
  } line_t;
  
- /*
-  * Handle all logic that has to do with villages
+ class World;
+ /**
+  * The village class, used to group structures into villages.
   */
  
+ class Village {
+ public:
+       /**
+        * The name of the village.
+        */
  
- struct Village{
        std::string name;
+       
+       /**
+        * The coordinate of where the village starts.
+        * 
+        * This is used to check if the player has entered the village's area.
+        */
+       
        vec2 start;
+       
+       /**
+        * The coordinate of where the village ends.
+        * 
+        * This is used to check if the player has entered the village's area.
+        */
+       
        vec2 end;
+       
+       /**
+        * TODO
+        */
+       
        bool in;
  
+       /**
+        * A vector of all structures that are associated with this village.
+        */
        std::vector<Structures *> build;
-       Village(const char *meme){
-               name = meme;
-               end.x = -0xffffffff;
-               start.x = 0xffffffff;
-               in = false;
-       }
+       
+       /**
+        * Creates a village of name `meme` in the world `w`.
+        */
+       
+       Village(const char *meme, World *w);
  };
  
 +extern Player *player;
 +
  /**
   * The world class. This class does everything a world should do.
   */
diff --cc main.cpp
index cb28bcc9f7ce5198e052b581347160a8386e3d66,fa08beb68e647f45bb1223111cc8b2c94e6bf60b..fa833fb78d720fcece5c8a5c1b6de7a314ef9559
+++ b/main.cpp
@@@ -100,79 -83,61 +83,87 @@@ Player    *player
  
  extern bool worldInside;
  
- extern Menu* currentMenu;
+ /**
+  * TODO
+  */
  
- /*
-  *    tickCount contains the number of ticks generated since main loop entrance.
-  *    This variable might be used anywhere.
-  *
-  *    deltaTime is used for interpolation stuff.
-  *
-  *    Pretty sure these variables are considered static as they might be externally
-  *    referenced somewhere.
- */
+ extern Menu *currentMenu;
+ /**
+  * The current number of ticks, used for logic operations and day/night cycles.
+  */
  
  unsigned int tickCount = DAY_CYCLE;
+ /**
+  * TODO
+  */
  unsigned int deltaTime = 0;
  
- /*
-  *
- */
+ /**
+  * TODO
 */
  
  GLuint fragShader;
+ /**
+  * TODO
+  */
+  
  GLuint shaderProgram;
- GLuint colorIndex;
- GLuint mouseTex;
  
- bool uiLoop = false;
++/**
++ *    Threads and various variables to be used when multithreading the game,
++ *  mutex will prevent multiple threads from changing the same data,
++ *  and the condition_variable will wait for threads to reach the same point
++ */
++
 +std::mutex mtx;
 +std::condition_variable cv;
++ThreadPool pool(10);
++
 +
 +/*
 + *    loops is used for texture animation. It is believed to be passed to entity
 + *    draw functions, although it may be externally referenced instead.
 +*/
 +
- unsigned int loops = 0;       // Used for texture animation
+ /**
+  * TODO
+  */
  
ThreadPool pool(10);
GLuint colorIndex;
  
- extern void initEverything(void);
 +/*
 + *    initEverything
 + *
 + *    Before the main loop, things like the player, entities, and worlds should
 + *    be created. This game has not reached the point that these can be scripted
 + *    or programmed, so this function substitues for that. It is defined in
 + *    src/gameplay.cpp.
 + *
 +*/
 +
+ /**
+  * TODO
+  */
  
- /*
-  *    mainLoop is in fact the main loop, which runs 'infinitely' (as long as gameRunning
-  *
-  *
-  *
-  *    is set). Each loop updates timing values (tickCount and deltaTime), runs logic()
-  *    if MSEC_PER_TICK milliseconds have passed, and then runs render().
-  *
-  *    logic handles all user input and entity/world physics.
-  *
-  *    render handles all drawing to the window, calling draw functions for everything.
-  *
- */
+ GLuint mouseTex;
  
- void logic(void);
- void render(void);
- void mainLoop(void);
+ /**
+  * Used for texture animation. It is externally referenced by ui.cpp
+  * and entities.cpp.
+  */
  
- /*
-  *    This offset is used as the player offset in the world drawing so
-  *    everything can be moved according to the player
- */
+ unsigned int loops = 0;
+ /**
+  * Gives a coordinate based off of the player's location to allow for drawing to
+  * be in a constant 'absolute' place on the window.
+  */
  
- vec2 offset;                                                                                                                                                  /*      OFFSET!!!!!!!!!!!!!!!!!!!! */
+ vec2 offset;
  
  Menu *currentMenu;
  Menu optionsMenu;
index afcc9adf91215ebfc8df7a2643705ad6abfc673e,6c2da81d8a38688afe0904daf666632ab886e2ea..5e8d51ca6f652be551e43fdb5b3ce6710b2c4ad8
@@@ -136,36 -135,6 +136,36 @@@ NPC::~NPC()
        delete[] name;
  }
  
-       inv = NULL;
 +Merchant::Merchant(){ //sets all of the Merchant specific traits on object creation
 +      width = HLINE * 10;
 +      height = HLINE * 16;
 +      
 +      type    = MERCHT; //sets type to merchant
 +      subtype = 0;
 +
 +      health = maxHealth = 100;
 +      
 +      maxHealth = health = 100;
 +      canMove = true;
 +      
 +      //tex = new Texturec(1,"assets/NPC.png");
 +      //inv = new Inventory(NPC_INV_SIZE);
-       while(!aiFunc.empty()){
++      //inv = new Inventory(1);
++                                                                                                            
 +      //randDialog = rand() % RAND_DIALOG_COUNT - 1;
 +      dialogIndex = 0;
 +}
 +
 +Merchant::~Merchant(){
-       }
++      /*while(!aiFunc.empty()){
 +              aiFunc.pop_back();
-       delete inv;
-       delete tex;
-       delete[] name;
++      }*/
 +      
++      //delete inv;
++      //delete tex;
++      //delete[] name;
 +}
 +
  Structures::Structures(){ //sets the structure type
        health = maxHealth = 1;
        
@@@ -457,10 -425,6 +457,12 @@@ void NPC::interact(){ //have the npc's 
        canMove=true;
  }
  
-       ui::merchantBox(name, ":Accept:Good Bye", false, "Welcome to smithy\'s. Buy your sausages here you freaking mean lording screw-face");
 +void Merchant::interact(){
++      ui::merchantBox(name, &bsinv, ":Accept:Good-Bye", false, "Welcome to Smithy\'s. Buy your sausages here you freaking meme lording screw-face");
++      //ui::merchantBox();
++      ui::waitForDialog();
 +}
 +
  void Object::interact(void){
        if(questObject && alive){
                ui::dialogBox(player->name,":Yes:No",false,pickupDialog);               
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..d49217dbc4426e3ebf589449b470e4f50d0e4ef3
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,95 @@@
++#include "threadpool.h"
++
++// Constructor.
++ThreadPool::ThreadPool(int threads) :
++      terminate(false),
++      stopped(false)
++{
++      // Create number of required threads and add them to the thread pool vector.
++    for(int i = 0; i < threads; i++)
++    {
++      threadPool.emplace_back(thread(&ThreadPool::Invoke, this));
++    }
++}
++
++void ThreadPool::Enqueue(function<void()> f)
++{
++      // Scope based locking.
++      {
++              // Put unique lock on task mutex.
++              unique_lock<mutex> lock(tasksMutex);
++
++              // Push task into queue.
++              tasks.push(f);
++      }
++
++      // Wake up one thread.
++      condition.notify_one();
++}
++
++void ThreadPool::Invoke() {
++
++      function<void()> task;
++      while(true)
++      {
++              // Scope based locking.
++              {
++                      // Put unique lock on task mutex.
++                      unique_lock<mutex> lock(tasksMutex);
++
++                      // Wait until queue is not empty or termination signal is sent.
++                      condition.wait(lock, [this]{ return !tasks.empty() || terminate; });
++
++                      // If termination signal received and queue is empty then exit else continue clearing the queue.
++                      if (terminate && tasks.empty())
++                      {
++                              return;
++                      }
++
++                      // Get next task in the queue.
++                      task = tasks.front();
++
++                      // Remove it from the queue.
++                      tasks.pop();
++              }
++
++              // Execute the task.
++              task();
++      }
++}
++
++void ThreadPool::ShutDown()
++{
++      // Scope based locking.
++      {
++              // Put unique lock on task mutex.
++              unique_lock<mutex> lock(tasksMutex);
++
++              // Set termination flag to true.
++              terminate = true;
++      }
++
++      // Wake up all threads.
++      condition.notify_all();
++
++      // Join all threads.
++      for(thread &thread : threadPool)
++      {
++              thread.join();
++      }
++
++      // Empty workers vector.
++      threadPool.empty();
++
++      // Indicate that the pool has been shut down.
++      stopped = true;
++}
++
++// Destructor.
++ThreadPool::~ThreadPool()
++{
++      if (!stopped)
++      {
++              ShutDown();
++      }
++}
diff --cc src/ui.cpp
index 836a98eb0ac1758a0f8bd0e22e871bbf4c65415d,0d1fb49e7b97969bc76d68a3d1bbdebddd1025cb..00c0864c96751bfc999b09d142e101fbf5de433b
@@@ -46,17 -43,25 +43,25 @@@ static unsigned char fontColor[3] = {25
  
  /*
   *    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         merchAOptLoc[2][3];
+ static float           dialogOptLoc[4][3];
  static unsigned char dialogOptCount = 0;
- static bool typeOutDone = true;
+ static bool                    typeOutDone = true;
 -static int                     dialogPassiveTime = 0;
+ /*
+  * Menu-related objects
+  */
  
- extern MenucurrentMenu;
+ extern Menu *currentMenu;
  extern Menu pauseMenu;
  
+ /**
+  * The sound made when displaying characters with dialogBox or importantText.
+  */
  
  static Mix_Chunk *dialogClick;
  
@@@ -85,53 -106,71 +106,74 @@@ void Menu::gotoParent()
  }
  
  void Menu::gotoChild(){
-       if(child == NULL){
+       if(!child)
                currentMenu = NULL;
-       }else{
+       else
                currentMenu = child;
-       }
  }
  
+ static vec2 premouse={0,0};
  namespace ui {
        
-       /*
-        *      Mouse coordinates.
-       */
+       /**
+        * The current position of the mouse.
+        */
        
        vec2 mouse;
-       static vec2 premouse={0,0};             
  
-       /*
-        *      Variety of keydown bools
-       */
-       bool edown;
-       /*
-        *      Debugging flags.
-       */
+       /**
+        * 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.
+        */
        
-       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;
 +      bool dialogMerchant = false;
++      std::vector<BuySell> *minv;
 +      int dialogPassiveTime = 0;
  
-       
-       /*
-        *      Dialog stuff that needs to be 'public'.
-       */
+       /**
+        * 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.
+        */
+       
        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;
        
-       /*
-        *      Current font size. Changing this WILL NOT change the font size, see setFontSize() for
-        *      actual font size changing.
-       */
+       /**
+        * The current font size.
+        * 
+        * DO NOT change this directly, use setFontSize() instead.
+        */
        
        unsigned int fontSize;
  
  #ifdef DEBUG
                DEBUG_printf("Using font %s\n",ttf);
  #endif // DEBUG
        }
        
-       /*
-        *      Sets a new font size (default: 12).
-       */
+       /**
+        * Sets a new font size and renders the necessary characters (default font
+        * size: 16; 24 for importantText).
+        */
        
        void setFontSize(unsigned int size){
 +              mtx.lock();
                unsigned int i,j;
-               char *buf;
                
-               fontSize=size;
-               FT_Set_Pixel_Sizes(ftf,0,fontSize);
+               std::unique_ptr<uint8_t[]> rgbaBuf;
+               size_t rgbaBufSize = 0;
                
-               /*
-                *      Pre-render 'all' the characters.
-               */
+               FT_Set_Pixel_Sizes(ftf,0,(fontSize = size));
                
-               glDeleteTextures(93,ftex);      //      delete[] any already-rendered textures
-               glGenTextures(93,ftex);         //      Generate new texture name/locations?
+               // delete old characters, make space for new ones
+               for(i=0; i < FT_CHAR_COUNT; i++){
+                       glDeleteTextures(1, &ftmap[i].tex);
+                       glGenTextures(1, &ftmap[i].tex);
+               }
                
+               // Load all characters we expect to use
                for(i=33;i<126;i++){
                
-                       /*
-                        *      Load the character from the font family file.
-                       */
-                       //uiLoop ? std::cout << "Loop while render\n" : std::cout << "No loop while render\n";          
+                       // 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();
                        }
                        
                        /*
-                        *      Transfer the character's bitmap (?) to a texture for rendering.
-                       */
+                        * Set up the OpenGL texture thing.
+                        */
                
-                       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);
+                       glBindTexture(GL_TEXTURE_2D, ftmap[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);
                
                        /*
-                        *      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.
-                       */
-                       
-                       buf = new char[ftf->glyph->bitmap.width * ftf->glyph->bitmap.rows * 4];
+                        * 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;
                
-                       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];
+                       // 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;
                        }
                        
-                       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;
+                       // save important character information
+                       ftmap[i-33].wh = { (int)ftf->glyph->bitmap.width, (int)ftf->glyph->bitmap.rows };
+                       ftmap[i-33].bl = { ftf->glyph->bitmap_left,               ftf->glyph->bitmap_top       };
+                       ftmap[i-33].ad = { ftf->glyph->advance.x >> 6,    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);  
+                       // 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());
                        
-                       delete[] buf;   //free(buf);
+                       rgbaBuf.release();
                }
 +              mtx.unlock();
        }
        
-       /*
-        *      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;
        
        float putText(const float x,const float y,const char *str,...){
                va_list args;
-               char *buf;
-               float width;
-               
-               /*
-                *      Create a wimpy buffer.
-               */
-               
-               buf = new char[512];    //(char *)calloc(128,sizeof(char));
-               memset(buf,0,512*sizeof(char));
-               
-               /*
-                *      Handle the formatted string, printing it to the buffer.
-               */
+               std::unique_ptr<char[]> buf (new char[512]);
                
-               va_start(args,str);
-               vsnprintf(buf,512,str,args);
+               // create the formatted string
+               va_start(args, str);
+               vsnprintf(buf.get(), 512, str, args);
                va_end(args);
                
-               /*
-                *      Draw the string, free resources, return the width of the string.
-               */
-               
-               width=putString(x,y,buf);
-               delete[] buf;   //free(buf);
-               
-               return width;
+               return putString(x, y, buf.get());
        }
+       
+       /**
+        * 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,...){
++              textWrapLimit = 110;
                va_list dialogArgs;
-               unsigned int len;
-               char *sopt,*soptbuf;
+               size_t len;
                
                dialogPassive = passive;
                
                        dialogOptCount--;
                };
  
-               dialogOptCount = 0;
                dialogOptChosen = 0;
-               memset(&dialogOptLoc,0,sizeof(float)*12);
+               memset(&dialogOptLoc, 0, sizeof(float) * 12);
++              //char *sopt = (char*)malloc(255);
++              //dialogOptCount = 4;
                
-               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,":");
+               // handle options if desired
+               if(opt){
 -                      std::unique_ptr<char[]> soptbuf (new char[strlen(opt) + 1]);
 -                      char *sopt = strtok(soptbuf.get(), ":");
++                      //std::vector<char*> soptbuf (new char[strlen(opt) + 1]);
++                      //std::unique_ptr<char[]> soptbuf (new char[strlen(opt) + 1]);
++                      char soptbuf[255];
++                      strcpy(soptbuf, opt);
++                      char *sopt = strtok(soptbuf, ":");
+                       // cycle through options
+                       while(sopt){
++                              printf("%s",sopt);
+                               strcpy( (dialogOptText[dialogOptCount++] = new char[strlen(sopt) + 1]), sopt);
+                               sopt = strtok(NULL,":");
                        }
-                       
-                       delete[] soptbuf;
                }
                
-               /*
-                *      Tell draw() that the box is ready. 
-               */
-               
+               // allow box to be displayed
                dialogBoxExists = true;
                dialogImportant = false;
                
-               if(ret)
-                       ret[0] = '\0';
+               // kill the string created by typeOut if it contains something
+               if(typeOutStr)
+                       *typeOutStr = '\0';
        }
-       void merchantBox(const char *name,const char *opt,bool passive,const char *text,...){
++
++      void merchantBox(const char *name,std::vector<BuySell> *bsinv,const char *opt,bool passive,const char *text,...){
 +              std::cout << "Buying and selling on the bi-weekly!" << std::endl;
 +              va_list dialogArgs;
-               unsigned int len;
-               char *sopt,*soptbuf;
++              size_t len;
 +              
++              minv = bsinv;
 +              dialogPassive = passive;
 +              
-               /*
-                *      Set up the text buffer.
-               */
++              // clear the buffer
++              memset(dialogBoxText, '\0', 512);
 +              
-               memset(dialogBoxText,0,512);
-               
-               /*
-                *      Get the text ready for rendering.
-               */
-               
-               len=strlen(name);
-               strcpy(dialogBoxText    ,name);
-               strcpy(dialogBoxText+len,": ");
-               len+=2;
++              // create the string
++              strcpy(dialogBoxText, name);
++              strcat(dialogBoxText, ": ");
 +              
++              len=strlen(dialogBoxText);
 +              va_start(dialogArgs,text);
-               vsnprintf(dialogBoxText+len,512-len,text,dialogArgs);
++              vsnprintf(dialogBoxText + len, 512 - len, text, dialogArgs);
 +              va_end(dialogArgs);
 +                              
-               /*
-                *      Set up option text.
-               */
-               
++              // free old option text
 +              while(dialogOptCount){
 +                      if(dialogOptText[dialogOptCount]){
-                               delete[] dialogOptText[dialogOptCount]; //free(dialogOptText[dialogOptCount]);
++                              delete[] dialogOptText[dialogOptCount];
 +                              dialogOptText[dialogOptCount] = NULL;
 +                      }
++                      
 +                      dialogOptCount--;
 +              };
 +
-               dialogOptCount = 0;
 +              dialogOptChosen = 0;
-               memset(&dialogOptLoc,0,sizeof(float)*12);
++              memset(&dialogOptLoc, 0, sizeof(float) * 12);
 +              
-               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,":");
++              // handle options if desired
++              if(opt){
++                      //std::unique_ptr<char[]> soptbuf (new char[strlen(opt) + 1]);
++                      char soptbuf[255];
++                      strcpy(soptbuf, opt);
++                      char *sopt = strtok(soptbuf, ":");
++
++                      // cycle through options
++                      while(sopt){
++                              strcpy( (dialogOptText[dialogOptCount++] = new char[strlen(sopt) + 1]), sopt);
++                              sopt = strtok(NULL,":");
 +                      }
-                       
-                       delete[] soptbuf;
 +              }
 +              
-               /*
-                *      Tell draw() that the box is ready. 
-               */
-               
++              // allow box to be displayed
 +              dialogBoxExists = true;
 +              dialogImportant = false;
 +              dialogMerchant = true;
++              textWrapLimit = 50;
 +              
-               if(ret)
-                       ret[0] = '\0';
++              // kill the string created by typeOut if it contains something
++              if(typeOutStr)
++                      *typeOutStr = '\0';
++      }
++      
++      void merchantBox(){
++              textWrapLimit = 50;
++              dialogMerchant = true;
 +      }
+       
+       /**
+        * Wait for a dialog box to be dismissed.
+        */
+       
        void waitForDialog(void){
                do{
                        mainLoop();
                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);
-                               if(dialogPassive){
-                                       dialogPassiveTime -= deltaTime;
-                                       if(dialogPassiveTime < 0){
-                                               dialogPassive = false;
-                                               dialogImportant = false;
-                                               dialogBoxExists = false;
-                                       }
+                               setFontColor(255, 255, 255);
+                               
+                               // handle timeout
+                               if(dialogPassive && (dialogPassiveTime -= deltaTime) <= 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 if(dialogMerchant){
-                               /*static std::string merchOpt[3] = {"Accept",
-                                                                                                 "Cancel"};*/
 +                              x=offset.x-SCREEN_WIDTH/6;
 +                              y=(offset.y+SCREEN_HEIGHT/2)-HLINE*8;
 +                      
 +                      
 +                              glColor3ub(255,255,255);
 +                              glBegin(GL_LINE_STRIP);
 +                                      glVertex2f(x-1                                    ,y+1);
 +                                      glVertex2f(x+1+(SCREEN_WIDTH/3),y+1);
 +                                      glVertex2f(x+1+(SCREEN_WIDTH/3),y-1-SCREEN_HEIGHT*.6);
 +                                      glVertex2f(x-1,y-1-SCREEN_HEIGHT*.6);
 +                                      glVertex2f(x,y+1);
 +                              glEnd();
                        
-                               for(i=0;i<dialogOptCount;i++){
-                                       dialogOptLoc[i][1] = (y-SCREEN_HEIGHT*.55) - i*fontSize;
-                                       setFontColor(255,255,255);
-                                       tmp = putStringCentered(offset.x,dialogOptLoc[i][1],dialogOptText[i]);
 +                              glColor3ub(0,0,0);
 +                              glRectf(x,y,x+SCREEN_WIDTH/3,y-SCREEN_HEIGHT*.6);
 +                              
-                                       //merchOptLoc[i][1] = y - SCREEN_HEIGHT / 4 + (fontSize + HLINE) * (i + 1);
-                                       if(mouse.x > dialogOptLoc[i][0] &&
-                                          mouse.x < dialogOptLoc[i][2] &&
-                                          mouse.y > dialogOptLoc[i][1] &&
-                                          mouse.y < dialogOptLoc[i][1] + fontSize){ // fontSize
-                                                 setFontColor(255,255,0);
-                                                 putStringCentered(offset.x,dialogOptLoc[i][1],dialogOptText[i]);
++                              // draw typeOut'd text
++                              putString(x + HLINE, y - fontSize - HLINE, (rtext = typeOut(dialogBoxText)));
++                              merchAOptLoc[0][0] = offset.x - (SCREEN_WIDTH / 5.5);
++                              merchAOptLoc[0][1] = offset.x + (SCREEN_WIDTH / 5.5);
++                              merchAOptLoc[1][0] = offset.y + (SCREEN_HEIGHT *.25);
++                              merchAOptLoc[1][1] = offset.y + (SCREEN_HEIGHT *.25);
++                              merchAOptLoc[2][0] = offset.x - (SCREEN_WIDTH / 5.5) - 16;
++                              merchAOptLoc[2][1] = offset.x + (SCREEN_WIDTH / 5.5) + 16;
++
++                              glColor3ub(255,255,255);
++                              glBegin(GL_TRIANGLES);
++                                      glVertex2f(merchAOptLoc[2][0],merchAOptLoc[1][0]);
++                                      glVertex2f(merchAOptLoc[0][0],merchAOptLoc[1][0]-8);
++                                      glVertex2f(merchAOptLoc[0][0],merchAOptLoc[1][0]+8);
++                              glEnd();
++                      
++                              // 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
 +                                      dialogOptLoc[i][2] = offset.x + tmp;
 +                                      dialogOptLoc[i][0] = offset.x - tmp;
-                               setFontColor(255,255,255);      
-                       }else{
++                                      dialogOptLoc[i][1] = y - SCREEN_HEIGHT / 2 - (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]);
 +                                      }
 +                              }
-                       
-                       
-                               glColor3ub(255,255,255);
++                              
++                              setFontColor(255, 255, 255);
++                      }else{ //normal dialog box
 +                      
 +                              x=offset.x-SCREEN_WIDTH/2+HLINE*8;
 +                              y=(offset.y+SCREEN_HEIGHT/2)-HLINE*8;
++                                              
+                               // draw white border
+                               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();
                        
-                               glColor3ub(0,0,0);
-                               glRectf(x,y,x+SCREEN_WIDTH-HLINE*16,y-SCREEN_HEIGHT/4);
-                       
-                               rtext=typeOut(dialogBoxText);
+                               // draw black box
+                               glColor3ub(0, 0, 0);
+                               glRectf(x, y, x + SCREEN_WIDTH - HLINE * 16, y - SCREEN_HEIGHT / 4);
                        
-                               putString(x+HLINE,y-fontSize-HLINE,rtext);
+                               // draw typeOut'd text
+                               putString(x + HLINE, y - fontSize - HLINE, (rtext = typeOut(dialogBoxText)));
                        
-                               for(i=0;i<dialogOptCount;i++){
-                                       setFontColor(255,255,255);
-                                       tmp = putStringCentered(offset.x,dialogOptLoc[i][1],dialogOptText[i]);
+                               // 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
                                        dialogOptLoc[i][2] = offset.x + tmp;
                                        dialogOptLoc[i][0] = offset.x - tmp;
                                        dialogOptLoc[i][1] = y - SCREEN_HEIGHT / 4 + (fontSize + HLINE) * (i + 1);
                        return;
                }
  
-               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
+               // 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 ){
                                dialogOptChosen = i + 1;
-                               goto DONE;
+                               break;
+                       }
+               }
++
++              if(dialogMerchant){
++                      for(i = 0; i < 2; i++){
 +                      }
 +              }
- DONE:
+               
+               // handle important text
                if(dialogImportant){
                        dialogImportant = false;
                        setFontSize(16);
-                       //toggleBlack();
                }
-               /*if(ui::fontSize != 16)
-                       setFontSize(16);*/
  
 -              // kill the dialog box
 +              if(dialogMerchant) dialogMerchant = false;
                dialogBoxExists = false;
        }
 -      
 +
        void handleEvents(void){
                static bool left=true,right=false;
                static int heyOhLetsGo = 0;
                                        pixels = new GLubyte[ 3 * SCREEN_WIDTH * SCREEN_HEIGHT];
                                        glReadPixels(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, GL_RGB, GL_UNSIGNED_BYTE, pixels);
  
--                                      static std::thread scr;
--                                      scr = std::thread(takeScreenshot,pixels);
--                                      scr.detach();
--                                      //takeScreenshot(pixels);
++                                      //static std::thread scr;
++                                      //scr = std::thread(takeScreenshot,pixels);
++                                      //scr.detach();
++                                      takeScreenshot(pixels);
  
                                        std::cout << "Took screenshot" << std::endl;
                                        break;
diff --cc src/world.cpp
index 306933d5cd5769743d998adeab5e1bd473b36148,303d53b020c9121a13ae12d1367f971f29f770de..9e891fb26c92a431d67a96e7750af3edac630628
@@@ -118,6 -118,6 +118,9 @@@ void World::deleteEntities(void)
                delete mob.back();
                mob.pop_back();
        }
++      while(!merchant.empty()){
++              merchant.pop_back();
++      }
        while(!npc.empty()){
                delete npc.back();
                npc.pop_back();
        while(!light.empty()){
                light.pop_back();
        }
++      while(!village.empty()){
++              delete village.back();
++              village.pop_back();
++      }
  }
  
  World::~World(void){
@@@ -1545,14 -1532,14 +1548,15 @@@ World *loadWorldFromXMLNoSave(const cha
        
        xml.LoadFile(currentXML);
        wxml = xml.FirstChildElement("World");
--      vil = xml.FirstChildElement("World")->FirstChildElement("village");
  
        if(wxml){
                wxml = wxml->FirstChildElement();
++              vil = xml.FirstChildElement("World")->FirstChildElement("village");
                Indoor = false;
                tmp = new World();
        }else if((wxml = xml.FirstChildElement("IndoorWorld"))){
                wxml = wxml->FirstChildElement();
++              vil = NULL;
                Indoor = true;
                tmp = new IndoorWorld();
        }
                                                           (char*)vil->Attribute("texture"),
                                                           ptr);
  
 -                      vptr->build.push_back(tmp->build.back());
 +              }else if(!strcmp(name, "stall")){
 +                      if(!strcmp(vil->Attribute("type"),"market")){
 +                              std::cout << "Market" << std::endl;
 +                              tmp->addStructure((BUILD_SUB)70,
 +                                                         vil->QueryFloatAttribute("x", &spawnx) != XML_NO_ERROR ? 
 +                                                         randx : spawnx,
 +                                                         100,
 +                                                         (char*)vil->Attribute("texture"),
 +                                                         ptr);
 +                              tmp->addMerchant(0,100);
++                              if(!strcmp(name,"buy")){
++                                      std::cout << "Buying";
++                              }else if(!strcmp(name,"sell")){
++                                      std::cout << "Selling";
++                              }
 +                              strcpy(tmp->merchant.back()->name,"meme");
 +
 +                      }else if(!strcmp(vil->Attribute("type"),"trader")){
 +                              std::cout << "Trader" << std::endl;
 +                              tmp->addStructure((BUILD_SUB)71,
 +                                                         vil->QueryFloatAttribute("x", &spawnx) != XML_NO_ERROR ? 
 +                                                         randx : spawnx,
 +                                                         100,
 +                                                         (char*)vil->Attribute("texture"),
 +                                                         ptr);
 +                      }
                }
-               tmp->village.back().build.push_back(tmp->build.back());
-               if(tmp->village.back().build.back()->loc.x < tmp->village.back().start.x){
-                       tmp->village.back().start.x = tmp->village.back().build.back()->loc.x;
++                      vptr->build.push_back(tmp->build.back());
+               if(vptr->build.back()->loc.x < vptr->start.x){
+                       vptr->start.x = vptr->build.back()->loc.x;
                }
-               if(tmp->village.back().build.back()->loc.x + tmp->village.back().build.back()->width > tmp->village.back().end.x){
-                       tmp->village.back().end.x = tmp->village.back().build.back()->loc.x + tmp->village.back().build.back()->width;
+               if(vptr->build.back()->loc.x + vptr->build.back()->width > vptr->end.x){
+                       vptr->end.x = vptr->build.back()->loc.x + vptr->build.back()->width;
                }
  
                //go to the next element in the village block