public IEnumerable <Act.Status> WrangleAnimal(CreatureAI agent, CreatureAI creature) { creature.PositionConstraint = new BoundingBox(agent.Position - new Vector3(1.0f, 0.5f, 1.0f), agent.Position + new Vector3(1.0f, 0.5f, 1.0f)); Drawer3D.DrawLine(creature.Position, agent.Position, Color.Black, 0.05f); yield return(Act.Status.Success); }
public virtual void Render(DwarfTime gameTime, ChunkManager chunks, Camera camera, SpriteBatch spriteBatch, GraphicsDevice graphicsDevice, Shader effect, bool renderingForWater) { if (Debugger.Switches.DrawBoundingBoxes) { Drawer3D.DrawBox(BoundingBox, Color.Blue, 0.02f, false); Drawer3D.DrawLine(GlobalTransform.Translation, GlobalTransform.Translation + Vector3.UnitX, Color.Red, 0.02f); Drawer3D.DrawLine(GlobalTransform.Translation, GlobalTransform.Translation + Vector3.UnitY, Color.Blue, 0.02f); Drawer3D.DrawLine(GlobalTransform.Translation, GlobalTransform.Translation + Vector3.UnitZ, Color.Green, 0.02f); } }
private void DrawDebugPath() { if (Debugger.Switches.DrawPaths) { for (var i = 0; i < Path.Count; ++i) { if (Path[i].MoveType == MoveType.Jump) { Drawer3D.DrawLine(GetPathPoint(Path[i].SourceVoxel), GetPathPoint(Path[i].DestinationVoxel), Color.Red, 0.1f); } else { Drawer3D.DrawLine(GetPathPoint(Path[i].SourceVoxel), GetPathPoint(Path[i].DestinationVoxel), Color.Blue, 0.1f); } } } }
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.FindValidVoxelNear(chunks, Agent.Position); if (!voxUnder.IsValid) { if (Debugger.Switches.DrawPaths) { Creature.World.UserInterface.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 { 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 && response.Path != null && response.Path.Count > 0) { var goal = GetGoal(); bool obeysGoal = goal == null ? false : (response.Success && (goal.IsInGoalRegion(response.Path.Last().DestinationVoxel))); if (Debugger.Switches.DrawPaths) { if (obeysGoal) { Creature.World.UserInterface.MakeWorldPopup(String.Format("Using Old Path", response.Result), Creature.Physics, -10, 1); } else { Creature.World.UserInterface.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.UserInterface.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.UserInterface.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); } } }
public override IEnumerable <Status> Run() { Path = null; Timeouts = 0; PlannerTimer.Reset(PlannerTimer.TargetTimeSeconds); Voxel voxUnder = new Voxel(); while (true) { if (Path != null) { yield return(Status.Success); break; } if (Timeouts > MaxTimeouts) { yield return(Status.Fail); break; } PlannerTimer.Update(DwarfTime.LastTime); ChunkManager chunks = PlayState.ChunkManager; if (PlannerTimer.HasTriggered || Timeouts == 0) { if (!chunks.ChunkData.GetVoxel(Agent.Position, ref voxUnder)) { Creature.DrawIndicator(IndicatorManager.StandardIndicators.Question); yield return(Status.Fail); break; } if (Target == null && Type != PlanType.Edge) { Creature.DrawIndicator(IndicatorManager.StandardIndicators.Question); yield return(Status.Fail); break; } if (voxUnder != null) { Path = null; AstarPlanRequest aspr = new AstarPlanRequest { Subscriber = PlanSubscriber, Start = voxUnder, MaxExpansions = MaxExpansions, Sender = Agent, HeuristicWeight = Weights[Timeouts] }; switch (Type) { case PlanType.Radius: aspr.GoalRegion = new SphereGoalRegion(Target, Radius); break; case PlanType.Into: aspr.GoalRegion = new VoxelGoalRegion(Target); break; case PlanType.Adjacent: aspr.GoalRegion = new AdjacentVoxelGoalRegion2D(Target); break; case PlanType.Edge: aspr.GoalRegion = new EdgeGoalRegion(); break; } PlanSubscriber.SendRequest(aspr); PlannerTimer.Reset(PlannerTimer.TargetTimeSeconds); WaitingOnResponse = true; yield return(Status.Running); } else { Path = null; Creature.DrawIndicator(IndicatorManager.StandardIndicators.Question); yield return(Status.Fail); break; } Timeouts++; } else { if (Target != null && Creature.AI.DrawAIPlan) { Drawer3D.DrawLine(Creature.AI.Position, Target.Position, Color.Blue, 0.25f); } Status statusResult = Status.Running; while (PlanSubscriber.Responses.Count > 0) { AStarPlanResponse response; PlanSubscriber.Responses.TryDequeue(out response); if (response.Success) { Path = response.Path; if (Type == PlanType.Adjacent && Path.Count > 0) { Path.RemoveAt(Path.Count - 1); } WaitingOnResponse = false; statusResult = Status.Success; } else { Creature.DrawIndicator(IndicatorManager.StandardIndicators.Question); statusResult = Status.Fail; } } yield return(statusResult); } } }
/// <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.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); } } agent.AI.AddXP(Math.Max((int)(VoxelLibrary.GetVoxelType(blackBoardVoxel.TypeName).StartingHealth / 4), 1)); agent.Stats.NumBlocksDestroyed++; } // 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); } }