diff --git a/Barotrauma/BarotraumaShared/Content/Items/Artifacts/artifacts.xml b/Barotrauma/BarotraumaShared/Content/Items/Artifacts/artifacts.xml index 65e9ee3dd..47f7cb4fe 100644 --- a/Barotrauma/BarotraumaShared/Content/Items/Artifacts/artifacts.xml +++ b/Barotrauma/BarotraumaShared/Content/Items/Artifacts/artifacts.xml @@ -91,9 +91,8 @@ diff --git a/Barotrauma/BarotraumaShared/Content/Items/Diving/divinggear.xml b/Barotrauma/BarotraumaShared/Content/Items/Diving/divinggear.xml index 9cbd1a043..3e81f150e 100644 --- a/Barotrauma/BarotraumaShared/Content/Items/Diving/divinggear.xml +++ b/Barotrauma/BarotraumaShared/Content/Items/Diving/divinggear.xml @@ -3,7 +3,7 @@ diff --git a/Barotrauma/BarotraumaShared/Source/Characters/AI/Objectives/AIObjectiveContainItem.cs b/Barotrauma/BarotraumaShared/Source/Characters/AI/Objectives/AIObjectiveContainItem.cs index 9dc4e26bc..2e1f95d8c 100644 --- a/Barotrauma/BarotraumaShared/Source/Characters/AI/Objectives/AIObjectiveContainItem.cs +++ b/Barotrauma/BarotraumaShared/Source/Characters/AI/Objectives/AIObjectiveContainItem.cs @@ -6,24 +6,29 @@ namespace Barotrauma { class AIObjectiveContainItem: AIObjective { - private string itemName; + private string[] itemNames; private ItemContainer container; bool isCompleted; public bool IgnoreAlreadyContainedItems; - + public AIObjectiveContainItem(Character character, string itemName, ItemContainer container) + : this(character, new string[] { itemName }, container) + { + } + + public AIObjectiveContainItem(Character character, string[] itemNames, ItemContainer container) : base (character, "") { - this.itemName = itemName; + this.itemNames = itemNames; this.container = container; } public override bool IsCompleted() { - return isCompleted || container.Inventory.FindItem(itemName)!=null; + return isCompleted || itemNames.Any(name => container.Inventory.FindItem(name) != null); } public override float GetPriority(AIObjectiveManager objectiveManager) @@ -41,10 +46,10 @@ namespace Barotrauma if (isCompleted) return; //get the item that should be contained - var itemToContain = character.Inventory.FindItem(itemName); + var itemToContain = character.Inventory.FindItem(itemNames); if (itemToContain == null) { - var getItem = new AIObjectiveGetItem(character, itemName); + var getItem = new AIObjectiveGetItem(character, itemNames); getItem.IgnoreContainedItems = IgnoreAlreadyContainedItems; AddSubObjective(getItem); return; @@ -79,8 +84,15 @@ namespace Barotrauma { AIObjectiveContainItem objective = otherObjective as AIObjectiveContainItem; if (objective == null) return false; + if (objective.container != container) return false; + if (objective.itemNames.Length != itemNames.Length) return false; - return objective.itemName == itemName && objective.container == container; + for (int i = 0; i < itemNames.Length; i++) + { + if (objective.itemNames[i] != itemNames[i]) return false; + } + + return true; } diff --git a/Barotrauma/BarotraumaShared/Source/Characters/AI/Objectives/AIObjectiveFindDivingGear.cs b/Barotrauma/BarotraumaShared/Source/Characters/AI/Objectives/AIObjectiveFindDivingGear.cs index 132408dd3..b3d1d4e33 100644 --- a/Barotrauma/BarotraumaShared/Source/Characters/AI/Objectives/AIObjectiveFindDivingGear.cs +++ b/Barotrauma/BarotraumaShared/Source/Characters/AI/Objectives/AIObjectiveFindDivingGear.cs @@ -11,12 +11,20 @@ namespace Barotrauma public override bool IsCompleted() { - var item = character.Inventory.FindItem(gearName); - if (item == null) return false; + for (int i = 0; i < character.Inventory.Items.Length; i++) + { + if (CharacterInventory.limbSlots[i] == InvSlotType.Any || character.Inventory.Items[i] == null) continue; + if (character.Inventory.Items[i].Prefab.NameMatches(gearName) || character.Inventory.Items[i].HasTag(gearName)) + { + var containedItems = character.Inventory.Items[i].ContainedItems; + if (containedItems == null) continue; - var containedItems = item.ContainedItems; - var oxygenTank = Array.Find(containedItems, i => i.Prefab.NameMatches("Oxygen Tank") && i.Condition > 0.0f); - return oxygenTank != null; + var oxygenTank = Array.Find(containedItems, it => (it.Prefab.NameMatches("Oxygen Tank") || it.HasTag("oxygensource")) && it.Condition > 0.0f); + if (oxygenTank != null) return true; + } + } + + return false; } public AIObjectiveFindDivingGear(Character character, bool needDivingSuit) @@ -41,25 +49,24 @@ namespace Barotrauma var containedItems = item.ContainedItems; if (containedItems == null) return; - //check if there's an oxygen tank in the mask - var oxygenTank = Array.Find(containedItems, i => i.Prefab.NameMatches("Oxygen Tank")); - - if (oxygenTank != null) + //check if there's an oxygen tank in the mask/suit + foreach (Item containedItem in containedItems) { - if (oxygenTank.Condition > 0.0f) + if (containedItem == null) continue; + if (containedItem.Condition <= 0.0f) { + containedItem.Drop(); + } + else if (containedItem.Prefab.NameMatches("Oxygen Tank") || containedItem.HasTag("oxygensource")) + { + //we've got an oxygen source inside the mask/suit, all good return; } - else - { - oxygenTank.Drop(); - } } - - + if (!(subObjective is AIObjectiveContainItem) || subObjective.IsCompleted()) { - subObjective = new AIObjectiveContainItem(character, "Oxygen Tank", item.GetComponent()); + subObjective = new AIObjectiveContainItem(character, new string[] { "Oxygen Tank", "oxygensource" }, item.GetComponent()); } } diff --git a/Barotrauma/BarotraumaShared/Source/Characters/AI/Objectives/AIObjectiveGetItem.cs b/Barotrauma/BarotraumaShared/Source/Characters/AI/Objectives/AIObjectiveGetItem.cs index 05c80fa69..2f69713bd 100644 --- a/Barotrauma/BarotraumaShared/Source/Characters/AI/Objectives/AIObjectiveGetItem.cs +++ b/Barotrauma/BarotraumaShared/Source/Characters/AI/Objectives/AIObjectiveGetItem.cs @@ -2,13 +2,12 @@ using Microsoft.Xna.Framework; using System.Collections.Generic; using System.Linq; -using System; namespace Barotrauma { class AIObjectiveGetItem : AIObjective { - private string itemName; + private string[] itemNames; private Item targetItem, moveToTarget; @@ -49,24 +48,33 @@ namespace Barotrauma this.targetItem = targetItem; } - public AIObjectiveGetItem(Character character, string itemName, bool equip=false) - : base (character, "") + public AIObjectiveGetItem(Character character, string itemName, bool equip = false) + : this(character, new string[] { itemName }, equip) + { + } + + public AIObjectiveGetItem(Character character, string[] itemNames, bool equip = false) + : base(character, "") { canBeCompleted = true; this.equip = equip; currSearchIndex = 0; - - this.itemName = itemName; + + this.itemNames = itemNames; } protected override void Act(float deltaTime) { FindTargetItem(); - if (targetItem == null || moveToTarget == null) return; + if (targetItem == null || moveToTarget == null) + { + character?.AIController?.SteeringManager?.Reset(); + return; + } - if (Vector2.Distance(character.Position, moveToTarget.Position) < targetItem.InteractDistance*2.0f) + if (Vector2.Distance(character.Position, moveToTarget.Position) < targetItem.InteractDistance * 2.0f) { int targetSlot = -1; if (equip) @@ -82,8 +90,8 @@ namespace Barotrauma foreach (InvSlotType slots in pickable.AllowedSlots) { if (slots.HasFlag(InvSlotType.Any)) continue; - - for (int i = 0; i @@ -127,14 +139,14 @@ namespace Barotrauma /// private void FindTargetItem() { - if (itemName == null) + if (itemNames == null) { if (targetItem == null) canBeCompleted = false; return; } float currDist = moveToTarget == null ? 0.0f : Vector2.DistanceSquared(moveToTarget.Position, character.Position); - + for (int i = 0; i < 10 && currSearchIndex < Item.ItemList.Count - 2; i++) { currSearchIndex++; @@ -143,21 +155,26 @@ namespace Barotrauma if (item.CurrentHull == null || item.Condition <= 0.0f) continue; if (IgnoreContainedItems && item.Container != null) continue; - if (item.Name != itemName && !item.HasTag(itemName)) continue; + if (!itemNames.Any(name => item.Prefab.NameMatches(name) || item.HasTag(name))) continue; - //if the item is inside a character's inventory, don't steal it - if (item.ParentInventory is CharacterInventory) continue; + //if the item is inside a character's inventory, don't steal it unless the character is dead + if (item.ParentInventory is CharacterInventory) + { + Character owner = item.ParentInventory.Owner as Character; + if (owner != null && !owner.IsDead) continue; + } //if the item is inside an item, which is inside a character's inventory, don't steal it - if (item.ParentInventory != null && item.ParentInventory.Owner is Item) + Item rootContainer = item.GetRootContainer(); + if (rootContainer != null && rootContainer.ParentInventory is CharacterInventory) { - if (((Item)item.ParentInventory.Owner).ParentInventory is CharacterInventory) continue; + Character owner = rootContainer.ParentInventory.Owner as Character; + if (owner != null && !owner.IsDead) continue; } //ignore if item is further away than the currently targeted item - Item rootContainer = item.GetRootContainer(); if (moveToTarget != null && Vector2.DistanceSquared((rootContainer ?? item).Position, character.Position) > currDist) continue; - + targetItem = item; moveToTarget = rootContainer ?? item; } @@ -165,23 +182,44 @@ namespace Barotrauma //if searched through all the items and a target wasn't found, can't be completed if (currSearchIndex >= Item.ItemList.Count && targetItem == null) canBeCompleted = false; } - + public override bool IsDuplicate(AIObjective otherObjective) { AIObjectiveGetItem getItem = otherObjective as AIObjectiveGetItem; if (getItem == null) return false; - return (getItem.itemName == itemName); + if (getItem.equip != equip) return false; + if (getItem.itemNames != null && itemNames != null) + { + if (getItem.itemNames.Length != itemNames.Length) return false; + for (int i = 0; i < getItem.itemNames.Length; i++) + { + if (getItem.itemNames[i] != itemNames[i]) return false; + } + return true; + } + else if (getItem.itemNames == null && itemNames == null) + { + return getItem.targetItem == targetItem; + } + + return false; } public override bool IsCompleted() { - if (itemName!=null) + if (itemNames != null) { - return character.Inventory.FindItem(itemName) != null; + foreach (string itemName in itemNames) + { + var matchingItem = character.Inventory.FindItem(itemName); + if (matchingItem != null && (!equip || character.HasEquippedItem(matchingItem))) return true; + } + return false; + } - else if (targetItem!= null) + else if (targetItem != null) { - return character.Inventory.Items.Contains(targetItem); + return character.Inventory.Items.Contains(targetItem) && (!equip || character.HasEquippedItem(targetItem)); } else { diff --git a/Barotrauma/BarotraumaShared/Source/Characters/Character.cs b/Barotrauma/BarotraumaShared/Source/Characters/Character.cs index da7694ae1..bbec5ff12 100644 --- a/Barotrauma/BarotraumaShared/Source/Characters/Character.cs +++ b/Barotrauma/BarotraumaShared/Source/Characters/Character.cs @@ -1045,6 +1045,17 @@ namespace Barotrauma return !inventory.IsInLimbSlot(item, InvSlotType.Any); } + public bool HasEquippedItem(string itemName) + { + for (int i = 0; i < inventory.Items.Length; i++) + { + if (CharacterInventory.limbSlots[i] == InvSlotType.Any || inventory.Items[i] == null) continue; + if (inventory.Items[i].Prefab.NameMatches(itemName) || inventory.Items[i].HasTag(itemName)) return true; + } + + return false; + } + public bool HasSelectedItem(Item item) { return selectedItems.Contains(item); diff --git a/Barotrauma/BarotraumaShared/Source/Items/Inventory.cs b/Barotrauma/BarotraumaShared/Source/Items/Inventory.cs index 77e20af31..e2f1c0a1b 100644 --- a/Barotrauma/BarotraumaShared/Source/Items/Inventory.cs +++ b/Barotrauma/BarotraumaShared/Source/Items/Inventory.cs @@ -143,10 +143,21 @@ namespace Barotrauma public Item FindItem(string itemName) { if (itemName == null) return null; - return Items.FirstOrDefault(i => i != null && (i.Prefab.NameMatches(itemName) || i.HasTag(itemName))); } + public Item FindItem(string[] itemNames) + { + if (itemNames == null) return null; + + foreach (string itemName in itemNames) + { + var item = FindItem(itemName); + if (item != null) return item; + } + return null; + } + public virtual void RemoveItem(Item item) { if (item == null) return;