Unstable v0.1300.0.0 (February 19th 2021)
This commit is contained in:
@@ -1,18 +1,17 @@
|
||||
using Microsoft.Xna.Framework;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Barotrauma.Items.Components;
|
||||
using System.Linq;
|
||||
|
||||
namespace Barotrauma
|
||||
{
|
||||
public enum AIState { Idle, Attack, Escape, Eat, Flee, Avoid, Aggressive, PassiveAggressive, Protect, Observe, Freeze, Follow }
|
||||
|
||||
abstract partial class AIController : ISteerable
|
||||
{
|
||||
public bool Enabled;
|
||||
|
||||
public readonly Character Character;
|
||||
|
||||
private AIState state;
|
||||
|
||||
// Update only when the value changes, not when it keeps the same.
|
||||
protected AITarget _lastAiTarget;
|
||||
// Updated each time the value is updated (also when the value is the same).
|
||||
@@ -74,25 +73,6 @@ namespace Barotrauma
|
||||
get { return true; }
|
||||
}
|
||||
|
||||
public virtual AIObjectiveManager ObjectiveManager
|
||||
{
|
||||
get { return null; }
|
||||
}
|
||||
|
||||
public AIState State
|
||||
{
|
||||
get { return state; }
|
||||
set
|
||||
{
|
||||
if (state == value) { return; }
|
||||
PreviousState = state;
|
||||
OnStateChanged(state, value);
|
||||
state = value;
|
||||
}
|
||||
}
|
||||
|
||||
public AIState PreviousState { get; protected set; }
|
||||
|
||||
private IEnumerable<Hull> visibleHulls;
|
||||
private float hullVisibilityTimer;
|
||||
const float hullVisibilityInterval = 0.5f;
|
||||
@@ -112,6 +92,9 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
protected bool HasValidPath(bool requireNonDirty = false) =>
|
||||
steeringManager is IndoorsSteeringManager pathSteering && pathSteering.CurrentPath != null && !pathSteering.CurrentPath.Finished && !pathSteering.CurrentPath.Unreachable && (!requireNonDirty || !pathSteering.IsPathDirty);
|
||||
|
||||
public AIController (Character c)
|
||||
{
|
||||
Character = c;
|
||||
@@ -149,8 +132,177 @@ namespace Barotrauma
|
||||
|
||||
public void FaceTarget(ISpatialEntity target) => Character.AnimController.TargetDir = target.WorldPosition.X > Character.WorldPosition.X ? Direction.Right : Direction.Left;
|
||||
|
||||
public bool IsSteeringThroughGap { get; protected set; }
|
||||
|
||||
public virtual bool SteerThroughGap(Structure wall, WallSection section, Vector2 targetWorldPos, float deltaTime)
|
||||
{
|
||||
if (wall == null) { return false; }
|
||||
if (section == null) { return false; }
|
||||
Gap gap = section.gap;
|
||||
if (gap == null) { return false; }
|
||||
float maxDistance = Math.Min(wall.Rect.Width, wall.Rect.Height);
|
||||
if (Vector2.DistanceSquared(Character.WorldPosition, targetWorldPos) > maxDistance * maxDistance) { return false; }
|
||||
Hull targetHull = gap.FlowTargetHull;
|
||||
if (targetHull == null) { return false; }
|
||||
if (wall.IsHorizontal)
|
||||
{
|
||||
targetWorldPos.Y = targetHull.WorldRect.Y - targetHull.Rect.Height / 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
targetWorldPos.X = targetHull.WorldRect.Center.X;
|
||||
}
|
||||
return SteerThroughGap(gap, targetWorldPos, deltaTime, maxDistance: -1);
|
||||
}
|
||||
|
||||
public virtual bool SteerThroughGap(Gap gap, Vector2 targetWorldPos, float deltaTime, float maxDistance = -1)
|
||||
{
|
||||
Hull targetHull = gap.FlowTargetHull;
|
||||
if (targetHull == null) { return false; }
|
||||
if (maxDistance > 0)
|
||||
{
|
||||
if (Vector2.DistanceSquared(Character.WorldPosition, targetWorldPos) > maxDistance * maxDistance) { return false; }
|
||||
}
|
||||
if (SteeringManager is IndoorsSteeringManager pathSteering)
|
||||
{
|
||||
pathSteering.ResetPath();
|
||||
}
|
||||
SteeringManager.SteeringManual(deltaTime, Vector2.Normalize(targetWorldPos - Character.WorldPosition));
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool CanPassThroughHole(Structure wall, int sectionIndex, int requiredHoleCount)
|
||||
{
|
||||
if (!wall.SectionBodyDisabled(sectionIndex)) { return false; }
|
||||
int holeCount = 1;
|
||||
for (int j = sectionIndex - 1; j > sectionIndex - requiredHoleCount; j--)
|
||||
{
|
||||
if (wall.SectionBodyDisabled(j))
|
||||
{
|
||||
holeCount++;
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
for (int j = sectionIndex + 1; j < sectionIndex + requiredHoleCount; j++)
|
||||
{
|
||||
if (wall.SectionBodyDisabled(j))
|
||||
{
|
||||
holeCount++;
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
return holeCount >= requiredHoleCount;
|
||||
}
|
||||
|
||||
protected bool IsWallDisabled(Structure wall)
|
||||
{
|
||||
bool isDisabled = true;
|
||||
for (int i = 0; i < wall.Sections.Length; i++)
|
||||
{
|
||||
if (!wall.SectionBodyDisabled(i))
|
||||
{
|
||||
isDisabled = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return isDisabled;
|
||||
}
|
||||
|
||||
private readonly HashSet<Item> unequippedItems = new HashSet<Item>();
|
||||
public bool TakeItem(Item item, Inventory targetInventory, bool equip, bool dropOtherIfCannotMove = true, bool allowSwapping = false, bool storeUnequipped = false)
|
||||
{
|
||||
var pickable = item.GetComponent<Pickable>();
|
||||
if (pickable == null) { return false; }
|
||||
if (item.ParentInventory is ItemInventory itemInventory)
|
||||
{
|
||||
if (!itemInventory.Container.HasRequiredItems(Character, addMessage: false)) { return false; }
|
||||
}
|
||||
if (equip)
|
||||
{
|
||||
int targetSlot = -1;
|
||||
//check if all the slots required by the item are free
|
||||
foreach (InvSlotType slots in pickable.AllowedSlots)
|
||||
{
|
||||
if (slots.HasFlag(InvSlotType.Any)) { continue; }
|
||||
for (int i = 0; i < targetInventory.Capacity; i++)
|
||||
{
|
||||
if (targetInventory is CharacterInventory characterInventory)
|
||||
{
|
||||
//slot not needed by the item, continue
|
||||
if (!slots.HasFlag(characterInventory.SlotTypes[i])) { continue; }
|
||||
}
|
||||
targetSlot = i;
|
||||
//slot free, continue
|
||||
var otherItem = targetInventory.GetItemAt(i);
|
||||
if (otherItem == null) { continue; }
|
||||
//try to move the existing item to LimbSlot.Any and continue if successful
|
||||
if (otherItem.AllowedSlots.Contains(InvSlotType.Any) && targetInventory.TryPutItem(otherItem, Character, CharacterInventory.anySlot))
|
||||
{
|
||||
if (storeUnequipped && targetInventory.Owner == Character)
|
||||
{
|
||||
unequippedItems.Add(otherItem);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (dropOtherIfCannotMove)
|
||||
{
|
||||
//if everything else fails, simply drop the existing item
|
||||
otherItem.Drop(Character);
|
||||
}
|
||||
}
|
||||
}
|
||||
return targetInventory.TryPutItem(item, targetSlot, allowSwapping, allowCombine: false, Character);
|
||||
}
|
||||
else
|
||||
{
|
||||
return targetInventory.TryPutItem(item, Character, CharacterInventory.anySlot);
|
||||
}
|
||||
}
|
||||
|
||||
public void UnequipEmptyItems(Item item, bool avoidDroppingInSea = true) => UnequipEmptyItems(Character, item, avoidDroppingInSea);
|
||||
|
||||
public static void UnequipEmptyItems(Character character, Item item, bool avoidDroppingInSea = true)
|
||||
{
|
||||
if (item.OwnInventory.AllItems.Any(it => it.Condition <= 0.0f))
|
||||
{
|
||||
foreach (Item containedItem in item.OwnInventory.AllItemsMod)
|
||||
{
|
||||
if (containedItem == null) { continue; }
|
||||
if (containedItem.Condition <= 0.0f)
|
||||
{
|
||||
if (character.Submarine == null && avoidDroppingInSea)
|
||||
{
|
||||
// If we are outside of main sub, try to put the item in the inventory instead dropping it in the sea.
|
||||
if (character.Inventory.TryPutItem(containedItem, character, CharacterInventory.anySlot))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
}
|
||||
containedItem.Drop(character);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void ReequipUnequipped()
|
||||
{
|
||||
foreach (var item in unequippedItems)
|
||||
{
|
||||
if (item != null && !item.Removed && Character.HasItem(item))
|
||||
{
|
||||
TakeItem(item, Character.Inventory, equip: true, dropOtherIfCannotMove: true, allowSwapping: true, storeUnequipped: false);
|
||||
}
|
||||
}
|
||||
unequippedItems.Clear();
|
||||
}
|
||||
|
||||
protected virtual void OnStateChanged(AIState from, AIState to) { }
|
||||
protected virtual void OnTargetChanged(AITarget previousTarget, AITarget newTarget) { }
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user