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:
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
32
Content.Server/AI/Operators/Inventory/DropEntityOperator.cs
Normal file
32
Content.Server/AI/Operators/Inventory/DropEntityOperator.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
38
Content.Server/AI/Operators/Inventory/EquipEntityOperator.cs
Normal file
38
Content.Server/AI/Operators/Inventory/EquipEntityOperator.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
55
Content.Server/AI/Operators/Inventory/OpenStorageOperator.cs
Normal file
55
Content.Server/AI/Operators/Inventory/OpenStorageOperator.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user