private IOutputSpeech Do(AdventureEngine engine, AdventureCommandType command, XElement ssml = null) { ssml = ssml ?? new XElement("speak"); ProcessResponse(engine.Do(command)); return(new SsmlOutputSpeech { Ssml = ssml.ToString(SaveOptions.DisableFormatting) }); // local functions void ProcessResponse(AdventureResponse response) { switch (response) { case AdventureResponseSay say: ssml.Add(new XElement("p", new XText(say.Text))); break; case AdventureResponseDelay delay: ssml.Add(new XElement("break", new XAttribute("time", (int)delay.Delay.TotalMilliseconds + "ms"))); break; case AdventureResponsePlay play: ssml.Add(new XElement("audio", new XAttribute("src", _adventureSoundFilesPublicUrl + play.Name))); break; case AdventureResponseNotUnderstood _: ssml.Add(new XElement("p", new XText(PROMPT_MISUNDERSTOOD))); break; case AdventureResponseBye _: ssml.Add(new XElement("p", new XText(PROMPT_GOODBYE))); break; case AdventureResponseFinished _: break; case AdventureResponseMultiple multiple: foreach (var nestedResponse in multiple.Responses) { ProcessResponse(nestedResponse); } break; default: throw new AdventureException($"Unknown response type: {response?.GetType().FullName}"); } } }
//--- Methods --- public AAdventureResponse Do(AdventureCommandType command) { var responses = new List <AAdventureResponse>(); // record that a command was issued ++_state.CommandsIssued; // some commands are optional and don't require to be defined for a place var optional = false; switch (command) { case AdventureCommandType.Describe: case AdventureCommandType.Help: case AdventureCommandType.Hint: case AdventureCommandType.Restart: case AdventureCommandType.Quit: optional = true; break; } // check if the place has associated actions for the choice if (!_adventure.Places.TryGetValue(_state.CurrentPlaceId, out AdventurePlace place)) { throw new AdventureException($"Cannot find current place: '{_state.CurrentPlaceId}'"); } if (place.Choices.TryGetValue(command, out IEnumerable <KeyValuePair <AdventureActionType, string> > choice)) { foreach (var action in choice) { switch (action.Key) { case AdventureActionType.Goto: if (!_adventure.Places.TryGetValue(action.Value, out place)) { throw new AdventureException($"Cannot find goto place '{action.Value}'"); } // check if we're in a new place and need to describe it if (_state.CurrentPlaceId != place.Id) { _state.CurrentPlaceId = place.Id; DescribePlace(place); } break; case AdventureActionType.Say: responses.Add(new AdventureResponseSay(action.Value)); break; case AdventureActionType.Pause: if (!double.TryParse(action.Value, out double delayValue)) { throw new AdventureException($"Delay must be a number '{action.Value}'"); } responses.Add(new AdventureResponseDelay(TimeSpan.FromSeconds(delayValue))); break; case AdventureActionType.Play: responses.Add(new AdventureResponsePlay(action.Value)); break; } } } else if (!optional) { responses.Add(new AdventureResponseNotUnderstood()); } switch (command) { case AdventureCommandType.Describe: DescribePlace(place); break; case AdventureCommandType.Help: responses.Add(new AdventureResponseSay(place.Instructions)); break; case AdventureCommandType.Hint: // hints are optional; nothing else to do by default break; case AdventureCommandType.Restart: // update player statistics ++_state.AdventureAttempts; _state.Start = DateTime.UtcNow; _state.End = null; // check if current place has custom instructions for handling a restart if ((choice == null) || !choice.Any(c => c.Key == AdventureActionType.Goto)) { place = _adventure.Places[Adventure.StartPlaceId]; _state.CurrentPlaceId = place.Id; } DescribePlace(place); break; case AdventureCommandType.Quit: responses.Add(new AdventureResponseBye()); break; } return((responses.Count == 1) ? responses.First() : new AdventureResponseMultiple(responses)); // helper functions void DescribePlace(AdventurePlace current) { if ((current.Description != null) && (current.Instructions != null)) { responses.Add(new AdventureResponseSay(current.Description)); responses.Add(new AdventureResponseSay(current.Instructions)); } else if (current.Description != null) { responses.Add(new AdventureResponseSay(current.Description)); } else if (current.Instructions != null) { responses.Add(new AdventureResponseSay(current.Instructions)); } } }