Exemplo n.º 1
0
    /// <summary>
    /// Turns a JSON-formatted Twine node into a GameObject with all the relevant data in a TwineNode component.
    /// </summary>
    /// <returns>GameObject of single node.</returns>
    /// <param name="nodeJSON">A Twine Node, in JSON format</param>
    public static GameObject MakeGameObjectFromStoryNode(JSONNode nodeJSON)
    {
#if UNITY_EDITOR
        GameObject nodeGameObject = new GameObject(nodeJSON["name"]);
        nodeGameObject.AddComponent <TwineNode> ();

        // Save additional Twine data on a Twine component
        TwineNode twineNode = nodeGameObject.GetComponent <TwineNode> ();
        twineNode.pid  = nodeJSON["pid"];
        twineNode.name = nodeJSON["name"];

        twineNode.tags = GetDequotedStringArrayFromJsonArray(nodeJSON["tags"]);

        twineNode.content = GetVisibleText(nodeJSON["text"]);

        string[] variableExpressions = GetVariableExpressions(nodeJSON["text"]);
        ActivateVariableExpressions(variableExpressions, twineNode);

        // Upon creation of this node, ensure that it is a decision node if it has
        //	the decision tag:
        // Vice versa for condition node
        twineNode.isDecisionNode  = (twineNode.tags != null && twineNode.tags.Contains(PRAIRIE_DECISION_TAG));
        twineNode.isConditionNode = (twineNode.tags != null && twineNode.tags.Contains(PRAIRIE_CONDITION_TAG));

        // Start all twine nodes as deactivated at first:
        twineNode.Deactivate();

        return(nodeGameObject);
#endif
    }
Exemplo n.º 2
0
    /// <summary>
    /// Turns a JSON-formatted Twine node into a GameObject with all the relevant data in a TwineNode component.
    /// </summary>
    /// <returns>GameObject of single node.</returns>
    /// <param name="storyNode">A Twine Node, in JSON format</param>
    public static GameObject MakeGameObjectFromStoryNode(JSONNode storyNode)
    {
                #if UNITY_EDITOR
        GameObject nodeGameObject = new GameObject(storyNode["name"]);
        nodeGameObject.AddComponent <TwineNode> ();

        // Save additional Twine data on a Twine component
        TwineNode twineNode = nodeGameObject.GetComponent <TwineNode> ();
        twineNode.pid  = storyNode["pid"];
        twineNode.name = storyNode["name"];

        twineNode.tags = GetDequotedStringArrayFromJsonArray(storyNode["tags"]);

        twineNode.content = RemoveTwineLinks(storyNode["text"]);

        // Upon creation of this node, ensure that it is a decision node if it has
        //	the decision tag:
        twineNode.isDecisionNode = (twineNode.tags != null && twineNode.tags.Contains(PRAIRIE_DECISION_TAG));

        // Start all twine nodes as deactivated at first:
        twineNode.Deactivate();

        return(nodeGameObject);
                #endif
    }
Exemplo n.º 3
0
    public static void MatchChildren(Dictionary <string, JSONNode> twineNodesJsonByName, Dictionary <string, GameObject> gameObjectsByName)
    {
        foreach (KeyValuePair <string, GameObject> entry in gameObjectsByName)
        {
            string     nodeName   = entry.Key;
            GameObject nodeObject = entry.Value;

            TwineNode twineNode = nodeObject.GetComponent <TwineNode>();
            JSONNode  jsonNode  = twineNodesJsonByName[nodeName];

            // Iterate through the links and establish object relationships:
            JSONNode nodeLinks = jsonNode["links"];

            twineNode.children  = new GameObject[nodeLinks.Count];
            twineNode.linkNames = new string[nodeLinks.Count];

            for (int i = 0; i < nodeLinks.Count; i++)
            {
                JSONNode   link            = nodeLinks[i];
                string     linkName        = link["name"];
                GameObject linkDestination = gameObjectsByName[link["link"]];

                // Remember parent:
                linkDestination.GetComponent <TwineNode>().parents.Add(nodeObject);

                // Set link as a child, and remember the name.
                twineNode.children[i]  = linkDestination;
                twineNode.linkNames[i] = linkName;
            }
        }
    }
Exemplo n.º 4
0
 public TwineData(List <string> rawData)
 {
     for (int i = 0; i < rawData.Count; i++)
     {
         TwineNode twineNode = new TwineNode();
         Data.Add(twineNode.Parse(rawData[i]));
     }
     //current = Data[0];
 }
Exemplo n.º 5
0
 	public TwineData(List <string> rawData)
	{
		for (int i = 0; i < rawData.Count; i++)
        {
        	TwineNode twineNode = new TwineNode();
        	Data.Add(twineNode.Parse(rawData[i]));
        }
        //current = Data[0];
	}
Exemplo n.º 6
0
    public static void ReadJson(string jsonString, string prefabDestinationDirectory)
    {
        // parse using `SimpleJSON`
        JSONNode  parsedJson  = JSON.Parse(jsonString);
        JSONArray parsedArray = parsedJson["passages"].AsArray;

        // parent game object which will be the story prefab
        string nameOfStory = parsedJson["name"];

        Debug.Log(nameOfStory);
        GameObject parent = new GameObject(nameOfStory);

        // Now, let's make GameObject nodes out of every twine/json node.
        //	Also, for easy access when setting up our parent-child relationships,
        //	we'll keep two dictionaries, linking names --> JSONNodes and names --> GameObjects
        Dictionary <string, JSONNode>   twineNodesJsonByName   = new Dictionary <string, JSONNode>();
        Dictionary <string, GameObject> twineGameObjectsByName = new Dictionary <string, GameObject>();

        string startNodePid = parsedJson["startnode"].ToString();

        // remove the surrounding quotes (leftover from JSONNode toString() method)
        startNodePid = startNodePid.Replace('"', ' ').Trim();

        foreach (JSONNode storyNode in parsedArray)
        {
            GameObject twineNodeObject = MakeGameObjectFromStoryNode(storyNode);

            // Bind this node to the parent "Story" object
            twineNodeObject.transform.SetParent(parent.transform);

            // Store this node and its game object in our dictionaries:
            twineNodesJsonByName[twineNodeObject.name]   = storyNode;
            twineGameObjectsByName[twineNodeObject.name] = twineNodeObject;

            TwineNode twineNode = twineNodeObject.GetComponent <TwineNode>();

            if (startNodePid.Equals(twineNode.pid))
            {
                // Tell the start node that it's a start node
                twineNodeObject.GetComponent <TwineNode>().isStartNode = true;
            }
        }

        // link nodes to their children
        MatchChildren(twineNodesJsonByName, twineGameObjectsByName);

        // "If the directory already exists, this method does not create a new directory..."
        // - From the C# docs
        System.IO.Directory.CreateDirectory(prefabDestinationDirectory);

        // save a prefab to disk, and then remove the GameObject from the scene
        string prefabDestination = prefabDestinationDirectory + "/" + parent.name + " - Twine.prefab";

        PrefabUtility.CreatePrefab(prefabDestination, parent);
        GameObject.DestroyImmediate(parent);
    }
Exemplo n.º 7
0
 //go to next node
 public void NextNode()
 {
     for (int i = 0; i < Data.Count; i++)
     {
         if (current.LinkData == Data[i].Passage)
         {
             current = Data[i];
         }
     }
 }
Exemplo n.º 8
0
	public void NextNode(TwineNode current , string link)
	{
		for(int i = 0; i >Data.Count; i++)
		{
			if(Data[i].Link == link)
			{
				current = Data[i];
			}
		}
	}
Exemplo n.º 9
0
    	public void NextNode(TwineNode current)
	{
		for(int i = 0; i > Data.Count; i++)
		{
			if(current.Link == Data[i].Title)
			{
				current = Data[i];
			}
		}
	}
Exemplo n.º 10
0
 public void NextNode(TwineNode current)
 {
     for (int i = 0; i > Data.Count; i++)
     {
         if (current.Link == Data[i].Title)
         {
             current = Data[i];
         }
     }
 }
Exemplo n.º 11
0
 public void NextNode(TwineNode current, string link)
 {
     for (int i = 0; i > Data.Count; i++)
     {
         if (Data[i].Link == link)
         {
             current = Data[i];
         }
     }
 }
Exemplo n.º 12
0
 //go to specific node
 public void NextNode(string link)
 {
     for (int i = 0; i < Data.Count; i++)
     {
         if (link.Trim() == Data[i].Passage.Trim())
         {
             current = Data[i];
             break;
         }
     }
 }
Exemplo n.º 13
0
    // Create the nodes with multiple pieces of content, such as a speaker and what she's saying.
    public TwineData(List <string> data, string[] split)
    {
        for (int i = 0; i < data.Count; i++)
        {
            TwineNode twineNode = new TwineNode(data[i], split);
            Data.Add(twineNode);

            if (i == 0)
            {
                current = twineNode;
            }
        }
    }
Exemplo n.º 14
0
	/// <summary>
	/// Find the FirstPersonInteractor in the world, and use it to activate
	/// 	the TwineNode's child at the given index.
	/// </summary>
	/// <param name="index">Index of the child to activate.</param>
	private void ActivateChildAtIndex(int index) 
	{
		// Find the interactor:
		FirstPersonInteractor interactor = (FirstPersonInteractor) FindObjectOfType(typeof(FirstPersonInteractor));

		if (interactor != null) {
			GameObject interactorObject = interactor.gameObject;
		
			// Now activate the child using this interactor!
			TwineNode child = this.children [index].GetComponent<TwineNode> ();
			child.Activate (interactorObject);
		}
	}
Exemplo n.º 15
0
    public void TwinePromptGUI()
    {
        // get list of twine nodes we need prompts for, the keys of our dictionary
        AssociatedTwineNodes associatedNodes = this.prompt.gameObject.GetComponent <AssociatedTwineNodes> ();
        List <string>        twineNodeNames  = new List <string> ();

        foreach (GameObject twineNodeObject in associatedNodes.associatedTwineNodeObjects)
        {
            TwineNode twineNode = twineNodeObject.GetComponent <TwineNode> ();
            twineNodeNames.Add(twineNode.name);
        }

        // special case: if only one twine node - use the basic input
        if (twineNodeNames.Count == 1)
        {
            // use the simple prompt GUI without allowing for cycles
            EditorGUI.BeginChangeCheck();
            SimplePromptGUI(cyclicAllowed: false);
            if (EditorGUI.EndChangeCheck())
            {
                // bind the result from simple GUI back to the twine based key
                prompt.twinePrompts.Set(twineNodeNames[0], prompt.firstPrompt);
                // since this is effectivally a reflection of the data modified, we do
                // not need to create a seperate undo event
            }
            // do not fall through into the dictionary input
            return;
        }

        EditorGUILayout.LabelField("Twine Prompts:");

        // build dictionary and get a value for each key
        foreach (string nodeName in twineNodeNames)
        {
            string previousValue = this.prompt.twinePrompts.ValueForKey(nodeName);
            if (previousValue == null)
            {
                previousValue = "";                     // default to empty string
            }

            GUIContent label = new GUIContent(nodeName, "Text displayed when a player can progress the story to this twine node.");

            EditorGUI.BeginChangeCheck();
            string newPromptText = EditorGUILayout.TextField(label, previousValue);
            if (EditorGUI.EndChangeCheck())
            {
                Undo.RecordObject(prompt, "Change Prompt");
                this.prompt.twinePrompts.Set(nodeName, newPromptText);
            }
        }
    }
Exemplo n.º 16
0
    /// <summary>
    /// Checks if any of the Twine Nodes (from the list of options for the dropdown)
    /// has the same name as the object this component is attached to.
    ///
    /// Suggests the first item in the list if there is no name match.
    /// </summary>
    /// <returns>The suggested twine node index.</returns>
    /// <param name="nodes">Nodes.</param>
    private int GetSuggestedTwineNodeIndex(TwineNode[] nodes)
    {
        GameObject attachedGameObject = ((AssociatedTwineNodes)target).gameObject;

        for (int i = 0; i < nodes.Length; i++)
        {
            TwineNode node = nodes [i];
            if (node.name.Equals(attachedGameObject.name))
            {
                return(i);
            }
        }

        // If no name match found, then choose the first node in the list:
        return(0);
    }
Exemplo n.º 17
0
    protected override void PerformAction()
    {
        foreach (GameObject twineNodeObject in associatedTwineNodeObjects)
        {
            TwineNode twineNode = twineNodeObject.GetComponent <TwineNode> ();

            if (twineNode != null)
            {
                // Activate the node!
                if (twineNode.Activate(this.rootInteractor))
                {
                    return;
                }
            }
        }
    }
Exemplo n.º 18
0
    /// <summary>
    /// Search the game objects associated with the Twine node (associatedTwineNodes), and gather their indices
    /// relative to the allNodes list.
    /// </summary>
    /// <returns>The selected indices from object list.</returns>
    /// <param name="associatedTwineNodes">The associated twine nodes component being edited.</param>
    /// <param name="allNodes">All Twine nodes in the scene.</param>
    private List <int> GetSelectedIndicesFromObjectList(AssociatedTwineNodes associatedTwineNodes, TwineNode[] allNodes)
    {
        List <int> selectedTwineNodeIndices = new List <int> ();

        for (int i = 0; i < associatedTwineNodes.associatedTwineNodeObjects.Count; i++)
        {
            GameObject nodeObject = associatedTwineNodes.associatedTwineNodeObjects [i];

            for (int j = 0; j < allNodes.Length; j++)
            {
                TwineNode node = allNodes [j];
                if (node.gameObject == nodeObject)
                {
                    selectedTwineNodeIndices.Add(j);
                }
            }
        }

        return(selectedTwineNodeIndices);
    }
    // check if the current object has an active twine node
    public bool isAssociatedTwineNodeActive()
    {
        AssociatedTwineNodes nodes = this.gameObject.GetComponent <AssociatedTwineNodes>();

        if (nodes == null)
        {
            return(false);
        }                                             // sanity check

        foreach (GameObject twineNodeObject in nodes.associatedTwineNodeObjects)
        {
            TwineNode twineNode = twineNodeObject.GetComponent <TwineNode> ();
            if (twineNode.enabled)
            {
                return(true);
            }
        }

        return(false);
    }
Exemplo n.º 20
0
    // ---- TWINE PROMPT ----

    // returns the twine node this prompt which is currently active
    public TwineNode GetActiveAssociatedTwineNode()
    {
        AssociatedTwineNodes nodes = this.gameObject.GetComponent <AssociatedTwineNodes>();

        if (nodes == null)
        {
            return(null);
        }                                    // sanity check

        foreach (GameObject twineNodeObject in nodes.associatedTwineNodeObjects)
        {
            TwineNode twineNode = twineNodeObject.GetComponent <TwineNode> ();
            if (twineNode.HasActiveParentNode())
            {
                return(twineNode);
            }
        }

        // no active twine node was found
        return(null);
    }
Exemplo n.º 21
0
    public string GetPrompt()
    {
        if (this.isTwinePrompt)
        {
            TwineNode activeNode = this.GetActiveAssociatedTwineNode();
            if (activeNode == null)
            {
                // if there is no active node, return an empty (hidden) prompt
                return("");
            }
            // return the prompt associated with this node
            string twinePrompt = this.twinePrompts.ValueForKey(activeNode.name);
            if (twinePrompt == null)
            {
                return("");
            }                                         // use empty prompt if not specified
            return(twinePrompt);
        }

        // return single or cyclic prompt
        return(curPrompt == FIRST_PROMPT ? this.firstPrompt : this.secondPrompt);
    }
Exemplo n.º 22
0
 public void Awake()
 {
     this.node = (TwineNode)target;
 }
Exemplo n.º 23
0
    /// <summary>
    /// Sets the
    /// </summary>
    /// <param name="expressions">Node's variable expressions</param>
    /// <param name="node">Twine node</param>
    /// <returns>True, unless something goes wrong</returns>
    public static bool ActivateVariableExpressions(string[] expressions, TwineNode node)
    {
        // Matches an alphanumeric string preceded by a dollar sign
        // E.g.
        //   "$var"
        //   "$1Apple3"
        //   not "$.var"
        //   not "$app le"
        Regex variableRegex = new Regex("\\$\\w*");

        // Finds an instance of a variable being assigned, starting with the
        // ":" and including the assigned value in a sub-group.
        // E.g.
        //   ":red" and "red"
        //   ":      -3" and "-3"
        Regex assignmentRegex = new Regex(":\\s*(-?\\w*)");

        // Looks for addition and retrieves the variable, the operator, and
        // the value.
        // E.g.
        //   "$var + 1" and "var", "+", "1"
        //   "$var+-1" and "var", "+", "-1"
        //   "$var -apple" and "var", "-", "apple"
        Regex additionRegex = new Regex("\\$(\\w*)\\s*([+-])\\s*(-?\\w*)");

        // Like the previous, but detects a value being compared to a value
        // with an equals sign rather than assignments.  Also gets comparison
        // type.
        // E.g.
        //   "= red" and "=", "red"
        //   "!= 3" and "!=", "3"
        Regex matchValueRegex = new Regex("(!?=|<=?|>=?)\\s*(-?\\w*)");

        // Finds a twine link - i.e. a double-bracketed line of text - with the
        // link content in a sub-group
        // E.g.
        //   "[[Next Node]]" and "Next Node"
        Regex linkRegex = new Regex("\\[\\[([^\\]]*)\\]\\]");

        // Matches all variable lines that start with "if", ignoring case
        Regex ifRegex = new Regex("^\\s*if", RegexOptions.IgnoreCase);

        Debug.Log("Going through variable expressions...");
        foreach (string expression in expressions)
        {
            Debug.Log("Analyzing var expression...");
            if (assignmentRegex.IsMatch(expression))
            {
                string variable = variableRegex.Match(expression).Value;
                string value    = assignmentRegex.Match(expression).Groups[1].Value;
                node.AddAssignment(variable, value);
                Debug.Log("Adding assignment...");
                Debug.Log("Assignment value = " + value);
            }
            else if (additionRegex.IsMatch(expression))
            {
                GroupCollection matches   = additionRegex.Match(expression).Groups;
                string          variable  = matches[1].Value;
                string          operation = matches[2].Value;
                string          value     = matches[3].Value;
                // If we're subtracting, flip the sign of the value
                if (operation[0] == '-')
                {
                    if (value[0] != '-')
                    {
                        value = "-" + value;
                    }
                    else
                    {
                        value = value.Substring(1);
                    }
                }
                // Now add a "+" to the value to mark this as addition, not
                // assignment
                value = "+" + value;
                node.AddAssignment(variable, value);
                Debug.Log("Adding addition...");
                Debug.Log("Addition value = " + value);
            }
            else if (ifRegex.IsMatch(expression))
            {
                // This condition covers both types of "if" statement.
                // We should probably later extend it to cover <, >, <=, and >=,
                // if we decide to implement them.
                Debug.Log("Adding conditional...");
                string variable  = variableRegex.Match(expression).Value;
                string operation = matchValueRegex.Match(expression).Groups[1].Value;
                Debug.Log("Operation: " + operation);
                string matchValue = matchValueRegex.Match(expression).Groups[2].Value;
                string link       = linkRegex.Match(expression).Groups[1].Value;
                node.AddConditional(variable, matchValue, link, operation);
            }
            else
            {
                Debug.Log("Unknown variable expression!");
            }
        }
        return(false);
    }