private GameComponent GetBodyAt(VoxelHandle voxel, CollisionManager objectHash, string tag)
 {
     return(objectHash.EnumerateIntersectingObjects(voxel.GetBoundingBox(),
                                                    CollisionManager.CollisionType.Static).OfType <GameComponent>().FirstOrDefault(component => component.Tags.Contains(tag)));
 }
        /// <summary> gets the list of actions that the creature can take from a given voxel. </summary>
        public IEnumerable <MoveAction> GetMoveActions(VoxelHandle voxel)
        {
            if (!voxel.IsValid || !voxel.IsEmpty)
            {
                yield break;
            }

            CollisionManager objectHash = Creature.Manager.World.CollisionManager;

            var  neighborHood     = GetNeighborhood(voxel);
            bool inWater          = (neighborHood[1, 1, 1].IsValid && neighborHood[1, 1, 1].WaterCell.WaterLevel > WaterManager.inWaterThreshold);
            bool standingOnGround = (neighborHood[1, 0, 1].IsValid && !neighborHood[1, 0, 1].IsEmpty);
            bool topCovered       = (neighborHood[1, 2, 1].IsValid && !neighborHood[1, 2, 1].IsEmpty);
            bool hasNeighbors     = HasNeighbors(neighborHood);
            bool isClimbing       = false;

            var successors = new List <MoveAction>();

            if (CanClimb)
            {
                //Climbing ladders.
                var bodies = objectHash.EnumerateIntersectingObjects(voxel.GetBoundingBox(), CollisionManager.CollisionType.Static).OfType <GameComponent>();

                var ladder = bodies.FirstOrDefault(component => component.Tags.Contains("Climbable"));

                // if the creature can climb objects and a ladder is in this voxel,
                // then add a climb action.
                if (ladder != null)
                {
                    successors.Add(new MoveAction
                    {
                        Diff           = new Vector3(1, 2, 1),
                        MoveType       = MoveType.Climb,
                        InteractObject = ladder
                    });

                    isClimbing = true;

                    if (!standingOnGround)
                    {
                        successors.Add(new MoveAction
                        {
                            Diff           = new Vector3(1, 0, 1),
                            MoveType       = MoveType.Climb,
                            InteractObject = ladder
                        });
                    }

                    standingOnGround = true;
                }
            }

            // If the creature can climb walls and is not blocked by a voxl above.
            if (CanClimbWalls && !topCovered)
            {
                var walls = new VoxelHandle[]
                {
                    neighborHood[2, 1, 1], neighborHood[0, 1, 1], neighborHood[1, 1, 2],
                    neighborHood[1, 1, 0]
                };

                var wall = VoxelHandle.InvalidHandle;
                foreach (var w in walls)
                {
                    if (w.IsValid && !w.IsEmpty)
                    {
                        wall = w;
                    }
                }

                if (wall.IsValid)
                {
                    isClimbing = true;
                    successors.Add(new MoveAction
                    {
                        Diff        = new Vector3(1, 2, 1),
                        MoveType    = MoveType.ClimbWalls,
                        ActionVoxel = wall
                    });

                    if (!standingOnGround)
                    {
                        successors.Add(new MoveAction
                        {
                            Diff        = new Vector3(1, 0, 1),
                            MoveType    = MoveType.ClimbWalls,
                            ActionVoxel = wall
                        });
                    }
                }
            }

            // If the creature either can walk or is in water, add the
            // eight-connected free neighbors around the voxel.
            if ((CanWalk && standingOnGround) || (CanSwim && inWater))
            {
                // If the creature is in water, it can swim. Otherwise, it will walk.
                var moveType = inWater ? MoveType.Swim : MoveType.Walk;
                if (!neighborHood[0, 1, 1].IsValid || neighborHood[0, 1, 1].IsEmpty)
                {
                    // +- x
                    successors.Add(new MoveAction
                    {
                        Diff     = new Vector3(0, 1, 1),
                        MoveType = moveType
                    });
                }

                if (!neighborHood[2, 1, 1].IsValid || neighborHood[2, 1, 1].IsEmpty)
                {
                    successors.Add(new MoveAction
                    {
                        Diff     = new Vector3(2, 1, 1),
                        MoveType = moveType
                    });
                }

                if (!neighborHood[1, 1, 0].IsValid || neighborHood[1, 1, 0].IsEmpty)
                {
                    // +- z
                    successors.Add(new MoveAction
                    {
                        Diff     = new Vector3(1, 1, 0),
                        MoveType = moveType
                    });
                }

                if (!neighborHood[1, 1, 2].IsValid || neighborHood[1, 1, 2].IsEmpty)
                {
                    successors.Add(new MoveAction
                    {
                        Diff     = new Vector3(1, 1, 2),
                        MoveType = moveType
                    });
                }

                // Only bother worrying about 8-connected movement if there are
                // no full neighbors around the voxel.
                if (!hasNeighbors)
                {
                    if (!neighborHood[2, 1, 2].IsValid || neighborHood[2, 1, 2].IsEmpty)
                    {
                        // +x + z
                        successors.Add(new MoveAction
                        {
                            Diff     = new Vector3(2, 1, 2),
                            MoveType = moveType
                        });
                    }

                    if (!neighborHood[2, 1, 0].IsValid || neighborHood[2, 1, 0].IsEmpty)
                    {
                        successors.Add(new MoveAction
                        {
                            Diff     = new Vector3(2, 1, 0),
                            MoveType = moveType
                        });
                    }

                    if (!neighborHood[0, 1, 2].IsValid || neighborHood[0, 1, 2].IsEmpty)
                    {
                        // -x -z
                        successors.Add(new MoveAction
                        {
                            Diff     = new Vector3(0, 1, 2),
                            MoveType = moveType
                        });
                    }

                    if (!neighborHood[0, 1, 0].IsValid || neighborHood[0, 1, 0].IsEmpty)
                    {
                        successors.Add(new MoveAction
                        {
                            Diff     = new Vector3(0, 1, 0),
                            MoveType = moveType
                        });
                    }
                }
            }

            // If the creature's head is free, and it is standing on ground,
            // or if it is in water, or if it is climbing, it can also jump
            // to voxels that are 1 cell away and 1 cell up.
            if (!topCovered && (standingOnGround || (CanSwim && inWater) || isClimbing))
            {
                for (int dx = 0; dx <= 2; dx++)
                {
                    for (int dz = 0; dz <= 2; dz++)
                    {
                        if (dx == 1 && dz == 1)
                        {
                            continue;
                        }

                        if (neighborHood[dx, 1, dz].IsValid && !neighborHood[dx, 1, dz].IsEmpty)
                        {
                            successors.Add(new MoveAction
                            {
                                Diff     = new Vector3(dx, 2, dz),
                                MoveType = MoveType.Jump
                            });
                        }
                    }
                }
            }


            // If the creature is not in water and is not standing on ground,
            // it can fall one voxel downward in free space.
            if (!inWater && !standingOnGround)
            {
                successors.Add(new MoveAction
                {
                    Diff     = new Vector3(1, 0, 1),
                    MoveType = MoveType.Fall
                });
            }

            // If the creature can fly and is not underwater, it can fly
            // to any adjacent empty cell.
            if (CanFly && !inWater)
            {
                for (int dx = 0; dx <= 2; dx++)
                {
                    for (int dz = 0; dz <= 2; dz++)
                    {
                        for (int dy = 0; dy <= 2; dy++)
                        {
                            if (dx == 1 && dz == 1 && dy == 1)
                            {
                                continue;
                            }

                            if (!neighborHood[dx, 1, dz].IsValid || neighborHood[dx, 1, dz].IsEmpty)
                            {
                                successors.Add(new MoveAction
                                {
                                    Diff     = new Vector3(dx, dy, dz),
                                    MoveType = MoveType.Fly
                                });
                            }
                        }
                    }
                }
            }

            // Now, validate each move action that the creature might take.
            foreach (MoveAction v in successors)
            {
                var n = neighborHood[(int)v.Diff.X, (int)v.Diff.Y, (int)v.Diff.Z];
                if (n.IsValid && (n.IsEmpty || n.WaterCell.WaterLevel > 0))
                {
                    // Do one final check to see if there is an object blocking the motion.
                    bool blockedByObject   = false;
                    var  objectsAtNeighbor = Creature.Manager.World.CollisionManager.EnumerateIntersectingObjects(
                        n.GetBoundingBox(), CollisionManager.CollisionType.Static);

                    // If there is an object blocking the motion, determine if it can be passed through.

                    foreach (var body in objectsAtNeighbor.OfType <GameComponent>())
                    {
                        var door = body.GetRoot().EnumerateAll().OfType <Door>().FirstOrDefault();
                        // If there is an enemy door blocking movement, we can destroy it to get through.
                        if (door != null)
                        {
                            if (
                                Creature.World.Diplomacy.GetPolitics(door.TeamFaction, Creature.Faction)
                                .GetCurrentRelationship() !=
                                Relationship.Loving)
                            {
                                if (Can(MoveType.DestroyObject))
                                {
                                    yield return(new MoveAction
                                    {
                                        Diff = v.Diff,
                                        MoveType = MoveType.DestroyObject,
                                        InteractObject = door,
                                        DestinationVoxel = n,
                                        SourceVoxel = voxel
                                    });
                                }
                                blockedByObject = true;
                            }
                        }
                    }

                    // If no object blocked us, we can move freely as normal.
                    if (!blockedByObject)
                    {
                        MoveAction newAction = v;
                        newAction.SourceVoxel      = voxel;
                        newAction.DestinationVoxel = n;
                        yield return(newAction);
                    }
                }
            }
        }