コード例 #1
0
        public static Game Parse(string source)
        {
            var jsonGame = JsonConvert.DeserializeObject <JObject>(source);
            var places   = new Dictionary <string, GamePlace>();

            foreach (var jsonPlace in GetObject(jsonGame, "places")?.Properties() ?? Enumerable.Empty <JProperty>())
            {
                // get id and description for place
                var id           = jsonPlace.Name;
                var description  = GetString(jsonPlace.Value, "description");
                var instructions = GetString(jsonPlace.Value, "instructions");
                bool.TryParse(GetString(jsonPlace.Value, "finished") ?? "false", out bool finished);

                // parse player choices
                var choices = new Dictionary <GameCommandType, IEnumerable <KeyValuePair <GameActionType, string> > >();
                foreach (var jsonChoice in GetObject(jsonPlace.Value, "choices")?.Properties() ?? Enumerable.Empty <JProperty>())
                {
                    // parse choice command
                    var choice = (string)jsonChoice.Name;
                    if (!Enum.TryParse(choice, true, out GameCommandType command))
                    {
                        throw new GameLoaderException($"Illegal value for choice ({choice}) at {jsonChoice.Path}.");
                    }
                    if (jsonChoice.Value is JArray array)
                    {
                        var actions = array.Select(item => {
                            var property = ((JObject)item).Properties().First();
                            if (!Enum.TryParse(property.Name, true, out GameActionType action))
                            {
                                throw new GameLoaderException($"Illegal key for action ({property.Name}) at {property.Path}.");
                            }
                            return(new KeyValuePair <GameActionType, string>(action, (string)property.Value));
                        }).ToArray();
                        choices[command] = actions;
                    }
                    else
                    {
                        throw new GameLoaderException($"Expected object at {jsonChoice.Value.Path} but found {jsonChoice.Value?.Type.ToString() ?? "null"} instead.");
                    }
                }
                var place = new GamePlace(id, description, instructions, finished, choices);
                places[place.Id] = place;
            }

            // ensure there is a start room
            if (!places.ContainsKey(Game.StartPlaceId))
            {
                places[Game.StartPlaceId] = new GamePlace(
                    Game.StartPlaceId,
                    "No start place is defined for this adventure. Please check your adventure file and try again.",
                    "Please check your adventure file and try again.",
                    false,
                    new Dictionary <GameCommandType, IEnumerable <KeyValuePair <GameActionType, string> > >()
                    );
            }
            return(new Game(places));

            // helper functions
            JObject GetObject(JToken json, string key)
            {
                if (json is JObject objOuter)
                {
                    var token = objOuter[key];
                    if (token == null)
                    {
                        return(null);
                    }
                    if (token is JObject objInner)
                    {
                        return(objInner);
                    }
                    throw new GameLoaderException($"Expected object at {json.Path}.{key} but found {token?.Type.ToString() ?? "null"} instead.");
                }
                else
                {
                    throw new GameLoaderException($"Expected object at {json.Path} but found {json?.Type.ToString() ?? "null"} instead.");
                }
            }

            string GetString(JToken token, string key, bool required = true)
            {
                if (token is JObject obj)
                {
                    var value = obj[key];
                    try {
                        return((string)value);
                    } catch {
                        throw new GameLoaderException($"Expected string at {token.Path}.{key} but found {token?.Type.ToString().ToLower() ?? "null"} instead.");
                    }
                }
                else if (required)
                {
                    throw new GameLoaderException($"Expected string at {token.Path} but found {token?.Type.ToString().ToLower() ?? "null"} instead.");
                }
                return(null);
            }
        }
コード例 #2
0
        //--- Methods ---
        public IEnumerable <AGameResponse> Do(GamePlayer player, GameCommandType command)
        {
            var result = new List <AGameResponse>();

            // some commands are optional and don't require to be defined for a place
            var optional = false;

            switch (command)
            {
            case GameCommandType.Describe:
            case GameCommandType.Help:
            case GameCommandType.Hint:
            case GameCommandType.Restart:
            case GameCommandType.Quit:
                optional = true;
                break;
            }

            // check if the place has associated actions for the choice
            GamePlace place = Places[player.PlaceId];

            if (place.Choices.TryGetValue(command, out IEnumerable <KeyValuePair <GameActionType, string> > choice))
            {
                foreach (var action in choice)
                {
                    switch (action.Key)
                    {
                    case GameActionType.Goto:
                        if (!Places.TryGetValue(action.Value, out place))
                        {
                            throw new GameException($"Cannot find place: '{action.Value}'");
                        }
                        if (player.PlaceId != place.Id)
                        {
                            player.PlaceId = place.Id;
                            DescribePlace(place);

                            // check if the current place marks the end of the adventure
                            if (place.Finished)
                            {
                                result.Add(new GameResponseFinished());
                            }
                        }
                        break;

                    case GameActionType.Say:
                        result.Add(new GameResponseSay(action.Value));
                        break;

                    case GameActionType.Pause:
                        if (!double.TryParse(action.Value, out double delayValue))
                        {
                            throw new GameException($"Delay must be a number: '{action.Value}'");
                        }
                        result.Add(new GameResponseDelay(TimeSpan.FromSeconds(delayValue)));
                        break;

                    case GameActionType.Play:
                        result.Add(new GameResponsePlay(action.Value));
                        break;
                    }
                }
            }
            else if (!optional)
            {
                result.Add(new GameResponseNotUnderstood());
            }
            switch (command)
            {
            case GameCommandType.Describe:
                DescribePlace(place);
                break;

            case GameCommandType.Help:
                result.Add(new GameResponseSay(place.Instructions));
                break;

            case GameCommandType.Hint:

                // hints are optional; nothing else to do by default
                break;

            case GameCommandType.Restart:
                if ((choice == null) || !choice.Any(c => c.Key == GameActionType.Goto))
                {
                    place          = Places[Game.StartPlaceId];
                    player.PlaceId = place.Id;
                }
                DescribePlace(place);
                break;

            case GameCommandType.Quit:
                result.Add(new GameResponseBye());
                break;
            }
            return(result);

            // helper functions
            void DescribePlace(GamePlace current)
            {
                if ((current.Description != null) && (current.Instructions != null))
                {
                    result.Add(new GameResponseSay(current.Description));
                    result.Add(new GameResponseSay(current.Instructions));
                }
                else if (current.Description != null)
                {
                    result.Add(new GameResponseSay(current.Description));
                }
                else if (current.Instructions != null)
                {
                    result.Add(new GameResponseSay(current.Instructions));
                }
            }
        }