Example #1
0
        public DisambigCommandHandler(
            Actor Actor,
            CommandParser.MatchedCommand MatchedCommand,
            ParserCommandHandler ParentHandler)
        {
            this.ParentHandler  = ParentHandler;
            this.MatchedCommand = MatchedCommand;

            // Find an object parameter such that
            //  a) each match has a parameter with that name
            //  b) at least one match has a value different from the others

            var foundAmbiguousArgument = false;

            // Note that we iterate only over the arguments in the first match. If the first match doesn't have the
            // argument, that argument can't satisfy condition a above.
            foreach (var argument in MatchedCommand.Matches[0])
            {
                // It's only possible to disambiguate on MudObjects. If any match - including the first one - has
                // a value for that argument that is not a MudObject, disambiguation will fail.
                if (argument.Value is MudObject)
                {
                    var uniqueMatchables = new List <MudObject>();
                    var rejected         = false;

                    foreach (var match in MatchedCommand.Matches)
                    {
                        if (match.ContainsKey(argument.Key) &&
                            match[argument.Key] is MudObject)
                        {
                            var matchableObject = match[argument.Key] as MudObject;
                            if (!uniqueMatchables.Contains(matchableObject))
                            {
                                uniqueMatchables.Add(matchableObject);
                            }
                        }
                        else
                        {
                            rejected = true;
                            break;
                        }
                    }

                    if (!rejected && uniqueMatchables.Count > 1)
                    {
                        // Disambiguate on this object.
                        DisambigArgument = argument.Key;
                        DisambigObjects  = uniqueMatchables;

                        foundAmbiguousArgument = true;
                        break;
                    }
                }
            }

            if (foundAmbiguousArgument)
            {
                var response = new StringBuilder();
                response.Append("Which did you mean?\r\n");
                for (var i = 0; i < DisambigObjects.Count; ++i)
                {
                    response.Append(String.Format("{0}: {1}\r\n", i, Core.GlobalRules.ConsiderValueRule <String>("printed name", Actor, DisambigObjects[i], "the")));
                }
                MudObject.SendMessage(Actor, response.ToString());
            }
            else
            {
                MudObject.SendMessage(Actor, "I couldn't figure out how to disambiguate that command.");
            }
        }
Example #2
0
        public MatchedCommand ParseCommand(PendingCommand Command)
        {
            var tokens = new LinkedList <String>(Command.RawCommand.Split(new char[] { ' ', '\t' }, StringSplitOptions.RemoveEmptyEntries));

            var rootMatch = new PossibleMatch(tokens.First);

            rootMatch.Upsert("ACTOR", Command.Actor);
            rootMatch.Upsert("LOCATION", Command.Actor == null ? null : Command.Actor.Location);

            // A pending command can have some properties set when it is queued. For example, the 'go' action
            // generates a 'look' command after processing. It will give the 'look' command a property named
            // 'auto' to indicate that the look command was generated. Rules can then use this property to
            // implement behavior. From the same example, 'look' may emit a brief description if it is generated
            // by the 'go' action, but emit a more detailed description if the player enters the command 'look'.
            //      See StandardActions.Go
            if (Command.PreSettings != null)
            {
                foreach (var setting in Command.PreSettings)
                {
                    rootMatch.Upsert(setting.Key.ToUpper(), setting.Value);
                }
            }

            var matchContext = new MatchContext {
                ExecutingActor = Command.Actor
            };

            // Try every single command defined, until one matches.
            foreach (var command in Commands)
            {
                IEnumerable <PossibleMatch> matches;

                try
                {
                    matches = command.Matcher.Match(rootMatch, matchContext);
                }
                catch (MatchAborted ma)
                {
                    // The match didn't fail; it generated an error. These means the match progressed to a point
                    // where the author of the command felt that the input could not logically match any other
                    // command, however, the input was still malformed in some way. Abort matching, and dummy up
                    // a command entry to display the error message to the player.
                    return(new MatchedCommand(
                               new CommandEntry().ProceduralRule((match, actor) =>
                    {
                        MudObject.SendMessage(actor, ma.Message);
                        return PerformResult.Continue;
                    }),
                               // We need a fake match just so it can be passed to the procedural rule.
                               new PossibleMatch[] { new PossibleMatch(null) }));
                }

                // Only accept matches that consumed all of the input.
                matches = matches.Where(m => m.Next == null);

                // If we did consume all of the input, we will assume this match is successful. Note it is
                // possible for a command to generate multiple matches, but not possible to match multiple commands.
                if (matches.Count() > 0)
                {
                    return(new MatchedCommand(command, matches));
                }
            }
            return(null);
        }