Example #1
0
        private void getRootNode(ref DialogueRoot root)
        {
            // NOTE: It's always the last matching root in an array that will be chosen as starting point!

            root = dialogue.rootNodes[0];
            for (int i = 0; i < dialogue.rootNodes.Length; ++i)
            {
                DialogueRoot curRoot = dialogue.rootNodes[i];
                // Ignore roots that (for whatever reason) don't have a node assigned:
                if (curRoot.node == null)
                {
                    continue;
                }

                // Either chose a root with zero conditions:
                if (string.IsNullOrEmpty(curRoot.conditions.keyword))
                {
                    root = curRoot;
                    continue;
                }
                // Or pick a root where all conditions have been cleared:
                else if (trigger != null && trigger.checkDialogueCondition(ref curRoot.conditions))
                {
                    root = curRoot;
                    continue;
                }
            }
        }
Example #2
0
        public bool startDialogue(IDialogueTrigger inTrigger, IBindingCore inBindingCore)
        {
            // NOTE: Returns false if the conditions for none of the root nodes were met!

            if (dialogue == null)
            {
                return(false);
            }
            if (inBindingCore == null)
            {
                Debug.LogWarning("[DialogueController] Error! Null binding core may result in dialogue bindings not being resolved!");
            }

            trigger     = inTrigger;
            bindingCore = inBindingCore;

            // Reset all flags, counters and references:
            reset();

            // Execute start binding right away:
            executeBinding(ref dialogue.startBinding);

            DialogueRoot root = DialogueRoot.Blank;

            getRootNode(ref root);

            bool started = selectNode(root.node);

            // Notify the dialogue trigger of the start of a new dialogue:
            if (started && trigger != null)
            {
                trigger.notifyDialogueEvent(DialogueEvent.Start);
            }
            return(started);
        }
Example #3
0
        public bool createNewNode(Dialogue dialogue, ref List <Node> nodes)
        {
            // Make sure the dialogue asset is non-null:
            if (dialogue == null)
            {
                return(false);
            }
            // Update node list: (initialize list and load existing nodes from dialogue asset)
            if (nodes == null || nodes.Count == 0)
            {
                createNodeList(dialogue, ref nodes);
            }

            // Create a new node asset in dialogue:
            DialogueNode newDNode = DialogueEditorHelper.createNewNode(dialogue);
            // Create an editor node representation:
            Node newNode = Node.Blank;

            newNode.node = newDNode;

            // Set newly created node as root node if no root has been assigned yet:
            if (dialogue.rootNodes == null || dialogue.rootNodes.Length == 0)
            {
                // Create new root node in dialogue with no conditions:
                DialogueConditions newRootConds = DialogueConditions.None;
                DialogueRoot       newRoot      = new DialogueRoot()
                {
                    node = newDNode, conditions = newRootConds
                };
                dialogue.rootNodes = new DialogueRoot[1] {
                    newRoot
                };
                newNode.rootId = 0;

                // Save changes to asset:
                DialogueEditorHelper.saveDialogueAsset(dialogue);
            }

            // Center the new node on screen:
            newNode.rect.center = new Vector2(Screen.width, Screen.height) * 0.5f + offset;

            // Add the new node representation to nodes list:
            nodes.Add(newNode);
            return(true);
        }
Example #4
0
        public bool selectResponse(int responseIndex)
        {
            // Make sure there currently is an active node:
            if (currentNode == null)
            {
                Debug.LogError("[DialogueController] Error! Unable to select response from null node! Aborting response.");
                return(false);
            }

            // Ignore response index and show next content item instead, if multiple contents exist for the current node:
            if (currentNode.content != null && currentNode.content.Length > 1 && currentContentIndex < currentNode.content.Length - 1)
            {
                // Increment content index:
                currentContentIndex++;

                // Execute any binding assigned to the new content:
                executeBinding(ref currentNode.content[currentContentIndex].eventBinding);

                // Notify the dialogue trigger that a next content will now be displayed:
                if (trigger != null)
                {
                    trigger.notifyDialogueEvent(DialogueEvent.ContentChanged);
                }

                return(true);
            }

            // Verify index and currently active selection:
            DialogueResponse[] responses = getCurrentResponses();
            if (responses == null || responseIndex < 0 || responseIndex >= responses.Length)
            {
                Debug.LogError("[DialogueController] Error! Invalid response index " + responseIndex + " selected! Aborting response.");
                return(false);
            }

            // If a followup node was provided, select it right away:
            DialogueResponse selected = responses[responseIndex];

            if (selected.nextNode != null)
            {
                // Notify the dialogue trigger that a response was selected:
                if (trigger != null)
                {
                    trigger.notifyDialogueEvent(DialogueEvent.PlayerResponse);
                }

                // Select followup node:
                return(selectNode(selected.nextNode));
            }

            // There was no followup node, so proceed according to the dialogue's behaviour mode instead:
            DialogueBehaviour behaviour = dialogue.behaviour;
            bool result = true;

            switch (behaviour.onNullResponse)
            {
            // End dialogue:
            case DialogueBehaviour.NullResponseAction.End:
                result = endDialogue();
                break;

            // Return to root node:
            case DialogueBehaviour.NullResponseAction.ReturnToRoot:
            {
                DialogueRoot root = DialogueRoot.Blank;
                getRootNode(ref root);
                result = selectNode(root.node);
            }
            break;

            // Refuse any further actions and just stay on the current node:
            case DialogueBehaviour.NullResponseAction.None:
                result = false;
                break;

            // Unidentified behaviour, throw an error. Though I can't even begin to imagine how you'd mess this one up:
            default:
                Debug.LogError("[DialogueController] Error! Unidentified NullResponse behaviour type: " + behaviour.onNullResponse.ToString());
                result = false;
                break;
            }

            return(result);
        }
Example #5
0
        public bool drawNodes(Dialogue asset, List <Node> inNodes, Vector2 inOffet)
        {
            if (asset == null || inNodes == null)
            {
                return(false);
            }

            offset = inOffet;

            bool changed = false;

            nodes = inNodes;

            Vector2 rootPos  = new Vector2(0, Screen.height * 0.5f);
            Rect    rootRect = new Rect(rootPos.x - offset.x - 39, rootPos.y - offset.y - 7, 38, 14);

            EditorGUI.DrawRect(new Rect(rootRect.x - 1, rootRect.y - 1, rootRect.width + 2, rootRect.height + 2), Color.black);
            EditorGUI.DrawRect(rootRect, new Color(0.75f, 0.75f, 0.75f));
            EditorGUI.LabelField(rootRect, "Root");

            if (nodes != null && nodes.Count != 0)
            {
                // Draw links between nodes first:
                for (int i = 0; i < nodes.Count; ++i)
                {
                    Node         node  = nodes[i];
                    DialogueNode dNode = node.node;

                    // Links from dialogue root:
                    if (node.rootId >= 0)
                    {
                        DialogueRoot root           = asset.rootNodes[node.rootId];
                        bool         rootConditions = !string.IsNullOrEmpty(root.conditions.keyword);
                        drawNodeLink(rootPos, node, i, 0, rootConditions);
                    }

                    // Links to response nodes:
                    if (dNode.responses != null)
                    {
                        for (int j = 0; j < dNode.responses.Length; ++j)
                        {
                            DialogueResponse resp    = dNode.responses[j];
                            Vector2          respPos = getResponsePosition(node, j);

                            // Draw short red lines to indicate a response is no linked to any node:
                            if (resp.nextNode == null)
                            {
                                respPos      -= offset;
                                Handles.color = Color.red;
                                Handles.DrawLine(respPos, respPos + Vector2.right * 32);
                                continue;
                            }

                            // Figure out the editor node representing the response's connected node asset:
                            Node targetNode = Node.Blank;
                            int  k          = 0;
                            for (k = 0; k < nodes.Count; ++k)
                            {
                                Node n = nodes[k];
                                if (n.node == resp.nextNode)
                                {
                                    targetNode = n;
                                    break;
                                }
                            }

                            // Draw link in a different color if conditions apply for the associated response:
                            bool hasConditions = !string.IsNullOrEmpty(resp.conditions.keyword);

                            // Draw a bezier curve starting at the response button and leading to the connected node:
                            drawNodeLink(respPos, targetNode, i, k, hasConditions);
                        }
                    }
                }

                // Draw the actual individual nodes:
                for (int i = 0; i < nodes.Count; ++i)
                {
                    Node node = nodes[i];
                    // If a node is null, mark it for later deletion:
                    if (node.node == null)
                    {
                        node.rootId = -1;
                        nodes[i]    = node;
                        continue;
                    }

                    bool isSelected = selected.node == node.node;
                    // Update drag&drop:
                    NodeAction actions = new NodeAction()
                    {
                        changed = false, selected = false, startDragDrop = false
                    };
                    if (isSelected && dragNDrop)
                    {
                        Vector2 mousePos = Event.current.mousePosition;
                        node.rect.x     = mousePos.x - 123 + offset.x;
                        node.rect.y     = mousePos.y - 5 + offset.y;
                        actions.changed = true;
                    }

                    // Round positions to whole numbers, 'cause without it the damn thing looks ugly as hell:
                    node.rect.x = Mathf.Round(node.rect.x);
                    node.rect.y = Mathf.Round(node.rect.y);

                    // Draw the node on screen:
                    actions = drawNode(ref node, isSelected, i);
                    // Raise the dirty flag if the node has been changed:
                    if (actions.changed)
                    {
                        nodes[i] = node;
                        changed  = true;
                    }
                    // Select the node if a related action was performed:
                    if (actions.selected)
                    {
                        setSelection(node);
                    }
                    // Start drag&drop of the node if a related action was performed:
                    if (actions.startDragDrop)
                    {
                        toggleDragNDrop();
                    }
                }

                // Draw response dropdown overlay:
                if (selectedResponseDropdown && selectedResponse >= 0 && selectedResponse < selected.node.responses.Length)
                {
                    Node             respNode  = selected;
                    DialogueNode     respDNode = respNode.node;
                    DialogueResponse resp      = respDNode.responses[selectedResponse];

                    const float w = 160;
                    const float h = 94;

                    Rect  respRect = respNode.rect;
                    float respPosY = Mathf.Round(respRect.y + 33 + (-respDNode.responses.Length * .5f + selectedResponse) * 17);
                    respRect = new Rect(respRect.x - offset.x + 138, respPosY - offset.y, w + 2, h + 2);

                    GUI.BeginGroup(respRect);

                    EditorGUI.DrawRect(new Rect(0, 0, w + 2, h + 2), Color.black);
                    EditorGUI.DrawRect(new Rect(1, 1, w, h), new Color(0.75f, 0.75f, 0.75f));

                    EditorGUI.LabelField(new Rect(2, 2, w, 16), string.Format("Edit response {0}:", selectedResponse));

                    // Button for creating a new node linked to this response:
                    if (GUI.Button(new Rect(2, 20, 78, 16), "New Node"))
                    {
                        if (createNewNode(asset, ref nodes))
                        {
                            int newNodeId = nodes.Count - 1;
                            if (createNodeLink(selected, selectedResponse, newNodeId))
                            {
                                //Debug.Log("Creating new node connected to selected node's response " + selectedResponse);
                                setSelection(nodes[newNodeId]);
                            }
                        }
                    }

                    // Button for removing the currently set link:
                    bool uiShowClearLink = selected.node.responses != null &&
                                           selectedResponse >= 0 &&
                                           selectedResponse < selected.node.responses.Length &&
                                           selected.node.responses[selectedResponse].nextNode == null;
                    EditorGUI.BeginDisabledGroup(uiShowClearLink);
                    if (GUI.Button(new Rect(82, 20, 78, 16), "Clear Link"))
                    {
                        //Debug.Log("Resetting response " + selectedResponse + " in selected node.");
                        createNodeLink(respNode, selectedResponse, -1);
                    }
                    EditorGUI.EndDisabledGroup();

                    // Button and input field for linking to a specific node using its displayed node ID:
                    if (GUI.Button(new Rect(2, 38, 128, 16), "Link to ID"))
                    {
                        createNodeLink(respNode, selectedResponse, responseTargetNodeId);
                        //Debug.Log("Connecting selected node's response " + selectedResponse + " to node " + responseTargetNodeId);
                    }
                    responseTargetNodeId = EditorGUI.DelayedIntField(new Rect(131, 38, 29, 16), responseTargetNodeId);

                    bool prevChanged = GUI.changed;
                    GUI.changed = false;

                    EditorGUI.LabelField(new Rect(2, 60, 34, 16), "Text");
                    resp.responseText = EditorGUI.DelayedTextField(new Rect(36, 60, w - 36, 16), resp.responseText);

                    EditorGUI.LabelField(new Rect(2, 78, 34, 16), "Cond");
                    resp.conditions.keyword = EditorGUI.DelayedTextField(new Rect(36, 78, w - 36, 16), resp.conditions.keyword);

                    if (GUI.changed)
                    {
                        EditorUtility.SetDirty(asset);
                    }
                    GUI.changed = GUI.changed || prevChanged;

                    GUI.EndGroup();
                }
            }

            return(changed);
        }