Allegro.cc - Online Community

Allegro.cc Forums » Programming Questions » NPC Conversation

This thread is locked; no one can reply to it. rss feed Print
NPC Conversation
allegro programmer
Member #15,653
June 2014

I noticed no has done a post regarding dialogue between player and NPC, im sure it would help alot of people.

Does anyone have some advice for organizing a conversation between a player and npc in allegro.

Right now i have blue box made in photoshop that appears when i draw text on the screen. this occurence only happens once then im unable to have the player reply and so on.

for example://when enter is pressed goes to next line

NPC:HI How are you
press enter
Player: hello
press enter
NPC: go here
press enter
player: okay

can this be organized in simple if statement?

if (npc.boundx.boundy>player.boundx)//this is example I know how to code detection
{
al_draw_textf(line1)
}
then what if their are 4 lines

Cassio Renan
Member #14,189
April 2012
avatar

What you're probably looking for is a GUI(Graphical User Interface). You can try designing your own, or you can search for a good one with allegro support. TGUI is a nice one that comes to mind.

allegro programmer
Member #15,653
June 2014

so allegro doesnt have any built in string management seems like i could
do
line1=aldrawtext(line1)
line2=aldrawtext(line2)
line3=aldrawtext(line3)
line4=aldrawtext(line4)

then

if (keys[ENTER])
for ( i=0; i<4;i++)
if(i>0)
line 1
if(i>1)
line2 and so on

it doesnt work though for some reason

Arthur Kalliokoski
Second in Command
February 2005
avatar

“Throughout history, poverty is the normal condition of man. Advances which permit this norm to be exceeded — here and there, now and then — are the work of an extremely small minority, frequently despised, often condemned, and almost always opposed by all right-thinking people. Whenever this tiny minority is kept from creating, or (as sometimes happens) is driven out of a society, the people then slip back into abject poverty. This is known as "bad luck.”

― Robert A. Heinlein

allegro programmer
Member #15,653
June 2014

i download tgui it seems cool, but outdated.also no tutorials or videos using it.

Gideon Weems
Member #3,925
October 2003

Is Guichan still a viable option? Edgar's working on a GUI lib, as well... There are so many GUI libraries that I lose track.

Arthur:

http://hackertyper.com/

allegro programmer
Member #15,653
June 2014

id prefer not to use a gui lib if possible how do i modify my if statement for it to display one line after the next upon pressing enter..

what is this hacker stuff?

LennyLen
Member #5,313
December 2004
avatar

There have actually been quite a few discussions here on this topic. You can try using the site search engine to find them, or use Google to search the site.

Edgar Reynaldo
Member #8,592
May 2007
avatar

You don't need a gui, you just need a little more skill with C.

To carry on a conversation, you just need to use a little linked list that moves from one conversation event to another. Or if your conversation is linear and doesn't have any branches you could use a vector.

typedef std::list<const char*> CLIST;
CLIST Conversation;
conversation.push_back("Hello");
conversation.push_back("How are you");
conversation.push_back("Just fine thanks.");
conversation.push_back("So on...");

CLIST::iterator cit = conversation.begin();

if (ev.type == ALLEGRO_EVENT_KEY_DOWN && ev.keyboard.keycode == ALLEGRO_KEY_ENTER) {
   CLIST::iterator cit2 = cit;
   ++cit2;
   if (cit2 != conversation.end()) {
      cit = cit2;
   }
}

LennyLen
Member #5,313
December 2004
avatar

You don't need a gui, you just need a little more skill with C++.

FTFY

beoran
Member #12,636
March 2011

In C you could do it like this (untested code):

#SelectExpand
1/* Before your event loop function: */ 2 3struct conversation_struct { 4 int index; 5 const char * text[]; 6}; 7 8struct conversation_struct 9conversation = { 10 0, 11 { "Hello", "How Are You", "Just Fine Thanks", "So On", NULL } 12}; 13 14 15/* In your main event loop : */ 16const char * text_to_draw = NULL; 17 18if (ev.type == ALLEGRO_EVENT_KEY_DOWN && ev.keyboard.keycode == ALLEGRO_KEY_ENTER) { 19 if (conversation.text[conversation.index]) { 20 text_to_draw = conversation.text[conversation.index]; 21 conversation.index++; 22 } else { 23 conversation.index = 0; 24 text_to_draw = NULL; 25 } 26} 27 28/* Draw text here with al_draw_text or al_draw_textf. */

Dizzy Egg
Member #10,824
March 2009
avatar

Well, just to really confuse things, I do mine like this (I like each character to appear at a time, rather than whole lines); I use little codes in the string to decide what happens next, something like:

#SelectExpand
1char NPC_Chat[CHAT_SIZE]; 2 3... 4 5//NPC_Chat would hold a string like this: 6 7"Hello,~005my name is Dizzy!~005¬How can I help today?@"; 8 9... 10 11//Then, in my conversation function 12 13while(strlen(NPC_Chat) > 0) 14{ 15 char c = getNextChar(NPC_Chat); 16 17 if(c == '~') //Chat delay 18 { 19 //extract 3 character time, and delay 20 } 21 else if(c == '¬') 22 { 23 //new line, increase line yPos and reset line xPos 24 } 25 else if(c == '@') 26 { 27 //prompt, wait for enter key to be pressed 28 } 29 else 30 { 31 //not a special character, so just print character, increase xPos and continue 32 xPos += characterWidth(c); 33 } 34}

So basically I pick characters (like '¬' and '~') and use those as little codes in the string. This way I can have a whole multiline conversation, with delays/colour changes/prompts etc etc, that all look like:

"Welcome!...~010listen, I don't suppose¬you know where...~005...oh, nevermind!@"
"They say that ^082Mythril^255 is¬the strongest metal...~010¬bring me some ^020NOW^255!@"

etc etc...

----------------------------------------------------
Please check out my songs:
https://soundcloud.com/dont-rob-the-machina

#00JMP00
Member #14,740
November 2012

My guess would be, just look at you're conversation as an automat or machine.
This would reduce the possibility dramatically.

PC can, quit, choose an item. You only have to organize this, which is a more or less sizeable problem.

Furthermore you can organize options as a tree. Each options spawns new options, which can be choosen or not.
It is rather a logic thing than an gui thing, IMHO.

Edgar Reynaldo
Member #8,592
May 2007
avatar

LennyLen said:

FTFY

I just meant C in general, like C and C++ together.

This is what I was going to put up. It's a bastardization of C and C++. But there's a working example and source code.
NPC_conversation.7z

#SelectExpand
1 2 3#include "allegro5/allegro.h" 4#include "allegro5/allegro_image.h" 5#include "allegro5/allegro_font.h" 6#include "allegro5/allegro_ttf.h" 7#include "allegro5/allegro_primitives.h" 8#include <cstdio> 9 10ALLEGRO_DISPLAY* display = NULL; 11ALLEGRO_EVENT_QUEUE* queue = NULL; 12ALLEGRO_BITMAP* image = NULL; 13ALLEGRO_TIMER* timer = NULL; 14ALLEGRO_FONT* font1 = NULL; 15ALLEGRO_FONT* font2 = NULL; 16ALLEGRO_COLOR color1; 17ALLEGRO_COLOR color2; 18 19 20int keys[ALLEGRO_KEY_MAX]; 21 22ALLEGRO_BITMAP* MakeTile() { 23 ALLEGRO_BITMAP* tile = al_create_bitmap(256,256); 24 al_set_target_bitmap(tile); 25 for (int y = 0 ; y < 256 ; ++y) { 26 for (int x = 0 ; x < 256 ; ++x) { 27 al_draw_pixel(x , y , al_map_rgba(x , y , 0 , 255)); 28 } 29 } 30 return tile; 31} 32 33class CONVERSATION { 34public : 35 const char* text; 36 ALLEGRO_COLOR text_color; 37 CONVERSATION* next; 38 CONVERSATION* prev; 39 ALLEGRO_FONT* font; 40}; 41CONVERSATION* CreateConversationElement(const char* text , ALLEGRO_COLOR text_color , ALLEGRO_FONT* font) { 42 CONVERSATION* c = new CONVERSATION(); 43 c->text = text; 44 c->text_color = text_color; 45 c->font = font; 46 return c; 47} 48 49CONVERSATION* SetConversationPrev(CONVERSATION* c , CONVERSATION* cprev) { 50 c->prev = cprev; 51 if (cprev) { 52 cprev->next = c; 53 } 54 return cprev; 55} 56 57 58CONVERSATION* SetConversationNext(CONVERSATION* c , CONVERSATION* cnext) { 59 c->next = cnext; 60 if (cnext) { 61 cnext->prev = c; 62 } 63 return cnext; 64} 65 66CONVERSATION* MakeFirstConversation() { 67 CONVERSATION* npcAroot = CreateConversationElement("Hello. This is the beginning of the conversation." , color1 , font1); 68 CONVERSATION* npcBroot = CreateConversationElement("Oh? We're going to have a conversation?" , color2 , font2); 69 SetConversationPrev(npcAroot , 0); 70 SetConversationPrev(npcBroot , npcAroot); 71 72 CONVERSATION* A2 = CreateConversationElement("Yes. Is there anything you'd like to talk about?" , color1 , font1); 73 SetConversationPrev(A2 , npcBroot); 74 75 CONVERSATION* B2 = CreateConversationElement("Could we talk about NPC programming?" , color2 , font2); 76 SetConversationPrev(B2 , A2); 77 78 CONVERSATION* A3 = CreateConversationElement("Sure, what do you want to know?" , color1 , font1); 79 SetConversationPrev(A3 , B2); 80 81 CONVERSATION* B3 = CreateConversationElement("How do I make a conversation?" , color2 , font2); 82 SetConversationPrev(B3 , A3); 83 84 CONVERSATION* A4 = CreateConversationElement("Well, you could use a linked list." , color1 , font1); 85 SetConversationPrev(A4 , B3); 86 SetConversationNext(A4 , 0); 87 88 return npcAroot; 89} 90 91void DestroyConversation(CONVERSATION* root) { 92 if (root->next) { 93 DestroyConversation(root->next); 94 } 95 delete root; 96} 97 98int main(int argc , char** argv) { 99 100 for (int i = 0 ; i < ALLEGRO_KEY_MAX ; ++i) {keys[i] = false;} 101 102 if (!al_init()) {return -1;} 103 if (!al_init_image_addon()) {return -2;} 104 if (!al_install_keyboard()) {return -3;} 105 if (!al_init_font_addon()) {return -4;} 106 if (!al_init_ttf_addon()) {return -5;} 107 if (!al_init_primitives_addon()) {return -6;} 108 109 110 al_set_new_display_flags(ALLEGRO_WINDOWED | ALLEGRO_RESIZABLE); 111 112 display = al_create_display(640,480); 113 114 queue = al_create_event_queue(); 115 if (!queue) {return -4;} 116 117 timer = al_create_timer(1.0/60.0); 118 if (!timer) {return -5;} 119 120 al_register_event_source(queue , al_get_display_event_source(display)); 121 al_register_event_source(queue , al_get_keyboard_event_source()); 122 al_register_event_source(queue , al_get_timer_event_source(timer)); 123 124 125 image = MakeTile(); 126 al_set_target_bitmap(al_get_backbuffer(display)); 127 128 font1 = al_load_ttf_font("consola.ttf" , 20 , 0); 129 font2 = al_load_ttf_font("verdana.ttf" , 20 , 0); 130 131 color1 = al_map_rgb(255,255,0); 132 color2 = al_map_rgb(255,127,64); 133 134 135 136 bool redraw = true; 137 bool quit = false; 138 139 CONVERSATION* c = MakeFirstConversation(); 140 141 do { 142 if (redraw) { 143 al_clear_to_color(al_map_rgb(255,255,255)); 144/* 145 for (int y = 0 ; y < al_get_display_height(display) / al_get_bitmap_height(image) + 1 ; ++y) { 146 for (int x = 0 ; x < al_get_display_width(display) / al_get_bitmap_width(image) + 1; ++x) { 147 al_draw_bitmap(image , x*al_get_bitmap_width(image) , y*al_get_bitmap_height(image) , 0); 148 } 149 } 150*/ 151 // draw current part of conversation 152 int tw = al_get_text_width(c->font , c->text); 153 int th = al_get_font_line_height(c->font); 154 int tx = al_get_display_width(display)/2 - tw/2 - 20; 155 int ty = al_get_display_height(display)/2 - th/2 - 20; 156 157 al_draw_filled_rectangle(tx , ty , tx + tw + 40 , ty + th + 40 , al_map_rgb(0,0,0)); 158 al_draw_text(c->font , c->text_color , al_get_display_width(display)/2 , al_get_display_height(display)/2 , 159 ALLEGRO_ALIGN_CENTER , c->text); 160 161 162 al_flip_display(); 163 redraw = false; 164 } 165 do { 166 ALLEGRO_EVENT ev; 167 al_wait_for_event(queue , &ev); 168 if (ev.type == ALLEGRO_EVENT_DISPLAY_CLOSE) {quit = true;} 169 if (ev.type == ALLEGRO_EVENT_KEY_DOWN && ev.keyboard.keycode == ALLEGRO_KEY_ESCAPE) {quit = true;} 170 if (ev.type == ALLEGRO_EVENT_DISPLAY_RESIZE) { 171 al_acknowledge_resize(display); 172 redraw = true; 173 } 174 if (ev.type == ALLEGRO_EVENT_TIMER) {redraw = true;} 175 176 if (ev.type == ALLEGRO_EVENT_KEY_DOWN || ev.type == ALLEGRO_EVENT_KEY_UP) { 177 if (ev.type == ALLEGRO_EVENT_KEY_DOWN) {keys[ev.keyboard.keycode] = true;} 178 if (ev.type == ALLEGRO_EVENT_KEY_UP) {keys[ev.keyboard.keycode] = false;} 179 } 180 if (ev.type == ALLEGRO_EVENT_KEY_DOWN && (ev.keyboard.keycode == ALLEGRO_KEY_ENTER || ev.keyboard.keycode == ALLEGRO_KEY_SPACE)) { 181 if (c->next) { 182 c = c->next; 183 } 184 redraw = true; 185 } 186 if (ev.type == ALLEGRO_EVENT_KEY_DOWN && ev.keyboard.keycode == ALLEGRO_KEY_BACKSPACE) { 187 if (c->prev) { 188 c = c->prev; 189 } 190 redraw = true; 191 } 192 193 194 } while (!al_is_event_queue_empty(queue)); 195 196 } while (!quit); 197 198 DestroyConversation(c); 199 200 return 0; 201}

Arthur Kalliokoski
Second in Command
February 2005
avatar

Just so we're clear on this, we're talking about a "window" that scrolls like a console? While using TTF fonts in A5 of course.

“Throughout history, poverty is the normal condition of man. Advances which permit this norm to be exceeded — here and there, now and then — are the work of an extremely small minority, frequently despised, often condemned, and almost always opposed by all right-thinking people. Whenever this tiny minority is kept from creating, or (as sometimes happens) is driven out of a society, the people then slip back into abject poverty. This is known as "bad luck.”

― Robert A. Heinlein

allegro programmer
Member #15,653
June 2014

First off thanks for taking the time to reply ive been applying some of the ideas to my code trying to get them to work.

edgar: im getting an abortrun error saying vector-item-0 line 174 when running the main file.

*idk if this is relevant to the problem* when im looking through the zip in bittorrent.. when i click the npcexe saying im missing the libz.dll.

Edgar Reynaldo
Member #8,592
May 2007
avatar

allegro programmer
Member #15,653
June 2014

thanks edgar, nice code. I saved this in a word document and researching vectors a bit more so i can use this for my game.

Go to: