2021-01-03 09:13:01 -06:00
#nullable enable
2020-08-22 22:29:20 +02:00
using System ;
2019-09-06 10:05:02 +02:00
using System.Threading ;
2020-06-28 09:23:26 -06:00
using Content.Server.GameObjects.Components.Power.ApcNetComponents ;
2019-09-06 10:05:02 +02:00
using Content.Server.GameObjects.Components.VendingMachines ;
2021-02-12 07:02:14 -08:00
using Content.Server.Interfaces.GameObjects.Components.Doors ;
2019-10-13 16:39:21 +02:00
using Content.Shared.GameObjects.Components.Doors ;
2020-09-01 12:34:53 +02:00
using Content.Shared.Interfaces ;
2020-07-18 22:51:56 -07:00
using Content.Shared.Interfaces.GameObjects.Components ;
2019-10-13 16:39:21 +02:00
using Robust.Server.GameObjects ;
2021-03-21 09:12:03 -07:00
using Robust.Shared.Audio ;
2019-09-06 10:05:02 +02:00
using Robust.Shared.GameObjects ;
using Robust.Shared.Localization ;
2020-05-27 15:09:22 +02:00
using Robust.Shared.Maths ;
2021-03-21 09:12:03 -07:00
using Robust.Shared.Player ;
2020-09-08 13:30:22 +02:00
using Robust.Shared.ViewVariables ;
2020-05-27 15:09:22 +02:00
using static Content . Shared . GameObjects . Components . SharedWiresComponent ;
2019-09-06 10:05:02 +02:00
using static Content . Shared . GameObjects . Components . SharedWiresComponent . WiresAction ;
namespace Content.Server.GameObjects.Components.Doors
{
2021-02-12 07:02:14 -08:00
/// <summary>
/// Companion component to ServerDoorComponent that handles airlock-specific behavior -- wires, requiring power to operate, bolts, and allowing automatic closing.
/// </summary>
2019-09-06 10:05:02 +02:00
[RegisterComponent]
2021-02-12 07:02:14 -08:00
[ComponentReference(typeof(IDoorCheck))]
public class AirlockComponent : Component , IWires , IDoorCheck
2019-09-06 10:05:02 +02:00
{
public override string Name = > "Airlock" ;
2021-02-12 07:02:14 -08:00
[ComponentDependency]
private readonly ServerDoorComponent ? _doorComponent = null ;
[ComponentDependency]
private readonly SharedAppearanceComponent ? _appearanceComponent = null ;
[ComponentDependency]
private readonly PowerReceiverComponent ? _receiverComponent = null ;
[ComponentDependency]
private readonly WiresComponent ? _wiresComponent = null ;
2019-09-06 10:05:02 +02:00
/// <summary>
/// Duration for which power will be disabled after pulsing either power wire.
/// </summary>
private static readonly TimeSpan PowerWiresTimeout = TimeSpan . FromSeconds ( 5.0 ) ;
2020-11-27 11:00:49 +01:00
private CancellationTokenSource _powerWiresPulsedTimerCancel = new ( ) ;
2019-09-06 10:05:02 +02:00
private bool _powerWiresPulsed ;
2020-05-27 15:09:22 +02:00
2019-09-06 10:05:02 +02:00
/// <summary>
/// True if either power wire was pulsed in the last <see cref="PowerWiresTimeout"/>.
/// </summary>
2020-09-08 13:30:22 +02:00
[ViewVariables(VVAccess.ReadWrite)]
2019-09-06 10:05:02 +02:00
private bool PowerWiresPulsed
{
get = > _powerWiresPulsed ;
set
{
_powerWiresPulsed = value ;
UpdateWiresStatus ( ) ;
2019-10-13 18:29:57 +02:00
UpdatePowerCutStatus ( ) ;
2019-09-06 10:05:02 +02:00
}
}
2020-07-02 15:31:06 +02:00
private bool _boltsDown ;
2020-09-08 13:30:22 +02:00
[ViewVariables(VVAccess.ReadWrite)]
2020-10-08 11:59:20 -04:00
public bool BoltsDown
2020-07-02 15:31:06 +02:00
{
get = > _boltsDown ;
set
{
_boltsDown = value ;
UpdateBoltLightStatus ( ) ;
}
}
private bool _boltLightsWirePulsed = true ;
2020-09-08 13:30:22 +02:00
[ViewVariables(VVAccess.ReadWrite)]
2020-07-02 15:31:06 +02:00
private bool BoltLightsVisible
{
2021-02-12 07:02:14 -08:00
get = > _boltLightsWirePulsed & & BoltsDown & & IsPowered ( )
& & _doorComponent ! = null & & _doorComponent . State = = SharedDoorComponent . DoorState . Closed ;
2020-07-02 15:31:06 +02:00
set
{
_boltLightsWirePulsed = value ;
UpdateBoltLightStatus ( ) ;
}
}
2021-02-12 07:02:14 -08:00
private static readonly TimeSpan AutoCloseDelayFast = TimeSpan . FromSeconds ( 1 ) ;
[ViewVariables(VVAccess.ReadWrite)]
private bool _autoClose = true ;
[ViewVariables(VVAccess.ReadWrite)]
private bool _normalCloseSpeed = true ;
2020-09-08 13:30:22 +02:00
[ViewVariables(VVAccess.ReadWrite)]
2021-02-12 07:02:14 -08:00
private bool _safety = true ;
public override void Initialize ( )
2020-07-17 10:51:43 +02:00
{
2021-02-12 07:02:14 -08:00
base . Initialize ( ) ;
if ( _receiverComponent ! = null & & _appearanceComponent ! = null )
{
_appearanceComponent . SetData ( DoorVisuals . Powered , _receiverComponent . Powered ) ;
}
}
public override void HandleMessage ( ComponentMessage message , IComponent ? component )
{
base . HandleMessage ( message , component ) ;
switch ( message )
{
case PowerChangedMessage powerChanged :
PowerDeviceOnOnPowerStateChanged ( powerChanged ) ;
break ;
}
}
void IDoorCheck . OnStateChange ( SharedDoorComponent . DoorState doorState )
{
// Only show the maintenance panel if the airlock is closed
if ( _wiresComponent ! = null )
{
_wiresComponent . IsPanelVisible = doorState ! = SharedDoorComponent . DoorState . Open ;
}
// If the door is closed, we should look if the bolt was locked while closing
UpdateBoltLightStatus ( ) ;
}
bool IDoorCheck . OpenCheck ( ) = > CanChangeState ( ) ;
bool IDoorCheck . CloseCheck ( ) = > CanChangeState ( ) ;
bool IDoorCheck . DenyCheck ( ) = > CanChangeState ( ) ;
bool IDoorCheck . SafetyCheck ( ) = > _safety ;
bool IDoorCheck . AutoCloseCheck ( ) = > _autoClose ;
TimeSpan ? IDoorCheck . GetCloseSpeed ( )
{
if ( _normalCloseSpeed )
{
return null ;
}
return AutoCloseDelayFast ;
}
bool IDoorCheck . BlockActivate ( ActivateEventArgs eventArgs )
{
if ( _wiresComponent ! = null & & _wiresComponent . IsPanelOpen & &
eventArgs . User . TryGetComponent ( out IActorComponent ? actor ) )
{
_wiresComponent . OpenInterface ( actor . playerSession ) ;
return true ;
}
return false ;
}
bool IDoorCheck . CanPryCheck ( InteractUsingEventArgs eventArgs )
{
if ( IsBolted ( ) )
{
Owner . PopupMessage ( eventArgs . User , Loc . GetString ( "The airlock's bolts prevent it from being forced!" ) ) ;
return false ;
}
if ( IsPowered ( ) )
{
Owner . PopupMessage ( eventArgs . User , Loc . GetString ( "The powered motors block your efforts!" ) ) ;
return false ;
}
return true ;
}
private bool CanChangeState ( )
{
return IsPowered ( ) & & ! IsBolted ( ) ;
}
private bool IsBolted ( )
{
return _boltsDown ;
}
private bool IsPowered ( )
{
return _receiverComponent = = null | | _receiverComponent . Powered ;
}
private void UpdateBoltLightStatus ( )
{
if ( _appearanceComponent ! = null )
{
_appearanceComponent . SetData ( DoorVisuals . BoltLights , BoltLightsVisible ) ;
}
2020-07-17 10:51:43 +02:00
}
2019-09-06 10:05:02 +02:00
private void UpdateWiresStatus ( )
{
2021-02-12 07:02:14 -08:00
if ( _doorComponent = = null )
{
return ;
}
2020-05-27 15:09:22 +02:00
var powerLight = new StatusLightData ( Color . Yellow , StatusLightState . On , "POWR" ) ;
2019-10-13 18:29:57 +02:00
if ( PowerWiresPulsed )
2019-09-06 10:05:02 +02:00
{
2020-05-27 15:09:22 +02:00
powerLight = new StatusLightData ( Color . Yellow , StatusLightState . BlinkingFast , "POWR" ) ;
}
2021-02-12 07:02:14 -08:00
else if ( _wiresComponent ! = null & &
_wiresComponent . IsWireCut ( Wires . MainPower ) & &
_wiresComponent . IsWireCut ( Wires . BackupPower ) )
2019-09-06 10:05:02 +02:00
{
2020-05-27 15:09:22 +02:00
powerLight = new StatusLightData ( Color . Red , StatusLightState . On , "POWR" ) ;
2019-09-06 10:05:02 +02:00
}
2020-05-27 15:09:22 +02:00
2020-07-02 15:31:06 +02:00
var boltStatus =
new StatusLightData ( Color . Red , BoltsDown ? StatusLightState . On : StatusLightState . Off , "BOLT" ) ;
var boltLightsStatus = new StatusLightData ( Color . Lime ,
_boltLightsWirePulsed ? StatusLightState . On : StatusLightState . Off , "BLTL" ) ;
2020-07-17 10:51:43 +02:00
var timingStatus =
2021-02-12 07:02:14 -08:00
new StatusLightData ( Color . Orange , ! _autoClose ? StatusLightState . Off :
! _normalCloseSpeed ? StatusLightState . BlinkingSlow :
2020-07-17 10:51:43 +02:00
StatusLightState . On ,
"TIME" ) ;
var safetyStatus =
2021-02-12 07:02:14 -08:00
new StatusLightData ( Color . Red , _safety ? StatusLightState . On : StatusLightState . Off , "SAFE" ) ;
2020-07-17 10:51:43 +02:00
2021-02-12 07:02:14 -08:00
if ( _wiresComponent = = null )
2020-08-22 22:29:20 +02:00
{
return ;
}
2021-02-12 07:02:14 -08:00
_wiresComponent . SetStatus ( AirlockWireStatus . PowerIndicator , powerLight ) ;
_wiresComponent . SetStatus ( AirlockWireStatus . BoltIndicator , boltStatus ) ;
_wiresComponent . SetStatus ( AirlockWireStatus . BoltLightIndicator , boltLightsStatus ) ;
_wiresComponent . SetStatus ( AirlockWireStatus . AIControlIndicator , new StatusLightData ( Color . Purple , StatusLightState . BlinkingSlow , "AICT" ) ) ;
_wiresComponent . SetStatus ( AirlockWireStatus . TimingIndicator , timingStatus ) ;
_wiresComponent . SetStatus ( AirlockWireStatus . SafetyIndicator , safetyStatus ) ;
2020-05-27 15:09:22 +02:00
/ *
_wires . SetStatus ( 6 , powerLight ) ;
_wires . SetStatus ( 7 , powerLight ) ;
_wires . SetStatus ( 8 , powerLight ) ;
_wires . SetStatus ( 9 , powerLight ) ;
_wires . SetStatus ( 10 , powerLight ) ;
_wires . SetStatus ( 11 , powerLight ) ; * /
2019-09-06 10:05:02 +02:00
}
2019-10-13 18:29:57 +02:00
private void UpdatePowerCutStatus ( )
{
2021-02-12 07:02:14 -08:00
if ( _receiverComponent = = null )
2020-08-22 22:29:20 +02:00
{
return ;
}
if ( PowerWiresPulsed )
{
2021-02-12 07:02:14 -08:00
_receiverComponent . PowerDisabled = true ;
2020-08-22 22:29:20 +02:00
return ;
}
2021-02-12 07:02:14 -08:00
if ( _wiresComponent = = null )
2020-08-22 22:29:20 +02:00
{
return ;
}
2021-02-12 07:02:14 -08:00
_receiverComponent . PowerDisabled =
_wiresComponent . IsWireCut ( Wires . MainPower ) | |
_wiresComponent . IsWireCut ( Wires . BackupPower ) ;
2019-10-13 16:39:21 +02:00
}
2021-01-03 09:13:01 -06:00
private void PowerDeviceOnOnPowerStateChanged ( PowerChangedMessage e )
2019-10-13 16:39:21 +02:00
{
2021-02-12 07:02:14 -08:00
if ( _appearanceComponent ! = null )
2019-10-13 16:39:21 +02:00
{
2021-02-12 07:02:14 -08:00
_appearanceComponent . SetData ( DoorVisuals . Powered , e . Powered ) ;
2019-10-13 16:39:21 +02:00
}
2020-07-02 15:31:06 +02:00
// BoltLights also got out
UpdateBoltLightStatus ( ) ;
2019-09-06 10:05:02 +02:00
}
private enum Wires
{
/// <summary>
/// Pulsing turns off power for <see cref="AirlockComponent.PowerWiresTimeout"/>.
/// Cutting turns off power permanently if <see cref="BackupPower"/> is also cut.
/// Mending restores power.
/// </summary>
MainPower ,
2020-05-27 15:09:22 +02:00
2019-09-06 10:05:02 +02:00
/// <see cref="MainPower"/>
BackupPower ,
2020-07-02 15:31:06 +02:00
/// <summary>
/// Pulsing causes for bolts to toggle (but only raise if power is on)
/// Cutting causes Bolts to drop
/// Mending does nothing
/// </summary>
Bolts ,
/// <summary>
/// Pulsing causes light to toggle
/// Cutting causes light to go out
/// Mending causes them to go on again
/// </summary>
BoltLight ,
2020-07-17 10:51:43 +02:00
// Placeholder for when AI is implemented
AIControl ,
/// <summary>
/// Pulsing causes door to close faster
/// Cutting disables door timer, causing door to stop closing automatically
/// Mending restores door timer
/// </summary>
Timing ,
/// <summary>
/// Pulsing toggles safety
/// Cutting disables safety
/// Mending enables safety
/// </summary>
Safety ,
2019-09-06 10:05:02 +02:00
}
public void RegisterWires ( WiresComponent . WiresBuilder builder )
{
builder . CreateWire ( Wires . MainPower ) ;
builder . CreateWire ( Wires . BackupPower ) ;
2020-07-02 15:31:06 +02:00
builder . CreateWire ( Wires . Bolts ) ;
builder . CreateWire ( Wires . BoltLight ) ;
2020-07-17 10:51:43 +02:00
builder . CreateWire ( Wires . Timing ) ;
builder . CreateWire ( Wires . Safety ) ;
2020-07-02 15:31:06 +02:00
/ *
2020-05-27 15:09:22 +02:00
builder . CreateWire ( 6 ) ;
builder . CreateWire ( 7 ) ;
builder . CreateWire ( 8 ) ;
builder . CreateWire ( 9 ) ;
builder . CreateWire ( 10 ) ;
builder . CreateWire ( 11 ) ; * /
2019-09-06 10:05:02 +02:00
UpdateWiresStatus ( ) ;
}
public void WiresUpdate ( WiresUpdateEventArgs args )
{
2021-02-12 07:02:14 -08:00
if ( _doorComponent = = null )
{
return ;
}
2019-09-06 10:05:02 +02:00
if ( args . Action = = Pulse )
{
switch ( args . Identifier )
{
case Wires . MainPower :
case Wires . BackupPower :
PowerWiresPulsed = true ;
2020-08-22 22:29:20 +02:00
_powerWiresPulsedTimerCancel . Cancel ( ) ;
2020-09-03 21:54:10 +02:00
_powerWiresPulsedTimerCancel = new CancellationTokenSource ( ) ;
2020-10-30 05:02:49 +01:00
Owner . SpawnTimer ( PowerWiresTimeout ,
2019-09-06 10:05:02 +02:00
( ) = > PowerWiresPulsed = false ,
_powerWiresPulsedTimerCancel . Token ) ;
break ;
2020-07-02 15:31:06 +02:00
case Wires . Bolts :
if ( ! BoltsDown )
{
SetBoltsWithAudio ( true ) ;
}
else
{
if ( IsPowered ( ) ) // only raise again if powered
{
SetBoltsWithAudio ( false ) ;
}
}
break ;
case Wires . BoltLight :
// we need to change the property here to set the appearance again
BoltLightsVisible = ! _boltLightsWirePulsed ;
break ;
2020-07-17 10:51:43 +02:00
case Wires . Timing :
2021-02-12 07:02:14 -08:00
_normalCloseSpeed = ! _normalCloseSpeed ;
_doorComponent . RefreshAutoClose ( ) ;
2020-07-17 10:51:43 +02:00
break ;
case Wires . Safety :
2021-02-12 07:02:14 -08:00
_safety = ! _safety ;
2020-07-17 10:51:43 +02:00
break ;
2019-09-06 10:05:02 +02:00
}
}
2021-02-14 06:38:41 -08:00
else if ( args . Action = = Mend )
2019-09-06 10:05:02 +02:00
{
switch ( args . Identifier )
{
case Wires . MainPower :
case Wires . BackupPower :
// mending power wires instantly restores power
_powerWiresPulsedTimerCancel ? . Cancel ( ) ;
PowerWiresPulsed = false ;
break ;
2020-07-02 15:31:06 +02:00
case Wires . BoltLight :
BoltLightsVisible = true ;
break ;
2020-07-17 10:51:43 +02:00
case Wires . Timing :
2021-02-12 07:02:14 -08:00
_autoClose = true ;
_doorComponent . RefreshAutoClose ( ) ;
2020-07-17 10:51:43 +02:00
break ;
case Wires . Safety :
2021-02-12 07:02:14 -08:00
_safety = true ;
2020-07-17 10:51:43 +02:00
break ;
2020-07-02 15:31:06 +02:00
}
}
2021-02-14 06:38:41 -08:00
else if ( args . Action = = Cut )
2020-07-02 15:31:06 +02:00
{
switch ( args . Identifier )
{
case Wires . Bolts :
SetBoltsWithAudio ( true ) ;
break ;
case Wires . BoltLight :
BoltLightsVisible = false ;
break ;
2020-07-17 10:51:43 +02:00
case Wires . Timing :
2021-02-12 07:02:14 -08:00
_autoClose = false ;
_doorComponent . RefreshAutoClose ( ) ;
2020-07-17 10:51:43 +02:00
break ;
case Wires . Safety :
2021-02-12 07:02:14 -08:00
_safety = false ;
2020-07-17 10:51:43 +02:00
break ;
2019-09-06 10:05:02 +02:00
}
}
UpdateWiresStatus ( ) ;
2019-10-13 18:29:57 +02:00
UpdatePowerCutStatus ( ) ;
2019-09-06 10:05:02 +02:00
}
2020-07-02 15:31:06 +02:00
public void SetBoltsWithAudio ( bool newBolts )
{
if ( newBolts = = BoltsDown )
{
return ;
}
BoltsDown = newBolts ;
2021-03-21 09:12:03 -07:00
SoundSystem . Play ( Filter . Broadcast ( ) , newBolts ? "/Audio/Machines/boltsdown.ogg" : "/Audio/Machines/boltsup.ogg" , Owner ) ;
2020-07-02 15:31:06 +02:00
}
2019-09-06 10:05:02 +02:00
}
}