示例#1
0
    /// <summary>
    /// Defines behavior for selecting right-click context items. Modify this function if you wish to create custom nodes and context menu behaviors.
    /// </summary>
    public override void ContextCallback(object obj)
    {
        switch (obj.ToString())
        {
        case "dialogueNode":
            numberOfStates++;
            DialogueNode.Create(new Rect(mousePos.x, mousePos.y, 350, 350), numberOfStates);
            break;

        case "dialogueChoice":
            numberOfChoiceStates++;
            DialogueChoiceNode.Create(new Rect(mousePos.x, mousePos.y, 100, 50), numberOfChoiceStates);
            break;

        case "deleteNode":
            Node node = NodeAtPosition(mousePos);
            if (node != null)
            {
                if (node.GetType() == typeof(DialogueNode))
                {
                    numberOfStates--;
                }
                else if (node.GetType() == typeof(DialogueChoiceNode))
                {
                    numberOfChoiceStates--;
                }

                // Find all nodes with higher state values than the deleted node and subtract 1 from their state.
                foreach (Node successorNode in nodeCanvas.nodes)
                {
                    // Ignore choice states
                    if (successorNode.state != -2 && successorNode.state > node.state)
                    {
                        successorNode.state--;
                        successorNode.name = "State " + successorNode.state;
                    }
                }

                nodeCanvas.nodes.Remove(node);

                if (node.GetType() == typeof(DialogueChoiceNode))
                {
                    _nodeCanvas.choiceNodes.Remove(node);
                    _nodeCanvas.choiceNodeNames.Remove(node.name);
                }

                // Iterate over all the other nodes and update start/final states
                foreach (Node editorNode in Node_Editor.editor.nodeCanvas.nodes)
                {
                    Node_Editor.editor.RecalculateFrom(editorNode);
                }

                node.OnDelete();
            }

            break;
        }
    }
示例#2
0
 private void ShowChoices(HashSet <string> flag_set)
 {
     if (choice_node.answers.Count > 0)
     {
         valid_choices = new List <int>();
         var new_choices = new List <string>();
         choice_responses = new List <string>();
         for (int i = 0; i < choice_node.answers.Count; i++)
         {
             Port port = choice_node.GetPort($"answers[{i}]");
             if (port.IsConnected && port.ConnectedPorts[0].node is InteractionNode)
             {
                 if ((port.ConnectedPorts[0].node as InteractionNode).FlagsMeetRequirements(flag_set))
                 {
                     valid_choices.Add(i);
                     var answer = choice_node.answers[i];
                     new_choices.Add(answer.list_text);
                     if (answer.unique_preview)
                     {
                         choice_responses.Add(answer.preview);
                     }
                     else if (answer.show_preview && port.ConnectedPorts[0].node is DialogueNode)
                     {
                         choice_responses.Add((port.ConnectedPorts[0].node as DialogueNode).Dialogue);
                     }
                     else
                     {
                         choice_responses.Add(null);
                     }
                 }
             }
             else
             {
                 valid_choices.Add(i);
                 var answer = choice_node.answers[i];
                 new_choices.Add(answer.list_text);
                 if (answer.show_preview)
                 {
                     choice_responses.Add(answer.preview);
                 }
                 else
                 {
                     choice_responses.Add(null);
                 }
             }
         }
         if (valid_choices.Count > 0)
         {
             ChoicePanel.visible = true;
             UpdateChoices(new_choices);
             current_choice = 0;
             ScrollAndShowChoice();
             return;
         }
     }
     ChoicePanel.visible = false;
     choice_node         = null;
 }
示例#3
0
 public void Show(DialogueNode node, HashSet <string> flag_set)
 {
     dialogue_node = node;
     ShowDialogue();
     if (node is DialogueChoiceNode)
     {
         choice_node = node as DialogueChoiceNode;
         ShowChoices(flag_set);
     }
 }
示例#4
0
 public void Hide()
 {
     DialoguePanel.visible     = false;
     PortraitContainer.visible = false;
     NameLabel.visible         = false;
     ChoicePanel.visible       = false;
     ChoiceLabel.visible       = false;
     UpdateChoices(new string[0]);
     dialogue_node = null;
     choice_node   = null;
 }
示例#5
0
 private void ShowChoices(FlagSet flag_set)
 {
     if (choice_node.answers.Count > 0)
     {
         var choices = new List <ListController <int> .ListElement>();
         for (int i = 0; i < choice_node.answers.Count; i++)
         {
             Port port   = choice_node.GetPort($"answers[{i}]");
             var  answer = choice_node.answers[i];
             if (port.IsConnected && port.ConnectedPorts[0].node is InteractionNode)
             {
                 if ((port.ConnectedPorts[0].node as InteractionNode).FlagsMeetRequirements(flag_set))
                 {
                     var choice = new ListController <int> .ListElement()
                     {
                         text      = answer.list_text,
                         value     = i,
                         choosable = true,
                     };
                     if (answer.unique_preview)
                     {
                         choice.description = answer.preview;
                     }
                     else if (answer.show_preview && port.ConnectedPorts[0].node is DialogueNode)
                     {
                         choice.description = (port.ConnectedPorts[0].node as DialogueNode).Dialogue;
                     }
                     else
                     {
                         choice.description = null;
                     }
                     choices.Add(choice);
                 }
             }
             else
             {
                 choices.Add(new ListController <int> .ListElement()
                 {
                     text        = answer.list_text,
                     description = answer.show_preview || answer.unique_preview ? answer.preview : null,
                     choosable   = true,
                     value       = i
                 });
             }
         }
         if (choices.Count > 0)
         {
             this.choice_controller.ShowList(choices);
             return;
         }
     }
     choice_node = null;
 }
示例#6
0
    public void Hide()
    {
        DialogueRender.enabled = false;

        // Hide visible information
        DialoguePanel.visible           = false;
        PortraitContainer.style.display = DisplayStyle.None;
        NameLabel.visible = false;
        this.choice_controller.Hide();
        this.recipe_controller.Hide();

        // Clear dialogue node state
        dialogue_node = null;
        choice_node   = null;
        recipe_node   = null;
    }
示例#7
0
    public void Show(DialogueNode node, Inventory inventory, FlagSet flag_set)
    {
        DialogueRender.enabled = true;

        dialogue_node  = node;
        this.inventory = inventory;
        ShowDialogue();
        this.do_confirm = false;
        if (node is DialogueChoiceNode)
        {
            choice_node = node as DialogueChoiceNode;
            ShowChoices(flag_set);
        }
        if (node is MakeRecipeNode)
        {
            recipe_node = node as MakeRecipeNode;
            ShowRecipes(inventory);
        }
    }
    /// <summary>
    /// Creates a new Dialogue Choice Node.
    /// </summary>
    public static void Create(Rect NodeRect, int choiceStateNumber)
    {
        DialogueChoiceNode node = ScriptableObject.CreateInstance <DialogueChoiceNode>();

        node.name                = "Choice State " + choiceStateNumber;
        node.rect                = NodeRect;
        node.originState         = -1; // I just chose -1. I don't think this matters. Will need to enforce that this state has an input though.
        node.state               = -2; // values <= -2 are choice states.
        node.numberOfTransitions = 0;
        node.isStartState        = false;
        node.expanded            = true;

        // Instantiate 9 outputs for the choice selection
        for (int i = 0; i < 9; i++)
        {
            NodeOutput.Create(node, "Dialogue Option " + (i + 1).ToString(), typeof(int));
        }

        // Create input for previous state
        NodeInput.Create(node, "Previous Dialogue State", typeof(int));

        node.Init();
    }
    /// <summary>
    /// Parses the data from the FSM assets that have been created in the Dialogue Creator and creates
    /// DialogueFSM objects on the appropriate characters in the game.
    /// </summary>
    private void LoadDialogue()
    {
        Object[] fsms = Resources.LoadAll("Dialogue", typeof(DialogueNodeCanvas));         // load fsm's from Resources/Dialogue folder

        // Iterate over every dialogue FSM that is saved.
        for (int i = 0; i < fsms.Length; i++)
        {
            DialogueNodeCanvas fsm = (DialogueNodeCanvas)fsms[i];             // grab each Node Canvas Object, which holds all our states

            DialogueFSM newFSM = new DialogueFSM(fsm.numberOfTimesConversationCanHappen, fsm.probabilityOfOccurrence);

            string initiator = null;             // the character who initiates this fsm

            // Iterate over every node in the FSM
            foreach (Node node in fsm.nodes)
            {
                if (node.GetType() == typeof(DialogueNode))
                {
                    DialogueNode newNode = (DialogueNode)node;

                    if (newNode.isStartState)
                    {
                        // Assign the initiator to the player if the player initiation toggle has been set on the start state. Otherwise, set it to the npc's name.
                        initiator = newNode.playerInitiatesConversation ? GameObject.FindWithTag("Player").name : newNode.speakers[0].name;

                        if (!characters.ContainsKey(initiator))
                        {
                            return;                             // stop loading if the initiator doesn't exist.
                        }
                    }

                    // Separate the style sprite into a body and tail. Note that the body and tail sprites MUST have the same prefix to their names as the original style. For instance, if the original style is "NormalDialogue", then the body and tail must be "NormalDialogueBody" and "NormalDialogueTail".
                    List <Sprite> newBodyStyles = new List <Sprite>();
                    List <Sprite> newTailStyles = new List <Sprite>();

                    for (int j = 0; j < newNode.styles.Count; j++)
                    {
                        newBodyStyles.Add(Resources.Load <Sprite>("Sprites/Dialogue/" + newNode.styles[j].name + "Body"));
                        newTailStyles.Add(Resources.Load <Sprite>("Sprites/Dialogue/" + newNode.styles[j].name + "Tail"));
                    }

                    // Parse data from dialogue node. Note that we are using our characters hash table for the speaker. This might not be necessary, but this should ensure that we are grabbing the instances of the gameobjects that are IN the scene instead of in the editor. I'm not sure if there's a distinction between prefabs in the editor and instantiated prefabs in the scene.
                    List <GameObject> newSpeakerList = new List <GameObject>();

                    bool charactersExist = true;

                    foreach (GameObject character in newNode.speakers)
                    {
                        if (!characters.ContainsKey(character.name))
                        {
                            charactersExist = false;
                            break;
                        }

                        newSpeakerList.Add(characters[character.name]);
                        newFSM.AddParticipant(characters[character.name]);
                    }

                    // If the character is not in the scene, stop loading this FSM.
                    if (!charactersExist)
                    {
                        break;
                    }

                    newFSM.AddState(newSpeakerList, newNode.dialogues, newNode.description, newBodyStyles, newTailStyles, newNode.state);

                    // Add Transitions for non-choice nodes.
                    if (newNode.Outputs[0].connections.Count > 0)
                    {
                        // Ignore states that transition to a choice state
                        if (newNode.Outputs[0].connections[0].body.state > -2)
                        {
                            // Note that all states fire on the 0 input. However, choices fire on 1 - 9 inputs. Proceeding through dialogue always occurs using 0 input.
                            newFSM.AddTransition(newNode.state, newNode.Outputs[0].connections[0].body.state, 0);
                        }
                    }
                    else if (newNode.returnsToChoiceNode)
                    {
                        // Iterate over the previous choice node and create transitions for this state to go to any of the choice options on the previous choice node.
                        for (int j = 0; j < newNode.previousChoiceNode.Outputs.Count; j++)
                        {
                            if (newNode.previousChoiceNode.Outputs[j].connections.Count == 0)
                            {
                                continue;
                            }

                            newFSM.AddTransition(newNode.state, newNode.previousChoiceNode.Outputs[j].connections[0].body.state, j + 1);
                        }
                    }
                    else
                    {
                        // handle the final state case. A dialogue node with no output connection must be a final state so it transitions to -1.
                        newFSM.AddTransition(newNode.state, -1, 0);
                    }
                }
                else if (node.GetType() == typeof(DialogueChoiceNode))
                {
                    DialogueChoiceNode newNode = (DialogueChoiceNode)node;

                    // Parse transitions from choice node. Origin state is what leads us to the choice node. It is the state, all dialogue choices come from.
                    for (int j = 0; j < newNode.Outputs.Count; j++)
                    {
                        if (newNode.Outputs[j].connections.Count > 0)
                        {
                            newFSM.AddTransition(newNode.originState, newNode.Outputs[j].connections[0].body.state, j + 1);
                        }
                    }
                }
            }

            // Parse required quests
            List <string> tempRequiredStates = new List <string>();

            foreach (GameStateName stateName in fsm.requiredGameStates)
            {
                tempRequiredStates.Add(stateName.eventName);
            }

            newFSM.AddRequiredGameStates(tempRequiredStates);

            characters[initiator].GetComponent <DialogueManager>().AddFSM(newFSM);            // add the new FSM to the character's FSM list.
        }

        Destroy(gameObject);         // destroy the game object after it's finished loading all dialogue
    }