Have problem to add a new predicate "HasTalked"

Hello, I want if i’ve already talked with a NPC but didn’t takes a quest or Item or else, I want to display out some dialogue.
I implement the interface into the AIConversant.
But my solution not works. I found out that the Condition script never invoke the methode from the interface and I don’t know why?
Here my code:

namespace BS.Dialogue
{
    public class AIConversant : MonoBehaviour, IPredicateEvaluator  //, IRaycastable
    {
        [SerializeField] Dialogue theDialogue = null;
        [SerializeField] string npcName;

        private bool hasTalked = false;

        public void HandleDialogue(PlayerController callingController)
        {
            if (theDialogue == null)
            {
                return;
            }
            else
            {
                callingController.GetComponent<PlayerConversant>().StartDialogue(this, theDialogue);
            }
            return;
        }

        public string GetNpcName()
        {
            return npcName;
        }

        public void GetDialogue()
        {
            GameObject.FindGameObjectWithTag("Player").GetComponent<PlayerConversant>().StartDialogue(this, theDialogue);            
        }

        // HasTalked predicate
        public bool? Evaluate(string predicate, string[] parameters)
        {
            switch (predicate)
            {
                case "HasTalked":
                if (GetHasTalked())
                {
                    return HasTalked(parameters[0]);
                }
                return false;
            }
            return null;
        }

        // Is set from the Dialogue Trigger
        public void SetHasTalked()
        {
            hasTalked = true;
        }

        public bool GetHasTalked()
        {
            return hasTalked;
        }

        public bool HasTalked(string dialogueName)
        {
            return theDialogue.name == dialogueName;
        }        
    }
}



Thanks for every input.

The issue is that we collect the IPredicateEvaluators on our Player, and not on all other characters in the scene.
You would need some sort of blackboard/player memory on the Player to make this happen… Perhaps even in PlayerConversant, in this case…

Dictionary<string, bool> conversantsSpokenWith = new Dictionary<string, bool>();

public bool? Evaluate(string predicate, string[] parameters)
{
    if(predicate=="HasTalked")
    return conversantsSpokenWith.ContainsKey(parameters[0]);
}

When you start a conversation with an AIConversant, add the name of the AIConversant to the conversantsSpokenWith.

conversantsSpokenWith[otherName] = true;

Hi Brian
Thank you so mutch for your solution!! :grinning:
Just one thing. I hav to add the NPC name into the dicionary still from the invoke of a Dialogue Trigger.
Otherwise if the Dialogue starts, he means i’ve already have talked to him and the first Dialogue never will appear.
Here the code I put in the PlazerConversant script:

Dictionary<string, bool> conversantsSpokenWith = new Dictionary<string, bool>();
        
public bool? Evaluate(string predicate, string[] parameters)
        {
            switch (predicate)
            {
                case "HasTalked":
                    return conversantsSpokenWith.ContainsKey(parameters[0]);
            }
            return null;  
        }

 // Invoke from Dialogue Trigger        
public void AddNPCName()
        {
            if (conversantsSpokenWith.ContainsKey(currentConversant.GetNpcName()))
            {
                return;
            }
            conversantsSpokenWith.Add(currentConversant.GetNpcName(), true);
        }

It works fine. I’m so happy!!
Thanks again!

Hi again :grinning:
But now I have another problem. How I can save this Data?
I started an attempt, but it’s out of my knowledge. Have you an input for me?

If you’re using the original saving system (BinaryFormatter), then you can simply make the PlayerConversant and ISaveable and return the Dictionary itself

public object CaptureState()
{
    return conversantsSpokenWith;
}

public void RestoreState(object state)
{
    if(state is Dictionary<string, bool> stateDict)
    conversantsSpokenWith = stateDict;
}

If you’re using the Json saving system, you will have to be a little more brute force about it. As we’re only using a Dictionary to ensure unique keys and for rapid indexing, we can store the data as a JArray

public JToken CaptureAsJToken()
{
    JArray state = new JArray();
    foreach(string token in conversantsSpokenWith.Keys)
    {
          state.Add(token);
    } 
    return state;
}

public void RestoreFromJToken(JToken state)
{
    if(state is JArray stateArray)
    {
         conversantsSpokenWith.Clear();
         foreach(JToken token in stateArray)
         {
                conversantsSpokenWith[token.ToString()]=true;
         }
     }
}

Yeah I use the Json saving system.
Thank you, that works perfect. I learned again somethig, so great!!
I finished now the course 100%. It’s really super. I’ve done the invetory course too and the half of the core combat. The core combat I will finsh next, and then may be 3rd person combat course, because my RPG you have to playing with the gamepad.
So I have much stuff to do for next year. :crazy_face:
Merry christmas to you and the hole gamedev.tv team :hugs:

Stay tuned for my guide for integrating the Third Person Combat and Traversal course into the RPG Course series, hopefully to be completed by New Years.

This topic was automatically closed 24 hours after the last reply. New replies are no longer allowed.

Privacy & Terms