Files
LuaCsForBarotraumaEP/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/Objectives/AIObjectiveInspectNoises.cs
2026-04-09 15:10:07 +03:00

127 lines
6.1 KiB
C#

using System;
namespace Barotrauma
{
class AIObjectiveInspectNoises : AIObjective
{
public override Identifier Identifier { get; set; } = "inspect noises".ToIdentifier();
private AIObjectiveGoTo inspectNoiseObjective;
/// <summary>
/// Initial priority of the objective to check noises made by enemies
/// </summary>
const float InspectNoisePriority = 10.0f;
/// <summary>
/// How much the priority of the objective to check noises made by enemies increases per noise
/// </summary>
const float InspectNoisePriorityIncrease = 10.0f;
private const float InspectNoiseInterval = 1.0f;
private float inspectNoiseTimer;
/// <summary>
/// If the character is not currently inspecting the noise (= if some other objective is taking priority)
/// it forgets about it after this delay runs out. Otherwise they might unnecessarily go and inspect some
/// noise that was emitted a long time ago once done with the higher-prio objective.
/// </summary>
private const float InspectNoiseExpirationDelay = 60.0f;
private float inspectNoiseExpirationTimer = 0.0f;
protected override float GetPriority() => inspectNoiseObjective?.Priority ?? 0.0f;
public AIObjectiveInspectNoises(Character character, AIObjectiveManager objectiveManager, float priorityModifier = 1)
: base(character, objectiveManager, priorityModifier)
{
inspectNoiseTimer = Rand.Range(0.0f, InspectNoiseInterval);
}
public override void Update(float deltaTime)
{
base.Update(deltaTime);
inspectNoiseTimer -= deltaTime;
if (inspectNoiseTimer <= 0.0f)
{
CheckEnemyNoises();
inspectNoiseTimer = InspectNoiseInterval;
}
//if we're not currently inspecting the noise (something else taking priority), forget about it after a while
if (inspectNoiseObjective != null && objectiveManager.GetActiveObjective() != inspectNoiseObjective)
{
inspectNoiseExpirationTimer += deltaTime;
if (inspectNoiseExpirationTimer > InspectNoiseExpirationDelay)
{
inspectNoiseObjective.Abandon = true;
}
}
}
/// <summary>
/// Check if there's any loud provocative items used by enemies nearby (= if someone fired a gun somewhere), and go inspect them
/// </summary>
private void CheckEnemyNoises()
{
if (character.CurrentHull == null) { return; }
//forget about inspecting if we're doing another subobjective (= fighting something)
if (inspectNoiseObjective != null &&
CurrentSubObjective != inspectNoiseObjective)
{
inspectNoiseObjective.Abandon = true;
}
foreach (var aiTarget in AITarget.List)
{
if (aiTarget.ShouldBeIgnored()) { continue; }
if (!aiTarget.IsWithinSector(character.WorldPosition)) { continue; }
if (aiTarget.Entity is not Item item) { continue; }
if (!item.HasTag(Tags.ProvocativeToHumanAI)) { continue; }
if (item.GetRootInventoryOwner() is Character targetCharacter &&
AIObjectiveFightIntruders.IsValidTarget(targetCharacter, character, targetCharactersInOtherSubs: false))
{
float range = aiTarget.SoundRange * HumanAIController.Hearing;
float dist = character.CurrentHull.GetApproximateDistance(character.Position, targetCharacter.Position, targetCharacter.CurrentHull, range, distanceMultiplierPerClosedDoor: 2);
if (dist > range) { continue; }
character.Speak(TextManager.Get("dialogheardenemy").Value, identifier: "heardenemy".ToIdentifier(), minDurationBetweenSimilar: 30.0f);
if (inspectNoiseObjective != null && subObjectives.Contains(inspectNoiseObjective))
{
//priority of inspecting noises increases with each noise
//but orders still remain a higher priority
inspectNoiseObjective.Priority = Math.Min(inspectNoiseObjective.Priority + InspectNoisePriorityIncrease, AIObjectiveManager.LowestOrderPriority - 1);
//only refresh the target if the character hasn't yet started inspecting the noise
//(if it has, it should not switch the target, otherwise you could e.g. bounce an NPC back and forth by firing guns at different sides of an outpost)
if (objectiveManager.GetActiveObjective() != inspectNoiseObjective &&
inspectNoiseObjective.Target != targetCharacter.CurrentHull)
{
CreateInspectNoiseObjective(targetCharacter.CurrentHull, priority: inspectNoiseObjective.Priority);
}
}
else
{
CreateInspectNoiseObjective(targetCharacter.CurrentHull, priority: InspectNoisePriority);
}
}
}
void CreateInspectNoiseObjective(ISpatialEntity target, float priority)
{
RemoveSubObjective(ref inspectNoiseObjective);
inspectNoiseObjective = new AIObjectiveGoTo(target, character, objectiveManager)
{
Priority = priority,
SourceObjective = this
};
inspectNoiseObjective.Completed += () => { inspectNoiseObjective = null; inspectNoiseExpirationTimer = 0.0f; };
inspectNoiseObjective.Abandoned += () => { inspectNoiseObjective = null; inspectNoiseExpirationTimer = 0.0f; };
AddSubObjective(inspectNoiseObjective);
}
}
protected override void Act(float deltaTime)
{
}
protected override bool CheckObjectiveState() => false;
}
}