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); } } } }