Пример #1
0
    public static void OnConversationEnded(this NPCConversation conversation, UnityAction action)
    {
        // Deserialize the conversation for modification
        EditableConversation editableConversation = conversation.DeserializeForEditor();

        // Filter all speech nodes that have no speech node after and have no options after
        IEnumerable <EditableSpeechNode> leaves = editableConversation.SpeechNodes
                                                  .Where(node => node.SpeechUID == EditableConversation.INVALID_UID && (node.OptionUIDs == null || node.OptionUIDs.Count <= 0));

        // For each event associated with the leaf, make that leaf end the conversation when finished
        foreach (EditableSpeechNode leaf in leaves)
        {
            NodeEventHolder eventHolder = conversation.GetNodeData(leaf.ID);
            eventHolder.Event.AddListener(action);
        }
    }
Пример #2
0
    private EditableSpeechNode CreateSpeechNode(NPCConversation conversation, EditableConversation editableConversation, string text, float xPos, float yPos, bool isRoot, UnityAction callback)
    {
        // Create a new speech node
        EditableSpeechNode speechNode = new EditableSpeechNode()
        {
            Text       = text,
            Name       = npcName,
            Icon       = npcIcon,
            TMPFont    = npcFont,
            ID         = conversation.CurrentIDCounter,
            EditorInfo = new EditableConversationNode.EditorArgs()
            {
                xPos   = xPos,
                yPos   = yPos,
                isRoot = isRoot
            }
        };

        // Setup the node event.
        NodeEventHolder nodeEvent = conversation.GetNodeData(conversation.CurrentIDCounter);

        nodeEvent.Icon    = npcIcon;
        nodeEvent.TMPFont = npcFont;

        // If the callback is not null that add it to the event
        if (callback != null)
        {
            nodeEvent.Event.AddListener(callback);
        }

        // Add this to the list of speech nodes
        editableConversation.SpeechNodes.Add(speechNode);

        // Update the counter
        conversation.CurrentIDCounter++;

        // Return the speech node
        return(speechNode);
    }
    public void Respond()
    {
        if (GameManager.Instance)
        {
            // Deserialize the conversation for modification
            EditableConversation editableConversation = conversation.DeserializeForEditor();

            // Filter all speech nodes that have no speech node after and have no options after
            IEnumerable <EditableSpeechNode> leaves = editableConversation.SpeechNodes
                                                      .Where(node => node.SpeechUID == EditableConversation.INVALID_UID && (node.OptionUIDs == null || node.OptionUIDs.Count <= 0));

            // For each event associated with the leaf, make that leaf end the conversation when finished
            foreach (EditableSpeechNode leaf in leaves)
            {
                NodeEventHolder eventHolder = conversation.GetNodeData(leaf.ID);
                eventHolder.Event.AddListener(OnConversationEnded);
            }

            // Say the given conversation on the dialogue manager
            DialogueManager dialogue = GameManager.Instance.m_dialogueManager;
            dialogue.SetNewDialogue(conversation);
        }
    }
Пример #4
0
    private EditableOptionNode CreateOptionNode(NPCConversation conversation, EditableConversation editableConversation, string text, float xPos, float yPos)
    {
        // Create a new option node with the same label as the quiz option
        EditableOptionNode optionNode = new EditableOptionNode()
        {
            Text       = text,
            TMPFont    = npcFont,
            ID         = conversation.CurrentIDCounter,
            EditorInfo = new EditableConversationNode.EditorArgs()
            {
                xPos = xPos,
                yPos = yPos
            }
        };

        // Add this option node to the editable conversation
        editableConversation.Options.Add(optionNode);

        // Update the current id
        conversation.CurrentIDCounter++;

        // Return the new node
        return(optionNode);
    }
Пример #5
0
    public NPCConversation Create(DialogueManager dialogueManager)
    {
        // Build a new quiz. This will result in regenerating new questions from any randomized pools
        GenerateQuizInstance();

        // Create the callback that is called after any option is answered
        UnityAction OptionSelectedFunctor(int questionIndex, int optionIndex)
        {
            return(() => currentQuiz.AnswerQuestion(questionIndex, optionIndex));
        }

        // Say the conversation that corresponds to the grade that the player got on the quiz
        void SayResponse()
        {
            // Destroy any previous response
            if (currentResponse)
            {
                Destroy(currentResponse);
            }
            // Instantiate a new response
            currentResponse = response.Get(CurrentQuiz.Grade).InstantiateAndSay();

            // If we should requiz when we fail, then we must say the quiz after the response
            if (requizOnFail && CurrentQuiz.Grade != QuizGrade.Excellent)
            {
                SayQuizConversationNext();
            }
            // If we will not requiz, then invoke my conversation ended event when this conversation is done
            else
            {
                // Set the quiz on the reports data to the quiz that we just finished
                GameManager.Instance.NotebookUI.Data.Reports.SetQuiz(LevelID.Current(), currentQuiz);

                // Invoke the quiz conversation ended event when the response is over
                currentResponse.OnConversationEnded(onConversationEnded.Invoke);
            }
        }

        // Try to get an npc conversation. If it exists, destroy it and add a new one
        NPCConversation conversation = gameObject.GetComponent <NPCConversation>();

        if (conversation)
        {
#if UNITY_EDITOR
            DestroyImmediate(conversation);
#else
            Destroy(conversation);
#endif
        }
        conversation = gameObject.AddComponent <NPCConversation>();

        // Create the conversation to be edited here in the code
        EditableConversation editableConversation = new EditableConversation();
        EditableSpeechNode   previousSpeechNode   = null;

        // A list of all nodes added to the conversation
        List <EditableConversationNode> nodes = new List <EditableConversationNode>();

        // Loop over every question and add speech and option nodes for each
        for (int i = 0; i < currentQuiz.RuntimeTemplate.Questions.Length; i++)
        {
            // Cache the current question
            QuizQuestion question = currentQuiz.RuntimeTemplate.Questions[i];

            // Create a new speech node
            EditableSpeechNode currentSpeechNode = CreateSpeechNode(conversation, editableConversation, question.Question, 0, i * 300, i == 0, null);
            nodes.Add(currentSpeechNode);

            // If a previous speech node exists, then make the options on the previous node
            // point to the speech on the current node
            if (previousSpeechNode != null)
            {
                foreach (EditableOptionNode option in previousSpeechNode.Options)
                {
                    option.Speech.SetSpeech(currentSpeechNode);
                }
            }

            // Add an option node for each quiz option
            for (int j = 0; j < question.Options.Length; j++)
            {
                // Get the current option
                QuizOption option = question.Options[j];

                // Create a new option node with the same label as the quiz option
                EditableOptionNode optionNode = CreateOptionNode(conversation, editableConversation, option.Label, j * 220, (i * 300) + 100);
                currentSpeechNode.AddOption(optionNode);
                nodes.Add(optionNode);

                // Create a dummy node. It is used to invoke events
                UnityAction        optionCallback = OptionSelectedFunctor(i, j);
                EditableSpeechNode dummyNode      = CreateSpeechNode(conversation, editableConversation, string.Empty, j * 220, (i * 300) + 200, false, optionCallback);
                nodes.Add(dummyNode);

                // Make the dummy node advance immediately
                dummyNode.AdvanceDialogueAutomatically   = true;
                dummyNode.AutoAdvanceShouldDisplayOption = false;
                dummyNode.TimeUntilAdvance = 0f;

                // Make the option node point to the dummy node
                optionNode.SetSpeech(dummyNode);
            }

            // Update previous speech node to current before resuming
            previousSpeechNode = currentSpeechNode;
        }

        // Create the end of quiz node
        EditableSpeechNode endOfQuiz = CreateSpeechNode(conversation, editableConversation, endOfQuizText, 0, currentQuiz.RuntimeTemplate.Questions.Length * 300, false, SayResponse);
        nodes.Add(endOfQuiz);

        // If a previous speech node exists,
        // then make its options point to the end of quiz node
        if (previousSpeechNode != null)
        {
            foreach (EditableOptionNode option in previousSpeechNode.Options)
            {
                option.Speech.SetSpeech(endOfQuiz);
            }
        }

        // Have all the nodes register their UIDs (whatever the frick THAT means)
        foreach (EditableConversationNode node in nodes)
        {
            node.RegisterUIDs();
        }

        // Serialize the editable conversation back into the NPCConversation and return the result
        conversation.RuntimeSave(editableConversation);
        return(conversation);
    }
Пример #6
0
    public void OnValidate()
    {
        if (text == null || !tryParseConversation)
        {
            return;
        }

        tryParseConversation = false; // try parsing once


        GameObject gameObject = new GameObject("New Conversation");

        gameObject.transform.parent = transform;

        NPCConversation NPCConversation = gameObject.AddComponent <NPCConversation>();

        // Load in id and icon info
        Dictionary <string, Sprite> idToIconDictionary = new Dictionary <string, Sprite>();

        if (iconIDInput.Length > 0)
        {
            foreach (var pair in iconIDInput)
            {
                idToIconDictionary.Add(pair.id, pair.icon);
            }
        }

        // Preprocess
        string toParse = text.text;
        EditableConversation conversation = new EditableConversation();

        string[] nodeTexts = toParse.Split('\n');

        // Initialize root node
        EditableSpeechNode root = new EditableSpeechNode();

        root.Text = nodeTexts[0].Substring(nodeTexts[0].IndexOf(':', 1) + 1).Trim();
        root.Name = defaultName;
        root.Icon = defaultIcon;
        string iconID = nodeTexts[0].Substring(1, nodeTexts[0].IndexOf(':', 1) - 1);

        if (idToIconDictionary.ContainsKey(iconID))
        {
            root.Icon = idToIconDictionary[iconID];
            NPCConversation.GetNodeData(NPCConversation.CurrentIDCounter).Icon = root.Icon;
        }
        root.ID                = NPCConversation.CurrentIDCounter++;
        root.TMPFont           = defaultFont;
        root.EditorInfo.isRoot = true;
        conversation.SpeechNodes.Add(root);
        bool previousNodeIsSpeech = true;

        EditableSpeechNode              previousSpeech  = root;
        List <EditableOptionNode>       previousOptions = new List <EditableOptionNode>();
        List <EditableConversationNode> nodes           = new List <EditableConversationNode>();

        nodes.Add(root);

        for (int i = 1; i < nodeTexts.Length; i++)
        {
            string currentText = nodeTexts[i];
            if (currentText.Length == 0)
            {
                continue;
            }

            EditableConversationNode node;

            // First char is a colon, this is a speech
            if (currentText[0] == ':')
            {
                EditableSpeechNode speechNode = new EditableSpeechNode();
                speechNode.Name = defaultName;

                // text enclosed by colons is id of the icon
                iconID = currentText.Substring(1, currentText.IndexOf(':', 1) - 1);
                if (idToIconDictionary.ContainsKey(iconID))
                {
                    speechNode.Icon = idToIconDictionary[iconID];
                    NPCConversation.GetNodeData(NPCConversation.CurrentIDCounter).Icon = speechNode.Icon;
                }
                else
                {
                    // unknown id
                    speechNode.Icon = defaultIcon;
                }

                // connect previous nodes to speech
                if (previousNodeIsSpeech)
                {
                    speechNode.parents.Add(previousSpeech);
                    previousSpeech.SetSpeech(speechNode);
                }
                else
                {
                    // Connect previous immediate options to node
                    foreach (var option in previousOptions)
                    {
                        speechNode.parents.Add(option);
                        option.SetSpeech(speechNode);
                    }
                    previousOptions.Clear();
                }

                previousNodeIsSpeech = true;
                previousSpeech       = speechNode;
                conversation.SpeechNodes.Add(speechNode);

                node = speechNode;
            }
            else
            {
                EditableOptionNode optionNode = new EditableOptionNode();

                optionNode.parents.Add(previousSpeech);
                previousSpeech.AddOption(optionNode);
                previousNodeIsSpeech = false;
                previousOptions.Add(optionNode);
                conversation.Options.Add(optionNode);

                node = optionNode;
            }
            // Common info
            node.EditorInfo.yPos = 100 * i;
            node.Text            = currentText.Substring(currentText.IndexOf(':', 1) + 1).Trim();
            node.TMPFont         = defaultFont;
            node.ID = NPCConversation.CurrentIDCounter++;
            nodes.Add(node);
        }

        foreach (EditableConversationNode node in nodes)
        {
            node.RegisterUIDs();
        }

        NPCConversation.Serialize(conversation);
    }