2022-03-25 17:17:29 +13:00
using Content.Server.Administration.Logs ;
2023-12-29 04:47:43 -08:00
using Content.Server.Chemistry.Containers.EntitySystems ;
2022-03-25 17:17:29 +13:00
using Content.Server.Explosion.EntitySystems ;
using Content.Shared.Chemistry.Components ;
using Content.Shared.Database ;
2022-06-01 01:39:06 -07:00
using Content.Shared.Examine ;
2022-03-25 17:17:29 +13:00
using Content.Shared.Payload.Components ;
using Content.Shared.Tag ;
using Robust.Shared.Containers ;
using Robust.Shared.Serialization.Manager ;
using Robust.Shared.Utility ;
2023-12-29 04:47:43 -08:00
using System.Linq ;
2022-03-25 17:17:29 +13:00
namespace Content.Server.Payload.EntitySystems ;
public sealed class PayloadSystem : EntitySystem
{
[Dependency] private readonly TagSystem _tagSystem = default ! ;
2023-12-29 04:47:43 -08:00
[Dependency] private readonly SolutionContainerSystem _solutionContainerSystem = default ! ;
[Dependency] private readonly IAdminLogManager _adminLogger = default ! ;
2022-03-25 17:17:29 +13:00
[Dependency] private readonly IComponentFactory _componentFactory = default ! ;
[Dependency] private readonly ISerializationManager _serializationManager = default ! ;
public override void Initialize ( )
{
base . Initialize ( ) ;
SubscribeLocalEvent < PayloadCaseComponent , TriggerEvent > ( OnCaseTriggered ) ;
SubscribeLocalEvent < PayloadTriggerComponent , TriggerEvent > ( OnTriggerTriggered ) ;
SubscribeLocalEvent < PayloadCaseComponent , EntInsertedIntoContainerMessage > ( OnEntityInserted ) ;
SubscribeLocalEvent < PayloadCaseComponent , EntRemovedFromContainerMessage > ( OnEntityRemoved ) ;
2022-06-01 01:39:06 -07:00
SubscribeLocalEvent < PayloadCaseComponent , ExaminedEvent > ( OnExamined ) ;
2022-03-25 17:17:29 +13:00
SubscribeLocalEvent < ChemicalPayloadComponent , TriggerEvent > ( HandleChemicalPayloadTrigger ) ;
}
2023-12-29 04:47:43 -08:00
public IEnumerable < EntityUid > GetAllPayloads ( EntityUid uid , ContainerManagerComponent ? contMan = null )
2022-03-25 17:17:29 +13:00
{
2022-06-01 01:39:06 -07:00
if ( ! Resolve ( uid , ref contMan , false ) )
yield break ;
2022-03-25 17:17:29 +13:00
foreach ( var container in contMan . Containers . Values )
{
foreach ( var entity in container . ContainedEntities )
{
if ( _tagSystem . HasTag ( entity , "Payload" ) )
2022-06-01 01:39:06 -07:00
yield return entity ;
2022-03-25 17:17:29 +13:00
}
}
}
2022-06-01 01:39:06 -07:00
private void OnCaseTriggered ( EntityUid uid , PayloadCaseComponent component , TriggerEvent args )
{
if ( ! TryComp ( uid , out ContainerManagerComponent ? contMan ) )
return ;
// Pass trigger event onto all contained payloads. Payload capacity configurable by construction graphs.
foreach ( var ent in GetAllPayloads ( uid , contMan ) )
{
RaiseLocalEvent ( ent , args , false ) ;
}
}
2022-03-25 17:17:29 +13:00
private void OnTriggerTriggered ( EntityUid uid , PayloadTriggerComponent component , TriggerEvent args )
{
if ( ! component . Active )
return ;
if ( Transform ( uid ) . ParentUid is not { Valid : true } parent )
return ;
// Ensure we don't enter a trigger-loop
DebugTools . Assert ( ! _tagSystem . HasTag ( uid , "Payload" ) ) ;
RaiseLocalEvent ( parent , args , false ) ;
}
private void OnEntityInserted ( EntityUid uid , PayloadCaseComponent _ , EntInsertedIntoContainerMessage args )
{
if ( ! TryComp ( args . Entity , out PayloadTriggerComponent ? trigger ) )
return ;
trigger . Active = true ;
if ( trigger . Components = = null )
return ;
// ANY payload trigger that gets inserted can grant components. It is up to the construction graphs to determine trigger capacity.
foreach ( var ( name , data ) in trigger . Components )
{
if ( ! _componentFactory . TryGetRegistration ( name , out var registration ) )
continue ;
if ( HasComp ( uid , registration . Type ) )
continue ;
if ( _componentFactory . GetComponent ( registration . Type ) is not Component component )
continue ;
2022-08-05 00:17:16 +02:00
var temp = ( object ) component ;
2022-11-27 19:25:55 +01:00
_serializationManager . CopyTo ( data . Component , ref temp ) ;
2023-12-29 04:47:43 -08:00
EntityManager . AddComponent ( uid , ( Component ) temp ! ) ;
2022-03-25 17:17:29 +13:00
trigger . GrantedComponents . Add ( registration . Type ) ;
}
}
private void OnEntityRemoved ( EntityUid uid , PayloadCaseComponent component , EntRemovedFromContainerMessage args )
{
if ( ! TryComp ( args . Entity , out PayloadTriggerComponent ? trigger ) )
return ;
trigger . Active = false ;
foreach ( var type in trigger . GrantedComponents )
{
EntityManager . RemoveComponent ( uid , type ) ;
}
trigger . GrantedComponents . Clear ( ) ;
}
2022-06-01 01:39:06 -07:00
private void OnExamined ( EntityUid uid , PayloadCaseComponent component , ExaminedEvent args )
{
2024-01-05 23:53:13 -07:00
using ( args . PushGroup ( nameof ( PayloadCaseComponent ) ) )
2022-06-01 01:39:06 -07:00
{
2024-01-05 23:53:13 -07:00
if ( ! args . IsInDetailsRange )
{
args . PushMarkup ( Loc . GetString ( "payload-case-not-close-enough" , ( "ent" , uid ) ) ) ;
return ;
}
2022-06-01 01:39:06 -07:00
2024-01-05 23:53:13 -07:00
if ( GetAllPayloads ( uid ) . Any ( ) )
{
args . PushMarkup ( Loc . GetString ( "payload-case-has-payload" , ( "ent" , uid ) ) ) ;
}
else
{
args . PushMarkup ( Loc . GetString ( "payload-case-does-not-have-payload" , ( "ent" , uid ) ) ) ;
}
2022-06-01 01:39:06 -07:00
}
}
2023-12-29 04:47:43 -08:00
private void HandleChemicalPayloadTrigger ( Entity < ChemicalPayloadComponent > entity , ref TriggerEvent args )
2022-03-25 17:17:29 +13:00
{
2023-12-29 04:47:43 -08:00
if ( entity . Comp . BeakerSlotA . Item is not EntityUid beakerA
| | entity . Comp . BeakerSlotB . Item is not EntityUid beakerB
2022-03-25 17:17:29 +13:00
| | ! TryComp ( beakerA , out FitsInDispenserComponent ? compA )
| | ! TryComp ( beakerB , out FitsInDispenserComponent ? compB )
2023-12-29 04:47:43 -08:00
| | ! _solutionContainerSystem . TryGetSolution ( beakerA , compA . Solution , out var solnA , out var solutionA )
| | ! _solutionContainerSystem . TryGetSolution ( beakerB , compB . Solution , out var solnB , out var solutionB )
2023-01-12 16:41:40 +13:00
| | solutionA . Volume = = 0
| | solutionB . Volume = = 0 )
2022-03-25 17:17:29 +13:00
{
return ;
}
var solStringA = SolutionContainerSystem . ToPrettyString ( solutionA ) ;
var solStringB = SolutionContainerSystem . ToPrettyString ( solutionB ) ;
2022-05-28 23:41:17 -07:00
_adminLogger . Add ( LogType . ChemicalReaction ,
2023-12-29 04:47:43 -08:00
$"Chemical bomb payload {ToPrettyString(entity.Owner):payload} at {Transform(entity.Owner).MapPosition:location} is combining two solutions: {solStringA:solutionA} and {solStringB:solutionB}" ) ;
2022-03-25 17:17:29 +13:00
solutionA . MaxVolume + = solutionB . MaxVolume ;
2023-12-29 04:47:43 -08:00
_solutionContainerSystem . TryAddSolution ( solnA . Value , solutionB ) ;
_solutionContainerSystem . RemoveAllSolution ( solnB . Value ) ;
2022-03-25 17:17:29 +13:00
// The grenade might be a dud. Redistribute solution:
2023-12-29 04:47:43 -08:00
var tmpSol = _solutionContainerSystem . SplitSolution ( solnA . Value , solutionA . Volume * solutionB . MaxVolume / solutionA . MaxVolume ) ;
_solutionContainerSystem . TryAddSolution ( solnB . Value , tmpSol ) ;
2022-03-25 17:17:29 +13:00
solutionA . MaxVolume - = solutionB . MaxVolume ;
2023-12-29 04:47:43 -08:00
_solutionContainerSystem . UpdateChemicals ( solnA . Value ) ;
2022-06-01 01:39:06 -07:00
args . Handled = true ;
2022-03-25 17:17:29 +13:00
}
}