Add utility AI (#806)

Co-authored-by: Pieter-Jan Briers <pieterjan.briers@gmail.com>
Co-authored-by: Metal Gear Sloth <metalgearsloth@gmail.com>
Co-authored-by: Pieter-Jan Briers <pieterjan.briers+git@gmail.com>
This commit is contained in:
metalgearsloth
2020-06-18 22:52:44 +10:00
committed by GitHub
parent 9b8cedf6c6
commit 5391d3c72a
211 changed files with 10335 additions and 527 deletions

View File

@@ -0,0 +1,73 @@
using Content.Server.AI.Utility;
using Content.Server.AI.WorldState.States.Inventory;
using Content.Server.GameObjects.Components;
using Content.Server.GameObjects.EntitySystems;
using Content.Server.Utility;
using Robust.Shared.Interfaces.GameObjects;
namespace Content.Server.AI.Operators.Inventory
{
/// <summary>
/// Close the last EntityStorage we opened
/// This will also update the State for it (which a regular InteractWith won't do)
/// </summary>
public sealed class CloseLastStorageOperator : AiOperator
{
private readonly IEntity _owner;
private IEntity _target;
public CloseLastStorageOperator(IEntity owner)
{
_owner = owner;
}
public override bool TryStartup()
{
if (!base.TryStartup())
{
return true;
}
var blackboard = UtilityAiHelpers.GetBlackboard(_owner);
if (blackboard == null)
{
return false;
}
_target = blackboard.GetState<LastOpenedStorageState>().GetValue();
return _target != null;
}
public override void Shutdown(Outcome outcome)
{
base.Shutdown(outcome);
var blackboard = UtilityAiHelpers.GetBlackboard(_owner);
blackboard?.GetState<LastOpenedStorageState>().SetValue(null);
}
public override Outcome Execute(float frameTime)
{
if (!InteractionChecks.InRangeUnobstructed(_owner, _target.Transform.MapPosition))
{
return Outcome.Failed;
}
if (!_target.TryGetComponent(out EntityStorageComponent storageComponent) ||
storageComponent.IsWeldedShut)
{
return Outcome.Failed;
}
if (storageComponent.Open)
{
var activateArgs = new ActivateEventArgs {User = _owner, Target = _target};
storageComponent.Activate(activateArgs);
}
return Outcome.Success;
}
}
}

View File

@@ -0,0 +1,32 @@
using Content.Server.GameObjects;
using Robust.Shared.Interfaces.GameObjects;
using Robust.Shared.Log;
namespace Content.Server.AI.Operators.Inventory
{
public class DropEntityOperator : AiOperator
{
private readonly IEntity _owner;
private readonly IEntity _entity;
public DropEntityOperator(IEntity owner, IEntity entity)
{
_owner = owner;
_entity = entity;
}
/// <summary>
/// Requires EquipEntityOperator to put it in the active hand first
/// </summary>
/// <param name="frameTime"></param>
/// <returns></returns>
public override Outcome Execute(float frameTime)
{
if (!_owner.TryGetComponent(out HandsComponent handsComponent))
{
return Outcome.Failed;
}
return handsComponent.Drop(_entity) ? Outcome.Success : Outcome.Failed;
}
}
}

View File

@@ -0,0 +1,30 @@
using Content.Server.GameObjects;
using Robust.Shared.Interfaces.GameObjects;
namespace Content.Server.AI.Operators.Inventory
{
public class DropHandItemsOperator : AiOperator
{
private readonly IEntity _owner;
public DropHandItemsOperator(IEntity owner)
{
_owner = owner;
}
public override Outcome Execute(float frameTime)
{
if (!_owner.TryGetComponent(out HandsComponent handsComponent))
{
return Outcome.Failed;
}
foreach (var item in handsComponent.GetAllHeldItems())
{
handsComponent.Drop(item.Owner);
}
return Outcome.Success;
}
}
}

View File

@@ -0,0 +1,38 @@
using Content.Server.GameObjects;
using Robust.Shared.Interfaces.GameObjects;
namespace Content.Server.AI.Operators.Inventory
{
public sealed class EquipEntityOperator : AiOperator
{
private readonly IEntity _owner;
private readonly IEntity _entity;
public EquipEntityOperator(IEntity owner, IEntity entity)
{
_owner = owner;
_entity = entity;
}
public override Outcome Execute(float frameTime)
{
if (!_owner.TryGetComponent(out HandsComponent handsComponent))
{
return Outcome.Failed;
}
// TODO: If in clothing then click on it
foreach (var hand in handsComponent.ActivePriorityEnumerable())
{
if (handsComponent.GetHand(hand)?.Owner == _entity)
{
handsComponent.ActiveIndex = hand;
return Outcome.Success;
}
}
// TODO: Get free hand count; if no hands free then fail right here
// TODO: Go through inventory
return Outcome.Failed;
}
}
}

View File

@@ -0,0 +1,48 @@
using Content.Server.GameObjects.Components.Mobs;
using Content.Server.GameObjects.EntitySystems;
using Content.Server.Utility;
using Robust.Shared.Interfaces.GameObjects;
using Robust.Shared.IoC;
namespace Content.Server.AI.Operators.Inventory
{
/// <summary>
/// A Generic interacter; if you need to check stuff then make your own
/// </summary>
public class InteractWithEntityOperator : AiOperator
{
private readonly IEntity _owner;
private readonly IEntity _useTarget;
public InteractWithEntityOperator(IEntity owner, IEntity useTarget)
{
_owner = owner;
_useTarget = useTarget;
}
public override Outcome Execute(float frameTime)
{
if (_useTarget.Transform.GridID != _owner.Transform.GridID)
{
return Outcome.Failed;
}
if (!InteractionChecks.InRangeUnobstructed(_owner, _useTarget.Transform.MapPosition))
{
return Outcome.Failed;
}
if (_owner.TryGetComponent(out CombatModeComponent combatModeComponent))
{
combatModeComponent.IsInCombatMode = false;
}
// Click on da thing
var interactionSystem = IoCManager.Resolve<IEntitySystemManager>().GetEntitySystem<InteractionSystem>();
interactionSystem.UseItemInHand(_owner, _useTarget.Transform.GridPosition, _useTarget.Uid);
return Outcome.Success;
}
}
}

View File

@@ -0,0 +1,55 @@
using Content.Server.AI.Utility;
using Content.Server.AI.WorldState.States.Inventory;
using Content.Server.GameObjects.Components;
using Content.Server.GameObjects.EntitySystems;
using Content.Server.Utility;
using Robust.Shared.Containers;
using Robust.Shared.Interfaces.GameObjects;
namespace Content.Server.AI.Operators.Inventory
{
/// <summary>
/// If the target is in EntityStorage will open its parent container
/// </summary>
public sealed class OpenStorageOperator : AiOperator
{
private readonly IEntity _owner;
private readonly IEntity _target;
public OpenStorageOperator(IEntity owner, IEntity target)
{
_owner = owner;
_target = target;
}
public override Outcome Execute(float frameTime)
{
if (!InteractionChecks.InRangeUnobstructed(_owner, _target.Transform.MapPosition))
{
return Outcome.Failed;
}
if (!ContainerHelpers.TryGetContainer(_target, out var container))
{
return Outcome.Success;
}
if (!container.Owner.TryGetComponent(out EntityStorageComponent storageComponent) ||
storageComponent.IsWeldedShut)
{
return Outcome.Failed;
}
if (!storageComponent.Open)
{
var activateArgs = new ActivateEventArgs {User = _owner, Target = _target};
storageComponent.Activate(activateArgs);
}
var blackboard = UtilityAiHelpers.GetBlackboard(_owner);
blackboard?.GetState<LastOpenedStorageState>().SetValue(container.Owner);
return Outcome.Success;
}
}
}

View File

@@ -0,0 +1,65 @@
using Content.Server.GameObjects;
using Content.Server.GameObjects.EntitySystems;
using Content.Server.Utility;
using Robust.Shared.Containers;
using Robust.Shared.Interfaces.GameObjects;
using Robust.Shared.IoC;
namespace Content.Server.AI.Operators.Inventory
{
public class PickupEntityOperator : AiOperator
{
// Input variables
private readonly IEntity _owner;
private readonly IEntity _target;
public PickupEntityOperator(IEntity owner, IEntity target)
{
_owner = owner;
_target = target;
}
// TODO: When I spawn new entities they seem to duplicate clothing or something?
public override Outcome Execute(float frameTime)
{
if (_target == null ||
_target.Deleted ||
!_target.HasComponent<ItemComponent>() ||
ContainerHelpers.IsInContainer(_target) ||
!InteractionChecks.InRangeUnobstructed(_owner, _target.Transform.MapPosition))
{
return Outcome.Failed;
}
if (!_owner.TryGetComponent(out HandsComponent handsComponent))
{
return Outcome.Failed;
}
var emptyHands = false;
foreach (var hand in handsComponent.ActivePriorityEnumerable())
{
if (handsComponent.GetHand(hand) == null)
{
if (handsComponent.ActiveIndex != hand)
{
handsComponent.ActiveIndex = hand;
}
emptyHands = true;
break;
}
}
if (!emptyHands)
{
return Outcome.Failed;
}
var interactionSystem = IoCManager.Resolve<IEntitySystemManager>().GetEntitySystem<InteractionSystem>();
interactionSystem.Interaction(_owner, _target);
return Outcome.Success;
}
}
}

View File

@@ -0,0 +1,49 @@
using Content.Server.GameObjects;
using Robust.Shared.Interfaces.GameObjects;
namespace Content.Server.AI.Operators.Inventory
{
/// <summary>
/// Will find the item in storage, put it in an active hand, then use it
/// </summary>
public class UseItemInHandsOperator : AiOperator
{
private readonly IEntity _owner;
private readonly IEntity _target;
public UseItemInHandsOperator(IEntity owner, IEntity target)
{
_owner = owner;
_target = target;
}
public override Outcome Execute(float frameTime)
{
if (_target == null)
{
return Outcome.Failed;
}
// TODO: Also have this check storage a la backpack etc.
if (!_owner.TryGetComponent(out HandsComponent handsComponent))
{
return Outcome.Failed;
}
if (_target.TryGetComponent(out ItemComponent itemComponent))
{
return Outcome.Failed;
}
foreach (var slot in handsComponent.ActivePriorityEnumerable())
{
if (handsComponent.GetHand(slot) != itemComponent) continue;
handsComponent.ActiveIndex = slot;
handsComponent.ActivateItem();
return Outcome.Success;
}
return Outcome.Failed;
}
}
}