protected override void Act(float deltaTime) { if (followControlledCharacter) { if (Character.Controlled == null) { Abandon = true; return; } Target = Character.Controlled; } if (Target == character) { // Wait character.AIController.SteeringManager.Reset(); return; } waitUntilPathUnreachable -= deltaTime; if (!character.IsClimbing) { character.SelectedConstruction = null; } if (Target is Entity e) { if (e.Removed) { Abandon = true; } else { character.AIController.SelectTarget(e.AiTarget); } } var targetHull = Target is Hull h ? h : Target is Item i ? i.CurrentHull : Target is Character c ? c.CurrentHull : character.CurrentHull; if (!followControlledCharacter) { // Abandon if going through unsafe paths. Note ignores unsafe nodes when following an order or when the objective is set to ignore unsafe hulls. bool containsUnsafeNodes = HumanAIController.CurrentOrder == null && !HumanAIController.ObjectiveManager.CurrentObjective.IgnoreUnsafeHulls && PathSteering != null && PathSteering.CurrentPath != null && PathSteering.CurrentPath.Nodes.Any(n => HumanAIController.UnsafeHulls.Contains(n.CurrentHull)); if (containsUnsafeNodes || HumanAIController.UnreachableHulls.Contains(targetHull)) { Abandon = true; SteeringManager.Reset(); return; } } bool insideSteering = SteeringManager == PathSteering && PathSteering.CurrentPath != null && !PathSteering.IsPathDirty; bool isInside = character.CurrentHull != null; bool targetIsOutside = (Target != null && targetHull == null) || (insideSteering && PathSteering.CurrentPath.HasOutdoorsNodes); if (isInside && targetIsOutside && !AllowGoingOutside) { Abandon = true; } else if (waitUntilPathUnreachable < 0) { if (SteeringManager == PathSteering && PathSteering.CurrentPath != null && PathSteering.CurrentPath.Unreachable && !PathSteering.IsPathDirty) { if (repeat) { SteeringManager.Reset(); } else { Abandon = true; } } } if (Abandon) { #if DEBUG DebugConsole.NewMessage($"{character.Name}: Cannot reach the target: {Target.ToString()}", Color.Yellow); #endif if (objectiveManager.CurrentOrder != null && objectiveManager.CurrentOrder.ReportFailures) { character.Speak(TextManager.Get("DialogCannotReach"), identifier: "cannotreach", minDurationBetweenSimilar: 10.0f); } SteeringManager.Reset(); } else { if (getDivingGearIfNeeded && !character.LockHands) { Character followTarget = Target as Character; bool needsDivingSuit = targetIsOutside; bool needsDivingGear = needsDivingSuit || HumanAIController.NeedsDivingGear(character, targetHull, out needsDivingSuit); if (!needsDivingGear && mimic) { if (HumanAIController.HasDivingSuit(followTarget)) { needsDivingGear = true; needsDivingSuit = true; } else if (HumanAIController.HasDivingMask(followTarget)) { needsDivingGear = true; } } bool needsEquipment = false; if (needsDivingSuit) { needsEquipment = !HumanAIController.HasDivingSuit(character, AIObjectiveFindDivingGear.lowOxygenThreshold); } else if (needsDivingGear) { needsEquipment = !HumanAIController.HasDivingGear(character, AIObjectiveFindDivingGear.lowOxygenThreshold); } if (needsEquipment) { TryAddSubObjective(ref findDivingGear, () => new AIObjectiveFindDivingGear(character, needsDivingSuit, objectiveManager), onAbandon: () => Abandon = true, onCompleted: () => RemoveSubObjective(ref findDivingGear)); return; } } if (repeat && IsCloseEnough) { OnCompleted(); return; } if (SteeringManager == PathSteering) { Func <PathNode, bool> nodeFilter = null; if (isInside && !AllowGoingOutside) { nodeFilter = node => node.Waypoint.CurrentHull != null; } PathSteering.SteeringSeek(character.GetRelativeSimPosition(Target), 1, startNodeFilter, endNodeFilter, nodeFilter); } else { SteeringManager.SteeringSeek(character.GetRelativeSimPosition(Target), 10); } if (!insideSteering) { SteeringManager.SteeringAvoid(deltaTime, lookAheadDistance: 5, weight: 1); } } }
protected override void Act(float deltaTime) { if (followControlledCharacter) { if (Character.Controlled == null) { abandon = true; return; } Target = Character.Controlled; } if (Target == character) { character.AIController.SteeringManager.Reset(); abandon = true; return; } waitUntilPathUnreachable -= deltaTime; if (!character.IsClimbing) { character.SelectedConstruction = null; } if (Target is Entity e) { if (e.Removed) { abandon = true; } else { character.AIController.SelectTarget(e.AiTarget); } } bool isInside = character.CurrentHull != null; bool insideSteering = SteeringManager == PathSteering && PathSteering.CurrentPath != null && !PathSteering.IsPathDirty; var targetHull = Target is Hull h ? h : Target is Item i ? i.CurrentHull : Target is Character c ? c.CurrentHull : character.CurrentHull; bool targetIsOutside = (Target != null && targetHull == null) || (insideSteering && PathSteering.CurrentPath.HasOutdoorsNodes); if (isInside && targetIsOutside && !AllowGoingOutside) { abandon = true; } else if (waitUntilPathUnreachable < 0) { if (SteeringManager == PathSteering && PathSteering.CurrentPath != null && PathSteering.CurrentPath.Unreachable) { if (repeat) { SteeringManager.Reset(); } else { abandon = true; } } } if (abandon) { #if DEBUG DebugConsole.NewMessage($"{character.Name}: Cannot reach the target: {Target.ToString()}", Color.Yellow); #endif if (objectiveManager.CurrentOrder != null) { character.Speak(TextManager.Get("DialogCannotReach"), identifier: "cannotreach", minDurationBetweenSimilar: 10.0f); } character.AIController.SteeringManager.Reset(); } else { Vector2 currTargetSimPos = Vector2.Zero; currTargetSimPos = Target.SimPosition; // Take the sub position into account in the sim pos if (SteeringManager != PathSteering && character.Submarine == null && Target.Submarine != null) { currTargetSimPos += Target.Submarine.SimPosition; } else if (character.Submarine != null && Target.Submarine == null) { currTargetSimPos -= character.Submarine.SimPosition; } else if (character.Submarine != Target.Submarine) { if (character.Submarine != null && Target.Submarine != null) { Vector2 diff = character.Submarine.SimPosition - Target.Submarine.SimPosition; currTargetSimPos -= diff; } } if (PathSteering != null) { PathSteering.startNodeFilter = startNodeFilter; PathSteering.endNodeFilter = endNodeFilter; } SteeringManager.SteeringSeek(currTargetSimPos); if (SteeringManager != PathSteering) { SteeringManager.SteeringAvoid(deltaTime, lookAheadDistance: 5, weight: 1, heading: VectorExtensions.Forward(character.AnimController.Collider.Rotation)); } if (getDivingGearIfNeeded) { Character followTarget = Target as Character; bool needsDivingGear = HumanAIController.NeedsDivingGear(targetHull) || mimic && HumanAIController.HasDivingMask(followTarget); bool needsDivingSuit = needsDivingGear && (targetHull == null || targetIsOutside || targetHull.WaterPercentage > 90) || mimic && HumanAIController.HasDivingSuit(followTarget); bool needsEquipment = false; if (needsDivingSuit) { needsEquipment = !HumanAIController.HasDivingSuit(character); } else if (needsDivingGear) { needsEquipment = !HumanAIController.HasDivingMask(character); } if (needsEquipment) { TryAddSubObjective(ref findDivingGear, () => new AIObjectiveFindDivingGear(character, needsDivingSuit, objectiveManager)); } } } }
public void Update(float deltaTime) { position += new Vector2(velocity.X, velocity.Y) * deltaTime; depth = MathHelper.Clamp(depth + velocity.Z * deltaTime, 0.0f, MaxDepth); checkWallsTimer -= deltaTime; if (checkWallsTimer <= 0.0f && Level.Loaded != null) { checkWallsTimer = CheckWallsInterval; obstacleDiff = Vector2.Zero; if (position.Y > Level.Loaded.Size.Y) { obstacleDiff = Vector2.UnitY; } else if (position.Y < 0.0f) { obstacleDiff = -Vector2.UnitY; } else if (position.X < 0.0f) { obstacleDiff = Vector2.UnitX; } else if (position.X > Level.Loaded.Size.X) { obstacleDiff = -Vector2.UnitX; } else { var cells = Level.Loaded.GetCells(position, 1); if (cells.Count > 0) { int cellCount = 0; foreach (Voronoi2.VoronoiCell cell in cells) { Vector2 diff = cell.Center - position; if (diff.LengthSquared() > 5000.0f * 5000.0f) { continue; } obstacleDiff += diff; cellCount++; } if (cellCount > 0) { obstacleDiff /= cellCount; obstacleDist = obstacleDiff.Length(); obstacleDiff = Vector2.Normalize(obstacleDiff); } } } } if (Swarm != null) { Vector2 midPoint = Swarm.MidPoint(); float midPointDist = Vector2.Distance(SimPosition, midPoint) * 100.0f; if (midPointDist > Swarm.MaxDistance) { steeringManager.SteeringSeek(midPoint, ((midPointDist / Swarm.MaxDistance) - 1.0f) * prefab.Speed); } steeringManager.SteeringManual(deltaTime, Swarm.AvgVelocity() * Swarm.Cohesion); } if (prefab.WanderAmount > 0.0f) { steeringManager.SteeringWander(prefab.Speed); } if (obstacleDiff != Vector2.Zero) { steeringManager.SteeringManual(deltaTime, -obstacleDiff * (1.0f - obstacleDist / 5000.0f) * prefab.Speed); } steeringManager.Update(prefab.Speed); if (prefab.WanderZAmount > 0.0f) { wanderZPhase += Rand.Range(-prefab.WanderZAmount, prefab.WanderZAmount); velocity.Z = (float)Math.Sin(wanderZPhase) * prefab.Speed; } velocity = Vector3.Lerp(velocity, new Vector3(Steering.X, Steering.Y, velocity.Z), deltaTime); }
public void Update(float deltaTime) { position += new Vector2(velocity.X, velocity.Y) * deltaTime; depth = MathHelper.Clamp(depth + velocity.Z * deltaTime, 0.0f, MaxDepth); checkWallsTimer -= deltaTime; if (checkWallsTimer <= 0.0f && Level.Loaded != null) { checkWallsTimer = CheckWallsInterval; obstacleDiff = Vector2.Zero; if (position.Y > Level.Loaded.Size.Y) { obstacleDiff = Vector2.UnitY; } else if (position.Y < 0.0f) { obstacleDiff = -Vector2.UnitY; } else if (position.X < 0.0f) { obstacleDiff = Vector2.UnitX; } else if (position.X > Level.Loaded.Size.X) { obstacleDiff = -Vector2.UnitX; } else { var cells = Level.Loaded.GetCells(position, 1); if (cells.Count > 0) { foreach (Voronoi2.VoronoiCell cell in cells) { obstacleDiff += cell.Center - position; } obstacleDiff /= cells.Count; obstacleDiff = Vector2.Normalize(obstacleDiff) * prefab.Speed; } } } if (Swarm != null) { Vector2 midPoint = Swarm.MidPoint(); float midPointDist = Vector2.Distance(SimPosition, midPoint); if (midPointDist > Swarm.MaxDistance) { steeringManager.SteeringSeek(midPoint, (midPointDist / Swarm.MaxDistance) * prefab.Speed); } } if (prefab.WanderAmount > 0.0f) { steeringManager.SteeringWander(prefab.Speed); } //Level.Loaded.Size if (obstacleDiff != Vector2.Zero) { steeringManager.SteeringSeek(SimPosition - obstacleDiff, prefab.Speed * 2.0f); } steeringManager.Update(prefab.Speed); if (prefab.WanderZAmount > 0.0f) { ang += Rand.Range(-prefab.WanderZAmount, prefab.WanderZAmount); velocity.Z = (float)Math.Sin(ang) * prefab.Speed; } velocity = Vector3.Lerp(velocity, new Vector3(Steering.X, Steering.Y, velocity.Z), deltaTime); }
public void Update(float deltaTime) { position += new Vector2(velocity.X, velocity.Y) * deltaTime; depth = MathHelper.Clamp(depth + velocity.Z * deltaTime, Prefab.MinDepth, Prefab.MaxDepth * 10); if (Prefab.FlashInterval > 0.0f) { flashTimer -= deltaTime; if (flashTimer > 0.0f) { alpha = 0.0f; } else { //value goes from 0 to 1 and back to 0 during the flash alpha = (float)Math.Sin(-flashTimer / Prefab.FlashDuration * MathHelper.Pi) * PerlinNoise.GetPerlin((float)Timing.TotalTime * 0.1f, (float)Timing.TotalTime * 0.2f); if (flashTimer < -Prefab.FlashDuration) { flashTimer = Prefab.FlashInterval; } } } checkWallsTimer -= deltaTime; if (checkWallsTimer <= 0.0f && Level.Loaded != null) { checkWallsTimer = CheckWallsInterval; obstacleDiff = Vector2.Zero; if (position.Y > Level.Loaded.Size.Y) { obstacleDiff = Vector2.UnitY; } else if (position.Y < 0.0f) { obstacleDiff = -Vector2.UnitY; } else if (position.X < 0.0f) { obstacleDiff = Vector2.UnitX; } else if (position.X > Level.Loaded.Size.X) { obstacleDiff = -Vector2.UnitX; } else { var cells = Level.Loaded.GetCells(position, 1); if (cells.Count > 0) { int cellCount = 0; foreach (Voronoi2.VoronoiCell cell in cells) { Vector2 diff = cell.Center - position; if (diff.LengthSquared() > 5000.0f * 5000.0f) { continue; } obstacleDiff += diff; cellCount++; } if (cellCount > 0) { obstacleDiff /= cellCount; obstacleDist = obstacleDiff.Length(); obstacleDiff = Vector2.Normalize(obstacleDiff); } } } } if (Swarm != null) { Vector2 midPoint = Swarm.MidPoint(); float midPointDist = Vector2.Distance(SimPosition, midPoint) * 100.0f; if (midPointDist > Swarm.MaxDistance) { steeringManager.SteeringSeek(midPoint, ((midPointDist / Swarm.MaxDistance) - 1.0f) * Prefab.Speed); } steeringManager.SteeringManual(deltaTime, Swarm.AvgVelocity() * Swarm.Cohesion); } if (Prefab.WanderAmount > 0.0f) { steeringManager.SteeringWander(Prefab.Speed); } if (obstacleDiff != Vector2.Zero) { steeringManager.SteeringManual(deltaTime, -obstacleDiff * (1.0f - obstacleDist / 5000.0f) * Prefab.Speed); } steeringManager.Update(Prefab.Speed); if (Prefab.WanderZAmount > 0.0f) { wanderZPhase += Rand.Range(-Prefab.WanderZAmount, Prefab.WanderZAmount); velocity.Z = (float)Math.Sin(wanderZPhase) * Prefab.Speed; } velocity = Vector3.Lerp(velocity, new Vector3(Steering.X, Steering.Y, velocity.Z), deltaTime); UpdateDeformations(deltaTime); }