public void Init() { // Create the basic actor instances and behavior for test. witnessThing = new Thing() { Name = "WitnessThing", Id = TestThingID.Generate("testthing") }; actingThing = new Thing() { Name = "ActingThing", Id = TestThingID.Generate("testthing") }; openableThing = new Thing() { Name = "OpenableThing", Id = TestThingID.Generate("testthing") }; opensClosesBehavior = new OpensClosesBehavior(); // Set up the actors inside another (which we'll call a "room" although it needn't actually be a room). room = new Thing() { Name = "Room", Id = TestThingID.Generate("room") }; room.Add(witnessThing); room.Add(actingThing); room.Add(openableThing); // Prepare to verify correct eventing occurs. witnessThing.Eventing.MiscellaneousRequest += (root, e) => { lastWitnessRequest = e; }; witnessThing.Eventing.MiscellaneousEvent += (root, e) => { lastWitnessEvent = e; }; actingThing.Eventing.MiscellaneousRequest += (root, e) => { lastActorRequest = e; }; actingThing.Eventing.MiscellaneousEvent += (root, e) => { lastActorEvent = e; }; }
public void TestOpeningAndClosingOfLockedAndUnlockedThings() { // Make our lockable thing also openable. var opensClosesBehavior = new OpensClosesBehavior(); this.lockableThing.Behaviors.Add(opensClosesBehavior); this.lockableThing.Behaviors.Add(this.locksUnlocksBehavior); // Verify that the thing is still in the default locked state. Assert.IsTrue(this.locksUnlocksBehavior.IsLocked); // Verify that attempts to open the locked thing do not work. // (Note that adding player-convenience features like automatic unlock attempts on behalf of the // player when trying to open something, depending on their settings or whatnot, may require such // tests to become much more robust here.) opensClosesBehavior.Open(this.actingThing); Assert.IsTrue(this.locksUnlocksBehavior.IsLocked); Assert.IsTrue(!opensClosesBehavior.IsOpen); // Verify that attempts to open an unlocked thing do work though. this.locksUnlocksBehavior.Unlock(this.actingThing); opensClosesBehavior.Open(this.actingThing); Assert.IsTrue(!this.locksUnlocksBehavior.IsLocked); Assert.IsTrue(opensClosesBehavior.IsOpen); // Verify that trying to lock an open thing is either cancelled (leaving it open and unlocked) // or is automatically closed for the actor since the intent could be implied. this.locksUnlocksBehavior.Lock(this.actingThing); bool isClosedAndLocked = !opensClosesBehavior.IsOpen && this.locksUnlocksBehavior.IsLocked; bool isOpenAndUnlocked = opensClosesBehavior.IsOpen && !this.locksUnlocksBehavior.IsLocked; Assert.IsTrue(isClosedAndLocked || isOpenAndUnlocked); }
public void TestOpeningClosingAndMovementForExits() { // Create two one-way exits and two rooms to attach them to. var openableExitA = new Thing() { Name = "OpenableExitA", Id = TestThingID.Generate("testthing") }; var openableExitB = new Thing() { Name = "OpenableExitB", Id = TestThingID.Generate("testthing") }; var roomA = new Thing(new RoomBehavior()) { Name = "Room A", Id = TestThingID.Generate("testroom") }; var roomB = new Thing(new RoomBehavior()) { Name = "Room B", Id = TestThingID.Generate("testroom") }; roomA.Add(openableExitA); roomB.Add(openableExitB); // Attach ExitBehavior and OpensClosesBehaviors in different orders though, to verify in test that // eventing and such work correctly regardless of attachment order. var exitBehaviorA = new ExitBehavior(); var exitBehaviorB = new ExitBehavior(); var opensClosesBehaviorB = new OpensClosesBehavior(); openableExitA.Behaviors.Add(exitBehaviorA); openableExitA.Behaviors.Add(opensClosesBehavior); openableExitB.Behaviors.Add(opensClosesBehaviorB); openableExitB.Behaviors.Add(exitBehaviorB); // Rig up behaviors so the actor can move, and move from one A to B, and from B to A. actingThing.Behaviors.Add(new MovableBehavior()); exitBehaviorA.AddDestination("toB", roomB.Id); exitBehaviorB.AddDestination("toA", roomA.Id); // Ensure that the actingThing cannot move through either exit while it is in default (closed) state. roomA.Add(actingThing); exitBehaviorA.MoveThrough(actingThing); Assert.AreSame(roomA, actingThing.Parent); roomB.Add(actingThing); exitBehaviorB.MoveThrough(actingThing); Assert.AreSame(roomB, actingThing.Parent); // Ensure that the actingThing can open and move through each openable exit to get between rooms. opensClosesBehaviorB.Open(actingThing); exitBehaviorB.MoveThrough(actingThing); Assert.AreSame(roomA, actingThing.Parent); opensClosesBehavior.Open(actingThing); exitBehaviorA.MoveThrough(actingThing); Assert.AreSame(roomB, actingThing.Parent); }
/// <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); } int itemParam = 0; parent = sender.Thing.Parent; if (actionInput.Tail.ToLower().Contains("from")) { // Find the from keyword in the params. int itemMarker = 0; for (int i = 0; i < actionInput.Params.Length; i++) { if (actionInput.Params[i].ToLower() == "from") { itemMarker = i; } } // Destination container for (int j = itemParam; j < itemMarker; j++) { destinationContainerName += actionInput.Params[j] + ' '; } destinationContainerName = destinationContainerName.Trim(); // Source Container name is everything from the marker to the end. sourceContainerName = string.Empty; for (int i = itemMarker + 1; i < actionInput.Params.Length; i++) { sourceContainerName += actionInput.Params[i] + ' '; } sourceContainerName = sourceContainerName.Trim(); // Rule: Do we have an item matching the one specified in our inventory? // If not then does the room have a container with the name. // TODO: Fix: This Find pattern is probably broken... destinationContainer = sender.Thing.Children.Find(t => t.Name == destinationContainerName.ToLower()); if (destinationContainer == null) { destinationContainer = parent.Children.Find(t => t.Name == destinationContainerName.ToLower()); if (destinationContainer == null) { return("You cannot see " + destinationContainerName); } } // Rule: Is the item specified as a container actually a container? this.containerBehavior = destinationContainer.Behaviors.FindFirst <ContainerBehavior>(); if (this.containerBehavior == null) { return(destinationContainerName + " is not able to hold things."); } else { var holdsLiquidBehavior = destinationContainer.Behaviors.FindFirst <HoldsLiquidBehavior>(); if (holdsLiquidBehavior == null) { return(string.Format( "It does not appear that the {0} will hold liquid.", destinationContainerName)); } } // Rule: Is the item open? var openableBehavior = destinationContainer.Behaviors.FindFirst <OpensClosesBehavior>(); if (openableBehavior != null && !openableBehavior.IsOpen) { return(string.Format("You cannot fill the {0} as it is closed.", destinationContainerName)); } // Rule: Do we have an item matching the one specified in our inventory? // If not then does the room have a container with the name. // TODO: Investigate; This search method is probably broken. sourceContainer = sender.Thing.Children.Find(t => t.Name == sourceContainerName.ToLower()); if (sourceContainer == null) { sourceContainer = parent.Children.Find(t => t.Name == sourceContainerName.ToLower()); if (sourceContainer == null) { return("You cannot see " + sourceContainerName); } } // Rule: Is the item specified as a container actually a container? ContainerBehavior containerBehavior = sourceContainer.Behaviors.FindFirst <ContainerBehavior>(); if (containerBehavior == null) { return(string.Format("The {0} does not hold anything to fill the {1} with.", sourceContainerName, destinationContainerName)); } // TODO: HoldsLiquidBehavior? // Rule: Is the item open? OpensClosesBehavior opensClosesBehavior = sourceContainer.Behaviors.FindFirst <OpensClosesBehavior>(); if (!opensClosesBehavior.IsOpen) { return(string.Format("You cannot fill from the {0} as it is closed.", sourceContainerName)); } } else { return("You must use \"from\" to specify the source, as in, \"fill wine skin from fountain\"."); } return(null); }