Files
LuaCsForBarotraumaEP/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/Objectives/AIObjectiveDeconstructItems.cs
2026-04-09 15:10:07 +03:00

134 lines
5.6 KiB
C#

using Barotrauma.Extensions;
using Barotrauma.Items.Components;
using System.Collections.Generic;
using System.Linq;
namespace Barotrauma
{
class AIObjectiveDeconstructItems : AIObjectiveLoop<Item>
{
public override Identifier Identifier { get; set; } = "deconstruct items".ToIdentifier();
//Clear periodically, because we may ending up ignoring items when all deconstructors are full
protected override float IgnoreListClearInterval => 30;
protected override bool AllowInFriendlySubs => true;
protected override int MaxTargets => 10;
private bool checkedDeconstructorExists;
public AIObjectiveDeconstructItems(Character character, AIObjectiveManager objectiveManager, float priorityModifier = 1)
: base(character, objectiveManager, priorityModifier)
{
}
public override void OnSelected()
{
base.OnSelected();
if (!checkedDeconstructorExists)
{
if (character.Submarine == null ||
Item.ItemList.None(it =>
it.GetComponent<Deconstructor>() != null &&
!it.IgnoreByAI(character) &&
it.IsInteractable(character) &&
character.Submarine.IsEntityFoundOnThisSub(it, includingConnectedSubs: true, allowDifferentTeam: true, allowDifferentType: true)))
{
character.Speak(TextManager.Get("orderdialogself.deconstructitem.nodeconstructor").Value, delay: 5.0f,
identifier: "nodeconstructor".ToIdentifier(), minDurationBetweenSimilar: 30.0f);
Abandon = true;
}
checkedDeconstructorExists = true;
}
}
public override void Reset()
{
base.Reset();
checkedDeconstructorExists = false;
}
protected override float GetTargetPriority()
{
if (Targets.None()) { return 0; }
if (objectiveManager.IsOrder(this))
{
return objectiveManager.GetOrderPriority(this);
}
return AIObjectiveManager.RunPriority - 0.5f;
}
protected override bool IsValidTarget(Item target)
{
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.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))
{
return Objectives.ContainsKey(target) && AIObjectiveCleanupItems.IsItemInsideValidSubmarine(target, character);
}
//note that the item can be outside hulls and still be a valid target - it can be in the character's inventory
if (target.CurrentHull != null && target.CurrentHull.FireSources.Count > 0) { return false; }
foreach (Character c in Character.CharacterList)
{
if (c == character || !HumanAIController.IsActive(c)) { continue; }
if (c.CurrentHull == target.CurrentHull && !HumanAIController.IsFriendly(c))
{
// Don't deconstruct items in rooms that have enemies inside.
return false;
}
else if (c.TeamID == character.TeamID && c.AIController is HumanAIController humanAi)
{
if (humanAi.ObjectiveManager.CurrentObjective is AIObjectiveDeconstructItem deconstruct && deconstruct.Item == target)
{
return false;
}
}
}
return true;
}
protected override IEnumerable<Item> GetList() => Item.DeconstructItems;
protected override AIObjective ObjectiveConstructor(Item item)
=> new AIObjectiveDeconstructItem(item, character, objectiveManager, priorityModifier: PriorityModifier);
protected override void OnObjectiveCompleted(AIObjective objective, Item target)
=> HumanAIController.RemoveTargets<AIObjectiveDeconstructItems, Item>(character, target);
private static bool IsValidTarget(Item item, Character character, bool checkInventory)
{
if (item == null || item.Removed) { return false; }
if (item.GetRootInventoryOwner() == character) { return true; }
return AIObjectiveCleanupItems.IsValidTarget(
item,
character,
checkInventory,
allowUnloading: true,
requireValidContainer: false,
ignoreItemsMarkedForDeconstruction: false);
}
public override void OnDeselected()
{
base.OnDeselected();
foreach (var subObjective in SubObjectives)
{
if (subObjective is AIObjectiveDeconstructItem deconstructObjective)
{
deconstructObjective.DropTarget();
}
}
}
}
}