2022-09-29 15:51:59 +10:00
using System.Linq ;
2022-11-19 17:07:50 +01:00
using System.Diagnostics.CodeAnalysis ;
2021-12-16 23:42:02 +13:00
using Content.Server.Chemistry.Components ;
2022-11-19 17:07:50 +01:00
using Content.Server.Chemistry.Components.SolutionManager ;
2023-04-22 22:43:46 -05:00
// using Content.Server.Weapons.Melee;
2022-11-19 17:07:50 +01:00
using Content.Shared.Chemistry.Reagent ;
using Content.Shared.Database ;
using Content.Shared.FixedPoint ;
using Content.Shared.IdentityManagement ;
2021-06-09 22:19:39 +02:00
using Content.Shared.Interaction ;
2022-05-06 23:44:29 +02:00
using Content.Shared.Interaction.Events ;
2023-01-13 16:57:10 -08:00
using Content.Shared.Mobs.Components ;
2022-09-29 15:51:59 +10:00
using Content.Shared.Weapons.Melee.Events ;
2023-02-27 13:19:52 -08:00
using Content.Shared.Timing ;
2021-06-05 00:20:52 -07:00
2021-06-09 22:19:39 +02:00
namespace Content.Server.Chemistry.EntitySystems
2021-06-05 00:20:52 -07:00
{
2022-02-07 00:34:13 +11:00
public sealed partial class ChemistrySystem
2021-06-05 00:20:52 -07:00
{
2023-02-27 13:19:52 -08:00
[Dependency] private readonly UseDelaySystem _useDelay = default ! ;
2022-02-07 00:34:13 +11:00
private void InitializeHypospray ( )
2021-06-05 00:20:52 -07:00
{
SubscribeLocalEvent < HyposprayComponent , AfterInteractEvent > ( OnAfterInteract ) ;
2022-09-29 15:51:59 +10:00
SubscribeLocalEvent < HyposprayComponent , MeleeHitEvent > ( OnAttack ) ;
2021-09-06 15:49:44 +02:00
SubscribeLocalEvent < HyposprayComponent , SolutionChangedEvent > ( OnSolutionChange ) ;
2022-05-06 23:44:29 +02:00
SubscribeLocalEvent < HyposprayComponent , UseInHandEvent > ( OnUseInHand ) ;
}
private void OnUseInHand ( EntityUid uid , HyposprayComponent component , UseInHandEvent args )
{
2023-04-22 22:43:46 -05:00
if ( args . Handled )
return ;
2022-05-06 23:44:29 +02:00
2022-11-19 17:07:50 +01:00
TryDoInject ( uid , args . User , args . User ) ;
2022-05-06 23:44:29 +02:00
args . Handled = true ;
2021-09-06 15:49:44 +02:00
}
private void OnSolutionChange ( EntityUid uid , HyposprayComponent component , SolutionChangedEvent args )
{
2022-02-02 17:34:25 +11:00
Dirty ( component ) ;
2021-06-05 00:20:52 -07:00
}
2022-11-19 17:07:50 +01:00
public void OnAfterInteract ( EntityUid uid , HyposprayComponent component , AfterInteractEvent args )
2021-06-05 00:20:52 -07:00
{
if ( ! args . CanReach )
return ;
2022-02-07 00:34:13 +11:00
2021-06-05 00:20:52 -07:00
var target = args . Target ;
var user = args . User ;
2022-11-19 17:07:50 +01:00
TryDoInject ( uid , target , user ) ;
2021-06-05 00:20:52 -07:00
}
2022-11-19 17:07:50 +01:00
public void OnAttack ( EntityUid uid , HyposprayComponent component , MeleeHitEvent args )
2021-06-05 00:20:52 -07:00
{
2022-09-29 15:51:59 +10:00
if ( ! args . HitEntities . Any ( ) )
2021-12-14 06:17:18 +01:00
return ;
2021-06-05 00:20:52 -07:00
2022-11-19 17:07:50 +01:00
TryDoInject ( uid , args . HitEntities . First ( ) , args . User ) ;
}
public bool TryDoInject ( EntityUid uid , EntityUid ? target , EntityUid user , HyposprayComponent ? component = null )
{
if ( ! Resolve ( uid , ref component ) )
return false ;
if ( ! EligibleEntity ( target , _entMan ) )
return false ;
2023-04-22 22:43:46 -05:00
if ( TryComp ( uid , out UseDelayComponent ? delayComp ) & & _useDelay . ActiveDelay ( uid , delayComp ) )
return false ;
2023-02-27 13:19:52 -08:00
2022-11-19 17:07:50 +01:00
string? msgFormat = null ;
if ( target = = user )
msgFormat = "hypospray-component-inject-self-message" ;
else if ( EligibleEntity ( user , _entMan ) & & _interaction . TryRollClumsy ( user , component . ClumsyFailChance ) )
{
msgFormat = "hypospray-component-inject-self-clumsy-message" ;
target = user ;
}
_solutions . TryGetSolution ( uid , component . SolutionName , out var hypoSpraySolution ) ;
2023-01-12 16:41:40 +13:00
if ( hypoSpraySolution = = null | | hypoSpraySolution . Volume = = 0 )
2022-11-19 17:07:50 +01:00
{
2022-12-19 10:41:47 +13:00
_popup . PopupCursor ( Loc . GetString ( "hypospray-component-empty-message" ) , user ) ;
2022-11-19 17:07:50 +01:00
return true ;
}
if ( ! _solutions . TryGetInjectableSolution ( target . Value , out var targetSolution ) )
{
2022-12-19 10:41:47 +13:00
_popup . PopupCursor ( Loc . GetString ( "hypospray-cant-inject" , ( "target" , Identity . Entity ( target . Value , _entMan ) ) ) , user ) ;
2022-11-19 17:07:50 +01:00
return false ;
}
2022-12-19 10:41:47 +13:00
_popup . PopupCursor ( Loc . GetString ( msgFormat ? ? "hypospray-component-inject-other-message" , ( "other" , target ) ) , user ) ;
2022-11-19 17:07:50 +01:00
if ( target ! = user )
{
2023-04-25 16:18:52 +03:00
_popup . PopupEntity ( Loc . GetString ( "hypospray-component-feel-prick-message" ) , target . Value , target . Value ) ;
2022-11-19 17:07:50 +01:00
// TODO: This should just be using melee attacks...
// meleeSys.SendLunge(angle, user);
}
_audio . PlayPvs ( component . InjectSound , user ) ;
2023-02-27 13:19:52 -08:00
// Medipens and such use this system and don't have a delay, requiring extra checks
// BeginDelay function returns if item is already on delay
if ( delayComp is not null )
_useDelay . BeginDelay ( uid , delayComp ) ;
2022-11-19 17:07:50 +01:00
// Get transfer amount. May be smaller than component.TransferAmount if not enough room
var realTransferAmount = FixedPoint2 . Min ( component . TransferAmount , targetSolution . AvailableVolume ) ;
if ( realTransferAmount < = 0 )
{
2022-12-19 10:41:47 +13:00
_popup . PopupCursor ( Loc . GetString ( "hypospray-component-transfer-already-full-message" , ( "owner" , target ) ) , user ) ;
2022-11-19 17:07:50 +01:00
return true ;
}
// Move units from attackSolution to targetSolution
var removedSolution = _solutions . SplitSolution ( uid , hypoSpraySolution , realTransferAmount ) ;
if ( ! targetSolution . CanAddSolution ( removedSolution ) )
return true ;
_reactiveSystem . DoEntityReaction ( target . Value , removedSolution , ReactionMethod . Injection ) ;
_solutions . TryAddSolution ( target . Value , targetSolution , removedSolution ) ;
2023-04-22 22:43:46 -05:00
// same LogType as syringes...
2022-11-19 17:07:50 +01:00
_adminLogger . Add ( LogType . ForceFeed , $"{_entMan.ToPrettyString(user):user} injected {_entMan.ToPrettyString(target.Value):target} with a solution {SolutionContainerSystem.ToPrettyString(removedSolution):removedSolution} using a {_entMan.ToPrettyString(uid):using}" ) ;
return true ;
}
static bool EligibleEntity ( [ NotNullWhen ( true ) ] EntityUid ? entity , IEntityManager entMan )
{
// TODO: Does checking for BodyComponent make sense as a "can be hypospray'd" tag?
// In SS13 the hypospray ONLY works on mobs, NOT beakers or anything else.
return entMan . HasComponent < SolutionContainerManagerComponent > ( entity )
& & entMan . HasComponent < MobStateComponent > ( entity ) ;
2021-06-05 00:20:52 -07:00
}
}
}