public virtual void HandleCollisions(bool queryNeighborHood, VoxelHandle[] neighborHood, ChunkManager chunks, float dt) { if (CollideMode == CollisionMode.None) { return; } int y = (int)Position.Y; if (CurrentVoxel.IsValid && !CurrentVoxel.IsEmpty) { var currentBox = CurrentVoxel.GetBoundingBox(); if (currentBox.Contains(Position) == ContainmentType.Contains) { ResolveTerrainCollisionGradientMethod(); OnTerrainCollision(CurrentVoxel); return; } } if (queryNeighborHood) { int i = 0; foreach (var v in VoxelHelpers.EnumerateManhattanCube(CurrentVoxel.Coordinate).Select(c => new VoxelHandle(chunks, c))) { neighborHood[i] = v; i++; } } foreach (var v in neighborHood) { if (!v.IsValid || v.IsEmpty) { continue; } if (CollideMode == CollisionMode.UpDown && (int)v.Coordinate.Y == y) { continue; } if (CollideMode == CollisionMode.Sides && (int)v.Coordinate.Y != y) { continue; } if (Collide(v.GetBoundingBox(), dt)) { OnTerrainCollision(v); } } }
public Zone GetMostLikelyZone(VoxelHandle v) { foreach (var r in PersistentData.Zones.Where(r => r.ContainsVoxel(v))) { return(r); } BoundingBox larger = new BoundingBox(v.GetBoundingBox().Min - new Vector3(0.5f, 0.5f, 0.5f), v.GetBoundingBox().Max + new Vector3(0.5f, 0.5f, 0.5f)); return((from room in PersistentData.BuildDesignations from buildDesignation in room.VoxelOrders where larger.Intersects(buildDesignation.Voxel.GetBoundingBox()) select buildDesignation.ToBuild).FirstOrDefault()); }
public static IEnumerable <GlobalVoxelCoordinate> BreadthFirstSearchNonBlocking( ChunkManager Data, GlobalVoxelCoordinate Start, float Radius, Func <GlobalVoxelCoordinate, bool> IsGoal) { 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)) { yield return(current); yield break; } var delta = current.ToVector3() - Start.ToVector3(); if (delta.LengthSquared() < radiusSquared) { foreach (var neighbor in VoxelHelpers.EnumerateManhattanNeighbors(current)) { var v = new VoxelHandle(Data, neighbor); if (!visited.Contains(neighbor) && v.IsValid && v.IsEmpty) { if (Debugger.Switches.DrawPaths) { Drawer3D.DrawBox(v.GetBoundingBox(), Color.Red, 0.1f, true); } visited.Add(neighbor); queue.Enqueue(neighbor); } } } yield return(new GlobalVoxelCoordinate(-9999, -9999, -9999)); } }
public DestroyOnTimer(ComponentManager Manager, ChunkManager chunkManager, VoxelHandle Voxel) : base(Manager, "DestroyTimer", Matrix.CreateTranslation(Voxel.GetBoundingBox().Center()), new Vector3(0.5f, 0.5f, 0.5f), Vector3.Zero) { this.Voxel = Voxel; }
public void Update(ParticleManager manager, DwarfTime gameTime, ChunkManager chunks, Camera camera) { ParticleEmitter._camera = camera; List <Particle> toRemove = new List <Particle>(); TriggerTimer.Update(gameTime); if (TriggerTimer.HasTriggered && Data.ParticlesPerFrame > 0) { Trigger(Data.ParticlesPerFrame, Vector3.Zero, new Color(255, 255, 0)); } bool particlePhysics = GameSettings.Default.ParticlePhysics; foreach (Particle p in Particles) { float vel = p.Velocity.LengthSquared(); if (Data.EmitsLight && p.Scale > 0.1f) { DynamicLight.TempLights.Add(new DynamicLight(10.0f, 255.0f, false) { Position = p.Position }); } p.Position += p.Velocity * (float)gameTime.ElapsedGameTime.TotalSeconds; if (Data.RotatesWithVelocity) { Vector3 cameraVel = camera.Project(p.Velocity + camera.Position); float projectionX = cameraVel.X; float projectionY = cameraVel.Y; p.Angle = (float)Math.Atan2(projectionY, projectionX); } else { p.Angle += (float)(p.AngularVelocity * gameTime.ElapsedGameTime.TotalSeconds); } if (!Data.Sleeps || vel > 0.01f) { p.Velocity += Data.ConstantAccel * (float)gameTime.ElapsedGameTime.TotalSeconds; } p.Velocity *= Data.LinearDamping; p.AngularVelocity *= Data.AngularDamping; if (!Data.UseManualControl) { p.LifeRemaining -= Data.ParticleDecay * (float)gameTime.ElapsedGameTime.TotalSeconds; } else if (p.TimeAlive > 60) { p.LifeRemaining = 0; } p.Scale += Data.GrowthSpeed * (float)gameTime.ElapsedGameTime.TotalSeconds; p.Scale = Math.Max(p.Scale, 0.0f); var v = new VoxelHandle(chunks.ChunkData, GlobalVoxelCoordinate.FromVector3(p.Position)); if (Data.HasLighting) { if (v.IsValid) { p.LightRamp = new Color(v.Sunlight ? 255 : 0, 255, 0); } } else { p.LightRamp = new Color(255, 255, 0); } if (Data.CollidesWorld && particlePhysics && vel > 0.2f) { if (v.IsValid && !v.IsEmpty) { BoundingBox b = new BoundingBox(p.Position - Vector3.One * p.Scale * 0.5f, p.Position + Vector3.One * p.Scale * 0.5f); BoundingBox vBox = v.GetBoundingBox(); Physics.Contact contact = new Physics.Contact(); if (Physics.TestStaticAABBAABB(b, vBox, ref contact)) { p.Position += contact.NEnter * contact.Penetration; Vector3 newVelocity = Vector3.Reflect(p.Velocity, -contact.NEnter); p.Velocity = newVelocity * Data.Damping; p.AngularVelocity *= 0.5f; if (Data.Sleeps) { p.Velocity = Vector3.Zero; p.AngularVelocity = 0.0f; vel = 0.0f; } if (!String.IsNullOrEmpty(Data.SpatterType)) { var above = VoxelHelpers.GetVoxelAbove(v); if (!above.IsValid || above.IsEmpty) { float x = MathFunctions.Clamp(p.Position.X, vBox.Min.X + 0.1f, vBox.Max.X - 0.1f); float z = MathFunctions.Clamp(p.Position.Z, vBox.Min.Z + 0.1f, vBox.Max.Z - 0.1f); manager.Create(Data.SpatterType, VertexNoise.Warp(new Vector3(x, v.RampType == RampType.None ? v.WorldPosition.Y + 1.02f : v.WorldPosition.Y + 0.6f, z)), Vector3.Zero, Color.White, Vector3.Up); } else { manager.Create(Data.SpatterType, p.Position - contact.NEnter * contact.Penetration * 0.95f, Vector3.Zero, Color.White, contact.NEnter); } p.LifeRemaining = -1.0f; } } } } if (p.LifeRemaining < 0) { if (p.InstanceData != null) { p.InstanceData.ShouldDraw = false; p.InstanceData.Transform = Matrix.CreateTranslation(camera.Position + new Vector3(-1000, -1000, -1000)); Sprites[p.Frame].Remove(p.InstanceData); } toRemove.Add(p); } else if (p.InstanceData != null) { p.TimeAlive += (float)gameTime.ElapsedGameTime.TotalSeconds + MathFunctions.Rand() * 0.01f; int prevFrame = p.Frame; int newFrame = AnimPlayer.GetFrame(p.TimeAlive); if (vel < 0.2f) { newFrame = prevFrame; } if (newFrame != prevFrame) { p.Frame = newFrame; if (Sprites.Count > 0) { Sprites[prevFrame].Remove(p.InstanceData); Sprites[newFrame].Add(p.InstanceData); } if (/*!Data.Animation.Loops && */ p.Frame == Data.Animation.Frames.Count - 1) { p.LifeRemaining *= 0.1f; } } p.InstanceData.ShouldDraw = true; p.InstanceData.Transform = MatrixFromParticle(Data, p); p.InstanceData.LightRamp = p.LightRamp; } } foreach (Particle p in toRemove) { Particles.Remove(p); } foreach (var sprites in Sprites) { sprites.Update(gameTime, camera, GameState.Game.GraphicsDevice, chunks.World.Master.MaxViewingLevel); } }
public override void Update(DwarfTime gameTime, ChunkManager chunks, Camera camera) { ParticleEmitter._camera = camera; List <Particle> toRemove = new List <Particle>(); TriggerTimer.Update(gameTime); if (TriggerTimer.HasTriggered && Data.ParticlesPerFrame > 0) { Trigger(Data.ParticlesPerFrame, Vector3.Zero, Tint); } bool particlePhysics = GameSettings.Default.ParticlePhysics; foreach (Particle p in Particles) { float vel = p.Velocity.LengthSquared(); if (!Data.Sleeps || vel > 0.2f) { if (Data.EmitsLight && p.Scale > 0.1f) { DynamicLight.TempLights.Add(new DynamicLight(10.0f, 255.0f, false) { Position = p.Position }); } p.Position += p.Velocity * (float)gameTime.ElapsedGameTime.TotalSeconds; if (Data.RotatesWithVelocity) { Vector3 cameraVel = camera.Project(p.Velocity + camera.Position); float projectionX = cameraVel.X; float projectionY = cameraVel.Y; p.Angle = (float)Math.Atan2(projectionY, projectionX); } else { p.Angle += (float)(p.AngularVelocity * gameTime.ElapsedGameTime.TotalSeconds); } p.Velocity += Data.ConstantAccel * (float)gameTime.ElapsedGameTime.TotalSeconds; p.Velocity *= Data.LinearDamping; p.AngularVelocity *= Data.AngularDamping; } else if (Data.Sleeps && vel < 0.2f) { p.Velocity = Vector3.Zero; } if (!Data.UseManualControl) { p.LifeRemaining -= Data.ParticleDecay * (float)gameTime.ElapsedGameTime.TotalSeconds; } p.Scale += Data.GrowthSpeed * (float)gameTime.ElapsedGameTime.TotalSeconds; p.Scale = Math.Max(p.Scale, 0.0f); var v = new VoxelHandle(chunks.ChunkData, GlobalVoxelCoordinate.FromVector3(p.Position)); if (Data.HasLighting) { if (v.IsValid && v.IsEmpty) { p.Tint = new Color(v.SunColor, 255, 0); } } if (Data.CollidesWorld && particlePhysics && vel > 0.2f) { BoundingBox b = new BoundingBox(p.Position - Vector3.One * p.Scale * 0.5f, p.Position + Vector3.One * p.Scale * 0.5f); if (v.IsValid && !v.IsEmpty) { Physics.Contact contact = new Physics.Contact(); if (Physics.TestStaticAABBAABB(b, v.GetBoundingBox(), ref contact)) { p.Position += contact.NEnter * contact.Penetration; Vector3 newVelocity = Vector3.Reflect(p.Velocity, -contact.NEnter); p.Velocity = newVelocity * Data.Damping; p.AngularVelocity *= 0.5f; } } } if (p.LifeRemaining < 0) { if (p.InstanceData != null) { p.InstanceData.ShouldDraw = false; p.InstanceData.Transform = Matrix.CreateTranslation(camera.Position + new Vector3(-1000, -1000, -1000)); Sprites[p.Frame].Remove(p.InstanceData); } toRemove.Add(p); } else if (p.InstanceData != null) { p.TimeAlive += (float)gameTime.ElapsedGameTime.TotalSeconds + MathFunctions.Rand() * 0.01f; int prevFrame = p.Frame; int newFrame = AnimPlayer.GetFrame(p.TimeAlive); if (newFrame != prevFrame) { p.Frame = newFrame; if (Sprites.Count > 0) { Sprites[prevFrame].Remove(p.InstanceData); Sprites[newFrame].Add(p.InstanceData); } if (/*!Data.Animation.Loops && */ p.Frame == Data.Animation.Frames.Count - 1) { p.LifeRemaining *= 0.1f; } } p.InstanceData.ShouldDraw = true; p.InstanceData.Transform = MatrixFromParticle(p); p.InstanceData.Color = p.Tint; } } foreach (Particle p in toRemove) { Particles.Remove(p); } foreach (var sprites in Sprites) { sprites.Update(gameTime, camera, chunks.Graphics, chunks.ChunkData.MaxViewingLevel); } if (Particles.Count > 0) { base.Update(gameTime, chunks, camera); } }
public override IEnumerable <Status> Run() { foreach (var res in Agent.Blackboard.GetData <List <Resource> >(ResourceBlackboardName)) { if (!Creature.Inventory.Contains(res)) { yield return(Status.Fail); } } foreach (var status in Creature.HitAndWait(1.0f, true, () => Location.Coordinate.ToVector3() + Vector3.One * 0.5f)) { if (status == Status.Running) { yield return(status); } } foreach (var res in Agent.Blackboard.GetData <List <Resource> >(ResourceBlackboardName)) { var grabbed = Creature.Inventory.RemoveAndCreate(res, Inventory.RestockType.Any); if (grabbed == null) { yield return(Status.Fail); yield break; } else { // 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.World.ChunkManager, c)); var closest = VoxelHandle.InvalidHandle; var 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); } } // Todo: Shitbox - what happens if the player saves while this animation is in progress?? How is the OnComplete restored? var motion = new TossMotion(1.0f, 2.0f, grabbed.LocalTransform, Location.Coordinate.ToVector3() + new Vector3(0.5f, 0.5f, 0.5f)); if (grabbed.GetRoot().GetComponent <Physics>().HasValue(out var grabbedPhysics)) { grabbedPhysics.CollideMode = Physics.CollisionMode.None; } grabbed.AnimationQueue.Add(motion); motion.OnComplete += () => grabbed.Die(); } if (Library.GetVoxelType(VoxelType).HasValue(out var vType)) { PlaceVoxel(Location, vType, Creature.Manager.World); } Creature.Stats.NumBlocksPlaced++; Creature.AI.AddXP(1); yield return(Status.Success); yield break; } }
private void Place(VoxelHandle Location) { var assignments = new List <Task>(); for (var i = 0; i < PreviewBodies.Count; ++i) { var body = PreviewBodies[i]; var piece = Pattern.Pieces[i]; var actualPosition = new VoxelHandle(Location.Chunk.Manager.ChunkData, Location.Coordinate + new GlobalVoxelOffset(piece.Offset.X, 0, piece.Offset.Y)); var addNewDesignation = true; foreach (var entity in Player.World.CollisionManager.EnumerateIntersectingObjects(actualPosition.GetBoundingBox().Expand(-0.2f), CollisionManager.CollisionType.Static)) { if (!addNewDesignation) { break; } if (Object.ReferenceEquals(entity, body)) { continue; } var possibleCombination = FindPossibleCombination(piece, entity); if (possibleCombination != null) { var combinedPiece = new Rail.JunctionPiece { RailPiece = possibleCombination.Result, Orientation = Rail.OrientationHelper.Rotate((entity as RailPiece).Piece.Orientation, (int)possibleCombination.ResultRelativeOrientation), }; var existingDesignation = Player.Faction.Designations.EnumerateEntityDesignations(DesignationType.Craft).FirstOrDefault(d => Object.ReferenceEquals(d.Body, entity)); if (existingDesignation != null) { (entity as RailPiece).UpdatePiece(combinedPiece, actualPosition); (existingDesignation.Tag as CraftDesignation).Progress = 0.0f; body.Delete(); addNewDesignation = false; } else { (entity as RailPiece).Die(); body.UpdatePiece(combinedPiece, actualPosition); } } } if (addNewDesignation) { var startPos = body.Position + new Vector3(0.0f, -0.3f, 0.0f); var endPos = body.Position; var designation = new CraftDesignation { Entity = body, WorkPile = new WorkPile(Player.World.ComponentManager, startPos), OverrideOrientation = false, Valid = true, ItemType = RailCraftItem, SelectedResources = SelectedResources, Location = new VoxelHandle(Player.World.ChunkManager.ChunkData, GlobalVoxelCoordinate.FromVector3(body.Position)), HasResources = false, ResourcesReservedFor = null, Orientation = 0.0f, Progress = 0.0f, }; Player.World.ComponentManager.RootComponent.AddChild(designation.WorkPile); designation.WorkPile.AnimationQueue.Add(new EaseMotion(1.1f, Matrix.CreateTranslation(startPos), endPos)); Player.World.ParticleManager.Trigger("puff", endPos, Color.White, 10); Player.Faction.Designations.AddEntityDesignation(body, DesignationType.Craft, designation); assignments.Add(new CraftItemTask(designation)); } } if (assignments.Count > 0) { Player.World.Master.TaskManager.AddTasks(assignments); } }
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 ExploredListener(ComponentManager Manager, VoxelHandle Voxel) : base(Manager, "ExplorationSpawner", Matrix.CreateTranslation(Voxel.GetBoundingBox().Center()), new Vector3(0.5f, 0.5f, 0.5f), Vector3.Zero) { this.Voxel = Voxel; this.CollisionType = CollisionType.Static; }
public void CheckSurroundings(GameComponent Body, DwarfTime gameTime, ChunkManager chunks) { if (Heat > Flashpoint) { var insideBodies = World.EnumerateIntersectingObjects(Body.GetBoundingBox()); foreach (var body in insideBodies.Where(b => b != Parent && b.Active && b.Parent == Manager.RootComponent)) { var flames = body.GetComponent <Flammable>(); if (flames != null) { flames.Heat += 100; } } SoundManager.PlaySound(ContentPaths.Audio.fire, Body.Position, true); } float expansion = Heat > Flashpoint ? 1.0f : 0.0f; foreach (var coordinate in VoxelHelpers.EnumerateCoordinatesInBoundingBox(Body.BoundingBox.Expand(expansion))) { var voxel = new VoxelHandle(chunks, coordinate); if (!voxel.IsValid) { continue; } if (Heat > Flashpoint && MathFunctions.RandEvent(0.5f)) { if (voxel.Type.IsFlammable) { if (MathFunctions.RandEvent(0.1f)) { var existingItems = World.EnumerateIntersectingObjects(voxel.GetBoundingBox().Expand(-0.1f)); if (!existingItems.Any(e => e is Fire)) { EntityFactory.CreateEntity <Fire>("Fire", voxel.GetBoundingBox().Center()); } SoundManager.PlaySound(ContentPaths.Audio.Oscar.sfx_env_lava_spread, voxel.GetBoundingBox().Center(), true, 1.0f); VoxelHelpers.KillVoxel(World, voxel); } } if (voxel.GrassType != 0x0) { if (MathFunctions.RandEvent(0.1f)) { var box = voxel.GetBoundingBox().Expand(-0.1f); box.Min += Vector3.One; // Todo: Why shifting one on every axis? box.Max += Vector3.One; if (!World.EnumerateIntersectingObjects(box).Any(e => e is Fire)) { EntityFactory.CreateEntity <Fire>("Fire", box.Center()); } } if (MathFunctions.RandEvent(0.5f)) { SoundManager.PlaySound(ContentPaths.Audio.Oscar.sfx_env_lava_spread, voxel.GetBoundingBox().Center(), true, 1.0f); voxel.GrassType = 0x0; } } } if (voxel.LiquidLevel <= 0) { continue; } if (voxel.LiquidType == LiquidType.Lava) { Heat += 100.0f; } else if (voxel.LiquidType == LiquidType.Water) { Heat = Heat * 0.25f; } } }
private bool ValidatePlanting(VoxelHandle voxel) { if (!voxel.Type.IsSoil) { Player.World.ShowTooltip("Can only plant on soil!"); return(false); } if (ResourceLibrary.Resources[PlantType].Tags.Contains(Resource.ResourceTags.AboveGroundPlant)) { if (voxel.Sunlight == false) { Player.World.ShowTooltip("Can only plant " + PlantType + " above ground."); return(false); } } else if (ResourceLibrary.Resources[PlantType].Tags.Contains(Resource.ResourceTags.BelowGroundPlant)) { if (voxel.Sunlight) { Player.World.ShowTooltip("Can only plant " + PlantType + " below ground."); return(false); } } var designation = Player.Faction.Designations.GetVoxelDesignation(voxel, DesignationType.Plant); if (designation != null) { Player.World.ShowTooltip("You're already planting here."); return(false); } var boundingBox = new BoundingBox(voxel.Coordinate.ToVector3() + new Vector3(0.2f, 0.2f, 0.2f), voxel.Coordinate.ToVector3() + new Vector3(0.8f, 0.8f, 0.8f)); var entities = Player.World.EnumerateIntersectingObjects(boundingBox, CollisionType.Static).OfType <IVoxelListener>(); if (entities.Any()) { if (Debugger.Switches.DrawToolDebugInfo) { Drawer3D.DrawBox(boundingBox, Color.Red, 0.03f, false); foreach (var entity in entities) { Drawer3D.DrawBox((entity as Body).GetBoundingBox(), Color.Yellow, 0.03f, false); } } Player.World.ShowTooltip("There's something in the way."); return(false); } // We have to shrink the bounding box used because for some reason zones overflow their bounds a little during their collision check. if (Player.Faction.GetIntersectingRooms(voxel.GetBoundingBox().Expand(-0.2f)).Count > 0) { Player.World.ShowTooltip("Can't plant inside zones."); return(false); } Player.World.ShowTooltip("Click to plant."); return(true); }
/// <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); } } } }
private bool ValidatePlanting(VoxelHandle voxel) { if (!voxel.Type.IsSoil) { World.UserInterface.ShowTooltip("Can only plant on soil!"); return(false); } if (Library.GetResourceType(PlantType).Tags.Contains(Resource.ResourceTags.AboveGroundPlant)) { if (voxel.Sunlight == false) { World.UserInterface.ShowTooltip("Can only plant " + PlantType + " above ground."); return(false); } } else if (Library.GetResourceType(PlantType).Tags.Contains(Resource.ResourceTags.BelowGroundPlant)) { if (voxel.Sunlight) { World.UserInterface.ShowTooltip("Can only plant " + PlantType + " below ground."); return(false); } } var designation = World.PersistentData.Designations.GetVoxelDesignation(voxel, DesignationType.Plant); if (designation != null) { World.UserInterface.ShowTooltip("You're already planting here."); return(false); } var boundingBox = new BoundingBox(voxel.Coordinate.ToVector3() + new Vector3(0.2f, 0.2f, 0.2f), voxel.Coordinate.ToVector3() + new Vector3(0.8f, 0.8f, 0.8f)); var entities = World.EnumerateIntersectingObjects(boundingBox, CollisionType.Static).OfType <IVoxelListener>(); if (entities.Any()) { if (Debugger.Switches.DrawToolDebugInfo) { Drawer3D.DrawBox(boundingBox, Color.Red, 0.03f, false); foreach (var entity in entities) { Drawer3D.DrawBox((entity as GameComponent).GetBoundingBox(), Color.Yellow, 0.03f, false); } } World.UserInterface.ShowTooltip("There's something in the way."); return(false); } var voxelBox = voxel.GetBoundingBox().Expand(-0.2f); if (World.EnumerateZones().Where(room => room.Intersects(voxelBox)).Any()) { World.UserInterface.ShowTooltip("Can't plant inside zones."); return(false); } World.UserInterface.ShowTooltip("Click to plant."); return(true); }
private IEnumerable <MoveAction> EnumerateSuccessors(MoveState state, VoxelHandle voxel, VoxelHandle[,,] neighborHood, bool inWater, bool standingOnGround, bool topCovered, bool hasNeighbors, bool isRiding, HashSet <Body> neighborObjects) { bool isClimbing = false; if (CanClimb || Can(MoveType.RideVehicle)) { //Climbing ladders. var bodies = neighborObjects.Where(o => o.GetBoundingBox().Intersects(voxel.GetBoundingBox())); if (!isRiding) { 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 && CanClimb) { yield return(new MoveAction { Diff = new Vector3(1, 2, 1), MoveType = MoveType.Climb, InteractObject = ladder }); if (!standingOnGround) { yield return(new MoveAction { Diff = new Vector3(1, 0, 1), MoveType = MoveType.Climb, InteractObject = ladder }); } standingOnGround = true; } } if (!isRiding) { var rails = bodies.OfType <Rail.RailEntity>().Where(r => r.Active); if (rails.Count() > 0 && Can(MoveType.RideVehicle)) { { foreach (var rail in rails) { if (rail.GetContainingVoxel() != state.Voxel) { continue; } yield return(new MoveAction() { SourceState = state, DestinationState = new MoveState() { VehicleState = new VehicleState() { Rail = rail }, Voxel = rail.GetContainingVoxel() }, MoveType = MoveType.EnterVehicle, Diff = new Vector3(1, 1, 1) }); } } } } if (Can(MoveType.ExitVehicle) && isRiding) { yield return(new MoveAction() { SourceState = state, DestinationState = new MoveState() { VehicleState = new VehicleState(), Voxel = state.Voxel }, MoveType = MoveType.ExitVehicle, Diff = new Vector3(1, 1, 1) }); } if (Can(MoveType.RideVehicle) && isRiding) { foreach (var neighbor in Rail.RailHelper.EnumerateForwardNetworkConnections(state.VehicleState.PrevRail, state.VehicleState.Rail)) { var neighborRail = Creature.Manager.FindComponent(neighbor) as Rail.RailEntity; if (neighborRail == null || !neighborRail.Active) { continue; } yield return(new MoveAction() { SourceState = state, DestinationState = new MoveState() { Voxel = neighborRail.GetContainingVoxel(), VehicleState = new VehicleState() { Rail = neighborRail, PrevRail = state.VehicleState.Rail } }, MoveType = MoveType.RideVehicle, }); } } } // If the creature can climb walls and is not blocked by a voxl above. if (!isRiding && CanClimbWalls && !topCovered) { // This monstrosity is unrolling an inner loop so that we don't have to allocate an array or // enumerators. var wall = VoxelHandle.InvalidHandle; var n211 = neighborHood[2, 1, 1]; if (n211.IsValid && !n211.IsEmpty) { wall = n211; } else { var n011 = neighborHood[0, 1, 1]; if (n011.IsValid && !n011.IsEmpty) { wall = n011; } else { var n112 = neighborHood[1, 1, 2]; if (n112.IsValid && !n112.IsEmpty) { wall = n112; } else { var n110 = neighborHood[1, 1, 0]; if (n110.IsValid && !n110.IsEmpty) { wall = n110; } } } } if (wall.IsValid) { isClimbing = true; yield return(new MoveAction { Diff = new Vector3(1, 2, 1), MoveType = MoveType.ClimbWalls, ActionVoxel = wall }); if (!standingOnGround) { yield return(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 (!isRiding && ((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 yield return(new MoveAction { Diff = new Vector3(0, 1, 1), MoveType = moveType }); } if (!neighborHood[2, 1, 1].IsValid || neighborHood[2, 1, 1].IsEmpty) { yield return(new MoveAction { Diff = new Vector3(2, 1, 1), MoveType = moveType }); } if (!neighborHood[1, 1, 0].IsValid || neighborHood[1, 1, 0].IsEmpty) { // +- z yield return(new MoveAction { Diff = new Vector3(1, 1, 0), MoveType = moveType }); } if (!neighborHood[1, 1, 2].IsValid || neighborHood[1, 1, 2].IsEmpty) { yield return(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 yield return(new MoveAction { Diff = new Vector3(2, 1, 2), MoveType = moveType }); } if (!neighborHood[2, 1, 0].IsValid || neighborHood[2, 1, 0].IsEmpty) { yield return(new MoveAction { Diff = new Vector3(2, 1, 0), MoveType = moveType }); } if (!neighborHood[0, 1, 2].IsValid || neighborHood[0, 1, 2].IsEmpty) { // -x -z yield return(new MoveAction { Diff = new Vector3(0, 1, 2), MoveType = moveType }); } if (!neighborHood[0, 1, 0].IsValid || neighborHood[0, 1, 0].IsEmpty) { yield return(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 (!isRiding && (!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) { yield return(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 (!isRiding && !inWater && !standingOnGround) { yield return(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 (!isRiding && 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) { yield return(new MoveAction { Diff = new Vector3(dx, dy, dz), MoveType = MoveType.Fly }); } } } } } }
private GameComponent GetBodyAt(VoxelHandle voxel, WorldManager World, string tag) { return(World.EnumerateIntersectingObjects(voxel.GetBoundingBox(), CollisionType.Static).OfType <GameComponent>().FirstOrDefault(component => component.Tags.Contains(tag))); }
private IEnumerable <MoveAction> EnumerateSuccessors( MoveState state, VoxelHandle voxel, MoveActionTempStorage Storage, bool inWater, bool standingOnGround, bool topCovered, bool hasNeighbors) { bool isClimbing = false; if (state.VehicleType == VehicleTypes.Rail) { if (Can(MoveType.ExitVehicle)) // Possibly redundant... If they can ride they should be able to exit right? { yield return(new MoveAction() { SourceState = state, DestinationState = new MoveState() { VehicleType = VehicleTypes.None, Voxel = state.Voxel }, MoveType = MoveType.ExitVehicle, Diff = new Vector3(1, 1, 1), CostMultiplier = 1.0f }); } if (Can(MoveType.RideVehicle)) { foreach (var neighbor in Rail.RailHelper.EnumerateForwardNetworkConnections(state.PrevRail, state.Rail)) { var neighborRail = Creature.Manager.FindComponent(neighbor) as Rail.RailEntity; if (neighborRail == null || !neighborRail.Active) { continue; } yield return(new MoveAction() { SourceState = state, DestinationState = new MoveState() { Voxel = neighborRail.GetContainingVoxel(), Rail = neighborRail, PrevRail = state.Rail, VehicleType = VehicleTypes.Rail }, MoveType = MoveType.RideVehicle, CostMultiplier = 1.0f }); } } yield break; // Nothing can be done without exiting the rails first. } if (CanClimb || Can(MoveType.RideVehicle)) { //Climbing ladders and riding rails. var bodies = Storage.NeighborObjects.Where(o => o.GetBoundingBox().Intersects(voxel.GetBoundingBox())); // if the creature can climb objects and a ladder is in this voxel, // then add a climb action. if (CanClimb) { var ladder = bodies.FirstOrDefault(component => component.Tags.Contains("Climbable")); if (ladder != null) { yield return(new MoveAction { SourceState = state, Diff = new Vector3(1, 2, 1), MoveType = MoveType.Climb, InteractObject = ladder, CostMultiplier = 1.0f, DestinationVoxel = Storage.Neighborhood[1, 2, 1] }); if (!standingOnGround) { yield return(new MoveAction { SourceState = state, Diff = new Vector3(1, 0, 1), MoveType = MoveType.Climb, InteractObject = ladder, CostMultiplier = 1.0f, DestinationVoxel = Storage.Neighborhood[1, 2, 1] }); } standingOnGround = true; } } if (Can(MoveType.RideVehicle)) { var rails = bodies.OfType <Rail.RailEntity>().Where(r => r.Active); if (rails.Count() > 0 && Can(MoveType.RideVehicle)) { { foreach (var rail in rails) { if (rail.GetContainingVoxel() != state.Voxel) { continue; } yield return(new MoveAction() { SourceState = state, DestinationState = new MoveState() { VehicleType = VehicleTypes.Rail, Rail = rail, Voxel = rail.GetContainingVoxel() }, MoveType = MoveType.EnterVehicle, Diff = new Vector3(1, 1, 1), CostMultiplier = 1.0f }); } } } var elevators = bodies.OfType <Elevators.ElevatorShaft>().Where(r => r.Active && System.Math.Abs(r.Position.Y - voxel.Center.Y) < 0.5f); foreach (var elevator in elevators) { foreach (var elevatorExit in Elevators.Helper.EnumerateExits(elevator.Shaft)) { if (object.ReferenceEquals(elevator, elevatorExit.ShaftSegment)) { continue; // Ignore exits from the segment we are entering at. } yield return(new MoveAction() { SourceState = state, DestinationState = new MoveState() { Voxel = elevatorExit.OntoVoxel, VehicleType = VehicleTypes.None, Tag = new Elevators.ElevatorMoveState { Entrance = elevator, Exit = elevatorExit.ShaftSegment } }, MoveType = MoveType.RideElevator, CostMultiplier = elevator.GetQueueSize() + 1.0f }); } } } } // 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 (Storage.Neighborhood[dx, dy, dz].IsValid && Storage.Neighborhood[dx, dy, dz].IsEmpty) { yield return(new MoveAction { SourceState = state, Diff = new Vector3(dx, dy, dz), MoveType = MoveType.Fly, CostMultiplier = 1.0f, DestinationVoxel = Storage.Neighborhood[dx, dy, dz] }); } } } } } // 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 && Storage.Neighborhood[1, 0, 1].IsValid) { yield return(new MoveAction { SourceState = state, Diff = new Vector3(1, 0, 1), MoveType = MoveType.Fall, CostMultiplier = 1.0f, DestinationVoxel = Storage.Neighborhood[1, 0, 1] }); } // If the creature can climb walls and is not blocked by a voxl above. if (CanClimbWalls && !topCovered) { // This monstrosity is unrolling an inner loop so that we don't have to allocate an array or // enumerators. var wall = VoxelHandle.InvalidHandle; if (Storage.Neighborhood[2, 1, 1].IsValid && !Storage.Neighborhood[2, 1, 1].IsEmpty) { wall = Storage.Neighborhood[2, 1, 1]; } else if (Storage.Neighborhood[0, 1, 1].IsValid && !Storage.Neighborhood[0, 1, 1].IsEmpty) { wall = Storage.Neighborhood[0, 1, 1]; } else if (Storage.Neighborhood[1, 1, 2].IsValid && !Storage.Neighborhood[1, 1, 2].IsEmpty) { wall = Storage.Neighborhood[1, 1, 2]; } else if (Storage.Neighborhood[1, 1, 0].IsValid && !Storage.Neighborhood[1, 1, 0].IsEmpty) { wall = Storage.Neighborhood[1, 1, 0]; } if (wall.IsValid) { isClimbing = true; if (Storage.Neighborhood[1, 2, 1].IsValid) { yield return(new MoveAction { SourceState = state, Diff = new Vector3(1, 2, 1), MoveType = MoveType.ClimbWalls, ActionVoxel = wall, CostMultiplier = 1.0f, DestinationVoxel = Storage.Neighborhood[1, 2, 1] }); } if (!standingOnGround && Storage.Neighborhood[1, 0, 1].IsValid) { yield return(new MoveAction { SourceState = state, Diff = new Vector3(1, 0, 1), MoveType = MoveType.ClimbWalls, ActionVoxel = wall, CostMultiplier = 1.0f, DestinationVoxel = Storage.Neighborhood[1, 0, 1] }); } } } // 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 (Storage.Neighborhood[0, 1, 1].IsValid && Storage.Neighborhood[0, 1, 1].IsEmpty) { // +- x yield return(new MoveAction { SourceState = state, DestinationVoxel = Storage.Neighborhood[0, 1, 1], Diff = new Vector3(0, 1, 1), MoveType = moveType, CostMultiplier = 1.0f }); } if (Storage.Neighborhood[2, 1, 1].IsValid && Storage.Neighborhood[2, 1, 1].IsEmpty) { yield return(new MoveAction { SourceState = state, Diff = new Vector3(2, 1, 1), MoveType = moveType, CostMultiplier = 1.0f, DestinationVoxel = Storage.Neighborhood[2, 1, 1] }); } if (Storage.Neighborhood[1, 1, 0].IsValid && Storage.Neighborhood[1, 1, 0].IsEmpty) { // +- z yield return(new MoveAction { SourceState = state, Diff = new Vector3(1, 1, 0), MoveType = moveType, CostMultiplier = 1.0f, DestinationVoxel = Storage.Neighborhood[1, 1, 0] }); } if (Storage.Neighborhood[1, 1, 2].IsValid && Storage.Neighborhood[1, 1, 2].IsEmpty) { yield return(new MoveAction { SourceState = state, Diff = new Vector3(1, 1, 2), MoveType = moveType, CostMultiplier = 1.0f, DestinationVoxel = Storage.Neighborhood[1, 1, 2] }); } // Only bother worrying about 8-connected movement if there are // no full neighbors around the voxel. if (!hasNeighbors) { if (Storage.Neighborhood[2, 1, 2].IsValid && Storage.Neighborhood[2, 1, 2].IsEmpty) { // +x + z yield return(new MoveAction { SourceState = state, Diff = new Vector3(2, 1, 2), MoveType = moveType, CostMultiplier = 1.0f, DestinationVoxel = Storage.Neighborhood[2, 1, 2] }); } if (Storage.Neighborhood[2, 1, 0].IsValid && Storage.Neighborhood[2, 1, 0].IsEmpty) { yield return(new MoveAction { SourceState = state, Diff = new Vector3(2, 1, 0), MoveType = moveType, CostMultiplier = 1.0f, DestinationVoxel = Storage.Neighborhood[2, 1, 0] }); } if (Storage.Neighborhood[0, 1, 2].IsValid && Storage.Neighborhood[0, 1, 2].IsEmpty) { // -x -z yield return(new MoveAction { SourceState = state, Diff = new Vector3(0, 1, 2), MoveType = moveType, CostMultiplier = 1.0f, DestinationVoxel = Storage.Neighborhood[0, 1, 2] }); } if (Storage.Neighborhood[0, 1, 0].IsValid && Storage.Neighborhood[0, 1, 0].IsEmpty) { yield return(new MoveAction { SourceState = state, Diff = new Vector3(0, 1, 0), MoveType = moveType, CostMultiplier = 1.0f, DestinationVoxel = Storage.Neighborhood[0, 1, 0] }); } } } // 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 (Storage.Neighborhood[dx, 1, dz].IsValid && !Storage.Neighborhood[dx, 1, dz].IsEmpty) { // Check to see if there is headspace for a higher jump. //var highAbove = state.Voxel.Chunk.Manager.CreateVoxelHandle(Storage.Neighborhood[dx, 1, dz].Coordinate + new GlobalVoxelOffset(0, 2, 0)); //if (highAbove.IsValid && highAbove.IsEmpty) // yield return new MoveAction // { // SourceState = state, // Diff = new Vector3(dx, 2, dz), // MoveType = MoveType.HighJump, // DestinationVoxel = Storage.Neighborhood[dx, 2, dz], // CostMultiplier = 1.0f // }; //else yield return(new MoveAction { SourceState = state, Diff = new Vector3(dx, 2, dz), MoveType = MoveType.Jump, DestinationVoxel = Storage.Neighborhood[dx, 2, dz], CostMultiplier = 1.0f }); } } } } /* * if (CanDig) * { * // This loop is unrolled for speed. It gets the manhattan neighbors and tells the creature that it can mine * // the surrounding rock to get through. * VoxelHandle neighbor = Storage.Neighborhood[0, 1, 1]; * if (neighbor.IsValid && !neighbor.IsEmpty && (!IsDwarf || !neighbor.IsPlayerBuilt)) * { * yield return (new MoveAction * { * SourceState = state, * Diff = new Vector3(0, 1, 1), * MoveType = MoveType.Dig, * DestinationVoxel = neighbor, * CostMultiplier = 1.0f * }); * } * * neighbor = Storage.Neighborhood[2, 1, 1]; * if (neighbor.IsValid && !neighbor.IsEmpty && (!IsDwarf || !neighbor.IsPlayerBuilt)) * { * yield return (new MoveAction * { * SourceState = state, * Diff = new Vector3(2, 1, 1), * MoveType = MoveType.Dig, * DestinationVoxel = neighbor, * CostMultiplier = 1.0f * }); * } * * neighbor = Storage.Neighborhood[1, 1, 2]; * if (neighbor.IsValid && !neighbor.IsEmpty && (!IsDwarf || !neighbor.IsPlayerBuilt)) * { * yield return (new MoveAction * { * SourceState = state, * Diff = new Vector3(1, 1, 2), * MoveType = MoveType.Dig, * DestinationVoxel = neighbor, * CostMultiplier = 1.0f * }); * } * * neighbor = Storage.Neighborhood[1, 1, 0]; * if (neighbor.IsValid && !neighbor.IsEmpty && (!IsDwarf || !neighbor.IsPlayerBuilt)) * { * yield return (new MoveAction * { * SourceState = state, * Diff = new Vector3(1, 1, 0), * MoveType = MoveType.Dig, * DestinationVoxel = neighbor, * CostMultiplier = 1.0f * }); * } * * neighbor = Storage.Neighborhood[1, 2, 1]; * if (neighbor.IsValid && !neighbor.IsEmpty && (!IsDwarf || !neighbor.IsPlayerBuilt)) * { * yield return (new MoveAction * { * SourceState = state, * Diff = new Vector3(1, 2, 1), * MoveType = MoveType.Dig, * DestinationVoxel = neighbor, * CostMultiplier = 1.0f * }); * } * * neighbor = Storage.Neighborhood[1, 0, 1]; * if (neighbor.IsValid && !neighbor.IsEmpty && (!IsDwarf || !neighbor.IsPlayerBuilt)) * { * yield return (new MoveAction * { * SourceState = state, * Diff = new Vector3(1, 0, 1), * MoveType = MoveType.Dig, * DestinationVoxel = neighbor, * CostMultiplier = 1.0f * }); * } * } */ }
public void WalkUpdate(DwarfTime time, ChunkManager chunks) { { var mouseState = Mouse.GetState(); if (!GameState.Game.GraphicsDevice.Viewport.Bounds.Contains(mouseState.X, mouseState.Y)) { return; } } // Don't attempt any camera control if the user is trying to type intoa focus item. if (World.UserInterface.Gui.FocusItem != null && !World.UserInterface.Gui.FocusItem.IsAnyParentTransparent() && !World.UserInterface.Gui.FocusItem.IsAnyParentHidden()) { return; } if (GameSettings.Default.FogofWar) { var currentCoordinate = GlobalVoxelCoordinate.FromVector3(Position); if (currentCoordinate != _prevVoxelCoord) { VoxelHelpers.RadiusReveal(chunks, new VoxelHandle(chunks, currentCoordinate), 10); _prevVoxelCoord = currentCoordinate; } } float diffPhi = 0; float diffTheta = 0; Vector3 forward = (Target - Position); forward.Normalize(); Vector3 right = Vector3.Cross(forward, UpVector); Vector3 up = Vector3.Cross(right, forward); right.Normalize(); up.Normalize(); MouseState mouse = Mouse.GetState(); KeyboardState keys = Keyboard.GetState(); var bounds = new BoundingBox(World.ChunkManager.Bounds.Min, World.ChunkManager.Bounds.Max + Vector3.UnitY * 20); ZoomTargets.Clear(); Target = MathFunctions.Clamp(Target, bounds); float diffX, diffY = 0; float dt = (float)time.ElapsedRealTime.TotalSeconds; SnapToBounds(new BoundingBox(World.ChunkManager.Bounds.Min, World.ChunkManager.Bounds.Max + Vector3.UnitY * 20)); bool switchState = false; bool isAnyRotationKeyActive = keys.IsKeyDown(ControlSettings.Mappings.CameraMode) || keys.IsKeyDown(Keys.RightShift) || Mouse.GetState().MiddleButton == ButtonState.Pressed; if (isAnyRotationKeyActive && !shiftPressed) { shiftPressed = true; mouseOnRotate = GameState.Game.GraphicsDevice.Viewport.Bounds.Center; mousePrerotate = new Point(mouse.X, mouse.Y); switchState = true; mouseActiveInWalk = !mouseActiveInWalk; } else if (!isAnyRotationKeyActive && shiftPressed) { shiftPressed = false; } if (shiftPressed) { Mouse.SetPosition(mousePrerotate.X, mousePrerotate.Y); KeyManager.TrueMousePos = new Point(mousePrerotate.X, mousePrerotate.Y); } else { KeyManager.TrueMousePos = new Point(mouse.X, mouse.Y); } if (KeyManager.RotationEnabled(this)) { World.UserInterface.Gui.MouseVisible = false; Mouse.SetPosition(mouseOnRotate.X, mouseOnRotate.Y); if (!switchState) { diffX = mouse.X - mouseOnRotate.X; diffY = mouse.Y - mouseOnRotate.Y; } else { diffX = 0; diffY = 0; } if (!isLeftPressed && mouse.LeftButton == ButtonState.Pressed) { isLeftPressed = true; } else if (mouse.LeftButton == ButtonState.Released) { isLeftPressed = false; } if (!isRightPressed && mouse.RightButton == ButtonState.Pressed) { isRightPressed = true; } else if (mouse.RightButton == ButtonState.Released) { isRightPressed = false; } if (!isRightPressed) { float filterDiffX = (float)(diffX * dt); float filterDiffY = (float)(diffY * dt); diffTheta = (filterDiffX); diffPhi = -(filterDiffY); } KeyManager.TrueMousePos = mousePrerotate; } else { World.UserInterface.Gui.MouseVisible = true; } Vector3 velocityToSet = Vector3.Zero; if (EnableControl) { if (keys.IsKeyDown(ControlSettings.Mappings.Forward) || keys.IsKeyDown(Keys.Up)) { Vector3 mov = forward; mov.Normalize(); velocityToSet += mov * CameraMoveSpeed; } else if (keys.IsKeyDown(ControlSettings.Mappings.Back) || keys.IsKeyDown(Keys.Down)) { Vector3 mov = forward; mov.Normalize(); velocityToSet += -mov * CameraMoveSpeed; } if (keys.IsKeyDown(ControlSettings.Mappings.Left) || keys.IsKeyDown(Keys.Left)) { Vector3 mov = right; mov.Normalize(); velocityToSet += -mov * CameraMoveSpeed; } else if (keys.IsKeyDown(ControlSettings.Mappings.Right) || keys.IsKeyDown(Keys.Right)) { Vector3 mov = right; mov.Normalize(); velocityToSet += mov * CameraMoveSpeed; } } if (keys.IsKeyDown(ControlSettings.Mappings.Fly)) { flyKeyPressed = true; } else { if (flyKeyPressed) { flying = !flying; } flyKeyPressed = false; } if (velocityToSet.LengthSquared() > 0) { if (!flying) { float y = Velocity.Y; Velocity = Velocity * 0.5f + 0.5f * velocityToSet; Velocity = new Vector3(Velocity.X, y, Velocity.Z); } else { Velocity = Velocity * 0.5f + 0.5f * velocityToSet; } } LastWheel = mouse.ScrollWheelValue; float ymult = flying ? 0.9f : 1.0f; Velocity = new Vector3(Velocity.X * 0.9f, Velocity.Y * ymult, Velocity.Z * 0.9f); float subSteps = 10.0f; float subStepLength = 1.0f / subSteps; crouched = false; for (int i = 0; i < subSteps; i++) { VoxelHandle currentVoxel = new VoxelHandle(World.ChunkManager, GlobalVoxelCoordinate.FromVector3(Position)); var below = VoxelHelpers.GetNeighbor(currentVoxel, new GlobalVoxelOffset(0, -1, 0)); var above = VoxelHelpers.GetNeighbor(currentVoxel, new GlobalVoxelOffset(0, 1, 0)); if (above.IsValid && !above.IsEmpty) { crouched = true; } if (!flying) { if (!below.IsValid || below.IsEmpty) { Velocity += dt * Gravity * subStepLength; } else if (keys.IsKeyDown(ControlSettings.Mappings.Jump)) { Velocity += -dt * Gravity * subStepLength * 4; } if (currentVoxel.IsValid && currentVoxel.LiquidLevel > 0) { Velocity += -dt * Gravity * subStepLength * 0.999f; if (keys.IsKeyDown(ControlSettings.Mappings.Jump)) { Velocity += -dt * Gravity * subStepLength * 0.5f; } Velocity *= 0.99f; } } if (!CollidesWithChunks(World.ChunkManager, Position, true, true, 0.4f, 0.9f)) { MoveTarget(Velocity * dt * subStepLength); PushVelocity = Vector3.Zero; } else { MoveTarget(Velocity * dt * subStepLength); } } VoxelHandle voxelAfterMove = new VoxelHandle(World.ChunkManager, GlobalVoxelCoordinate.FromVector3(Position)); if (voxelAfterMove.IsValid && !voxelAfterMove.IsEmpty) { float distCenter = (voxelAfterMove.GetBoundingBox().Center() - Position).Length(); if (distCenter < 0.5f) { float closest = float.MaxValue; VoxelHandle closestVoxel = VoxelHandle.InvalidHandle; foreach (var voxel in VoxelHelpers.EnumerateAllNeighbors(voxelAfterMove.Coordinate).Select(c => new VoxelHandle(World.ChunkManager, c)).Where(v => v.IsEmpty)) { float d = (voxel.GetBoundingBox().Center() - Position).Length(); if (d < closest) { closest = d; closestVoxel = voxel; } } if (closestVoxel.IsValid) { var newPosition = closestVoxel.GetBoundingBox().Center(); var diff = (newPosition - Position); MoveTarget(diff); } } } Target += right * diffTheta * 0.1f; var newTarget = up * diffPhi * 0.1f + Target; var newForward = (Target - Position); if (Math.Abs(Vector3.Dot(newForward, UpVector)) < 0.99f) { Target = newTarget; } var diffTarget = Target - Position; diffTarget.Normalize(); Target = Position + diffTarget * 1.0f; UpdateBasisVectors(); UpdateViewMatrix(); }
private bool CanPlace(VoxelHandle Location, Rail.JunctionPiece Piece, RailPiece PreviewEntity) { var actualPosition = new VoxelHandle(Location.Chunk.Manager.ChunkData, Location.Coordinate + new GlobalVoxelOffset(Piece.Offset.X, 0, Piece.Offset.Y)); if (!actualPosition.IsValid) { return(false); } if (!actualPosition.IsEmpty) { return(false); } if (actualPosition.Coordinate.Y == 0) { return(false); // ??? } var local = actualPosition.Coordinate.GetLocalVoxelCoordinate(); var voxelUnder = new VoxelHandle(actualPosition.Chunk, new LocalVoxelCoordinate(local.X, local.Y - 1, local.Z)); if (voxelUnder.IsEmpty) { return(false); } foreach (var entity in Player.World.CollisionManager.EnumerateIntersectingObjects(actualPosition.GetBoundingBox().Expand(-0.2f), CollisionManager.CollisionType.Static)) { if (Object.ReferenceEquals(entity, PreviewEntity)) { continue; } if (entity is NewVoxelListener) { continue; } if (FindPossibleCombination(Piece, entity) != null) { return(true); } if (GamePerformance.DebugVisualizationEnabled) { Drawer3D.DrawBox(entity.GetBoundingBox(), Color.Yellow, 0.1f, false); } return(false); } return(true); }