2022-10-04 02:57:32 +02:00
using Content.Server.Administration.Logs ;
2021-10-05 14:29:03 +11:00
using Content.Server.Chemistry.Components ;
2023-12-29 04:47:43 -08:00
using Content.Server.Chemistry.Containers.EntitySystems ;
2022-10-04 02:57:32 +02:00
using Content.Shared.Chemistry ;
using Content.Shared.Chemistry.Dispenser ;
2023-10-14 09:45:28 -07:00
using Content.Shared.Chemistry.EntitySystems ;
2023-09-05 09:55:10 +12:00
using Content.Shared.Chemistry.Reagent ;
2022-10-04 02:57:32 +02:00
using Content.Shared.Containers.ItemSlots ;
using Content.Shared.Database ;
2023-02-19 01:03:06 +00:00
using Content.Shared.Emag.Components ;
2022-02-17 21:43:24 -05:00
using Content.Shared.Emag.Systems ;
2021-09-06 15:49:44 +02:00
using JetBrains.Annotations ;
2023-11-27 22:12:34 +11:00
using Robust.Server.Audio ;
2022-10-04 02:57:32 +02:00
using Robust.Server.GameObjects ;
using Robust.Shared.Audio ;
2021-11-02 09:04:07 +00:00
using Robust.Shared.Containers ;
2022-10-04 02:57:32 +02:00
using Robust.Shared.Prototypes ;
2023-12-29 04:47:43 -08:00
using System.Linq ;
2021-09-06 15:49:44 +02:00
namespace Content.Server.Chemistry.EntitySystems
{
2022-10-04 02:57:32 +02:00
/// <summary>
/// Contains all the server-side logic for reagent dispensers.
/// <seealso cref="ReagentDispenserComponent"/>
/// </summary>
2021-09-06 15:49:44 +02:00
[UsedImplicitly]
2022-10-04 02:57:32 +02:00
public sealed class ReagentDispenserSystem : EntitySystem
2021-09-06 15:49:44 +02:00
{
2022-10-04 02:57:32 +02:00
[Dependency] private readonly AudioSystem _audioSystem = default ! ;
[Dependency] private readonly SolutionContainerSystem _solutionContainerSystem = default ! ;
[Dependency] private readonly ItemSlotsSystem _itemSlotsSystem = default ! ;
[Dependency] private readonly UserInterfaceSystem _userInterfaceSystem = default ! ;
[Dependency] private readonly IPrototypeManager _prototypeManager = default ! ;
[Dependency] private readonly IAdminLogManager _adminLogger = default ! ;
2021-09-06 15:49:44 +02:00
public override void Initialize ( )
{
base . Initialize ( ) ;
2022-10-04 02:57:32 +02:00
2023-10-19 12:34:31 -07:00
SubscribeLocalEvent < ReagentDispenserComponent , ComponentStartup > ( SubscribeUpdateUiState ) ;
2023-12-29 04:47:43 -08:00
SubscribeLocalEvent < ReagentDispenserComponent , SolutionContainerChangedEvent > ( SubscribeUpdateUiState ) ;
2023-10-19 12:34:31 -07:00
SubscribeLocalEvent < ReagentDispenserComponent , EntInsertedIntoContainerMessage > ( SubscribeUpdateUiState ) ;
SubscribeLocalEvent < ReagentDispenserComponent , EntRemovedFromContainerMessage > ( SubscribeUpdateUiState ) ;
SubscribeLocalEvent < ReagentDispenserComponent , BoundUIOpenedEvent > ( SubscribeUpdateUiState ) ;
2022-02-17 21:43:24 -05:00
SubscribeLocalEvent < ReagentDispenserComponent , GotEmaggedEvent > ( OnEmagged ) ;
2022-10-04 02:57:32 +02:00
SubscribeLocalEvent < ReagentDispenserComponent , ReagentDispenserSetDispenseAmountMessage > ( OnSetDispenseAmountMessage ) ;
SubscribeLocalEvent < ReagentDispenserComponent , ReagentDispenserDispenseReagentMessage > ( OnDispenseReagentMessage ) ;
SubscribeLocalEvent < ReagentDispenserComponent , ReagentDispenserClearContainerSolutionMessage > ( OnClearContainerSolutionMessage ) ;
}
2023-10-19 12:34:31 -07:00
private void SubscribeUpdateUiState < T > ( Entity < ReagentDispenserComponent > ent , ref T ev )
2022-10-04 02:57:32 +02:00
{
2023-10-19 12:34:31 -07:00
UpdateUiState ( ent ) ;
}
private void UpdateUiState ( Entity < ReagentDispenserComponent > reagentDispenser )
{
var outputContainer = _itemSlotsSystem . GetItemOrNull ( reagentDispenser , SharedReagentDispenser . OutputSlotName ) ;
2022-10-04 02:57:32 +02:00
var outputContainerInfo = BuildOutputContainerInfo ( outputContainer ) ;
var inventory = GetInventory ( reagentDispenser ) ;
2023-10-19 12:34:31 -07:00
var state = new ReagentDispenserBoundUserInterfaceState ( outputContainerInfo , inventory , reagentDispenser . Comp . DispenseAmount ) ;
_userInterfaceSystem . TrySetUiState ( reagentDispenser , ReagentDispenserUiKey . Key , state ) ;
2022-10-04 02:57:32 +02:00
}
private ContainerInfo ? BuildOutputContainerInfo ( EntityUid ? container )
{
if ( container is not { Valid : true } )
return null ;
2023-12-29 04:47:43 -08:00
if ( _solutionContainerSystem . TryGetFitsInDispenser ( container . Value , out _ , out var solution ) )
2022-10-04 02:57:32 +02:00
{
2023-09-05 09:55:10 +12:00
return new ContainerInfo ( Name ( container . Value ) , solution . Volume , solution . MaxVolume )
{
Reagents = solution . Contents
} ;
2022-10-04 02:57:32 +02:00
}
return null ;
}
2023-10-19 12:34:31 -07:00
private List < ReagentId > GetInventory ( Entity < ReagentDispenserComponent > ent )
2022-10-04 02:57:32 +02:00
{
2023-10-19 12:34:31 -07:00
var reagentDispenser = ent . Comp ;
2023-09-05 09:55:10 +12:00
var inventory = new List < ReagentId > ( ) ;
2022-10-04 02:57:32 +02:00
if ( reagentDispenser . PackPrototypeId is not null
& & _prototypeManager . TryIndex ( reagentDispenser . PackPrototypeId , out ReagentDispenserInventoryPrototype ? packPrototype ) )
{
2023-09-05 09:55:10 +12:00
inventory . AddRange ( packPrototype . Inventory . Select ( x = > new ReagentId ( x , null ) ) ) ;
2022-10-04 02:57:32 +02:00
}
2023-10-19 12:34:31 -07:00
if ( HasComp < EmaggedComponent > ( ent )
2022-10-04 02:57:32 +02:00
& & reagentDispenser . EmagPackPrototypeId is not null
& & _prototypeManager . TryIndex ( reagentDispenser . EmagPackPrototypeId , out ReagentDispenserInventoryPrototype ? emagPackPrototype ) )
{
2023-09-05 09:55:10 +12:00
inventory . AddRange ( emagPackPrototype . Inventory . Select ( x = > new ReagentId ( x , null ) ) ) ;
2022-10-04 02:57:32 +02:00
}
return inventory ;
2022-02-17 21:43:24 -05:00
}
2023-10-19 12:34:31 -07:00
private void OnEmagged ( Entity < ReagentDispenserComponent > reagentDispenser , ref GotEmaggedEvent args )
2022-02-17 21:43:24 -05:00
{
2023-02-19 01:03:06 +00:00
// adding component manually to have correct state
2023-10-19 12:34:31 -07:00
EntityManager . AddComponent < EmaggedComponent > ( reagentDispenser ) ;
2023-02-19 01:03:06 +00:00
UpdateUiState ( reagentDispenser ) ;
args . Handled = true ;
2021-09-06 15:49:44 +02:00
}
2022-10-04 02:57:32 +02:00
2023-10-19 12:34:31 -07:00
private void OnSetDispenseAmountMessage ( Entity < ReagentDispenserComponent > reagentDispenser , ref ReagentDispenserSetDispenseAmountMessage message )
2022-10-04 02:57:32 +02:00
{
2023-10-19 12:34:31 -07:00
reagentDispenser . Comp . DispenseAmount = message . ReagentDispenserDispenseAmount ;
2022-10-04 02:57:32 +02:00
UpdateUiState ( reagentDispenser ) ;
ClickSound ( reagentDispenser ) ;
}
2023-10-19 12:34:31 -07:00
private void OnDispenseReagentMessage ( Entity < ReagentDispenserComponent > reagentDispenser , ref ReagentDispenserDispenseReagentMessage message )
2022-10-04 02:57:32 +02:00
{
// Ensure that the reagent is something this reagent dispenser can dispense.
if ( ! GetInventory ( reagentDispenser ) . Contains ( message . ReagentId ) )
return ;
2023-10-19 12:34:31 -07:00
var outputContainer = _itemSlotsSystem . GetItemOrNull ( reagentDispenser , SharedReagentDispenser . OutputSlotName ) ;
2023-12-29 04:47:43 -08:00
if ( outputContainer is not { Valid : true } | | ! _solutionContainerSystem . TryGetFitsInDispenser ( outputContainer . Value , out var solution , out _ ) )
2022-10-04 02:57:32 +02:00
return ;
2023-12-29 04:47:43 -08:00
if ( _solutionContainerSystem . TryAddReagent ( solution . Value , message . ReagentId , ( int ) reagentDispenser . Comp . DispenseAmount , out var dispensedAmount )
2022-10-04 02:57:32 +02:00
& & message . Session . AttachedEntity is not null )
{
_adminLogger . Add ( LogType . ChemicalReaction , LogImpact . Medium ,
$"{ToPrettyString(message.Session.AttachedEntity.Value):player} dispensed {dispensedAmount}u of {message.ReagentId} into {ToPrettyString(outputContainer.Value):entity}" ) ;
}
UpdateUiState ( reagentDispenser ) ;
ClickSound ( reagentDispenser ) ;
}
2023-10-19 12:34:31 -07:00
private void OnClearContainerSolutionMessage ( Entity < ReagentDispenserComponent > reagentDispenser , ref ReagentDispenserClearContainerSolutionMessage message )
2022-10-04 02:57:32 +02:00
{
2023-10-19 12:34:31 -07:00
var outputContainer = _itemSlotsSystem . GetItemOrNull ( reagentDispenser , SharedReagentDispenser . OutputSlotName ) ;
2023-12-29 04:47:43 -08:00
if ( outputContainer is not { Valid : true } | | ! _solutionContainerSystem . TryGetFitsInDispenser ( outputContainer . Value , out var solution , out _ ) )
2022-10-04 02:57:32 +02:00
return ;
2023-12-29 04:47:43 -08:00
_solutionContainerSystem . RemoveAllSolution ( solution . Value ) ;
2022-10-04 02:57:32 +02:00
UpdateUiState ( reagentDispenser ) ;
ClickSound ( reagentDispenser ) ;
}
2023-10-19 12:34:31 -07:00
private void ClickSound ( Entity < ReagentDispenserComponent > reagentDispenser )
2022-10-04 02:57:32 +02:00
{
2023-10-19 12:34:31 -07:00
_audioSystem . PlayPvs ( reagentDispenser . Comp . ClickSound , reagentDispenser , AudioParams . Default . WithVolume ( - 2f ) ) ;
2022-10-04 02:57:32 +02:00
}
2021-09-06 15:49:44 +02:00
}
}