/// <summary> /// Execute the input as if it were a tiny MooScript verb attached to the player. /// </summary> /// <returns> /// If the MooScript returns a value, it will be sent back to the player. /// </returns> public static string ExecuteImmediate(string input, Player player) { Verb v = new Verb() { name = "inline", help = "", code = input.Substring(1) + ';' }; var param = new Verb.VerbParameters() { input = input, self = player.world.findObject( player.id ), dobj = Mob.None, prep = Verb.Prep.None, iobj = Mob.None, player = player, world = player.world }; object rv; using( var ac = new ActorContext( player, player.id ) ) rv = v.invoke( param ); // Try to do some reallly basic type massaging to make it viewable on the terminal. string rvs; if (rv is string) { rvs = "\"{0}\"".FormatI(rv); } else if (rv is System.Collections.IEnumerable) { rvs = string.Join(", ", (from object i in (System.Collections.IEnumerable)rv select i.ToStringI())); } else rvs = rv.ToStringI(); return MooCode.PrepareForClient(rvs); }
/// <summary> /// Process a line of input from the player: parse and execute any action. /// </summary> public static string ProcessInput(string input, Player player) { // Ignore empty lines. if( input.Length == 0 ) return ""; // Does the input start with a special character? if (input[0] == ';') { // Execute this as a chunk of MooScript, as if it was attached // to the player. return ExecuteImmediate(input, player); } if (input[0] == '"') input = "say " + input.Substring(1); if (input[0] == ':') input = "emote " + input.Substring(1); if (input[0] == '@') input = "whisper " + input.Substring(1); // Split the input. string[] pieces = input.Trim().Split(' ', '\t', '\n', '\r'); if (pieces.Length == 0) return ""; // For now, the verb is always one word. string verb = pieces[0]; if (verb.EqualsI("/me") || verb == ":") verb = "emote"; // Start gathering values for the verb call. var param = new Verb.VerbParameters() { input = input, inputwords = pieces, self = null, world = player.world, player = player }; // Try for a #1._processInput verb first. If one exists and it returns anything // besides false, we'll let it deal with everything else. var root = player.world.findObject( 1 ); var playerMob = player.world.findObject( player.id ); Verb rootProcess = root.verbGet("_processInput"); if (rootProcess != null) { param.self = root; param.caller = playerMob; try { // This verb doesn't get any special permissions. It's just processing input from the user. object results; using( var ac = new ActorContext( player, player.id ) ) results = rootProcess.invoke(param); if (results == null || (results is bool && (bool)results == false)) { // Proceed jolly onwards... } else { // Our work here is finished. return ""; } } catch( Exception ex ) { // Just assume it didn't handle it. Sucks to get in a loop here if you // mess up your global handler..! Log.Error( "Error while processing _processInput: {0}", ex ); } param.self = null; param.caller = null; } // Look for complete wildcard verbs on the player and in the player's location. // If we find one that matches, stop processing anything else. var selectedVerb = SearchWildcardVerbsFrom(playerMob, verb, param); if (!selectedVerb.Any()) selectedVerb = SearchWildcardVerbsFrom(playerMob.location, verb, param); if (selectedVerb.Any()) { var v = selectedVerb.First(); param.self = v.foundOn; using( var ac = new ActorContext( player, v.definedOn.ownerId ) ) v.verb.invoke(param); return ""; } // Skip forward until we find a preposition. var remaining = pieces.Skip(1); var start = remaining; Verb.PrepMatch p = Verb.PrepMatch.None; string dobjName = null; for (int skip=0; skip<remaining.Count(); ++skip) { var chunk = remaining.Skip(skip); p = Verb.MatchPrep(chunk); if (p.isReal) { // Skip over the preposition after saving its words. param.prepwords = p.words.ToArray(); remaining = chunk.Skip(param.prepwords.Length); // What came before it is the direct object. param.dobjwords = start.Take(skip).ToArray(); dobjName = string.Join(" ", param.dobjwords); break; } } if (p.prep == Verb.Prep.None) { // No preposition -> the rest of the string is the direct object. param.dobjwords = remaining.ToArray(); dobjName = string.Join(" ", param.dobjwords); remaining = new string[0]; } // For now, the indirect object is always the rest of the phrase. string iobjName = null; if (remaining.Count() > 0) { param.iobjwords = remaining.ToArray(); iobjName = string.Join(" ", param.iobjwords); } // Look for objects around the player that might match the direct and indirect objects. Mob dobj = ObjectMatch(dobjName, playerMob); Mob iobj = ObjectMatch(iobjName, playerMob); // Save the objects we found so we can verb-search. param.dobj = dobj; param.prep = p.prep; param.iobj = iobj; // Look for a matching verb. selectedVerb = SearchVerbsFrom(playerMob, verb, param); if (selectedVerb.Count() == 0) selectedVerb = SearchVerbsFrom(playerMob.location, verb, param); if (selectedVerb.Count() == 0 && dobj != null) selectedVerb = SearchVerbsFrom(dobj, verb, param); if (selectedVerb.Count() == 0 && iobj != null) selectedVerb = SearchVerbsFrom(iobj, verb, param); // Couldn't find one? if (selectedVerb.Count() != 1) { // Try for a "_huh" verb on the room the player is in. SourcedItem<Verb> huh = playerMob.location.findVerb("_huh"); if (huh != null) { param.self = playerMob.location; using( var ac = new ActorContext( player, huh.source.id ) ) huh.item.invoke(param); return ""; } // Nothin' doin'. Just return a default error. return "Sorry, I don't know what that means."; } // Execute the verb. var v2 = selectedVerb.First(); param.self = v2.foundOn; using( var ac = new ActorContext( player, v2.definedOn.ownerId ) ) v2.verb.invoke(param); // Any output will come from the script. return ""; }