2021-07-25 00:53:53 -07:00
using System ;
2021-02-03 14:05:31 +01:00
using System.Threading.Tasks ;
2021-10-29 13:40:15 +01:00
using Content.Server.Chemistry.Components.SolutionManager ;
using Content.Server.Chemistry.EntitySystems ;
2021-07-25 00:53:53 -07:00
using Content.Server.UserInterface ;
using Content.Shared.Chemistry ;
2021-09-06 15:49:44 +02:00
using Content.Shared.Chemistry.Components ;
2021-11-03 16:48:03 -07:00
using Content.Shared.FixedPoint ;
2021-06-09 22:19:39 +02:00
using Content.Shared.Interaction ;
using Content.Shared.Interaction.Helpers ;
2021-09-26 15:18:45 +02:00
using Content.Shared.Popups ;
2021-07-25 00:53:53 -07:00
using Robust.Server.GameObjects ;
2021-02-03 14:05:31 +01:00
using Robust.Shared.GameObjects ;
2021-12-03 12:23:18 +01:00
using Robust.Shared.IoC ;
2021-02-03 14:05:31 +01:00
using Robust.Shared.Localization ;
2021-03-05 01:08:38 +01:00
using Robust.Shared.Serialization.Manager.Attributes ;
2021-02-03 14:05:31 +01:00
using Robust.Shared.ViewVariables ;
2021-06-09 22:19:39 +02:00
namespace Content.Server.Chemistry.Components
2021-02-03 14:05:31 +01:00
{
/// <summary>
/// Gives click behavior for transferring to/from other reagent containers.
/// </summary>
[RegisterComponent]
public sealed class SolutionTransferComponent : Component , IAfterInteract
{
2021-12-05 18:09:01 +01:00
[Dependency] private readonly IEntityManager _entities = default ! ;
2021-02-03 14:05:31 +01:00
// Behavior is as such:
// If it's a reagent tank, TAKE reagent.
// If it's anything else, GIVE reagent.
// Of course, only if possible.
/// <summary>
/// The amount of solution to be transferred from this solution when clicking on other solutions with it.
/// </summary>
2021-03-05 01:08:38 +01:00
[DataField("transferAmount")]
2021-02-03 14:05:31 +01:00
[ViewVariables(VVAccess.ReadWrite)]
2021-11-03 16:48:03 -07:00
public FixedPoint2 TransferAmount { get ; set ; } = FixedPoint2 . New ( 5 ) ;
2021-02-03 14:05:31 +01:00
2021-07-25 00:53:53 -07:00
/// <summary>
/// The minimum amount of solution that can be transferred at once from this solution.
/// </summary>
[DataField("minTransferAmount")]
[ViewVariables(VVAccess.ReadWrite)]
2021-11-03 16:48:03 -07:00
public FixedPoint2 MinimumTransferAmount { get ; set ; } = FixedPoint2 . New ( 5 ) ;
2021-07-25 00:53:53 -07:00
/// <summary>
/// The maximum amount of solution that can be transferred at once from this solution.
/// </summary>
[DataField("maxTransferAmount")]
[ViewVariables(VVAccess.ReadWrite)]
2021-11-03 16:48:03 -07:00
public FixedPoint2 MaximumTransferAmount { get ; set ; } = FixedPoint2 . New ( 50 ) ;
2021-07-25 00:53:53 -07:00
2021-02-03 14:05:31 +01:00
/// <summary>
/// Can this entity take reagent from reagent tanks?
/// </summary>
2021-03-05 01:08:38 +01:00
[DataField("canReceive")]
2021-02-03 14:05:31 +01:00
[ViewVariables(VVAccess.ReadWrite)]
2021-03-05 01:08:38 +01:00
public bool CanReceive { get ; set ; } = true ;
2021-02-03 14:05:31 +01:00
/// <summary>
/// Can this entity give reagent to other reagent containers?
/// </summary>
2021-03-05 01:08:38 +01:00
[DataField("canSend")]
2021-02-03 14:05:31 +01:00
[ViewVariables(VVAccess.ReadWrite)]
2021-03-05 01:08:38 +01:00
public bool CanSend { get ; set ; } = true ;
2021-02-03 14:05:31 +01:00
2021-07-25 00:53:53 -07:00
/// <summary>
/// Whether you're allowed to change the transfer amount.
/// </summary>
[DataField("canChangeTransferAmount")]
[ViewVariables(VVAccess.ReadWrite)]
public bool CanChangeTransferAmount { get ; set ; } = false ;
2021-10-05 14:29:03 +11:00
[ViewVariables] public BoundUserInterface ? UserInterface = > Owner . GetUIOrNull ( TransferAmountUiKey . Key ) ;
2021-07-25 00:53:53 -07:00
protected override void Initialize ( )
{
base . Initialize ( ) ;
if ( UserInterface ! = null )
{
UserInterface . OnReceiveMessage + = UserInterfaceOnReceiveMessage ;
}
}
public void UserInterfaceOnReceiveMessage ( ServerBoundUserInterfaceMessage serverMsg )
{
2021-12-06 15:34:46 +01:00
if ( serverMsg . Session . AttachedEntity = = null )
return ;
2021-07-25 00:53:53 -07:00
switch ( serverMsg . Message )
{
case TransferAmountSetValueMessage svm :
var sval = svm . Value . Float ( ) ;
var amount = Math . Clamp ( sval , MinimumTransferAmount . Float ( ) ,
MaximumTransferAmount . Float ( ) ) ;
2021-12-06 15:34:46 +01:00
serverMsg . Session . AttachedEntity . Value . PopupMessage ( Loc . GetString ( "comp-solution-transfer-set-amount" ,
2021-09-06 15:49:44 +02:00
( "amount" , amount ) ) ) ;
2021-11-03 16:48:03 -07:00
SetTransferAmount ( FixedPoint2 . New ( amount ) ) ;
2021-07-25 00:53:53 -07:00
break ;
}
}
2021-11-03 16:48:03 -07:00
public void SetTransferAmount ( FixedPoint2 amount )
2021-07-25 00:53:53 -07:00
{
2021-11-03 16:48:03 -07:00
amount = FixedPoint2 . New ( Math . Clamp ( amount . Int ( ) , MinimumTransferAmount . Int ( ) ,
2021-09-06 15:49:44 +02:00
MaximumTransferAmount . Int ( ) ) ) ;
2021-07-25 00:53:53 -07:00
TransferAmount = amount ;
}
2021-02-03 14:05:31 +01:00
async Task < bool > IAfterInteract . AfterInteract ( AfterInteractEventArgs eventArgs )
{
2021-09-06 15:49:44 +02:00
var solutionsSys = EntitySystem . Get < SolutionContainerSystem > ( ) ;
2022-02-05 15:39:01 +13:00
if ( ! eventArgs . CanReach | | eventArgs . Target = = null )
2021-02-03 14:05:31 +01:00
return false ;
2021-12-05 18:09:01 +01:00
var target = eventArgs . Target ! . Value ;
2021-02-03 14:05:31 +01:00
2022-02-12 16:18:35 -06:00
//Special case for reagent tanks, because normally clicking another container will give solution, not take it.
if ( CanReceive & & ! _entities . HasComponent < RefillableSolutionComponent > ( target ) // target must not be refillable (e.g. Reagent Tanks)
& & solutionsSys . TryGetDrainableSolution ( target , out var targetDrain ) // target must be drainable
& & _entities . TryGetComponent ( Owner , out RefillableSolutionComponent refillComp )
& & solutionsSys . TryGetRefillableSolution ( Owner , out var ownerRefill , refillable : refillComp ) )
2021-09-06 15:49:44 +02:00
2021-02-03 14:05:31 +01:00
{
2021-12-21 19:52:59 -07:00
2022-02-12 16:18:35 -06:00
var transferAmount = TransferAmount ; // This is the player-configurable transfer amount of "Owner," not the target reagent tank.
if ( _entities . TryGetComponent ( Owner , out RefillableSolutionComponent ? refill ) & & refill . MaxRefill ! = null ) // Owner is the entity receiving solution from target.
2021-12-21 19:52:59 -07:00
{
2022-02-12 16:18:35 -06:00
transferAmount = FixedPoint2 . Min ( transferAmount , ( FixedPoint2 ) refill . MaxRefill ) ; // if the receiver has a smaller transfer limit, use that instead
2021-12-21 19:52:59 -07:00
}
2022-02-12 16:18:35 -06:00
var transferred = DoTransfer ( eventArgs . User , target , targetDrain , Owner , ownerRefill , transferAmount ) ;
2021-02-03 14:05:31 +01:00
if ( transferred > 0 )
{
2021-09-06 15:49:44 +02:00
var toTheBrim = ownerRefill . AvailableVolume = = 0 ;
2021-02-03 14:05:31 +01:00
var msg = toTheBrim
2021-07-25 00:53:53 -07:00
? "comp-solution-transfer-fill-fully"
: "comp-solution-transfer-fill-normal" ;
2021-02-03 14:05:31 +01:00
2021-09-06 15:49:44 +02:00
target . PopupMessage ( eventArgs . User ,
Loc . GetString ( msg , ( "owner" , eventArgs . Target ) , ( "amount" , transferred ) , ( "target" , Owner ) ) ) ;
2021-02-03 14:05:31 +01:00
return true ;
}
}
2022-02-12 16:18:35 -06:00
// if target is refillable, and owner is drainable
2021-12-05 18:09:01 +01:00
if ( CanSend & & solutionsSys . TryGetRefillableSolution ( target , out var targetRefill )
2021-12-03 15:53:09 +01:00
& & solutionsSys . TryGetDrainableSolution ( Owner , out var ownerDrain ) )
2021-02-03 14:05:31 +01:00
{
2021-12-21 19:52:59 -07:00
var transferAmount = TransferAmount ;
if ( _entities . TryGetComponent ( target , out RefillableSolutionComponent ? refill ) & & refill . MaxRefill ! = null )
{
transferAmount = FixedPoint2 . Min ( transferAmount , ( FixedPoint2 ) refill . MaxRefill ) ;
}
var transferred = DoTransfer ( eventArgs . User , Owner , ownerDrain , target , targetRefill , transferAmount ) ;
2021-02-03 14:05:31 +01:00
if ( transferred > 0 )
{
2021-06-21 02:13:54 +02:00
Owner . PopupMessage ( eventArgs . User ,
2021-09-06 15:49:44 +02:00
Loc . GetString ( "comp-solution-transfer-transfer-solution" ,
( "amount" , transferred ) ,
( "target" , target ) ) ) ;
2021-02-03 14:05:31 +01:00
return true ;
}
}
2022-02-15 23:19:53 +13:00
return false ;
2021-02-03 14:05:31 +01:00
}
/// <returns>The actual amount transferred.</returns>
2021-12-05 18:09:01 +01:00
private static FixedPoint2 DoTransfer ( EntityUid user ,
EntityUid sourceEntity ,
2021-09-06 15:49:44 +02:00
Solution source ,
2021-12-05 18:09:01 +01:00
EntityUid targetEntity ,
2021-09-06 15:49:44 +02:00
Solution target ,
2021-11-03 16:48:03 -07:00
FixedPoint2 amount )
2021-02-03 14:05:31 +01:00
{
2021-09-06 15:49:44 +02:00
2021-02-03 14:05:31 +01:00
if ( source . DrainAvailable = = 0 )
{
2021-09-06 15:49:44 +02:00
sourceEntity . PopupMessage ( user ,
Loc . GetString ( "comp-solution-transfer-is-empty" , ( "target" , sourceEntity ) ) ) ;
2021-11-03 16:48:03 -07:00
return FixedPoint2 . Zero ;
2021-02-03 14:05:31 +01:00
}
2021-09-06 15:49:44 +02:00
if ( target . AvailableVolume = = 0 )
2021-02-03 14:05:31 +01:00
{
2021-09-06 15:49:44 +02:00
targetEntity . PopupMessage ( user ,
Loc . GetString ( "comp-solution-transfer-is-full" , ( "target" , targetEntity ) ) ) ;
2021-11-03 16:48:03 -07:00
return FixedPoint2 . Zero ;
2021-02-03 14:05:31 +01:00
}
2021-12-21 19:52:59 -07:00
var actualAmount = FixedPoint2 . Min ( amount , FixedPoint2 . Min ( source . DrainAvailable , target . AvailableVolume ) ) ;
2021-02-03 14:05:31 +01:00
2021-12-03 15:53:09 +01:00
var solution = EntitySystem . Get < SolutionContainerSystem > ( ) . Drain ( sourceEntity , source , actualAmount ) ;
EntitySystem . Get < SolutionContainerSystem > ( ) . Refill ( targetEntity , target , solution ) ;
2021-02-03 14:05:31 +01:00
return actualAmount ;
}
}
}