v0.11.0.9
This commit is contained in:
@@ -67,6 +67,12 @@ namespace Barotrauma
|
||||
_abandon = value;
|
||||
if (_abandon)
|
||||
{
|
||||
#if DEBUG
|
||||
if (HumanAIController.debugai && objectiveManager.CurrentOrder == this)
|
||||
{
|
||||
throw new Exception("Order abandoned!");
|
||||
}
|
||||
#endif
|
||||
OnAbandon();
|
||||
}
|
||||
}
|
||||
@@ -96,9 +102,21 @@ namespace Barotrauma
|
||||
return all;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A single shot event. Automatically cleared after launching. Use OnCompleted method for implementing (internal) persistent behavior.
|
||||
/// </summary>
|
||||
public event Action Completed;
|
||||
/// <summary>
|
||||
/// A single shot event. Automatically cleared after launching. Use OnAbandoned method for implementing (internal) persistent behavior.
|
||||
/// </summary>
|
||||
public event Action Abandoned;
|
||||
/// <summary>
|
||||
/// A single shot event. Automatically cleared after launching. Use OnSelected method for implementing (internal) persistent behavior.
|
||||
/// </summary>
|
||||
public event Action Selected;
|
||||
/// <summary>
|
||||
/// A single shot event. Automatically cleared after launching. Use OnDeselected method for implementing (internal) persistent behavior.
|
||||
/// </summary>
|
||||
public event Action Deselected;
|
||||
|
||||
protected HumanAIController HumanAIController => character.AIController as HumanAIController;
|
||||
@@ -318,22 +336,26 @@ namespace Barotrauma
|
||||
{
|
||||
Reset();
|
||||
Selected?.Invoke();
|
||||
Selected = null;
|
||||
}
|
||||
|
||||
public virtual void OnDeselected()
|
||||
{
|
||||
CumulatedDevotion = 0;
|
||||
Deselected?.Invoke();
|
||||
Deselected = null;
|
||||
}
|
||||
|
||||
protected virtual void OnCompleted()
|
||||
{
|
||||
Completed?.Invoke();
|
||||
Completed = null;
|
||||
}
|
||||
|
||||
protected virtual void OnAbandon()
|
||||
{
|
||||
Abandoned?.Invoke();
|
||||
Abandoned = null;
|
||||
}
|
||||
|
||||
public virtual void Reset()
|
||||
@@ -408,7 +430,14 @@ namespace Barotrauma
|
||||
subObjectives.Remove(subObjective);
|
||||
if (AbandonWhenCannotCompleteSubjectives)
|
||||
{
|
||||
Abandon = true;
|
||||
if (objectiveManager.CurrentOrder == this)
|
||||
{
|
||||
Reset();
|
||||
}
|
||||
else
|
||||
{
|
||||
Abandon = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+1
@@ -20,6 +20,7 @@ namespace Barotrauma
|
||||
{
|
||||
if (battery == null) { return false; }
|
||||
var item = battery.Item;
|
||||
if (item.IgnoreByAI) { return false; }
|
||||
if (item.NonInteractable) { return false; }
|
||||
if (item.Submarine == null) { return false; }
|
||||
if (item.CurrentHull == null) { return false; }
|
||||
|
||||
+38
-7
@@ -1,4 +1,5 @@
|
||||
using Barotrauma.Items.Components;
|
||||
using Barotrauma.Extensions;
|
||||
using Barotrauma.Items.Components;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
@@ -25,7 +26,7 @@ namespace Barotrauma
|
||||
{
|
||||
// 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)) { return Objectives.ContainsKey(target) && IsItemInsideValidSubmarine(target, character); }
|
||||
if (!IsValidTarget(target, character, checkInventory: true)) { return Objectives.ContainsKey(target) && IsItemInsideValidSubmarine(target, character); }
|
||||
if (target.CurrentHull.FireSources.Count > 0) { return false; }
|
||||
// Don't repair items in rooms that have enemies inside.
|
||||
if (Character.CharacterList.Any(c => c.CurrentHull == target.CurrentHull && !HumanAIController.IsFriendly(c) && HumanAIController.IsActive(c))) { return false; }
|
||||
@@ -55,15 +56,13 @@ namespace Barotrauma
|
||||
return true;
|
||||
}
|
||||
|
||||
public static bool IsValidTarget(Item item, Character character)
|
||||
public static bool IsValidTarget(Item item, Character character, bool checkInventory)
|
||||
{
|
||||
if (item == null) { return false; }
|
||||
if (item.IgnoreByAI) { return false; }
|
||||
if (item.NonInteractable) { return false; }
|
||||
if (item.ParentInventory != null) { return false; }
|
||||
if (character != null && !IsItemInsideValidSubmarine(item, character)) { return false; }
|
||||
//var rootContainer = item.GetRootContainer();
|
||||
//// Only target items lying on the ground (= not inside a container) (do we need this check?)
|
||||
//if (rootContainer != null) { return false; }
|
||||
var pickable = item.GetComponent<Pickable>();
|
||||
if (pickable == null) { return false; }
|
||||
if (pickable is Holdable h && h.Attachable && h.Attached) { return false; }
|
||||
@@ -80,7 +79,39 @@ namespace Barotrauma
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return item.Prefab.PreferredContainers.Any();
|
||||
if (item.Prefab.PreferredContainers.None())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (!checkInventory)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
bool canEquip = true;
|
||||
if (!item.AllowedSlots.Contains(InvSlotType.Any))
|
||||
{
|
||||
canEquip = false;
|
||||
var inv = character.Inventory;
|
||||
foreach (var allowedSlot in item.AllowedSlots)
|
||||
{
|
||||
foreach (var slotType in inv.SlotTypes)
|
||||
{
|
||||
if (allowedSlot.HasFlag(slotType))
|
||||
{
|
||||
for (int i = 0; i < inv.Capacity; i++)
|
||||
{
|
||||
canEquip = true;
|
||||
if (allowedSlot.HasFlag(inv.SlotTypes[i]) && inv.Items[i] != null)
|
||||
{
|
||||
canEquip = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return canEquip;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -110,7 +110,7 @@ namespace Barotrauma
|
||||
private bool IsOffensiveOrArrest => initialMode == CombatMode.Offensive || initialMode == CombatMode.Arrest;
|
||||
private bool TargetEliminated => Enemy == null || Enemy.Removed || Enemy.IsUnconscious;
|
||||
private bool IsEnemyDisabled => Enemy == null || Enemy.Removed || Enemy.IsDead;
|
||||
private bool EnemyIsClose() => Enemy != null && character.CurrentHull == Enemy.CurrentHull || Vector2.DistanceSquared(character.Position, Enemy.Position) < 500;
|
||||
private bool EnemyIsClose() => Enemy != null && character.CurrentHull != null && character.CurrentHull == Enemy.CurrentHull || Vector2.DistanceSquared(character.Position, Enemy.Position) < 500;
|
||||
|
||||
public AIObjectiveCombat(Character character, Character enemy, CombatMode mode, AIObjectiveManager objectiveManager, float priorityModifier = 1, float coolDown = 10.0f)
|
||||
: base(character, objectiveManager, priorityModifier)
|
||||
|
||||
+22
-16
@@ -21,7 +21,8 @@ namespace Barotrauma
|
||||
//can either be a tag or an identifier
|
||||
public readonly string[] itemIdentifiers;
|
||||
public readonly ItemContainer container;
|
||||
public readonly Item item;
|
||||
private readonly Item item;
|
||||
public Item ItemToContain { get; private set; }
|
||||
|
||||
private AIObjectiveGetItem getItemObjective;
|
||||
private AIObjectiveGoTo goToObjective;
|
||||
@@ -30,7 +31,7 @@ namespace Barotrauma
|
||||
|
||||
public bool AllowToFindDivingGear { get; set; } = true;
|
||||
public bool AllowDangerousPressure { get; set; }
|
||||
public float ConditionLevel { get; set; }
|
||||
public float ConditionLevel { get; set; } = 1;
|
||||
public bool Equip { get; set; }
|
||||
public bool RemoveEmpty { get; set; } = true;
|
||||
|
||||
@@ -59,7 +60,7 @@ namespace Barotrauma
|
||||
protected override bool Check()
|
||||
{
|
||||
if (IsCompleted) { return true; }
|
||||
if (container == null)
|
||||
if (container == null || (container.Item != null && container.Item.IsThisOrAnyContainerIgnoredByAI()))
|
||||
{
|
||||
Abandon = true;
|
||||
return false;
|
||||
@@ -82,19 +83,24 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
private bool CheckItem(Item i) => itemIdentifiers.Any(id => i.Prefab.Identifier == id || i.HasTag(id)) && i.ConditionPercentage > ConditionLevel;
|
||||
private bool CheckItem(Item i) => itemIdentifiers.Any(id => i.Prefab.Identifier == id || i.HasTag(id)) && i.ConditionPercentage >= ConditionLevel;
|
||||
|
||||
protected override void Act(float deltaTime)
|
||||
{
|
||||
if (container == null)
|
||||
if (container == null || (container.Item != null && container.Item.IsThisOrAnyContainerIgnoredByAI()))
|
||||
{
|
||||
Abandon = true;
|
||||
return;
|
||||
}
|
||||
Item itemToContain = item ?? character.Inventory.FindItem(i => CheckItem(i) && i.Container != container.Item, recursive: true);
|
||||
if (itemToContain != null)
|
||||
ItemToContain = item ?? character.Inventory.FindItem(i => CheckItem(i) && i.Container != container.Item, recursive: true);
|
||||
if (ItemToContain != null)
|
||||
{
|
||||
if (character.CanInteractWith(container.Item, out _, checkLinked: false))
|
||||
if (!character.CanInteractWith(ItemToContain, checkLinked: false))
|
||||
{
|
||||
Abandon = true;
|
||||
return;
|
||||
}
|
||||
if (character.CanInteractWith(container.Item, checkLinked: false))
|
||||
{
|
||||
if (RemoveEmpty)
|
||||
{
|
||||
@@ -108,29 +114,29 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
// Contain the item
|
||||
if (itemToContain.ParentInventory == character.Inventory)
|
||||
if (ItemToContain.ParentInventory == character.Inventory)
|
||||
{
|
||||
if (!container.Inventory.CanBePut(itemToContain))
|
||||
if (!container.Inventory.CanBePut(ItemToContain))
|
||||
{
|
||||
Abandon = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
character.Inventory.RemoveItem(itemToContain);
|
||||
if (container.Inventory.TryPutItem(itemToContain, null))
|
||||
character.Inventory.RemoveItem(ItemToContain);
|
||||
if (container.Inventory.TryPutItem(ItemToContain, null))
|
||||
{
|
||||
IsCompleted = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
itemToContain.Drop(character);
|
||||
ItemToContain.Drop(character);
|
||||
Abandon = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (container.Combine(itemToContain, character))
|
||||
if (container.Combine(ItemToContain, character))
|
||||
{
|
||||
IsCompleted = true;
|
||||
}
|
||||
@@ -142,11 +148,11 @@ namespace Barotrauma
|
||||
}
|
||||
else
|
||||
{
|
||||
// TODO: should we just use GetItem?
|
||||
TryAddSubObjective(ref goToObjective, () => new AIObjectiveGoTo(container.Item, character, objectiveManager, getDivingGearIfNeeded: AllowToFindDivingGear)
|
||||
{
|
||||
DialogueIdentifier = "dialogcannotreachtarget",
|
||||
TargetName = container.Item.Name
|
||||
TargetName = container.Item.Name,
|
||||
abortCondition = () => !ItemToContain.IsOwnedBy(character)
|
||||
},
|
||||
onAbandon: () => Abandon = true,
|
||||
onCompleted: () => RemoveSubObjective(ref goToObjective));
|
||||
|
||||
+19
-23
@@ -78,12 +78,21 @@ namespace Barotrauma
|
||||
{
|
||||
TryAddSubObjective(ref getExtinguisherObjective, () =>
|
||||
{
|
||||
character.Speak(TextManager.Get("DialogFindExtinguisher"), null, 2.0f, "findextinguisher", 30.0f);
|
||||
return new AIObjectiveGetItem(character, "fireextinguisher", objectiveManager, equip: true)
|
||||
if (!character.HasEquippedItem("fireextinguisher", allowBroken: false))
|
||||
{
|
||||
character.Speak(TextManager.Get("DialogFindExtinguisher"), null, 2.0f, "findextinguisher", 30.0f);
|
||||
}
|
||||
var getItemObjective = new AIObjectiveGetItem(character, "fireextinguisher", objectiveManager, equip: true)
|
||||
{
|
||||
AllowStealing = true,
|
||||
// If the item is inside an unsafe hull, decrease the priority
|
||||
GetItemPriority = i => HumanAIController.UnsafeHulls.Contains(i.CurrentHull) ? 0.1f : 1
|
||||
};
|
||||
if (objectiveManager.IsCurrentOrder<AIObjectiveExtinguishFires>())
|
||||
{
|
||||
getItemObjective.Abandoned += () => character.Speak(TextManager.Get("dialogcannotfindfireextinguisher"), null, 0.0f, "dialogcannotfindfireextinguisher", 10.0f);
|
||||
};
|
||||
return getItemObjective;
|
||||
});
|
||||
}
|
||||
else
|
||||
@@ -99,9 +108,12 @@ namespace Barotrauma
|
||||
}
|
||||
foreach (FireSource fs in targetHull.FireSources)
|
||||
{
|
||||
bool inRange = fs.IsInDamageRange(character, MathHelper.Clamp(fs.DamageRange * 1.5f, extinguisher.Range * 0.5f, extinguisher.Range));
|
||||
bool move = !inRange || !HumanAIController.VisibleHulls.Contains(fs.Hull);
|
||||
if (inRange || useExtinquisherTimer > 0.0f)
|
||||
float xDist = Math.Abs(character.WorldPosition.X - fs.WorldPosition.X) - fs.DamageRange;
|
||||
float yDist = Math.Abs(character.WorldPosition.Y - fs.WorldPosition.Y);
|
||||
bool inRange = xDist + yDist < extinguisher.Range;
|
||||
bool canSee = HumanAIController.VisibleHulls.Contains(fs.Hull) || character.CanSeeTarget(fs);
|
||||
bool move = !inRange || !canSee;
|
||||
if ((inRange && canSee) || useExtinquisherTimer > 0)
|
||||
{
|
||||
useExtinquisherTimer += deltaTime;
|
||||
if (useExtinquisherTimer > 2.0f)
|
||||
@@ -115,19 +127,7 @@ namespace Barotrauma
|
||||
character.CursorPosition += VectorExtensions.Forward(extinguisherItem.body.TransformedRotation + (float)Math.Sin(sinTime) / 2, dist / 2);
|
||||
if (extinguisherItem.RequireAimToUse)
|
||||
{
|
||||
bool isOperatingButtons = false;
|
||||
if (SteeringManager == PathSteering)
|
||||
{
|
||||
var door = PathSteering.CurrentPath?.CurrentNode?.ConnectedDoor;
|
||||
if (door != null && !door.IsOpen && !door.IsBroken)
|
||||
{
|
||||
isOperatingButtons = door.HasIntegratedButtons || door.Item.GetConnectedComponents<Controller>(true).Any();
|
||||
}
|
||||
}
|
||||
if (!isOperatingButtons)
|
||||
{
|
||||
character.SetInput(InputType.Aim, false, true);
|
||||
}
|
||||
character.SetInput(InputType.Aim, false, true);
|
||||
sinTime += deltaTime * 10;
|
||||
}
|
||||
character.SetInput(extinguisherItem.IsShootable ? InputType.Shoot : InputType.Use, false, true);
|
||||
@@ -136,15 +136,11 @@ namespace Barotrauma
|
||||
{
|
||||
character.Speak(TextManager.GetWithVariable("DialogPutOutFire", "[roomname]", targetHull.DisplayName, true), null, 0, "putoutfire", 10.0f);
|
||||
}
|
||||
if (!character.CanSeeTarget(fs))
|
||||
{
|
||||
move = true;
|
||||
}
|
||||
}
|
||||
if (move)
|
||||
{
|
||||
//go to the first firesource
|
||||
if (TryAddSubObjective(ref gotoObjective, () => new AIObjectiveGoTo(fs, character, objectiveManager, closeEnough: extinguisher.Range / 2)
|
||||
if (TryAddSubObjective(ref gotoObjective, () => new AIObjectiveGoTo(fs, character, objectiveManager, closeEnough: Math.Max(fs.DamageRange, extinguisher.Range * 0.7f))
|
||||
{
|
||||
DialogueIdentifier = "dialogcannotreachfire",
|
||||
TargetName = fs.Hull.DisplayName
|
||||
|
||||
+1
@@ -38,6 +38,7 @@ namespace Barotrauma
|
||||
public static bool IsValidTarget(Hull hull, Character character)
|
||||
{
|
||||
if (hull == null) { return false; }
|
||||
if (hull.IgnoreByAI) { return false; }
|
||||
if (hull.FireSources.None()) { return false; }
|
||||
if (hull.Submarine == null) { return false; }
|
||||
if (character.Submarine == null) { return false; }
|
||||
|
||||
+2
-2
@@ -46,6 +46,7 @@ namespace Barotrauma
|
||||
}
|
||||
return new AIObjectiveGetItem(character, gearTag, objectiveManager, equip: true)
|
||||
{
|
||||
AllowStealing = true,
|
||||
AllowToFindDivingGear = false,
|
||||
AllowDangerousPressure = true
|
||||
};
|
||||
@@ -85,8 +86,7 @@ namespace Barotrauma
|
||||
return new AIObjectiveContainItem(character, OXYGEN_SOURCE, targetItem.GetComponent<ItemContainer>(), objectiveManager, spawnItemIfNotFound: character.TeamID == Character.TeamType.FriendlyNPC)
|
||||
{
|
||||
AllowToFindDivingGear = false,
|
||||
AllowDangerousPressure = true,
|
||||
ConditionLevel = 0
|
||||
AllowDangerousPressure = true
|
||||
};
|
||||
},
|
||||
onAbandon: () => Abandon = true,
|
||||
|
||||
+1
-1
@@ -46,7 +46,7 @@ namespace Barotrauma
|
||||
}
|
||||
if (character.CurrentHull == null)
|
||||
{
|
||||
Priority = objectiveManager.CurrentOrder is AIObjectiveGoTo && HumanAIController.HasDivingSuit(character) ? 0 : 100;
|
||||
Priority = (objectiveManager.IsCurrentOrder<AIObjectiveGoTo>() || objectiveManager.Objectives.Any(o => o is AIObjectiveCombat)) && HumanAIController.HasDivingSuit(character) ? 0 : 100;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
+8
-1
@@ -65,7 +65,14 @@ namespace Barotrauma
|
||||
if (weldingTool == null)
|
||||
{
|
||||
TryAddSubObjective(ref getWeldingTool, () => new AIObjectiveGetItem(character, "weldingequipment", objectiveManager, equip: true, spawnItemIfNotFound: character.TeamID == Character.TeamType.FriendlyNPC),
|
||||
onAbandon: () => Abandon = true,
|
||||
onAbandon: () =>
|
||||
{
|
||||
if (objectiveManager.IsCurrentOrder<AIObjectiveFixLeaks>())
|
||||
{
|
||||
character.Speak(TextManager.Get("dialogcannotfindweldingequipment"), null, 0.0f, "dialogcannotfindweldingequipment", 10.0f);
|
||||
}
|
||||
Abandon = true;
|
||||
},
|
||||
onCompleted: () => RemoveSubObjective(ref getWeldingTool));
|
||||
return;
|
||||
}
|
||||
|
||||
+2
@@ -71,6 +71,8 @@ namespace Barotrauma
|
||||
public static bool IsValidTarget(Gap gap, Character character)
|
||||
{
|
||||
if (gap == null) { return false; }
|
||||
// Don't fix a leak on a wall section set to be ignored
|
||||
if (gap.ConnectedWall?.Sections?.Any(s => s.gap == gap && s.IgnoreByAI) ?? false) { return false; }
|
||||
if (gap.ConnectedWall == null || gap.ConnectedDoor != null || gap.Open <= 0 || gap.linkedTo.All(l => l == null)) { return false; }
|
||||
if (gap.Submarine == null || character.Submarine == null) { return false; }
|
||||
// Don't allow going into another sub, unless it's connected and of the same team and type.
|
||||
|
||||
+14
-13
@@ -18,13 +18,13 @@ namespace Barotrauma
|
||||
public float TargetCondition { get; set; } = 1;
|
||||
public bool AllowDangerousPressure { get; set; }
|
||||
|
||||
private string[] identifiersOrTags;
|
||||
private readonly string[] identifiersOrTags;
|
||||
|
||||
//if the item can't be found, spawn it in the character's inventory (used by outpost NPCs)
|
||||
private bool spawnItemIfNotFound = false;
|
||||
|
||||
private Item targetItem;
|
||||
private Item originalTarget;
|
||||
private readonly Item originalTarget;
|
||||
private ISpatialEntity moveToTarget;
|
||||
private bool isDoneSeeking;
|
||||
public Item TargetItem => targetItem;
|
||||
@@ -32,13 +32,18 @@ namespace Barotrauma
|
||||
public string[] ignoredContainerIdentifiers;
|
||||
private AIObjectiveGoTo goToObjective;
|
||||
private float currItemPriority;
|
||||
private bool checkInventory;
|
||||
private readonly bool checkInventory;
|
||||
|
||||
public static float DefaultReach = 100;
|
||||
|
||||
public bool AllowToFindDivingGear { get; set; } = true;
|
||||
public bool MustBeSpecificItem { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Is the character allowed to take the item from somewhere else than their own sub (e.g. an outpost)
|
||||
/// </summary>
|
||||
public bool AllowStealing { get; set; }
|
||||
|
||||
public AIObjectiveGetItem(Character character, Item targetItem, AIObjectiveManager objectiveManager, bool equip = true, float priorityModifier = 1)
|
||||
: base(character, objectiveManager, priorityModifier)
|
||||
{
|
||||
@@ -246,9 +251,13 @@ namespace Barotrauma
|
||||
currSearchIndex++;
|
||||
var item = Item.ItemList[currSearchIndex];
|
||||
Submarine itemSub = item.Submarine ?? item.ParentInventory?.Owner?.Submarine;
|
||||
Submarine mySub = character.Submarine;
|
||||
if (itemSub == null) { continue; }
|
||||
Submarine mySub = character.Submarine;
|
||||
if (mySub == null) { continue; }
|
||||
if (!AllowStealing)
|
||||
{
|
||||
if (character.TeamID == Character.TeamType.FriendlyNPC != item.SpawnedInOutpost) { continue; }
|
||||
}
|
||||
if (!CheckItem(item)) { continue; }
|
||||
if (ignoredContainerIdentifiers != null && item.Container != null)
|
||||
{
|
||||
@@ -339,6 +348,7 @@ namespace Barotrauma
|
||||
private bool CheckItem(Item item)
|
||||
{
|
||||
if (item.NonInteractable) { return false; }
|
||||
if (item.IsThisOrAnyContainerIgnoredByAI()) { return false; }
|
||||
if (ignoredItems.Contains(item)) { return false; };
|
||||
if (item.Condition < TargetCondition) { return false; }
|
||||
if (ItemFilter != null && !ItemFilter(item)) { return false; }
|
||||
@@ -362,14 +372,5 @@ namespace Barotrauma
|
||||
isDoneSeeking = false;
|
||||
currSearchIndex = 0;
|
||||
}
|
||||
|
||||
protected override void OnAbandon()
|
||||
{
|
||||
base.OnAbandon();
|
||||
if (objectiveManager.CurrentOrder != null)
|
||||
{
|
||||
character.Speak(TextManager.Get("DialogCannotFindItem"), null, 0.0f, "cannotfinditem", 10.0f);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+15
-1
@@ -30,6 +30,8 @@ namespace Barotrauma
|
||||
public bool followControlledCharacter;
|
||||
public bool mimic;
|
||||
|
||||
public float extraDistanceWhileSwimming;
|
||||
public float extraDistanceOutsideSub;
|
||||
private float _closeEnough = 50;
|
||||
private readonly float minDistance = 50;
|
||||
/// <summary>
|
||||
@@ -37,7 +39,19 @@ namespace Barotrauma
|
||||
/// </summary>
|
||||
public float CloseEnough
|
||||
{
|
||||
get { return _closeEnough; }
|
||||
get
|
||||
{
|
||||
float dist = _closeEnough;
|
||||
if (character.AnimController.InWater)
|
||||
{
|
||||
dist += extraDistanceWhileSwimming;
|
||||
}
|
||||
if (character.CurrentHull == null)
|
||||
{
|
||||
dist += extraDistanceOutsideSub;
|
||||
}
|
||||
return dist;
|
||||
}
|
||||
set
|
||||
{
|
||||
_closeEnough = Math.Max(minDistance, value);
|
||||
|
||||
+26
-13
@@ -21,14 +21,13 @@ namespace Barotrauma
|
||||
set
|
||||
{
|
||||
behavior = value;
|
||||
if (behavior == BehaviorType.StayInHull && character.TeamID != Character.TeamType.FriendlyNPC)
|
||||
{
|
||||
DebugConsole.NewMessage($"AIObjectiveIdle.BehaviorType.StayInHull is implemented only for outpost NPCs. Using passive behavior for {character.Name} ({character.Info.Job.Prefab.Identifier})", color: Color.Red);
|
||||
behavior = BehaviorType.Passive;
|
||||
}
|
||||
switch (behavior)
|
||||
{
|
||||
case BehaviorType.Active:
|
||||
newTargetIntervalMin = 10;
|
||||
newTargetIntervalMax = 20;
|
||||
standStillMin = 2;
|
||||
standStillMax = 10;
|
||||
break;
|
||||
case BehaviorType.Passive:
|
||||
case BehaviorType.StayInHull:
|
||||
newTargetIntervalMin = 60;
|
||||
@@ -36,6 +35,18 @@ namespace Barotrauma
|
||||
standStillMin = 30;
|
||||
standStillMax = 60;
|
||||
break;
|
||||
case BehaviorType.Active:
|
||||
newTargetIntervalMin = 40;
|
||||
newTargetIntervalMax = 60;
|
||||
standStillMin = 20;
|
||||
standStillMax = 40;
|
||||
break;
|
||||
case BehaviorType.Patrol:
|
||||
newTargetIntervalMin = 15;
|
||||
newTargetIntervalMax = 30;
|
||||
standStillMin = 5;
|
||||
standStillMax = 10;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -49,9 +60,10 @@ namespace Barotrauma
|
||||
|
||||
public enum BehaviorType
|
||||
{
|
||||
Active,
|
||||
Patrol,
|
||||
Passive,
|
||||
StayInHull
|
||||
StayInHull,
|
||||
Active
|
||||
}
|
||||
public Hull TargetHull { get; set; }
|
||||
private Hull currentTarget;
|
||||
@@ -307,14 +319,14 @@ namespace Barotrauma
|
||||
public void Wander(float deltaTime)
|
||||
{
|
||||
if (character.IsClimbing) { return; }
|
||||
if (!character.AnimController.InWater)
|
||||
var currentHull = character.CurrentHull;
|
||||
if (!character.AnimController.InWater && currentHull != null)
|
||||
{
|
||||
standStillTimer -= deltaTime;
|
||||
if (standStillTimer > 0.0f)
|
||||
{
|
||||
walkDuration = Rand.Range(walkDurationMin, walkDurationMax);
|
||||
var currentHull = character.CurrentHull;
|
||||
if (currentHull != null && currentHull.Rect.Width > IndoorsSteeringManager.smallRoomSize / 2 && tooCloseCharacter == null)
|
||||
if (currentHull.Rect.Width > IndoorsSteeringManager.smallRoomSize / 2 && tooCloseCharacter == null)
|
||||
{
|
||||
foreach (Character c in Character.CharacterList)
|
||||
{
|
||||
@@ -434,10 +446,11 @@ namespace Barotrauma
|
||||
targetHulls.Add(hull);
|
||||
float weight = hull.RectWidth;
|
||||
// Prefer rooms that are closer. Avoid rooms that are not in the same level.
|
||||
// If the behavior is active, prefer rooms that are not close.
|
||||
float yDist = Math.Abs(character.WorldPosition.Y - hull.WorldPosition.Y);
|
||||
yDist = yDist > 100 ? yDist * 5 : 0;
|
||||
float dist = Math.Abs(character.WorldPosition.X - hull.WorldPosition.X) + yDist;
|
||||
float distanceFactor = MathHelper.Lerp(1, 0, MathUtils.InverseLerp(0, 2500, dist));
|
||||
float distanceFactor = behavior == BehaviorType.Patrol ? MathHelper.Lerp(1, 0, MathUtils.InverseLerp(2500, 0, dist)) : MathHelper.Lerp(1, 0, MathUtils.InverseLerp(0, 2500, dist));
|
||||
float waterFactor = MathHelper.Lerp(1, 0, MathUtils.InverseLerp(0, 100, hull.WaterPercentage * 2));
|
||||
weight *= distanceFactor * waterFactor;
|
||||
hullWeights.Add(weight);
|
||||
@@ -474,7 +487,7 @@ namespace Barotrauma
|
||||
foreach (Item item in Item.ItemList)
|
||||
{
|
||||
if (item.CurrentHull != hull) { continue; }
|
||||
if (AIObjectiveCleanupItems.IsValidTarget(item, character) && !ignoredItems.Contains(item))
|
||||
if (AIObjectiveCleanupItems.IsValidTarget(item, character, checkInventory: true) && !ignoredItems.Contains(item))
|
||||
{
|
||||
itemsToClean.Add(item);
|
||||
}
|
||||
|
||||
+6
-1
@@ -245,7 +245,10 @@ namespace Barotrauma
|
||||
public void SortObjectives()
|
||||
{
|
||||
CurrentOrder?.GetPriority();
|
||||
Objectives.ForEach(o => o.GetPriority());
|
||||
for (int i = Objectives.Count - 1; i >= 0; i--)
|
||||
{
|
||||
Objectives[i].GetPriority();
|
||||
}
|
||||
if (Objectives.Any())
|
||||
{
|
||||
Objectives.Sort((x, y) => y.Priority.CompareTo(x.Priority));
|
||||
@@ -305,6 +308,8 @@ namespace Barotrauma
|
||||
newObjective = new AIObjectiveGoTo(orderGiver, character, this, repeat: true, priorityModifier: priorityModifier)
|
||||
{
|
||||
CloseEnough = Rand.Range(90, 100) + Rand.Range(50, 70) * Math.Min(HumanAIController.CountCrew(c => c.ObjectiveManager.CurrentOrder is AIObjectiveGoTo gotoOrder && gotoOrder.Target == orderGiver, onlyBots: true), 4),
|
||||
extraDistanceOutsideSub = 100,
|
||||
extraDistanceWhileSwimming = 100,
|
||||
AllowGoingOutside = true,
|
||||
IgnoreIfTargetDead = true,
|
||||
followControlledCharacter = orderGiver == character,
|
||||
|
||||
+13
-4
@@ -157,11 +157,20 @@ namespace Barotrauma
|
||||
Abandon = true;
|
||||
return;
|
||||
}
|
||||
// Don't allow to operate an item that someone with a better skills already operates, unless this is an order
|
||||
if (objectiveManager.CurrentOrder != this && HumanAIController.IsItemOperatedByAnother(target, out _))
|
||||
// If this is not an order...
|
||||
if (objectiveManager.CurrentOrder != this)
|
||||
{
|
||||
// Don't abandon
|
||||
return;
|
||||
// Don't allow to operate an item that someone with a better skills already operates
|
||||
if (HumanAIController.IsItemOperatedByAnother(target, out _))
|
||||
{
|
||||
// Don't abandon
|
||||
return;
|
||||
}
|
||||
if (component.Item.IgnoreByAI || (useController && controller.Item.IgnoreByAI))
|
||||
{
|
||||
Abandon = true;
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (operateTarget != null)
|
||||
{
|
||||
|
||||
+1
@@ -27,6 +27,7 @@ namespace Barotrauma
|
||||
protected override bool Filter(Pump pump)
|
||||
{
|
||||
if (pump == null) { return false; }
|
||||
if (pump.Item.IgnoreByAI) { return false; }
|
||||
if (pump.Item.NonInteractable) { return false; }
|
||||
if (pump.Item.HasTag("ballast")) { return false; }
|
||||
if (pump.Item.Submarine == null) { return false; }
|
||||
|
||||
+6
-1
@@ -90,7 +90,12 @@ namespace Barotrauma
|
||||
{
|
||||
foreach (RelatedItem requiredItem in kvp.Value)
|
||||
{
|
||||
subObjectives.Add(new AIObjectiveGetItem(character, requiredItem.Identifiers, objectiveManager, true));
|
||||
var getItemObjective = new AIObjectiveGetItem(character, requiredItem.Identifiers, objectiveManager, true);
|
||||
if (objectiveManager.IsCurrentOrder<AIObjectiveRepairItems>())
|
||||
{
|
||||
getItemObjective.Abandoned += () => character.Speak(TextManager.Get("dialogcannotfindrequireditemtorepair"), null, 0.0f, "dialogcannotfindrequireditemtorepair", 10.0f);
|
||||
}
|
||||
subObjectives.Add(getItemObjective);
|
||||
}
|
||||
}
|
||||
return;
|
||||
|
||||
+1
@@ -148,6 +148,7 @@ namespace Barotrauma
|
||||
public static bool IsValidTarget(Item item, Character character)
|
||||
{
|
||||
if (item == null) { return false; }
|
||||
if (item.IgnoreByAI) { return false; }
|
||||
if (item.NonInteractable) { return false; }
|
||||
if (item.IsFullCondition) { return false; }
|
||||
if (item.CurrentHull == null) { return false; }
|
||||
|
||||
Reference in New Issue
Block a user