2022-02-07 00:34:13 +11:00
using Content.Server.Body.Components ;
using Content.Server.Chemistry.Components ;
2023-12-29 04:47:43 -08:00
using Content.Server.Chemistry.Containers.EntitySystems ;
2022-02-07 00:34:13 +11:00
using Content.Shared.Chemistry.Components ;
2023-10-14 09:45:28 -07:00
using Content.Shared.Chemistry.Components.SolutionManager ;
using Content.Shared.Chemistry.EntitySystems ;
2022-02-07 00:34:13 +11:00
using Content.Shared.Chemistry.Reagent ;
using Content.Shared.Database ;
2023-12-29 04:47:43 -08:00
using Content.Shared.DoAfter ;
2022-02-07 00:34:13 +11:00
using Content.Shared.FixedPoint ;
2023-12-29 04:47:43 -08:00
using Content.Shared.Forensics ;
2022-07-10 18:36:53 -07:00
using Content.Shared.IdentityManagement ;
2022-02-07 00:34:13 +11:00
using Content.Shared.Interaction ;
2022-03-13 01:33:23 +13:00
using Content.Shared.Interaction.Events ;
2023-01-13 16:57:10 -08:00
using Content.Shared.Mobs.Components ;
2023-12-28 20:45:42 -07:00
using Content.Shared.Stacks ;
2023-12-29 04:47:43 -08:00
using Content.Shared.Verbs ;
using Robust.Shared.GameStates ;
2023-10-29 04:21:02 +11:00
using Robust.Shared.Player ;
2022-02-07 00:34:13 +11:00
namespace Content.Server.Chemistry.EntitySystems ;
public sealed partial class ChemistrySystem
{
2022-10-26 01:40:06 -05:00
/// <summary>
/// Default transfer amounts for the set-transfer verb.
/// </summary>
2023-12-29 04:47:43 -08:00
public static readonly List < int > TransferAmounts = new ( ) { 1 , 5 , 10 , 15 } ;
2022-02-07 00:34:13 +11:00
private void InitializeInjector ( )
{
2022-10-26 01:40:06 -05:00
SubscribeLocalEvent < InjectorComponent , GetVerbsEvent < AlternativeVerb > > ( AddSetTransferVerbs ) ;
2023-12-29 04:47:43 -08:00
SubscribeLocalEvent < InjectorComponent , SolutionContainerChangedEvent > ( OnSolutionChange ) ;
2023-04-03 13:13:48 +12:00
SubscribeLocalEvent < InjectorComponent , InjectorDoAfterEvent > ( OnInjectDoAfter ) ;
2022-02-07 00:34:13 +11:00
SubscribeLocalEvent < InjectorComponent , ComponentStartup > ( OnInjectorStartup ) ;
SubscribeLocalEvent < InjectorComponent , UseInHandEvent > ( OnInjectorUse ) ;
SubscribeLocalEvent < InjectorComponent , AfterInteractEvent > ( OnInjectorAfterInteract ) ;
SubscribeLocalEvent < InjectorComponent , ComponentGetState > ( OnInjectorGetState ) ;
}
2023-12-29 04:47:43 -08:00
private void AddSetTransferVerbs ( Entity < InjectorComponent > entity , ref GetVerbsEvent < AlternativeVerb > args )
2022-10-26 01:40:06 -05:00
{
if ( ! args . CanAccess | | ! args . CanInteract | | args . Hands = = null )
return ;
2023-08-24 03:10:55 -07:00
if ( ! EntityManager . TryGetComponent ( args . User , out ActorComponent ? actor ) )
2022-10-26 01:40:06 -05:00
return ;
2023-12-29 04:47:43 -08:00
var ( uid , component ) = entity ;
2022-10-26 01:40:06 -05:00
// Add specific transfer verbs according to the container's size
var priority = 0 ;
2023-12-29 04:47:43 -08:00
var user = args . User ;
2022-10-26 01:40:06 -05:00
foreach ( var amount in TransferAmounts )
{
2023-12-29 04:47:43 -08:00
if ( amount < component . MinimumTransferAmount . Int ( ) | | amount > component . MaximumTransferAmount . Int ( ) )
2022-10-26 01:40:06 -05:00
continue ;
AlternativeVerb verb = new ( ) ;
verb . Text = Loc . GetString ( "comp-solution-transfer-verb-amount" , ( "amount" , amount ) ) ;
verb . Category = VerbCategory . SetTransferAmount ;
verb . Act = ( ) = >
{
component . TransferAmount = FixedPoint2 . New ( amount ) ;
2023-12-29 04:47:43 -08:00
_popup . PopupEntity ( Loc . GetString ( "comp-solution-transfer-set-amount" , ( "amount" , amount ) ) , user , user ) ;
2022-10-26 01:40:06 -05:00
} ;
// we want to sort by size, not alphabetically by the verb text.
verb . Priority = priority ;
priority - - ;
args . Verbs . Add ( verb ) ;
}
}
2023-12-29 04:47:43 -08:00
private void UseInjector ( Entity < InjectorComponent > injector , EntityUid target , EntityUid user )
2022-02-17 15:00:41 -07:00
{
2022-02-07 00:34:13 +11:00
// Handle injecting/drawing for solutions
2023-12-29 04:47:43 -08:00
if ( injector . Comp . ToggleState = = SharedInjectorComponent . InjectorToggleMode . Inject )
2022-02-07 00:34:13 +11:00
{
2023-12-29 04:47:43 -08:00
if ( _solutionContainers . TryGetInjectableSolution ( target , out var injectableSolution , out _ ) )
2022-02-07 00:34:13 +11:00
{
2023-12-29 04:47:43 -08:00
TryInject ( injector , target , injectableSolution . Value , user , false ) ;
2022-02-07 00:34:13 +11:00
}
2023-12-29 04:47:43 -08:00
else if ( _solutionContainers . TryGetRefillableSolution ( target , out var refillableSolution , out _ ) )
2022-02-07 00:34:13 +11:00
{
2023-12-29 04:47:43 -08:00
TryInject ( injector , target , refillableSolution . Value , user , true ) ;
2022-02-07 00:34:13 +11:00
}
else if ( TryComp < BloodstreamComponent > ( target , out var bloodstream ) )
{
2023-12-29 04:47:43 -08:00
TryInjectIntoBloodstream ( injector , ( target , bloodstream ) , user ) ;
2022-02-07 00:34:13 +11:00
}
else
{
_popup . PopupEntity ( Loc . GetString ( "injector-component-cannot-transfer-message" ,
2023-02-24 19:01:25 -05:00
( "target" , Identity . Entity ( target , EntityManager ) ) ) , injector , user ) ;
2022-02-07 00:34:13 +11:00
}
}
2023-12-29 04:47:43 -08:00
else if ( injector . Comp . ToggleState = = SharedInjectorComponent . InjectorToggleMode . Draw )
2022-02-07 00:34:13 +11:00
{
2022-08-25 23:56:56 +10:00
// Draw from a bloodstream, if the target has that
2023-12-29 04:47:43 -08:00
if ( TryComp < BloodstreamComponent > ( target , out var stream ) & &
_solutionContainers . ResolveSolution ( target , stream . BloodSolutionName , ref stream . BloodSolution ) )
2022-07-04 20:37:21 -04:00
{
2023-12-29 04:47:43 -08:00
TryDraw ( injector , ( target , stream ) , stream . BloodSolution . Value , user ) ;
2022-07-04 20:37:21 -04:00
return ;
}
2022-08-25 23:56:56 +10:00
// Draw from an object (food, beaker, etc)
2023-12-29 04:47:43 -08:00
if ( _solutionContainers . TryGetDrawableSolution ( target , out var drawableSolution , out _ ) )
2022-02-07 00:34:13 +11:00
{
2023-12-29 04:47:43 -08:00
TryDraw ( injector , target , drawableSolution . Value , user ) ;
2022-02-07 00:34:13 +11:00
}
else
{
_popup . PopupEntity ( Loc . GetString ( "injector-component-cannot-draw-message" ,
2023-12-29 04:47:43 -08:00
( "target" , Identity . Entity ( target , EntityManager ) ) ) , injector . Owner , user ) ;
2022-02-07 00:34:13 +11:00
}
}
}
2023-12-29 04:47:43 -08:00
private void OnSolutionChange ( Entity < InjectorComponent > entity , ref SolutionContainerChangedEvent args )
2022-02-07 00:34:13 +11:00
{
2023-12-29 04:47:43 -08:00
Dirty ( entity ) ;
2022-02-07 00:34:13 +11:00
}
2023-12-29 04:47:43 -08:00
private void OnInjectorGetState ( Entity < InjectorComponent > entity , ref ComponentGetState args )
2022-02-07 00:34:13 +11:00
{
2023-12-29 04:47:43 -08:00
_solutionContainers . TryGetSolution ( entity . Owner , InjectorComponent . SolutionName , out _ , out var solution ) ;
2022-02-07 00:34:13 +11:00
2023-01-12 16:41:40 +13:00
var currentVolume = solution ? . Volume ? ? FixedPoint2 . Zero ;
2022-02-07 00:34:13 +11:00
var maxVolume = solution ? . MaxVolume ? ? FixedPoint2 . Zero ;
2023-12-29 04:47:43 -08:00
args . State = new SharedInjectorComponent . InjectorComponentState ( currentVolume , maxVolume , entity . Comp . ToggleState ) ;
2022-02-07 00:34:13 +11:00
}
2023-12-29 04:47:43 -08:00
private void OnInjectDoAfter ( Entity < InjectorComponent > entity , ref InjectorDoAfterEvent args )
2022-02-07 00:34:13 +11:00
{
2023-04-03 13:13:48 +12:00
if ( args . Cancelled | | args . Handled | | args . Args . Target = = null )
2022-08-25 23:56:56 +10:00
return ;
2022-02-07 00:34:13 +11:00
2023-12-29 04:47:43 -08:00
UseInjector ( entity , args . Args . Target . Value , args . Args . User ) ;
2023-02-24 19:01:25 -05:00
args . Handled = true ;
}
2023-12-29 04:47:43 -08:00
private void OnInjectorAfterInteract ( Entity < InjectorComponent > entity , ref AfterInteractEvent args )
2023-02-24 19:01:25 -05:00
{
if ( args . Handled | | ! args . CanReach )
2022-02-07 00:34:13 +11:00
return ;
//Make sure we have the attacking entity
2023-12-29 04:47:43 -08:00
if ( args . Target is not { Valid : true } target | | ! HasComp < SolutionContainerManagerComponent > ( entity ) )
2022-02-07 00:34:13 +11:00
return ;
// Is the target a mob? If yes, use a do-after to give them time to respond.
2023-02-24 19:01:25 -05:00
if ( HasComp < MobStateComponent > ( target ) | | HasComp < BloodstreamComponent > ( target ) )
2022-02-07 00:34:13 +11:00
{
2022-11-09 16:59:54 -08:00
// Are use using an injector capible of targeting a mob?
2023-12-29 04:47:43 -08:00
if ( entity . Comp . IgnoreMobs )
2022-11-09 16:59:54 -08:00
return ;
2023-12-29 04:47:43 -08:00
InjectDoAfter ( entity , target , args . User ) ;
2022-02-07 00:34:13 +11:00
args . Handled = true ;
return ;
}
2022-02-10 04:08:59 +13:00
2023-12-29 04:47:43 -08:00
UseInjector ( entity , target , args . User ) ;
2022-02-10 04:08:59 +13:00
args . Handled = true ;
2022-02-07 00:34:13 +11:00
}
2023-12-29 04:47:43 -08:00
private void OnInjectorStartup ( Entity < InjectorComponent > entity , ref ComponentStartup args )
2022-02-07 00:34:13 +11:00
{
2023-01-19 03:56:45 +01:00
// ???? why ?????
2023-12-29 04:47:43 -08:00
Dirty ( entity ) ;
2022-02-07 00:34:13 +11:00
}
2023-12-29 04:47:43 -08:00
private void OnInjectorUse ( Entity < InjectorComponent > entity , ref UseInHandEvent args )
2022-02-07 00:34:13 +11:00
{
2022-08-25 23:56:56 +10:00
if ( args . Handled )
return ;
2022-02-07 00:34:13 +11:00
2023-12-29 04:47:43 -08:00
Toggle ( entity , args . User ) ;
2022-02-07 00:34:13 +11:00
args . Handled = true ;
}
/// <summary>
/// Toggle between draw/inject state if applicable
/// </summary>
2023-12-29 04:47:43 -08:00
private void Toggle ( Entity < InjectorComponent > injector , EntityUid user )
2022-02-07 00:34:13 +11:00
{
2023-12-29 04:47:43 -08:00
if ( injector . Comp . InjectOnly )
2022-02-07 00:34:13 +11:00
{
return ;
}
string msg ;
2023-12-29 04:47:43 -08:00
switch ( injector . Comp . ToggleState )
2022-02-07 00:34:13 +11:00
{
case SharedInjectorComponent . InjectorToggleMode . Inject :
2023-12-29 04:47:43 -08:00
injector . Comp . ToggleState = SharedInjectorComponent . InjectorToggleMode . Draw ;
2022-02-07 00:34:13 +11:00
msg = "injector-component-drawing-text" ;
break ;
case SharedInjectorComponent . InjectorToggleMode . Draw :
2023-12-29 04:47:43 -08:00
injector . Comp . ToggleState = SharedInjectorComponent . InjectorToggleMode . Inject ;
2022-02-07 00:34:13 +11:00
msg = "injector-component-injecting-text" ;
break ;
default :
throw new ArgumentOutOfRangeException ( ) ;
}
2023-02-24 19:01:25 -05:00
_popup . PopupEntity ( Loc . GetString ( msg ) , injector , user ) ;
2022-02-07 00:34:13 +11:00
}
/// <summary>
/// Send informative pop-up messages and wait for a do-after to complete.
/// </summary>
2023-12-29 04:47:43 -08:00
private void InjectDoAfter ( Entity < InjectorComponent > injector , EntityUid target , EntityUid user )
2022-02-07 00:34:13 +11:00
{
// Create a pop-up for the user
2022-12-19 10:41:47 +13:00
_popup . PopupEntity ( Loc . GetString ( "injector-component-injecting-user" ) , target , user ) ;
2022-02-07 00:34:13 +11:00
2023-12-29 04:47:43 -08:00
if ( ! _solutionContainers . TryGetSolution ( injector . Owner , InjectorComponent . SolutionName , out _ , out var solution ) )
2022-02-07 00:34:13 +11:00
return ;
2023-12-29 04:47:43 -08:00
var actualDelay = MathF . Max ( injector . Comp . Delay , 1f ) ;
2022-10-26 01:40:06 -05:00
2023-04-18 10:23:54 -04:00
// Injections take 0.5 seconds longer per additional 5u
2023-12-29 04:47:43 -08:00
actualDelay + = ( float ) injector . Comp . TransferAmount / injector . Comp . Delay - 0.5f ;
2022-10-26 01:40:06 -05:00
2023-02-26 00:33:06 -05:00
var isTarget = user ! = target ;
if ( isTarget )
2022-02-07 00:34:13 +11:00
{
// Create a pop-up for the target
2022-07-31 15:43:38 +12:00
var userName = Identity . Entity ( user , EntityManager ) ;
2022-02-07 00:34:13 +11:00
_popup . PopupEntity ( Loc . GetString ( "injector-component-injecting-target" ,
2022-12-19 10:41:47 +13:00
( "user" , userName ) ) , user , target ) ;
2022-02-07 00:34:13 +11:00
// Check if the target is incapacitated or in combat mode and modify time accordingly.
2022-08-25 23:56:56 +10:00
if ( _mobState . IsIncapacitated ( target ) )
2022-02-07 00:34:13 +11:00
{
2023-04-18 10:23:54 -04:00
actualDelay / = 2.5f ;
2022-02-07 00:34:13 +11:00
}
2022-08-25 23:56:56 +10:00
else if ( _combat . IsInCombatMode ( target ) )
2022-02-07 00:34:13 +11:00
{
// Slightly increase the delay when the target is in combat mode. Helps prevents cheese injections in
// combat with fast syringes & lag.
actualDelay + = 1 ;
}
// Add an admin log, using the "force feed" log type. It's not quite feeding, but the effect is the same.
2023-12-29 04:47:43 -08:00
if ( injector . Comp . ToggleState = = SharedInjectorComponent . InjectorToggleMode . Inject )
2022-02-07 00:34:13 +11:00
{
2022-05-28 23:41:17 -07:00
_adminLogger . Add ( LogType . ForceFeed ,
2022-02-07 00:34:13 +11:00
$"{EntityManager.ToPrettyString(user):user} is attempting to inject {EntityManager.ToPrettyString(target):target} with a solution {SolutionContainerSystem.ToPrettyString(solution):solution}" ) ;
}
2024-01-02 10:47:31 -08:00
else
{
_adminLogger . Add ( LogType . ForceFeed ,
$"{EntityManager.ToPrettyString(user):user} is attempting to draw {injector.Comp.TransferAmount.ToString()} units from {EntityManager.ToPrettyString(target):target}" ) ;
}
2022-02-07 00:34:13 +11:00
}
else
{
// Self-injections take half as long.
actualDelay / = 2 ;
2023-12-29 04:47:43 -08:00
if ( injector . Comp . ToggleState = = SharedInjectorComponent . InjectorToggleMode . Inject )
2024-01-02 10:47:31 -08:00
{
_adminLogger . Add ( LogType . Ingestion ,
$"{EntityManager.ToPrettyString(user):user} is attempting to inject themselves with a solution {SolutionContainerSystem.ToPrettyString(solution):solution}." ) ;
}
else
{
_adminLogger . Add ( LogType . ForceFeed ,
$"{EntityManager.ToPrettyString(user):user} is attempting to draw {injector.Comp.TransferAmount.ToString()} units from themselves." ) ;
}
2022-02-07 00:34:13 +11:00
}
2023-12-29 04:47:43 -08:00
_doAfter . TryStartDoAfter ( new DoAfterArgs ( EntityManager , user , actualDelay , new InjectorDoAfterEvent ( ) , injector . Owner , target : target , used : injector . Owner )
2022-02-07 00:34:13 +11:00
{
BreakOnUserMove = true ,
BreakOnDamage = true ,
BreakOnTargetMove = true ,
2023-04-03 13:13:48 +12:00
MovementThreshold = 0.1f ,
2022-02-07 00:34:13 +11:00
} ) ;
}
2023-12-29 04:47:43 -08:00
private void TryInjectIntoBloodstream ( Entity < InjectorComponent > injector , Entity < BloodstreamComponent > target , EntityUid user )
2022-02-07 00:34:13 +11:00
{
// Get transfer amount. May be smaller than _transferAmount if not enough room
2023-12-29 04:47:43 -08:00
if ( ! _solutionContainers . ResolveSolution ( target . Owner , target . Comp . ChemicalSolutionName , ref target . Comp . ChemicalSolution , out var chemSolution ) )
{
_popup . PopupEntity ( Loc . GetString ( "injector-component-cannot-inject-message" , ( "target" , Identity . Entity ( target , EntityManager ) ) ) , injector . Owner , user ) ;
return ;
}
2022-02-07 00:34:13 +11:00
2023-12-29 04:47:43 -08:00
var realTransferAmount = FixedPoint2 . Min ( injector . Comp . TransferAmount , chemSolution . AvailableVolume ) ;
2022-02-07 00:34:13 +11:00
if ( realTransferAmount < = 0 )
{
2023-12-29 04:47:43 -08:00
_popup . PopupEntity ( Loc . GetString ( "injector-component-cannot-inject-message" , ( "target" , Identity . Entity ( target , EntityManager ) ) ) , injector . Owner , user ) ;
2022-02-07 00:34:13 +11:00
return ;
}
// Move units from attackSolution to targetSolution
2023-12-29 04:47:43 -08:00
var removedSolution = _solutionContainers . SplitSolution ( target . Comp . ChemicalSolution . Value , realTransferAmount ) ;
2022-02-07 00:34:13 +11:00
2023-12-29 04:47:43 -08:00
_blood . TryAddToChemicals ( target , removedSolution , target . Comp ) ;
2022-02-07 00:34:13 +11:00
2023-02-24 19:01:25 -05:00
_reactiveSystem . DoEntityReaction ( target , removedSolution , ReactionMethod . Injection ) ;
2022-02-07 00:34:13 +11:00
_popup . PopupEntity ( Loc . GetString ( "injector-component-inject-success-message" ,
2023-01-12 16:41:40 +13:00
( "amount" , removedSolution . Volume ) ,
2023-12-29 04:47:43 -08:00
( "target" , Identity . Entity ( target , EntityManager ) ) ) , injector . Owner , user ) ;
2022-02-07 00:34:13 +11:00
2023-12-29 04:47:43 -08:00
Dirty ( injector ) ;
AfterInject ( injector , target ) ;
2022-02-07 00:34:13 +11:00
}
2023-12-29 04:47:43 -08:00
private void TryInject ( Entity < InjectorComponent > injector , EntityUid targetEntity , Entity < SolutionComponent > targetSolution , EntityUid user , bool asRefill )
2022-02-07 00:34:13 +11:00
{
2023-12-29 04:47:43 -08:00
if ( ! _solutionContainers . TryGetSolution ( injector . Owner , InjectorComponent . SolutionName , out var soln , out var solution ) | | solution . Volume = = 0 )
2022-02-07 00:34:13 +11:00
return ;
// Get transfer amount. May be smaller than _transferAmount if not enough room
2023-12-29 04:47:43 -08:00
var realTransferAmount = FixedPoint2 . Min ( injector . Comp . TransferAmount , targetSolution . Comp . Solution . AvailableVolume ) ;
2022-02-07 00:34:13 +11:00
if ( realTransferAmount < = 0 )
{
2022-07-10 18:36:53 -07:00
_popup . PopupEntity ( Loc . GetString ( "injector-component-target-already-full-message" , ( "target" , Identity . Entity ( targetEntity , EntityManager ) ) ) ,
2023-12-29 04:47:43 -08:00
injector . Owner , user ) ;
2022-02-07 00:34:13 +11:00
return ;
}
// Move units from attackSolution to targetSolution
2023-05-06 10:23:05 +03:00
Solution removedSolution ;
2023-08-24 03:10:55 -07:00
if ( TryComp < StackComponent > ( targetEntity , out var stack ) )
2023-12-29 04:47:43 -08:00
removedSolution = _solutionContainers . SplitStackSolution ( soln . Value , realTransferAmount , stack . Count ) ;
2023-05-06 10:23:05 +03:00
else
2023-12-29 04:47:43 -08:00
removedSolution = _solutionContainers . SplitSolution ( soln . Value , realTransferAmount ) ;
2022-02-07 00:34:13 +11:00
2023-02-24 19:01:25 -05:00
_reactiveSystem . DoEntityReaction ( targetEntity , removedSolution , ReactionMethod . Injection ) ;
2022-02-07 00:34:13 +11:00
if ( ! asRefill )
2023-12-29 04:47:43 -08:00
_solutionContainers . Inject ( targetEntity , targetSolution , removedSolution ) ;
2022-02-07 00:34:13 +11:00
else
2023-12-29 04:47:43 -08:00
_solutionContainers . Refill ( targetEntity , targetSolution , removedSolution ) ;
2022-02-07 00:34:13 +11:00
_popup . PopupEntity ( Loc . GetString ( "injector-component-transfer-success-message" ,
2023-01-12 16:41:40 +13:00
( "amount" , removedSolution . Volume ) ,
2023-12-29 04:47:43 -08:00
( "target" , Identity . Entity ( targetEntity , EntityManager ) ) ) , injector . Owner , user ) ;
2022-02-07 00:34:13 +11:00
2023-12-29 04:47:43 -08:00
Dirty ( injector ) ;
AfterInject ( injector , targetEntity ) ;
2022-02-07 00:34:13 +11:00
}
2023-12-29 04:47:43 -08:00
private void AfterInject ( Entity < InjectorComponent > injector , EntityUid target )
2022-02-07 00:34:13 +11:00
{
// Automatically set syringe to draw after completely draining it.
2023-12-29 04:47:43 -08:00
if ( _solutionContainers . TryGetSolution ( injector . Owner , InjectorComponent . SolutionName , out _ , out var solution ) & & solution . Volume = = 0 )
2022-02-07 00:34:13 +11:00
{
2023-12-29 04:47:43 -08:00
injector . Comp . ToggleState = SharedInjectorComponent . InjectorToggleMode . Draw ;
2022-02-07 00:34:13 +11:00
}
2023-12-15 04:52:55 -05:00
// Leave some DNA from the injectee on it
var ev = new TransferDnaEvent { Donor = target , Recipient = injector } ;
RaiseLocalEvent ( target , ref ev ) ;
2022-02-07 00:34:13 +11:00
}
2023-12-29 04:47:43 -08:00
private void AfterDraw ( Entity < InjectorComponent > injector , EntityUid target )
2022-02-07 00:34:13 +11:00
{
// Automatically set syringe to inject after completely filling it.
2023-12-29 04:47:43 -08:00
if ( _solutionContainers . TryGetSolution ( injector . Owner , InjectorComponent . SolutionName , out _ , out var solution ) & & solution . AvailableVolume = = 0 )
2022-02-07 00:34:13 +11:00
{
2023-12-29 04:47:43 -08:00
injector . Comp . ToggleState = SharedInjectorComponent . InjectorToggleMode . Inject ;
2022-02-07 00:34:13 +11:00
}
2023-12-15 04:52:55 -05:00
// Leave some DNA from the drawee on it
var ev = new TransferDnaEvent { Donor = target , Recipient = injector } ;
RaiseLocalEvent ( target , ref ev ) ;
2022-02-07 00:34:13 +11:00
}
2023-12-29 04:47:43 -08:00
private void TryDraw ( Entity < InjectorComponent > injector , Entity < BloodstreamComponent ? > target , Entity < SolutionComponent > targetSolution , EntityUid user )
2022-02-07 00:34:13 +11:00
{
2023-12-29 04:47:43 -08:00
if ( ! _solutionContainers . TryGetSolution ( injector . Owner , InjectorComponent . SolutionName , out var soln , out var solution ) | | solution . AvailableVolume = = 0 )
2022-02-07 00:34:13 +11:00
{
return ;
}
2022-11-03 17:16:31 -07:00
// Get transfer amount. May be smaller than _transferAmount if not enough room, also make sure there's room in the injector
2023-12-29 04:47:43 -08:00
var realTransferAmount = FixedPoint2 . Min ( injector . Comp . TransferAmount , targetSolution . Comp . Solution . Volume , solution . AvailableVolume ) ;
2022-02-07 00:34:13 +11:00
if ( realTransferAmount < = 0 )
{
2023-12-29 04:47:43 -08:00
_popup . PopupEntity ( Loc . GetString ( "injector-component-target-is-empty-message" , ( "target" , Identity . Entity ( target , EntityManager ) ) ) ,
injector . Owner , user ) ;
2022-02-07 00:34:13 +11:00
return ;
}
2022-07-17 02:32:19 -04:00
// We have some snowflaked behavior for streams.
2023-12-29 04:47:43 -08:00
if ( target . Comp ! = null )
2022-07-04 20:37:21 -04:00
{
2023-12-29 04:47:43 -08:00
DrawFromBlood ( injector , ( target . Owner , target . Comp ) , soln . Value , realTransferAmount , user ) ;
2022-07-04 20:37:21 -04:00
return ;
}
2022-02-07 00:34:13 +11:00
// Move units from attackSolution to targetSolution
2023-12-29 04:47:43 -08:00
var removedSolution = _solutionContainers . Draw ( target . Owner , targetSolution , realTransferAmount ) ;
2022-02-07 00:34:13 +11:00
2023-12-29 04:47:43 -08:00
if ( ! _solutionContainers . TryAddSolution ( soln . Value , removedSolution ) )
2022-02-07 00:34:13 +11:00
{
return ;
}
_popup . PopupEntity ( Loc . GetString ( "injector-component-draw-success-message" ,
2023-01-12 16:41:40 +13:00
( "amount" , removedSolution . Volume ) ,
2023-12-29 04:47:43 -08:00
( "target" , Identity . Entity ( target , EntityManager ) ) ) , injector . Owner , user ) ;
2022-02-07 00:34:13 +11:00
2023-12-29 04:47:43 -08:00
Dirty ( injector ) ;
AfterDraw ( injector , target ) ;
2022-02-07 00:34:13 +11:00
}
2023-12-29 04:47:43 -08:00
private void DrawFromBlood ( Entity < InjectorComponent > injector , Entity < BloodstreamComponent > target , Entity < SolutionComponent > injectorSolution , FixedPoint2 transferAmount , EntityUid user )
2022-07-04 20:37:21 -04:00
{
2022-07-17 02:32:19 -04:00
var drawAmount = ( float ) transferAmount ;
2023-12-29 04:47:43 -08:00
if ( _solutionContainers . ResolveSolution ( target . Owner , target . Comp . ChemicalSolutionName , ref target . Comp . ChemicalSolution ) )
2022-07-04 20:37:21 -04:00
{
2023-12-29 04:47:43 -08:00
var chemTemp = _solutionContainers . SplitSolution ( target . Comp . ChemicalSolution . Value , drawAmount * 0.15f ) ;
_solutionContainers . TryAddSolution ( injectorSolution , chemTemp ) ;
drawAmount - = ( float ) chemTemp . Volume ;
2022-07-04 20:37:21 -04:00
}
2023-12-29 04:47:43 -08:00
if ( _solutionContainers . ResolveSolution ( target . Owner , target . Comp . BloodSolutionName , ref target . Comp . BloodSolution ) )
{
var bloodTemp = _solutionContainers . SplitSolution ( target . Comp . BloodSolution . Value , drawAmount ) ;
_solutionContainers . TryAddSolution ( injectorSolution , bloodTemp ) ;
}
2022-07-04 20:37:21 -04:00
_popup . PopupEntity ( Loc . GetString ( "injector-component-draw-success-message" ,
2022-07-17 02:32:19 -04:00
( "amount" , transferAmount ) ,
2023-12-29 04:47:43 -08:00
( "target" , Identity . Entity ( target , EntityManager ) ) ) , injector . Owner , user ) ;
2022-07-04 20:37:21 -04:00
2023-12-29 04:47:43 -08:00
Dirty ( injector ) ;
AfterDraw ( injector , target ) ;
2022-02-07 00:34:13 +11:00
}
}