/// <summary>Checks against the guards for the command.</summary> /// <param name="actionInput">The full input specified for executing the command.</param> /// <returns>A string with the error message for the user upon guard failure, else null.</returns> public override string Guards(ActionInput actionInput) { IController sender = actionInput.Controller; string commonFailure = VerifyCommonGuards(actionInput, ActionGuards); if (commonFailure != null) { return commonFailure; } // Rule: Do we have an item matching in our inventory? // @@@ TODO: Support drinking from, for instance, a fountain sitting in the room. string itemIdentifier = actionInput.Tail.Trim(); this.thingToDrink = sender.Thing.FindChild(itemIdentifier.ToLower()); if (this.thingToDrink == null) { return "You do not hold " + actionInput.Tail.Trim() + "."; } // Rule: Is the item drinkable? this.drinkableBehavior = this.thingToDrink.Behaviors.FindFirst<DrinkableBehavior>(); if (this.drinkableBehavior == null) { return itemIdentifier + " is not drinkable"; } return null; }
/// <summary>Prepare for, and determine if the command's prerequisites have been met.</summary> /// <param name="actionInput">The full input specified for executing the command.</param> /// <returns>A string with the error message for the user upon guard failure, else null.</returns> public override string Guards(ActionInput actionInput) { string commonFailure = VerifyCommonGuards(actionInput, ActionGuards); if (commonFailure != null) { return commonFailure; } // Rule: Did they specify a tree to chop? // @@@ TODO: Better thing finders... Thing parent = actionInput.Controller.Thing.Parent; Thing thing = parent.Children.Find(t => t.Name.Equals(actionInput.Params[0], StringComparison.CurrentCultureIgnoreCase)); if (thing == null) { return string.Format("{0} is not here.", actionInput.Params[0]); } // @@@ TODO: Detect ConsumableProviderBehavior on the item, and detect if it is choppable. //if (!(item is Item)) //{ // return string.Format("{0} is not a tree.", actionInput.Params[0]); //} //this.tree = (Item) item; //if (this.tree.NumberOfResources <= 0) //{ // return string.Format("The tree doesn't contain any suitable wood."); //} return null; }
/// <summary>Executes the command.</summary> /// <param name="actionInput">The full input specified for executing the command.</param> public override void Execute(ActionInput actionInput) { IController sender = actionInput.Controller; this.itemToWieldBehavior.Wielder = sender.Thing; // Create an event handler that intercepts the ChangeOwnerEvent and // prevents dropping/trading the item around while it is wielded. // A reference is stored in the WieldableBehavior instance so it // can be easily removed by the unwield command. var interceptor = new CancellableGameEventHandler(this.Eventing_MovementRequest); this.itemToWieldBehavior.MovementInterceptor = interceptor; this.itemToWield.Eventing.MovementRequest += interceptor; var contextMessage = new ContextualString(sender.Thing, this.itemToWield.Parent) { ToOriginator = "You wield the $WieldedItem.Name.", ToOthers = "$ActiveThing.Name wields a $WieldedItem.Name.", }; var sensoryMessage = new SensoryMessage(SensoryType.Sight, 100, contextMessage); var wieldEvent = new WieldUnwieldEvent(this.itemToWield, true, sender.Thing, sensoryMessage); sender.Thing.Eventing.OnCombatRequest(wieldEvent, EventScope.ParentsDown); if (!wieldEvent.IsCancelled) { sender.Thing.Eventing.OnCombatEvent(wieldEvent, EventScope.ParentsDown); } }
/// <summary>Prepare for, and determine if the command's prerequisites have been met.</summary> /// <param name="actionInput">The full input specified for executing the command.</param> /// <returns>A string with the error message for the user upon guard failure, else null.</returns> public override string Guards(ActionInput actionInput) { string commonFailure = VerifyCommonGuards(actionInput, ActionGuards); if (commonFailure != null) { return commonFailure; } // Rule: We should have at least 1 item in our words array. int numberWords = actionInput.Params.Length; if (numberWords < 2) { return "You must specify a room to create a portal to."; } // Check to see if the first word is a number. string roomToGet = actionInput.Params[1]; if (string.IsNullOrEmpty(roomToGet)) { // Its not a number so it could be an entity... try it. this.targetPlace = GameAction.GetPlayerOrMobile(actionInput.Params[0]); if (this.targetPlace == null) { return "Could not convert " + actionInput.Params[0] + " to a room number."; } } // this.targetRoom = bridge.World.FindRoom(roomToGet); if (this.targetPlace == null) { return string.Format("Could not find the room {0}.", roomToGet); } return null; }
/// <summary>Checks against the guards for the command.</summary> /// <param name="actionInput">The full input specified for executing the command.</param> /// <returns>A string with the error message for the user upon guard failure, else null.</returns> public override string Guards(ActionInput actionInput) { string commonFailure = VerifyCommonGuards(actionInput, ActionGuards); if (commonFailure != null) { return commonFailure; } string[] normalizedParams = this.NormalizeParameters(actionInput.Controller); string role = normalizedParams[0]; string playerName = normalizedParams[1]; Thing player = GameAction.GetPlayerOrMobile(playerName); if (player == null) { // If the player is not online, then load the player from the database //player = PlayerBehavior.Load(playerName); } // Rule: Does the player exist in our Universe? // @@@ TODO: Add code to make sure the player exists. // Rule: Does player already have role? /* @@@ FIX if (Contains(player.Roles, role)) { return player.Name + " already has the " + role + " role."; }*/ return null; }
/// <summary>Executes the command.</summary> /// <param name="actionInput">The full input specified for executing the command.</param> public override void Execute(ActionInput actionInput) { // Not sure what would call this other than a player, but exit early just in case. // Implicitly also verifies that this.sender exists. if (this.userControlledBehavior == null) { return; } // No arguments were provided. Just show the current buffer setting and exit. if (string.IsNullOrEmpty(actionInput.Tail)) { this.ShowCurrentBuffer(); return; } // Set the value for the current session if (this.session.Connection != null) { this.session.Connection.PagingRowLimit = (this.parsedBufferLength == -1) ? this.session.Terminal.Height : this.parsedBufferLength; } this.userControlledBehavior.PagingRowLimit = this.parsedBufferLength; this.userControlledBehavior.Save(); this.ShowCurrentBuffer(); }
public void TestParseText() { // Test empty string var actionInput = new ActionInput(string.Empty, null); Verify.IsNull(actionInput.Noun); Verify.IsNull(actionInput.Tail); Verify.IsNull(actionInput.Params); // Test simple 1-word command var oneWordInput = new ActionInput("look", null); Verify.AreEqual(oneWordInput.Noun, "look"); Verify.IsNull(actionInput.Tail); Verify.IsNull(actionInput.Params); // Test 2-word command var twoWordInput = new ActionInput("look foo", null); Verify.AreEqual(twoWordInput.Noun, "look"); Verify.AreEqual(twoWordInput.Tail, "foo"); Verify.IsNotNull(twoWordInput.Params); Verify.AreEqual(twoWordInput.Params.Length, 1); // Test 2-word command var threeWordInput = new ActionInput("create consumable metal", null); Verify.AreEqual(threeWordInput.Noun, "create"); Verify.AreEqual(threeWordInput.Tail, "consumable metal"); Verify.IsNotNull(threeWordInput.Params); Verify.AreEqual(threeWordInput.Params.Length, 2); // Test input with leading/trailing spaces var spacedWordInput = new ActionInput(" look foo ", null); Verify.AreEqual(spacedWordInput.Noun, "look"); Verify.AreEqual(spacedWordInput.Tail, "foo"); Verify.IsNotNull(spacedWordInput.Params); Verify.AreEqual(spacedWordInput.Params.Length, 1); }
/// <summary>Executes the command.</summary> /// <param name="actionInput">The full input specified for executing the command.</param> public override void Execute(ActionInput actionInput) { IController sender = actionInput.Controller; Thing parent = sender.Thing.Parent; string searchString = actionInput.Tail.Trim().ToLower(); if (string.IsNullOrEmpty(searchString)) { sender.Write("You must specify something to search for."); return; } // Unique case. Use 'here' to list the contents of the room. if (searchString == "here") { sender.Write(this.ListRoomItems(parent)); return; } // First check the place where the sender is located (like a room) for the target, // and if not found, search the sender's children (like inventory) for the target. Thing thing = parent.FindChild(searchString) ?? sender.Thing.FindChild(searchString); if (thing != null) { // @@@ TODO: Send a SensoryEvent? sender.Write(thing.Description); } else { sender.Write("You cannot find " + searchString + "."); } }
/// <summary>Executes the command.</summary> /// <param name="actionInput">The full input specified for executing the command.</param> public override void Execute(ActionInput actionInput) { IController sender = actionInput.Controller; var contextMessage = new ContextualString(sender.Thing, this.target) { ToOriginator = "You cast ThunderClap at $ActiveThing.Name!", ToReceiver = "$Aggressor.Name casts ThunderClap at you, you only hear a ringing in your ears now.", ToOthers = "You hear $Aggressor.Name cast ThunderClap at $ActiveThing.Name! It was very loud.", }; var sm = new SensoryMessage(SensoryType.Hearing, 100, contextMessage); var attackEvent = new AttackEvent(this.target, sm, sender.Thing); sender.Thing.Eventing.OnCombatRequest(attackEvent, EventScope.ParentsDown); if (!attackEvent.IsCancelled) { var deafenEffect = new AlterSenseEffect() { SensoryType = SensoryType.Hearing, AlterAmount = -1000, Duration = new TimeSpan(0, 0, 45), }; this.target.Behaviors.Add(deafenEffect); sender.Thing.Eventing.OnCombatEvent(attackEvent, EventScope.ParentsDown); } }
/// <summary>Checks against the guards for the command.</summary> /// <param name="actionInput">The full input specified for executing the command.</param> /// <returns>A string with the error message for the user upon guard failure, else null.</returns> public override string Guards(ActionInput actionInput) { string commonFailure = VerifyCommonGuards(actionInput, ActionGuards); if (commonFailure != null) { return commonFailure; } string targetName = actionInput.Tail.Trim().ToLower(); // Rule: Is the target an entity? this.target = GameAction.GetPlayerOrMobile(targetName); if (this.target == null) { return "You cannot see " + targetName + "."; } // Rule: Is the target in the same room? if (actionInput.Controller.Thing.Parent.ID != this.target.Parent.ID) { return "You cannot see " + targetName + "."; } // Rule: Is the target alive? if (this.target.Stats["health"].Value <= 0) { return this.target.Name + " is dead."; } return null; }
/// <summary>Executes the command.</summary> /// <param name="actionInput">The full input specified for executing the command.</param> public override void Execute(ActionInput actionInput) { IController sender = actionInput.Controller; var parameters = actionInput.Params; // Ensure two 'credits' commands at the same time do not race for shared cache, etc. lock (cacheLockObject) { if (cachedContents == null || (parameters.Length > 0 && parameters[0].ToLower() == "reload")) { StreamReader reader = new StreamReader("Files\\Credits.txt"); StringBuilder stringBuilder = new StringBuilder(); string s; while ((s = reader.ReadLine()) != null) { if (!s.StartsWith(";")) { stringBuilder.AppendLine(s); } } cachedContents = stringBuilder.ToString(); } sender.Write(cachedContents); } }
/// <summary>Checks against the guards for the command.</summary> /// <param name="actionInput">The full input specified for executing the command.</param> /// <returns>A string with the error message for the user upon guard failure, else null.</returns> public override string Guards(ActionInput actionInput) { IController sender = actionInput.Controller; string commonFailure = VerifyCommonGuards(actionInput, ActionGuards); if (commonFailure != null) { return commonFailure; } // The comon guards already guarantees the sender is a player, hence no null checks here. this.player = sender.Thing; this.playerBehavior = sender.Thing.Behaviors.FindFirst<PlayerBehavior>(); // Rule: The new pretitle must be empty or meet the length requirements. this.oldPretitle = this.player.SingularPrefix; if (!string.IsNullOrEmpty(actionInput.Tail)) { this.newPretitle = actionInput.Tail; if (this.newPretitle.Length < 2 || this.newPretitle.Length > 15) { return "The pretitle may not be less than 2 nor more than 15 characters long."; } } //// One could implement 'no color' or 'no swearing' or 'no non-alpha character' rules here, etc. return null; }
/// <summary>Executes the command.</summary> /// <param name="actionInput">The full input specified for executing the command.</param> public override void Execute(ActionInput actionInput) { // Generate an item changed owner event. IController sender = actionInput.Controller; ContextualStringBuilder csb = new ContextualStringBuilder(sender.Thing, this.parent); csb.Append(@"$ActiveThing.Name drops $Thing.Name.", ContextualStringUsage.WhenNotBeingPassedToOriginator); csb.Append(@"You drop $Thing.Name.", ContextualStringUsage.OnlyWhenBeingPassedToOriginator); SensoryMessage message = new SensoryMessage(SensoryType.Sight, 100, csb); var changeOwnerEvent = new ChangeOwnerEvent(sender.Thing, message, sender.Thing, this.parent, this.thing); // Broadcast as a request and see if anything wants to prevent the event. this.parent.Eventing.OnMovementRequest(changeOwnerEvent, EventScope.ParentsDown); if (!changeOwnerEvent.IsCancelled) { // Always have to remove an item before adding it because of the event observer system. // @@@ TODO: Test, this may be broken now... this.thing.Parent.Remove(this.thing); this.parent.Add(this.thing); //// @@@ BUG: Saving currently throws a NotImplementedException. Disabled for now... this.thing.Save(); this.parent.Save(); // Broadcast the event. this.parent.Eventing.OnMovementEvent(changeOwnerEvent, EventScope.ParentsDown); } }
/// <summary>Executes the command.</summary> /// <param name="actionInput">The full input specified for executing the command.</param> public override void Execute(ActionInput actionInput) { IController sender = actionInput.Controller; string[] normalizedParams = this.NormalizeParameters(sender); string role = normalizedParams[0]; string playerName = normalizedParams[1]; Thing player = GameAction.GetPlayerOrMobile(playerName); if (player == null) { // If the player is not online, then load the player from the database //player = PlayerBehavior.Load(playerName); } var userControlledBehavior = player.Behaviors.FindFirst<UserControlledBehavior>(); var existingRole = (from r in userControlledBehavior.Roles where r.Name == role select r).FirstOrDefault(); if (existingRole == null) { var roleRepository = new RoleRepository(); // @@@ TODO: The role.ToUpper is a hack. Need to create a case insensitive method for the RoleRepository.NoGen.cs class. RoleRecord record = roleRepository.GetByName(role.ToUpper()); //userControlledBehavior.RoleRecords.Add(record); //userControlledBehavior.UpdateRoles(); player.Save(); sender.Write(player.Name + " has been granted the " + role + " role.", true); } }
/// <summary>Executes the command.</summary> /// <param name="actionInput">The full input specified for executing the command.</param> public override void Execute(ActionInput actionInput) { IController sender = actionInput.Controller; // Remove "weapon" from input tail and use the rest as the name. string weaponName = actionInput.Tail.Substring(6).Trim().ToLower(); Thing weaponItem = new Thing(new WieldableBehavior(), new MovableBehavior()); weaponItem.Name = weaponName; weaponItem.SingularPrefix = "a"; //weaponItem.ID = Guid.NewGuid().ToString(); weaponItem.ID = "0"; var wasAdded = sender.Thing.Parent.Add(weaponItem); var userControlledBehavior = sender.Thing.Behaviors.FindFirst<UserControlledBehavior>(); if (wasAdded) { userControlledBehavior.Controller.Write(string.Format("You create a weapon called {0}.", weaponItem.Name)); } else { userControlledBehavior.Controller.Write(string.Format("Could not add {0} to the room!", weaponItem.Name)); } }
/// <summary>Executes the command.</summary> /// <param name="actionInput">The full input specified for executing the command.</param> public override void Execute(ActionInput actionInput) { IController sender = actionInput.Controller; // Strings to be displayed when the effect is applied/removed. var muteString = new ContextualString(sender.Thing, this.playerToMute) { ToOriginator = "You mute $Target.", ToReceiver = "You are muted by $ActiveThing.", ToOthers = "$ActiveThing mutes $Target." }; var unmuteString = new ContextualString(sender.Thing, this.playerToMute) { ToOriginator = "$Target is no longer mute.", ToReceiver = "You are no longer mute." }; // Turn the above sets of strings into sensory messages. var muteMessage = new SensoryMessage(SensoryType.Sight, 100, muteString); var unmuteMessage = new SensoryMessage(SensoryType.Sight, 100, unmuteString); // Create the effect. var muteEffect = new MutedEffect(sender.Thing, this.muteDuration, muteMessage, unmuteMessage); // Apply the effect. this.playerToMute.Behaviors.Add(muteEffect); }
/// <summary>Executes the command.</summary> /// <param name="actionInput">The full input specified for executing the command.</param> public override void Execute(ActionInput actionInput) { IController sender = actionInput.Controller; if (sender != null && sender.Thing != null) { Thing entity = sender.Thing; if (entity != null) { if (!string.IsNullOrEmpty(this.NewDescription)) { entity.Description = this.NewDescription; entity.Save(); sender.Write("Description successfully changed."); } else { sender.Write(string.Format("Your current description is \"{0}\".", entity.Description)); } } else { sender.Write("Unexpected error occurred changing description, please contact admin."); } } }
/// <summary>Checks against the guards for the command.</summary> /// <param name="actionInput">The full input specified for executing the command.</param> /// <returns>A string with the error message for the user upon guard failure, else null.</returns> public override string Guards(ActionInput actionInput) { IController sender = actionInput.Controller; string commonFailure = VerifyCommonGuards(actionInput, ActionGuards); if (commonFailure != null) { return commonFailure; } // Rule: A thing must be singly targeted. // @@@ TODO: Try to find a single target according to the specified identifiers. If more than one thing // meets the identifiers then use a disambiguation targeting system to try to narrow to one thing. // @@@ TODO: This sort of find pattern may become common; maybe we need to simplify // to having a Thing method which does this? IE "List<Thing> FindChildren<T>(string id)"? Predicate<Thing> findPredicate = (Thing t) => t.Behaviors.FindFirst<EnterableExitableBehavior>() != null; List<Thing> enterableThings = sender.Thing.Parent.FindAllChildren(findPredicate); if (enterableThings.Count > 1) { return "There is more than one thing by that identity."; } else if (enterableThings.Count == 1) { Thing thing = enterableThings.First(); this.enterableBehavior = thing.Behaviors.FindFirst<EnterableExitableBehavior>(); if (this.enterableBehavior == null) { return "You can not enter " + thing.Name + "."; } } // If we got this far, we couldn't find an appropriate enterable thing in the room. return "You can't see anything like that to enter."; }
/// <summary>Checks against the guards for the command.</summary> /// <param name="actionInput">The full input specified for executing the command.</param> /// <returns>A string with the error message for the user upon guard failure, else null.</returns> public override string Guards(ActionInput actionInput) { IController sender = actionInput.Controller; Thing wielder = sender.Thing; Thing room = wielder.Parent; string commonFailure = VerifyCommonGuards(actionInput, ActionGuards); if (commonFailure != null) { return commonFailure; } string itemName = actionInput.Tail.Trim().ToLower(); // First look for a matching item in inventory and make sure it can // be wielded. If nothing was found in inventory, look for a matching // wieldable item in the surrounding environment. this.itemToUnwield = wielder.FindChild(item => item.Name.ToLower() == itemName && item.HasBehavior<WieldableBehavior>() && item.Behaviors.FindFirst<WieldableBehavior>().Wielder == sender.Thing); if (this.itemToUnwield == null) { this.itemToUnwield = wielder.Parent.FindChild(item => item.Name.ToLower() == itemName && item.HasBehavior<WieldableBehavior>() && item.Behaviors.FindFirst<WieldableBehavior>().Wielder == sender.Thing); } if (this.itemToUnwield == null) { return "You are not wielding the " + itemName + "."; } this.itemToUnwieldBehavior = this.itemToUnwield.Behaviors.FindFirst<WieldableBehavior>(); return null; }
/// <summary>Executes the command.</summary> /// <param name="actionInput">The full input specified for executing the command.</param> public override void Execute(ActionInput actionInput) { IController sender = actionInput.Controller; this.itemToUnwieldBehavior.Wielder = null; // Remove the event handler that prevents dropping the item while wielded. var interceptor = this.itemToUnwieldBehavior.MovementInterceptor; this.itemToUnwield.Eventing.MovementRequest -= interceptor; var contextMessage = new ContextualString(sender.Thing, this.itemToUnwield.Parent) { ToOriginator = "You unwield the $WieldedItem.Name.", ToOthers = "$ActiveThing.Name unwields a $WieldedItem.Name.", }; var sensoryMessage = new SensoryMessage(SensoryType.Sight, 100, contextMessage); var unwieldEvent = new WieldUnwieldEvent(this.itemToUnwield, true, sender.Thing, sensoryMessage); sender.Thing.Eventing.OnCombatRequest(unwieldEvent, EventScope.ParentsDown); if (!unwieldEvent.IsCancelled) { sender.Thing.Eventing.OnCombatEvent(unwieldEvent, EventScope.ParentsDown); } }
/// <summary>Executes the command.</summary> /// <param name="actionInput">The full input specified for executing the command.</param> public override void Execute(ActionInput actionInput) { // Send just one message to the command sender since they know what's going on. IController sender = actionInput.Controller; // Attempt exact ID match var targetPlace = ThingManager.Instance.FindThing(actionInput.Tail); // If input is a simple number, assume we mean a room int roomNum; targetPlace = int.TryParse(actionInput.Tail, out roomNum) ? ThingManager.Instance.FindThing("room/" + roomNum) : ThingManager.Instance.FindThingByName(actionInput.Tail, false, true); if (targetPlace == null) { sender.Write("Room or Entity not found.\n"); return; } if (targetPlace.FindBehavior<RoomBehavior>() == null) { // If the target's parent is a room, go there instead if (targetPlace.Parent != null && targetPlace.Parent.FindBehavior<RoomBehavior>() != null) { targetPlace = targetPlace.Parent; } else { sender.Write("Target is not a room and is not in a room!\n"); return; } } var leaveContextMessage = new ContextualString(sender.Thing, sender.Thing.Parent) { ToOriginator = null, ToReceiver = @"$ActiveThing.Name disappears into nothingness.", ToOthers = @"$ActiveThing.Name disappears into nothingness.", }; var arriveContextMessage = new ContextualString(sender.Thing, targetPlace) { ToOriginator = "You teleport to " + targetPlace.Name + ".", ToReceiver = @"$ActiveThing.Name appears from nothingness.", ToOthers = @"$ActiveThing.Name appears from nothingness.", }; var leaveMessage = new SensoryMessage(SensoryType.Sight, 100, leaveContextMessage); var arriveMessage = new SensoryMessage(SensoryType.Sight, 100, arriveContextMessage); // If we successfully move (IE the move may get cancelled if the user doesn't have permission // to enter a particular location, some other behavior cancels it, etc), then perform a 'look' // command to get immediate feedback about the new location. // @@@ TODO: This should not 'enqueue' a command since, should the player have a bunch of // other commands entered, the 'look' feedback will not immediately accompany the 'goto' // command results like it should. var movableBehavior = sender.Thing.FindBehavior<MovableBehavior>(); if (movableBehavior != null && movableBehavior.Move(targetPlace, sender.Thing, leaveMessage, arriveMessage)) { CommandManager.Instance.EnqueueAction(new ActionInput("look", sender)); } }
/// <summary>Executes the command.</summary> /// <param name="actionInput">The full input specified for executing the command.</param> public override void Execute(ActionInput actionInput) { string div = string.Empty; string mudName = MudEngineAttributes.Instance.MudName; string mudNameLine = " "; string plural = string.Empty; string plural1 = string.Empty; StringBuilder sb = new StringBuilder(); plural1 = "is"; if (PlayerManager.Instance.Players.Count > 1) { plural = "s"; plural1 = "are"; } // TODO: Version, Sort and add by guild/class // div = "<%b%><%green%>" + string.Empty.PadLeft(sender.Entity.Terminal.Width, '~') + "<%n%>"; div = "<%b%><%green%>~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~<%n%>"; mudNameLine += mudName; sb.AppendLine(); sb.AppendLine(div); sb.AppendLine(mudNameLine); sb.AppendLine(div); sb.AppendLine(); sb.AppendLine("The following player" + plural + " " + plural1 + " currently online:"); foreach (PlayerBehavior player in PlayerManager.Instance.Players) { // TODO: I used string literal to handle "" issue is there a neater approach? sb.AppendFormat(@"<%mxpsecureline%><send ""finger {0}|tell {0}"" ""|finger|tell"">{0}</send>", player.Parent.Name); sb.AppendFormat(" - {0}", player.Parent.Name); // Add in AFK message if (player.IsAFK) { sb.Append(" (afk"); if (!string.IsNullOrEmpty(player.AFKReason)) { sb.AppendFormat(": {0}", player.AFKReason); } sb.Append(")"); } // End with a newline char sb.Append("<%nl%>"); } sb.AppendLine(); sb.AppendLine(div); sb.AppendFormat("Counted {0} player{1} online.", PlayerManager.Instance.Players.Count, plural); sb.AppendLine(); sb.AppendLine(div); actionInput.Controller.Write(sb.ToString().TrimEnd(null)); }
/// <summary>Executes the command.</summary> /// <param name="actionInput">The full input specified for executing the command.</param> public override void Execute(ActionInput actionInput) { IController sender = actionInput.Controller; Die die = DiceService.Instance.GetDie(3); // This is how you send text back to the player int height = die.Roll(); sender.Write("Congrats! You've jumped " + height + " feet! You're special boy! This is for testing, so George quits punching me back."); }
/// <summary>Checks against the guards for the command.</summary> /// <param name="actionInput">The full input specified for executing the command.</param> /// <returns>A string with the error message for the user upon guard failure, else null.</returns> public override string Guards(ActionInput actionInput) { string commonFailure = VerifyCommonGuards(actionInput, ActionGuards); if (commonFailure != null) { return commonFailure; } return null; }
/// <summary>Executes the command.</summary> /// <param name="actionInput">The full input specified for executing the command.</param> public override void Execute(ActionInput actionInput) { IController sender = actionInput.Controller; StringBuilder sb = new StringBuilder(); sb.Append("Game time is: "); // @@@ Broken: sb.AppendLine(bridge.World.TimeSystem.Now); sb.Append("Real world server time is: "); sb.AppendLine(DateTime.Now.ToString()); sender.Write(sb.ToString()); }
/// <summary>Checks against the guards for the command.</summary> /// <param name="actionInput">The full input specified for executing the command.</param> /// <returns>A string with the error message for the user upon guard failure, else null.</returns> public override string Guards(ActionInput actionInput) { string commonFailure = VerifyCommonGuards(actionInput, ActionGuards); if (commonFailure != null) { return commonFailure; } // There are currently no arguments nor situations where we expect failure. return null; }
/// <summary>Checks against the guards for the command.</summary> /// <param name="actionInput">The full input specified for executing the command.</param> /// <returns>A string with the error message for the user upon guard failure, else null.</returns> public override string Guards(ActionInput actionInput) { string commonFailure = VerifyCommonGuards(actionInput, ActionGuards); if (commonFailure != null) { return commonFailure; } this.sayText = actionInput.Tail.Trim(); return null; }
/// <summary>Executes the command.</summary> /// <param name="actionInput">The full input specified for executing the command.</param> public override void Execute(ActionInput actionInput) { /* @@@ Add an AltersSensesEffect or whatnot instead of modifying permanent senses! if (sender.Thing.Senses.Contains(SensoryType.Sight)) { sender.Thing.Senses[SensoryType.Sight].Enabled = false; } sender.Write("You blind yourself"); */ }
/// <summary>Executes the command.</summary> /// <param name="actionInput">The full input specified for executing the command.</param> public override void Execute(ActionInput actionInput) { ////target.Effects.AddEffect(new StatEffect("mobility", -2, "", "Your mobility increases"), //// new TimeSpan(0, 1, 0, 0)); ////sender.Thing.Effects.AddEffect(new Unbalance(), new TimeSpan(0, 0, 3)); // @@@ TODO: Should use Request and Event pattern and avoid direct Controller.Writes //var userControlledBehavior = sender.Thing.BehaviorManager.FindFirst<UserControlledBehavior>(); //userControlledBehavior.Controller.Write("You cast a web over " + this.target.Name); //this.target.Controller.Write(sender.Thing.Name + " casts a web over you"); }
/// <summary>Executes the command.</summary> /// <param name="actionInput">The full input specified for executing the command.</param> public override void Execute(ActionInput actionInput) { IController sender = actionInput.Controller; Thing parent = sender.Thing.Parent; // This is to keep track of the previous rooms we've yelled at, to prevent echoes. List<Thing> previousRooms = new List<Thing>(); this.CreateYellEvent(sender.Thing); this.TraverseRoom(parent, actionInput, sender, this.RoomFallOff, previousRooms); }
/// <summary>Creates a scripting command from action input.</summary> /// <param name="actionInput">The action input to transform into a ScriptingCommand instance.</param> /// <returns>A new ScriptingCommand instance for the specified input, if found, else null.</returns> public ScriptingCommand Create(ActionInput actionInput) { // TODO: Build targeting into command selection when there are multiple valid targets; IE if multiple // openable things registered an "open" context command, then if the user said "open door" then we // want to select the context command attached to the closest match for "door" as our command; if // there are still multiple targets, we can start a conflict resolution prompt, etc. Individual non- // context commands may also wish to use such targeting code, so it should be built to be reusable. ScriptingCommand command = TryCreateMasterCommand(actionInput, 0) ?? TryCreateMasterCommand(actionInput, 1) ?? TryCreateContextCommand(actionInput, 0) ?? TryCreateContextCommand(actionInput, 1); if (command == null) { actionInput.Controller.Write(new OutputBuilder().AppendLine(unknownCommandResponse)); } return(command); }
private ScriptingCommand TryCreateMasterCommand(ActionInput actionInput, int lastKeywordIndex) { string commandAlias = GetCommandAlias(actionInput, lastKeywordIndex); // If this isn't actually a command, bail now. ////if (string.IsNullOrEmpty(commandAlias) || !this.masterCommandList.ContainsKey(commandAlias)) if (string.IsNullOrEmpty(commandAlias) || !CommandManager.Instance.MasterCommandList.ContainsKey(commandAlias)) { return(null); } // Create a new instance of the specified GameAction. Command command = CommandManager.Instance.MasterCommandList[commandAlias]; var commandScript = (GameAction)command.Constructor.Invoke(null); // Track the execute and guards delegates of this instance for calling soon, with the user's input. var executeDelegate = new CommandScriptExecuteDelegate(commandScript.Execute); var guardsDelegate = new CommandScriptGuardsDelegate(commandScript.Guards); return(new ScriptingCommand(command.Name, executeDelegate, guardsDelegate, command.SecurityRole, actionInput)); }
private ScriptingCommand TryCreateContextCommand(ActionInput actionInput, int lastKeywordIndex) { string commandAlias = GetCommandAlias(actionInput, lastKeywordIndex); if (string.IsNullOrEmpty(commandAlias)) { return(null); } // Find the first valid command of this name and of applicable context, if any. Thing sender = actionInput.Controller.Thing; var contextCommand = CommandManager.Instance.GetContextCommands(sender, commandAlias).FirstOrDefault(); if (contextCommand == null) { return(null); } var executeDelegate = new CommandScriptExecuteDelegate(contextCommand.CommandScript.Execute); var guardsDelegate = new CommandScriptGuardsDelegate(contextCommand.CommandScript.Guards); return(new ScriptingCommand(contextCommand.CommandKey, executeDelegate, guardsDelegate, SecurityRole.all, actionInput)); }
/// <summary>Try to execute the specified action input as a command.</summary> /// <param name="actionInput">The action input to try to execute.</param> private void TryExecuteAction(ActionInput actionInput) { try { ScriptingCommand command = CommandCreator.Instance.Create(actionInput); if (command == null) { return; } // Verify the user has permissions to use this command. string guardsErrorMessage = CommandGuardHelpers.VerifyCommandPermission(command); if (guardsErrorMessage == null) { guardsErrorMessage = (string)command.GuardsDelegate.DynamicInvoke(actionInput); } // Verify that the other command-specific guards are passed. if (guardsErrorMessage == null) { // Execute the command if we passed all the guards. command.ExecuteDelegate.DynamicInvoke(actionInput); } else { // Otherwise display what went wrong to the user of the action. IController controller = actionInput.Controller; controller.Write(new OutputBuilder().AppendLine(guardsErrorMessage)); } } catch (Exception ex) { // Most of our exceptions should be TargetInvocationExceptions but we're going to // handle them basically the same way as others, except that we only care about the // inner exception (what actually went wrong, since we know we're doing invokes here). if (ex is TargetInvocationException && ex.InnerException != null) { ex = ex.InnerException; } // In order to isolate command-specific issues, we're going to trap the exception, log // the details, and kill that command. (Other commands and the game itself should be // able to continue through such situations.) // Start gathering info, but carefully to avoid causing potential further exceptions here. IController controller = actionInput.Controller; #if DEBUG Thing thing = controller != null ? controller.Thing : null; string thingName = thing != null ? thing.Name : "[null]"; string thingID = thing != null?thing.Id.ToString() : "[null]"; string fullCommand = actionInput != null ? actionInput.FullText : "[null]"; string format = "Exception encountered for command: {1}{0}From thing: {2} (ID: {3}){0}{4}"; string message = string.Format(format, Environment.NewLine, fullCommand, thingName, thingID, ex.ToDeepString()); #endif // If the debugger is attached, we probably want to break now in order to better debug // the issue closer to where it occurred; if your debugger broke here you may want to // look at the stack trace to see where the exception originated. if (Debugger.IsAttached) { string stackTrace = ex.StackTrace; Debugger.Break(); } // TODO: FIX: this.host..UpdateSubSystemHost(this, message); if (controller != null) { #if DEBUG controller.Write(new OutputBuilder().AppendLine(message)); #else controller.Write(new OutputBuilder().AppendLine("An error occured processing your command.")); #endif } } }
/// <summary>Try to execute the specified action input as a command.</summary> /// <param name="actionInput">The action input to try to execute.</param> private void TryExecuteAction(ActionInput actionInput) { Debug.Assert(actionInput != null, "actionInput must be defined."); try { ScriptingCommand command = CommandCreator.Instance.Create(actionInput); if (command == null) { return; } // Verify the user has permissions to use this command. string guardsErrorMessage = CommandGuardHelpers.VerifyCommandPermission(command); if (guardsErrorMessage == null) { guardsErrorMessage = (string)command.GuardsDelegate.DynamicInvoke(actionInput); } // Verify that the other command-specific guards are passed. if (guardsErrorMessage == null) { // Execute the command if we passed all the guards. command.ExecuteDelegate.DynamicInvoke(actionInput); } else { // Otherwise display what went wrong to the issuing session of this action input. // (If there is no such session, such as an AI issuing a malformed action, for now this is just ignored. TODO: Send this issue to server log?) actionInput.Session?.WriteLine(guardsErrorMessage); } } catch (Exception ex) { // Most of our exceptions should be TargetInvocationExceptions but we're going to // handle them basically the same way as others, except that we only care about the // inner exception (what actually went wrong, since we know we're doing invokes here). if (ex is TargetInvocationException && ex.InnerException != null) { ex = ex.InnerException; } // In order to isolate command-specific issues, we're going to trap the exception, log // the details, and kill that command. (Other commands and the game itself should be // able to continue through such situations.) // Start gathering info, but carefully to avoid causing potential further exceptions here. #if DEBUG // TODO: Improve action error output to always provide full details to server log and admin players. // https://github.com/DavidRieman/WheelMUD/issues/136 string thingName = actionInput.Actor?.Name ?? "[null]"; string thingID = actionInput.Actor?.Id.ToString() ?? "[null]"; string fullCommand = actionInput.FullText ?? "[null]"; string format = "Exception encountered for command: {1}{0}From thing: {2} (ID: {3}){0}{4}"; string message = string.Format(format, Environment.NewLine, fullCommand, thingName, thingID, ex.ToDeepString()); #else string message = "An error occurred while processing your command."; #endif actionInput.Session?.WriteLine(message); // If the debugger is attached, we probably want to break now in order to better debug // the issue closer to where it occurred; if your debugger broke here you may want to // look at the stack trace to see where the exception originated. if (Debugger.IsAttached) { string stackTrace = ex.StackTrace; Debugger.Break(); } } }
/// <summary>Place an action on the command queue for execution.</summary> /// <param name="actionInput">The action input to attempt to execute.</param> public void ExecuteAction(ActionInput actionInput) { LastActionInput = actionInput; ActionReceived?.Invoke((IController)this, actionInput); }
/// <summary>Executes the command.</summary> /// <remarks>Verify that the Guards pass first.</remarks> /// <param name="actionInput">The full input specified for executing the command.</param> public abstract void Execute(ActionInput actionInput);
/// <summary>Execute the action.</summary> /// <param name="actionInput">The full input specified for executing the command.</param> public override void Execute(ActionInput actionInput) { // If the user invoked the context command, move them through this exit. exitBehavior.MoveThrough(actionInput.Controller.Thing); }
/// <summary>Guards the command against incorrect usage.</summary> /// <param name="actionInput">The full input specified for executing the command.</param> /// <returns>An error message describing the failure for the user, or null if all guards pass.</returns> public abstract string Guards(ActionInput actionInput);
/// <summary>Called when an action has been received, the manager can then put the action onto the queue.</summary> /// <param name="sender">The entity sending the action.</param> /// <param name="actionInput">The action input to be enqueued.</param> public void OnActionReceived(Thing sender, ActionInput actionInput) { CommandManager.Instance.EnqueueAction(actionInput); }