using Barotrauma.Items.Components; using Barotrauma.Networking; using System.Collections.Generic; using System.Linq; namespace Barotrauma { partial class Traitor { public class GoalFindItem : HumanoidGoal { private readonly string identifier; private readonly bool preferNew; private readonly bool allowNew; private readonly bool allowExisting; private readonly HashSet allowedContainerIdentifiers = new HashSet(); private ItemPrefab targetPrefab; private Item targetContainer; private Item target; private HashSet existingItems = new HashSet(); private string targetNameText; private string targetContainerNameText; private string targetHullNameText; public override IEnumerable InfoTextKeys => base.InfoTextKeys.Concat(new string[] { "[identifier]", "[target]", "[targethullname]" }); public override IEnumerable InfoTextValues(Traitor traitor) => base.InfoTextValues(traitor).Concat(new string[] { targetNameText ?? "", targetContainerNameText ?? "", targetHullNameText ?? "" }); public override bool IsCompleted => target != null && Traitors.Any(traitor => traitor.Character.HasItem(target)); public override bool CanBeCompleted(ICollection traitors) { if (!base.CanBeCompleted(traitors)) { return false; } if (target == null) { var targetPrefabCandidate = FindItemPrefab(identifier); return targetPrefabCandidate != null && FindTargetContainer(traitors, targetPrefabCandidate) != null; } if (target.Removed) { return false; } if (target.Submarine == null) { if (!(target.ParentInventory?.Owner is Character)) { return false; } } else { if (Traitors.All(traitor => target.Submarine.TeamID != traitor.Character.TeamID)) { return false; } } return true; } public override bool IsEnemy(Character character) => base.IsEnemy(character) || (target != null && target.FindParentInventory(inventory => inventory == character.Inventory) != null); protected ItemPrefab FindItemPrefab(string identifier) { return (ItemPrefab)MapEntityPrefab.List.Find(prefab => prefab is ItemPrefab && prefab.Identifier == identifier); } protected Item FindRandomContainer(ICollection traitors, ItemPrefab targetPrefabCandidate, bool includeNew, bool includeExisting) { List suitableItems = new List(); foreach (Item item in Item.ItemList) { if (item.Submarine == null || traitors.All(traitor => item.Submarine.TeamID != traitor.Character.TeamID)) { continue; } if (item.GetComponent() != null && allowedContainerIdentifiers.Contains(item.prefab.Identifier)) { if ((includeNew && !item.OwnInventory.IsFull()) || (includeExisting && item.OwnInventory.FindItemByIdentifier(targetPrefabCandidate.Identifier) != null)) { suitableItems.Add(item); } } } if (suitableItems.Count == 0) { return null; } return suitableItems[TraitorMission.Random(suitableItems.Count)]; } protected Item FindTargetContainer(ICollection traitors, ItemPrefab targetPrefabCandidate) { Item result = null; if (preferNew) { result = FindRandomContainer(traitors, targetPrefabCandidate, true, false); } if (result == null) { result = FindRandomContainer(traitors, targetPrefabCandidate, allowNew, allowExisting); } if (result == null) { return null; } if (allowNew && !result.OwnInventory.IsFull()) { return result; } if (allowExisting && result.OwnInventory.FindItemByIdentifier(targetPrefabCandidate.Identifier) != null) { return result; } return null; } public override bool Start(Traitor traitor) { if (!base.Start(traitor)) { return false; } if (targetPrefab != null) { return true; } targetPrefab = FindItemPrefab(identifier); if (targetPrefab == null) { return false; } var targetPrefabTextId = targetPrefab.GetItemNameTextId(); targetNameText = targetPrefabTextId != null ? TextManager.FormatServerMessage(targetPrefabTextId) : targetPrefab.Name; targetContainer = FindTargetContainer(Traitors, targetPrefab); if (targetContainer == null) { targetPrefab = null; targetContainer = null; return false; } var containerPrefabTextId = targetContainer.Prefab.GetItemNameTextId(); targetContainerNameText = containerPrefabTextId != null ? TextManager.FormatServerMessage(containerPrefabTextId) : targetContainer.Prefab.Name; var targetHullTextId = targetContainer.CurrentHull?.prefab.GetHullNameTextId(); targetHullNameText = targetHullTextId != null ? TextManager.FormatServerMessage(targetHullTextId) : targetContainer?.CurrentHull?.DisplayName ?? ""; if (allowNew && !targetContainer.OwnInventory.IsFull()) { existingItems.Clear(); foreach (var item in targetContainer.OwnInventory.Items) { existingItems.Add(item); } Entity.Spawner.AddToSpawnQueue(targetPrefab, targetContainer.OwnInventory); target = null; } else if (allowExisting) { target = targetContainer.OwnInventory.FindItemByIdentifier(targetPrefab.Identifier); } else { targetPrefab = null; targetContainer = null; return false; } return true; } public override void Update(float deltaTime) { base.Update(deltaTime); if (target == null) { target = targetContainer.OwnInventory.Items.FirstOrDefault(item => item != null && item.Prefab.Identifier == identifier && !existingItems.Contains(item)); if (target != null) { existingItems.Clear(); } } } public GoalFindItem(string identifier, bool preferNew, bool allowNew, bool allowExisting, params string[] allowedContainerIdentifiers) { this.identifier = identifier; this.preferNew = preferNew; this.allowNew = allowNew; this.allowExisting = allowExisting; this.allowedContainerIdentifiers.UnionWith(allowedContainerIdentifiers); } } } }