Unstable 1.2.4.0
This commit is contained in:
@@ -91,6 +91,11 @@ namespace Barotrauma
|
||||
private IEnumerable<Hull> visibleHulls;
|
||||
private float hullVisibilityTimer;
|
||||
const float hullVisibilityInterval = 0.5f;
|
||||
|
||||
/// <summary>
|
||||
/// Returns hulls that are visible to the character, including the current hull.
|
||||
/// Note that this is not an accurate visibility check, it only checks for open gaps between the adjacent and linked hulls.
|
||||
/// </summary>
|
||||
public IEnumerable<Hull> VisibleHulls
|
||||
{
|
||||
get
|
||||
@@ -353,7 +358,7 @@ namespace Barotrauma
|
||||
public static void UnequipContainedItems(Character character, Item parentItem, Func<Item, bool> predicate, bool avoidDroppingInSea = true, int? unequipMax = null)
|
||||
{
|
||||
var inventory = parentItem.OwnInventory;
|
||||
if (inventory == null) { return; }
|
||||
if (inventory == null || !inventory.Container.DrawInventory) { return; }
|
||||
int removed = 0;
|
||||
if (predicate == null || inventory.AllItems.Any(predicate))
|
||||
{
|
||||
|
||||
@@ -262,7 +262,7 @@ namespace Barotrauma
|
||||
|
||||
if (aiElements.Count == 0)
|
||||
{
|
||||
DebugConsole.ThrowError("Error in file \"" + c.Params.File + "\" - no AI element found.",
|
||||
DebugConsole.ThrowError("Error in file \"" + c.Params.File.Path + "\" - no AI element found.",
|
||||
contentPackage: c.Prefab?.ContentPackage);
|
||||
outsideSteering = new SteeringManager(this);
|
||||
insideSteering = new IndoorsSteeringManager(this, false, false);
|
||||
@@ -312,7 +312,7 @@ namespace Barotrauma
|
||||
}
|
||||
ReevaluateAttacks();
|
||||
outsideSteering = new SteeringManager(this);
|
||||
insideSteering = new IndoorsSteeringManager(this, Character.Params.AI.CanOpenDoors, canAttackDoors);
|
||||
insideSteering = new IndoorsSteeringManager(this, AIParams.CanOpenDoors, canAttackDoors);
|
||||
steeringManager = outsideSteering;
|
||||
State = AIState.Idle;
|
||||
requiredHoleCount = (int)Math.Ceiling(ConvertUnits.ToDisplayUnits(colliderWidth) / Structure.WallSectionSize);
|
||||
@@ -322,6 +322,10 @@ namespace Barotrauma
|
||||
}
|
||||
|
||||
private CharacterParams.AIParams _aiParams;
|
||||
/// <summary>
|
||||
/// Shorthand for <see cref="Character.Params.AI"/> with null checking.
|
||||
/// </summary>
|
||||
/// <returns><see cref="Character.Params.AI"/> or an empty params. Does not return nulls.</returns>
|
||||
public CharacterParams.AIParams AIParams
|
||||
{
|
||||
get
|
||||
@@ -565,7 +569,7 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
if (Character.Params.UsePathFinding && Character.Params.AI.UsePathFindingToGetInside && AIParams.CanOpenDoors)
|
||||
if (Character.Params.UsePathFinding && AIParams.UsePathFindingToGetInside && AIParams.CanOpenDoors)
|
||||
{
|
||||
// Meant for monsters outside the player sub that target something inside the sub and can use the doors to access the sub (Husk).
|
||||
bool IsCloseEnoughToTargetSub(float threshold) => SelectedAiTarget?.Entity?.Submarine is Submarine sub && sub != null && Vector2.DistanceSquared(Character.WorldPosition, sub.WorldPosition) < MathUtils.Pow(Math.Max(sub.Borders.Size.X, sub.Borders.Size.Y) / 2 + threshold, 2);
|
||||
@@ -3097,7 +3101,10 @@ namespace Barotrauma
|
||||
break;
|
||||
}
|
||||
|
||||
valueModifier *= targetMemory.Priority / (float)Math.Sqrt(dist);
|
||||
valueModifier *=
|
||||
targetMemory.Priority /
|
||||
//sqrt = the further the target is, the less the distance matters
|
||||
MathF.Sqrt(dist);
|
||||
|
||||
if (valueModifier > targetValue)
|
||||
{
|
||||
|
||||
@@ -685,8 +685,8 @@ namespace Barotrauma
|
||||
}
|
||||
if (removeDivingSuit)
|
||||
{
|
||||
var divingSuit = Character.Inventory.FindItemByTag(Tags.HeavyDivingGear);
|
||||
if (divingSuit != null && !divingSuit.HasTag(Tags.DivingGearWearableIndoors))
|
||||
var divingSuit = Character.Inventory.FindEquippedItemByTag(Tags.HeavyDivingGear);
|
||||
if (divingSuit != null && !divingSuit.HasTag(Tags.DivingGearWearableIndoors) && divingSuit.IsInteractable(Character))
|
||||
{
|
||||
if (shouldActOnSuffocation || Character.Submarine?.TeamID != Character.TeamID || ObjectiveManager.GetCurrentPriority() >= AIObjectiveManager.RunPriority)
|
||||
{
|
||||
@@ -727,54 +727,51 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
if (takeMaskOff)
|
||||
{
|
||||
if (Character.HasEquippedItem(Tags.LightDivingGear))
|
||||
{
|
||||
var mask = Character.Inventory.FindEquippedItemByTag(Tags.LightDivingGear);
|
||||
if (mask != null)
|
||||
{
|
||||
var mask = Character.Inventory.FindItemByTag(Tags.LightDivingGear);
|
||||
if (mask != null)
|
||||
if (!mask.AllowedSlots.Contains(InvSlotType.Any) || !Character.Inventory.TryPutItem(mask, Character, new List<InvSlotType>() { InvSlotType.Any }))
|
||||
{
|
||||
if (!mask.AllowedSlots.Contains(InvSlotType.Any) || !Character.Inventory.TryPutItem(mask, Character, new List<InvSlotType>() { InvSlotType.Any }))
|
||||
if (Character.Submarine?.TeamID != Character.TeamID || ObjectiveManager.GetCurrentPriority() >= AIObjectiveManager.RunPriority)
|
||||
{
|
||||
if (Character.Submarine?.TeamID != Character.TeamID || ObjectiveManager.GetCurrentPriority() >= AIObjectiveManager.RunPriority)
|
||||
mask.Drop(Character);
|
||||
HandleRelocation(mask);
|
||||
ReequipUnequipped();
|
||||
}
|
||||
else if (findItemState == FindItemState.None || findItemState == FindItemState.DivingMask)
|
||||
{
|
||||
findItemState = FindItemState.DivingMask;
|
||||
if (FindSuitableContainer(mask, out Item targetContainer))
|
||||
{
|
||||
mask.Drop(Character);
|
||||
HandleRelocation(mask);
|
||||
ReequipUnequipped();
|
||||
}
|
||||
else if (findItemState == FindItemState.None || findItemState == FindItemState.DivingMask)
|
||||
{
|
||||
findItemState = FindItemState.DivingMask;
|
||||
if (FindSuitableContainer(mask, out Item targetContainer))
|
||||
findItemState = FindItemState.None;
|
||||
itemIndex = 0;
|
||||
if (targetContainer != null)
|
||||
{
|
||||
findItemState = FindItemState.None;
|
||||
itemIndex = 0;
|
||||
if (targetContainer != null)
|
||||
var decontainObjective = new AIObjectiveDecontainItem(Character, mask, ObjectiveManager, targetContainer: targetContainer.GetComponent<ItemContainer>());
|
||||
decontainObjective.Abandoned += () =>
|
||||
{
|
||||
var decontainObjective = new AIObjectiveDecontainItem(Character, mask, ObjectiveManager, targetContainer: targetContainer.GetComponent<ItemContainer>());
|
||||
decontainObjective.Abandoned += () =>
|
||||
{
|
||||
ReequipUnequipped();
|
||||
IgnoredItems.Add(targetContainer);
|
||||
};
|
||||
decontainObjective.Completed += () => ReequipUnequipped();
|
||||
ObjectiveManager.CurrentObjective.AddSubObjective(decontainObjective, addFirst: true);
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
mask.Drop(Character);
|
||||
HandleRelocation(mask);
|
||||
ReequipUnequipped();
|
||||
}
|
||||
IgnoredItems.Add(targetContainer);
|
||||
};
|
||||
decontainObjective.Completed += () => ReequipUnequipped();
|
||||
ObjectiveManager.CurrentObjective.AddSubObjective(decontainObjective, addFirst: true);
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
mask.Drop(Character);
|
||||
HandleRelocation(mask);
|
||||
ReequipUnequipped();
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ReequipUnequipped();
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ReequipUnequipped();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -784,13 +781,11 @@ namespace Barotrauma
|
||||
|
||||
if (findItemState == FindItemState.None || findItemState == FindItemState.OtherItem)
|
||||
{
|
||||
for (int i = 0; i < 2; i++)
|
||||
foreach (Item item in Character.HeldItems)
|
||||
{
|
||||
var hand = i == 0 ? InvSlotType.RightHand : InvSlotType.LeftHand;
|
||||
Item item = Character.Inventory.GetItemInLimbSlot(hand);
|
||||
if (item == null) { continue; }
|
||||
if (item == null || !item.IsInteractable(Character)) { continue; }
|
||||
|
||||
if (!item.AllowedSlots.Contains(InvSlotType.Any) || !Character.Inventory.TryPutItem(item, Character, new List<InvSlotType>() { InvSlotType.Any }) && Character.Submarine?.TeamID == Character.TeamID )
|
||||
if (!item.AllowedSlots.Contains(InvSlotType.Any) || !Character.Inventory.TryPutItem(item, Character, CharacterInventory.AnySlot) && Character.Submarine?.TeamID == Character.TeamID)
|
||||
{
|
||||
if (item.AllowedSlots.Contains(InvSlotType.Bag) && Character.Inventory.TryPutItem(item, Character, new List<InvSlotType>() { InvSlotType.Bag })) { continue; }
|
||||
findItemState = FindItemState.OtherItem;
|
||||
@@ -1389,7 +1384,10 @@ namespace Barotrauma
|
||||
// Don't react to friendly enemy AI attacking other characters. E.g. husks attacking someone when whe are a cultist.
|
||||
continue;
|
||||
}
|
||||
bool isWitnessing = otherHumanAI.VisibleHulls.Contains(Character.CurrentHull) || otherHumanAI.VisibleHulls.Contains(attacker.CurrentHull);
|
||||
bool isWitnessing =
|
||||
otherHumanAI.VisibleHulls.Contains(Character.CurrentHull) ||
|
||||
otherHumanAI.VisibleHulls.Contains(attacker.CurrentHull) ||
|
||||
otherCharacter.CanSeeTarget(attacker, seeThroughWindows: true);
|
||||
if (!isWitnessing)
|
||||
{
|
||||
//if the other character did not witness the attack, and the character is not within report range (or capable of reporting)
|
||||
@@ -1754,11 +1752,11 @@ namespace Barotrauma
|
||||
if (otherCharacter == character || otherCharacter.TeamID == character.TeamID || otherCharacter.IsDead ||
|
||||
otherCharacter.Info?.Job == null ||
|
||||
otherCharacter.AIController is not HumanAIController otherHumanAI ||
|
||||
!otherHumanAI.VisibleHulls.Contains(character.CurrentHull))
|
||||
Vector2.DistanceSquared(otherCharacter.WorldPosition, character.WorldPosition) > 1000.0f * 1000.0f)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if (!otherCharacter.CanSeeTarget(character)) { continue; }
|
||||
if (!otherCharacter.CanSeeTarget(character, seeThroughWindows: true)) { continue; }
|
||||
|
||||
if (!otherHumanAI.structureDamageAccumulator.ContainsKey(character)) { otherHumanAI.structureDamageAccumulator.Add(character, 0.0f); }
|
||||
float prevAccumulatedDamage = otherHumanAI.structureDamageAccumulator[character];
|
||||
@@ -1840,13 +1838,13 @@ namespace Barotrauma
|
||||
foreach (Character otherCharacter in Character.CharacterList)
|
||||
{
|
||||
if (otherCharacter == thief || otherCharacter.TeamID == thief.TeamID || otherCharacter.IsIncapacitated || otherCharacter.Stun > 0.0f ||
|
||||
otherCharacter.Info?.Job == null || !(otherCharacter.AIController is HumanAIController otherHumanAI) ||
|
||||
!otherHumanAI.VisibleHulls.Contains(thief.CurrentHull))
|
||||
otherCharacter.Info?.Job == null || otherCharacter.AIController is not HumanAIController otherHumanAI ||
|
||||
Vector2.DistanceSquared(otherCharacter.WorldPosition, thief.WorldPosition) > 1000.0f * 1000.0f)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
//if (!otherCharacter.IsFacing(thief.WorldPosition)) { continue; }
|
||||
if (!otherCharacter.CanSeeTarget(thief)) { continue; }
|
||||
if (!otherCharacter.CanSeeTarget(thief, seeThroughWindows: true)) { continue; }
|
||||
// Don't react if the player is taking an extinguisher and there's any fires on the sub, or diving gear when the sub is flooding
|
||||
// -> allow them to use the emergency items
|
||||
if (thief.Submarine != null)
|
||||
|
||||
+5
-1
@@ -1070,7 +1070,8 @@ namespace Barotrauma
|
||||
{
|
||||
// Try reload ammunition from inventory
|
||||
static bool IsInsideHeadset(Item i) => i.ParentInventory?.Owner is Item ownerItem && ownerItem.HasTag(Tags.MobileRadio);
|
||||
Item ammunition = character.Inventory.FindItem(i => i.HasIdentifierOrTags(ammunitionIdentifiers) && i.Condition > 0 && !IsInsideHeadset(i), recursive: true);
|
||||
Item ammunition = character.Inventory.FindItem(i =>
|
||||
i.HasIdentifierOrTags(ammunitionIdentifiers) && i.Condition > 0 && !IsInsideHeadset(i) && i.IsInteractable(character), recursive: true);
|
||||
if (ammunition != null)
|
||||
{
|
||||
var container = Weapon.GetComponent<ItemContainer>();
|
||||
@@ -1089,6 +1090,9 @@ namespace Barotrauma
|
||||
}
|
||||
else if (!HoldPosition && IsOffensiveOrArrest && seekAmmo && ammunitionIdentifiers != null)
|
||||
{
|
||||
// Inventory not drawn = it's not interactable
|
||||
// If the weapon is empty and the inventory is inaccessible, it can't be reloaded
|
||||
if (!Weapon.OwnInventory.Container.DrawInventory) { return false; }
|
||||
SeekAmmunition(ammunitionIdentifiers);
|
||||
}
|
||||
return false;
|
||||
|
||||
+6
-4
@@ -14,7 +14,7 @@ namespace Barotrauma
|
||||
private int escapeProgress;
|
||||
private bool isBeingWatched;
|
||||
|
||||
private bool shouldSwitchTeams;
|
||||
private readonly bool shouldSwitchTeams;
|
||||
|
||||
const string EscapeTeamChangeIdentifier = "escape";
|
||||
|
||||
@@ -88,10 +88,12 @@ namespace Barotrauma
|
||||
escapeProgress += Rand.Range(2, 5);
|
||||
if (escapeProgress > 15)
|
||||
{
|
||||
Item handcuffs = character.Inventory.FindItemByTag(Tags.HandLockerItem);
|
||||
if (handcuffs != null)
|
||||
foreach (var it in character.HeldItems)
|
||||
{
|
||||
handcuffs.Drop(character);
|
||||
if (it.HasTag(Tags.HandLockerItem) && it.IsInteractable(character))
|
||||
{
|
||||
it.Drop(character);
|
||||
}
|
||||
}
|
||||
}
|
||||
escapeTimer = EscapeIntervalTimer * Rand.Range(0.75f, 1.25f);
|
||||
|
||||
+1
-1
@@ -114,7 +114,7 @@ namespace Barotrauma
|
||||
if (!IsValidTarget(target, character)) { continue; }
|
||||
//if we spot someone wearing or holding stolen items, immediately check them (with 100% chance of spotting the stolen items)
|
||||
if (target.Inventory.AllItems.Any(it => it.SpawnedInCurrentOutpost && !it.AllowStealing && target.HasEquippedItem(it)) &&
|
||||
character.CanSeeTarget(target))
|
||||
character.CanSeeTarget(target, seeThroughWindows: true))
|
||||
{
|
||||
AIObjectiveCheckStolenItems? existingObjective =
|
||||
objectiveManager.GetActiveObjectives<AIObjectiveCheckStolenItems>().FirstOrDefault(o => o.TargetCharacter == target);
|
||||
|
||||
+1
-1
@@ -120,7 +120,7 @@ namespace Barotrauma
|
||||
// The intention behind this is to reduce unnecessary path finding calls in cases where the bot can't find a path.
|
||||
timerMargin += 0.5f;
|
||||
timerMargin = Math.Min(timerMargin, newTargetIntervalMin);
|
||||
newTargetTimer = Math.Min(newTargetTimer, timerMargin);
|
||||
newTargetTimer = Math.Max(newTargetTimer, timerMargin);
|
||||
}
|
||||
|
||||
private void SetTargetTimerHigh()
|
||||
|
||||
@@ -664,6 +664,13 @@ namespace Barotrauma
|
||||
WallSectionIndex = wallSectionIndex ?? other.WallSectionIndex;
|
||||
|
||||
UseController = useController ?? other.UseController;
|
||||
|
||||
#if DEBUG
|
||||
if (UseController && ConnectedController == null)
|
||||
{
|
||||
DebugConsole.ThrowError($"AI: Created an Order {Identifier} that's set to use a Controller, but a Controller was not specified.\n{Environment.StackTrace.CleanupStackTrace()}");
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
public Order WithOption(Identifier option)
|
||||
@@ -713,7 +720,12 @@ namespace Barotrauma
|
||||
|
||||
public Order WithItemComponent(Item item, ItemComponent component = null)
|
||||
{
|
||||
return new Order(this, targetEntity: item, targetItemComponent: component ?? GetTargetItemComponent(item));
|
||||
Controller controller = null;
|
||||
if (UseController)
|
||||
{
|
||||
controller = item?.FindController(tags: ControllerTags);
|
||||
}
|
||||
return new Order(this, targetEntity: item, targetItemComponent: component ?? GetTargetItemComponent(item), connectedController: controller);
|
||||
}
|
||||
|
||||
public Order WithWallSection(Structure wall, int? sectionIndex)
|
||||
|
||||
Reference in New Issue
Block a user