2022-10-04 02:57:32 +02:00
using System.Linq ;
using Content.Server.Administration.Logs ;
2021-10-05 14:29:03 +11:00
using Content.Server.Chemistry.Components ;
2022-10-04 02:57:32 +02:00
using Content.Shared.Chemistry ;
using Content.Shared.Chemistry.Dispenser ;
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 ;
2023-01-12 16:41:40 +13:00
using Content.Shared.FixedPoint ;
2021-09-06 15:49:44 +02:00
using JetBrains.Annotations ;
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 ;
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
SubscribeLocalEvent < ReagentDispenserComponent , ComponentStartup > ( ( _ , comp , _ ) = > UpdateUiState ( comp ) ) ;
SubscribeLocalEvent < ReagentDispenserComponent , SolutionChangedEvent > ( ( _ , comp , _ ) = > UpdateUiState ( comp ) ) ;
SubscribeLocalEvent < ReagentDispenserComponent , EntInsertedIntoContainerMessage > ( ( _ , comp , _ ) = > UpdateUiState ( comp ) ) ;
SubscribeLocalEvent < ReagentDispenserComponent , EntRemovedFromContainerMessage > ( ( _ , comp , _ ) = > UpdateUiState ( comp ) ) ;
SubscribeLocalEvent < ReagentDispenserComponent , BoundUIOpenedEvent > ( ( _ , comp , _ ) = > UpdateUiState ( comp ) ) ;
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 ) ;
}
private void UpdateUiState ( ReagentDispenserComponent reagentDispenser )
{
var outputContainer = _itemSlotsSystem . GetItemOrNull ( reagentDispenser . Owner , SharedReagentDispenser . OutputSlotName ) ;
var outputContainerInfo = BuildOutputContainerInfo ( outputContainer ) ;
var inventory = GetInventory ( reagentDispenser ) ;
var state = new ReagentDispenserBoundUserInterfaceState ( outputContainerInfo , inventory , reagentDispenser . DispenseAmount ) ;
_userInterfaceSystem . TrySetUiState ( reagentDispenser . Owner , ReagentDispenserUiKey . Key , state ) ;
}
private ContainerInfo ? BuildOutputContainerInfo ( EntityUid ? container )
{
if ( container is not { Valid : true } )
return null ;
if ( _solutionContainerSystem . TryGetFitsInDispenser ( container . Value , out var solution ) )
{
var reagents = solution . Contents . Select ( reagent = > ( reagent . ReagentId , reagent . Quantity ) ) . ToList ( ) ;
2023-01-12 16:41:40 +13:00
return new ContainerInfo ( Name ( container . Value ) , true , solution . Volume , solution . MaxVolume , reagents ) ;
2022-10-04 02:57:32 +02:00
}
return null ;
}
private List < string > GetInventory ( ReagentDispenserComponent reagentDispenser )
{
var inventory = new List < string > ( ) ;
if ( reagentDispenser . PackPrototypeId is not null
& & _prototypeManager . TryIndex ( reagentDispenser . PackPrototypeId , out ReagentDispenserInventoryPrototype ? packPrototype ) )
{
inventory . AddRange ( packPrototype . Inventory ) ;
}
2023-02-19 01:03:06 +00:00
if ( HasComp < EmaggedComponent > ( reagentDispenser . Owner )
2022-10-04 02:57:32 +02:00
& & reagentDispenser . EmagPackPrototypeId is not null
& & _prototypeManager . TryIndex ( reagentDispenser . EmagPackPrototypeId , out ReagentDispenserInventoryPrototype ? emagPackPrototype ) )
{
inventory . AddRange ( emagPackPrototype . Inventory ) ;
}
return inventory ;
2022-02-17 21:43:24 -05:00
}
2023-01-21 10:12:45 -05:00
private void OnEmagged ( EntityUid uid , 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
EntityManager . AddComponent < EmaggedComponent > ( uid ) ;
UpdateUiState ( reagentDispenser ) ;
args . Handled = true ;
2021-09-06 15:49:44 +02:00
}
2022-10-04 02:57:32 +02:00
private void OnSetDispenseAmountMessage ( EntityUid uid , ReagentDispenserComponent reagentDispenser , ReagentDispenserSetDispenseAmountMessage message )
{
reagentDispenser . DispenseAmount = message . ReagentDispenserDispenseAmount ;
UpdateUiState ( reagentDispenser ) ;
ClickSound ( reagentDispenser ) ;
}
private void OnDispenseReagentMessage ( EntityUid uid , ReagentDispenserComponent reagentDispenser , ReagentDispenserDispenseReagentMessage message )
{
// Ensure that the reagent is something this reagent dispenser can dispense.
if ( ! GetInventory ( reagentDispenser ) . Contains ( message . ReagentId ) )
return ;
var outputContainer = _itemSlotsSystem . GetItemOrNull ( reagentDispenser . Owner , SharedReagentDispenser . OutputSlotName ) ;
if ( outputContainer is not { Valid : true } | | ! _solutionContainerSystem . TryGetFitsInDispenser ( outputContainer . Value , out var solution ) )
return ;
if ( _solutionContainerSystem . TryAddReagent ( outputContainer . Value , solution , message . ReagentId , ( int ) reagentDispenser . DispenseAmount , out var dispensedAmount )
& & 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 ) ;
}
private void OnClearContainerSolutionMessage ( EntityUid uid , ReagentDispenserComponent reagentDispenser , ReagentDispenserClearContainerSolutionMessage message )
{
var outputContainer = _itemSlotsSystem . GetItemOrNull ( reagentDispenser . Owner , SharedReagentDispenser . OutputSlotName ) ;
if ( outputContainer is not { Valid : true } | | ! _solutionContainerSystem . TryGetFitsInDispenser ( outputContainer . Value , out var solution ) )
return ;
_solutionContainerSystem . RemoveAllSolution ( outputContainer . Value , solution ) ;
UpdateUiState ( reagentDispenser ) ;
ClickSound ( reagentDispenser ) ;
}
private void ClickSound ( ReagentDispenserComponent reagentDispenser )
{
_audioSystem . PlayPvs ( reagentDispenser . ClickSound , reagentDispenser . Owner , AudioParams . Default . WithVolume ( - 2f ) ) ;
}
2021-09-06 15:49:44 +02:00
}
}