2020-08-29 20:46:42 +10:00
using System.Collections.Generic ;
2021-11-29 12:25:22 +13:00
using Content.Shared.ActionBlocker ;
2021-11-23 23:00:16 +13:00
using Content.Shared.Administration.Logs ;
2021-11-28 14:56:53 +01:00
using Content.Shared.Database ;
2021-11-23 23:00:16 +13:00
using Content.Shared.Hands.Components ;
2021-11-29 12:25:22 +13:00
using Content.Shared.Interaction ;
using Robust.Shared.Containers ;
2020-08-29 20:46:42 +10:00
using Robust.Shared.GameObjects ;
2021-11-23 23:00:16 +13:00
using Robust.Shared.IoC ;
2020-08-29 20:46:42 +10:00
2021-06-09 22:19:39 +02:00
namespace Content.Shared.Verbs
2020-08-29 20:46:42 +10:00
{
2021-11-23 23:00:16 +13:00
public abstract class SharedVerbSystem : EntitySystem
2020-08-29 20:46:42 +10:00
{
2021-11-23 23:00:16 +13:00
[Dependency] private readonly SharedAdminLogSystem _logSystem = default ! ;
2021-11-29 12:25:22 +13:00
[Dependency] private readonly SharedInteractionSystem _interactionSystem = default ! ;
[Dependency] private readonly ActionBlockerSystem _actionBlockerSystem = default ! ;
2021-11-23 23:00:16 +13:00
2021-10-05 14:29:03 +11:00
/// <summary>
2021-10-28 18:21:19 +13:00
/// Raises a number of events in order to get all verbs of the given type(s) defined in local systems. This
/// does not request verbs from the server.
2021-10-05 14:29:03 +11:00
/// </summary>
2021-12-04 12:35:33 +01:00
public virtual Dictionary < VerbType , SortedSet < Verb > > GetLocalVerbs ( EntityUid target , EntityUid user , VerbType verbTypes , bool force = false )
2021-10-05 14:29:03 +11:00
{
Dictionary < VerbType , SortedSet < Verb > > verbs = new ( ) ;
2021-11-29 12:25:22 +13:00
// accessibility checks
bool canAccess = false ;
if ( force | | target = = user )
canAccess = true ;
else if ( _interactionSystem . InRangeUnobstructed ( user , target , ignoreInsideBlocker : true ) )
{
if ( user . IsInSameOrParentContainer ( target ) )
canAccess = true ;
else
// the item might be in a backpack that the user has open
2021-12-03 15:53:09 +01:00
canAccess = _interactionSystem . CanAccessViaStorage ( user , target ) ;
2021-11-29 12:25:22 +13:00
}
// A large number of verbs need to check action blockers. Instead of repeatedly having each system individually
// call ActionBlocker checks, just cache it for the verb request.
2021-12-03 15:53:09 +01:00
var canInteract = force | | _actionBlockerSystem . CanInteract ( user ) ;
2021-11-29 12:25:22 +13:00
2021-12-05 21:02:04 +01:00
EntityUid @using = default ;
2021-12-04 12:35:33 +01:00
if ( EntityManager . TryGetComponent ( user , out SharedHandsComponent ? hands ) & & ( force | | _actionBlockerSystem . CanUse ( user ) ) )
2021-11-29 12:25:22 +13:00
{
hands . TryGetActiveHeldEntity ( out @using ) ;
// Check whether the "Held" entity is a virtual pull entity. If yes, set that as the entity being "Used".
// This allows you to do things like buckle a dragged person onto a surgery table, without click-dragging
// their sprite.
2021-12-05 21:02:04 +01:00
if ( @using ! = default & & EntityManager . TryGetComponent < HandVirtualItemComponent ? > ( @using , out var pull ) )
2021-11-29 12:25:22 +13:00
{
2021-12-05 21:02:04 +01:00
@using = pull . BlockingEntity ;
2021-11-29 12:25:22 +13:00
}
}
2021-10-05 14:29:03 +11:00
if ( ( verbTypes & VerbType . Interaction ) = = VerbType . Interaction )
2020-08-30 11:37:06 +02:00
{
2021-11-29 12:25:22 +13:00
GetInteractionVerbsEvent getVerbEvent = new ( user , target , @using , hands , canInteract , canAccess ) ;
2021-12-03 15:53:09 +01:00
RaiseLocalEvent ( target , getVerbEvent ) ;
2021-10-05 14:29:03 +11:00
verbs . Add ( VerbType . Interaction , getVerbEvent . Verbs ) ;
2020-08-30 11:37:06 +02:00
}
2020-08-29 20:46:42 +10:00
2021-10-05 14:29:03 +11:00
if ( ( verbTypes & VerbType . Activation ) = = VerbType . Activation )
{
2021-11-29 12:25:22 +13:00
GetActivationVerbsEvent getVerbEvent = new ( user , target , @using , hands , canInteract , canAccess ) ;
2021-12-03 15:53:09 +01:00
RaiseLocalEvent ( target , getVerbEvent ) ;
2021-10-05 14:29:03 +11:00
verbs . Add ( VerbType . Activation , getVerbEvent . Verbs ) ;
}
2020-10-30 04:52:37 +01:00
2021-10-05 14:29:03 +11:00
if ( ( verbTypes & VerbType . Alternative ) = = VerbType . Alternative )
{
2021-11-29 12:25:22 +13:00
GetAlternativeVerbsEvent getVerbEvent = new ( user , target , @using , hands , canInteract , canAccess ) ;
2021-12-03 15:53:09 +01:00
RaiseLocalEvent ( target , getVerbEvent ) ;
2021-10-05 14:29:03 +11:00
verbs . Add ( VerbType . Alternative , getVerbEvent . Verbs ) ;
}
2020-08-29 20:46:42 +10:00
2021-10-05 14:29:03 +11:00
if ( ( verbTypes & VerbType . Other ) = = VerbType . Other )
2020-08-29 20:46:42 +10:00
{
2021-11-29 12:25:22 +13:00
GetOtherVerbsEvent getVerbEvent = new ( user , target , @using , hands , canInteract , canAccess ) ;
2021-12-03 15:53:09 +01:00
RaiseLocalEvent ( target , getVerbEvent ) ;
2021-10-05 14:29:03 +11:00
verbs . Add ( VerbType . Other , getVerbEvent . Verbs ) ;
2020-08-29 20:46:42 +10:00
}
2021-10-05 14:29:03 +11:00
return verbs ;
}
/// <summary>
2021-10-28 18:21:19 +13:00
/// Execute the provided verb.
2021-10-05 14:29:03 +11:00
/// </summary>
/// <remarks>
2021-10-28 18:21:19 +13:00
/// This will try to call the action delegates and raise the local events for the given verb.
2021-10-05 14:29:03 +11:00
/// </remarks>
2021-11-23 23:00:16 +13:00
public void ExecuteVerb ( Verb verb , EntityUid user , EntityUid target , bool forced = false )
2021-10-05 14:29:03 +11:00
{
2021-11-23 23:00:16 +13:00
// first, lets log the verb. Just in case it ends up crashing the server or something.
LogVerb ( verb , user , target , forced ) ;
2021-10-05 14:29:03 +11:00
2021-11-23 23:00:16 +13:00
// then invoke any relevant actions
2021-10-28 18:21:19 +13:00
verb . Act ? . Invoke ( ) ;
2021-10-05 14:29:03 +11:00
// Maybe raise a local event
2021-10-28 18:21:19 +13:00
if ( verb . ExecutionEventArgs ! = null )
2021-10-05 14:29:03 +11:00
{
2021-10-28 18:21:19 +13:00
if ( verb . EventTarget . IsValid ( ) )
RaiseLocalEvent ( verb . EventTarget , verb . ExecutionEventArgs ) ;
2021-10-05 14:29:03 +11:00
else
2021-10-28 18:21:19 +13:00
RaiseLocalEvent ( verb . ExecutionEventArgs ) ;
2021-10-05 14:29:03 +11:00
}
2020-08-29 20:46:42 +10:00
}
2021-11-23 23:00:16 +13:00
2021-12-05 21:02:04 +01:00
public void LogVerb ( Verb verb , EntityUid user , EntityUid target , bool forced )
2021-11-23 23:00:16 +13:00
{
// first get the held item. again.
2021-12-05 18:09:01 +01:00
EntityUid usedUid = default ;
2021-12-05 21:02:04 +01:00
if ( EntityManager . TryGetComponent ( user , out SharedHandsComponent ? hands ) & &
2021-12-05 18:09:01 +01:00
hands . TryGetActiveHeldEntity ( out var heldEntity ) )
2021-11-23 23:00:16 +13:00
{
2021-12-05 18:09:01 +01:00
usedUid = heldEntity ;
2021-12-05 21:02:04 +01:00
if ( usedUid ! = default & & EntityManager . TryGetComponent ( usedUid , out HandVirtualItemComponent ? pull ) )
2021-11-29 02:34:44 +13:00
usedUid = pull . BlockingEntity ;
2021-11-23 23:00:16 +13:00
}
2021-11-29 02:34:44 +13:00
// get all the entities
2021-12-05 21:02:04 +01:00
if ( ! user . IsValid ( ) | | ! target . IsValid ( ) )
2021-11-29 02:34:44 +13:00
return ;
2021-12-04 12:35:33 +01:00
EntityUid ? used = null ;
2021-12-05 21:02:04 +01:00
if ( usedUid ! = default )
EntityManager . EntityExists ( usedUid ) ;
2021-11-29 02:34:44 +13:00
2021-11-23 23:00:16 +13:00
var verbText = $"{verb.Category?.Text} {verb.Text}" . Trim ( ) ;
2021-12-14 00:22:58 +13:00
// lets not frame people, eh?
var executionText = forced ? "was forced to execute" : "executed" ;
if ( used = = null )
{
2021-11-23 23:00:16 +13:00
_logSystem . Add ( LogType . Verb , verb . Impact ,
2021-12-14 00:22:58 +13:00
$"{ToPrettyString(user):user} {executionText} the [{verbText:verb}] verb targeting {ToPrettyString(target):target}" ) ;
}
2021-11-23 23:00:16 +13:00
else
2021-12-14 00:22:58 +13:00
{
2021-11-23 23:00:16 +13:00
_logSystem . Add ( LogType . Verb , verb . Impact ,
2021-12-14 00:22:58 +13:00
$"{ToPrettyString(user):user} {executionText} the [{verbText:verb}] verb targeting {ToPrettyString(target):target} while holding {ToPrettyString(used.Value):held}" ) ;
}
2021-11-23 23:00:16 +13:00
}
2020-08-29 20:46:42 +10:00
}
2020-08-30 11:37:06 +02:00
}