public void Update(Creature creature, DwarfTime gameTime, ChunkManager chunks, Camera camera) { float dt = (float)gameTime.ElapsedGameTime.TotalSeconds; Hunger.CurrentValue -= dt * creature.Stats.HungerGrowth; Health.CurrentValue = (creature.Hp - creature.MinHealth) / (creature.MaxHealth - creature.MinHealth); if (creature.Stats.CanSleep) { Energy.CurrentValue = (float)(100 * Math.Sin(PlayState.Time.GetTotalHours() * Math.PI / 24.0f)); } else { Energy.CurrentValue = 100.0f; } if (Energy.IsUnhappy()) { creature.DrawIndicator(IndicatorManager.StandardIndicators.Sleepy); } if (creature.Stats.CanEat && Hunger.IsUnhappy()) { creature.DrawIndicator(IndicatorManager.StandardIndicators.Hungry); if (Hunger.CurrentValue <= 1e-12 && (DateTime.Now - LastHungerDamageTime).TotalSeconds > HungerDamageRate) { creature.Damage(1.0f / (creature.Stats.HungerResistance) * HungerDamageRate); LastHungerDamageTime = DateTime.Now; } } }
public bool InitializePath() { // ERROR CHECKS / INITIALIZING Creature.CurrentCharacterMode = Creature.CharacterMode.Walking; Creature.OverrideCharacterMode = false; Agent.Physics.Orientation = Physics.OrientMode.RotateY; ActionTimes = new List <float>(); Path = GetPath(); if (Path == null) { SetPath(null); Creature.DrawIndicator(IndicatorManager.StandardIndicators.Question); return(false); } if (Path.Count > 0) { RandomPositionOffsets = new List <Vector3>(); int i = 0; float dt = 0; float time = 0; foreach (Creature.MoveAction action in Path) { RandomPositionOffsets.Add(MathFunctions.RandVector3Box(-0.1f, 0.1f, 0.0f, 0.0f, -0.1f, 0.1f)); dt = GetActionTime(action, i); ActionTimes.Add(dt); time += dt; i++; } RandomPositionOffsets[0] = Agent.Position - (Path[0].Voxel.Position + Vector3.One * 0.5f); TrajectoryTimer = new Timer(time, true); return(true); } return(true); }
public override IEnumerable <Status> Run() { if (Zone == null) { Creature.DrawIndicator(IndicatorManager.StandardIndicators.Question); yield return(Status.Fail); yield break; } if (Resource.Count <= 0) { yield return(Status.Success); yield break; } List <GameComponent> createdItems = Creature.Inventory.RemoveAndCreate(Resource, Inventory.RestockType.RestockResource); if (createdItems.Count == 0) { yield return(Status.Success); } foreach (GameComponent b in createdItems) { if (Zone.AddItem(b)) { Creature.Stats.NumItemsGathered++; } else { Creature.Inventory.AddResource(new ResourceAmount(Resource.Type, 1), Inventory.RestockType.RestockResource); b.Delete(); } } Creature.NoiseMaker.MakeNoise("Stockpile", Creature.AI.Position); Creature.CurrentCharacterMode = Creature.Stats.CurrentClass.AttackMode; Creature.Sprite.ResetAnimations(Creature.Stats.CurrentClass.AttackMode); Creature.Sprite.PlayAnimations(Creature.Stats.CurrentClass.AttackMode); while (!Creature.Sprite.AnimPlayer.IsDone()) { yield return(Status.Running); } var resource = Library.GetResourceType(Resource.Type); if (resource.Tags.Contains(DwarfCorp.Resource.ResourceTags.Corpse)) { Creature.AddThought("I laid a friend to rest.", new TimeSpan(0, 8, 0, 0), 10.0f); } yield return(Status.Running); Creature.CurrentCharacterMode = CharacterMode.Idle; yield return(Status.Success); }
public void Converse(CreatureAI other) { if (SpeakTimer.HasTriggered) { AddThought(Thought.ThoughtType.Talked); Creature.DrawIndicator(IndicatorManager.StandardIndicators.Dots); Creature.Physics.Face(other.Position); SpeakTimer.Reset(SpeakTimer.TargetTimeSeconds); } }
public override IEnumerable <Status> Run() { var zone = Agent.Blackboard.GetData <Zone>(StockpileName); var resource = Agent.Blackboard.GetData <Resource>(ResourceName); if (zone == null || !(zone is Stockpile) || resource == null) { Creature.DrawIndicator(IndicatorManager.StandardIndicators.Question); yield return(Status.Fail); yield break; } var createdItems = Creature.Inventory.RemoveAndCreate(resource, Inventory.RestockType.RestockResource); if ((zone as Stockpile).AddResource(resource)) { var toss = new TossMotion(1.0f, 2.5f, createdItems.LocalTransform, zone.GetBoundingBox().Center() + new Vector3(0.5f, 0.5f, 0.5f)); if (createdItems.GetRoot().GetComponent <Physics>().HasValue(out var physics)) { physics.CollideMode = Physics.CollisionMode.None; } createdItems.AnimationQueue.Add(toss); toss.OnComplete += createdItems.Die; Creature.Stats.NumItemsGathered++; } else { Creature.Inventory.AddResource(resource, Inventory.RestockType.RestockResource); createdItems.Delete(); } Creature.NoiseMaker.MakeNoise("Stockpile", Creature.AI.Position); Creature.CurrentCharacterMode = Creature.Stats.CurrentClass.AttackMode; Creature.Sprite.ResetAnimations(Creature.Stats.CurrentClass.AttackMode); Creature.Sprite.PlayAnimations(Creature.Stats.CurrentClass.AttackMode); while (!Creature.Sprite.AnimPlayer.IsDone()) { yield return(Status.Running); } if (Library.GetResourceType(resource.TypeName).HasValue(out var res) && res.Tags.Contains("Corpse")) { Creature.AddThought("I laid a friend to rest.", new TimeSpan(0, 8, 0, 0), 10.0f); } yield return(Status.Running); Creature.CurrentCharacterMode = CharacterMode.Idle; yield return(Status.Success); }
public override IEnumerable <Status> Run() { if (Zone == null) { Creature.DrawIndicator(IndicatorManager.StandardIndicators.Question); yield return(Status.Fail); yield break; } if (Resource.NumResources <= 0) { yield return(Status.Success); yield break; } List <Body> createdItems = Creature.Inventory.RemoveAndCreate(Resource, Inventory.RestockType.RestockResource); if (createdItems.Count == 0) { yield return(Status.Success); } foreach (Body b in createdItems) { if (Zone.AddItem(b)) { Creature.Stats.NumItemsGathered++; } } Creature.NoiseMaker.MakeNoise("Stockpile", Creature.AI.Position); Creature.CurrentCharacterMode = Creature.AttackMode; Creature.Sprite.ResetAnimations(Creature.AttackMode); Creature.Sprite.PlayAnimations(Creature.AttackMode); while (!Creature.Sprite.AnimPlayer.IsDone()) { yield return(Status.Running); } var resource = ResourceLibrary.GetResourceByName(Resource.ResourceType); if (resource.Tags.Contains(DwarfCorp.Resource.ResourceTags.Corpse)) { Creature.AddThought(Thought.ThoughtType.BuriedDead); } yield return(Status.Running); Creature.CurrentCharacterMode = CharacterMode.Idle; yield return(Status.Success); }
public override IEnumerable <Status> Run() { if (Zone == null) { Creature.DrawIndicator(IndicatorManager.StandardIndicators.Question); yield return(Status.Fail); yield break; } if (Resource.NumResources <= 0) { yield return(Status.Success); yield break; } List <Body> createdItems = Creature.Inventory.RemoveAndCreate(Resource); if (createdItems.Count == 0) { Creature.DrawIndicator(IndicatorManager.StandardIndicators.Question); yield return(Status.Fail); } foreach (Body b in createdItems) { if (Zone.AddItem(b)) { Creature.NoiseMaker.MakeNoise("Hurt", Creature.AI.Position); Creature.Stats.NumItemsGathered++; Creature.AI.AddXP(1); Creature.CurrentCharacterMode = Creature.CharacterMode.Attacking; Creature.Sprite.ResetAnimations(Creature.CharacterMode.Attacking); Creature.Sprite.PlayAnimations(Creature.CharacterMode.Attacking); while (!Creature.Sprite.CurrentAnimation.IsDone()) { yield return(Status.Running); } yield return(Status.Running); } else { Creature.DrawIndicator(IndicatorManager.StandardIndicators.Question); Creature.CurrentCharacterMode = Creature.CharacterMode.Idle; yield return(Status.Fail); } } Creature.CurrentCharacterMode = Creature.CharacterMode.Idle; yield return(Status.Success); }
public static IEnumerable <Act.Status> EatStockedFood(this Creature agent) { List <ResourceAmount> foods = agent.Faction.ListResourcesWithTag(Resource.ResourceTags.Edible); if (foods.Count == 0) { if (agent.Allies == "Dwarf") { agent.Manager.World.MakeAnnouncement("We're out of food!", "Our stockpiles don't have any food. Our employees will starve!"); } yield return(Act.Status.Fail); yield break; } else { foreach (ResourceAmount resourceAmount in foods) { if (resourceAmount.NumResources > 0) { Resource resource = ResourceLibrary.GetResourceByName(resourceAmount.ResourceType); bool removed = agent.Faction.RemoveResources(new List <ResourceAmount>() { new ResourceAmount(resourceAmount.ResourceType, 1) }, agent.AI.Position); agent.Status.Hunger.CurrentValue += resource.FoodContent; agent.NoiseMaker.MakeNoise("Chew", agent.AI.Position); if (!removed) { yield return(Act.Status.Fail); } else { agent.DrawIndicator(resource.Image, resource.Tint); agent.AI.AddThought(Thought.ThoughtType.AteFood); yield return(Act.Status.Success); } yield break; } } if (agent.Allies == "Dwarf") { agent.Manager.World.MakeAnnouncement("We're out of food!", "Our stockpiles don't have any food. Our employees will starve!"); } yield return(Act.Status.Fail); yield break; } }
public override IEnumerable <Status> Run() { if (Zone == null) { Creature.DrawIndicator(IndicatorManager.StandardIndicators.Question); yield return(Status.Fail); yield break; } if (Money <= 0) { yield return(Status.Success); yield break; } DwarfBux moneyPut = 0m; if (Zone.AddMoney(Creature.AI.Position, Money, ref moneyPut)) { Creature.AI.AddMoney(-Money); Creature.NoiseMaker.MakeNoise("Stockpile", Creature.AI.Position); Creature.Stats.NumItemsGathered++; Creature.AI.AddXP(1); Creature.CurrentCharacterMode = CharacterMode.Attacking; Creature.Sprite.ResetAnimations(CharacterMode.Attacking); Creature.Sprite.PlayAnimations(CharacterMode.Attacking); while (!Creature.Sprite.AnimPlayer.IsDone()) { yield return(Status.Running); } yield return(Status.Running); } else { Creature.DrawIndicator(IndicatorManager.StandardIndicators.Question); Creature.CurrentCharacterMode = CharacterMode.Idle; Creature.AI.GatherManager.StockMoneyOrders.Add(new GatherManager.StockMoneyOrder() { Destination = null, Money = Money - moneyPut }); yield return(Status.Fail); } Creature.CurrentCharacterMode = CharacterMode.Idle; yield return(Status.Success); }
public override IEnumerable <Status> Run() { bool validTargetFound = false; List <Zone> sortedPiles; if (ResourceLibrary.GetResourceByName(this.Item.ResourceType).Tags.Contains(Resource.ResourceTags.Money)) { sortedPiles = new List <Zone>(Creature.Faction.Treasurys); sortedPiles.Sort(CompareTreasurys); } else { sortedPiles = new List <Zone>(Creature.Faction.Stockpiles.Where(pile => pile.IsAllowed(Item.ResourceType))); sortedPiles.Sort(CompareStockpiles); } foreach (Zone s in sortedPiles) { if (s.IsFull()) { continue; } var v = s.GetNearestVoxel(Creature.Physics.GlobalTransform.Translation); if (!v.IsValid || v.IsEmpty) { continue; } Voxel = v; Stockpile = s; validTargetFound = true; break; } if (validTargetFound) { yield return(Status.Success); } else { Creature.DrawIndicator(IndicatorManager.StandardIndicators.Question); yield return(Status.Fail); } }
public override IEnumerable <Status> Run() { InitializePath(); if (TrajectoryTimer == null) { yield break; } while (!TrajectoryTimer.HasTriggered) { TrajectoryTimer.Update(DwarfTime.LastTime); ValidPathTimer.Update(DwarfTime.LastTime); foreach (Status status in PerformCurrentAction()) { if (status == Status.Fail) { yield return(Status.Fail); } else if (status == Status.Success) { break; } yield return(Status.Running); } if (Agent.DrawPath) { List <Vector3> points = Path.Select( (v, i) => v.Voxel.Position + new Vector3(0.5f, 0.5f, 0.5f) + RandomPositionOffsets[i]) .ToList(); Drawer3D.DrawLineList(points, Color.Red, 0.1f); } // Check if the path has been made invalid if (ValidPathTimer.HasTriggered && !IsPathValid(Path)) { Creature.OverrideCharacterMode = false; Creature.DrawIndicator(IndicatorManager.StandardIndicators.Question); yield return(Status.Fail); } yield return(Status.Running); } Creature.OverrideCharacterMode = false; SetPath(null); yield return(Status.Success); }
public override IEnumerable <Status> Run() { // Todo: Re-add random offsets? Creature.CurrentCharacterMode = CharacterMode.Walking; Creature.OverrideCharacterMode = false; Agent.Physics.Orientation = Physics.OrientMode.RotateY; if (Path == null || Path.Count == 0) { Path = null; Creature.DrawIndicator(IndicatorManager.StandardIndicators.Question); yield return(Act.Status.Success); } foreach (var step in Path) { if (Agent.MinecartActive && (step.MoveType != MoveType.RideVehicle && step.MoveType != MoveType.EnterVehicle && step.MoveType != MoveType.ExitVehicle)) { var x = 5; } foreach (var status in PerformStep(step)) { //Agent.Physics.PropogateTransforms(); DeltaTime += (float)DwarfTime.LastTime.ElapsedGameTime.TotalSeconds; Creature.Physics.CollisionType = CollisionType.Dynamic; if (status == Status.Fail) { CleanupMinecart(); yield return(Status.Fail); } else { DrawDebugPath(); yield return(Status.Running); } } } Creature.OverrideCharacterMode = false; Path = null; Agent.GetRoot().SetFlagRecursive(GameComponent.Flag.Visible, true); CleanupMinecart(); yield return(Status.Success); }
public override IEnumerable <Status> Run() { if (Zone == null) { Creature.DrawIndicator(IndicatorManager.StandardIndicators.Question); yield return(Status.Fail); yield break; } if (Resource.NumResources <= 0) { yield return(Status.Success); yield break; } List <Body> createdItems = Creature.Inventory.RemoveAndCreate(Resource); if (createdItems.Count == 0) { Creature.DrawIndicator(IndicatorManager.StandardIndicators.Question); yield return(Status.Fail); } foreach (Body b in createdItems) { if (Zone.AddItem(b)) { Creature.NoiseMaker.MakeNoise("Hurt", Creature.AI.Position); Creature.Stats.NumItemsGathered++; Creature.AI.AddXP(1); yield return(Status.Running); } else { Creature.DrawIndicator(IndicatorManager.StandardIndicators.Question); yield return(Status.Fail); } } yield return(Status.Success); }
public override IEnumerable <Status> Run() { bool validTargetFound = false; List <Stockpile> sortedPiles = new List <Stockpile>(Creature.Faction.Stockpiles); sortedPiles.Sort(CompareStockpiles); foreach (Stockpile s in sortedPiles) { if (s.IsFull()) { continue; } Voxel v = s.GetNearestVoxel(Creature.Physics.GlobalTransform.Translation); if (v.IsEmpty) { continue; } Voxel = v; Stockpile = s; if (Voxel == null) { continue; } validTargetFound = true; break; } if (validTargetFound) { yield return(Status.Success); } else { Creature.DrawIndicator(IndicatorManager.StandardIndicators.Question); yield return(Status.Fail); } }
public override IEnumerable <Status> Run() { if (TargetZone == null) { yield return(Status.Fail); } else { Voxel v = TargetZone.GetNearestVoxel(Agent.Position); if (!v.IsEmpty) { Agent.Blackboard.SetData(OutputVoxel, v); yield return(Status.Success); } else { Creature.DrawIndicator(IndicatorManager.StandardIndicators.Question); yield return(Status.Fail); } } }
public override IEnumerable <Status> Run() { bool validTargetFound = false; var sortedPiles = Creature.World.EnumerateZones().OfType <Stockpile>().Where(pile => pile.IsAllowed(Item.TypeName)).ToList(); sortedPiles.Sort(CompareStockpiles); foreach (var s in sortedPiles) { if (s.IsFull()) { continue; } var v = s.GetNearestVoxel(Creature.Physics.GlobalTransform.Translation); if (!v.IsValid || v.IsEmpty) { continue; } Agent.Blackboard.SetData <VoxelHandle>(VoxelBlackboardName, v); Agent.Blackboard.SetData <Zone>(StockpileBlackboardName, s); validTargetFound = true; break; } if (validTargetFound) { yield return(Status.Success); } else { Creature.DrawIndicator(IndicatorManager.StandardIndicators.Question); yield return(Status.Fail); } }
public override IEnumerable <Status> Run() { Body grabbed = Creature.Hands.GetFirstGrab(); if (grabbed == null) { Creature.DrawIndicator(IndicatorManager.StandardIndicators.Question); yield return(Status.Fail); } else { Creature.Hands.UnGrab(grabbed); Matrix m = Matrix.Identity; m.Translation = Creature.Physics.GlobalTransform.Translation; Agent.Blackboard.SetData <object>("HeldObject", null); grabbed.LocalTransform = m; grabbed.HasMoved = true; grabbed.IsActive = true; yield return(Status.Success); } }
public override IEnumerable<Status> Run() { bool validTargetFound = false; List<Zone> sortedPiles; sortedPiles = new List<Zone>(Creature.World.EnumerateZones().Where(pile => pile is Stockpile && (pile as Stockpile).IsAllowed(Item.Type))); sortedPiles.Sort(CompareStockpiles); foreach (Zone s in sortedPiles) { if(s.IsFull()) { continue; } var v = s.GetNearestVoxel(Creature.Physics.GlobalTransform.Translation); if(!v.IsValid || v.IsEmpty) continue; Voxel = v; Stockpile = s; validTargetFound = true; break; } if(validTargetFound) { yield return Status.Success; } else { Creature.DrawIndicator(IndicatorManager.StandardIndicators.Question); yield return Status.Fail; } }
public static IEnumerable <Act.Status> Dig(this Creature agent, string voxel, float energyLoss) { Vector3 LocalTarget = agent.AI.Position; agent.Sprite.ResetAnimations(Creature.CharacterMode.Attacking); while (true) { agent.CurrentCharacterMode = Creature.CharacterMode.Attacking; Voxel blackBoardVoxel = agent.AI.Blackboard.GetData <Voxel>(voxel); if (blackBoardVoxel == null) { agent.DrawIndicator(IndicatorManager.StandardIndicators.Question); yield return(Act.Status.Fail); break; } Voxel vox = blackBoardVoxel; if (vox.Health <= 0.0f || !agent.Faction.IsDigDesignation(vox)) { agent.AI.AddXP(Math.Max((int)(VoxelLibrary.GetVoxelType(blackBoardVoxel.TypeName).StartingHealth / 4), 1)); if (vox.Health <= 0.0f) { vox.Kill(); } agent.Stats.NumBlocksDestroyed++; agent.CurrentCharacterMode = Creature.CharacterMode.Idle; yield return(Act.Status.Success); break; } agent.Physics.Face(vox.Position + Vector3.One * 0.5f); agent.Physics.Velocity *= 0.9f; agent.Attacks[0].Perform(agent.Physics.Position, vox, DwarfTime.LastTime, agent.Stats.BaseDigSpeed, agent.Faction.Name); yield return(Act.Status.Running); } }
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); } } }
public override IEnumerable <Status> Run() { if (Target == null) { yield return(Status.Fail); } switch (PickType) { case (PickUpType.Room): case (PickUpType.Stockpile): { if (Zone == null) { yield return(Status.Fail); break; } bool removed = Zone.Resources.RemoveResource(new ResourceAmount(Target.Tags[0])); if (removed) { if (Creature.Inventory.Pickup(Target)) { Agent.Blackboard.SetData(StashedItemOut, new ResourceAmount(Target)); SoundManager.PlaySound(ContentPaths.Audio.dig, Agent.Position); yield return(Status.Success); } else { yield return(Status.Fail); } } else { yield return(Status.Fail); } break; } case (PickUpType.None): { if (!Creature.Inventory.Pickup(Target)) { yield return(Status.Fail); } if (Creature.Faction.GatherDesignations.Contains(Target)) { Creature.Faction.GatherDesignations.Remove(Target); } ResourceAmount resource = new ResourceAmount(Target); Agent.Blackboard.SetData(StashedItemOut, resource); Creature.DrawIndicator(resource.ResourceType.Image); SoundManager.PlaySound(ContentPaths.Audio.dig, Agent.Position); yield return(Status.Success); break; } } }
public override IEnumerable <Status> Run() { InitializePath(); if (Path == null || Path.Count == 0) { yield return(Act.Status.Success); } if (TrajectoryTimer == null) { yield break; } while (!TrajectoryTimer.HasTriggered) { TrajectoryTimer.Update(DwarfTime.LastTime); ValidPathTimer.Update(DwarfTime.LastTime); foreach (Status status in PerformCurrentAction()) { if (status == Status.Fail) { yield return(Status.Fail); } else if (status == Status.Success) { break; } yield return(Status.Running); } if (Agent.DrawPath) { List <Vector3> points = Path.Select( (v, i) => v.SourceVoxel.WorldPosition + new Vector3(0.5f, 0.5f, 0.5f) + RandomPositionOffsets[i]) .ToList(); points.Add(Path[Path.Count - 1].DestinationVoxel.WorldPosition + new Vector3(0.5f, 0.5f, 0.5f)); List <Color> colors = Path.Select((v, i) => { switch (v.MoveType) { case MoveType.Climb: return(Color.Cyan); case MoveType.ClimbWalls: return(Color.DarkCyan); case MoveType.DestroyObject: return(Color.Orange); case MoveType.Fall: return(Color.LightBlue); case MoveType.Fly: return(Color.Green); case MoveType.Jump: return(Color.Yellow); case MoveType.Swim: return(Color.Blue); case MoveType.Walk: return(Color.Red); } return(Color.White); }) .ToList(); colors.Add(Color.White); Drawer3D.DrawLineList(points, colors, 0.1f); } // Check if the path has been made invalid if (ValidPathTimer.HasTriggered && !IsPathValid(Path)) { Creature.OverrideCharacterMode = false; Creature.DrawIndicator(IndicatorManager.StandardIndicators.Question); yield return(Status.Fail); } yield return(Status.Running); } Creature.OverrideCharacterMode = false; SetPath(null); yield return(Status.Success); }
public override IEnumerable <Status> Run() { InitializePath(); if (Path == null || Path.Count == 0) { yield return(Act.Status.Success); } if (TrajectoryTimer == null) { yield break; } while (!TrajectoryTimer.HasTriggered) { Agent.GetRoot().SetFlagRecursive(GameComponent.Flag.Visible, true); TrajectoryTimer.Update(DwarfTime.LastTime); ValidPathTimer.Update(DwarfTime.LastTime); foreach (Status status in PerformCurrentAction()) { if (status == Status.Fail) { CleanupMinecart(); yield return(Status.Fail); } else if (status == Status.Success) { break; } Creature.Physics.AnimationQueue.Clear(); yield return(Status.Running); } if (Debugger.Switches.DrawPaths) { List <Vector3> points = Path.Select( (v, i) => v.SourceVoxel.WorldPosition + new Vector3(0.5f, 0.5f, 0.5f) + RandomPositionOffsets[i]) .ToList(); points.Add(Path[Path.Count - 1].DestinationVoxel.WorldPosition + new Vector3(0.5f, 0.5f, 0.5f)); List <Color> colors = Path.Select((v, i) => { switch (v.MoveType) { case MoveType.Climb: return(Color.Cyan); case MoveType.ClimbWalls: return(Color.DarkCyan); case MoveType.DestroyObject: return(Color.Orange); case MoveType.Fall: return(Color.LightBlue); case MoveType.Fly: return(Color.Green); case MoveType.Jump: return(Color.Yellow); case MoveType.Swim: return(Color.Blue); case MoveType.Walk: return(Color.Red); } return(Color.White); }) .ToList(); colors.Add(Color.White); Drawer3D.DrawLineList(points, colors, 0.1f); } float t = 0; int currentIndex = 0; MoveAction action = new MoveAction(); if (GetCurrentAction(ref action, ref t, ref currentIndex)) { // Check if the path has been made invalid if (ValidPathTimer.HasTriggered && !IsPathValid(Path, currentIndex)) { Creature.OverrideCharacterMode = false; Creature.DrawIndicator(IndicatorManager.StandardIndicators.Question); CleanupMinecart(); Agent.GetRoot().SetFlagRecursive(GameComponent.Flag.Visible, true); yield return(Status.Fail); } } Creature.Physics.AnimationQueue.Clear(); yield return(Status.Running); } Creature.OverrideCharacterMode = false; SetPath(null); Agent.GetRoot().SetFlagRecursive(GameComponent.Flag.Visible, true); CleanupMinecart(); yield return(Status.Success); }
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) { if (Creature.Faction == PlayState.Master.Faction) { PlayState.AnnouncementManager.Announce(Creature.Stats.FullName + " (" + Creature.Stats.CurrentLevel.Name + ")" + " got lost.", Creature.Stats.FullName + "'s target was lost.", () => Agent.ZoomToMe()); } 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 }; if (Type == PlanType.Radius) { aspr.GoalRegion = new SphereGoalRegion(Target, Radius); } else if (Type == PlanType.Into) { aspr.GoalRegion = new VoxelGoalRegion(Target); } else if (Type == PlanType.Adjacent) { aspr.GoalRegion = new AdjacentVoxelGoalRegion2D(Target); } PlanSubscriber.SendRequest(aspr); PlannerTimer.Reset(PlannerTimer.TargetTimeSeconds); WaitingOnResponse = true; yield return(Status.Running); } else { Path = null; if (Creature.Faction == PlayState.Master.Faction) { PlayState.AnnouncementManager.Announce(Creature.Stats.FullName + " got lost.", Creature.Stats.FullName + " couldn't find a path. The target was invalid.", () => Agent.ZoomToMe()); } Creature.DrawIndicator(IndicatorManager.StandardIndicators.Question); yield return(Status.Fail); break; } Timeouts++; } else { 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 { if (Creature.Faction == PlayState.Master.Faction) { PlayState.AnnouncementManager.Announce(Creature.Stats.FullName + " got lost.", Creature.Stats.FullName + " couldn't find a path in time.", Agent.ZoomToMe); } 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); } }
public override void Update(DwarfTime gameTime, ChunkManager chunks, Camera camera) { IdleTimer.Update(gameTime); SpeakTimer.Update(gameTime); OrderEnemyAttack(); DeleteBadTasks(); PreEmptTasks(); if (Status.Energy.IsUnhappy() && PlayState.Time.IsNight()) { Task toReturn = new SatisfyTirednessTask(); toReturn.SetupScript(Creature); if (!Tasks.Contains(toReturn)) { Tasks.Add(toReturn); } } if (Status.Hunger.IsUnhappy() && Faction.CountResourcesWithTag(Resource.ResourceTags.Food) > 0) { Task toReturn = new SatisfyHungerTask(); toReturn.SetupScript(Creature); if (!Tasks.Contains(toReturn)) { Tasks.Add(toReturn); } } if (CurrentTask != null && CurrentAct != null) { Act.Status status = CurrentAct.Tick(); bool retried = false; if (status == Act.Status.Fail) { if (CurrentTask.ShouldRetry(Creature)) { if (!Tasks.Contains(CurrentTask)) { CurrentTask.Priority = Task.PriorityType.Eventually; Tasks.Add(CurrentTask); CurrentTask.SetupScript(Creature); retried = true; } } } if (status != Act.Status.Running && !retried) { CurrentTask = null; } } else { bool tantrum = false; if (Status.Happiness.IsUnhappy()) { tantrum = MathFunctions.Rand(0, 1) < 0.25f; } Task goal = GetEasiestTask(Tasks); if (goal != null) { if (tantrum) { Creature.DrawIndicator(IndicatorManager.StandardIndicators.Sad); if (Creature.Allies == "Dwarf") { PlayState.AnnouncementManager.Announce(Stats.FullName + " (" + Stats.CurrentLevel.Name + ")" + " refuses to work!", "Our employee is unhappy, and would rather not work!", ZoomToMe); } CurrentTask = null; } else { IdleTimer.Reset(IdleTimer.TargetTimeSeconds); goal.SetupScript(Creature); CurrentTask = goal; Tasks.Remove(goal); } } else { CurrentTask = ActOnIdle(); } } PlannerTimer.Update(gameTime); UpdateThoughts(); UpdateXP(); base.Update(gameTime, chunks, camera); }
public override IEnumerable <Status> Run() { Creature.Sprite.ResetAnimations(Creature.AttackMode); // Block since we're in a coroutine. while (true) { var vox = OwnerTask.Voxel; // Somehow, there wasn't a voxel to mine. if (!vox.IsValid) { Creature.DrawIndicator(IndicatorManager.StandardIndicators.Question); Agent.SetMessage("Failed to dig. Invalid voxel."); yield return(Act.Status.Fail); break; } // If the voxel has already been destroyed, just ignore it and return. if (OwnerTask.VoxelHealth <= 0 || (CheckOwnership && !Creature.Faction.Designations.IsVoxelDesignation(vox, DesignationType.Dig))) { Creature.CurrentCharacterMode = CharacterMode.Idle; yield return(Act.Status.Success); break; } // Look at the block and slow your velocity down. Creature.Physics.Face(vox.WorldPosition + Vector3.One * 0.5f); Creature.Physics.Velocity *= 0.01f; // Play the attack animations. Creature.CurrentCharacterMode = Creature.AttackMode; Creature.OverrideCharacterMode = true; Creature.Sprite.ResetAnimations(Creature.CurrentCharacterMode); Creature.Sprite.PlayAnimations(Creature.CurrentCharacterMode); // Wait until an attack was successful... foreach (var status in Creature.Attacks[0].PerformOnVoxel(Creature, Creature.Physics.Position, OwnerTask, DwarfTime.LastTime, Creature.Stats.BaseDigSpeed, Creature.Faction.Name)) { if (status == Act.Status.Running) { Creature.Physics.Face(vox.WorldPosition + Vector3.One * 0.5f); Creature.Physics.Velocity *= 0.01f; // Debug drawing. //if (agent.AI.DrawPath) // Drawer3D.DrawLine(vox.WorldPosition, agent.AI.Position, Color.Green, 0.25f); yield return(Act.Status.Running); } } Creature.OverrideCharacterMode = false; // If the voxel has been destroyed by you, gather it. if (OwnerTask.VoxelHealth <= 0.0f) { var voxelType = VoxelLibrary.GetVoxelType(vox.Type.Name); if (MathFunctions.RandEvent(0.5f)) { Creature.AI.AddXP(Math.Max((int)(voxelType.StartingHealth / 4), 1)); } Creature.Stats.NumBlocksDestroyed++; Creature.World.GoalManager.OnGameEvent(new Goals.Triggers.DigBlock(voxelType, Creature)); var items = Creature.World.ChunkManager.KillVoxel(vox); if (items != null) { foreach (Body item in items) { Creature.Gather(item); } } yield return(Act.Status.Success); } // Wait until the animation is done playing before continuing. while (!Creature.Sprite.AnimPlayer.IsDone() && Creature.Sprite.AnimPlayer.IsPlaying) { Creature.Physics.Face(vox.WorldPosition + Vector3.One * 0.5f); Creature.Physics.Velocity *= 0.01f; yield return(Act.Status.Running); } // Pause the animation and wait for a recharge timer. Creature.Sprite.PauseAnimations(Creature.CurrentCharacterMode); // Wait for a recharge timer to trigger. Creature.Attacks[0].RechargeTimer.Reset(); while (!Creature.Attacks[0].RechargeTimer.HasTriggered) { Creature.Attacks[0].RechargeTimer.Update(DwarfTime.LastTime); Creature.Physics.Face(vox.WorldPosition + Vector3.One * 0.5f); Creature.Physics.Velocity *= 0.01f; yield return(Act.Status.Running); } Creature.CurrentCharacterMode = CharacterMode.Idle; yield return(Act.Status.Running); } }
public override IEnumerable <Status> Run() { Path = null; Timeouts = 0; PlannerTimer.Reset(PlannerTimer.TargetTimeSeconds); while (true) { if (Path != null) { yield return(Status.Success); break; } if (Timeouts > MaxTimeouts) { yield return(Status.Fail); break; } 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); yield return(Status.Fail); break; } var voxUnder = new VoxelHandle(chunks.ChunkData, GlobalVoxelCoordinate.FromVector3(Agent.Position)); if (!voxUnder.IsValid) { Creature.DrawIndicator(IndicatorManager.StandardIndicators.Question); yield return(Status.Fail); break; } Path = null; AstarPlanRequest aspr = new AstarPlanRequest { Subscriber = Agent.PlanSubscriber, Start = voxUnder, MaxExpansions = MaxExpansions, Sender = Agent, HeuristicWeight = Weights[Timeouts] }; aspr.GoalRegion = GetGoal(); if (!Agent.PlanSubscriber.SendRequest(aspr)) { 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) { Path = response.Path; WaitingOnResponse = false; statusResult = Status.Success; } else if (response.Result == AStarPlanner.PlanResultCode.Invalid || response.Result == AStarPlanner.PlanResultCode.NoSolution || response.Result == AStarPlanner.PlanResultCode.Cancelled || response.Result == AStarPlanner.PlanResultCode.Invalid) { Creature.DrawIndicator(IndicatorManager.StandardIndicators.Question); statusResult = Status.Fail; yield return(Status.Fail); } else if (Timeouts <= MaxTimeouts) { Timeouts++; yield return(Status.Running); } else { Creature.DrawIndicator(IndicatorManager.StandardIndicators.Question); statusResult = Status.Fail; } } yield return(statusResult); } } }
public void Update(Creature creature, DwarfTime gameTime, ChunkManager chunks, Camera camera) { float dt = (float)gameTime.ElapsedGameTime.TotalSeconds; Hunger.CurrentValue -= dt * creature.Stats.HungerGrowth; Health.CurrentValue = (creature.Hp - creature.MinHealth) / (creature.MaxHealth - creature.MinHealth); if(creature.Stats.CanSleep) Energy.CurrentValue = (float) (100*Math.Sin(PlayState.Time.GetTotalHours()*Math.PI / 24.0f)); else { Energy.CurrentValue = 100.0f; } if(Energy.IsUnhappy()) { creature.DrawIndicator(IndicatorManager.StandardIndicators.Sleepy); } if(creature.Stats.CanEat && Hunger.IsUnhappy()) { creature.DrawIndicator(IndicatorManager.StandardIndicators.Hungry); if(Hunger.CurrentValue <= 1e-12 && (DateTime.Now - LastHungerDamageTime).TotalSeconds > HungerDamageRate) { creature.Damage(1.0f / (creature.Stats.HungerResistance) * HungerDamageRate); LastHungerDamageTime = DateTime.Now; } } }
public override IEnumerable <Status> Run() { Creature.Sprite.ResetAnimations(Creature.Stats.CurrentClass.AttackMode); // Block since we're in a coroutine. while (true) { var vox = OwnerTask.Voxel; // Somehow, there wasn't a voxel to mine. if (!vox.IsValid) { Creature.DrawIndicator(IndicatorManager.StandardIndicators.Question); Agent.SetTaskFailureReason("Failed to dig. Invalid voxel."); yield return(Act.Status.Fail); break; } // If the voxel has already been destroyed, just ignore it and return. if (OwnerTask.VoxelHealth <= 0 || (CheckOwnership && !Creature.World.PersistentData.Designations.IsVoxelDesignation(vox, DesignationType.Dig))) { Creature.CurrentCharacterMode = CharacterMode.Idle; yield return(Act.Status.Success); break; } // Look at the block and slow your velocity down. Creature.Physics.Face(vox.WorldPosition + Vector3.One * 0.5f); Creature.Physics.Velocity *= 0.01f; // Play the attack animations. Creature.CurrentCharacterMode = Creature.Stats.CurrentClass.AttackMode; Creature.OverrideCharacterMode = true; Creature.Sprite.ResetAnimations(Creature.CurrentCharacterMode); Creature.Sprite.PlayAnimations(Creature.CurrentCharacterMode); // Wait until an attack was successful... foreach (var status in PerformOnVoxel(Creature, Creature.Physics.Position, OwnerTask, DwarfTime.LastTime, Creature.Stats.BaseDigSpeed, Creature.Faction.ParentFaction.Name)) { if (status == Act.Status.Running) { Creature.Physics.Face(vox.WorldPosition + Vector3.One * 0.5f); Creature.Physics.Velocity *= 0.01f; yield return(Act.Status.Running); } } Creature.OverrideCharacterMode = false; // If the voxel has been destroyed by you, gather it. if (OwnerTask.VoxelHealth <= 0.0f) { if (Library.GetVoxelType(vox.Type.Name).HasValue(out VoxelType voxelType)) { Creature.AI.AddXP(Math.Max((int)(voxelType.StartingHealth / 4), 1)); Creature.Stats.NumBlocksDestroyed++; ActHelper.ApplyWearToTool(Creature.AI, GameSettings.Current.Wear_Dig); var items = VoxelHelpers.KillVoxel(Creature.World, vox); if (items != null) { foreach (GameComponent item in items) { Creature.Gather(item, TaskPriority.Eventually); } } yield return(Act.Status.Success); } } // Wait until the animation is done playing before continuing. while (!Creature.Sprite.AnimPlayer.IsDone() && Creature.Sprite.AnimPlayer.IsPlaying) { Creature.Physics.Face(vox.WorldPosition + Vector3.One * 0.5f); Creature.Physics.Velocity *= 0.01f; yield return(Act.Status.Running); } // Pause the animation and wait for a recharge timer. Creature.Sprite.PauseAnimations(Creature.CurrentCharacterMode); Creature.CurrentCharacterMode = CharacterMode.Idle; yield return(Act.Status.Running); } }