NPC Communication

Posted By: Ruben

NPC Communication - 05/01/14 13:05

I am just starting on trying to create a system for the player to communicate with NPCs. I created a witch for this purpose, for the player to try to speak with.

So far, I programmed it so that if I get within 150 quants of the witch, and I press the "m" key to bring up the mouse cursor, the mouse cursor will turn a green color (from a white color originally). If I click on the witch in the green mouse cursor state, some text will show up on the screen, as follows:

Witch: Hello, my sweetie!
- Hello. How are you?
- Get away from me, witch!

My goal is to allow the player to click on a response to the witch, so that depending on the response, the witch will respond appropriately, basically following the idea behind NPC communication in the games Skyrim, Oblivion, and Fallout 3.

This is my code so far for this:

Code:
...

function witch_event()
{	
   if ((event_type == EVENT_CLICK) && (my.STATE == 2))
   {
      PANEL* my_panel = pan_create(NULL,0);
      FONT* my_font = font_create("Arial#30");   
  	
      pan_setstring(my_panel, 0, 300, 400, my_font, 
                    str_create("Witch:  Hello, my sweetie!"));
      pan_setstring(my_panel, 0, 300, 450, my_font, 
                    str_create("- Hello.  How are you?"));
      pan_setstring(my_panel, 0, 300, 500, my_font, 
                    str_create("- Get away from me, witch!"));
      set(my_panel,SHOW);
  		
      if ((mouse_left) && (mouse_pos.x > 315))
      {
         set(my_panel,NULL);
      }		
   }
}

...

action castle_witch() // COMMUNICATION SYSTEM STARTEE
{
   my.emask |= ENABLE_CLICK;
   my.event = witch_event;
	
   ...
	
   my.STATE = 1;

   while (1)
   {  
      ...
		
      if(my.STATE == 1) 
      {
         my.ANIMATION += 1*time_step;
			    
         ent_animate(me,"idle",my.ANIMATION,ANM_CYCLE);
			
	 c_scan(my.x, my.pan, vector(360,0,150), SCAN_ENTS | 
                SCAN_FLAG2 | IGNORE_ME);
			
	 // detect all FLAG2 entities within 150 
         // quants 	
			
	 if (you)
	 {
	    my.STATE = 2;
	 }
	 else
	 {
	    mouse_map = cursor_pcx;
	 }
      }
		
      if(my.STATE == 2)
      {
         my.ANIMATION += 1*time_step;
         ent_animate(me,"idle",my.ANIMATION,ANM_CYCLE);
			
	 mouse_map = cursor_green_pcx;
				
	 enemy = your.CREATOR;
			
	 // get the angle to the enemy			
	 VECTOR vDirection;
	 ANGLE vTargetAngle;
	 var speed = 1;
	 vec_diff(vDirection,enemy.x,my.x);
	 vec_to_angle(vTargetAngle,vDirection);
	 // vAngle is now the angle to the 
         // enemy.		
	 // Turn right or left depending on the difference
	 // between the current and the target pan 
         // angle			
	 my.pan += (time_step * sign(ang(vTargetAngle.pan - 
                    my.pan)) * speed);
      }

      wait(1);
   }   
}


So basically, I am trying to test out clicking some part of the screen where the text panel lies, with the idea that eventually the player will click a response on the screen, and something appropriate will happen, like a certain response from the NPC. In the code above, I am trying to make it so that if I click the left mouse button, and if the x coordinate of the mouse cursor is greater than 315 simultaneously (One of the text responses starts at x = 316 on the screen), then the text panel by the witch that was created will disappear. So far, this is not happening.

Am I even going about this correctly in creating an NPC communication system, or is there a better way?
Posted By: DLively

Re: NPC Communication - 05/02/14 17:36

You need 3 strings:

1 for the question, 2 (or more) for the answers

each string will be controlled through a TEXT, so you can swap out the chars* later for multiple texts, without having several panels for your task.

Next you need 3 panels for each string. The strings will sit ontop of the panels, and the therfore giving the illusion of having 1000's of different text panels.


Then, when you click the witch (you can use vec_for_screen to check if your clicking anything)

Clicking the witch will activate the panels.

the panels buttons will have to be controlled through one function that outputs the approriate strings per NPC.

Code:
if(npc_number == 1){
if(mouse_panel)...
//do this
}
if(npc_number == 2){
if(mouse_panel)...
//do this
}

//then turn on the texts ;)



Posted By: Ruben

Re: NPC Communication - 05/13/14 18:52

Hello DLively. I am trying out your idea in using TEXT's. This is what I have so far:

Code:
...

TEXT* witchTalk1 =	
{
  string ("Witch:  Hello, my sweetie!");
} 

TEXT* witchResp1a =	
{
  string("- Hello.  How are you?");
} 

TEXT* witchResp1b =	
{
  string ("- Get away from me, witch!");
} 

function witch_event() 
{
	
	
	if ((event_type == EVENT_CLICK) && (my.STATE == 2))
	{
		PANEL* my_panel_0 = pan_create(NULL,0);
		PANEL* my_panel_1 = pan_create(NULL,0);
		PANEL* my_panel_2 = pan_create(NULL,0);
  		FONT* my_font = font_create("Arial#30");   
  	
  		pan_setstring(my_panel_0,0,300,400,my_font,str_create(witchTalk1));
  		pan_setstring(my_panel_1,0,300,450,my_font,str_create(witchResp1a));
  		pan_setstring(my_panel_2,0,300,500,my_font,str_create(witchResp1b));
  		set(my_panel_0,SHOW);
  		set(my_panel_1,SHOW);
  		set(my_panel_2,SHOW);
		
	}
}

action castle_witch() // COMMUNICATION SYSTEM STARTEE
{
	my.emask |= ENABLE_CLICK;
	my.event = witch_event;

	...
}

...


The program runs. However, when I click on the witch, instead of these strings showing on the screen:

Hello, my sweetie!
- Hello. How are you?
- Get away from me, witch!

...I get these strange symbols that show up where the strings should be. The symbols I see are that of a cross in place of the first string, a musical note in place of the second string, and a star in place of the third string.

Do you know what I am doing wrong to make the strings show up like they should?
Posted By: Ruben

Re: NPC Communication - 05/13/14 21:00

I am trying a different method without using TEXT's, for now. This is the code I have so far:

Code:
...

function witch_event() // ORIGINAL - WORKS - DO NOT TOUCH OR ALTER
{
	if ((event_type == EVENT_CLICK) && (my.STATE == 2))
	{
		PANEL* my_panel_0 = pan_create(NULL,0);
		PANEL* my_panel_1 = pan_create(NULL,0);
		PANEL* my_panel_2 = pan_create(NULL,0);
		PANEL* my_panel_3 = pan_create(NULL,0);
		FONT* my_font1 = font_create("Times#35i");  
  		FONT* my_font2 = font_create("Times#30i");   
  	
  		pan_setstring(my_panel_0,0,300,400,my_font1,str_create("Hello, my sweetie!"));
  		pan_setstring(my_panel_1,0,300,450,my_font2,str_create("           Hello.  How are you?"));
  		pan_setstring(my_panel_2,0,300,500,my_font2,str_create("           Get away from me, witch!"));
  		pan_setstring(my_panel_3,0,300,550,my_font2,str_create("           (Ignore)"));
  		
  		wait(13);
  		set(my_panel_0,SHOW);
  		wait(120);
  		set(my_panel_1,SHOW);
  		set(my_panel_2,SHOW);
  		set(my_panel_3,SHOW);
  		
  		

	  	if(mouse_left && my_panel_1)
  		{
		  	beep(); // Debugger
			
 	 		pan_setstring(my_panel_0,0,300,400,my_font1,str_create("I am very well.  Would you like to buy a potion?"));
	  		pan_setstring(my_panel_1,0,300,450,my_font2,str_create("           Yes, I would."));
  			pan_setstring(my_panel_2,0,300,500,my_font2,str_create("           No thank you."));
  			pan_setstring(my_panel_3,0,300,550,my_font2,str_create("           (Ignore)"));
  					
  			wait(13);	
  			set(my_panel_0,SHOW);
  			wait(120);
  			set(my_panel_1,SHOW);
  			set(my_panel_2,SHOW);
  			set(my_panel_3,SHOW);
		}
	}
}

...

action player()
{
	...

	set(my,FLAG2);

	...
}

action castle_witch() // COMMUNICATION SYSTEM STARTEE
{
	my.emask |= ENABLE_CLICK;
	my.event = witch_event;
	
	...
	
	my.STATE = 1;
	
	while (1)
	{  
		// state 1: wait until player comes close enough ////// 
		if(my.STATE == 1) 
		{
			my.ANIMATION += 1*time_step;
			ent_animate(me,"idle",my.ANIMATION,ANM_CYCLE);
			
			c_scan(my.x,my.pan,vector(360,0,150),SCAN_ENTS | SCAN_FLAG2 | IGNORE_ME);
			
			// detect all FLAG2 entities within 750 quants 	
			
			if (you)
			{
				my.STATE = 2;
				
			}
			else
			{
				mouse_map = cursor_pcx;
			}
		
		}
		
		if(my.STATE == 2) // Witch senses player, turns toward player
		{
			my.ANIMATION += 1*time_step;
			ent_animate(me,"idle",my.ANIMATION,ANM_CYCLE);
			
			mouse_map = cursor_green_pcx;
				
			enemy = your.CREATOR;
			
			// get the angle to the enemy			
			VECTOR vDirection;
			ANGLE vTargetAngle;
			var speed = 1;
			vec_diff(vDirection,enemy.x,my.x);
			vec_to_angle(vTargetAngle,vDirection);
			// vAngle is now the angle to the enemy.		
			// Turn right or left depending on the difference
			// between the current and the target pan angle			
			my.pan += (time_step * sign(ang(vTargetAngle.pan - my.pan)) * speed);
		}

		wait(1);
	}
   
}	

...



The text that is supposed to show up when I first left-mouse-click on the witch:
Code:
Hello, my sweetie!
            Hello.  How are you?
            Get away from me, witch!
           (Ignore)


...is actually showing up. However, when I click on the first response (my_panel_1 - "Hello. How are you?"), I do not hear the beep() debugger go off (as given in the code), and nothing happens. If the player left-mouse-clicks the first response (my_panel_1 - "Hello. How are you?") from the text above, I want the text below to replace the text above, as given here:
Code:
I am very well.  Would you like to buy a potion?
           Yes, I would.
           No thank you.
           (Ignore)


Does anyone know why the program is not allowing me to left-mouse-click "my_panel_1" in the first set of text to initiate the action that replaces the first set of text with the second set of text?
Posted By: Uhrwerk

Re: NPC Communication - 05/14/14 22:37

Normally a click is defined as releasing the left mouse button on an object. So mouse_left should always be null in this case.
Posted By: DLively

Re: NPC Communication - 05/16/14 01:28

You are missing a "button" in your panels wink Buttons are an easier method than the one you have chosen laugh
Posted By: Ruben

Re: NPC Communication - 05/17/14 22:35

I may try to add buttons in the near future, but for now, it looks like I may have something that is working to some degree using only strings.

Right now I have working code that makes it so that if I left-click on the witch, this text will appear on the screen:

Code:
Hello, my sweetie!
         Hello.  How are you?
         Get away from me, witch!
  	 (Ignore)



I also programmed it so that if the player clicks on the first response ("Hello. How are you?" - judging by the location of the mouse cursor when the left mouse button is clicked), this text will show up on the screen:

Code:
I am very well.  Would you like to buy a potion?
         Yes, I would.
         No thank you.
  	 (Ignore)



The only problem is that the second set of text overlaps over the first set of text, so that you are able to see both sets of text simultaneously. I want to make it so that if the player clicks the first response ("Hello. How are you?") from the first set of text, the entire first set of text will disappear, and the second set of text will replace it.

Here is the code I am using to try to make this happen:

Code:
...

function witch_event() 
{
   if ((event_type == EVENT_CLICK) && (my.STATE == 2))
   {
      PANEL* talk_panel_0 = pan_create(NULL,0);
      PANEL* talk_panel_1 = pan_create(NULL,0);
      FONT* talk_font1 = font_create("Times#35i");  
      FONT* talk_font2 = font_create("Times#30i");   
      STRING* statement = str_create("Hello, my sweetie!");
      STRING* reply_1 = str_create("           Hello.  How are you?");
      STRING* reply_2 = str_create("           Get away from me, witch!");
      STRING* reply_3 = str_create("           (Ignore)");

      pan_setstring(talk_panel_0,0,300,400,talk_font1,statement);
      pan_setstring(talk_panel_1,0,300,450,talk_font2,reply_1);
      pan_setstring(talk_panel_1,0,300,500,talk_font2,reply_2);
      pan_setstring(talk_panel_1,0,300,550,talk_font2,reply_3);

      wait(13);
      set(talk_panel_0,SHOW);
      wait(120);
      set(talk_panel_1,SHOW);

      while(1)
      {	
         if(mouse_left && (mouse_pos.x > 377) && (mouse_pos.x < 602) &&  (mouse_pos.y > 456) &&  
            (mouse_pos.y < 474)) // Mouse cursor locations of the "Hello.  How are you?" response
	 {
	    statement = NULL;
	    reply_1 = NULL;
	    reply_2 = NULL;
	    reply_3 = NULL;	
				
	    statement = str_create("I am very well.  Would you like to buy a potion?");
	    reply_1 = str_create("           Yes, I would.");
  	    reply_2 = str_create("           No thank you.");
  	    reply_3 = str_create("           (Ignore)");
				
	    pan_setstring(talk_panel_0,0,300,400,talk_font1,statement);
	    pan_setstring(talk_panel_1,0,300,450,talk_font2,reply_1);
  	    pan_setstring(talk_panel_1,0,300,500,talk_font2,reply_2);
  	    pan_setstring(talk_panel_1,0,300,550,talk_font2,reply_3);
  			
  	    wait(13);
  	    set(talk_panel_0,SHOW);
  	    wait(120);
  	    set(talk_panel_1,SHOW);
  	 }
  	 wait(1);
      }
   }
}

...



Does anyone know what I am doing wrong to make it so that the first set of text disappears when I click on the first response:

"Hello. How are you?"

...and the second set of text replaces the first set of text?
Posted By: DLively

Re: NPC Communication - 05/18/14 01:57

where is your reset?
Posted By: Ruben

Re: NPC Communication - 05/18/14 03:07

I am not sure if I am using reset() correctly, but I tried putting them in my code, specifically in the while(1) loop, as shown here:

Code:
...

while(1)
		{
			
			
			if(mouse_left && (mouse_pos.x > 377) && (mouse_pos.x < 602) && (mouse_pos.y > 456) && (mouse_pos.y < 474))
			{
				reset(talk_panel_0,SHOW);
  				reset(talk_panel_1,SHOW);	
				
				statement = str_create("I am very well.  Would you like to buy a potion?");
				reply_1 = str_create("           Yes, I would.");
  				reply_2 = str_create("           No thank you.");
  				reply_3 = str_create("           (Ignore)");
				
				pan_setstring(talk_panel_0,0,300,400,talk_font1,statement);
				pan_setstring(talk_panel_1,0,300,450,talk_font2,reply_1);
  				pan_setstring(talk_panel_1,0,300,500,talk_font2,reply_2);
  				pan_setstring(talk_panel_1,0,300,550,talk_font2,reply_3);
  			
  				wait(13);
  				set(talk_panel_0,SHOW);
  				wait(120);
  				set(talk_panel_1,SHOW);
  			}
  			wait(1);
  		}

...


All the resets seem to do is restart the SHOW process for the panels (causing the strings to blink for a second from only showing the first set of strings, to showing the first and second sets of strings simultaneously), but it is not erasing the last set of strings. It still only overlays the second set of strings over the first set of strings, so they look all jumbled up.
Posted By: DLively

Re: NPC Communication - 05/18/14 03:53

reset(OBJ, FLAG)

its like set(OBJ,FLAG) but your turning it off rather than on
Posted By: Ruben

Re: NPC Communication - 05/18/14 04:13

Its nice to know how to turn off the set() using reset(), however, when I turn the set() back on after using reset(), it still has the same contents in it as before the reset(), including the new contents. Is there a way to erase the previous contents of set(), and add new contents of set() in the previous content's place?
Posted By: DLively

Re: NPC Communication - 05/18/14 04:35

http://www.conitec.net/beta/astring.htm
http://www.conitec.net/beta/astr-intro.htm
http://www.conitec.net/beta/astr_create.htm
Posted By: DLively

Re: NPC Communication - 05/23/14 06:43

Have you been successful? laugh
Posted By: Ruben

Re: NPC Communication - 05/24/14 01:03

Hello DLively. Yes, I believe I was successful. I used a series of these functions:

EVENT_CLICK
str_create
pan_setstring()
set()
reset()
mouse_left
mouse_pos.x
mouse_pox.y
mouse_mode

It seems to be working without creating buttons, although I might try using buttons in the future. But for now it seems to work in checking on the xy coordinate location of the mouse cursor, and when the left mouse button is clicked simultaneously, in seeing whether a player clicks on some text option.
Posted By: DLively

Re: NPC Communication - 05/24/14 01:55

Perfect. Thats what I wanted to hear laugh
Posted By: Ruben

Re: NPC Communication - 05/24/14 20:05

Thank you for your help. :-)
© 2024 lite-C Forums