public static bool IsValidPlacement( VoxelHandle Location, CraftItem CraftType, GameMaster Player, Body PreviewBody, String Verb, String PastParticple) { if (CraftType == null) { return(false); } if (!String.IsNullOrEmpty(CraftType.CraftLocation) && Player.Faction.FindNearestItemWithTags(CraftType.CraftLocation, Location.WorldPosition, false, null) == null) { Player.World.ShowToolPopup("Can't " + Verb + ", need " + CraftType.CraftLocation); return(false); } foreach (var req in CraftType.Prerequisites) { switch (req) { case CraftItem.CraftPrereq.NearWall: { var neighborFound = VoxelHelpers.EnumerateManhattanNeighbors2D(Location.Coordinate) .Select(c => new VoxelHandle(Player.World.ChunkManager.ChunkData, c)) .Any(v => v.IsValid && !v.IsEmpty); if (!neighborFound) { Player.World.ShowToolPopup("Must be " + PastParticple + " next to wall!"); return(false); } break; } case CraftItem.CraftPrereq.OnGround: { var below = VoxelHelpers.GetNeighbor(Location, new GlobalVoxelOffset(0, -1, 0)); if (!below.IsValid || below.IsEmpty) { Player.World.ShowToolPopup("Must be " + PastParticple + " on solid ground!"); return(false); } break; } } } if (PreviewBody != null) { // Just check for any intersecting body in octtree. var previewBox = PreviewBody.GetRotatedBoundingBox(); var sensorBox = previewBox; var sensor = PreviewBody.GetComponent <GenericVoxelListener>(); if (sensor != null) { sensorBox = sensor.GetRotatedBoundingBox(); } if (Debugger.Switches.DrawToolDebugInfo) { Drawer3D.DrawBox(sensorBox, Color.Yellow, 0.1f, false); } foreach (var intersectingObject in Player.World.EnumerateIntersectingObjects(sensorBox, CollisionType.Static)) { if (Object.ReferenceEquals(intersectingObject, sensor)) { continue; } var objectRoot = intersectingObject.GetRoot() as Body; if (objectRoot is WorkPile) { continue; } if (objectRoot != null && objectRoot.GetRotatedBoundingBox().Intersects(previewBox)) { Player.World.ShowToolPopup("Can't " + Verb + " here: intersects " + objectRoot.Name); return(false); } } bool intersectsWall = VoxelHelpers.EnumerateCoordinatesInBoundingBox (PreviewBody.GetRotatedBoundingBox().Expand(-0.1f)).Any( v => { var tvh = new VoxelHandle(Player.World.ChunkManager.ChunkData, v); return(tvh.IsValid && !tvh.IsEmpty); }); if (intersectsWall && !CraftType.Prerequisites.Contains(CraftItem.CraftPrereq.NearWall)) { Player.World.ShowToolPopup("Can't " + Verb + " here: intersects wall."); return(false); } } Player.World.ShowToolPopup(""); return(true); }
private bool ValidatePlanting(VoxelHandle voxel) { if (!voxel.Type.IsSoil) { World.UserInterface.ShowTooltip("Can only plant on soil!"); return(false); } if (Library.GetResourceType(PlantType).HasValue(out var plantRes)) { if (plantRes.Tags.Contains("AboveGroundPlant")) { if (voxel.Sunlight == false) { World.UserInterface.ShowTooltip("Can only plant " + PlantType + " above ground."); return(false); } } else if (plantRes.Tags.Contains("BelowGroundPlant")) { if (voxel.Sunlight) { World.UserInterface.ShowTooltip("Can only plant " + PlantType + " below ground."); return(false); } } } if (World.PersistentData.Designations.GetVoxelDesignation(voxel, DesignationType.Plant).HasValue(out var designation)) { 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().Any(z => z.GetBoundingBox().Expand(0.1f).Intersects(voxelBox))) { World.UserInterface.ShowTooltip("Can't plant inside zones."); return(false); } World.UserInterface.ShowTooltip("Click to plant."); return(true); }
/// <summary> /// This is the underlying Dig behavior that dwarves follow while digging. /// </summary> /// <param name="agent">The agent.</param> /// <param name="voxel">The voxel.</param> /// <param name="energyLoss">The energy loss the dwarf gets per block mined.</param> /// <returns>Success when the block is mined, fail if it fails to be mined, and running otherwise.</returns> public static IEnumerable <Act.Status> Dig(this Creature agent, string voxel, float energyLoss) { agent.Sprite.ResetAnimations(Creature.CharacterMode.Attacking); // Block since we're in a coroutine. while (true) { // Get the voxel stored in the agent's blackboard. Voxel blackBoardVoxel = agent.AI.Blackboard.GetData <Voxel>(voxel); // Somehow, there wasn't a voxel to mine. if (blackBoardVoxel == null) { agent.DrawIndicator(IndicatorManager.StandardIndicators.Question); yield return(Act.Status.Fail); break; } Voxel vox = blackBoardVoxel; // If the voxel has already been destroyed, just ignore it and return. if (vox.Health <= 0.0f || !agent.Faction.IsDigDesignation(vox)) { agent.AI.AddXP(Math.Max((int)(VoxelLibrary.GetVoxelType(blackBoardVoxel.TypeName).StartingHealth / 4), 1)); agent.Stats.NumBlocksDestroyed++; agent.CurrentCharacterMode = Creature.CharacterMode.Idle; yield return(Act.Status.Success); break; } // Look at the block and slow your velocity down. agent.Physics.Face(vox.Position + Vector3.One * 0.5f); agent.Physics.Velocity *= 0.9f; // Play the attack animations. agent.CurrentCharacterMode = Creature.CharacterMode.Attacking; agent.Sprite.ResetAnimations(agent.CurrentCharacterMode); agent.Sprite.PlayAnimations(agent.CurrentCharacterMode); // Wait until an attack was successful... foreach (var status in agent.Attacks[0].Perform(agent, agent.Physics.Position, vox, DwarfTime.LastTime, agent.Stats.BaseDigSpeed, agent.Faction.Name)) { if (status == Act.Status.Running) { agent.Physics.Face(vox.Position + Vector3.One * 0.5f); agent.Physics.Velocity *= 0.9f; // Debug drawing. if (agent.AI.DrawPath) { Drawer3D.DrawLine(vox.Position, agent.AI.Position, Color.Green, 0.25f); } yield return(Act.Status.Running); } } // If the voxel has been destroyed by you, gather it. if (vox.Health <= 0.0f) { List <Body> items = vox.Kill(); if (items != null) { foreach (Body item in items) { agent.Gather(item); } } } // Wait until the animation is done playing before continuing. while (!agent.Sprite.CurrentAnimation.IsDone() && agent.Sprite.CurrentAnimation.IsPlaying) { agent.Physics.Face(vox.Position + Vector3.One * 0.5f); agent.Physics.Velocity *= 0.9f; yield return(Act.Status.Running); } // Pause the animation and wait for a recharge timer. agent.Sprite.PauseAnimations(agent.CurrentCharacterMode); // Wait for a recharge timer to trigger. agent.Attacks[0].RechargeTimer.Reset(); while (!agent.Attacks[0].RechargeTimer.HasTriggered) { agent.Attacks[0].RechargeTimer.Update(DwarfTime.LastTime); agent.Physics.Face(vox.Position + Vector3.One * 0.5f); agent.Physics.Velocity *= 0.9f; yield return(Act.Status.Running); } agent.CurrentCharacterMode = Creature.CharacterMode.Idle; yield return(Act.Status.Running); } }
public override IEnumerable <Status> Run() { while (true) { Creature.AI.Blackboard.Erase(PathName); Agent.Blackboard.SetData <bool>("NoPath", false); PlanAct planAct = new PlanAct(Creature.AI, PathName, VoxelName, PlanType) { Radius = Radius, MaxTimeouts = MaxTimeouts }; planAct.Initialize(); bool planSucceeded = false; while (true) { Act.Status planStatus = planAct.Tick(); if (planStatus == Status.Fail) { yield return(Act.Status.Running); break; } else if (planStatus == Status.Running) { yield return(Act.Status.Running); } else if (planStatus == Status.Success) { planSucceeded = true; break; } yield return(Act.Status.Running); } if (!planSucceeded && planAct.LastResult == AStarPlanner.PlanResultCode.MaxExpansionsReached) { yield return(Act.Status.Running); Creature.CurrentCharacterMode = CharacterMode.Idle; Creature.Physics.Velocity = Vector3.Zero; Timer planTimeout = new Timer(MathFunctions.Rand(30.0f, 120.0f), false, Timer.TimerMode.Real); List <VoxelHandle> exploredVoxels = new List <VoxelHandle>(); Color debugColor = new Color(MathFunctions.RandVector3Cube() + Vector3.One * 0.5f); float debugScale = MathFunctions.Rand() * 0.5f + 0.5f; while (!planTimeout.HasTriggered) { // In this case, try to follow a greedy path toward the entity instead of just failing. var greedyPath = planAct.ComputeGreedyFallback(20, exploredVoxels); var goal = planAct.GetGoal(); Creature.AI.Blackboard.SetData("GreedyPath", greedyPath); var greedyPathFollow = new FollowPathAct(Creature.AI, "GreedyPath") { BlendEnd = true, BlendStart = false }; greedyPathFollow.Initialize(); foreach (var currStatus in greedyPathFollow.Run()) { if (Debugger.Switches.DrawPaths) { foreach (var voxel in exploredVoxels) { Drawer3D.DrawBox(voxel.GetBoundingBox().Expand(-debugScale), debugColor, 0.05f, false); } } if (!exploredVoxels.Contains(Agent.Physics.CurrentVoxel)) { exploredVoxels.Add(Agent.Physics.CurrentVoxel); } if (Debugger.Switches.DrawPaths) { Drawer3D.DrawLine(Agent.Position, goal.GetVoxel().WorldPosition, debugColor, 0.1f); } if (goal.IsInGoalRegion(Agent.Physics.CurrentVoxel)) { yield return(Act.Status.Success); yield break; } yield return(Act.Status.Running); } planTimeout.Update(DwarfTime.LastTime); } continue; } else if (!planSucceeded) { Agent.Blackboard.SetData <bool>("NoPath", true); yield return(Act.Status.Fail); yield break; } yield return(Act.Status.Success); yield break; } }
public override IEnumerable <Status> Run() { Path = null; Timeouts = 0; PlannerTimer.Reset(PlannerTimer.TargetTimeSeconds); var lastId = -1; Vector3 goalPos = Vector3.Zero; Agent.Blackboard.SetData <bool>("NoPath", false); while (true) { if (Path != null) { yield return(Status.Success); break; } if (Timeouts > MaxTimeouts) { Agent.Blackboard.SetData <bool>("NoPath", true); yield return(Status.Fail); break; } if (WaitingOnResponse && Debugger.Switches.DrawPaths) { Drawer3D.DrawLine(Creature.AI.Position, goalPos, Color.Blue, 0.25f); } PlannerTimer.Update(DwarfTime.LastTime); ChunkManager chunks = Creature.Manager.World.ChunkManager; if (PlannerTimer.HasTriggered || Timeouts == 0) { if (!Target.IsValid && Type != PlanType.Edge) { Creature.DrawIndicator(IndicatorManager.StandardIndicators.Question); Agent.Blackboard.SetData <bool>("NoPath", true); yield return(Status.Fail); break; } var voxUnder = VoxelHelpers.GetValidVoxelNear(chunks, Agent.Position); if (!voxUnder.IsValid) { if (Debugger.Switches.DrawPaths) { Creature.World.MakeWorldPopup(String.Format("Invalid request"), Creature.Physics, -10, 1); } Creature.DrawIndicator(IndicatorManager.StandardIndicators.Question); Agent.Blackboard.SetData <bool>("NoPath", true); yield return(Status.Fail); break; } Path = null; AstarPlanRequest aspr = new AstarPlanRequest { Subscriber = Agent.PlanSubscriber, Start = voxUnder, MaxExpansions = MaxExpansions, Sender = Agent, HeuristicWeight = Weights[Timeouts] }; lastId = aspr.ID; aspr.GoalRegion = GetGoal(); goalPos = GetGoal().GetVoxel().GetBoundingBox().Center(); Agent.PlanSubscriber.Clear(); if (!Agent.PlanSubscriber.SendRequest(aspr, aspr.ID)) { yield return(Status.Fail); yield break; } PlannerTimer.Reset(PlannerTimer.TargetTimeSeconds); WaitingOnResponse = true; yield return(Status.Running); Timeouts++; } else { if (Target.IsValid && Creature.AI.DrawAIPlan) { Drawer3D.DrawLine(Creature.AI.Position, Target.WorldPosition, Color.Blue, 0.25f); } Status statusResult = Status.Running; while (Agent.PlanSubscriber.Responses.Count > 0) { AStarPlanResponse response; if (!Agent.PlanSubscriber.Responses.TryDequeue(out response)) { yield return(Status.Running); continue; } LastResult = response.Result; if (response.Success && response.Request.ID == lastId) { Path = response.Path; WaitingOnResponse = false; statusResult = Status.Success; } else if (response.Request.ID != lastId) { bool obeysGoal = response.Success && (GetGoal().IsInGoalRegion(response.Path.Last().DestinationVoxel)); if (Debugger.Switches.DrawPaths) { if (obeysGoal) { Creature.World.MakeWorldPopup(String.Format("Using Old Path", response.Result), Creature.Physics, -10, 1); } else { Creature.World.MakeWorldPopup(String.Format("Old Path Dropped", response.Result), Creature.Physics, -10, 1); } } if (obeysGoal) { Path = response.Path; WaitingOnResponse = false; statusResult = Status.Success; } else { continue; } } else if (response.Result == AStarPlanner.PlanResultCode.Invalid || response.Result == AStarPlanner.PlanResultCode.NoSolution || response.Result == AStarPlanner.PlanResultCode.Cancelled || response.Result == AStarPlanner.PlanResultCode.Invalid) { if (Debugger.Switches.DrawPaths) { Creature.World.MakeWorldPopup(String.Format("Path: {0}", response.Result), Creature.Physics, -10, 1); } Creature.DrawIndicator(IndicatorManager.StandardIndicators.Question); Agent.Blackboard.SetData <bool>("NoPath", true); statusResult = Status.Fail; yield return(Status.Fail); } else if (Timeouts <= MaxTimeouts) { Timeouts++; yield return(Status.Running); } else { if (Debugger.Switches.DrawPaths) { Creature.World.MakeWorldPopup(String.Format("Max timeouts reached", response.Result), Creature.Physics, -10, 1); } Creature.DrawIndicator(IndicatorManager.StandardIndicators.Question); Agent.Blackboard.SetData <bool>("NoPath", true); statusResult = Status.Fail; } } yield return(statusResult); } } }
override public void Update(DwarfTime gameTime, ChunkManager chunks, Camera camera) { base.Update(gameTime, chunks, camera); Storm.InitializeStatics(); BoundingBox box = chunks.Bounds; box.Expand(10.0f); if (GlobalTransform.Translation.X < box.Min.X || GlobalTransform.Translation.X > box.Max.X || GlobalTransform.Translation.Z < box.Min.Z || GlobalTransform.Translation.Z > box.Max.Z) { Die(); } bool generateRainDrop = MathFunctions.RandEvent(Raininess * 0.75f); if (generateRainDrop) { for (int i = 0; i < MaxRainDrops; i++) { if (!RainDrops[i].IsAlive) { RainDrops[i].IsAlive = true; if (RainDrops[i].Particle != null) { RainDrops[i].Particle.LifeRemaining = 60.0f; RainDrops[i].Particle.TimeAlive = 0.0f; } RainDrops[i].Pos = MathFunctions.RandVector3Box(BoundingBox.Expand(5)); RainDrops[i].Pos = new Vector3(RainDrops[i].Pos.X, BoundingBox.Min.Y - 1, RainDrops[i].Pos.Z); RainDrops[i].Vel = Vector3.Down * Storm.Properties[TypeofStorm].RainSpeed + Velocity; break; } } } bool generateLightning = LightningChance > 0.0f && MathFunctions.RandEvent((float)(LightningChance * 0.001f)); if (generateLightning) { var below = VoxelHelpers.FindFirstVoxelBelowIncludingWater(new VoxelHandle(World.ChunkManager, GlobalVoxelCoordinate.FromVector3(new Vector3(Position.X, Math.Min(World.WorldSizeInVoxels.Y - 1, Position.Y), Position.Z)))); if (below.IsValid && !below.IsEmpty) { var above = VoxelHelpers.GetVoxelAbove(below); if (above.IsValid) { EntityFactory.CreateEntity <Fire>("Fire", above.GetBoundingBox().Center()); List <Vector3> lightningStrikes = new List <Vector3>(); List <Color> colors = new List <Color>(); var c = above.GetBoundingBox().Center(); for (float t = 0; t < 1.0f; t += 0.25f) { var p = c * t + Position * (1.0f - t); lightningStrikes.Add(p + MathFunctions.RandVector3Box(-5, 5, 0, 0.1f, -5, 5)); colors.Add(Color.White); } lightningStrikes.Add(c); colors.Add(Color.White); Drawer3D.DrawLineList(lightningStrikes, colors, 0.3f); SoundManager.PlaySound(ContentPaths.Audio.Oscar.sfx_gui_rain_storm_alert, MathFunctions.Rand(0.001f, 0.05f), MathFunctions.Rand(0.5f, 1.0f)); SoundManager.PlaySound(ContentPaths.Audio.Oscar.sfx_trap_destroyed, c, false, 1.0f, MathFunctions.Rand(-0.5f, 0.5f)); World.ParticleManager.Trigger("explode", c, Color.White, 10); } } } Storm.StormProperties stormProperties = Storm.Properties[TypeofStorm]; var rainEmitter = World.ParticleManager.Effects[stormProperties.RainEffect]; var hitEmitter = World.ParticleManager.Effects[stormProperties.HitEffect]; for (int i = 0; i < MaxRainDrops; i++) { if (!RainDrops[i].IsAlive) { continue; } RainDrops[i].Pos += RainDrops[i].Vel * DwarfTime.Dt; if (stormProperties.RainRandom > 0) { RainDrops[i].Vel.X += MathFunctions.Rand(-1, 1) * stormProperties.RainRandom * DwarfTime.Dt; RainDrops[i].Vel.Z += MathFunctions.Rand(-1, 1) * stormProperties.RainRandom * DwarfTime.Dt; } if (RainDrops[i].Pos.Y < 0) { RainDrops[i].IsAlive = false; } if (!RainDrops[i].IsAlive && RainDrops[i].Particle != null) { RainDrops[i].Particle.LifeRemaining = -1; } else if (RainDrops[i].IsAlive && RainDrops[i].Particle == null) { RainDrops[i].Particle = rainEmitter.Emitters[0].CreateParticle(RainDrops[i].Pos, RainDrops[i].Vel, Color.White); } else if (RainDrops[i].IsAlive && RainDrops[i].Particle != null) { RainDrops[i].Particle.Position = RainDrops[i].Pos; RainDrops[i].Particle.Velocity = RainDrops[i].Vel; } var test = new VoxelHandle(chunks, GlobalVoxelCoordinate.FromVector3(RainDrops[i].Pos)); if (!test.IsValid || (test.IsEmpty && test.LiquidLevel == 0)) { continue; } RainDrops[i].IsAlive = false; var hitBodies = World.EnumerateIntersectingObjects(new BoundingBox(RainDrops[i].Pos - Vector3.One, RainDrops[i].Pos + Vector3.One)); foreach (var body in hitBodies) { if (body.Parent != Manager.RootComponent) { continue; } var flames = body.GetRoot().GetComponent <Flammable>(); if (flames != null) { flames.Heat *= 0.25f; } var seeds = body.GetRoot().GetComponent <Seedling>(); if (seeds != null) { if (TypeofStorm == StormType.RainStorm) { seeds.GrowthTime += MathFunctions.Rand(1.0f, 12.0f); } else if (MathFunctions.RandEvent(0.01f)) { seeds.GetRoot().Die(); } } } hitEmitter.Trigger(1, RainDrops[i].Pos + Vector3.UnitY * 0.5f, Color.White); //if (!MathFunctions.RandEvent(0.1f)) continue; var above = test.IsEmpty ? test : VoxelHelpers.GetVoxelAbove(test); if (!above.IsValid || !above.IsEmpty) { continue; } if (TypeofStorm == StormType.RainStorm && (above.LiquidLevel < WaterManager.maxWaterLevel && (above.LiquidType == LiquidType.Water))) { above.LiquidLevel = (byte)Math.Min(WaterManager.maxWaterLevel, above.LiquidLevel + WaterManager.rainFallAmount); above.LiquidType = stormProperties.LiquidToCreate; } else if (TypeofStorm == StormType.SnowStorm && above.IsEmpty && above.LiquidLevel == 0) { if (test.GrassType == 0) { test.GrassType = Library.GetGrassType("snow").ID; test.GrassDecay = Library.GetGrassType("snow").InitialDecayValue; } else { var existingGrass = Library.GetGrassType((byte)test.GrassType); if (!String.IsNullOrEmpty(existingGrass.BecomeWhenSnowedOn)) { var newGrass = Library.GetGrassType(existingGrass.BecomeWhenSnowedOn); test.GrassType = newGrass.ID; test.GrassDecay = newGrass.InitialDecayValue; } } } } Matrix tf = LocalTransform; tf.Translation += Velocity * DwarfTime.Dt; LocalTransform = tf; }
/// <summary> /// Called when a frame is to be drawn to the screen /// </summary> /// <param name="gameTime">The current time</param> public void Render(DwarfTime gameTime) { if (!ShowingWorld) { return; } var frustum = Camera.GetDrawFrustum(); var renderables = EnumerateIntersectingObjects(frustum) .Where(r => r.IsVisible && !ChunkManager.IsAboveCullPlane(r.GetBoundingBox())); // Controls the sky fog float x = (1.0f - Sky.TimeOfDay); x = x * x; DefaultShader.FogColor = new Color(0.32f * x, 0.58f * x, 0.9f * x); DefaultShader.LightPositions = LightPositions; CompositeLibrary.Render(GraphicsDevice); CompositeLibrary.Update(); GraphicsDevice.DepthStencilState = DepthStencilState.Default; GraphicsDevice.BlendState = BlendState.Opaque; // Computes the water height. float wHeight = WaterRenderer.GetVisibleWaterHeight(ChunkManager, Camera, GraphicsDevice.Viewport, lastWaterHeight); lastWaterHeight = wHeight; // Draw reflection/refraction images WaterRenderer.DrawReflectionMap(renderables, gameTime, this, wHeight - 0.1f, GetReflectedCameraMatrix(wHeight), DefaultShader, GraphicsDevice); #region Draw Selection Buffer. if (SelectionBuffer == null) { SelectionBuffer = new SelectionBuffer(8, GraphicsDevice); } GraphicsDevice.RasterizerState = RasterizerState.CullNone; GraphicsDevice.DepthStencilState = DepthStencilState.Default; GraphicsDevice.BlendState = BlendState.Opaque; Plane slicePlane = WaterRenderer.CreatePlane(SlicePlane, new Vector3(0, -1, 0), Camera.ViewMatrix, false); if (SelectionBuffer.Begin(GraphicsDevice)) { // Draw the whole world, and make sure to handle slicing DefaultShader.ClipPlane = new Vector4(slicePlane.Normal, slicePlane.D); DefaultShader.ClippingEnabled = true; DefaultShader.View = Camera.ViewMatrix; DefaultShader.Projection = Camera.ProjectionMatrix; DefaultShader.World = Matrix.Identity; //GamePerformance.Instance.StartTrackPerformance("Render - Selection Buffer - Chunks"); ChunkRenderer.RenderSelectionBuffer(DefaultShader, GraphicsDevice, Camera.ViewMatrix); //GamePerformance.Instance.StopTrackPerformance("Render - Selection Buffer - Chunks"); //GamePerformance.Instance.StartTrackPerformance("Render - Selection Buffer - Components"); ComponentRenderer.RenderSelectionBuffer(renderables, gameTime, ChunkManager, Camera, DwarfGame.SpriteBatch, GraphicsDevice, DefaultShader); //GamePerformance.Instance.StopTrackPerformance("Render - Selection Buffer - Components"); //GamePerformance.Instance.StartTrackPerformance("Render - Selection Buffer - Instances"); InstanceRenderer.Flush(GraphicsDevice, DefaultShader, Camera, InstanceRenderMode.SelectionBuffer); //GamePerformance.Instance.StopTrackPerformance("Render - Selection Buffer - Instances"); SelectionBuffer.End(GraphicsDevice); } #endregion // Start drawing the bloom effect if (GameSettings.Default.EnableGlow) { bloom.BeginDraw(); } // Draw the sky GraphicsDevice.Clear(DefaultShader.FogColor); DrawSky(gameTime, Camera.ViewMatrix, 1.0f, DefaultShader.FogColor); // Defines the current slice for the GPU float level = ChunkManager.World.Master.MaxViewingLevel + 0.25f; if (level > VoxelConstants.ChunkSizeY) { level = 1000; } SlicePlane = level; DefaultShader.WindDirection = Weather.CurrentWind; DefaultShader.WindForce = 0.0005f * (1.0f + (float)Math.Sin(Time.GetTotalSeconds() * 0.001f)); // Draw the whole world, and make sure to handle slicing DefaultShader.ClipPlane = new Vector4(slicePlane.Normal, slicePlane.D); DefaultShader.ClippingEnabled = true; //Blue ghost effect above the current slice. DefaultShader.GhostClippingEnabled = true; Draw3DThings(gameTime, DefaultShader, Camera.ViewMatrix); // Now we want to draw the water on top of everything else DefaultShader.ClippingEnabled = true; DefaultShader.GhostClippingEnabled = false; //ComponentManager.CollisionManager.DebugDraw(); DefaultShader.View = Camera.ViewMatrix; DefaultShader.Projection = Camera.ProjectionMatrix; DefaultShader.GhostClippingEnabled = true; // Now draw all of the entities in the game DefaultShader.ClipPlane = new Vector4(slicePlane.Normal, slicePlane.D); DefaultShader.ClippingEnabled = true; if (Debugger.Switches.DrawOcttree) { foreach (var box in OctTree.EnumerateBounds(frustum)) { Drawer3D.DrawBox(box.Item2, Color.Yellow, 1.0f / (float)(box.Item1 + 1), false); } } // Render simple geometry (boxes, etc.) Drawer3D.Render(GraphicsDevice, DefaultShader, Camera, DesignationDrawer, PlayerFaction.Designations, this); DefaultShader.EnableShadows = false; DefaultShader.View = Camera.ViewMatrix; ComponentRenderer.Render(renderables, gameTime, ChunkManager, Camera, DwarfGame.SpriteBatch, GraphicsDevice, DefaultShader, ComponentRenderer.WaterRenderType.None, lastWaterHeight); InstanceRenderer.Flush(GraphicsDevice, DefaultShader, Camera, InstanceRenderMode.Normal); if (Master.CurrentToolMode == GameMaster.ToolMode.BuildZone || Master.CurrentToolMode == GameMaster.ToolMode.BuildWall || Master.CurrentToolMode == GameMaster.ToolMode.BuildObject) { DefaultShader.View = Camera.ViewMatrix; DefaultShader.Projection = Camera.ProjectionMatrix; DefaultShader.SetTexturedTechnique(); GraphicsDevice.BlendState = BlendState.NonPremultiplied; } WaterRenderer.DrawWater( GraphicsDevice, (float)gameTime.TotalGameTime.TotalSeconds, DefaultShader, Camera.ViewMatrix, GetReflectedCameraMatrix(wHeight), Camera.ProjectionMatrix, new Vector3(0.1f, 0.0f, 0.1f), Camera, ChunkManager); ParticleManager.Render(this, GraphicsDevice); DefaultShader.ClippingEnabled = false; if (GameSettings.Default.EnableGlow) { bloom.DrawTarget = UseFXAA ? fxaa.RenderTarget : null; if (UseFXAA) { fxaa.Begin(DwarfTime.LastTime); } bloom.Draw(gameTime.ToRealTime()); if (UseFXAA) { fxaa.End(DwarfTime.LastTime); } } else if (UseFXAA) { fxaa.End(DwarfTime.LastTime); } RasterizerState rasterizerState = new RasterizerState() { ScissorTestEnable = true }; if (Debugger.Switches.DrawSelectionBuffer) { SelectionBuffer.DebugDraw(GraphicsDevice.Viewport.Bounds); } try { DwarfGame.SafeSpriteBatchBegin(SpriteSortMode.Deferred, BlendState.NonPremultiplied, Drawer2D.PointMagLinearMin, null, rasterizerState, null, Matrix.Identity); //DwarfGame.SpriteBatch.Draw(Shadows.ShadowTexture, Vector2.Zero, Color.White); if (IsCameraUnderwater()) { Drawer2D.FillRect(DwarfGame.SpriteBatch, GraphicsDevice.Viewport.Bounds, new Color(10, 40, 60, 200)); } Drawer2D.Render(DwarfGame.SpriteBatch, Camera, GraphicsDevice.Viewport); IndicatorManager.Render(gameTime); } finally { DwarfGame.SpriteBatch.End(); } if (Debugger.Switches.DrawComposites) { Vector2 offset = Vector2.Zero; foreach (var composite in CompositeLibrary.Composites) { offset = composite.Value.DebugDraw(DwarfGame.SpriteBatch, (int)offset.X, (int)offset.Y); } } Master.Render(Game, gameTime, GraphicsDevice); DwarfGame.SpriteBatch.GraphicsDevice.ScissorRectangle = DwarfGame.SpriteBatch.GraphicsDevice.Viewport.Bounds; GraphicsDevice.DepthStencilState = DepthStencilState.Default; GraphicsDevice.BlendState = BlendState.Opaque; lock (ScreenshotLock) { foreach (Screenshot shot in Screenshots) { TakeScreenshot(shot.FileName, shot.Resolution); } Screenshots.Clear(); } }
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: if (!Step.DestinationVoxel.IsEmpty) { yield return(Status.Fail); } 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(); if (!Step.DestinationVoxel.IsEmpty) { yield return(Status.Fail); } SetAgentTranslation(GetPathPoint(Step.DestinationVoxel)); break; case MoveType.RideVehicle: if (!Step.DestinationVoxel.IsEmpty) { yield return(Status.Fail); } 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: CleanupMinecart(); // Todo: Fail if distance is too great. if (!Step.DestinationVoxel.IsEmpty) { yield return(Status.Fail); } foreach (var bit in Translate(Agent.Position, GetPathPoint(Step.DestinationVoxel), actionSpeed)) { SetCharacterMode(CharacterMode.Walking); yield return(Status.Running); } break; case MoveType.Swim: CleanupMinecart(); if (!Step.DestinationVoxel.IsEmpty) { yield return(Status.Fail); } 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(); if (!Step.DestinationVoxel.IsEmpty) { yield return(Status.Fail); } 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(); if (!Step.DestinationVoxel.IsEmpty) { yield return(Status.Fail); } 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(); if (!Step.DestinationVoxel.IsEmpty) { yield return(Status.Fail); } foreach (var bit in Translate(Agent.Position, GetPathPoint(Step.DestinationVoxel), actionSpeed)) { SetCharacterMode(CharacterMode.Falling); yield return(Status.Running); } break; case MoveType.Climb: CleanupMinecart(); if (!Step.DestinationVoxel.IsEmpty) { yield return(Status.Fail); } 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(); if (!Step.DestinationVoxel.IsEmpty) { yield return(Status.Fail); } 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(); if (!Step.DestinationVoxel.IsEmpty) { yield return(Status.Fail); } 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(); if (Step.DestinationVoxel.IsEmpty) // Reverse of other states! { yield return(Status.Fail); } 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(); if (!Step.DestinationVoxel.IsEmpty) { yield return(Status.Fail); } 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.DestinationVoxel.IsEmpty) { yield return(Status.Fail); } 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; } }