2020-09-13 14:23:52 +02:00
using System.Linq ;
2022-07-30 23:47:42 -03:00
using Content.Server.Administration.Logs ;
2023-03-23 10:10:49 -05:00
using Content.Server.Administration.Systems ;
using Content.Server.Chat.Managers ;
2022-07-30 23:47:42 -03:00
using Content.Server.Mind.Components ;
2021-06-09 22:19:39 +02:00
using Content.Server.NodeContainer ;
using Content.Server.Power.Components ;
using Content.Server.UserInterface ;
using Content.Shared.AME ;
2022-07-30 23:47:42 -03:00
using Content.Shared.Database ;
2022-03-17 20:13:31 +13:00
using Content.Shared.Hands.EntitySystems ;
2020-08-29 06:05:44 -05:00
using Robust.Server.GameObjects ;
using Robust.Shared.Audio ;
2021-03-01 15:24:46 -08:00
using Robust.Shared.Containers ;
2021-03-21 09:12:03 -07:00
using Robust.Shared.Player ;
2020-08-29 06:05:44 -05:00
2021-06-09 22:19:39 +02:00
namespace Content.Server.AME.Components
2020-08-29 06:05:44 -05:00
{
[RegisterComponent]
2022-04-15 17:20:20 -04:00
public sealed class AMEControllerComponent : SharedAMEControllerComponent
2020-08-29 06:05:44 -05:00
{
2021-12-05 18:09:01 +01:00
[Dependency] private readonly IEntityManager _entities = default ! ;
2022-03-17 20:13:31 +13:00
[Dependency] private readonly IEntitySystemManager _sysMan = default ! ;
2022-07-30 23:47:42 -03:00
[Dependency] private readonly IAdminLogManager _adminLogger = default ! ;
2023-03-23 10:10:49 -05:00
[Dependency] private readonly IChatManager _chat = default ! ;
2021-12-05 18:09:01 +01:00
2020-08-29 06:05:44 -05:00
[ViewVariables] private BoundUserInterface ? UserInterface = > Owner . GetUIOrNull ( AMEControllerUiKey . Key ) ;
2021-10-03 12:33:28 +01:00
private bool _injecting ;
[ViewVariables] public bool Injecting = > _injecting ;
2020-08-29 06:05:44 -05:00
[ViewVariables] public int InjectionAmount ;
private AppearanceComponent ? _appearance ;
private PowerSupplierComponent ? _powerSupplier ;
2021-07-10 17:35:33 +02:00
[DataField("clickSound")] private SoundSpecifier _clickSound = new SoundPathSpecifier ( "/Audio/Machines/machine_switch.ogg" ) ;
[DataField("injectSound")] private SoundSpecifier _injectSound = new SoundPathSpecifier ( "/Audio/Effects/bang.ogg" ) ;
2020-08-29 06:05:44 -05:00
2021-12-05 18:09:01 +01:00
private bool Powered = > ! _entities . TryGetComponent ( Owner , out ApcPowerReceiverComponent ? receiver ) | | receiver . Powered ;
2020-08-29 06:05:44 -05:00
[ViewVariables]
private int _stability = 100 ;
2022-04-15 17:20:20 -04:00
public ContainerSlot JarSlot = default ! ;
[ViewVariables] public bool HasJar = > JarSlot . ContainedEntity ! = null ;
2020-08-29 06:05:44 -05:00
2021-06-19 19:41:26 -07:00
protected override void Initialize ( )
2020-08-29 06:05:44 -05:00
{
base . Initialize ( ) ;
if ( UserInterface ! = null )
{
UserInterface . OnReceiveMessage + = OnUiReceiveMessage ;
}
2021-12-05 18:09:01 +01:00
_entities . TryGetComponent ( Owner , out _appearance ) ;
2020-08-29 06:05:44 -05:00
2021-12-05 18:09:01 +01:00
_entities . TryGetComponent ( Owner , out _powerSupplier ) ;
2020-08-29 06:05:44 -05:00
_injecting = false ;
InjectionAmount = 2 ;
2022-10-17 02:49:22 +11:00
// TODO: Fix this bad name. I'd update maps but then people get mad.
JarSlot = ContainerHelpers . EnsureContainer < ContainerSlot > ( Owner , $"AMEController-fuelJarContainer" ) ;
2020-08-29 06:05:44 -05:00
}
internal void OnUpdate ( float frameTime )
{
2021-07-31 19:52:33 +02:00
if ( ! _injecting )
2020-08-29 06:05:44 -05:00
{
return ;
}
2020-08-30 11:37:06 +02:00
var group = GetAMENodeGroup ( ) ;
if ( group = = null )
{
return ;
}
2022-04-15 17:20:20 -04:00
if ( JarSlot . ContainedEntity is not { Valid : true } jar )
2021-03-01 15:24:46 -08:00
return ;
2021-12-05 18:09:01 +01:00
_entities . TryGetComponent < AMEFuelContainerComponent ? > ( jar , out var fuelJar ) ;
2021-07-31 19:52:33 +02:00
if ( fuelJar ! = null & & _powerSupplier ! = null )
2020-08-29 06:05:44 -05:00
{
2020-12-16 13:31:47 +00:00
var availableInject = fuelJar . FuelAmount > = InjectionAmount ? InjectionAmount : fuelJar . FuelAmount ;
2021-07-04 18:11:52 +02:00
_powerSupplier . MaxSupply = group . InjectFuel ( availableInject , out var overloading ) ;
2020-12-16 13:31:47 +00:00
fuelJar . FuelAmount - = availableInject ;
InjectSound ( overloading ) ;
2020-08-29 06:05:44 -05:00
UpdateUserInterface ( ) ;
}
2020-08-30 11:37:06 +02:00
_stability = group . GetTotalStability ( ) ;
2020-08-29 06:05:44 -05:00
UpdateDisplay ( _stability ) ;
2021-07-31 19:52:33 +02:00
if ( _stability < = 0 ) { group . ExplodeCores ( ) ; }
2020-08-29 06:05:44 -05:00
}
2021-10-03 12:33:28 +01:00
// Used to update core count
public void OnAMENodeGroupUpdate ( )
{
UpdateUserInterface ( ) ;
}
2020-08-29 06:05:44 -05:00
private AMEControllerBoundUserInterfaceState GetUserInterfaceState ( )
{
2022-04-15 17:20:20 -04:00
if ( JarSlot . ContainedEntity is not { Valid : true } jar )
2020-08-29 06:05:44 -05:00
{
return new AMEControllerBoundUserInterfaceState ( Powered , IsMasterController ( ) , false , HasJar , 0 , InjectionAmount , GetCoreCount ( ) ) ;
}
2021-12-05 18:09:01 +01:00
var jarComponent = _entities . GetComponent < AMEFuelContainerComponent > ( jar ) ;
return new AMEControllerBoundUserInterfaceState ( Powered , IsMasterController ( ) , _injecting , HasJar , jarComponent . FuelAmount , InjectionAmount , GetCoreCount ( ) ) ;
2020-08-29 06:05:44 -05:00
}
/// <summary>
/// Checks whether the player entity is able to use the controller.
/// </summary>
/// <param name="playerEntity">The player entity.</param>
/// <returns>Returns true if the entity can use the controller, and false if it cannot.</returns>
2021-12-05 18:09:01 +01:00
private bool PlayerCanUseController ( EntityUid playerEntity , bool needsPower = true )
2020-08-29 06:05:44 -05:00
{
//Need player entity to check if they are still able to use the dispenser
2021-12-05 18:09:01 +01:00
if ( playerEntity = = default )
2020-08-29 06:05:44 -05:00
return false ;
2021-06-19 10:03:24 +02:00
2020-08-29 06:05:44 -05:00
//Check if device is powered
if ( needsPower & & ! Powered )
return false ;
return true ;
}
2022-03-29 03:58:51 +11:00
public void UpdateUserInterface ( )
2020-08-29 06:05:44 -05:00
{
var state = GetUserInterfaceState ( ) ;
UserInterface ? . SetState ( state ) ;
}
/// <summary>
/// Handles ui messages from the client. For things such as button presses
/// which interact with the world and require server action.
/// </summary>
/// <param name="obj">A user interface message from the client.</param>
private void OnUiReceiveMessage ( ServerBoundUserInterfaceMessage obj )
{
2021-12-05 18:09:01 +01:00
if ( obj . Session . AttachedEntity is not { Valid : true } player )
2020-08-29 06:05:44 -05:00
{
return ;
}
var msg = ( UiButtonPressedMessage ) obj . Message ;
var needsPower = msg . Button switch
{
UiButton . Eject = > false ,
_ = > true ,
} ;
2021-12-05 18:09:01 +01:00
if ( ! PlayerCanUseController ( player , needsPower ) )
2020-08-29 06:05:44 -05:00
return ;
switch ( msg . Button )
{
case UiButton . Eject :
2021-12-05 18:09:01 +01:00
TryEject ( player ) ;
2020-08-29 06:05:44 -05:00
break ;
case UiButton . ToggleInjection :
ToggleInjection ( ) ;
break ;
case UiButton . IncreaseFuel :
InjectionAmount + = 2 ;
break ;
case UiButton . DecreaseFuel :
InjectionAmount = InjectionAmount > 0 ? InjectionAmount - = 2 : 0 ;
break ;
}
2022-07-30 23:47:42 -03:00
// Logging
2023-03-27 10:24:00 +13:00
_entities . TryGetComponent ( player , out MindComponent ? mindComponent ) ;
if ( mindComponent ! = null )
2022-07-30 23:47:42 -03:00
{
var humanReadableState = _injecting ? "Inject" : "Not inject" ;
if ( msg . Button = = UiButton . IncreaseFuel | | msg . Button = = UiButton . DecreaseFuel )
2023-03-27 10:24:00 +13:00
_adminLogger . Add ( LogType . Action , LogImpact . Extreme , $"{_entities.ToPrettyString(mindComponent.Owner):player} has set the AME to inject {InjectionAmount} while set to {humanReadableState}" ) ;
2022-07-30 23:47:42 -03:00
if ( msg . Button = = UiButton . ToggleInjection )
2023-03-27 10:24:00 +13:00
_adminLogger . Add ( LogType . Action , LogImpact . Extreme , $"{_entities.ToPrettyString(mindComponent.Owner):player} has set the AME to {humanReadableState}" ) ;
2023-03-23 10:10:49 -05:00
// Admin alert
if ( GetCoreCount ( ) * 2 = = InjectionAmount - 2 & & msg . Button = = UiButton . IncreaseFuel )
2023-03-27 10:24:00 +13:00
_chat . SendAdminAlert ( player , $"increased AME over safe limit to {InjectionAmount}" , mindComponent ) ;
2022-07-30 23:47:42 -03:00
}
2021-10-03 12:33:28 +01:00
GetAMENodeGroup ( ) ? . UpdateCoreVisuals ( ) ;
2020-08-29 06:05:44 -05:00
UpdateUserInterface ( ) ;
ClickSound ( ) ;
}
2021-12-05 18:09:01 +01:00
private void TryEject ( EntityUid user )
2020-08-29 06:05:44 -05:00
{
if ( ! HasJar | | _injecting )
return ;
2022-04-15 17:20:20 -04:00
if ( JarSlot . ContainedEntity is not { Valid : true } jar )
2021-03-01 15:24:46 -08:00
return ;
2022-04-15 17:20:20 -04:00
JarSlot . Remove ( jar ) ;
2020-08-29 06:05:44 -05:00
UpdateUserInterface ( ) ;
2022-03-17 20:13:31 +13:00
_sysMan . GetEntitySystem < SharedHandsSystem > ( ) . PickupOrDrop ( user , jar ) ;
2020-08-29 06:05:44 -05:00
}
private void ToggleInjection ( )
{
if ( ! _injecting )
{
_appearance ? . SetData ( AMEControllerVisuals . DisplayState , "on" ) ;
}
else
{
_appearance ? . SetData ( AMEControllerVisuals . DisplayState , "off" ) ;
if ( _powerSupplier ! = null )
{
2021-07-04 18:11:52 +02:00
_powerSupplier . MaxSupply = 0 ;
2020-08-29 06:05:44 -05:00
}
}
_injecting = ! _injecting ;
UpdateUserInterface ( ) ;
}
private void UpdateDisplay ( int stability )
{
2021-07-31 19:52:33 +02:00
if ( _appearance = = null ) { return ; }
2020-08-29 06:05:44 -05:00
_appearance . TryGetData < string > ( AMEControllerVisuals . DisplayState , out var state ) ;
var newState = "on" ;
if ( stability < 50 ) { newState = "critical" ; }
if ( stability < 10 ) { newState = "fuck" ; }
if ( state ! = newState )
{
_appearance ? . SetData ( AMEControllerVisuals . DisplayState , newState ) ;
}
}
2020-08-30 11:37:06 +02:00
private AMENodeGroup ? GetAMENodeGroup ( )
2020-08-29 06:05:44 -05:00
{
2021-12-05 18:09:01 +01:00
_entities . TryGetComponent ( Owner , out NodeContainerComponent ? nodeContainer ) ;
2020-08-29 06:05:44 -05:00
2021-04-09 20:47:31 +02:00
var engineNodeGroup = nodeContainer ? . Nodes . Values
2020-08-29 06:05:44 -05:00
. Select ( node = > node . NodeGroup )
. OfType < AMENodeGroup > ( )
2020-12-08 10:58:46 +00:00
. FirstOrDefault ( ) ;
2020-08-29 06:05:44 -05:00
2020-08-30 11:37:06 +02:00
return engineNodeGroup ;
2020-08-29 06:05:44 -05:00
}
private bool IsMasterController ( )
{
2021-07-31 19:52:33 +02:00
if ( GetAMENodeGroup ( ) ? . MasterController = = this )
2020-08-29 06:05:44 -05:00
{
return true ;
}
return false ;
}
private int GetCoreCount ( )
{
var coreCount = 0 ;
2020-08-30 11:37:06 +02:00
var group = GetAMENodeGroup ( ) ;
2020-08-29 06:05:44 -05:00
2020-08-30 11:37:06 +02:00
if ( group ! = null )
2020-08-29 06:05:44 -05:00
{
2020-08-30 11:37:06 +02:00
coreCount = group . CoreCount ;
2020-08-29 06:05:44 -05:00
}
return coreCount ;
}
private void ClickSound ( )
{
2022-06-12 19:45:47 -04:00
SoundSystem . Play ( _clickSound . GetSound ( ) , Filter . Pvs ( Owner ) , Owner , AudioParams . Default . WithVolume ( - 2f ) ) ;
2020-08-29 06:05:44 -05:00
}
2020-12-16 13:31:47 +00:00
private void InjectSound ( bool overloading )
2020-08-29 06:05:44 -05:00
{
2022-06-12 19:45:47 -04:00
SoundSystem . Play ( _injectSound . GetSound ( ) , Filter . Pvs ( Owner ) , Owner , AudioParams . Default . WithVolume ( overloading ? 10f : 0f ) ) ;
2020-08-29 06:05:44 -05:00
}
}
}