OBT/1.2.0(Spring Update)
Sync with Upstream
This commit is contained in:
@@ -103,9 +103,19 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
// For temporarily forcing walking. Will reset after each priority calculation, so it will need to be kept alive by something.
|
||||
// The intention of this boolean to allow walking even when the priority is higher than AIObjectiveManager.RunPriority.
|
||||
public bool ForceWalk { get; set; }
|
||||
/// <summary>
|
||||
/// For temporarily forcing walking. Will reset after each priority calculation, so it will need to be kept alive by something.
|
||||
/// The intention of this boolean to allow walking even when the priority is higher than AIObjectiveManager.RunPriority.
|
||||
/// </summary>
|
||||
public bool ForceWalkTemporarily { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Forces the character to walk when executing this objective, even if the priority is above <see cref="AIObjectiveManager.RunPriority"/>.
|
||||
/// Unlike <see cref="ForceWalkTemporarily"/>, this value is not automatically reset.
|
||||
/// </summary>
|
||||
public bool ForceWalkPermanently { get; set; }
|
||||
|
||||
public bool ForceWalk => ForceWalkTemporarily || ForceWalkPermanently;
|
||||
|
||||
public bool IgnoreAtOutpost { get; set; }
|
||||
|
||||
@@ -313,7 +323,7 @@ namespace Barotrauma
|
||||
/// </summary>
|
||||
public float CalculatePriority()
|
||||
{
|
||||
ForceWalk = false;
|
||||
ForceWalkTemporarily = false;
|
||||
Priority = GetPriority();
|
||||
ForceHighestPriority = false;
|
||||
return Priority;
|
||||
|
||||
+1
-1
@@ -40,7 +40,7 @@ namespace Barotrauma
|
||||
if (subObjectives.All(so => so.SubObjectives.None()))
|
||||
{
|
||||
// If none of the subobjectives have subobjectives, no valid container was found. Don't allow running.
|
||||
ForceWalk = true;
|
||||
ForceWalkTemporarily = true;
|
||||
}
|
||||
return prio;
|
||||
}
|
||||
|
||||
+10
-8
@@ -258,13 +258,14 @@ namespace Barotrauma
|
||||
|
||||
protected override bool CheckObjectiveState()
|
||||
{
|
||||
if (character.Submarine is { TeamID: CharacterTeamType.FriendlyNPC } && character.Submarine == Enemy.Submarine)
|
||||
// In a friendly outpost, and the target is still in the outpost
|
||||
if (character.Submarine is { Info.IsOutpost: true } && character.IsOnFriendlyTeam(character.Submarine.TeamID) &&
|
||||
character.Submarine == Enemy.Submarine)
|
||||
{
|
||||
// Target still in the outpost
|
||||
// Outpost guards shouldn't lose the target in friendly outposts,
|
||||
// However, if we are not a guard, let's ensure that we allow the cooldown.
|
||||
if (character.TeamID == CharacterTeamType.FriendlyNPC && !character.IsSecurity)
|
||||
{
|
||||
// Outpost guards shouldn't lose the target in friendly outposts,
|
||||
// However, if we are not a guard, let's ensure that we allow the cooldown.
|
||||
allowCooldown = true;
|
||||
}
|
||||
}
|
||||
@@ -286,7 +287,8 @@ namespace Barotrauma
|
||||
{
|
||||
allowCooldown = true;
|
||||
// Target not in the outpost anymore.
|
||||
if (character.CanSeeTarget(Enemy))
|
||||
if (character.Submarine.IsConnectedTo(Enemy.Submarine) &&
|
||||
character.CanSeeTarget(Enemy))
|
||||
{
|
||||
allowCooldown = false;
|
||||
coolDownTimer = DefaultCoolDown;
|
||||
@@ -389,7 +391,7 @@ namespace Barotrauma
|
||||
HumanAIController.AutoFaceMovement = false;
|
||||
if (!gotoObjective.ShouldRun(true))
|
||||
{
|
||||
ForceWalk = true;
|
||||
ForceWalkTemporarily = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -468,7 +470,7 @@ namespace Barotrauma
|
||||
isMoving = true;
|
||||
if (!IsEnemyClose(MeleeDistance))
|
||||
{
|
||||
ForceWalk = true;
|
||||
ForceWalkTemporarily = true;
|
||||
}
|
||||
HumanAIController.FaceTarget(Enemy);
|
||||
HumanAIController.AutoFaceMovement = false;
|
||||
@@ -1234,7 +1236,7 @@ namespace Barotrauma
|
||||
}
|
||||
if (isAimBlocked)
|
||||
{
|
||||
ForceWalk = true;
|
||||
ForceWalkTemporarily = true;
|
||||
}
|
||||
if (!followTargetObjective.IsCloseEnough)
|
||||
{
|
||||
|
||||
+5
-1
@@ -95,7 +95,11 @@ namespace Barotrauma
|
||||
if (potentialDeconstructor?.InputContainer == null) { continue; }
|
||||
if (!potentialDeconstructor.InputContainer.Inventory.CanBePut(Item)) { continue; }
|
||||
if (!potentialDeconstructor.Item.HasAccess(character)) { continue; }
|
||||
if (Item.Prefab.DeconstructItems.None(it => it.IsValidDeconstructor(otherItem))) { continue; }
|
||||
if (Item.Prefab.DeconstructItems.Any() &&
|
||||
Item.Prefab.DeconstructItems.None(it => it.IsValidDeconstructor(otherItem)))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
float distFactor = GetDistanceFactor(Item.WorldPosition, potentialDeconstructor.Item.WorldPosition, factorAtMaxDistance: 0.2f);
|
||||
if (distFactor > bestDistFactor)
|
||||
{
|
||||
|
||||
+5
-1
@@ -64,7 +64,11 @@ namespace Barotrauma
|
||||
if (target == null || target.Removed) { return false; }
|
||||
//bots can't handle deconstructing items that require another item to deconstruct, let's not try to do that
|
||||
//in the vanilla game, this means unidentified genetic materials, which we don't want to "deconstruct" anyway
|
||||
if (target.Prefab.DeconstructItems.All(d => d.RequiredOtherItem.Length > 0)) { return false; }
|
||||
if (target.Prefab.DeconstructItems.Any() &&
|
||||
target.Prefab.DeconstructItems.All(d => d.RequiredOtherItem.Length > 0))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
// If the target was selected as a valid target, we'll have to accept it so that the objective can be completed.
|
||||
// The validity changes when a character picks the item up.
|
||||
if (!IsValidTarget(target, character, checkInventory: true))
|
||||
|
||||
+1
-1
@@ -148,7 +148,7 @@ namespace Barotrauma
|
||||
character.Speak(TextManager.GetWithVariable("DialogPutOutFire", "[roomname]", targetHull.DisplayName, FormatCapitals.Yes).Value, null, 0, "putoutfire".ToIdentifier(), 10.0f);
|
||||
}
|
||||
// Prevents running into the flames.
|
||||
objectiveManager.CurrentObjective.ForceWalk = true;
|
||||
objectiveManager.CurrentObjective.ForceWalkTemporarily = true;
|
||||
}
|
||||
if (moveCloser)
|
||||
{
|
||||
|
||||
+2
@@ -11,6 +11,8 @@ namespace Barotrauma
|
||||
public override Identifier Identifier { get; set; } = "extinguish fires".ToIdentifier();
|
||||
public override bool ForceRun => true;
|
||||
protected override bool AllowInAnySub => true;
|
||||
// Periodically clear the ignore list so that fires abandoned when fumbling with finding an extinguisher, navigating etc get reconsidered
|
||||
protected override float IgnoreListClearInterval => 30;
|
||||
|
||||
public AIObjectiveExtinguishFires(Character character, AIObjectiveManager objectiveManager, float priorityModifier = 1) : base(character, objectiveManager, priorityModifier) { }
|
||||
|
||||
|
||||
+22
-7
@@ -49,6 +49,13 @@ namespace Barotrauma
|
||||
public const float DefaultReach = 100;
|
||||
public const float MaxReach = 150;
|
||||
|
||||
/// <summary>
|
||||
/// How long it takes for the objective to be abandoned if no suitable item is found.
|
||||
/// Intended to be an optimization: if the bots are constantly trying to find some item (like a diving suit),
|
||||
/// it can easily lead to performance issues when e.g. AIObjectiveFindDivingGear constantly starts up new GetItem objectives.
|
||||
/// </summary>
|
||||
private float abandonDelayIfItemNotFound = 5.0f;
|
||||
|
||||
/// <summary>
|
||||
/// Is the goal of this objective to get diving gear (i.e. has it been created by <see cref="AIObjectiveFindDivingGear"/>)?
|
||||
/// If so, the objective won't attempt to create another objective if the path requires diving gear
|
||||
@@ -213,7 +220,7 @@ namespace Barotrauma
|
||||
{
|
||||
if (isDoneSeeking)
|
||||
{
|
||||
HandlePotentialItems();
|
||||
HandlePotentialItems(deltaTime);
|
||||
}
|
||||
if (objectiveManager.CurrentOrder is not AIObjectiveGoTo)
|
||||
{
|
||||
@@ -389,6 +396,8 @@ namespace Barotrauma
|
||||
// If the root container changes, the item is no longer where it was (taken by someone -> need to find another item)
|
||||
AbortCondition = obj => targetItem == null || (targetItem.GetRootInventoryOwner() is Entity owner && owner != moveToTarget && owner != character),
|
||||
SpeakIfFails = false,
|
||||
ForceWalkTemporarily = this.ForceWalkTemporarily,
|
||||
ForceWalkPermanently = this.ForceWalkPermanently,
|
||||
endNodeFilter = CreateEndNodeFilter(moveToTarget)
|
||||
};
|
||||
},
|
||||
@@ -598,7 +607,7 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
private void HandlePotentialItems()
|
||||
private void HandlePotentialItems(float deltaTime)
|
||||
{
|
||||
Debug.Assert(isDoneSeeking);
|
||||
if (itemCandidates.Any())
|
||||
@@ -652,10 +661,14 @@ namespace Barotrauma
|
||||
}
|
||||
else
|
||||
{
|
||||
#if DEBUG
|
||||
DebugConsole.NewMessage($"{character.Name}: Cannot find an item with the following identifier(s) or tag(s): {string.Join(", ", IdentifiersOrTags)}", Color.Yellow);
|
||||
#endif
|
||||
Abandon = true;
|
||||
abandonDelayIfItemNotFound -= deltaTime;
|
||||
if (abandonDelayIfItemNotFound <= 0.0f)
|
||||
{
|
||||
#if DEBUG
|
||||
DebugConsole.NewMessage($"{character.Name}: Cannot find an item with the following identifier(s) or tag(s): {string.Join(", ", IdentifiersOrTags)}", Color.Yellow);
|
||||
#endif
|
||||
Abandon = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -718,13 +731,15 @@ namespace Barotrauma
|
||||
|
||||
private bool CheckItem(Item item)
|
||||
{
|
||||
bool matchesIdentifiersOrTags = item.HasIdentifierOrTags(IdentifiersOrTags) || (AllowVariants && !item.Prefab.VariantOf.IsEmpty && IdentifiersOrTags.Contains(item.Prefab.VariantOf));
|
||||
if (!matchesIdentifiersOrTags) { return false; }
|
||||
if (!item.HasAccess(character)) { return false; }
|
||||
if (ignoredItems.Contains(item)) { return false; };
|
||||
if (ignoredIdentifiersOrTags != null && item.HasIdentifierOrTags(ignoredIdentifiersOrTags)) { return false; }
|
||||
if (item.Condition < TargetCondition) { return false; }
|
||||
if (ItemFilter != null && !ItemFilter(item)) { return false; }
|
||||
if (RequireNonEmpty && item.Components.Any(i => i.IsEmpty(character))) { return false; }
|
||||
return item.HasIdentifierOrTags(IdentifiersOrTags) || (AllowVariants && !item.Prefab.VariantOf.IsEmpty && IdentifiersOrTags.Contains(item.Prefab.VariantOf));
|
||||
return true;
|
||||
}
|
||||
|
||||
public override void Reset()
|
||||
|
||||
@@ -958,6 +958,7 @@ namespace Barotrauma
|
||||
|
||||
public bool ShouldRun(bool run)
|
||||
{
|
||||
if (ForceWalk) { return false; }
|
||||
if (run && objectiveManager.ForcedOrder == this && IsWaitOrder && !character.IsOnPlayerTeam)
|
||||
{
|
||||
// NPCs with a wait order don't run.
|
||||
|
||||
+4
-1
@@ -267,7 +267,10 @@ namespace Barotrauma
|
||||
if (node.Waypoint.CurrentHull != character.CurrentHull && HumanAIController.UnsafeHulls.Contains(node.Waypoint.CurrentHull)) { return false; }
|
||||
return true;
|
||||
//don't stop at ladders when idling
|
||||
}, endNodeFilter: node => node.Waypoint.Stairs == null && node.Waypoint.Ladders == null && (!isCurrentHullAllowed || !IsForbidden(node.Waypoint.CurrentHull)));
|
||||
}, endNodeFilter: node =>
|
||||
node.Waypoint.Stairs == null && node.Waypoint.CurrentHull == currentTarget && node.Waypoint.Ladders == null &&
|
||||
(!isCurrentHullAllowed || !IsForbidden(node.Waypoint.CurrentHull)));
|
||||
|
||||
if (path.Unreachable)
|
||||
{
|
||||
//can't go to this room, remove it from the list and try another room
|
||||
|
||||
+4
-3
@@ -78,9 +78,10 @@ namespace Barotrauma
|
||||
if (item.GetRootInventoryOwner() is Character targetCharacter &&
|
||||
AIObjectiveFightIntruders.IsValidTarget(targetCharacter, character, targetCharactersInOtherSubs: false))
|
||||
{
|
||||
float dist = character.CurrentHull.GetApproximateDistance(character.Position, targetCharacter.Position, targetCharacter.CurrentHull, aiTarget.SoundRange, distanceMultiplierPerClosedDoor: 2);
|
||||
if (dist * HumanAIController.Hearing > aiTarget.SoundRange) { continue; }
|
||||
|
||||
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))
|
||||
{
|
||||
|
||||
+1
-1
@@ -112,7 +112,7 @@ namespace Barotrauma
|
||||
float prio = objectiveManager.GetOrderPriority(this);
|
||||
if (subObjectives.All(so => so.SubObjectives.None() || so.Priority <= 0))
|
||||
{
|
||||
ForceWalk = true;
|
||||
ForceWalkTemporarily = true;
|
||||
}
|
||||
return prio;
|
||||
}
|
||||
|
||||
-4
@@ -103,10 +103,6 @@ namespace Barotrauma
|
||||
|
||||
public void AddObjective<T>(T objective) where T : AIObjective
|
||||
{
|
||||
var result = GameMain.LuaCs.Hook.Call<bool?>("AI.addObjective", this, objective);
|
||||
|
||||
if (result != null && result.Value) return;
|
||||
|
||||
if (objective == null)
|
||||
{
|
||||
#if DEBUG
|
||||
|
||||
+1
@@ -257,6 +257,7 @@ namespace Barotrauma
|
||||
{
|
||||
DialogueIdentifier = AIObjectiveGoTo.DialogCannotReachTarget,
|
||||
TargetName = target.Item.Name,
|
||||
ForceWalkPermanently = ForceWalk,
|
||||
endNodeFilter = EndNodeFilter ?? AIObjectiveGetItem.CreateEndNodeFilter(target.Item)
|
||||
},
|
||||
onAbandon: () => Abandon = true,
|
||||
|
||||
+1
-1
@@ -29,7 +29,7 @@ namespace Barotrauma
|
||||
{
|
||||
if (pump?.Item == null || pump.Item.Removed) { return false; }
|
||||
if (pump.Item.IgnoreByAI(character)) { return false; }
|
||||
if (!pump.Item.IsInteractable(character)) { return false; }
|
||||
if (!pump.Item.IsInteractable(character) || !pump.CanBeSelected) { return false; }
|
||||
if (pump.IsAutoControlled) { return false; }
|
||||
if (pump.Item.ConditionPercentage <= 0) { return false; }
|
||||
if (pump.Item.CurrentHull == null) { return false; }
|
||||
|
||||
+1
-1
@@ -136,7 +136,7 @@ namespace Barotrauma
|
||||
public static bool IsValidTarget(Character target, Character character, out bool ignoredAsMinorWounds)
|
||||
{
|
||||
ignoredAsMinorWounds = false;
|
||||
if (target == null || target.IsDead || target.Removed) { return false; }
|
||||
if (target == null || target.IsDead || target.Removed || target.InvisibleTimer > 0.0f) { return false; }
|
||||
if (target.IsInstigator) { return false; }
|
||||
if (target.IsPet) { return false; }
|
||||
if (!HumanAIController.IsFriendly(character, target, onlySameTeam: true)) { return false; }
|
||||
|
||||
Reference in New Issue
Block a user