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; } } }
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); }
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); }
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); }
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); }