Exemple #1
0
        /// <summary>
        ///  Moves the conversation to the next node, if possible obviously.  Checks the execution permission of this node, and if it can execute, will do so.
        /// </summary>
        /// <param name="nextNodeId">Desired next node, used in decisions or conversations with two sides.  If null, choose the first available.</param>
        /// <returns>The next node in the series.</returns>
        public bool MoveToNextNode(Guid?nextNodeId = null)
        {
            // Grab the next best node for us to move into.
            var bestNode = this.GetNextBestNode(nextNodeId);

            if (bestNode != null)
            {
                // Fire all actions for activating this new node, before we set it as current.
                ConversationEngine.ActivateNode(bestNode);
                this.SetNodeAsCurrent(bestNode);

                return(true);
            }

            // Moving to the next node was not possible, due to execution ability or a conversation error.
            return(false);
        }
Exemple #2
0
        /// <summary>
        ///  Chooses the next best node out of the ones cached in the conversation.  If an ID is given, we choose that one.  If not, we look at all eligible nodes (those
        ///     that have their conditions met).  If more than one node is eligible, we'll look at the priority in relation to the current node to decide.
        /// </summary>
        /// <param name="nextNodeId">If not null, the ID they would like to choose.</param>
        /// <returns>The next node we'd like to execute, or null if none was found.</returns>
        private ConversationNode GetNextBestNode(Guid?nextNodeId = null)
        {
            // Determine which nodes are eligible to execute. Save the result in the nodes, so future calculations aren't necessary.
            var eligibleNodes = this.NextNodes.Where(x => ConversationEngine.AreConditionsMet(x, true)).ToList();

            // If NO nodes were found, the dialogue likely wasn't set up right, as there needs to be an exit point in the dialogue. Return null.
            if (!eligibleNodes.Any())
            {
                log.LogMessage($"No nodes are eligible to execute. This is likely a design fault in the conversation. Returning NULL.", Logging.Enums.LogLevel.Warning);
                return(null);
            }

            // Initialize the conversation node as the requested node, if it was requested - Otherwise, we'll choose the best fit.
            ConversationNode selectedNode = nextNodeId.HasValue ? this.NextNodes.FirstOrDefault(x => x.Id == nextNodeId.Value) : null;

            if (selectedNode != null)
            {
                // Return the requested, if it can execute. If not, return null;
                return(selectedNode.IsEnabled.HasValue && selectedNode.IsEnabled.Value ? selectedNode : null);;
            }

            // If there's only 1 eligible node, return that.
            if (eligibleNodes.Count == 1)
            {
                return(eligibleNodes.FirstOrDefault());
            }

            // Now, since we have more than 1 node eligible, we'll decide based on the conversation order chosen.
            // I realize this is a scary query, but I wanted it in one line. Basically, this orders the nodes by priority, with null priority being last.
            // Then, we pick the first one that was calculated as eligible, and grab the node(s).  If there's more than one, we randomly choose one.
            var nextNodeSet = this.currentNode.NextNodes.Where(x => eligibleNodes.Select(e => e.Id).ToList().Contains(x.NextID))
                              .OrderByDescending(x => x.Priority.HasValue)
                              .ThenBy(x => x.Priority)
                              .GroupBy(x => x.Priority)
                              .FirstOrDefault();

            // There's only one - Perfect!
            if (nextNodeSet.Count() == 1)
            {
                return(this.NodeLookup[nextNodeSet.FirstOrDefault().NextID]);
            }

            // There's more than one, return a random one for us.
            return(this.NodeLookup[nextNodeSet.ToList().GetRandomEntry().NextID]);
        }
Exemple #3
0
        /// <summary>
        ///  Activates a node, first checking if it's been told that it can, and activating all actions associated with the event.  Typically, this is capped off
        ///     by the dialogue being presented.
        /// </summary>
        /// <param name="convoNode">The conversation node we're processing.</param>
        public static void ActivateNode(ConversationNode convoNode)
        {
            // Ensure the node has been enabled first!
            if (!convoNode.IsEnabled.HasValue)
            {
                ConversationEngine.AreConditionsMet(convoNode, true);
            }

            if (!convoNode.IsEnabled.Value)
            {
                log.LogMessage($"Conversation attempted to activate node { convoNode.Id }, but it hasn't been enabled yet.  Please run AreConditionsMet before attempting to execute.", Logging.Enums.LogLevel.Warning);
                return;
            }

            // If the node's been enabled, execute all actions and make it the current node.
            convoNode.DialogueActions?.ForEach(x =>
            {
                // If we have an action in the code, we'll execute this action.
                if (dialogueActions.ContainsKey(x.Key))
                {
                    dialogueActions[x.Key].PerformAction(x.Params);
                }
            });
        }