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); }