예제 #1
0
    /// <summary>
    /// Constructor for Quest Loading in the QuestLoader script.
    /// </summary>
    public Quest(QuestNodeCanvas questCanvas)
    {
        questName  = questCanvas.newQuest.questName;
        questGiver = questCanvas.newQuest.questGiver;

        objectives     = new List <List <QuestObjective> >();
        questDialogue  = null;
        turnInDialogue = null;

        // Parse concurrent objectives into our quest. Grab Objective Paths first and then sub objectives.
        foreach (ObjectivePath path in questCanvas.objectivePaths)
        {
            objectives.Add(new List <QuestObjective>());

            foreach (SubObjective subObjective in path.objectives)
            {
                if (subObjective.objective.tag == "Enemy")
                {
                    objectives[objectives.Count - 1].Add(new EnemyObjective(subObjective.objective.GetComponent <Enemy>(), subObjective.numberToCollect, questCanvas.newQuest.questGiver));
                }
                else if (subObjective.objective.tag == "Location")
                {
                    objectives[objectives.Count - 1].Add(new LocationObjective(subObjective.objective));
                }
                //else if(subObjective.objective.tag == "Item")
                //	objectives[objectives.Count - 1].Add(new ItemObjective(subObjective.objective.GetComponent<Item>()));
            }
        }

        // Set the first objective in each path to active.
        for (int i = 0; i < objectives.Count; i++)
        {
            objectives[i][0].SetActiveObjective();
        }

        // set up the linked list of next objectives
        foreach (List <QuestObjective> objectivePath in objectives)
        {
            for (int i = 0; i < objectivePath.Count - 1; i++)
            {
                objectivePath[i].SetNextObjective(objectivePath[i + 1]);
            }
        }

        requiredQuests = new List <string>();

        foreach (QuestAsset quest in questCanvas.requiredQuests)
        {
            requiredQuests.Add(quest.questName);
        }

        // Parse required game states
        requiredGameStates = new List <string>();

        foreach (GameStateName stateName in questCanvas.requiredGameStates)
        {
            requiredGameStates.Add(stateName.eventName);
        }
    }
예제 #2
0
    /// <summary>
    /// Loads the node canvas.
    /// </summary>
    /// <param name="path">The path to load from.</param>
    public override void LoadNodeCanvas(string path)
    {
        numberOfStates = 0;

        if (String.IsNullOrEmpty(path))
        {
            return;
        }

        Object[] objects = AssetDatabase.LoadAllAssetsAtPath(path);

        if (objects.Length == 0)
        {
            return;
        }

        QuestNodeCanvas newNodeCanvas = null;

        for (int cnt = 0; cnt < objects.Length; cnt++)
        {
            // We only have to search for the Node Canvas itself in the mess, because it still hold references to all of it's nodes and their connections
            object obj = objects[cnt];

            if (obj.GetType() == typeof(QuestNodeCanvas))
            {
                newNodeCanvas = obj as QuestNodeCanvas;
            }
        }

        if (newNodeCanvas == null)
        {
            return;
        }

        nodeCanvas = newNodeCanvas;

        // Set number of states
        foreach (Node node in nodeCanvas.nodes)
        {
            // count the current number of dialogue states
            if (node.state != -2)             // ignore choice nodes.
            {
                numberOfStates++;
            }
        }

        string[] folders = path.Split(new char[] { '/' }, StringSplitOptions.None);
        openedCanvas     = folders[folders.Length - 1];
        openedCanvasPath = path;

        InitGameStateData();

        Repaint();
        AssetDatabase.Refresh();
    }
예제 #3
0
    /// <summary>
    /// Parses the Dialogue FSM from the node editor and returns a DialgueFSM object.
    /// </summary>
    private DialogueFSM ParseDialogueFromQuest(QuestNodeCanvas questToParse, bool getTurnInQuestDialogue, bool getInProgressDialogue)
    {
        QuestNodeCanvas fsm = questToParse;             // grab each Node Canvas Object, which holds all our states

        DialogueFSM newFSM = new DialogueFSM(-1, 1.0f); // default values for quest dialogue. Probability is always 100% and can happen infinite number of times if the quest is available.

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

        // Iterate over every node in the FSM
        foreach (IQuestNode node in fsm.nodes)
        {
            // the boolean parameters act like switches. If we want a specific interaction, we want to ignore nodes that do not meet that interaction's criteria.
            if (!getTurnInQuestDialogue && !getInProgressDialogue && (node.IsTurnInDialogue() || node.IsInProgressDialogue()))
            {
                continue;
            }
            else if (getTurnInQuestDialogue && !node.IsTurnInDialogue())
            {
                continue;
            }
            else if (getInProgressDialogue && !node.IsInProgressDialogue())
            {
                continue;
            }

            if (node.GetType() == typeof(QuestDialogueNode))
            {
                QuestDialogueNode newNode = (QuestDialogueNode)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 ? "Player" : newNode.speakers[0].name;
                    newFSM.SetStartState(newNode.state);
                }

                // 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>();

                foreach (GameObject character in newNode.speakers)
                {
                    newSpeakerList.Add(speakers[character.name]);
                    newFSM.AddParticipant(speakers[character.name]);
                }

                newFSM.AddQuestState(newSpeakerList, newNode.dialogues, newNode.description, newBodyStyles, newTailStyles, newNode.state, newNode.accept, newNode.reject);

                // 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(QuestChoiceNode))
            {
                QuestChoiceNode newNode = (QuestChoiceNode)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);
                    }
                }
            }
        }

        // Check and make sure states were added. No states may be added to the FSM if no turn in dialogue options were created.
        if (newFSM.GetStateCount() > 0)
        {
            return(newFSM);
        }
        else
        {
            return(null);
        }
    }