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 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 void Initialize() { var closestItem = Agent.Faction.FindNearestItemWithTags("Bed", Agent.Position, true, Agent); var closestZone = Agent.World.FindNearestZone(Agent.Position); if (!Agent.Stats.Energy.IsSatisfied() && closestItem != null) { closestItem.ReservedFor = Agent; Creature.AI.Blackboard.SetData("Bed", closestItem); var unreserveAct = new Wrap(() => Creature.Unreserve("Bed")); Tree = new Select( new Sequence( new GoToEntityAct(closestItem, Creature.AI), new TeleportAct(Creature.AI) { Location = closestItem.GetRotatedBoundingBox().Center() + new Vector3(-0.0f, 0.75f, -0.0f) }, new SleepAct(Creature.AI) { RechargeRate = 1.0f, Teleport = true, TeleportLocation = closestItem.GetRotatedBoundingBox().Center() + new Vector3(-0.0f, 0.75f, -0.0f) }, unreserveAct), unreserveAct); } else if (!Agent.Stats.Energy.IsSatisfied() && closestItem == null && closestZone != null) { Creature.AddThought("I slept on the ground.", new TimeSpan(0, 8, 0, 0), -6.0f); Tree = new Sequence( new GoToZoneAct(Creature.AI, closestZone), new SleepAct(Creature.AI) { RechargeRate = 1.0f }); } else if (!Agent.Stats.Energy.IsSatisfied() && closestItem == null && closestZone == null) { Creature.AddThought("I slept on the ground.", new TimeSpan(0, 8, 0, 0), -6.0f); Tree = new SleepAct(Creature.AI) { RechargeRate = 1.0f }; } else { Tree = null; } base.Initialize(); }
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 void Initialize() { Body closestItem = Agent.Faction.FindNearestItemWithTags("Bed", Agent.Position, true, Agent); Zone closestZone = Agent.Faction.GetNearestRoom(Agent.Position); if (!Agent.Status.Energy.IsSatisfied() && closestItem != null) { closestItem.ReservedFor = Agent; Creature.AI.Blackboard.SetData("Bed", closestItem); closestItem.ReservedFor = Agent; Act unreserveAct = new Wrap(() => Creature.Unreserve("Bed")); Tree = new Sequence ( new GoToEntityAct(closestItem, Creature.AI), new TeleportAct(Creature.AI) { Location = closestItem.GetRotatedBoundingBox().Center() + new Vector3(-0.0f, 0.75f, -0.0f) }, new SleepAct(Creature.AI) { RechargeRate = 1.0f, Teleport = true, TeleportLocation = closestItem.GetRotatedBoundingBox().Center() + new Vector3(-0.0f, 0.75f, -0.0f) }, unreserveAct ) | unreserveAct; } else if (!Agent.Status.Energy.IsSatisfied() && closestItem == null && closestZone != null) { Creature.AddThought(Thought.ThoughtType.SleptOnGround); Tree = new Sequence(new GoToZoneAct(Creature.AI, closestZone), new SleepAct(Creature.AI) { RechargeRate = 1.0f }); } else if (!Agent.Status.Energy.IsSatisfied() && closestItem == null && closestZone == null) { Creature.AddThought(Thought.ThoughtType.SleptOnGround); Tree = new SleepAct(Creature.AI) { RechargeRate = 1.0f }; } else { Tree = null; } base.Initialize(); }
// If true, this creature can fight the other creature. Otherwise, we want to flee it. public FightOrFlightResponse FightOrFlight(CreatureAI creature) { if (IsDead || creature == null || creature.IsDead) { return(FightOrFlightResponse.Fight); } if (!Stats.Species.FeelsFear) { return(FightOrFlightResponse.Fight); } var fear = 0.0f; // If our health is low, we're a little afraid. if (Creature.Hp < Creature.MaxHealth * 0.25f) { fear += 0.125f; } // If there are a lot of nearby threats vs allies, we are even more afraid. if (Faction.Threats.Where(threat => threat != null && threat.AI != null && !threat.IsDead).Sum(threat => (threat.AI.Position - Position).Length() < 5.0f ? 1 : 0) - Faction.Minions.Where(minion => minion != null && !minion.IsDead).Sum(minion => (minion.Position - Position).Length() < 6.0f ? 1 : 0) > Creature.Stats.Constitution) { fear += 0.125f; } // In this case, we have a very very weak weapon in comparison to our enemy. if (Creature.Attacks[0].Weapon.DamageAmount * 20 < creature.Creature.Hp) { fear += 0.125f; } // If the creature has formidible weapons, we're in trouble. if (creature.Creature.Attacks[0].Weapon.DamageAmount * 4 > Creature.Hp) { fear += 0.125f; } fear = Math.Min(fear, 0.99f); if (MathFunctions.RandEvent(1.0f - fear)) { return(FightOrFlightResponse.Fight); } else { Creature.AddThought("I was frightened recently.", new TimeSpan(0, 4, 0, 0), -2.0f); return(FightOrFlightResponse.Flee); } }
public IEnumerable <Status> FarmATile() { if (Farm == null) { yield return(Status.Fail); yield break; } else if (Farm.Finished) { yield return(Status.Success); } else { Creature.CurrentCharacterMode = Creature.Stats.CurrentClass.AttackMode; Creature.Sprite.ResetAnimations(Creature.Stats.CurrentClass.AttackMode); Creature.Sprite.PlayAnimations(Creature.Stats.CurrentClass.AttackMode); while (Farm.Progress < Farm.TargetProgress && !Farm.Finished) { Creature.Physics.Velocity *= 0.1f; Farm.Progress += 3 * Creature.Stats.BaseFarmSpeed * DwarfTime.Dt; Drawer2D.DrawLoadBar(Agent.Manager.World.Renderer.Camera, Agent.Position + Vector3.Up, Color.LightGreen, Color.Black, 64, 4, Farm.Progress / Farm.TargetProgress); if (Farm.Progress >= (Farm.TargetProgress * 0.5f) && Farm.Voxel.Type.Name != "TilledSoil" && Library.GetVoxelType("TilledSoil").HasValue(out VoxelType tilledSoil)) { Farm.Voxel.Type = tilledSoil; } if (Farm.Progress >= Farm.TargetProgress && !Farm.Finished) { if (Library.GetResourceType(Farm.SeedType).HasValue(out var seedType)) { var plant = EntityFactory.CreateEntity <Plant>(seedType.PlantToGenerate, Farm.Voxel.WorldPosition + new Vector3(0.5f, 1.0f, 0.5f)); plant.Farm = Farm; var original = plant.LocalTransform; original.Translation += Vector3.Down; plant.AnimationQueue.Add(new EaseMotion(0.5f, original, plant.LocalTransform.Translation)); Creature.Manager.World.ParticleManager.Trigger("puff", original.Translation, Color.White, 20); SoundManager.PlaySound(ContentPaths.Audio.Oscar.sfx_env_plant_grow, Farm.Voxel.WorldPosition, true); } Farm.Finished = true; DestroyResources(); } if (MathFunctions.RandEvent(0.01f)) { Creature.Manager.World.ParticleManager.Trigger("dirt_particle", Creature.AI.Position, Color.White, 1); } yield return(Status.Running); Creature.Sprite.ReloopAnimations(Creature.Stats.CurrentClass.AttackMode); } Creature.CurrentCharacterMode = CharacterMode.Idle; Creature.AddThought("I farmed something!", new TimeSpan(0, 4, 0, 0), 1.0f); Creature.AI.AddXP(1); ActHelper.ApplyWearToTool(Creature.AI, GameSettings.Current.Wear_Dig); Creature.Sprite.PauseAnimations(Creature.Stats.CurrentClass.AttackMode); yield return(Status.Success); } }
public override void OnApply(Creature creature) { SavedThought = creature.AddThought(Description, new TimeSpan(1, 0, 0, 0), HappinessModifier); base.OnApply(creature); }
public override IEnumerable <Status> Run() { float startingHealth = Creature.Status.Health.CurrentValue; PreTeleport = Creature.AI.Position; if (Type == SleepType.Sleep) { while (!Creature.Status.Energy.IsSatisfied() && Creature.Manager.World.Time.IsNight()) { if (Creature.Physics.IsInLiquid) { Creature.Status.IsAsleep = false; Creature.CurrentCharacterMode = CharacterMode.Idle; Creature.OverrideCharacterMode = false; yield return(Status.Fail); } if (Teleport) { Creature.AI.Position = TeleportLocation; Creature.Physics.Velocity = Vector3.Zero; Creature.Physics.LocalPosition = TeleportLocation; Creature.Physics.AllowPhysicsSleep = true; Creature.Physics.IsSleeping = true; } Creature.CurrentCharacterMode = CharacterMode.Sleeping; Creature.Status.Energy.CurrentValue += DwarfTime.Dt * RechargeRate; if (Creature.Status.Health.CurrentValue < startingHealth) { Creature.Status.IsAsleep = false; Creature.CurrentCharacterMode = CharacterMode.Idle; Creature.OverrideCharacterMode = false; yield return(Status.Fail); } Creature.Status.IsAsleep = true; Creature.OverrideCharacterMode = false; yield return(Status.Running); } if (Teleport) { Creature.AI.Position = PreTeleport; Creature.Physics.Velocity = Vector3.Zero; Creature.Physics.LocalPosition = TeleportLocation; Creature.Physics.IsSleeping = false; Creature.Physics.AllowPhysicsSleep = false; } Creature.AddThought(Thought.ThoughtType.Slept); Creature.Status.IsAsleep = false; Creature.Physics.IsSleeping = false; Creature.Physics.AllowPhysicsSleep = false; yield return(Status.Success); } else { while (Creature.Status.Health.IsDissatisfied() || Creature.Buffs.Any(buff => buff is Disease)) { if (Creature.Physics.IsInLiquid) { Creature.Status.IsAsleep = false; Creature.CurrentCharacterMode = CharacterMode.Idle; Creature.OverrideCharacterMode = false; yield return(Status.Fail); } if (Teleport) { Creature.AI.Position = TeleportLocation; Creature.Physics.Velocity = Vector3.Zero; Creature.Physics.LocalPosition = TeleportLocation; Creature.Physics.IsSleeping = true; Creature.Physics.AllowPhysicsSleep = true; } Creature.CurrentCharacterMode = CharacterMode.Sleeping; Creature.Status.Energy.CurrentValue += DwarfTime.Dt * RechargeRate; Creature.Heal(DwarfTime.Dt * HealRate); Creature.Status.IsAsleep = true; Creature.OverrideCharacterMode = false; yield return(Status.Running); } if (Teleport) { Creature.AI.Position = PreTeleport; Creature.Physics.Velocity = Vector3.Zero; Creature.Physics.LocalPosition = TeleportLocation; Creature.Physics.IsSleeping = false; Creature.Physics.AllowPhysicsSleep = false; } Creature.AddThought(Thought.ThoughtType.Slept); Creature.Status.IsAsleep = false; Creature.Physics.IsSleeping = false; Creature.Physics.AllowPhysicsSleep = false; yield return(Status.Success); } }
public IEnumerable <Status> FarmATile() { if (FarmToWork == null) { yield return(Status.Fail); yield break; } else if (FarmToWork.Finished) { yield return(Status.Success); } else { Creature.CurrentCharacterMode = Creature.AttackMode; Creature.Sprite.ResetAnimations(Creature.AttackMode); Creature.Sprite.PlayAnimations(Creature.AttackMode); while (FarmToWork.Progress < FarmToWork.TargetProgress && !FarmToWork.Finished) { Creature.Physics.Velocity *= 0.1f; FarmToWork.Progress += 3 * Creature.Stats.BaseFarmSpeed * DwarfTime.Dt; Drawer2D.DrawLoadBar(Agent.Manager.World.Camera, Agent.Position + Vector3.Up, Color.LightGreen, Color.Black, 64, 4, FarmToWork.Progress / FarmToWork.TargetProgress); if (FarmToWork.Progress >= (FarmToWork.TargetProgress * 0.5f) && FarmToWork.Voxel.Type.Name != "TilledSoil") { FarmToWork.Voxel.Type = VoxelLibrary.GetVoxelType("TilledSoil"); } if (FarmToWork.Progress >= FarmToWork.TargetProgress && !FarmToWork.Finished) { var plant = EntityFactory.CreateEntity <Plant>( ResourceLibrary.Resources[FarmToWork.SeedResourceType].PlantToGenerate, FarmToWork.Voxel.WorldPosition + new Vector3(0.5f, 1.0f, 0.5f)); plant.Farm = FarmToWork; Matrix original = plant.LocalTransform; original.Translation += Vector3.Down; plant.AnimationQueue.Add(new EaseMotion(0.5f, original, plant.LocalTransform.Translation)); Creature.Manager.World.ParticleManager.Trigger("puff", original.Translation, Color.White, 20); SoundManager.PlaySound(ContentPaths.Audio.Oscar.sfx_env_plant_grow, FarmToWork.Voxel.WorldPosition, true); FarmToWork.Finished = true; DestroyResources(); } if (MathFunctions.RandEvent(0.01f)) { Creature.Manager.World.ParticleManager.Trigger("dirt_particle", Creature.AI.Position, Color.White, 1); } yield return(Status.Running); Creature.Sprite.ReloopAnimations(Creature.AttackMode); } Creature.CurrentCharacterMode = CharacterMode.Idle; Creature.AddThought(Thought.ThoughtType.Farmed); Creature.AI.AddXP(1); Creature.Sprite.PauseAnimations(Creature.AttackMode); yield return(Status.Success); } }
public override IEnumerable <Status> Run() { Creature.IsCloaked = false; if (CurrentAttack == null) { yield return(Status.Fail); yield break; } Timeout.Reset(); FailTimer.Reset(); if (Target == null && TargetName != null) { Target = Agent.Blackboard.GetData <GameComponent>(TargetName); if (Target == null) { yield return(Status.Fail); yield break; } } if (Agent.Faction.Race.IsIntelligent) { var targetInventory = Target.GetRoot().GetComponent <Inventory>(); if (targetInventory != null) { targetInventory.SetLastAttacker(Agent); } } CharacterMode defaultCharachterMode = Creature.AI.Movement.CanFly ? CharacterMode.Flying : CharacterMode.Walking; bool avoided = false; while (true) { Timeout.Update(DwarfTime.LastTime); FailTimer.Update(DwarfTime.LastTime); if (FailTimer.HasTriggered) { Creature.Physics.Orientation = Physics.OrientMode.RotateY; Creature.OverrideCharacterMode = false; Creature.CurrentCharacterMode = defaultCharachterMode; yield return(Status.Fail); yield break; } if (Timeout.HasTriggered) { if (Training) { Agent.AddXP(1); Creature.Physics.Orientation = Physics.OrientMode.RotateY; Creature.OverrideCharacterMode = false; Creature.CurrentCharacterMode = defaultCharachterMode; yield return(Status.Success); yield break; } else { Creature.Physics.Orientation = Physics.OrientMode.RotateY; Creature.OverrideCharacterMode = false; Creature.CurrentCharacterMode = defaultCharachterMode; yield return(Status.Fail); yield break; } } if (Target == null || Target.IsDead) { Creature.CurrentCharacterMode = defaultCharachterMode; Creature.Physics.Orientation = Physics.OrientMode.RotateY; yield return(Status.Success); } // Find the location of the melee target Vector3 targetPos = new Vector3(Target.GlobalTransform.Translation.X, Target.GetBoundingBox().Min.Y, Target.GlobalTransform.Translation.Z); Vector2 diff = new Vector2(targetPos.X, targetPos.Z) - new Vector2(Creature.AI.Position.X, Creature.AI.Position.Z); Creature.Physics.Face(targetPos); bool intersectsbounds = Creature.Physics.BoundingBox.Intersects(Target.BoundingBox); float dist = diff.Length(); // If we are really far from the target, something must have gone wrong. if (DefensiveStructure == null && !intersectsbounds && dist > CurrentAttack.Weapon.Range * 4) { Creature.Physics.Orientation = Physics.OrientMode.RotateY; Creature.OverrideCharacterMode = false; Creature.CurrentCharacterMode = defaultCharachterMode; yield return(Status.Fail); yield break; } if (DefensiveStructure != null) { if (Creature.Hp < LastHp) { float damage = LastHp - Creature.Hp; Creature.Heal(Math.Min(5.0f, damage)); var health = DefensiveStructure.GetRoot().GetComponent <Health>(); if (health != null) { health.Damage(damage); Drawer2D.DrawLoadBar(health.World.Renderer.Camera, DefensiveStructure.Position, Color.White, Color.Black, 32, 1, health.Hp / health.MaxHealth, 0.1f); } LastHp = Creature.Hp; } if (dist > CurrentAttack.Weapon.Range) { float sqrDist = dist * dist; foreach (var threat in Creature.AI.Faction.Threats) { float threatDist = (threat.AI.Position - Creature.AI.Position).LengthSquared(); if (threatDist < sqrDist) { sqrDist = threatDist; Target = threat.Physics; break; } } dist = (float)Math.Sqrt(sqrDist); } if (dist > CurrentAttack.Weapon.Range * 4) { yield return(Status.Fail); yield break; } if (DefensiveStructure.IsDead) { DefensiveStructure = null; } } LastHp = Creature.Hp; // If we're out of attack range, run toward the target. if (DefensiveStructure == null && !Creature.AI.Movement.IsSessile && !intersectsbounds && diff.Length() > CurrentAttack.Weapon.Range) { Creature.CurrentCharacterMode = defaultCharachterMode; var greedyPath = new GreedyPathAct(Creature.AI, Target, CurrentAttack.Weapon.Range * 0.75f) { PathLength = 5 }; greedyPath.Initialize(); foreach (Act.Status stat in greedyPath.Run()) { if (stat == Act.Status.Running) { yield return(Status.Running); } else { break; } } } // If we have a ranged weapon, try avoiding the target for a few seconds to get within range. else if (DefensiveStructure == null && !Creature.AI.Movement.IsSessile && !intersectsbounds && !avoided && (CurrentAttack.Weapon.Mode == Weapon.AttackMode.Ranged && dist < CurrentAttack.Weapon.Range * 0.15f)) { FailTimer.Reset(); foreach (Act.Status stat in AvoidTarget(CurrentAttack.Weapon.Range, 3.0f)) { yield return(Status.Running); } avoided = true; } // Else, stop and attack else if ((DefensiveStructure == null && dist < CurrentAttack.Weapon.Range) || (DefensiveStructure != null && dist < CurrentAttack.Weapon.Range * 2.0)) { if (CurrentAttack.Weapon.Mode == Weapon.AttackMode.Ranged && VoxelHelpers.DoesRayHitSolidVoxel(Creature.World.ChunkManager, Creature.AI.Position, Target.Position)) { yield return(Status.Fail); yield break; } FailTimer.Reset(); avoided = false; Creature.Physics.Orientation = Physics.OrientMode.Fixed; Creature.Physics.Velocity = new Vector3(Creature.Physics.Velocity.X * 0.9f, Creature.Physics.Velocity.Y, Creature.Physics.Velocity.Z * 0.9f); CurrentAttack.RechargeTimer.Reset(CurrentAttack.Weapon.RechargeRate); Creature.Sprite.ResetAnimations(Creature.Stats.CurrentClass.AttackMode); Creature.Sprite.PlayAnimations(Creature.Stats.CurrentClass.AttackMode); Creature.CurrentCharacterMode = Creature.Stats.CurrentClass.AttackMode; Creature.OverrideCharacterMode = true; Timer timeout = new Timer(10.0f, true); while (!CurrentAttack.Perform(Creature, Target, DwarfTime.LastTime, Creature.Stats.Strength + Creature.Stats.Size, Creature.AI.Position, Creature.Faction.ParentFaction.Name)) { timeout.Update(DwarfTime.LastTime); if (timeout.HasTriggered) { break; } Creature.Physics.Velocity = new Vector3(Creature.Physics.Velocity.X * 0.9f, Creature.Physics.Velocity.Y, Creature.Physics.Velocity.Z * 0.9f); if (Creature.AI.Movement.CanFly) { Creature.Physics.ApplyForce(-Creature.Physics.Gravity * 0.1f, DwarfTime.Dt); } yield return(Status.Running); } timeout.Reset(); while (!Agent.Creature.Sprite.AnimPlayer.IsDone()) { timeout.Update(DwarfTime.LastTime); if (timeout.HasTriggered) { break; } if (Creature.AI.Movement.CanFly) { Creature.Physics.ApplyForce(-Creature.Physics.Gravity * 0.1f, DwarfTime.Dt); } yield return(Status.Running); } var targetCreature = Target.GetRoot().GetComponent <CreatureAI>(); if (targetCreature != null && Creature.AI.FightOrFlight(targetCreature) == CreatureAI.FightOrFlightResponse.Flee) { yield return(Act.Status.Fail); yield break; } Creature.CurrentCharacterMode = CharacterMode.Attacking; Vector3 dogfightTarget = Vector3.Zero; while (!CurrentAttack.RechargeTimer.HasTriggered && !Target.IsDead) { CurrentAttack.RechargeTimer.Update(DwarfTime.LastTime); if (CurrentAttack.Weapon.Mode == Weapon.AttackMode.Dogfight) { dogfightTarget += MathFunctions.RandVector3Cube() * 0.1f; Vector3 output = Creature.Controller.GetOutput(DwarfTime.Dt, dogfightTarget + Target.Position, Creature.Physics.GlobalTransform.Translation) * 0.9f; Creature.Physics.ApplyForce(output - Creature.Physics.Gravity, DwarfTime.Dt); } else { Creature.Physics.Velocity = Vector3.Zero; if (Creature.AI.Movement.CanFly) { Creature.Physics.ApplyForce(-Creature.Physics.Gravity, DwarfTime.Dt); } } yield return(Status.Running); } Creature.CurrentCharacterMode = defaultCharachterMode; Creature.Physics.Orientation = Physics.OrientMode.RotateY; if (Target.IsDead) { Target = null; Agent.AddXP(10); Creature.Physics.Face(Creature.Physics.Velocity + Creature.Physics.GlobalTransform.Translation); Creature.Stats.NumThingsKilled++; Creature.AddThought("I killed somehing!", new TimeSpan(0, 8, 0, 0), 1.0f); Creature.Physics.Orientation = Physics.OrientMode.RotateY; Creature.OverrideCharacterMode = false; Creature.CurrentCharacterMode = defaultCharachterMode; yield return(Status.Success); break; } } yield return(Status.Running); } }
public override IEnumerable <Status> Run() { Creature.IsCloaked = false; if (CurrentAttack == null) { yield return(Status.Fail); yield break; } Timeout.Reset(); FailTimer.Reset(); if (Target == null && TargetName != null) { Target = Agent.Blackboard.GetData <Body>(TargetName); if (Target == null) { yield return(Status.Fail); yield break; } } if (Agent.Faction.Race.IsIntelligent) { var targetInventory = Target.GetRoot().GetComponent <Inventory>(); if (targetInventory != null) { targetInventory.SetLastAttacker(Agent); } } CharacterMode defaultCharachterMode = Creature.AI.Movement.CanFly ? CharacterMode.Flying : CharacterMode.Walking; bool avoided = false; while (true) { Timeout.Update(DwarfTime.LastTime); FailTimer.Update(DwarfTime.LastTime); if (FailTimer.HasTriggered) { Creature.Physics.Orientation = Physics.OrientMode.RotateY; Creature.OverrideCharacterMode = false; Creature.CurrentCharacterMode = defaultCharachterMode; yield return(Status.Fail); yield break; } if (Timeout.HasTriggered) { if (Training) { Agent.AddXP(1); Creature.Physics.Orientation = Physics.OrientMode.RotateY; Creature.OverrideCharacterMode = false; Creature.CurrentCharacterMode = defaultCharachterMode; yield return(Status.Success); yield break; } else { Creature.Physics.Orientation = Physics.OrientMode.RotateY; Creature.OverrideCharacterMode = false; Creature.CurrentCharacterMode = defaultCharachterMode; yield return(Status.Fail); yield break; } } if (Target == null || Target.IsDead) { Creature.CurrentCharacterMode = defaultCharachterMode; Creature.Physics.Orientation = Physics.OrientMode.RotateY; yield return(Status.Success); } // Find the location of the melee target Vector3 targetPos = new Vector3(Target.GlobalTransform.Translation.X, Target.GetBoundingBox().Min.Y, Target.GlobalTransform.Translation.Z); Vector2 diff = new Vector2(targetPos.X, targetPos.Z) - new Vector2(Creature.AI.Position.X, Creature.AI.Position.Z); Creature.Physics.Face(targetPos); bool intersectsbounds = Creature.Physics.BoundingBox.Intersects(Target.BoundingBox); // If we are really far from the target, something must have gone wrong. if (!intersectsbounds && diff.Length() > CurrentAttack.Range * 4) { Creature.Physics.Orientation = Physics.OrientMode.RotateY; Creature.OverrideCharacterMode = false; Creature.CurrentCharacterMode = defaultCharachterMode; yield return(Status.Fail); yield break; } // If we're out of attack range, run toward the target. if (!Creature.AI.Movement.IsSessile && !intersectsbounds && diff.Length() > CurrentAttack.Range) { Creature.CurrentCharacterMode = defaultCharachterMode; /* * Vector3 output = Creature.Controller.GetOutput(DwarfTime.Dt, targetPos, Creature.Physics.GlobalTransform.Translation) * 0.9f; * output.Y = 0.0f; * if (Creature.AI.Movement.CanFly) * { * Creature.Physics.ApplyForce(-Creature.Physics.Gravity, DwarfTime.Dt); * } * if (Creature.AI.Movement.IsSessile) * { * output *= 0.0f; * } * Creature.Physics.ApplyForce(output, DwarfTime.Dt); * Creature.Physics.Orientation = Physics.OrientMode.RotateY; */ GreedyPathAct greedyPath = new GreedyPathAct(Creature.AI, Target, CurrentAttack.Range * 0.75f) { PathLength = 5 }; greedyPath.Initialize(); foreach (Act.Status stat in greedyPath.Run()) { if (stat == Act.Status.Running) { yield return(Status.Running); } else { break; } } } // If we have a ranged weapon, try avoiding the target for a few seconds to get within range. else if (!Creature.AI.Movement.IsSessile && !intersectsbounds && !avoided && (CurrentAttack.Mode == Attack.AttackMode.Ranged && diff.Length() < CurrentAttack.Range * 0.15f)) { FailTimer.Reset(); foreach (Act.Status stat in AvoidTarget(CurrentAttack.Range, 3.0f)) { yield return(Status.Running); } avoided = true; } // Else, stop and attack else { if (CurrentAttack.Mode == Attack.AttackMode.Ranged && VoxelHelpers.DoesRayHitSolidVoxel(Creature.World.ChunkManager.ChunkData, Creature.AI.Position, Target.Position)) { yield return(Status.Fail); yield break; } FailTimer.Reset(); avoided = false; Creature.Physics.Orientation = Physics.OrientMode.Fixed; Creature.Physics.Velocity = new Vector3(Creature.Physics.Velocity.X * 0.9f, Creature.Physics.Velocity.Y, Creature.Physics.Velocity.Z * 0.9f); CurrentAttack.RechargeTimer.Reset(CurrentAttack.RechargeRate); Creature.Sprite.ResetAnimations(Creature.AttackMode); Creature.Sprite.PlayAnimations(Creature.AttackMode); Creature.CurrentCharacterMode = Creature.AttackMode; Creature.OverrideCharacterMode = true; Timer timeout = new Timer(10.0f, true); while (!CurrentAttack.Perform(Creature, Target, DwarfTime.LastTime, Creature.Stats.BuffedStr + Creature.Stats.BuffedSiz, Creature.AI.Position, Creature.Faction.Name)) { timeout.Update(DwarfTime.LastTime); if (timeout.HasTriggered) { break; } Creature.Physics.Velocity = new Vector3(Creature.Physics.Velocity.X * 0.9f, Creature.Physics.Velocity.Y, Creature.Physics.Velocity.Z * 0.9f); if (Creature.AI.Movement.CanFly) { Creature.Physics.ApplyForce(-Creature.Physics.Gravity * 0.1f, DwarfTime.Dt); } yield return(Status.Running); } timeout.Reset(); while (!Agent.Creature.Sprite.AnimPlayer.IsDone()) { timeout.Update(DwarfTime.LastTime); if (timeout.HasTriggered) { break; } if (Creature.AI.Movement.CanFly) { Creature.Physics.ApplyForce(-Creature.Physics.Gravity * 0.1f, DwarfTime.Dt); } yield return(Status.Running); } var targetCreature = Target.GetRoot().GetComponent <CreatureAI>(); if (targetCreature != null && !Creature.AI.FightOrFlight(targetCreature)) { yield return(Act.Status.Fail); yield break; } Creature.CurrentCharacterMode = CharacterMode.Attacking; Vector3 dogfightTarget = Vector3.Zero; while (!CurrentAttack.RechargeTimer.HasTriggered && !Target.IsDead) { CurrentAttack.RechargeTimer.Update(DwarfTime.LastTime); if (CurrentAttack.Mode == Attack.AttackMode.Dogfight) { dogfightTarget += MathFunctions.RandVector3Cube() * 0.1f; Vector3 output = Creature.Controller.GetOutput(DwarfTime.Dt, dogfightTarget + Target.Position, Creature.Physics.GlobalTransform.Translation) * 0.9f; Creature.Physics.ApplyForce(output - Creature.Physics.Gravity, DwarfTime.Dt); } else { Creature.Physics.Velocity = Vector3.Zero; if (Creature.AI.Movement.CanFly) { Creature.Physics.ApplyForce(-Creature.Physics.Gravity, DwarfTime.Dt); } } yield return(Status.Running); } Creature.CurrentCharacterMode = defaultCharachterMode; Creature.Physics.Orientation = Physics.OrientMode.RotateY; if (Target.IsDead) { Target = null; Agent.AddXP(10); Creature.Physics.Face(Creature.Physics.Velocity + Creature.Physics.GlobalTransform.Translation); Creature.Stats.NumThingsKilled++; Creature.AddThought(Thought.ThoughtType.KilledThing); Creature.Physics.Orientation = Physics.OrientMode.RotateY; Creature.OverrideCharacterMode = false; Creature.CurrentCharacterMode = defaultCharachterMode; yield return(Status.Success); break; } } yield return(Status.Running); } }
public override IEnumerable <Act.Status> Run() { if (Spell.IsResearched) { Creature.CurrentCharacterMode = CharacterMode.Idle; Creature.OverrideCharacterMode = false; yield return(Status.Success); yield break; } Timer starParitcle = new Timer(0.5f, false); float totalResearch = 0.0f; Sound3D sound = null; while (!Spell.IsResearched) { Creature.CurrentCharacterMode = Creature.AttackMode; Creature.OverrideCharacterMode = true; Creature.Sprite.ReloopAnimations(Creature.AttackMode); float research = Creature.Stats.BuffedInt * 0.25f * DwarfTime.Dt; Spell.ResearchProgress += research; totalResearch += research; Creature.Physics.Velocity *= 0; Drawer2D.DrawLoadBar(Creature.World.Camera, Creature.Physics.Position, Color.Cyan, Color.Black, 64, 4, Spell.ResearchProgress / Spell.ResearchTime); if ((int)totalResearch > 0) { if (sound == null || sound.EffectInstance.IsDisposed || sound.EffectInstance.State == SoundState.Stopped) { sound = SoundManager.PlaySound(ContentPaths.Audio.Oscar.sfx_ic_dwarf_magic_research, Creature.AI.Position, true); } //SoundManager.PlaySound(ContentPaths.Audio.tinkle, Creature.AI.Position, true); Creature.AI.AddXP((int)(totalResearch)); totalResearch = 0.0f; } if (Spell.ResearchProgress >= Spell.ResearchTime) { Creature.Manager.World.MakeAnnouncement( new Gui.Widgets.QueuedAnnouncement { Text = String.Format("{0} ({1}) discovered the {2} spell!", Creature.Stats.FullName, Creature.Stats.CurrentLevel.Name, Spell.Spell.Name), ClickAction = (gui, sender) => Agent.ZoomToMe() }); SoundManager.PlaySound(ContentPaths.Audio.Oscar.sfx_gui_positive_generic, 0.15f); } starParitcle.Update(DwarfTime.LastTime); if (starParitcle.HasTriggered) { Creature.Manager.World.ParticleManager.Trigger("star_particle", Creature.AI.Position, Color.White, 3); } yield return(Status.Running); } if (sound != null) { sound.Stop(); } Creature.AddThought(Thought.ThoughtType.Researched); Creature.OverrideCharacterMode = false; Creature.CurrentCharacterMode = CharacterMode.Idle; yield return(Status.Success); yield break; }
override public void Update(DwarfTime gameTime, ChunkManager chunks, Camera camera) { //base.Update(gameTime, chunks, camera); if (!Active) { return; } Creature.NoiseMaker.BasePitch = Stats.VoicePitch; AutoGatherTimer.Update(gameTime); IdleTimer.Update(gameTime); SpeakTimer.Update(gameTime); if (AutoGatherTimer.HasTriggered) { foreach (var body in World.EnumerateIntersectingObjects(Physics.BoundingBox.Expand(3.0f)).OfType <ResourceEntity>().Where(r => r.Active && r.AnimationQueue.Count == 0)) { Creature.GatherImmediately(body, Inventory.RestockType.RestockResource); } OrderEnemyAttack(); } DeleteBadTasks(); PreEmptTasks(); if (CurrentTask != null) { Stats.Boredom.CurrentValue -= (float)(CurrentTask.BoredomIncrease * gameTime.ElapsedGameTime.TotalSeconds); if (Stats.Boredom.IsCritical()) { Creature.AddThought("I have been overworked recently.", new TimeSpan(0, 4, 0, 0), -2.0f); } Stats.Energy.CurrentValue += (float)(CurrentTask.EnergyDecrease * gameTime.ElapsedGameTime.TotalSeconds); } // Heal thyself if (Stats.Health.IsDissatisfied()) { Task toReturn = new GetHealedTask(); if (!Tasks.Contains(toReturn) && CurrentTask != toReturn) { AssignTask(toReturn); } } // Try to go to sleep if we are low on energy and it is night time. if (Stats.Energy.IsCritical()) { Task toReturn = new SatisfyTirednessTask(); if (!Tasks.Contains(toReturn) && CurrentTask != toReturn) { AssignTask(toReturn); } } // Try to find food if we are hungry. if (Stats.Hunger.IsDissatisfied() && World.CountResourcesWithTag(Resource.ResourceTags.Edible) > 0) { Task toReturn = new SatisfyHungerTask() { MustPay = true }; if (Stats.Hunger.IsCritical()) { toReturn.Priority = TaskPriority.Urgent; } if (!Tasks.Contains(toReturn) && CurrentTask != toReturn) { AssignTask(toReturn); } } if (Stats.Boredom.IsDissatisfied()) { if (!Tasks.Any(task => task.BoredomIncrease < 0)) { Task toReturn = SatisfyBoredom(); if (toReturn != null && !Tasks.Contains(toReturn) && CurrentTask != toReturn) { AssignTask(toReturn); } } } restockTimer.Update(DwarfTime.LastTime); if (restockTimer.HasTriggered && Creature.Inventory.Resources.Count > 10) { Creature.RestockAllImmediately(); } if (CurrentTask == null) // We need something to do. { if (Stats.Happiness.IsSatisfied()) // We're happy, so make sure we aren't on strike. { Stats.IsOnStrike = false; UnhappinessTime = 0.0f; } if (Stats.IsOnStrike) // We're on strike, so track how long this job has sucked. { UnhappinessTime += gameTime.ElapsedGameTime.TotalMinutes; if (UnhappinessTime > GameSettings.Default.HoursUnhappyBeforeQuitting) // If we've been unhappy long enough, quit. { var thoughts = GetRoot().GetComponent <DwarfThoughts>(); Manager.World.MakeAnnouncement( // Can't use a popup because the dwarf will soon not exist. Also - this is a serious event! Message: String.Format("{0} has quit!{1}", Stats.FullName, (thoughts == null ? "" : (" The last straw: " + thoughts.Thoughts.Last(t => t.HappinessModifier < 0.0f).Description))), ClickAction: null, logEvent: true, eventDetails: (thoughts == null ? "So sick of this place!" : String.Join("\n", thoughts.Thoughts.Where(t => t.HappinessModifier < 0.0f).Select(t => t.Description))) ); LeaveWorld(); GetRoot().GetComponent <Inventory>().Die(); GetRoot().GetComponent <SelectionCircle>().Die(); if (thoughts != null) { thoughts.Thoughts.Clear(); } Faction.Minions.Remove(this); World.PersistentData.SelectedMinions.Remove(this); return; } } else if (Stats.Happiness.IsDissatisfied()) // We aren't on strike, but we hate this place. { if (MathFunctions.Rand(0, 1) < 0.25f) // We hate it so much that we might just go on strike! This can probably be tweaked. As it stands, // dorfs go on strike almost immediately every time. { Manager.World.UserInterface.MakeWorldPopup(String.Format("{0} ({1}) refuses to work!", Stats.FullName, Stats.CurrentClass.Name), Creature.Physics, -10, 10); Manager.World.Tutorial("happiness"); SoundManager.PlaySound(ContentPaths.Audio.Oscar.sfx_gui_negative_generic, 0.25f); Stats.IsOnStrike = true; } } if (!Stats.IsOnStrike) // We aren't on strike, so find a new task. { var goal = GetEasiestTask(Tasks); if (goal == null) { goal = World.TaskManager.GetBestTask(this); } if (goal != null) { IdleTimer.Reset(IdleTimer.TargetTimeSeconds); ChangeTask(goal); } else { var newTask = ActOnIdle(); if (newTask != null) { ChangeTask(newTask); } } } else { ChangeTask(ActOnIdle()); } } else { if (CurrentAct == null) // Should be impossible to have a current task and no current act. { // Try and recover the correct act. // <blecki> I always run with a breakpoint set here... just in case. ChangeAct(CurrentTask.CreateScript(Creature)); // This is a bad situation! if (CurrentAct == null) { ChangeTask(null); } } if (CurrentAct != null) { var status = CurrentAct.Tick(); bool retried = false; if (CurrentAct != null && CurrentTask != null) { if (status == Act.Status.Fail) { LastFailedAct = CurrentAct.Name; if (!FailedTasks.Any(task => task.TaskFailure.Equals(CurrentTask))) { FailedTasks.Add(new FailedTask() { TaskFailure = CurrentTask, FailedTime = World.Time.CurrentDate }); } if (CurrentTask.ShouldRetry(Creature)) { if (!Tasks.Contains(CurrentTask)) { ReassignCurrentTask(); retried = true; } } } } if (CurrentTask != null && CurrentTask.IsComplete(World)) { ChangeTask(null); } else if (status != Act.Status.Running && !retried) { ChangeTask(null); } } } // With a small probability, the creature will drown if its under water. if (MathFunctions.RandEvent(0.01f)) { var above = VoxelHelpers.GetVoxelAbove(Physics.CurrentVoxel); var below = VoxelHelpers.GetVoxelBelow(Physics.CurrentVoxel); bool shouldDrown = (above.IsValid && (!above.IsEmpty || above.LiquidLevel > 0)); if ((Physics.IsInLiquid || (!Movement.CanSwim && (below.IsValid && (below.LiquidLevel > 5)))) && (!Movement.CanSwim || shouldDrown)) { Creature.Damage(Movement.CanSwim ? 1.0f : 30.0f, Health.DamageType.Normal); } } if (PositionConstraint.Contains(Physics.LocalPosition) == ContainmentType.Disjoint) { Physics.LocalPosition = MathFunctions.Clamp(Physics.Position, PositionConstraint); Physics.PropogateTransforms(); } }