Esempio n. 1
0
        private async Task <bool> ExecuteActionsAsync(DialogContext dc, IEnumerable <CommandAction> actions)
        {
            var stateFlags = await _stateFlagsStateAccessor.GetAsync(dc.Context);

            var inventoryItems = await _inventoryItemsAccessor.GetAsync(dc.Context);

            // Get the room state. It always exists at this point because it's
            // set up in the BeginDialogAsync method.
            var roomStates = await _roomStateAccessor.GetAsync(dc.Context, () => new Dictionary <string, RoomState>());

            var roomState = roomStates[_roomId];

            var activities  = new List <IActivity>();
            var actionStack = new Stack <CommandAction>(actions.Reverse());

            // Process each action in turn, populating the activities list.
            while (actionStack.TryPop(out CommandAction nextAction))
            {
                switch (nextAction)
                {
                case AddToInventoryAction action:
                {
                    if (!inventoryItems.Contains(action.InventoryItemId))
                    {
                        inventoryItems.Add(action.InventoryItemId);

                        activities.Add(_activityFactory.InventoryItemAdded(dc, action.InventoryItemId));
                    }
                    break;
                }

                case ClearFlagAction action:
                {
                    if (stateFlags.Contains(action.Flag))
                    {
                        stateFlags.Remove(action.Flag);
                    }
                    break;
                }

                case GuiDelayAction action:
                {
                    activities.Add(_activityFactory.Delayed(dc, action.Milliseconds));
                    break;
                }

                case GuiChangeActorDirectionAction action:
                {
                    activities.Add(_activityFactory.ActorDirectionChanged(dc,
                                                                          action.ActorId, action.Direction));
                    break;
                }

                case GuiMoveActorAction action:
                {
                    // Save the actor's new position in the room state.
                    roomState.ActorPositions[action.ActorId] = action.Position;

                    activities.Add(_activityFactory.ActorMoved(dc, action.ActorId, action.Position));
                    break;
                }

                case GuiNarratorAction action:
                {
                    activities.Add(_activityFactory.Narrated(dc, action.Text));
                    break;
                }

                case GuiPlaceActorAction action:
                {
                    // Save the actor's new position in the room state.
                    roomState.ActorPositions[action.ActorId] = action.Position;

                    activities.Add(_activityFactory.ActorPlacedInRoom(dc, action.ActorId, action.Position));
                    break;
                }

                case GuiPlaceObjectAction action:
                {
                    // Save the object's new position in the room state.
                    roomState.ObjectPositions[action.ObjectId] = action.Position;

                    activities.Add(_activityFactory.ObjectPlacedInRoom(dc, action.ObjectId, action.Position));
                    break;
                }

                case GuiRemoveObjectAction action:
                {
                    // Remove the object from the room state.
                    roomState.ObjectPositions.Remove(action.ObjectId);

                    activities.Add(_activityFactory.ObjectRemovedFromRoom(dc, action.ObjectId));
                    break;
                }

                case RemoveFromInventoryAction action:
                {
                    if (inventoryItems.Contains(action.InventoryItemId))
                    {
                        inventoryItems.Remove(action.InventoryItemId);
                    }
                    activities.Add(_activityFactory.InventoryItemRemoved(dc, action.InventoryItemId));
                    break;
                }

                case SetFlagAction action:
                {
                    if (!stateFlags.Contains(action.Flag))
                    {
                        stateFlags.Add(action.Flag);
                    }
                    break;
                }

                case SpeakAction action:
                {
                    activities.Add(_activityFactory.Speak(dc, action.ActorId, action.Text));
                    break;
                }

                case StartConversationAction action:
                {
                    // If the result of the action indicates that we need to start a new dialog
                    // (e.g. conversation with an actor, or a switch to a new room), first send all
                    // activities collected up to this point to the client.
                    if (activities.Any())
                    {
                        await dc.Context.SendActivitiesAsync(activities.ToArray());
                    }

                    // If the player starts a conversation, save any remaining actions to the state.
                    // These will be executed when the conversation is done and this dialog
                    // continues.
                    if (actionStack.Any())
                    {
                        // Conver to List because Stacks don't serialize in the correct order.
                        // See https://github.com/JamesNK/Newtonsoft.Json/issues/971.
                        dc.ActiveDialog.State.Add(DialogStatePendingActions, actionStack.ToList());
                    }

                    // Start the conversation.
                    await dc.BeginDialogAsync(action.ConversationId);

                    // Stop processing any further actions now that we've switched to a new dialog.
                    return(false);
                }

                case SwitchRoomAction action:
                {
                    // If the result of the action indicates that we need to start a new dialog
                    // (e.g. conversation with an actor, or a switch to a new room), first send all
                    // activities collected up to this point to the client.
                    if (activities.Any())
                    {
                        await dc.Context.SendActivitiesAsync(activities.ToArray());
                    }

                    // Switch to the new room.
                    await dc.ReplaceDialogAsync(action.RoomId);

                    // Stop processing any further actions now that we've switched to a new dialog.
                    return(false);
                }

                case TextDescribeAction action:
                {
                    activities.Add(MessageFactory.Text(action.Text));
                    break;
                }
                }
            }

            await dc.Context.SendActivitiesAsync(activities.ToArray());

            // Returning true here indicates that we can continue processing the actions for this turn.
            return(true);
        }
Esempio n. 2
0
        private async Task <DialogTurnResult> RunStepAsync(DialogContext dc, string option = null)
        {
            // Find the current conversation tree node using the saved Step state.
            var node = _rootNode;

            if (dc.ActiveDialog.State.ContainsKey(DialogStateCurrentNodeId))
            {
                node = _rootNode.Find(Convert.ToInt32(dc.ActiveDialog.State[DialogStateCurrentNodeId]));
            }

            // Find the node that contains the actions for the reply.
            var nextNode = (option != null && node.ChildNodes.ContainsKey(option))
                ? node.ChildNodes[option]
                : node;

            // Process the actions, creating a list of activities to send back to the player.
            var activities      = new List <IActivity>();
            var activityFactory = new ActivityFactory(_gameInfo);
            var stateFlags      = await _stateFlagsStateAccessor.GetAsync(dc.Context);

            //
            foreach (var action in nextNode.Actions)
            {
                switch (action)
                {
                case GoToConversationTopicAction goToConversationTopicAction:
                    if (string.Equals(goToConversationTopicAction.Topic, "root", StringComparison.OrdinalIgnoreCase))
                    {
                        nextNode = _rootNode;
                    }
                    else if (node.ParentId.HasValue)
                    {
                        nextNode = _rootNode.Find(node.ParentId.Value);
                    }
                    break;

                case EndConversationAction endConversationAction:
                    nextNode = null;
                    break;

                case SpeakAction speakAction:
                    activities.Add(activityFactory.Speak(dc, speakAction.ActorId, speakAction.Text));
                    break;

                case SetFlagAction setFlagAction:
                    if (!stateFlags.Contains(setFlagAction.Flag))
                    {
                        stateFlags.Add(setFlagAction.Flag);
                    }
                    break;
                }
            }

            // Check if the conversation tree should continue;
            if (nextNode != null)
            {
                // If there are no child nodes in the next node, there's nothing for the player to do.
                // Revert to the current node for the next turn.
                if (!nextNode.ChildNodes.Any())
                {
                    nextNode = node;
                }

                // List the conversation tree options for the player.
                var options = nextNode.ChildNodes.Select(s => s.Key).ToArray();

                // Add the conversation tree options to the last outbound messages activity.
                var lastMessageIndex    = activities.FindLastIndex(a => a.Type == ActivityTypes.Message);
                var lastMessageActivity = (Activity)activities[lastMessageIndex].AsMessageActivity();
                var updatedActivity     = (Activity)MessageFactory.SuggestedActions(options, lastMessageActivity.Text);
                updatedActivity.Properties   = lastMessageActivity.Properties;
                activities[lastMessageIndex] = updatedActivity;
            }

            // Send all activities to the client.
            await dc.Context.SendActivitiesAsync(activities.ToArray());

            // Update the state so the next turn will start at the correct location in the dialog tree.
            if (nextNode != null)
            {
                dc.ActiveDialog.State[DialogStateCurrentNodeId] = nextNode.Id;
                return(new DialogTurnResult(DialogTurnStatus.Waiting));
            }

            // Or end the dialog tree if there's no next node.
            await dc.EndDialogAsync();

            return(new DialogTurnResult(DialogTurnStatus.Complete));
        }