/// <summary> /// Updates dialog for all speakers that are attached to dialog maps. /// </summary> void UpdateAllSpeakers() { for (int i = 0; i < dialogDatabase.maps.Count; i++) { DialogMap map = dialogDatabase.maps [i]; // only look at maps with speakers assigned if (map.speakerObject != null) { // early out if there's no 'Dialog' component on the assigned gameObject if (map.speakerObject.GetComponent <Dialog> () == null) { return; } Dialog speakerDialog = map.speakerObject.GetComponent <Dialog> (); // this speaker needs to be updated if (!speakerDialog.CompareToDialogMap(map)) { speakerDialog.UpdateDialog(map); } } } }
/// <summary> /// Makes sure only one node can be searching for a child at a time. /// </summary> /// <param name="node">Node.</param> void LookForChild(Node node) { // see if this node is already searching for a child if (node.wantsChild) { node.wantsChild = false; return; } DialogMap map = dialogDatabase.maps [selectedMap]; for (int i = 0; i < map.nodes.Count; i++) { Node n = map.nodes [i]; // clear any other nodes searching for children if (n.wantsChild) { n.wantsChild = false; } } // tag this node as searching for child node.wantsChild = true; }
/// <summary> /// Draws the node and manages its layout. /// </summary> /// <param name="id">Index of the node in the dialog maps list of nodes.</param> void DrawNode(int id) { DialogMap map = dialogDatabase.maps [selectedMap]; Node node = map.nodes [id]; // on a left-click, select this node if (Event.current.button == 0 && Event.current.type == EventType.mouseUp) { selectedNode = id; } // place on grid node.rect.x -= node.rect.x % mapGridSpacing; node.rect.y -= node.rect.y % mapGridSpacing; // keep node in screen node.rect.x = Mathf.Clamp(node.rect.x, nodeBackgroundScrollPosition.x, nodeBackgroundScrollPosition.x + nodeBackgroundDisplay.x - nodeWidth - scrollThickness); int currentNodeHeight = node.isExpanded ? nodeExpandedHeight : nodeCollapsedHeight; node.rect.y = Mathf.Clamp(node.rect.y, nodeBackgroundScrollPosition.y, nodeBackgroundScrollPosition.y + nodeBackgroundDisplay.y - currentNodeHeight - scrollThickness); // buttons handling connections to parents DrawNodeTopControls(node, id); // show the fullLine, or shortLine if available DrawNodeDialogLine(node); // buttons handling connections to children and collapsing or deleting the node DrawNodeBottomControls(node, id); GUI.DragWindow(); }
/// <summary> /// Show the dialog maps as boxes stacked in a vertical scrolling window. /// </summary> void ShowDialogMapStack() { GUIStyle labelStyle = new GUIStyle(EditorStyles.label); GUILayout.BeginVertical("helpbox"); // scrolling window dialogMapStackScrollPosition = GUILayout.BeginScrollView(dialogMapStackScrollPosition, GUILayout.Width(dialogMapStackDisplay.x), GUILayout.Height(dialogMapStackDisplay.y)); for (int i = 0; i < dialogDatabase.maps.Count; i++) { DialogMap map = dialogDatabase.maps [i]; if (selectedMap == i) { labelStyle.fontStyle = FontStyle.Bold; } else if (searchedMap != "" && map.speakerDisplayName.ToUpper().Contains(searchedMap.ToUpper())) { labelStyle.normal.textColor = Color.blue; } ShowDialogMap(i, labelStyle); labelStyle = new GUIStyle(EditorStyles.label); // reset the label style for the next loop } GUILayout.EndVertical(); GUILayout.EndArea(); }
/// <summary> /// Show the dialog map detail panel. /// </summary> void ShowDialogMapDetailPanel(DialogMap map) { // early out if (dialogDatabase.maps.Count == 0) { return; } int nameWidth = 290; int indexWidth = 90; int refIdWidth = 100; int nodesWidth = 90; GUIStyle nameStyle = new GUIStyle(EditorStyles.label); GUIStyle indexStyle = new GUIStyle(EditorStyles.miniLabel); GUIStyle refStyle = new GUIStyle(EditorStyles.miniLabel); GUIStyle nodeStyle = new GUIStyle(EditorStyles.miniLabel); nameStyle.fontStyle = FontStyle.Bold; indexStyle.fontStyle = FontStyle.Bold; refStyle.normal.textColor = Color.red; refStyle.fontStyle = FontStyle.Bold; nodeStyle.normal.textColor = Color.blue; nodeStyle.fontStyle = FontStyle.Bold; GUILayout.BeginVertical("helpbox"); // speakerDisplayName GUILayout.Label(map.speakerDisplayName, nameStyle, GUILayout.Width(nameWidth)); // index, RefId, and total nodes GUILayout.BeginHorizontal(); GUILayout.Label("Index: " + selectedMap.ToString(), indexStyle, GUILayout.Width(indexWidth)); GUILayout.Label("RefId: " + map.RefId.ToString(), refStyle, GUILayout.Width(refIdWidth)); GUILayout.Label("Nodes: " + map.nodes.Count.ToString(), nodeStyle, GUILayout.Width(nodesWidth)); GUILayout.EndHorizontal(); GUILayout.BeginHorizontal(); map.speakerObject = (GameObject)EditorGUILayout.ObjectField(map.speakerObject, typeof(GameObject), false); if (map.speakerObject != null) { string updateButtonText = "Updated"; GUIStyle buttonStyle = new GUIStyle(EditorStyles.miniButton); Dialog speakerDialog = PrepareUpdateButton(map, ref updateButtonText, ref buttonStyle); if (GUILayout.Button(updateButtonText, buttonStyle)) { if (speakerDialog != null) { speakerDialog.UpdateDialog(map); } } } GUILayout.EndHorizontal(); GUILayout.EndVertical(); }
/// <summary> /// Initializes a new instance of the <see cref="WanzerWeave.DialogEditor.Node"/> class. /// </summary> /// <param name="map">The dialog map being edited.</param> public Node(DialogMap map) { // reset the nodeRefId if all nodes for this dialog map have been deleted if (map.nodes.Count == 0) { map.ResetNodeRefId(); } // assign a NodeRefId to this nodes RefId this.RefId = map.GetNodeRefId(); }
/// <summary> /// Shows the scrolling prerequisites panel, each child will have a list of prerequisites that will translate into /// a list of coroutines to run in the dialog manager. /// </summary> /// <param name="node">Node being described.</param> void ShowChildPrereqsPanel(Node node) { GUIStyle labelStyle = new GUIStyle(EditorStyles.label); GUILayout.BeginVertical("helpbox"); // scrolling window childPrereqsStackScrollPosition = GUILayout.BeginScrollView(childPrereqsStackScrollPosition, GUILayout.Width(childPrereqsStackDisplay.x), GUILayout.Height(childPrereqsStackDisplay.y)); // this node has prereqs for its children if (node.prereqs.Count > 0) { // go through the list of coroutines for each child for (int i = 0; i < node.prereqs.Count; i++) { // keep all of the prerequisites for a single child in a box GUILayout.BeginVertical("box"); GUILayout.EndVertical(); DialogMap map = dialogDatabase.maps [i]; if (selectedMap == i) { labelStyle.fontStyle = FontStyle.Bold; } else if (searchedMap != "" && map.speakerDisplayName.ToUpper().Contains(searchedMap.ToUpper())) { labelStyle.normal.textColor = Color.blue; } ShowDialogMap(i, labelStyle); labelStyle = new GUIStyle(EditorStyles.label); // reset the label style for the next loop } } // this node has no children else { GUILayout.Label("No children!"); } GUILayout.EndVertical(); GUILayout.EndArea(); }
/// <summary> /// Finds the node index from reference identifier. /// </summary> /// <returns>The node index from reference identifier.</returns> /// <param name="refId">Reference identifier.</param> int FindNodeIndexFromRefId(ushort refId) { DialogMap map = dialogDatabase.maps [selectedMap]; for (int i = 0; i < map.nodes.Count; i++) { Node n = map.nodes [i]; if (n.RefId == refId) { return(i); } } Debug.Log("FindNodeIndexFromRefId should never be unable to find the node!"); return(-1); }
/// <summary> /// Adds a new speaker to dialog.asset with the name from the input field. /// </summary> void AddDialogMap() { DialogMap newMap = new DialogMap(dialogDatabase); if (speakerDisplayName == "") { newMap.speakerDisplayName = "NO NAME"; } else { newMap.speakerDisplayName = speakerDisplayName; } dialogDatabase.maps.Add(newMap); selectedMap = dialogDatabase.maps.Count - 1; }
/// <summary> /// Get the reference id of the node that is currently searching for a child. /// </summary> /// <returns>The reference id of the node currently searching for a child.</returns> ushort GetParentRefId() { DialogMap map = dialogDatabase.maps [selectedMap]; for (int i = 0; i < map.nodes.Count; i++) { Node n = map.nodes [i]; if (n.wantsChild) { return(n.RefId); } } // no one wants a child, return a null ushort Debug.Log("No one is searching for a child!"); return(new ushort()); }
/// <summary> /// Finds the nodes index based on the reference id. /// </summary> /// <returns>The nodes index based on the reference id.</returns> /// <param name="refId">The reference id of the node being searched for.</param> Node FindNodeFromRefId(ushort refId) { DialogMap map = dialogDatabase.maps [selectedMap]; for (int i = 0; i < map.nodes.Count; i++) { Node n = map.nodes [i]; if (n.RefId == refId) { return(n); } } // node not found, return null Debug.Log("Reference Id not found!"); return(null); }
/// <summary> /// Draws the node button that connects this node to a child, the collapse/expand button, and the delete button. /// </summary> /// <param name="node">Node being drawn.</param> /// <param name="id">Index of the node being drawn from the dialog maps list of nodes.</param> void DrawNodeBottomControls(Node node, int id) { DialogMap map = dialogDatabase.maps [selectedMap]; int button = 20; int middleX = (nodeWidth / 2) - (button / 2) + 2; int toRight = middleX - (button * 3 - 13); string expandCollapseDisplay = node.isExpanded ? "-" : "="; GUIStyle downArrow = new GUIStyle(EditorStyles.miniButton); downArrow.normal.textColor = node.wantsChild ? Color.magenta : Color.black; downArrow.fontStyle = node.wantsChild ? FontStyle.Bold : FontStyle.Normal; GUILayout.BeginHorizontal(); GUILayout.Space(middleX); if (GUILayout.Button("v", downArrow, GUILayout.Width(button))) { LookForChild(node); } GUILayout.Space(toRight); // expand or collapse node accordingly if (GUILayout.Button(expandCollapseDisplay, EditorStyles.miniButton, GUILayout.Width(button))) { if (node.isExpanded) { node.CollapseNode(nodeCollapsedHeight); } else if (!node.isExpanded) { node.ExpandNode(nodeExpandedHeight); } } if (GUILayout.Button("X", EditorStyles.miniButton, GUILayout.Width(button))) { map.RemoveNodeAtIndex(id); selectedNode = Mathf.Clamp(selectedNode, 0, map.nodes.Count - 1); } GUILayout.EndHorizontal(); }
/// <summary> /// Prepares the update button. /// </summary> /// <returns>The Dialog component of the gameObject attached to the speaker.</returns> /// <param name="map">The dialog map being Compareed.</param> /// <param name="updateButtonText">Update button text.</param> /// <param name="buttonStyle">Button style.</param> Dialog PrepareUpdateButton(DialogMap map, ref string updateButtonText, ref GUIStyle buttonStyle) { // if there's no 'HasDialog' component on the assigned gameObject if (map.speakerObject.GetComponent <Dialog> () == null) { updateButtonText = "No Dialog Component!"; buttonStyle.normal.textColor = Color.red; return(null); } // the component is present, compare them Dialog speakerDialog = map.speakerObject.GetComponent <Dialog> (); if (!speakerDialog.CompareToDialogMap(map)) { buttonStyle.normal.textColor = Color.red; updateButtonText = "Update!"; } return(speakerDialog); }
/// <summary> /// Shows the nodes in a manageable display, either a map or a list. /// </summary> void ShowNodeDisplay() { // early out if (dialogDatabase.maps.Count == 0) { return; } int displayButtonWidth = 150; int addNodeButtonWidth = 80; int updateAllButtonWidth = 250; int nodeX = (int)((nodeBackgroundScrollPosition.x + 140) - (nodeBackgroundScrollPosition.x % mapGridSpacing)); int nodeY = (int)((nodeBackgroundScrollPosition.y + 5) - (nodeBackgroundScrollPosition.y % mapGridSpacing)); Rect newNodeLocation = new Rect(nodeX, nodeY, nodeWidth, nodeExpandedHeight); string changeDisplayTo = FindNodeDisplayType(); GUIStyle updateAllStyle = new GUIStyle(EditorStyles.miniButton); string updateAllText = PrepareUpdateAllButton(ref updateAllStyle); DialogMap map = dialogDatabase.maps [selectedMap]; GUILayout.BeginHorizontal("helpbox"); // node display controls if (GUILayout.Button(changeDisplayTo, EditorStyles.miniButton, GUILayout.Width(displayButtonWidth))) { ChangeNodeDisplayType(); } if (GUILayout.Button("Add Node", EditorStyles.miniButton, GUILayout.Width(addNodeButtonWidth))) { map.AddNode(newNodeLocation); } if (GUILayout.Button(updateAllText, updateAllStyle, GUILayout.Width(updateAllButtonWidth))) { UpdateAllSpeakers(); } GUILayout.EndHorizontal(); // scrolling window nodeBackgroundScrollPosition = GUILayout.BeginScrollView(nodeBackgroundScrollPosition, "textfield", GUILayout.Width(nodeBackgroundDisplay.x), GUILayout.Height(nodeBackgroundDisplay.y)); // the actual dark background that forces the scrolling window to scroll all the time GUI.color = Color.black; GUILayout.Label("", EditorStyles.helpBox, GUILayout.Width(nodeBackgroundDimensions.x), GUILayout.Height(nodeBackgroundDimensions.y)); GUI.color = defaultGUIColor; // display the nodes in the appropriate manner switch (nodeDisplayMethod) { case NodeDisplayMethod.Map: ShowNodeMapDisplay(); break; case NodeDisplayMethod.List: Debug.Log("Show List Display"); break; } GUILayout.EndScrollView(); }
/// <summary> /// Shows the basic information about the node - speaker name, index : refId, fullLine and shortLine contents, /// the Set Start Node button and toggle for controlling whether the start node fullLine is displayed, and the /// number of parents and/or children and their indexes. /// </summary> /// <param name="node">Node being described.</param> void ShowBasicNodeDetails(Node node) { DialogMap map = dialogDatabase.maps [selectedMap]; int speakerDisplayNameWidth = 230; string idText = selectedNode.ToString() + ": <color=red>" + node.RefId.ToString() + "</color>"; int idWidth = 60; int parentsWidth = 70; int childrenWidth = 70; Vector2 fullLineDimensions = new Vector2(292, 100); Vector2 shortLineDimensions = new Vector2(292, 20); GUIStyle idStyle = new GUIStyle(EditorStyles.label); idStyle.fontStyle = FontStyle.Bold; idStyle.alignment = TextAnchor.MiddleRight; idStyle.richText = true; GUIStyle nameTextStyle = new GUIStyle(EditorStyles.label); nameTextStyle.fontStyle = FontStyle.Bold; GUIStyle boldMiniStyle = new GUIStyle(EditorStyles.miniLabel); boldMiniStyle.fontStyle = FontStyle.Bold; GUIStyle relationshipStyle = new GUIStyle(EditorStyles.miniLabel); relationshipStyle.richText = true; GUIStyle lineStyle = new GUIStyle(EditorStyles.textArea); lineStyle.fontSize = 10; GUIStyle toggleStyle = new GUIStyle(EditorStyles.toggle); toggleStyle.fontSize = 10; toggleStyle.fontStyle = FontStyle.Bold; GUILayout.BeginVertical("helpbox"); GUILayout.BeginHorizontal(); GUILayout.Label(map.speakerDisplayName, nameTextStyle, GUILayout.Width(speakerDisplayNameWidth)); GUILayout.Label(idText, idStyle, GUILayout.Width(idWidth)); GUILayout.EndHorizontal(); GUILayout.Space(10); GUILayout.BeginHorizontal(); GUILayout.Label("Full Line:", boldMiniStyle); if (map.startNode > map.nodes.Count - 1) { toggleStyle.normal.textColor = Color.red; } map.displayStartNode = GUILayout.Toggle(map.displayStartNode, "Display Start Node: " + map.startNode.ToString(), toggleStyle); toggleStyle.normal.textColor = Color.black; if (GUILayout.Button("Set Start Node", EditorStyles.miniButton, GUILayout.ExpandWidth(false))) { map.startNode = FindNodeIndexFromRefId(node.RefId); } GUILayout.EndHorizontal(); node.fullLine = GUILayout.TextArea(node.fullLine, lineStyle, GUILayout.Width(fullLineDimensions.x), GUILayout.Height(fullLineDimensions.y)); GUILayout.Label("Short Line:", boldMiniStyle); node.shortLine = GUILayout.TextField(node.shortLine, 100, GUILayout.Width(shortLineDimensions.x), GUILayout.Height(shortLineDimensions.y)); GUILayout.Space(5); GUILayout.BeginHorizontal(); GUILayout.Label("<b>Parents:</b> " + node.parents.Count, relationshipStyle, GUILayout.Width(parentsWidth)); GUILayout.Space(20); if (node.parents.Count > 0) { string displayText = "Indexes: "; for (int i = 0; i < node.parents.Count; i++) { ushort refId = node.parents [i]; displayText += FindNodeIndexFromRefId(refId).ToString(); if (i != node.parents.Count - 1) { displayText += ", "; } } GUILayout.Label(displayText, relationshipStyle); } GUILayout.EndHorizontal(); GUILayout.BeginHorizontal(); GUILayout.Label("<b>Children:</b> " + node.children.Count, relationshipStyle, GUILayout.Width(childrenWidth)); GUILayout.Space(20); if (node.children.Count > 0) { string displayText = "Indexes: "; for (int i = 0; i < node.children.Count; i++) { ushort refId = node.children [i]; displayText += FindNodeIndexFromRefId(refId).ToString(); if (i != node.children.Count - 1) { displayText += ", "; } } GUILayout.Label(displayText, relationshipStyle); } GUILayout.EndHorizontal(); GUILayout.EndVertical(); }
/// <summary> /// Called every frame the editor is focused. /// </summary> void OnGUI() { // no dialog.asset loaded if (dialogDatabase == null) { if (GUILayout.Button("New", EditorStyles.miniButton)) { CreateNewDialogDatabase(); } if (GUILayout.Button("Open", EditorStyles.miniButton)) { OpenDialogDatabase(); } } // dialog.asset loaded if (dialogDatabase != null) { // no speakers present if (dialogDatabase.maps.Count == 0) { ShowAddDialogMapPanel(); } // dialog maps are present if (dialogDatabase.maps.Count > 0) { selectedMap = Mathf.Clamp(selectedMap, 0, dialogDatabase.maps.Count - 1); DialogMap map = dialogDatabase.maps [selectedMap]; // column layout GUILayout.BeginHorizontal(); GUILayout.BeginArea(leftColumnRect); // ============================================= LEFT COLUMN ShowAddDialogMapPanel(); ShowDialogMapStack(); ShowSearchPanel(); ShowDialogMapDetailPanel(map); GUILayout.EndArea(); // ============================================= END LEFT COLUMN GUILayout.BeginArea(centerColumnRect); // ============================================= CENTER COLUMN ShowNodeDisplay(); GUILayout.EndArea(); // ============================================= END CENTER COLUMN if (map.nodes.Count > 0) { selectedNode = Mathf.Clamp(selectedNode, 0, map.nodes.Count - 1); Node node = map.nodes [selectedNode]; GUILayout.BeginArea(rightColumnRect); // ============================================= RIGHT COLUMN ShowBasicNodeDetails(node); ShowChildPrereqsPanel(node); GUILayout.EndArea(); // ============================================= END RIGHT COLUMN } GUILayout.EndHorizontal(); } } EditorUtility.SetDirty(dialogDatabase); }