]> code.bitgloo.com Git - clyne/gamedev.git/commitdiff
dialog buttons
authorClyne Sullivan <tullivan99@gmail.com>
Fri, 13 Nov 2015 12:07:04 +0000 (07:07 -0500)
committerClyne Sullivan <tullivan99@gmail.com>
Fri, 13 Nov 2015 12:07:04 +0000 (07:07 -0500)
Changelog
include/ui.h
main.cpp
src/entities.cpp
src/gameplay.cpp
src/inventory.cpp
src/ui.cpp
src/world.cpp

index 5fa36602b1a5bfb3f89916c8167b140428b5b575..e967987094604468e747f37575bd46bf2d451197 100644 (file)
--- a/Changelog
+++ b/Changelog
        - fixed building entering/exiting
        - prototyped first world for story-line-thing
        - andy fixes sdl
+
+11/12/2015:
+===========
+
+       - began documenting ui.cpp
+       - vastly improved dialog, added options/buttons
+       - improved world physics a lot
+       - created a generic object class
+       - began death handling stuffs
+       - added a quest list in-game
index 6ebbd1fabb366d0076b75a8bf94da662e00a393b..6fafb17d4b34720f524108a5b14296d78a648a98 100644 (file)
@@ -25,6 +25,8 @@ namespace ui {
        extern bool debug;
        extern bool posFlag;
        extern unsigned int fontSize;
+       extern bool                      dialogBoxExists;
+       extern unsigned char dialogOptChosen;
 
        /*
         *      Initializes the FreeType system.
@@ -57,7 +59,7 @@ namespace ui {
         *      limited until a right click is given, closing the box.
        */
        
-       void dialogBox(const char *name,const char *text,...);
+       void dialogBox(const char *name,char *opt,const char *text,...);
        
        /*
         *      Draws a larger string in the center of the screen. Drawing is done inside this function.
index 292cde6d9c63f35c5ade03cb57bd528d53e4b98f..16643ddd0ebff7ef995d6aaf1542cbf9cc2137b4 100644 (file)
--- a/main.cpp
+++ b/main.cpp
@@ -215,7 +215,7 @@ typedef enum {
        RAIN
 } WEATHER;
 
-#define DAY_CYCLE 3000
+#define DAY_CYCLE 2000
 
 static WEATHER weather = SUNNY;
 static vec2 star[100];
@@ -541,16 +541,17 @@ void mainLoop(void){
         *      Update debug variables if necessary
        */
        
-       if(++debugDiv==20){
-               debugDiv=0;
-               
-               fps=1000/deltaTime;
-               
-       }else if(!(debugDiv%10)){
-               debugY = player->loc.y;
+       if(ui::debug){
+               if(++debugDiv==20){
+                       debugDiv=0;
+                       fps=1000/deltaTime;
+               }else if(!(debugDiv%10)){
+                       debugY = player->loc.y;
+               }
        }
        
        render();       // Call the render loop
+       
 }
 
 extern bool fadeEnable;
@@ -1043,8 +1044,10 @@ void logic(){
 
                                        if(SDL_GetMouseState(NULL, NULL) & SDL_BUTTON(SDL_BUTTON_RIGHT)){
 
-                                               n->interact();
-                                               Mix_PlayChannel( -1, horn, 0);  // Audio feedback
+                                               if(!ui::dialogBoxExists){
+                                                       n->interact();
+                                                       Mix_PlayChannel( -1, horn, 0);  // Audio feedback
+                                               }
 
                                        }
                                }
index b076684b2cfacf960c2b960da638cfdb14dd1f54..981f60017949ee5dad0596c33e6554d147329ce3 100644 (file)
@@ -273,7 +273,7 @@ void NPC::interact(){ //have the npc's interact back to the player
                func=aiFunc.front();
                canMove=false;
                if(!func(this)){
-                       aiFunc.erase(aiFunc.begin());
+                       if(aiFunc.size())aiFunc.erase(aiFunc.begin());
                }
                canMove=true;
        }
index c1705119b213eb4b6d9fb132fa5a9d1a14578978..4e67bb84663aceebce36bec88a3040d6856c6914 100644 (file)
@@ -8,17 +8,37 @@ extern Player *player;
 
 extern void mainLoop(void);
 
+void waitForDialog(void){
+       do{
+               mainLoop();
+       }while(ui::dialogBoxExists);
+}
+
 int compTestQuest(NPC *speaker){
-       ui::dialogBox(speaker->name,"Ooo, that's a nice quest you got there. Lemme finish that for you ;).");
+       ui::dialogBox(speaker->name,NULL,"Ooo, that's a nice quest you got there. Lemme finish that for you ;).");
        player->qh.finish("Test",player);
        return 0;
 }
 
 int giveTestQuest(NPC *speaker){
-       unsigned int i;
-       ui::dialogBox(speaker->name,"Here, have a quest!");
-       player->qh.assign("Test");
-       currentWorld->npc[1]->addAIFunc(compTestQuest,true);
+       unsigned char i;
+       
+       char opt[]=":Yes:No";
+       ui::dialogBox(speaker->name,opt,"Here, have a quest!");
+       
+       waitForDialog();
+       
+       if(ui::dialogOptChosen == 1){
+       
+               ui::dialogBox(speaker->name,NULL,"Have a good day! :)");
+
+               waitForDialog();
+
+               player->qh.assign("Test");
+               currentWorld->npc[1]->addAIFunc(compTestQuest,true);
+               
+       }else return 1;
+       
        return 0;
 }
 
index c79a29bd7d46e31af81aeee8dfff377b7fa038bc..3360e6b8a493e5fee7fcc139d25b9892e1192438 100644 (file)
@@ -145,7 +145,7 @@ int Inventory::useItem(void){
        ITEM_ID id = item[sel].id;
        switch(id){
        default:
-               ui::dialogBox(itemName[id],"You cannot use this item.");
+               ui::dialogBox(itemName[id],NULL,"You cannot use this item.");
                break;
        }
        return 0;
index 237d09aeb840612e5aa5a09c1f7ebacd9824fa6e..9c25e030f70913482524c47263bfb87ad86caeb2 100644 (file)
@@ -1,32 +1,88 @@
 #include <ui.h>
 
-#define SDL_KEY e.key.keysym.sym       // Keeps the code neater :)
+/*
+ *     Create a macro to easily access SDL keypresses
+*/
 
-extern Player *player;                 // 'player' should be (must be) defined in main.cpp
-extern World  *currentWorld;   // should/must also be defined in main.cpp
+#define SDL_KEY e.key.keysym.sym
 
-extern std::vector<int (*)(NPC *)> AIpreload;  // see entities.cpp
-extern std::vector<NPC *> AIpreaddr;                   //
+/*
+ *     External references for updating player coords / current world.
+*/
+
+extern Player *player;
+extern World  *currentWorld;
+
+/*
+ *     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;
+
+/*
+ *     Pressing ESC or closing the window will set this to false.
+*/
 
 extern bool gameRunning;
 
-static FT_Library   ftl;               // Variables for the FreeType library and stuff
+/*
+ *     Freetype variables, and a GLuint for referencing rendered letters.
+*/
+
+static FT_Library   ftl;
 static FT_Face      ftf;
 static GLuint       ftex;
 
-static char *dialogBoxText;
+static unsigned char fontColor[3] = {255,255,255};
+
+/*
+ *     Variables for dialog boxes / options.
+*/
+
+static char *dialogBoxText                     = NULL;
+static char *dialogOptText[4];
+static int   dialogOptLoc[4][3];
+static unsigned char dialogOptCount = 0;
+
+/*
+ *     Toggled by pressing 'q', disables some controls when true.
+*/
 
 bool fadeEnable = false;
 
 namespace ui {
+       
+       /*
+        *      Mouse coordinates.
+       */
+       
        vec2 mouse;
+       
+       /*
+        *      Debugging flags.
+       */
+       
        bool debug=false;
        bool posFlag=false;
+       
+       /*
+        *      Dialog stuff that needs to be 'public'.
+       */
+       
        bool dialogBoxExists=false;
+       unsigned char dialogOptChosen = 0;
+       
+       /*
+        *      Current font size. Changing this WILL NOT change the font size, see setFontSize() for
+        *      actual font size changing.
+       */
+       
        unsigned int fontSize;
 
        /*
-        * initFonts(), setFontFace(), and setFontSize() are pretty self-explanatory
+        *      Initialises the Freetype library, and sets a font size.
        */
 
        void initFonts(void){
@@ -34,11 +90,16 @@ namespace ui {
                        std::cout<<"Error! Couldn't initialize freetype."<<std::endl;
                        abort();
                }
-               fontSize=12; // to be safe
+               fontSize=12;
 #ifdef DEBUG
                DEBUG_printf("Initialized FreeType2.\n",NULL);
 #endif // DEBUG
        }
+       
+       /*
+        *      Sets a new font family to use (*.ttf).
+       */
+       
        void setFontFace(const char *ttf){
                if(FT_New_Face(ftl,ttf,0,&ftf)){
                        std::cout<<"Error! Couldn't open "<<ttf<<"."<<std::endl;
@@ -48,20 +109,48 @@ namespace ui {
                DEBUG_printf("Using font %s\n",ttf);
 #endif // DEBUG
        }
+       
+       /*
+        *      Sets a new font size (default: 12).
+       */
+       
        void setFontSize(unsigned int size){
                fontSize=size;
                FT_Set_Pixel_Sizes(ftf,0,fontSize);
        }
+       
+       /*
+        *      Set a color for font rendering (default: white).
+       */
+       
+       void setFontColor(unsigned char r,unsigned char g,unsigned char b){
+               fontColor[0]=r;
+               fontColor[1]=g;
+               fontColor[2]=b;
+       }
+       
+       /*
+        *      Draws a character at the specified coordinates, aborting if the character is unknown.
+       */
+       
        float putChar(float x,float y,char c){
-               unsigned int j;
+               unsigned int i;
                char *buf;
                float w,h;
-               // Load the first/next character (if possible)
+               
+               /*
+                *      Load the character from the font family library.
+               */
+               
                if(FT_Load_Char(ftf,c,FT_LOAD_RENDER)){
                        std::cout<<"Error! Unsupported character "<<c<<" ("<<(int)c<<")."<<std::endl;
                        abort();
                }
-               // Load the bitmap with OpenGL
+               
+               /*
+                *      Load the character into a texture for rendering.
+               */
+               
                //glActiveTexture(GL_TEXTURE0);
                glGenTextures(1,&ftex);
                glBindTexture(GL_TEXTURE_2D,ftex);
@@ -70,30 +159,41 @@ namespace ui {
                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);
+               
                /*
-                *      ftf->glyph->bitmap.buffer simply stores a bitmap of the character,
-                *      and if OpenGL tries to load it directly it'll mistake it as a simple
-                *      red on black texture. Here we allocate enough space to convert this
-                *      bitmap to an RGBA-type buffer, also making the text white on black.
-                * 
-                *      TODO: allow different colors
+                *      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=(char *)malloc(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;
-                       buf[j*4+1]=255;
-                       buf[j*4+2]=255;
-                       buf[j*4+3]=ftf->glyph->bitmap.buffer[j]?255:0;
+               
+               for(i=0;i<ftf->glyph->bitmap.width*ftf->glyph->bitmap.rows;i++){
+                       buf[i*4  ]=fontColor[0];
+                       buf[i*4+1]=fontColor[1];
+                       buf[i*4+2]=fontColor[2];
+                       buf[i*4+3]=ftf->glyph->bitmap.buffer[i]?255:0;
                }
+               
                glTexImage2D(GL_TEXTURE_2D,0,GL_RGBA,ftf->glyph->bitmap.width,ftf->glyph->bitmap.rows,0,GL_RGBA,GL_UNSIGNED_BYTE,buf);
-               // Draw the texture and move the cursor
+               
+               /*
+                *      Get the width and height of the rendered character.
+               */
+               
                w=ftf->glyph->bitmap.width;
                h=ftf->glyph->bitmap.rows;
+               
+               /*
+                *      Draw the character:
+               */
+               
                glEnable(GL_TEXTURE_2D);
                glBindTexture(GL_TEXTURE_2D,ftex);
-               switch(c){      // Some characters are not properly spaced, make them so here
-               case '^':
-               case '*':
+               
+               switch(c){                                              //              We're bad, so in here we adjust the y of
+               case '^':                                               //              some letters so that they look like they
+               case '*':                                               //              fit.
                case '`':
                case '\'':
                case '\"':
@@ -110,6 +210,7 @@ namespace ui {
                case 'j':y-=fontSize/4;break;
                default:break;
                }
+               
                glBegin(GL_QUADS);
                        glColor3ub(255,255,255);
                        glTexCoord2f(0,1);glVertex2f(x,y);
@@ -117,75 +218,175 @@ namespace ui {
                        glTexCoord2f(1,0);glVertex2f(x+w,y+h);
                        glTexCoord2f(0,0);glVertex2f(x,y+h);
                glEnd();
+               
                glDisable(GL_TEXTURE_2D);
-               // Free the RGBA buffer and the OpenGL texture
+               
+               /*
+                *      Free resources, and return the width.
+               */
+               
                free(buf);
                glDeleteTextures(1,&ftex);
+               
                return w;
        }
+       
+       /*
+        *      Draw a string at the specified coordinates.
+       */
+       
        float putString(const float x,const float y,const char *s){
                unsigned int i=0,j;
                float xo=x,yo=y,pw=0;
+               
+               /*
+                *      Loop on each character:
+               */
+               
                do{
-                       if(s[i]=='\n'){
+                       if(s[i]=='\n'){                 //      Handle newlines
                                yo-=fontSize*1.05;
                                xo=x;
-                       }else if(s[i]==' '){
+                       }else if(s[i]==' '){    //      Handle spaces
                                xo+=fontSize/2;
-                       }else if(s[i]=='\b'){
+                       }else if(s[i]=='\b'){   //      Handle backspaces?
                                xo-=pw;
                        }else{
                                pw=putChar(xo,yo,s[i])+fontSize*.1;
                                xo+=pw;
                        }
                }while(s[++i]);
-               return xo;
+               
+               return xo;      // i.e. the string width
        }
+       
+       /*
+        *      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.
+       */
+       
        char *typeOut(char *str){
-               static unsigned int sinc,linc,size=0;
+               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.
                static char *ret = NULL;
                unsigned int i;
-               if(!ret)ret=(char *)calloc(512,sizeof(char));
-               if(size != strlen(str)){
-                       memset(ret,0,512);
-                       size=strlen(str);
-                       linc=0;
+               
+               /*
+                *      Create a well-sized buffer if we haven't yet.
+               */
+               
+               if(!ret) ret=(char *)calloc(512,sizeof(char));
+               
+               /*
+                *      Reset values if a new string is being passed.
+               */
+               
+               if(!size || ((linc>15)&(strncmp(ret,str,15)))){
+                       memset(ret,0,512);              //      Zero the buffer
+                       size=strlen(str);               //      Set the new target string size
+                       linc=0;                                 //      Reset the incrementers
                        sinc=1;
                }
+               
+               /*
+                *      Draw the next letter if necessary.
+               */
+               
                if(++sinc==2){
                        sinc=0;
-                       strncpy(ret+linc,str+linc,1);
+                       
+                       strncpy(ret+linc,str+linc,1);   //      Get next character
+                       
                        if(linc<size)linc++;
                }
-               return ret;
+               
+               return ret;             //      The buffered string.
        }
-       float putText(const float x,const float y,const char *str,...){ // putText() simply runs 'str' and the extra arguments though
-               va_list args;                                                                                           // vsnprintf(), which'll store the complete string to a buffer
-               char *buf;                                                                                                      // that's then passed to putString()
+       
+       /*
+        *      Draw a formatted string to the specified coordinates.
+       */
+       
+       float putText(const float x,const float y,const char *str,...){
+               va_list args;
+               char *buf;
                float width;
+               
+               /*
+                *      Create a wimpy buffer.
+               */
+               
                buf=(char *)calloc(128,sizeof(char));
+               
+               /*
+                *      Handle the formatted string, printing it to the buffer.
+               */
+               
                va_start(args,str);
                vsnprintf(buf,128,str,args);
                va_end(args);
+               
+               /*
+                *      Draw the string, free resources, return the width of the string.
+               */
+               
                width=putString(x,y,buf);
                free(buf);
+               
                return width;
        }
-       void dialogBox(const char *name,const char *text,...){
-               unsigned int name_len;
+       
+       void dialogBox(const char *name,char *opt,const char *text,...){
                va_list dialogArgs;
+               unsigned int len;
+               char *sopt;
+               
+               /*
+                *      Set up the text buffer.
+               */
+               
+               if(!dialogBoxText) dialogBoxText=(char *)malloc(512);
+               memset(dialogBoxText,0,512);
+               
+               /*
+                *      Get the text ready for rendering.
+               */
+               
+               len=strlen(name);
+               strcpy(dialogBoxText    ,name);
+               strcpy(dialogBoxText+len,": ");
+               len+=2;
+               
                va_start(dialogArgs,text);
-               dialogBoxExists=true;
-               if(dialogBoxText){
-                       free(dialogBoxText);
-                       dialogBoxText=NULL;
-               }
-               dialogBoxText=(char *)calloc(512,sizeof(char));
-               name_len=strlen(name);
-               strcpy(dialogBoxText,name);
-               strcpy(dialogBoxText+strlen(name),": ");
-               vsnprintf(dialogBoxText+name_len+2,512-name_len-2,text,dialogArgs);
+               vsnprintf(dialogBoxText+len,512-len,text,dialogArgs);
                va_end(dialogArgs);
+                               
+               /*
+                *      Set up option text.
+               */
+               
+               while(dialogOptCount){
+                       if(dialogOptText[dialogOptCount])
+                               free(dialogOptText[dialogOptCount]);
+                       dialogOptCount--;
+               };
+               dialogOptChosen=0;
+               dialogOptCount=0;
+               
+               sopt=strtok(opt,":");
+               while(sopt != NULL){
+                       dialogOptText[dialogOptCount]=(char *)malloc(strlen(sopt));
+                       strcpy(dialogOptText[dialogOptCount++],sopt);
+                       sopt=strtok(NULL,":");
+               }
+               
+               /*
+                *      Tell draw() that the box is ready. 
+               */
+               
+               dialogBoxExists = true;
+               
        }
        void importantText(const char *text,...){
                va_list textArgs;
@@ -204,17 +405,39 @@ namespace ui {
                free(ttext);
        }
        void draw(void){
+               unsigned char i;
                float x,y;
+               char *rtext;
+               
                if(dialogBoxExists){
+                       
                        glColor3ub(0,0,0);
                        x=player->loc.x-SCREEN_WIDTH/2+HLINE*8;
                        y=(offset.y+SCREEN_HEIGHT/2)-HLINE*8;
+                       
                        glRectf(x,y,x+SCREEN_WIDTH-HLINE*16,y-SCREEN_HEIGHT/4);
-                       char *rtext;
+                       
                        rtext=typeOut(dialogBoxText);
+                       
                        setFontSize(16);
                        putString(x+HLINE,y-fontSize-HLINE,rtext);
+                       
+                       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
+                                         setFontColor(255,255,0);
+                               }else setFontColor(255,255,255);
+                               dialogOptLoc[i][0]=x+HLINE;
+                               dialogOptLoc[i][1]=y-SCREEN_HEIGHT/4+(fontSize+HLINE)*(i+1);
+                               dialogOptLoc[i][2]=
+                       
+                               putString(x+HLINE,y-SCREEN_HEIGHT/4+(fontSize+HLINE)*(i+1),dialogOptText[i]);
+                       }
+                       setFontColor(255,255,255);
                }
+               
                setFontSize(14);
                putText(((SCREEN_WIDTH/2)+offset.x)-125,(offset.y+SCREEN_HEIGHT/2)-fontSize,"Health: %u/%u",player->health>0?(unsigned)player->health:0,
                                                                                                                                                                                        (unsigned)player->maxHealth);
@@ -227,6 +450,7 @@ namespace ui {
                }
        }
        void handleEvents(void){
+               unsigned char i;
                static bool left=false,right=false;
                static vec2 premouse={0,0};
                SDL_Event e;
@@ -243,8 +467,18 @@ namespace ui {
                                break;
                        case SDL_MOUSEBUTTONDOWN:
                                if((e.button.button&SDL_BUTTON_RIGHT)&&dialogBoxExists){
+                                       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;
+                                                       goto DONE;
+                                               }
+                                       }
+DONE:
                                        dialogBoxExists=false;
-                                       dialogBoxText=NULL;
+                                       //dialogBoxText=NULL;
                                }
                                break;
                        /*
@@ -306,9 +540,6 @@ namespace ui {
                                if(SDL_KEY==SDLK_e){
                                        player->inv->useItem();
                                }
-                               if(SDL_KEY==SDLK_c){
-                                       dialogBox("","You pressed `c`, but nothing happened?");
-                               }
                                if(SDL_KEY==SDLK_LSHIFT)player->speed = debug?4:3;                                                      // Sprint
                                if(SDL_KEY==SDLK_LCTRL)player->speed = .5;
                        }
@@ -340,7 +571,6 @@ namespace ui {
                
                if(player->inv->tossd)player->inv->itemToss();
                
-               unsigned int i;
                if(!dialogBoxExists&&AIpreaddr.size()){ // Flush preloaded AI functions if necessary
                        for(i=0;i<AIpreaddr.size();i++){
                                AIpreaddr.front()->addAIFunc(AIpreload.front(),false);
index 049e49877d49774ea6d7f7170874a9151d795e38..a6fe5400886a720d51e71080f1ed25dca53150ec 100644 (file)
@@ -589,7 +589,7 @@ World *World::goWorldLeft(Player *p){
 World *World::goWorldRight(Player *p){
        if(toRight&&p->loc.x+p->width>x_start+getWidth(this)-HLINE*10){
                p->loc.x=toRight->x_start+HLINE*10;
-               p->loc.y=toRight->line[toRight->lineCount-GEN_INC-1].y;
+               p->loc.y=toRight->line[0].y;
                return toRight;
        }
        return this;