private static VertexColorInfo CalculateVertexLight(VoxelHandle Vox, VoxelVertex Vertex, ChunkManager chunks) { int neighborsEmpty = 0; int neighborsChecked = 0; var color = new VertexColorInfo(); color.DynamicColor = 0; color.SunColor = 0; foreach (var c in VoxelHelpers.EnumerateVertexNeighbors(Vox.Coordinate, Vertex)) { var v = new VoxelHandle(chunks.ChunkData, c); if (!v.IsValid) { continue; } color.SunColor += v.SunColor; if (!v.IsEmpty || !v.IsExplored) { if (v.Type.EmitsLight) { color.DynamicColor = 255; } neighborsEmpty += 1; neighborsChecked += 1; } else { neighborsChecked += 1; } } float proportionHit = (float)neighborsEmpty / (float)neighborsChecked; color.AmbientColor = (int)Math.Min((1.0f - proportionHit) * 255.0f, 255); color.SunColor = (int)Math.Min((float)color.SunColor / (float)neighborsChecked, 255); return(color); }
private Vector3 ProjectToSurface(Vector3 pos) { var vox = VoxelHelpers.FindFirstVisibleVoxelOnRay(World.ChunkManager, new Vector3(pos.X, World.WorldSizeInVoxels.Y - 1, pos.Z), new Vector3(pos.X, 0, pos.Z)); if (!vox.IsValid) { return(pos); } var diffY = (vox.WorldPosition.Y + 0.5f) - pos.Y; if (Math.Abs(diffY) > 10) { diffY = Math.Sign(diffY) * 10; } return(new Vector3(pos.X, pos.Y + diffY, pos.Z)); }
public Flag(ComponentManager Manager, Vector3 position, CompanyInformation logo) : base(Manager, "Flag", Matrix.CreateTranslation(position), new Vector3(1.0f, 1.0f, 1.0f), Vector3.Zero) { this.Logo = logo; Tags.Add("Flag"); var voxelUnder = VoxelHelpers.FindFirstVoxelBelow(new VoxelHandle( Manager.World.ChunkManager.ChunkData, GlobalVoxelCoordinate.FromVector3(position))); if (voxelUnder.IsValid) { AddChild(new VoxelListener(Manager, Manager.World.ChunkManager, voxelUnder)); } CollisionType = CollisionManager.CollisionType.Static; CreateCosmeticChildren(Manager); }
public virtual void OrientToWalls() { Orient(0); var curr = new VoxelHandle(Manager.World.ChunkManager.ChunkData, GlobalVoxelCoordinate.FromVector3(LocalTransform.Translation)); if (curr.IsValid) { foreach (var n in VoxelHelpers.EnumerateManhattanNeighbors2D(curr.Coordinate)) { var v = new VoxelHandle(World.ChunkManager.ChunkData, n); if (v.IsValid && !v.IsEmpty) { Vector3 diff = n.ToVector3() - curr.WorldPosition; Orient((float)Math.Atan2(diff.X, diff.Z)); break; } } } }
public Bed(ComponentManager manager, Vector3 position) : base(manager, "Bed", Matrix.CreateTranslation(position), new Vector3(1.5f, 0.5f, 0.75f), new Vector3(-0.5f + 1.5f * 0.5f, -0.5f + 0.25f, -0.5f + 0.75f * 0.5f)) { Tags.Add("Bed"); CollisionType = CollisionManager.CollisionType.Static; var voxelUnder = VoxelHelpers.FindFirstVoxelBelow(new VoxelHandle( manager.World.ChunkManager.ChunkData, GlobalVoxelCoordinate.FromVector3(position))); if (voxelUnder.IsValid) { AddChild(new VoxelListener(manager, manager.World.ChunkManager, voxelUnder)); } CreateCosmeticChildren(manager); OrientToWalls(); }
public override Feasibility IsFeasible(Creature agent) { if (!agent.Stats.IsTaskAllowed(Task.TaskCategory.Dig)) { return(Feasibility.Infeasible); } if (!VoxelToKill.IsValid || VoxelToKill.IsEmpty || VoxelToKill.Health <= 0) { return(Feasibility.Infeasible); } if (agent.AI.Status.IsAsleep) { return(Feasibility.Infeasible); } return(agent.Faction.Designations.IsVoxelDesignation(VoxelToKill, DesignationType.Dig) && !VoxelHelpers.VoxelIsCompletelySurrounded(VoxelToKill) ? Feasibility.Feasible : Feasibility.Infeasible); }
public void CheckForLavaAndWater(Body Body, DwarfTime gameTime, ChunkManager chunks) { foreach (var coordinate in VoxelHelpers.EnumerateCoordinatesInBoundingBox(Body.BoundingBox)) { var voxel = new VoxelHandle(chunks.ChunkData, coordinate); if (!voxel.IsValid || voxel.LiquidLevel == 0) { continue; } if (voxel.LiquidType == LiquidType.Lava) { Heat += 100.0f; } else if (voxel.LiquidType == LiquidType.Water) { Heat = Math.Max(0.0f, Heat - 100.0f); } } }
public static bool BreadthFirstSearch( ChunkData Data, GlobalVoxelCoordinate Start, float Radius, Func <GlobalVoxelCoordinate, bool> IsGoal, out GlobalVoxelCoordinate Result) { var queue = new Queue <GlobalVoxelCoordinate>(); var visited = new HashSet <GlobalVoxelCoordinate>(); var radiusSquared = Radius * Radius; queue.Enqueue(Start); visited.Add(Start); while (queue.Count > 0) { var current = queue.Dequeue(); if (IsGoal(current)) { Result = current; return(true); } var delta = current.ToVector3() - Start.ToVector3(); if (delta.LengthSquared() < radiusSquared) { foreach (var neighbor in VoxelHelpers.EnumerateManhattanNeighbors(current)) { if (!visited.Contains(neighbor)) { visited.Add(neighbor); queue.Enqueue(neighbor); } } } } Result = new GlobalVoxelCoordinate(0, 0, 0); return(false); }
public Chair(ComponentManager manager, Vector3 position) : base(manager, "Chair", Matrix.Identity, new Vector3(1.0f, 1.0f, 1.0f), Vector3.Zero) { var matrix = Matrix.CreateRotationY((float)Math.PI * 0.5f); matrix.Translation = position - new Vector3(0, 0.22f, 0); LocalTransform = matrix; Initialize(Manager); CreateCosmeticChildren(Manager); var voxelUnder = VoxelHelpers.FindFirstVoxelBelow(new VoxelHandle( manager.World.ChunkManager.ChunkData, GlobalVoxelCoordinate.FromVector3(position))); if (voxelUnder.IsValid) { AddChild(new VoxelListener(manager, manager.World.ChunkManager, voxelUnder)); } }
override public void Update(DwarfTime gameTime, ChunkManager chunks, Camera camera) { base.Update(gameTime, chunks, camera); if (!Active) { return; } SenseTimer.Update(gameTime); if (SenseTimer.HasTriggered) { Creatures.Clear(); var myRoot = GetRoot(); foreach (var body in Manager.World.EnumerateIntersectingObjects(BoundingBox, b => b.Active && !Object.ReferenceEquals(b, myRoot) && b.IsRoot())) { if (body.GetComponent <Creature>().HasValue(out var minion)) { float dist = (body.Position - GlobalTransform.Translation).LengthSquared(); if (dist > SenseRadius) { continue; } if (CheckLineOfSight && VoxelHelpers.DoesRayHitSolidVoxel(Manager.World.ChunkManager, Position, body.Position)) { continue; } Creatures.Add(minion); } } } Creatures.RemoveAll(ai => ai.IsDead); }
public static bool VoxelIsCompletelySurrounded(VoxelHandle V) { if (V.Chunk == null) { return(false); } foreach (var neighborCoordinate in VoxelHelpers.EnumerateManhattanNeighbors(V.Coordinate)) { var voxelHandle = new VoxelHandle(V.Chunk.Manager.ChunkData, neighborCoordinate); if (!voxelHandle.IsValid) { return(false); } if (voxelHandle.IsEmpty) { return(false); } } return(true); }
public static bool VoxelIsSurroundedByWater(VoxelHandle V) { if (V.Chunk == null) { return(false); } foreach (var neighborCoordinate in VoxelHelpers.EnumerateManhattanNeighbors(V.Coordinate)) { var voxelHandle = new VoxelHandle(V.Chunk.Manager, neighborCoordinate); if (!voxelHandle.IsValid) { return(false); } if (voxelHandle.IsEmpty && voxelHandle.LiquidLevel < 4) { return(false); } } return(true); }
public AddDesignationResult AddVoxelDesignation(VoxelHandle Voxel, DesignationType Type, Object Tag, Task Task) { lock (designationLock) { var key = VoxelHelpers.GetVoxelQuickCompare(Voxel); List <VoxelDesignation> list = null; if (VoxelDesignations.ContainsKey(key)) { list = VoxelDesignations[key]; } else { list = new List <VoxelDesignation>(); VoxelDesignations.Add(key, list); } var existingEntry = list.FirstOrDefault(d => d.Type == Type); if (existingEntry != null) { existingEntry.Tag = Tag; return(AddDesignationResult.AlreadyExisted); } else { list.Add(new VoxelDesignation { Voxel = Voxel, Type = Type, Tag = Tag, Task = Task }); Voxel.Invalidate(); return(AddDesignationResult.Added); } } }
public bool CollidesWithChunks(ChunkManager chunks, Vector3 pos, bool applyForce, bool allowInvisible, float size = 0.5f, float height = 2.0f) { var box = new BoundingBox(pos - new Vector3(size, height * 0.5f, size), pos + new Vector3(size, height * 0.5f, size)); bool gotCollision = false; foreach (var v in VoxelHelpers.EnumerateCube(GlobalVoxelCoordinate.FromVector3(pos)) .Select(n => new VoxelHandle(chunks, n))) { if (!v.IsValid) { continue; } if (v.IsEmpty) { continue; } if (!allowInvisible && !v.IsVisible) { continue; } var voxAABB = v.GetBoundingBox(); if (box.Intersects(voxAABB)) { gotCollision = true; if (applyForce) { Collide(v, box, voxAABB); } else { return(true); } } } return(gotCollision); }
public static bool DoesVoxelHaveVisibleSurface(WorldManager World, VoxelHandle V) { if (!V.IsValid) { return(false); } if (V.Coordinate.Y >= World.Renderer.PersistentSettings.MaxViewingLevel) { return(false); } if (V.IsEmpty) { return(false); } if (V.Coordinate.Y == World.Renderer.PersistentSettings.MaxViewingLevel - 1) { return(true); } if (V.Coordinate.Y == World.WorldSizeInVoxels.Y - 1) { return(true); } foreach (var neighborCoordinate in VoxelHelpers.EnumerateManhattanNeighbors(V.Coordinate)) { var neighbor = new VoxelHandle(World.ChunkManager, neighborCoordinate); if (!neighbor.IsValid) { return(true); } if (neighbor.IsEmpty && neighbor.IsExplored) { return(true); } } return(false); }
public static bool DoesVoxelHaveVisibleSurface(WorldManager World, VoxelHandle V) { if (!V.IsValid) { return(false); } if (V.Coordinate.Y >= World.Master.MaxViewingLevel) { return(false); } if (V.IsEmpty) { return(false); } if (V.Coordinate.Y == World.Master.MaxViewingLevel - 1) { return(true); } if (V.Coordinate.Y == VoxelConstants.ChunkSizeY - 1) { return(true); } foreach (var neighborCoordinate in VoxelHelpers.EnumerateManhattanNeighbors(V.Coordinate)) { var neighbor = new VoxelHandle(World.ChunkManager.ChunkData, neighborCoordinate); if (!neighbor.IsValid) { return(true); } if (neighbor.IsEmpty && neighbor.IsExplored) { return(true); } } return(false); }
public override void OnVoxelsSelected(List <VoxelHandle> voxels, InputManager.MouseButton button) { var parentTask = Player.TaskManager.EnumerateTasks().OfType <GuardZoneTask>().FirstOrDefault(); if (parentTask == null) { parentTask = new GuardZoneTask(); Player.TaskManager.AddTask(parentTask); } if (button == InputManager.MouseButton.Left) { foreach (var v in voxels.Where(v => v.IsValid && !v.IsEmpty)) { var key = VoxelHelpers.GetVoxelQuickCompare(v); if (Player.Faction.GuardedVoxels.ContainsKey(key)) { return; } Player.Faction.Designations.AddVoxelDesignation(v, DesignationType.Guard, null, new GuardZoneTask.DesignationProxyTask(parentTask, v)); Player.Faction.GuardedVoxels.Add(key, v); } OnConfirm(Faction.FilterMinionsWithCapability(Player.World.Master.SelectedMinions, Task.TaskCategory.Gather)); } else { foreach (var v in voxels.Where(v => v.IsValid && !v.IsEmpty)) { var des = Player.Faction.Designations.GetVoxelDesignation(v, DesignationType.Guard); if (des != null) { Player.TaskManager.CancelTask(des.Task); } } } }
public IEnumerable <VoxelHandle> Select(BoundingBox buffer, Vector3 start, Vector3 end) { switch (Brush) { case VoxelBrush.Box: return(VoxelHelpers.EnumerateCoordinatesInBoundingBox(buffer) .Select(c => new VoxelHandle(Chunks.ChunkData, c)) .Where(v => v.IsValid)); case VoxelBrush.Shell: return(EnumerateShell(buffer) .Select(c => new VoxelHandle(Chunks.ChunkData, c)) .Where(v => v.IsValid)); case VoxelBrush.Stairs: return(EnumerateStairVoxels(buffer, start, end, SelectionType == VoxelSelectionType.SelectFilled) .Select(c => new VoxelHandle(Chunks.ChunkData, c)) .Where(v => v.IsValid)); default: throw new InvalidOperationException("VoxelBrush has invalid value"); } }
private static BoxTransition ComputeTransitions( ChunkData Data, VoxelHandle V, VoxelType Type) { if (Type.Transitions == VoxelType.TransitionType.Horizontal) { var value = ComputeTransitionValueOnPlane( VoxelHelpers.EnumerateManhattanNeighbors2D(V.Coordinate) .Select(c => new VoxelHandle(Data, c)), Type); return(new BoxTransition() { Top = (TransitionTexture)value }); } else { var transitionFrontBack = ComputeTransitionValueOnPlane( VoxelHelpers.EnumerateManhattanNeighbors2D(V.Coordinate, ChunkManager.SliceMode.Z) .Select(c => new VoxelHandle(Data, c)), Type); var transitionLeftRight = ComputeTransitionValueOnPlane( VoxelHelpers.EnumerateManhattanNeighbors2D(V.Coordinate, ChunkManager.SliceMode.X) .Select(c => new VoxelHandle(Data, c)), Type); return(new BoxTransition() { Front = (TransitionTexture)transitionFrontBack, Back = (TransitionTexture)transitionFrontBack, Left = (TransitionTexture)transitionLeftRight, Right = (TransitionTexture)transitionLeftRight }); } }
public override MaybeNull <Act> CreateScript(Creature creature) { var above = VoxelHelpers.GetVoxelAbove(creature.Physics.CurrentVoxel); if ((above.IsValid && above.LiquidLevel > 0) || creature.AI.Movement.CanFly) { return(new Wrap(() => SwimUp(creature)) { Name = "Swim up" }); } Act fallback = null; if (creature.World.EnumerateZones().Count() == 0) { fallback = new LongWanderAct(creature.AI) { PathLength = 20, Radius = 30, Is2D = true, Name = "Randomly wander." } } ; else { fallback = new GoToZoneAct(creature.AI, Datastructures.SelectRandom(creature.World.EnumerateZones())); } return(new Select(new Sequence(new Wrap(() => FindLandEnum(creature)) { Name = "Search for land." }, new GoToNamedVoxelAct("Land", PlanAct.PlanType.Into, creature.AI)), fallback) { Name = "Find Land" }); }
// This is a more expensive terrain collision method that has fewer problems than the box-collision method. // It works by stepping the physics object along the gradient of the terrain field until it is out of collision. // It will only work if the object is on the edge of the terrain (i.e exactly one voxel in or less). public void ResolveTerrainCollisionGradientMethod() { Vector3 localGradient = Vector3.Zero; var p = Position; localGradient = Position - CurrentVoxel.Center; localGradient += Velocity; // Prefer to push in the direction we're already going. foreach (var v in VoxelHelpers.EnumerateManhattanNeighbors(CurrentVoxel.Coordinate)) { var handle = new VoxelHandle(World.ChunkManager, v); var sign = (handle.IsValid && handle.IsEmpty) ? -1 : 1; localGradient += (p - handle.Center) * sign; } p += localGradient * 0.01f; Matrix m = LocalTransform; m.Translation = p; LocalTransform = m; Velocity += localGradient * 0.01f; PropogateTransforms(); UpdateBoundingBox(); }
public override void Update(DwarfTime gameTime, ChunkManager chunks, Camera camera) { UpdateTimer.Update(gameTime); if (UpdateTimer.HasTriggered) { Body p = (Body)Parent; var voxelBelow = new VoxelHandle(chunks.ChunkData, GlobalVoxelCoordinate.FromVector3(p.GlobalTransform.Translation + Vector3.Down * 0.25f)); if (voxelBelow.IsValid) { var shadowTarget = VoxelHelpers.FindFirstVoxelBelow(voxelBelow); if (shadowTarget.IsValid) { var h = shadowTarget.Coordinate.Y + 1; Vector3 pos = p.GlobalTransform.Translation; pos.Y = h; float scaleFactor = GlobalScale / (Math.Max((p.GlobalTransform.Translation.Y - h) * 0.25f, 1)); Matrix newTrans = OriginalTransform; newTrans *= Matrix.CreateScale(scaleFactor); newTrans.Translation = (pos - p.GlobalTransform.Translation) + new Vector3(0.0f, 0.1f, 0.0f); Tint = new Color(Tint.R, Tint.G, Tint.B, (int)(scaleFactor * 255)); Matrix globalRotation = p.GlobalTransform; globalRotation.Translation = Vector3.Zero; LocalTransform = newTrans * Matrix.Invert(globalRotation); } } UpdateTimer.HasTriggered = false; } base.Update(gameTime, chunks, camera); }
public List <Body> GenerateRandomSpawn(int numCreatures, Vector3 position) { if (Race.CreatureTypes.Count == 0) { return(new List <Body>()); } List <Body> toReturn = new List <Body>(); for (int i = 0; i < numCreatures; i++) { string creature = Race.CreatureTypes[MathFunctions.Random.Next(Race.CreatureTypes.Count)]; Vector3 offset = MathFunctions.RandVector3Cube() * 2; var voxelUnder = VoxelHelpers.FindFirstVoxelBelowIncludeWater(new VoxelHandle( World.ChunkManager.ChunkData, GlobalVoxelCoordinate.FromVector3(position + offset))); if (voxelUnder.IsValid) { var body = EntityFactory.CreateEntity <Body>(creature, voxelUnder.WorldPosition + new Vector3(0.5f, 1, 0.5f)); var ai = body.EnumerateAll().OfType <CreatureAI>().FirstOrDefault(); if (ai != null) { ai.Faction.Minions.Remove(ai); Minions.Add(ai); ai.Faction = this; ai.Creature.Allies = Name; } toReturn.Add(body); } } return(toReturn); }
public List <GameComponent> GenerateRandomSpawn(int numCreatures, Vector3 position) { var r = new List <GameComponent>(); if (Race.HasValue(out var race)) { if (race.CreatureTypes.Count == 0) { return(r); } for (int i = 0; i < numCreatures; i++) { var creature = race.CreatureTypes.SelectRandom(); var offset = MathFunctions.RandVector3Cube() * 2; var voxelUnder = VoxelHelpers.FindFirstVoxelBelowIncludingWater(World.ChunkManager.CreateVoxelHandle(GlobalVoxelCoordinate.FromVector3(position + offset))); if (voxelUnder.IsValid) { var body = EntityFactory.CreateEntity <GameComponent>(creature, voxelUnder.WorldPosition + new Vector3(0.5f, 1, 0.5f)); var ai = body.EnumerateAll().OfType <CreatureAI>().FirstOrDefault(); if (ai != null) { ai.Faction.Minions.Remove(ai); Minions.Add(ai); ai.Creature.Faction = this; } r.Add(body); } } } return(r); }
private void HandleMouseButton(ButtonState ButtonState, VoxelHandle underMouse, bool newVoxel, bool altPressed, ref bool ButtonPressed, InputManager.MouseButton Button) { // If the left mouse button is pressed, update the slection buffer. if (ButtonPressed) { // On release, select voxels. if (ButtonState == ButtonState.Released) { ReleaseSound.Play(World.Renderer.CursorLightPos); ButtonPressed = false; if (SelectionBuffer.Count > 0) { var t = new List <VoxelHandle>(SelectionBuffer); SelectionBuffer.Clear(); Selected.Invoke(t, Button); } BoxYOffset = 0; PrevBoxYOffsetInt = 0; } // Otherwise, update the selection buffer else { if (SelectionBuffer.Count == 0) { FirstVoxel = underMouse; SelectionBuffer.Add(underMouse); } else { SelectionBuffer.Clear(); SelectionBuffer.Add(FirstVoxel); SelectionBuffer.Add(underMouse); BoundingBox buffer = GetSelectionBox(); // Update the selection box to account for offsets from mouse wheel. if (BoxYOffset > 0) { buffer.Max.Y = MathFunctions.Clamp(buffer.Max.Y + (int)BoxYOffset, 0, World.WorldSizeInVoxels.Y - 1); } else if (BoxYOffset < 0) { buffer.Min.Y = MathFunctions.Clamp(buffer.Min.Y - (int)BoxYOffset, 0, World.WorldSizeInVoxels.Y - 1); } SelectionBuffer = Select(buffer, FirstVoxel.WorldPosition, underMouse.WorldPosition).ToList(); if (!altPressed && Brush.CullUnseenVoxels && SelectionType == VoxelSelectionType.SelectFilled) { SelectionBuffer.RemoveAll(v => { if (v.Equals(underMouse)) { return(false); } if (World.PersistentData.Designations.IsVoxelDesignation(v, DesignationType.Put)) { return(false); // Treat put designations as solid. } return(!VoxelHelpers.DoesVoxelHaveVisibleSurface(World, v)); }); } if (newVoxel) { DragSound.Play(World.Renderer.CursorLightPos, SelectionBuffer.Count / 20.0f); Dragged.Invoke(SelectionBuffer, Button); } } } } // If the mouse was not previously pressed, but is now pressed, then notify us of that. else if (ButtonState == ButtonState.Pressed) { ClickSound.Play(World.Renderer.CursorLightPos);; ButtonPressed = true; BoxYOffset = 0; PrevBoxYOffsetInt = 0; } }
public IEnumerable <Status> PerformStep(MoveAction Step) { var actionSpeed = GetAgentSpeed(Step.MoveType); switch (Step.MoveType) { #region Ride Elevator case MoveType.RideElevator: CleanupMinecart(); var shafts = Step.DestinationState.Tag as Elevators.ElevatorMoveState; if (shafts == null || shafts.Entrance == null || shafts.Entrance.IsDead || shafts.Exit == null || shafts.Exit.IsDead) { yield return(Status.Fail); } var shaft = shafts.Entrance.Shaft; if (shaft == null || shaft.Invalid) { yield return(Status.Fail); } if (!shaft.EnqueuDwarf(Agent, shafts)) { yield return(Status.Fail); } while (!shaft.ReadyToBoard(Agent)) { if (DeltaTime > 30.0f) { yield return(Status.Fail); // We waited too long. } if (shaft.Invalid) { yield return(Status.Fail); } SetCharacterMode(CharacterMode.Idle); if (Debugger.Switches.DebugElevators) { Drawer3D.DrawBox(shafts.Entrance.GetBoundingBox(), Color.Red, 0.1f, false); Drawer3D.DrawBox(shafts.Exit.GetBoundingBox(), Color.Red, 0.1f, false); Drawer3D.DrawBox(Step.DestinationVoxel.GetBoundingBox(), Color.Red, 0.1f, false); } yield return(Status.Running); } DeltaTime = 0; foreach (var bit in Translate(Agent.Position, GetPathPoint(shafts.Entrance.GetContainingVoxel()), actionSpeed)) { if (shaft.Invalid) { yield return(Status.Fail); } shaft.WaitForMe(Agent); SetCharacterMode(CharacterMode.Walking); if (Debugger.Switches.DebugElevators) { Drawer3D.DrawBox(shafts.Entrance.GetBoundingBox(), Color.Green, 0.1f, false); Drawer3D.DrawBox(shafts.Exit.GetBoundingBox(), Color.Green, 0.1f, false); Drawer3D.DrawBox(Step.DestinationVoxel.GetBoundingBox(), Color.Green, 0.1f, false); } yield return(Status.Running); } shaft.StartMotion(Agent); var grav = Creature.Physics.Gravity; //Creature.Physics.Gravity = Vector3.Zero; while (!shaft.AtDestination(Agent)) { if (shaft.Invalid) { yield return(Status.Fail); } SetCharacterMode(CharacterMode.Idle); if (Debugger.Switches.DebugElevators) { Drawer3D.DrawBox(shafts.Entrance.GetBoundingBox(), Color.Red, 0.1f, false); Drawer3D.DrawBox(shafts.Exit.GetBoundingBox(), Color.Red, 0.1f, false); Drawer3D.DrawBox(Step.DestinationVoxel.GetBoundingBox(), Color.Red, 0.1f, false); } yield return(Status.Running); } DeltaTime = 0; foreach (var bit in Translate(Agent.Physics.LocalPosition, GetPathPoint(Step.DestinationVoxel), actionSpeed)) { if (shaft.Invalid) { yield return(Status.Fail); } shaft.WaitForMe(Agent); SetCharacterMode(CharacterMode.Walking); if (Debugger.Switches.DebugElevators) { Drawer3D.DrawBox(shafts.Entrance.GetBoundingBox(), Color.Green, 0.1f, false); Drawer3D.DrawBox(shafts.Exit.GetBoundingBox(), Color.Green, 0.1f, false); Drawer3D.DrawBox(Step.DestinationVoxel.GetBoundingBox(), Color.Green, 0.1f, false); } yield return(Status.Running); } Creature.Physics.Gravity = grav; shaft.Done(Agent); break; #endregion case MoveType.EnterVehicle: Creature.NoiseMaker.MakeNoise("Jump", Agent.Position, false); foreach (var bit in Jump(GetPathPoint(Step.SourceVoxel), GetPathPoint(Step.DestinationVoxel), Step.DestinationVoxel.Center - Step.SourceVoxel.Center, actionSpeed, 1.5f)) { SetCharacterMode(Creature.Physics.Velocity.Y > 0 ? CharacterMode.Jumping : CharacterMode.Falling); yield return(Status.Running); } DeltaTime = 0.0f; SetupMinecart(); break; case MoveType.ExitVehicle: CleanupMinecart(); SetAgentTranslation(GetPathPoint(Step.DestinationVoxel)); break; case MoveType.RideVehicle: SetupMinecart(); var rail = Step.SourceState.Rail; if (rail == null) { yield return(Status.Fail); } var rideTime = 1.0f / actionSpeed; while (DeltaTime < rideTime) { var pos = rail.InterpolateSpline(DeltaTime / rideTime, Step.SourceVoxel.WorldPosition, Step.DestinationVoxel.WorldPosition); var transform = Agent.Physics.LocalTransform; transform.Translation = pos + Vector3.Up * 0.5f; Agent.Physics.LocalTransform = transform; Agent.Physics.Velocity = GetPathPoint(Step.DestinationVoxel) - GetPathPoint(Step.SourceVoxel); SetCharacterMode(CharacterMode.Minecart); transform.Translation = pos + Vector3.Up * -0.1f; if (Minecart != null) { Minecart.LocalTransform = transform; } yield return(Status.Running); } DeltaTime -= rideTime; break; case MoveType.Walk: // Todo: Fail if distance is too great. CleanupMinecart(); foreach (var bit in Translate(Agent.Position, GetPathPoint(Step.DestinationVoxel), actionSpeed)) { SetCharacterMode(CharacterMode.Walking); yield return(Status.Running); } break; case MoveType.Swim: CleanupMinecart(); foreach (var bit in Translate(Agent.Position, GetPathPoint(Step.DestinationVoxel), actionSpeed)) { Creature.NoiseMaker.MakeNoise("Swim", Agent.Position, true); SetCharacterMode(CharacterMode.Swimming); yield return(Status.Running); } break; case MoveType.Jump: { CleanupMinecart(); Creature.NoiseMaker.MakeNoise("Jump", Agent.Position, false); var dest = GetPathPoint(Step.DestinationVoxel); var above = VoxelHelpers.GetVoxelAbove(Step.SourceVoxel); if (above.IsValid && !above.IsEmpty) { yield return(Status.Fail); } foreach (var bit in Jump(Agent.Position, dest, dest - Agent.Position, actionSpeed / 2.0f, 0.0f)) { Creature.Physics.CollisionType = CollisionType.None; Creature.OverrideCharacterMode = false; SetCharacterMode(Creature.Physics.Velocity.Y > 0 ? CharacterMode.Jumping : CharacterMode.Falling); yield return(Status.Running); } SetAgentTranslation(dest); break; } case MoveType.HighJump: { CleanupMinecart(); Creature.NoiseMaker.MakeNoise("Jump", Agent.Position, false); var dest = GetPathPoint(Step.DestinationVoxel); var above = VoxelHelpers.GetVoxelAbove(Step.SourceVoxel); if (above.IsValid && !above.IsEmpty) { yield return(Status.Fail); } foreach (var bit in Jump(Agent.Position, dest, dest - Agent.Position, actionSpeed / 2.0f, 1.5f)) { Creature.Physics.CollisionType = CollisionType.None; Creature.OverrideCharacterMode = false; SetCharacterMode(Creature.Physics.Velocity.Y > 0 ? CharacterMode.Jumping : CharacterMode.Falling); yield return(Status.Running); } SetAgentTranslation(dest); break; } case MoveType.Fall: CleanupMinecart(); foreach (var bit in Translate(Agent.Position, GetPathPoint(Step.DestinationVoxel), actionSpeed)) { SetCharacterMode(CharacterMode.Falling); yield return(Status.Running); } break; case MoveType.Climb: CleanupMinecart(); DeltaTime = 0.0f; foreach (var bit in Translate(GetPathPoint(Step.SourceVoxel), GetPathPoint(Step.DestinationVoxel), actionSpeed)) { if (Step.InteractObject == null || Step.InteractObject.IsDead) { yield return(Status.Fail); } if (DeltaTime - LastNoiseTime > 1.0f) { Creature.NoiseMaker.MakeNoise("Climb", Agent.Position, false); LastNoiseTime = DeltaTime; } SetCharacterMode(CharacterMode.Climbing); yield return(Status.Running); } break; case MoveType.ClimbWalls: CleanupMinecart(); DeltaTime = 0.0f; foreach (var bit in Translate(GetPathPoint(Step.SourceVoxel), GetPathPoint(Step.DestinationVoxel), actionSpeed)) { if (DeltaTime - LastNoiseTime > 1.0f) { Creature.NoiseMaker.MakeNoise("Climb", Agent.Position, false); LastNoiseTime = DeltaTime; } SetCharacterMode(CharacterMode.Climbing); if (Step.ActionVoxel.IsValid) { var voxelVector = new Vector3(Step.ActionVoxel.Coordinate.X + 0.5f, Agent.Physics.Position.Y, Step.ActionVoxel.Coordinate.Z + 0.5f); Agent.Physics.Velocity = Vector3.Normalize(voxelVector - Agent.Physics.Position) * actionSpeed; } yield return(Status.Running); } break; case MoveType.Fly: CleanupMinecart(); DeltaTime = 0.0f; foreach (var bit in Translate(GetPathPoint(Step.SourceVoxel), GetPathPoint(Step.DestinationVoxel), actionSpeed)) { if ((int)(DeltaTime * 100) % 2 == 0) { Creature.NoiseMaker.MakeNoise("Flap", Agent.Position, false); } SetCharacterMode(CharacterMode.Flying); yield return(Status.Running); } break; case MoveType.Dig: CleanupMinecart(); var destroy = new DigAct(Creature.AI, new KillVoxelTask(Step.DestinationVoxel)) { CheckOwnership = false }; destroy.Initialize(); foreach (var status in destroy.Run()) { if (status == Act.Status.Fail) { yield return(Act.Status.Fail); } yield return(Act.Status.Running); } yield return(Act.Status.Fail); // Abort the path so that they stop digging if a path has opened. break; case MoveType.DestroyObject: CleanupMinecart(); var melee = new AttackAct(Creature.AI, (GameComponent)Step.InteractObject); melee.Initialize(); foreach (var status in melee.Run()) { if (status == Act.Status.Fail) { yield return(Act.Status.Fail); } yield return(Act.Status.Running); } yield return(Act.Status.Fail); // Abort the path so that they stop destroying things if a path has opened. break; case MoveType.Teleport: CleanupMinecart(); if (Step.InteractObject == null || Step.InteractObject.IsDead) { yield return(Status.Fail); } if (Step.InteractObject.GetComponent <MagicalObject>().HasValue(out var teleporter)) { teleporter.CurrentCharges--; } SoundManager.PlaySound(ContentPaths.Audio.Oscar.sfx_ic_dwarf_magic_research, Agent.Position, true, 1.0f); Agent.World.ParticleManager.Trigger("green_flame", (Step.InteractObject as GameComponent).Position, Color.White, 1); //Agent.GetRoot().SetFlagRecursive(GameComponent.Flag.Visible, false); { var source = GetPathPoint(Step.SourceVoxel); var dest = GetPathPoint(Step.DestinationVoxel); var delta = dest - source; var steps = delta.Length() * 2.0f; delta.Normalize(); delta *= 0.5f; for (var i = 0; i <= steps; ++i) { Agent.World.ParticleManager.Trigger("star_particle", source, Color.White, 1); source += delta; } } //foreach (var bit in Translate(GetPathPoint(Step.SourceVoxel), GetPathPoint(Step.DestinationVoxel), actionSpeed)) //{ // Agent.World.ParticleManager.Trigger("star_particle", Agent.Position, Color.White, 1); // yield return Status.Running; //} SetAgentTranslation(GetPathPoint(Step.DestinationVoxel)); //Agent.GetRoot().SetFlagRecursive(GameComponent.Flag.Visible, true); yield return(Status.Running); break; } }
public override IEnumerable <Status> Run() { if (!Creature.Faction.Designations.IsVoxelDesignation(Location, DesignationType.Put)) { yield return(Status.Success); yield break; } if (!Creature.Inventory.HasResource(Resource)) { yield return(Status.Fail); } foreach (var status in Creature.HitAndWait(1.0f, true, () => Location.Coordinate.ToVector3() + Vector3.One * 0.5f)) { if (!Creature.Faction.Designations.IsVoxelDesignation(Location, DesignationType.Put)) { yield return(Status.Success); yield break; } if (status == Status.Running) { yield return(status); } } var grabbed = Creature.Inventory.RemoveAndCreate(Resource, Inventory.RestockType.Any).FirstOrDefault(); if (grabbed == null) { yield return(Status.Fail); yield break; } else { if (Creature.Faction.Designations.IsVoxelDesignation(Location, DesignationType.Put)) { // If the creature intersects the box, find a voxel adjacent to it that is free, and jump there to avoid getting crushed. if (Creature.Physics.BoundingBox.Intersects(Location.GetBoundingBox())) { var neighbors = VoxelHelpers.EnumerateAllNeighbors(Location.Coordinate) .Select(c => new VoxelHandle(Agent.Chunks.ChunkData, c)); var closest = VoxelHandle.InvalidHandle; float closestDist = float.MaxValue; foreach (var voxel in neighbors) { if (!voxel.IsValid) { continue; } float dist = (voxel.WorldPosition - Creature.Physics.Position).LengthSquared(); if (dist < closestDist && voxel.IsEmpty) { closestDist = dist; closest = voxel; } } if (closest.IsValid) { TossMotion teleport = new TossMotion(0.5f, 1.0f, Creature.Physics.GlobalTransform, closest.WorldPosition + Vector3.One * 0.5f); Creature.Physics.AnimationQueue.Add(teleport); } } TossMotion motion = new TossMotion(1.0f, 2.0f, grabbed.LocalTransform, Location.Coordinate.ToVector3() + new Vector3(0.5f, 0.5f, 0.5f)); grabbed.GetRoot().GetComponent <Physics>().CollideMode = Physics.CollisionMode.None; grabbed.AnimationQueue.Add(motion); var put = Creature.Faction.Designations.GetVoxelDesignation(Location, DesignationType.Put) as short?; if (!put.HasValue) { yield return(Status.Fail); yield break; } var putType = VoxelLibrary.GetVoxelType(put.Value); motion.OnComplete += () => { grabbed.Die(); PlaceVoxel(Location, putType, Creature.Manager.World); Creature.Faction.Designations.RemoveVoxelDesignation(Location, DesignationType.Put); Creature.Stats.NumBlocksPlaced++; Creature.AI.AddXP(1); }; yield return(Status.Success); yield break; } else { Creature.Inventory.Pickup(grabbed, Inventory.RestockType.RestockResource); grabbed.Die(); yield return(Status.Success); } } }
public override void OnVoxelsSelected(List <VoxelHandle> refs, InputManager.MouseButton button) { if (Command.Contains("Build/")) { if (Library.CreateZone(Command.Substring(6), World).HasValue(out var zone)) { World.AddZone(zone); zone.CompleteRoomImmediately(refs); } } if (Command.Contains("Spawn/")) { string type = Command.Substring(6); foreach (var vox in refs.Where(vox => vox.IsValid)) { if (vox.IsEmpty) { var offset = Vector3.Zero; if (Library.GetCraftable(type).HasValue(out var craftItem)) { offset = craftItem.SpawnOffset; } var body = EntityFactory.CreateEntity <GameComponent>(type, vox.WorldPosition + new Vector3(0.5f, 0.0f, 0.5f) + offset); if (body != null) { body.PropogateTransforms(); if (craftItem != null) { if (craftItem.AddToOwnedPool) { World.PlayerFaction.OwnedObjects.Add(body); } if (craftItem.Deconstructable) { body.Tags.Add("Deconstructable"); // Todo: Should not need to set tag every time item is created. Inherint? } } } } } } else if (Command.Contains("Resource/")) { string type = Command.Substring("Resource/".Length); foreach (var vox in refs.Where(vox => vox.IsValid)) { var body = World.ComponentManager.RootComponent.AddChild(new ResourceEntity(World.ComponentManager, new Resource(type), vox.WorldPosition + new Vector3(0.5f, 0.5f, 0.5f))); body.PropogateTransforms(); } } else if (Command.Contains("Rail/")) { string type = Command.Substring("Rail/".Length); var junction = new Rail.JunctionPiece { RailPiece = type, Orientation = Rail.PieceOrientation.North, Offset = Point.Zero }; foreach (var vox in refs.Where(vox => vox.IsValid)) { if (vox.IsEmpty) { var entity = new Rail.RailEntity(World.ComponentManager, vox, junction); World.ComponentManager.RootComponent.AddChild(entity); } } } else if (Command.Contains("Grass/")) { var type = Library.GetGrassType(Command.Substring(6)); if (type != null) { foreach (var vox in refs.Where(v => v.IsValid)) { var v = vox; if (!vox.IsEmpty) { v.GrassType = type.ID; v.GrassDecay = type.InitialDecayValue; } } } } else if (Command.Contains("Decal/")) { var type = Library.GetDecalType(Command.Substring(6)); if (type != null) { foreach (var vox in refs.Where(v => v.IsValid)) { var v = vox; if (!vox.IsEmpty) { v.DecalType = type.ID; } } } } else if (Command.Contains("Disease")) { foreach (var creature in World.EnumerateIntersectingObjects(VoxelHelpers.GetVoxelBoundingBox(refs), CollisionType.Both).OfType <Creature>()) { creature.Stats.AcquireDisease(DiseaseLibrary.GetRandomDisease()); } } else { foreach (var vox in refs.Where(vox => vox.IsValid)) { if (Command.Contains("Place/")) { string type = Command.Substring(6); var v = vox; if (Library.GetVoxelType(type).HasValue(out VoxelType vType)) { v.Type = vType; } v.QuickSetLiquid(LiquidType.None, 0); if (type == "Magic") { World.ComponentManager.RootComponent.AddChild( new DestroyOnTimer(World.ComponentManager, World.ChunkManager, vox) { DestroyTimer = new Timer(5.0f + MathFunctions.Rand(-0.5f, 0.5f), true) }); } } else { switch (Command) { case "Delete Block": { var v = vox; World.OnVoxelDestroyed(vox); v.Type = Library.EmptyVoxelType; v.QuickSetLiquid(LiquidType.None, 0); } break; case "Nuke Column": { for (var y = 1; y < World.WorldSizeInVoxels.Y; ++y) { var v = World.ChunkManager.CreateVoxelHandle(new GlobalVoxelCoordinate(vox.Coordinate.X, y, vox.Coordinate.Z)); v.Type = Library.EmptyVoxelType; v.QuickSetLiquid(LiquidType.None, 0); } } break; case "Kill Block": foreach (var selected in refs) { if (!selected.IsEmpty) { VoxelHelpers.KillVoxel(World, selected); } } break; case "Fill Water": { if (vox.IsEmpty) { var v = vox; v.QuickSetLiquid(LiquidType.Water, WaterManager.maxWaterLevel); } } break; case "Fill Lava": { if (vox.IsEmpty) { var v = vox; v.QuickSetLiquid(LiquidType.Lava, WaterManager.maxWaterLevel); } } break; case "Fire": { foreach (var flam2 in World.EnumerateIntersectingObjects(vox.GetBoundingBox(), CollisionType.Both).OfType <Flammable>()) { flam2.Heat = flam2.Flashpoint + 1; } } break; default: break; } } } } }
override public void Update(DwarfTime gameTime, ChunkManager chunks, Camera camera) { base.Update(gameTime, chunks, camera); if (!Active) { return; } Creature.NoiseMaker.BasePitch = Stats.VoicePitch; // Non-dwarves are always at full energy. Stats.Energy.CurrentValue = 100.0f; AutoGatherTimer.Update(gameTime); if (AutoGatherTimer.HasTriggered) { if (!String.IsNullOrEmpty(Faction.Race.BecomeWhenEvil) && MathFunctions.RandEvent(0.01f)) { Faction.Minions.Remove(this); Faction = World.Factions.Factions[Faction.Race.BecomeWhenEvil]; Faction.AddMinion(this); } else if (!String.IsNullOrEmpty(Faction.Race.BecomeWhenNotEvil) && MathFunctions.RandEvent(0.01f)) { Faction.Minions.Remove(this); Faction = World.Factions.Factions[Faction.Race.BecomeWhenNotEvil]; Faction.AddMinion(this); } foreach (var body in World.EnumerateIntersectingObjects(Physics.BoundingBox.Expand(3.0f)).OfType <ResourceEntity>().Where(r => r.Active && r.AnimationQueue.Count == 0)) { var resource = Library.GetResourceType(body.Resource.Type); if (resource.Tags.Contains(Resource.ResourceTags.Edible)) { if ((Faction.Race.EatsMeat && resource.Tags.Contains(Resource.ResourceTags.AnimalProduct)) || (Faction.Race.EatsPlants && !resource.Tags.Contains(Resource.ResourceTags.AnimalProduct))) { Creature.GatherImmediately(body); AssignTask(new ActWrapperTask(new EatFoodAct(this, false))); } } } OrderEnemyAttack(); } DeleteBadTasks(); PreEmptTasks(); HandleReproduction(); // Try to find food if we are hungry. Wait - doesn't this rob the player? if (Stats.Hunger.IsDissatisfied() && World.CountResourcesWithTag(Resource.ResourceTags.Edible) > 0) { Task toReturn = new SatisfyHungerTask(); if (Stats.Hunger.IsCritical()) { toReturn.Priority = TaskPriority.Urgent; } if (!Tasks.Contains(toReturn) && CurrentTask != toReturn) { AssignTask(toReturn); } } if (CurrentTask == null) // We need something to do. { var goal = GetEasiestTask(Tasks); if (goal != null) { ChangeTask(goal); } else { var newTask = ActOnIdle(); if (newTask != null) { ChangeTask(newTask); } } } else { if (CurrentAct == null) // Should be impossible to have a current task and no current act. { // Try and recover the correct act. // <blecki> I always run with a breakpoint set here... just in case. ChangeAct(CurrentTask.CreateScript(Creature)); // This is a bad situation! if (CurrentAct == null) { ChangeTask(null); } } if (CurrentAct != null) { var status = CurrentAct.Tick(); bool retried = false; if (CurrentAct != null && CurrentTask != null) { if (status == Act.Status.Fail) { LastFailedAct = CurrentAct.Name; if (!FailedTasks.Any(task => task.TaskFailure.Equals(CurrentTask))) { FailedTasks.Add(new FailedTask() { TaskFailure = CurrentTask, FailedTime = World.Time.CurrentDate }); } if (CurrentTask.ShouldRetry(Creature)) { if (!Tasks.Contains(CurrentTask)) { ReassignCurrentTask(); retried = true; } } } } if (CurrentTask != null && CurrentTask.IsComplete(World)) { ChangeTask(null); } else if (status != Act.Status.Running && !retried) { ChangeTask(null); } } } // With a small probability, the creature will drown if its under water. if (MathFunctions.RandEvent(GameSettings.Default.DrownChance)) { var above = VoxelHelpers.GetVoxelAbove(Physics.CurrentVoxel); var below = VoxelHelpers.GetVoxelBelow(Physics.CurrentVoxel); bool shouldDrown = (above.IsValid && (!above.IsEmpty || above.LiquidLevel > 0)); if ((Physics.IsInLiquid || (!Movement.CanSwim && (below.IsValid && (below.LiquidLevel > 5)))) && (!Movement.CanSwim || shouldDrown)) { Creature.Damage(Movement.CanSwim ? 1.0f : 30.0f, Health.DamageType.Normal); } } if (PositionConstraint.Contains(Physics.LocalPosition) == ContainmentType.Disjoint) { Physics.LocalPosition = MathFunctions.Clamp(Physics.Position, PositionConstraint); Physics.PropogateTransforms(); } }
// Inverts GetMoveActions. So, returns the list of move actions whose target is the current voxel. // Very, very slow. public IEnumerable <MoveAction> GetInverseMoveActions(MoveState currentstate, OctTreeNode OctTree) { if (Parent == null) { yield break; } var creature = Creature; if (creature == null) { yield break; } var current = currentstate.Voxel; if (Can(MoveType.Teleport)) { var teleportObjects = Parent.Faction.OwnedObjects.Where(obj => obj.Active && obj.Tags.Contains("Teleporter")); foreach (var obj in teleportObjects) { if ((obj.Position - current.WorldPosition).LengthSquared() > 2) { continue; } for (int dx = -TeleportDistance; dx <= TeleportDistance; dx++) { for (int dz = -TeleportDistance; dz <= TeleportDistance; dz++) { for (int dy = -TeleportDistance; dy <= TeleportDistance; dy++) { if (dx * dx + dy * dy + dz * dz > TeleportDistanceSquared) { continue; } VoxelHandle teleportNeighbor = new VoxelHandle(Parent.World.ChunkManager.ChunkData, current.Coordinate + new GlobalVoxelOffset(dx, dy, dz)); if (teleportNeighbor.IsValid && teleportNeighbor.IsEmpty && !VoxelHelpers.GetNeighbor(teleportNeighbor, new GlobalVoxelOffset(0, -1, 0)).IsEmpty) { yield return(new MoveAction() { InteractObject = obj, Diff = new Vector3(dx, dx, dz), SourceVoxel = teleportNeighbor, DestinationState = currentstate, MoveType = MoveType.Teleport }); } } } } } } foreach (var v in VoxelHelpers.EnumerateCube(current.Coordinate) .Select(n => new VoxelHandle(current.Chunk.Manager.ChunkData, n)) .Where(h => h.IsValid && h.IsEmpty)) { foreach (var a in GetMoveActions(new MoveState() { Voxel = v }, OctTree).Where(a => a.DestinationState == currentstate)) { yield return(a); } if (!Can(MoveType.RideVehicle)) { continue; } // Now that dwarfs can ride vehicles, the inverse of the move actions becomes extremely complicated. We must now // iterate through all rails intersecting every neighbor and see if we can find a connection from that rail to this one. // Further, we must iterate through the entire rail network and enumerate all possible directions in and out of that rail. // Yay! var bodies = new HashSet <Body>(); OctTree.EnumerateItems(v.GetBoundingBox(), bodies); var rails = bodies.OfType <Rail.RailEntity>().Where(r => r.Active); foreach (var rail in rails) { if (rail.GetContainingVoxel() != v) { continue; } /* * if (!DwarfGame.IsMainThread) * { * for (int i = 0; i < 1; i++) * { * Drawer3D.DrawBox(rail.GetBoundingBox(), Color.Purple, 0.1f, false); * System.Threading.Thread.Sleep(1); * } * } */ foreach (var neighborRail in rail.NeighborRails.Select(neighbor => creature.Manager.FindComponent(neighbor.NeighborID) as Rail.RailEntity)) { var actions = GetMoveActions(new MoveState() { Voxel = v, VehicleState = new VehicleState() { Rail = rail, PrevRail = neighborRail } }, OctTree); foreach (var a in actions.Where(a => a.DestinationState == currentstate)) { yield return(a); /* * if (!DwarfGame.IsMainThread && a.MoveType == MoveType.RideVehicle) * { * for (int i = 0; i < 10; i++) * { * Drawer3D.DrawBox(rail.GetBoundingBox(), Color.Red, 0.1f, false); * System.Threading.Thread.Sleep(1); * } * } */ } } foreach (var a in GetMoveActions(new MoveState() { Voxel = v, VehicleState = new VehicleState() { Rail = rail, PrevRail = null } }, OctTree).Where(a => a.DestinationState == currentstate)) { yield return(a); } } } }