Unity Dialogue & Quests - Evaluate not being called

Howdy, I’ve nearly finished the Dialogue & Quests course (which is fantastic) and everything works great - except “Evaluate” is not being called in the Condition script, meaning the whole predicate system doesn’t work and choices are still appearing that shouldn’t. Any idea why this is?


It looks like your quests aren’t in a folder named Resources. The Resources.LoadAll method requires that the scripts be in a Resources folder, and this is how we check to see if a quest exists…
Of course, that does mean it should be not finding the quest in HasQuest and the predicate should fail.

Let’s take a look at your Condition.cs script and your PlayerConversant.cs script. Don’t forget to format the code by selecting it and pressing the </> button. (don’t post screenshots of the code, paste it direct)

1 Like
using System;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;


namespace RPG.Dialogue
{
    public class PlayerConversant : MonoBehaviour
    {
        Mech mech;
        Farmer farmer;

        [SerializeField] string playerName;

        Dialogue currentDialogue;
        DialogueNode currentNode = null;
        AIConversant currentConversant = null;
        bool isChoosing = false;

        public event Action onConversationUpdated;

        public void Start()
        {
            mech = FindObjectOfType<Mech>();
            farmer = FindObjectOfType<Farmer>();
        }

        public void StartDialogue(AIConversant newConversant, Dialogue newDialogue)
        {

            currentConversant = newConversant;
            mech.WindowOpen();
            farmer.WindowOpen();
            currentDialogue = newDialogue;
            currentNode = currentDialogue.GetRootNode();
            TriggerEnterAction();
            onConversationUpdated();
        }

        public void Quit()
        {
            mech.WindowClosed();
            farmer.WindowClosed();
            TriggerExitAction();
            currentConversant = null;
            currentDialogue = null;
            currentNode = null;
            isChoosing = false;
            onConversationUpdated();
        }

        public bool IsActive()
        {
            return currentDialogue != null;
        }

        public bool IsChoosing()
        {
            return isChoosing;
        }

        public string GetText()
        {
            if (currentNode == null)
            {
                return "";
            }

            return currentNode.GetText();
        }

        public string GetCurrentConversantName()
        {
            if (isChoosing)
            {
                return playerName;
            }
            else
            {
                return currentConversant.GetName();
            }
        }

        public IEnumerable<DialogueNode> GetChoices()
        {
            return FilterOnCondition(currentDialogue.GetPlayerChildren(currentNode));
        }

        public void SelectChoice(DialogueNode chosenNode)
        {
            currentNode = chosenNode;
            TriggerEnterAction();
            isChoosing = false;
            Next();
        }
    
        public void Next()
        {
            int numPlayerResponses = FilterOnCondition(currentDialogue.GetPlayerChildren(currentNode)).Count();
            if (numPlayerResponses > 0)
            {
                isChoosing = true;
                TriggerExitAction();
                onConversationUpdated();
                return;
            }

            DialogueNode[] children = FilterOnCondition(currentDialogue.GetAIChildren(currentNode)).ToArray();
            int randomIndex = UnityEngine.Random.Range(0, children.Count());
            TriggerExitAction();
            currentNode = children[randomIndex];
            TriggerEnterAction();
            onConversationUpdated();
        }

        public bool HasNext()
        {
            return FilterOnCondition(currentDialogue.GetAllChildren(currentNode)).Count() > 0;
        }

        private IEnumerable<DialogueNode> FilterOnCondition(IEnumerable<DialogueNode> inputNode)
        {
            foreach (var node in inputNode)
            {
                if (node.CheckCondition(GetEvaluators()))
                {
                    yield return node;
                }
            }
        }

        private IEnumerable<IPredicateEvaluator> GetEvaluators()
        {
            return GetComponents<IPredicateEvaluator>();
        }

        private void TriggerEnterAction()
        {
            if (currentNode != null)
            {
                TriggerAction(currentNode.GetOnEnterAction());
            }
        }

        private void TriggerExitAction()
        {
            if (currentNode != null)
            {
                TriggerAction(currentNode.GetOnExitAction());
            }
        }

        private void TriggerAction(string action)
        {
            if (action == "") return;

            foreach (DialogueTrigger trigger in currentConversant.GetComponents<DialogueTrigger>())
            {
                trigger.Trigger(action);
            }
        }
    }
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;


    [System.Serializable]
    public class Condition
    {
        [SerializeField]
        Disjunction[] and;

        public bool Check(IEnumerable<IPredicateEvaluator> evaluators)
        {
        Debug.Log("Condition:Check CALLED");

            foreach (Disjunction dis in and)
            {
                if (!dis.Check(evaluators))
                {
                    return false;
                }
            }
            return true;
        }

        [System.Serializable]
        class Disjunction
        {
            [SerializeField]
            Predicate[] or;

            public bool Check(IEnumerable<IPredicateEvaluator> evaluators)
            {

                foreach (Predicate pred in or)
                {
                    if (pred.Check(evaluators))
                    {
                        return true;
                    }
                }
                return false;
            }
        }

        [System.Serializable]
        class Predicate
        {
            [SerializeField]
            string predicate;
            [SerializeField]
            string[] parameters;
            [SerializeField]
            bool negate = false;

            public bool Check(IEnumerable<IPredicateEvaluator> evaluators)
            {
                foreach (var evaluator in evaluators)
                {
                    bool? result = evaluator.Evaluate(predicate, parameters);
                    if (result == null)
                    {
                        continue;
                    }

                    if (result == negate) return false;
                }
                return true;
            }
        }
    }

Thanks for having a look Brian, really appreciate it :slight_smile:

(I know the Condition isn’t using the CORE namespace but I don’t have that in my project so I’ve just left it without one)

Ok, the relevant portions of the code look right.
As I mentioned earlier, conditions are notoriously hard to debug. Zip up your project and upload it to https://gdev.tv/projectupload and I’ll take a look at it.

1 Like

The file was quite big so I ripped out what I could but was afraid to remove more in case the game stopped working - doesn’t look pretty but you should be able to recreate the problem.

WASD - move
Left click - interact with NPC
Quest Journal = QST button at top

Thanks again for having a look Brian, very kind of you, really appreciate it.

Ok, this one was quite the challenge, because I was unable to get any of my Debugs to fire within QuestList itself.

It appears that your QuestList is not on the player (farmer), but on some other GameObject within the scene. I was not able to find it, but I know it’s there because QuestGiver found it using FindObjectOfType<QuestList>

The QuestList should be on the same GameObject as the PlayerConversant. The PlayerConversant gets its list of evaluators from GetComponents<IPredicateEvaluator>, which returns the components on the player.

Try putting the QuestList on the player (farmer) instead of on a separate GameObject, and the Condition system should properly find it.

1 Like

Brian, thank you so much, I spent 2 days banging my head against a wall! I had a back-up plan ready - it would’ve been messy and probably caused more trouble down the line but now you’ve completely sorted it.
Thank you so very much Brian, you’re a legend.

1 Like

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

Privacy & Terms