public void Sense() { if (Allies == null && Creature != null) { Allies = Creature.Faction; } List <CreatureAI> sensed = new List <CreatureAI>(); VoxelHandle currentVoxel = new VoxelHandle(World.ChunkManager.ChunkData, GlobalVoxelCoordinate.FromVector3(Position)); if (!(currentVoxel.IsValid && currentVoxel.IsEmpty)) { return; } foreach (var thing in Manager.World.CollisionManager.EnumerateIntersectingObjects(BoundingBox, CollisionManager.CollisionType.Both)) { Body body = thing as Body; if (body == null) { continue; } CreatureAI minion = body.GetRoot().GetComponent <CreatureAI>(); if (minion == null) { continue; } Faction faction = minion.Faction; if (World.Diplomacy.GetPolitics(Allies, faction).GetCurrentRelationship() != Relationship.Hateful) { continue; } if (!minion.Active) { continue; } float dist = (minion.Position - GlobalTransform.Translation).LengthSquared(); if (dist < SenseRadius && !VoxelHelpers.DoesRayHitSolidVoxel( Manager.World.ChunkManager.ChunkData, Position, minion.Position)) { sensed.Add(minion); } } if (sensed.Count > 0) { OnEnemySensed.Invoke(sensed); } }
public void Sense() { if (Allies == null && Creature != null) { Allies = Creature.Faction; } List <CreatureAI> sensed = new List <CreatureAI>(); List <CreatureAI> collide = new List <CreatureAI>(); foreach (KeyValuePair <string, Faction> faction in Manager.World.Factions.Factions) { if (World.Diplomacy.GetPolitics(Allies, faction.Value).GetCurrentRelationship() != Relationship.Hateful) { continue; } foreach (CreatureAI minion in faction.Value.Minions) { if (!minion.Active) { continue; } if (Creature != null && minion.Sensor.Enemies.Contains(Creature)) { sensed.Add(minion); continue; } float dist = (minion.Position - GlobalTransform.Translation).LengthSquared(); if (dist < SenseRadius && !VoxelHelpers.DoesRayHitSolidVoxel( Manager.World.ChunkManager.ChunkData, Position, minion.Position)) { sensed.Add(minion); } if (dist < 1.0f) { collide.Add(minion); } } } if (sensed.Count > 0) { OnEnemySensed.Invoke(sensed); } }
override public void Update(DwarfTime gameTime, ChunkManager chunks, Camera camera) { base.Update(gameTime, chunks, camera); if (!Active) { return; } SenseTimer.Update(gameTime); if (SenseTimer.HasTriggered) { Creatures.Clear(); var myRoot = GetRoot(); foreach (var body in Manager.World.EnumerateIntersectingObjects(BoundingBox, b => b.Active && !Object.ReferenceEquals(b, myRoot) && b.IsRoot())) { var minion = body.GetComponent <Creature>(); if (minion == null) { continue; } float dist = (body.Position - GlobalTransform.Translation).LengthSquared(); if (dist > SenseRadius) { continue; } if (CheckLineOfSight && VoxelHelpers.DoesRayHitSolidVoxel(Manager.World.ChunkManager, Position, body.Position)) { continue; } Creatures.Add(minion); } } Creatures.RemoveAll(ai => ai.IsDead); }
public void Sense() { if (Name == "turret-sensor") { var x = 5; } if (!Active) { return; } if (Creature != null) { Allies = Creature.Faction; } // Don't sense enemies if we're inside the ground?? var currentVoxel = new VoxelHandle(World.ChunkManager, GlobalVoxelCoordinate.FromVector3(Position)); if (!(currentVoxel.IsValid && currentVoxel.IsEmpty)) { return; } var sensed = new List <CreatureAI>(); var myRoot = GetRoot(); foreach (var body in Manager.World.EnumerateIntersectingObjects(BoundingBox, b => !Object.ReferenceEquals(b, myRoot) && b.IsRoot())) { if (body.GetComponent <Flammable>().HasValue(out var flames) && flames.IsOnFire) { if (GetRoot().GetComponent <CreatureAI>().HasValue(out var myAI)) { var task = new FleeEntityTask(body, 5) { Priority = TaskPriority.Urgent, AutoRetry = false, ReassignOnDeath = false }; if (!myAI.HasTaskWithName(task)) { myAI.AssignTask(task); } continue; } } if (body.GetComponent <CreatureAI>().HasValue(out var minion)) { if (!minion.Active) { continue; } if (!DetectCloaked && minion.Creature.IsCloaked) { continue; } else if (DetectCloaked && minion.Creature.IsCloaked) { minion.Creature.IsCloaked = false; } if (World.Overworld.GetPolitics(Allies.ParentFaction, minion.Faction.ParentFaction).GetCurrentRelationship() != Relationship.Hateful) { continue; } if (!VoxelHelpers.DoesRayHitSolidVoxel(Manager.World.ChunkManager, Position, minion.Position)) { sensed.Add(minion); } } } if (sensed != null && sensed.Count > 0 && OnEnemySensed != null) { OnEnemySensed.Invoke(sensed); } }
public override IEnumerable <Status> Run() { 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; } } Inventory targetInventory = Target.GetRoot().GetComponent <Inventory>(); if (targetInventory != null) { targetInventory.OnDeath += targetInventory_OnDeath; } 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 * 8) { Creature.Physics.Orientation = Physics.OrientMode.RotateY; Creature.OverrideCharacterMode = false; Creature.CurrentCharacterMode = defaultCharachterMode; yield return(Status.Fail); } // 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(CharacterMode.Attacking); Creature.Sprite.PlayAnimations(CharacterMode.Attacking); Creature.CurrentCharacterMode = CharacterMode.Attacking; Creature.OverrideCharacterMode = true; while (!CurrentAttack.Perform(Creature, Target, DwarfTime.LastTime, Creature.Stats.BuffedStr + Creature.Stats.BuffedSiz, Creature.AI.Position, Creature.Faction.Name)) { 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); } while (!Agent.Creature.Sprite.AnimPlayer.IsDone()) { 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; Creature.Sprite.ReloopAnimations(CharacterMode.Attacking); CurrentAttack.RechargeTimer.Reset(CurrentAttack.RechargeRate); Vector3 dogfightTarget = Vector3.Zero; while (!CurrentAttack.RechargeTimer.HasTriggered && !Target.IsDead) { CurrentAttack.RechargeTimer.Update(DwarfTime.LastTime); if (CurrentAttack.Mode == Attack.AttackMode.Dogfight) { Creature.CurrentCharacterMode = CharacterMode.Attacking; 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.Sprite.PauseAnimations(CharacterMode.Attacking); 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, DwarfTime.Dt); } } yield return(Status.Running); } Creature.CurrentCharacterMode = defaultCharachterMode; Creature.Physics.Orientation = Physics.OrientMode.RotateY; if (Target.IsDead) { Creature.Faction.Designations.RemoveEntityDesignation(Target, DesignationType.Attack); Target = null; Agent.AddXP(10); Creature.Physics.Face(Creature.Physics.Velocity + Creature.Physics.GlobalTransform.Translation); Creature.Stats.NumThingsKilled++; Creature.AI.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 <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); } }