• Hey Guest! Ever feel like entering a Game Jam, but the time limit is always too much pressure? We get it... You lead a hectic life and dedicating 3 whole days to make a game just doesn't work for you! So, why not enter the GMC SLOW JAM? Take your time! Kick back and make your game over 4 months! Interested? Then just click here!

Npc talk tokens

S

Shariku Onikage

Guest
What's a good way to assign talk tokens for npcs? I have a script so that npc objects are wandering around on paths, and if they get close to each other they'll try to initiate a conversation. At the moment i basically have the following script:

Script: EnemyHasAChat
Code:
with(other) {
if (distance_to_object(other.id)  <=100){
      if other.talkingToken==1{   //talkingToken starts at 0
            talkingToken=2;
       }
       talkingToken=1;
       path_speed = 0;
       other.path_speed = 0;  //kind of get the feeling this isn't necessary at the moment

}
//actual speech destined to be a bit more complicated
if (talkingToken ==1){
    words = "Pay attention to me!"
    }


if (talkingToken==2){
    words="Geez. Hi there.";
    }

}
The problem here is that since both are running the script at the same time they both end up with the same talkingToken value (in this case 1) so they end up saying the same thing ("Pay attention to me!"). I've tried a few variations when it comes to assigning the tokens, using if and other. in various combinations but it all leads to the same both are running the script at the same time issue.

I sort of thought that instances would be running the scripts one after each other at slightly different moments but it's like they're running at the exact same time. What's the better way for me to be doing this?

Thanks in advance.
 

NightFrost

Member
You set talkingToken to 1 after checking the other participan't talkingToken value, so whatever the if-statment results in, you override it on the next line. First set the talkingToken to one, then check the other npc's token value. Or better yet, set nps'c token to one, the other's to two, and disallow the check if token is above zero:
Code:
if(talkingToken == 0){
   with(other) {
      if (distance_to_object(other.id)  <=100){
         talkingToken=1;
         other.talkingToken = 2;
         path_speed = 0;
         other.path_speed = 0;  //kind of get the feeling this isn't necessary at the moment
      }
   }
}
That way the npc checks to talk only if it is not already talking.
 
S

Shariku Onikage

Guest
Still the same thing i'm afraid. It gives both instances a talkingToken value of 2.
 

NightFrost

Member
EDIT - no, the code I suggested here can't work either. I'm not at my home computer at the moment so I can't test out actual code right now.
 
Z

Zaeith

Guest
You could try using priority queues for your NPCs where some NPCs have token precedence over others. That is, for npcs {A, B, C, D} the order follows A > B > C > D...

You could even go as far as throwing all the NPCs objects into a data structure and each step starting with the top of the list perform the check. That way if you have 50+ NPCs you're only performing one check every step versus 50+
 
S

Shariku Onikage

Guest
NPC's are procedurally generated enemy grunts, so i don't think a data structure is going to be suitable. Thanks anyway.

I figure i might try randomly assigning the talk tokens, but that's not working either. Though it assigns different talkingTokens to each instance, it then doesn't seem to assign the iTalk value, which is kind of odd.

Code:
with (other){
path_speed=0;
wordsToSay= "mustering courage to talk";  //pre-conversation check

if (talkingToken==0){
talkingToken= irandom(10); //randomly assign
}


if (talkingToken==other.talkingToken) {
    talkingToken= irandom(10);  //if they get the same token, do it again
    }

 if(talkingToken > other.talkingToken){
    iTalk=1;
    }
 if(talkingToken < other.talkingToken){
    iTalk=2;
    }
  if (iTalk ==1){
    wordsToSay= "Pay attention to me!"
    }


if (iTalk==2){
    wordsToSay="Geez. Hi there.";
    }
    }
Any advice?
 

Yal

šŸ§ *penguin noises*
GMC Elder
NPC's are procedurally generated enemy grunts, so i don't think a data structure is going to be suitable. Thanks anyway.
You can change those dynamically, though... ds_lists have built-in shuffling, and I think grids has as well. Or you could store all dialogue text (and metadata if needed, e.g. whether a bark is casual conversation, commands, reactions to being under attack etc) in a data structure and pull out random suitable ones when having conversations.
 
S

Shariku Onikage

Guest
Thanks, but i think that's more in the future. Right now i'm still just trying to figure out how to make them talk to each so that they say different things. It's still just ending up with them either getting no value or the same value (i.e. not talking or saying the same thing at the same time). The code i included above ends with them no value being assigned to iTalk, which suggests that i'm not doing something right with 'if(talkingToken > other.talkingToken)'. I get the feeling that because they're running the same script at the same time it's messing up the results.
 
A

Azure Spectre

Guest
NPC's are procedurally generated enemy grunts, so i don't think a data structure is going to be suitable. Thanks anyway.

I figure i might try randomly assigning the talk tokens, but that's not working either. Though it assigns different talkingTokens to each instance, it then doesn't seem to assign the iTalk value, which is kind of odd.

Code:
with (other){
path_speed=0;
wordsToSay= "mustering courage to talk";  //pre-conversation check

if (talkingToken==0){
talkingToken= irandom(10); //randomly assign
}


if (talkingToken==other.talkingToken) {
    talkingToken= irandom(10);  //if they get the same token, do it again
    }

 if(talkingToken > other.talkingToken){
    iTalk=1;
    }
 if(talkingToken < other.talkingToken){
    iTalk=2;
    }
  if (iTalk ==1){
    wordsToSay= "Pay attention to me!"
    }


if (iTalk==2){
    wordsToSay="Geez. Hi there.";
    }
    }
Any advice?
I ran into 3 problems testing this:
  • irandom(10) can return 0. Use irandom(9)+1
  • You are only setting half of the variables, so I was getting a one sided conversation.
  • Even after checking if both randoms are the same, it is possible that when you roll again, you will still get the same number. Fix this with a while() loop, or a >= check rather than just >.
Here's the code I came up with, I'm sure there are better solutions, but it works.
Code:
if talkingToken=0
{
    path_speed=0;
    talkingToken= irandom(9)+1;
    with (other)
    {
        path_speed=0;
        wordsToSay= "mustering courage to talk";  //pre-conversation check
   
        if (talkingToken==0)
        {
            talkingToken= irandom(9)+1; //randomly assign
        }
       
        if (talkingToken==other.talkingToken)
        {
            talkingToken= irandom(9)+1;  //if they get the same token, do it again
        }
         
        if(talkingToken >= other.talkingToken)
        {
            iTalk=1;
            other.iTalk=2;
        }
        if(talkingToken < other.talkingToken)
        {
            iTalk=2;
            other.iTalk=1;
        }
        if (iTalk ==1)
        {
            wordsToSay= "Pay attention to me!";
        }
        if (iTalk==2)
        {
            wordsToSay="Geez. Hi there.";
        }
        if (other.iTalk ==1)
        {
            other.wordsToSay= "Pay attention to me!";
        }
        if (other.iTalk==2)
        {
            other.wordsToSay="Geez. Hi there.";
        }
        show_debug_message('iTalk '+string(iTalk));
        show_debug_message('myToken '+string(talkingToken));
        show_debug_message('otherToken '+string(other.talkingToken));
    }
}
 
S

Shariku Onikage

Guest
I ran into 3 problems testing this:
  • irandom(10) can return 0. Use irandom(9)+1
  • You are only setting half of the variables, so I was getting a one sided conversation.
  • Even after checking if both randoms are the same, it is possible that when you roll again, you will still get the same number. Fix this with a while() loop, or a >= check rather than just >.
Here's the code I came up with, I'm sure there are better solutions, but it works.
Code:
if talkingToken=0
{
    path_speed=0;
    talkingToken= irandom(9)+1;
    with (other)
    {
        path_speed=0;
        wordsToSay= "mustering courage to talk";  //pre-conversation check
  
        if (talkingToken==0)
        {
            talkingToken= irandom(9)+1; //randomly assign
                wordsToSay= "assign first token";
        }
      
        if (talkingToken==other.talkingToken)
        {
            talkingToken= irandom(9)+1;  //if they get the same token, do it again
            wordsToSay= "sametoken";
        }
        
        if(talkingToken >= other.talkingToken)
        {
            iTalk=1;
            other.iTalk=2;
            wordsToSay= "more than ran!";
        }
        if(talkingToken < other.talkingToken)
        {
            iTalk=2;
            other.iTalk=1;
            wordsToSay= "less than ran";
        }
        if (iTalk ==1)
        {
            wordsToSay= "Pay attention to me!";
        }
        if (iTalk==2)
        {
            wordsToSay="Geez. Hi there.";
        }
        if (other.iTalk ==1)
        {
            other.wordsToSay= "Pay attention to me!";
        }
        if (other.iTalk==2)
        {
            other.wordsToSay="Geez. Hi there.";
        }
        show_debug_message('iTalk '+string(iTalk));
        show_debug_message('myToken '+string(talkingToken));
        show_debug_message('otherToken '+string(other.talkingToken));
    }
}
Thanks. I appreciate this, but still no joy. The debug message gives the following data:

**********************************.
Entering main loop.
**********************************.
iTalk 2
myToken 10
otherToken 10
wordsToSay: more than ran! //i added checks in the code above for each section to see what's running. It looks like the >= check is the only one that runs each time, most likely because the values are always the same as each other.
otherwordsToSay: more than ran!
iTalk 2
myToken 4
otherToken 4
wordsToSay: more than ran!
otherwordsToSay: more than ran!

It looks like the script assigns mytoken and othertoken the same result each time, so i'm guessing it's because each npc runs the script at the same time, hence the two sets of results messing each other up.
 

YanBG

Member
Do they have to say both lines(or more if many NPCs stumble) at the same time? What about checking if no other NPC show text and then draw it?
 
A

Azure Spectre

Guest
Thanks. I appreciate this, but still no joy. The debug message gives the following data:

**********************************.
Entering main loop.
**********************************.
iTalk 2
myToken 10
otherToken 10
wordsToSay: more than ran! //i added checks in the code above for each section to see what's running. It looks like the >= check is the only one that runs each time, most likely because the values are always the same as each other.
otherwordsToSay: more than ran!
iTalk 2
myToken 4
otherToken 4
wordsToSay: more than ran!
otherwordsToSay: more than ran!

It looks like the script assigns mytoken and othertoken the same result each time, so i'm guessing it's because each npc runs the script at the same time, hence the two sets of results messing each other up.
Interesting. Do you have another script somewhere that deals with any of these variables? They don't perform at the same time, because in my testing the debug messages only displayed once.

The only other stuff I have in my test objects is Create Event:

Code:
talkingToken= 0;
speed=4;
if obj_player.x>x
{
    direction=0;
}
else
{
    direction=180;
    image_xscale=-1;
}
wordsToSay = '';
iTalk = 0;
and Draw Event:
Code:
draw_self();
if talkingToken>0
{
    draw_set_color(c_blue);
    if direction=0
    {
        draw_text(x,y-48,wordsToSay);
    }
    else
    {
        draw_text(x,y+48,wordsToSay);
    }
    draw_set_color(c_black);
}
I'm also using speed rather than path_speed, but that shouldn't matter.

This is what I get.

 
A

Azure Spectre

Guest
@Shariku Onikage

https://www.mediafire.com/?qmq4fd6z9havm30

Edit:
Ok, I think I see the problem. Working out a fix now. I was running it in the collision event, so "other" referred to the other instance, doesn't look like you're doing that, but I'll look closer and make sure.

Edit2:

Step event code:
Code:
if check=0
{
    var myid = id;
    var ii=-1;
    var nearest=10000000000;
    var dist=0;
    with(oEnemy)
    {
        if id!=myid
        {
            dist=distance_to_point(other.x,other.y)
            if dist<nearest
            {
                nearest=dist;
                ii=id;
            }
        }
    }
    if ii!=-1
    {
        EnemyWantsToChat(ii);
    }
    check=1; //run only once
}
Then replace the first "other" in the script with "argument0".

The two objects were never communicating with each other to begin with, and when you call "other" in a script where there is no other, it returns "self" instead.
 
Last edited by a moderator:
S

Shariku Onikage

Guest
Oh thank freaking god that works.

Thank you so much. This has been driving me nuts.

Now, next stage is for them to have a continued conversation. I'll get to work on that.
 
Top