public void TestOneWayExitBehavior() { // Put the exit in room A only, and register an exit command to travel one way. roomA.Add(exit); exitBehavior.AddDestination("east", roomB.Id); // Ensure the exit is rigged up to the correct location now, but does not work the other way around. Assert.AreSame(exitBehavior.GetDestination(roomA), roomB); Assert.AreSame(exitBehavior.GetDestination(roomA), roomB); Assert.AreNotSame(exitBehavior.GetDestination(roomB), roomA); // Create an unmovable actor, and ensure that said actor cannot move through. actor = new Thing() { Name = "Actor" }; roomA.Add(actor); exitBehavior.MoveThrough(actor); Assert.AreSame(actor.Parent, roomA); // Make the actor movable, and try moving the actor through again. actor.Behaviors.Add(new MovableBehavior()); exitBehavior.MoveThrough(actor); Assert.AreSame(actor.Parent, roomB); // Ensure the actor does not end up in room A if we try to shove the actor through again. exitBehavior.MoveThrough(actor); Assert.AreSame(actor.Parent, roomB); // TODO: Place the actor back in room A, and try using the context command to move it? roomA.Add(actor); }
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 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>Executes the command.</summary> /// <param name="actionInput">The full input specified for executing the command.</param> public override void Execute(ActionInput actionInput) { string itemID = actionInput.Params[0]; IController sender = actionInput.Controller; Thing parent = sender.Thing.Parent; Thing thing = parent.FindChild(t => t.Id == itemID); if (thing == null) { parent = sender.Thing; thing = parent.FindChild(t => t.Id == itemID); if (thing == null) { sender.Write(string.Format("Cannot find {0}.", itemID)); return; } } Thing clonedThing = thing.Clone(); parent.Add(clonedThing); var userControlledBehavior = sender.Thing.Behaviors.FindFirst <UserControlledBehavior>(); userControlledBehavior.Controller.Write("You clone " + thing.Id + ". New item is " + clonedThing.Id + "."); }
// @@@ OpensClosesBehavior needs to listen for movement events and set e.Cancel if the transition object // is closed at the time. /// <summary> /// Move the entity to the specified room. /// </summary> /// <param name="destination"> /// @@@ TODO: The destination to move the entity to; if the destination has an ExitBehavior then this Thing is /// automatically moved to the other destination of the exit (IE an adjacent room, portal destination, /// or inside/outside of a vehicle, et cetera). /// </param> /// <param name="goingVia">The thing we are travelling via (IE an Exit, an Enterable thing, etc.)</param> /// <param name="leavingMessage">A sensory message describing this sort of 'leaving' movement.</param> /// <param name="arrivingMessage">A sensory message describing this sort of 'arriving' movement.</param> /// <returns>True if the entity was successfully moved, else false.</returns> public bool Move(Thing destination, Thing goingVia, SensoryMessage leavingMessage, SensoryMessage arrivingMessage) { Thing actor = this.Parent; Thing goingFrom = actor.Parent; // Prepare events to request and send (if not cancelled). var leaveEvent = new LeaveEvent(actor, goingFrom, destination, goingVia, leavingMessage); var arriveEvent = new ArriveEvent(actor, goingFrom, destination, goingVia, arrivingMessage); // Broadcast the Leave Request first to see if the player is allowed to leave. actor.Eventing.OnMovementRequest(leaveEvent, EventScope.ParentsDown); if (!leaveEvent.IsCancelled) { // Next see if the player is allowed to Arrive at the new location. destination.Eventing.OnMovementRequest(arriveEvent, EventScope.SelfDown); if (!arriveEvent.IsCancelled) { actor.Eventing.OnMovementEvent(leaveEvent, EventScope.ParentsDown); actor.RemoveFromParents(); destination.Add(actor); // @@@ TODO: Ensure these automatically enqueue a save. destination.Eventing.OnMovementEvent(arriveEvent, EventScope.SelfDown); return true; } } return false; }
public void TestMultipleParentingBehavior() { // Verify we can add and retrieve the MultipleParentsBehavior of a Thing. this.child.Behaviors.Add(this.multipleParentsBehavior); Verify.IsTrue(this.child.Behaviors.FindFirst<MultipleParentsBehavior>() == this.multipleParentsBehavior); // Verify it can now be a child of multiple parents, and one of those can be found as the primary Parent. this.parent1.Add(this.child); this.parent2.Add(this.child); Verify.IsTrue(this.parent1.Children.Contains(this.child)); Verify.IsTrue(this.parent2.Children.Contains(this.child)); Verify.IsTrue(this.child.Parent == this.parent1 || this.child.Parent == this.parent2); // Verify we can remove the item from a secondary parent, and still be attached well to the primary. this.parent2.Remove(this.child); Verify.IsTrue(this.parent1.Children.Contains(this.child)); Verify.IsTrue(!this.parent2.Children.Contains(this.child)); Verify.IsTrue(this.child.Parent == this.parent1); this.parent2.Add(this.child); // Verify we can remove the item from a primary parent, and a secondary parent becomes the primary. this.parent1.Remove(this.child); Verify.IsTrue(!this.parent1.Children.Contains(this.child)); Verify.IsTrue(this.parent2.Children.Contains(this.child)); Verify.IsTrue(this.child.Parent == this.parent2); this.parent1.Add(this.child); // Verify we can be attached to more than 2 parents. Thing parent3 = new Thing() { Name = "Thing3", ID = TestThingID.Generate("testthing") }; parent3.Add(this.child); Verify.IsTrue(this.parent1.Children.Contains(this.child)); Verify.IsTrue(this.parent2.Children.Contains(this.child)); Verify.IsTrue(parent3.Children.Contains(this.child)); Verify.IsTrue(this.child.Parent != null); }
/// <summary>Executes the command.</summary> /// <param name="actionInput">The full input specified for executing the command.</param> public override void Execute(ActionInput actionInput) { // TODO: Move item from one owner to another transactionally, if applicable. // TODO: Test, may be broken now... especially for only putting SOME of a stack... thing.Parent.Remove(thing); newParent.Add(thing); actionInput.Controller.Write(new OutputBuilder().AppendLine($"You put {thing.FullName} in {newParent.Name}.")); }
/// <summary>Executes the command.</summary> /// <param name="actionInput">The full input specified for executing the command.</param> public override void Execute(ActionInput actionInput) { // TODO: Move item from one owner to another transactionally, if applicable. // TODO: Single sensory message too? $"You put {thing.FullName} in {newParent.Name}." // TODO: Test, may be broken now... especially for only putting SOME of a stack... if (thing.Parent.Remove(thing)) { newParent.Add(thing); } }
/// <summary>Executes the command.</summary> /// <param name="actionInput">The full input specified for executing the command.</param> public override void Execute(ActionInput actionInput) { // TODO: Move item from one owner to another transactionally, if applicable. // TODO: Test, may be broken now... especially for only putting SOME of a stack... thing.Parent.Remove(thing); newParent.Add(thing); string message = string.Format("You put {0} in {1}", thing.FullName, newParent.Name); actionInput.Controller.Write(message); }
public void TestSingleParentingBehavior() { // Verify that a thing which has not yet been added to a parent, has none. Assert.IsTrue(child.Parent == null); // Verify that a basic thing can be added to a parent correctly. parent1.Add(child); Assert.IsTrue(parent1.Children.Contains(child)); Assert.IsTrue(!parent2.Children.Contains(child)); Assert.IsTrue(child.Parent == parent1); // Verify adding it to a second parent actually reassigns the parent. parent2.Add(child); Assert.IsTrue(parent2.Children.Contains(child)); Assert.IsTrue(!parent1.Children.Contains(child)); Assert.IsTrue(child.Parent == parent2); // Verify removing it from the last parent, cleans up the parent/child relationships. parent2.Remove(child); Assert.IsTrue(!parent1.Children.Contains(child)); Assert.IsTrue(!parent2.Children.Contains(child)); Assert.IsTrue(child.Parent == null); }
public void TestMultipleParentingBehavior() { // Verify we can add and retrieve the MultipleParentsBehavior of a Thing. child.Behaviors.Add(multipleParentsBehavior); Assert.IsTrue(child.Behaviors.FindFirst <MultipleParentsBehavior>() == multipleParentsBehavior); // Verify it can now be a child of multiple parents, and one of those can be found as the primary Parent. parent1.Add(child); parent2.Add(child); Assert.IsTrue(parent1.Children.Contains(child)); Assert.IsTrue(parent2.Children.Contains(child)); Assert.IsTrue(child.Parent == parent1 || child.Parent == parent2); // Verify we can remove the item from a secondary parent, and still be attached well to the primary. parent2.Remove(child); Assert.IsTrue(parent1.Children.Contains(child)); Assert.IsTrue(!parent2.Children.Contains(child)); Assert.IsTrue(child.Parent == parent1); parent2.Add(child); // Verify we can remove the item from a primary parent, and a secondary parent becomes the primary. parent1.Remove(child); Assert.IsTrue(!parent1.Children.Contains(child)); Assert.IsTrue(parent2.Children.Contains(child)); Assert.IsTrue(child.Parent == parent2); parent1.Add(child); // Verify we can be attached to more than 2 parents. Thing parent3 = new Thing() { Name = "Thing3", Id = TestThingID.Generate("testthing") }; parent3.Add(child); Assert.IsTrue(parent1.Children.Contains(child)); Assert.IsTrue(parent2.Children.Contains(child)); Assert.IsTrue(parent3.Children.Contains(child)); Assert.IsTrue(child.Parent != null); }
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(this.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. this.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(this.actingThing); exitBehaviorA.MoveThrough(this.actingThing); Verify.AreSame(roomA, this.actingThing.Parent); roomB.Add(this.actingThing); exitBehaviorB.MoveThrough(this.actingThing); Verify.AreSame(roomB, this.actingThing.Parent); // Ensure that the actingThing can open and move through each openable exit to get between rooms. opensClosesBehaviorB.Open(this.actingThing); exitBehaviorB.MoveThrough(this.actingThing); Verify.AreSame(roomA, this.actingThing.Parent); this.opensClosesBehavior.Open(this.actingThing); exitBehaviorA.MoveThrough(this.actingThing); Verify.AreSame(roomB, this.actingThing.Parent); }
public void Init() { // Create the basic actor instances and behavior for test. witness = new Thing() { Name = "Witness", Id = TestThingID.Generate("testthing") }; stalker1 = new Thing() { Name = "Stalker1", Id = TestThingID.Generate("testthing") }; stalker2 = new Thing() { Name = "Stalker2", Id = TestThingID.Generate("testthing") }; victim1 = new Thing() { Name = "Victim1", Id = TestThingID.Generate("testthing") }; victim2 = new Thing() { Name = "Victim2", Id = TestThingID.Generate("testthing") }; // Set up the rooms. room1 = new Thing() { Name = "Room", Id = TestThingID.Generate("room") }; room2 = new Thing() { Name = "Room 2", Id = TestThingID.Generate("room") }; // Set up an exit connecting the two rooms. exit = new Thing() { Name = "East Exit", Id = TestThingID.Generate("exit") }; var exitBehavior = new ExitBehavior(); ////exitBehavior.AddDestination("west", room1.ID); ////exitBehavior.AddDestination("east", room1.ID); ////exit.BehaviorManager.Add(exitBehavior); room1.Add(exit); room2.Add(exit); // Populate the first room. room1.Add(witness); room1.Add(stalker1); room1.Add(stalker2); room1.Add(victim1); room1.Add(victim2); // Prepare to verify correct eventing occurs. witness.Eventing.MovementRequest += (root, e) => { lastWitnessRequest = e; }; witness.Eventing.MovementEvent += (root, e) => { lastWitnessEvent = e; }; stalker1.Eventing.MovementRequest += (root, e) => { lastStalkerRequest = e; }; stalker1.Eventing.MovementEvent += (root, e) => { lastStalkerEvent = e; }; stalker2.Eventing.MovementRequest += (root, e) => { lastStalkerRequest = e; }; stalker2.Eventing.MovementEvent += (root, e) => { lastStalkerEvent = e; }; victim1.Eventing.MovementRequest += (root, e) => { lastVictimRequest = e; }; victim1.Eventing.MovementEvent += (root, e) => { lastVictimEvent = e; }; victim2.Eventing.MovementRequest += (root, e) => { lastVictimRequest = e; }; victim2.Eventing.MovementEvent += (root, e) => { lastVictimEvent = e; }; }