2020-08-22 22:29:20 +02:00
using System ;
2019-09-06 10:05:02 +02:00
using System.Threading ;
2021-06-09 22:19:39 +02:00
using Content.Server.Power.Components ;
using Content.Server.VendingMachines ;
2021-07-04 18:11:52 +02:00
using Content.Server.WireHacking ;
2021-06-09 22:19:39 +02:00
using Content.Shared.Doors ;
2021-07-10 17:35:33 +02:00
using Content.Shared.Sound ;
2021-03-21 09:12:03 -07:00
using Robust.Shared.Audio ;
2019-09-06 10:05:02 +02:00
using Robust.Shared.GameObjects ;
2021-12-03 11:11:52 +01:00
using Robust.Shared.IoC ;
2020-05-27 15:09:22 +02:00
using Robust.Shared.Maths ;
2021-03-21 09:12:03 -07:00
using Robust.Shared.Player ;
2021-07-10 17:35:33 +02:00
using Robust.Shared.Serialization.Manager.Attributes ;
2020-09-08 13:30:22 +02:00
using Robust.Shared.ViewVariables ;
2021-06-09 22:19:39 +02:00
using static Content . Shared . Wires . SharedWiresComponent ;
using static Content . Shared . Wires . SharedWiresComponent . WiresAction ;
2019-09-06 10:05:02 +02:00
2021-06-09 22:19:39 +02:00
namespace Content.Server.Doors.Components
2019-09-06 10:05:02 +02:00
{
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-08-02 04:57:06 -07:00
public class AirlockComponent : Component , IWires
2019-09-06 10:05:02 +02:00
{
public override string Name = > "Airlock" ;
2021-02-12 07:02:14 -08:00
[ComponentDependency]
2021-08-02 04:57:06 -07:00
public readonly ServerDoorComponent ? DoorComponent = null ;
2021-02-12 07:02:14 -08:00
[ComponentDependency]
2021-11-22 23:22:59 -08:00
public readonly AppearanceComponent ? AppearanceComponent = null ;
2021-02-12 07:02:14 -08:00
[ComponentDependency]
2021-08-02 04:57:06 -07:00
public readonly ApcPowerReceiverComponent ? ReceiverComponent = null ;
2021-02-12 07:02:14 -08:00
[ComponentDependency]
2021-08-02 04:57:06 -07:00
public readonly WiresComponent ? WiresComponent = null ;
/// <summary>
/// Sound to play when the bolts on the airlock go up.
/// </summary>
[DataField("boltUpSound")]
public SoundSpecifier BoltUpSound = new SoundPathSpecifier ( "/Audio/Machines/boltsup.ogg" ) ;
/// <summary>
/// Sound to play when the bolts on the airlock go down.
/// </summary>
[DataField("boltDownSound")]
public SoundSpecifier BoltDownSound = new SoundPathSpecifier ( "/Audio/Machines/boltsdown.ogg" ) ;
2021-02-12 07:02:14 -08:00
2019-09-06 10:05:02 +02:00
/// <summary>
/// Duration for which power will be disabled after pulsing either power wire.
/// </summary>
2021-08-02 04:57:06 -07:00
[DataField("powerWiresTimeout")]
public float PowerWiresTimeout = 5.0f ;
2019-09-06 10:05:02 +02:00
2021-08-05 19:43:58 -07:00
/// <summary>
/// Whether the maintenance panel should be visible even if the airlock is opened.
/// </summary>
[DataField("openPanelVisible")]
public bool OpenPanelVisible = false ;
2019-09-06 10:05:02 +02:00
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 ( )
2021-08-02 04:57:06 -07:00
& & 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
[ViewVariables(VVAccess.ReadWrite)]
2021-08-02 04:57:06 -07:00
[DataField("autoClose")]
public bool AutoClose = true ;
2021-02-12 07:02:14 -08:00
[ViewVariables(VVAccess.ReadWrite)]
2021-08-02 04:57:06 -07:00
[DataField("autoCloseDelayModifier")]
public float AutoCloseDelayModifier = 1.0f ;
2021-02-12 07:02:14 -08:00
2020-09-08 13:30:22 +02:00
[ViewVariables(VVAccess.ReadWrite)]
2021-10-28 22:38:36 -07:00
[DataField("safety")]
2021-08-02 04:57:06 -07:00
public bool Safety = true ;
2021-02-12 07:02:14 -08:00
2021-06-19 19:41:26 -07:00
protected override void Initialize ( )
2020-07-17 10:51:43 +02:00
{
2021-02-12 07:02:14 -08:00
base . Initialize ( ) ;
2021-08-02 04:57:06 -07:00
if ( ReceiverComponent ! = null & & AppearanceComponent ! = null )
2021-02-12 07:02:14 -08:00
{
2021-08-02 04:57:06 -07:00
AppearanceComponent . SetData ( DoorVisuals . Powered , ReceiverComponent . Powered ) ;
2021-02-12 07:02:14 -08:00
}
}
2021-08-02 04:57:06 -07:00
public bool CanChangeState ( )
2021-02-12 07:02:14 -08:00
{
return IsPowered ( ) & & ! IsBolted ( ) ;
}
2021-08-02 04:57:06 -07:00
public bool IsBolted ( )
2021-02-12 07:02:14 -08:00
{
return _boltsDown ;
}
2021-08-02 04:57:06 -07:00
public bool IsPowered ( )
2021-02-12 07:02:14 -08:00
{
2021-08-02 04:57:06 -07:00
return ReceiverComponent = = null | | ReceiverComponent . Powered ;
2021-02-12 07:02:14 -08:00
}
2021-08-02 04:57:06 -07:00
public void UpdateBoltLightStatus ( )
2021-02-12 07:02:14 -08:00
{
2021-08-02 04:57:06 -07:00
if ( AppearanceComponent ! = null )
2021-02-12 07:02:14 -08:00
{
2021-08-02 04:57:06 -07:00
AppearanceComponent . SetData ( DoorVisuals . BoltLights , BoltLightsVisible ) ;
2021-02-12 07:02:14 -08:00
}
2020-07-17 10:51:43 +02:00
}
2021-08-02 04:57:06 -07:00
public void UpdateWiresStatus ( )
2019-09-06 10:05:02 +02:00
{
2021-12-22 20:02:26 -08:00
if ( WiresComponent = = null ) return ;
var mainPowerCut = WiresComponent . IsWireCut ( Wires . MainPower ) ;
var backupPowerCut = WiresComponent . IsWireCut ( Wires . BackupPower ) ;
var statusLightState = PowerWiresPulsed ? StatusLightState . BlinkingFast : StatusLightState . On ;
StatusLightData powerLight ;
if ( mainPowerCut & & backupPowerCut )
2021-02-12 07:02:14 -08:00
{
2021-12-22 20:02:26 -08:00
powerLight = new StatusLightData ( Color . DarkGoldenrod , StatusLightState . Off , "POWER" ) ;
2021-02-12 07:02:14 -08:00
}
2021-12-22 20:02:26 -08:00
else if ( mainPowerCut ! = backupPowerCut )
2019-09-06 10:05:02 +02:00
{
2021-12-22 20:02:26 -08:00
powerLight = new StatusLightData ( Color . Gold , statusLightState , "POWER" ) ;
2020-05-27 15:09:22 +02:00
}
2021-12-22 20:02:26 -08:00
else
2019-09-06 10:05:02 +02:00
{
2021-12-22 20:02:26 -08:00
powerLight = new StatusLightData ( Color . Yellow , statusLightState , "POWER" ) ;
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 ,
2021-12-22 20:02:26 -08:00
_boltLightsWirePulsed ? StatusLightState . On : StatusLightState . Off , "BOLT LED" ) ;
2020-07-02 15:31:06 +02:00
2021-08-02 04:57:06 -07:00
var ev = new DoorGetCloseTimeModifierEvent ( ) ;
2021-12-03 15:53:09 +01:00
IoCManager . Resolve < IEntityManager > ( ) . EventBus . RaiseLocalEvent ( Owner , ev , false ) ;
2021-08-02 04:57:06 -07:00
2020-07-17 10:51:43 +02:00
var timingStatus =
2021-08-02 04:57:06 -07:00
new StatusLightData ( Color . Orange , ! AutoClose ? StatusLightState . Off :
2021-09-29 20:07:01 +10:00
! MathHelper . CloseToPercent ( ev . CloseTimeModifier , 1.0f ) ? StatusLightState . BlinkingSlow :
2020-07-17 10:51:43 +02:00
StatusLightState . On ,
"TIME" ) ;
var safetyStatus =
2021-12-22 20:02:26 -08:00
new StatusLightData ( Color . Red , Safety ? StatusLightState . On : StatusLightState . Off , "SAFETY" ) ;
2020-07-17 10:51:43 +02:00
2020-08-22 22:29:20 +02:00
2021-08-02 04:57:06 -07:00
WiresComponent . SetStatus ( AirlockWireStatus . PowerIndicator , powerLight ) ;
WiresComponent . SetStatus ( AirlockWireStatus . BoltIndicator , boltStatus ) ;
WiresComponent . SetStatus ( AirlockWireStatus . BoltLightIndicator , boltLightsStatus ) ;
2021-12-22 20:02:26 -08:00
WiresComponent . SetStatus ( AirlockWireStatus . AIControlIndicator , new StatusLightData ( Color . Purple , StatusLightState . BlinkingSlow , "AI CTRL" ) ) ;
2021-08-02 04:57:06 -07:00
WiresComponent . SetStatus ( AirlockWireStatus . TimingIndicator , timingStatus ) ;
WiresComponent . SetStatus ( AirlockWireStatus . SafetyIndicator , safetyStatus ) ;
2019-09-06 10:05:02 +02:00
}
2019-10-13 18:29:57 +02:00
private void UpdatePowerCutStatus ( )
{
2021-08-02 04:57:06 -07:00
if ( ReceiverComponent = = null )
2020-08-22 22:29:20 +02:00
{
return ;
}
if ( PowerWiresPulsed )
{
2021-08-02 04:57:06 -07:00
ReceiverComponent . PowerDisabled = true ;
2020-08-22 22:29:20 +02:00
return ;
}
2021-08-02 04:57:06 -07:00
if ( WiresComponent = = null )
2020-08-22 22:29:20 +02:00
{
return ;
}
2021-08-02 04:57:06 -07:00
ReceiverComponent . PowerDisabled =
2021-12-22 20:02:26 -08:00
WiresComponent . IsWireCut ( Wires . MainPower ) & &
2021-08-02 04:57:06 -07:00
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-08-02 04:57:06 -07:00
if ( AppearanceComponent ! = null )
2019-10-13 16:39:21 +02:00
{
2021-08-02 04:57:06 -07: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 ) ;
2021-08-02 04:57:06 -07:00
2019-09-06 10:05:02 +02:00
UpdateWiresStatus ( ) ;
}
public void WiresUpdate ( WiresUpdateEventArgs args )
{
2021-08-10 15:05:49 -07:00
if ( DoorComponent = = null )
2021-02-12 07:02:14 -08:00
{
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 ( ) ;
2021-08-02 04:57:06 -07:00
Owner . SpawnTimer ( TimeSpan . FromSeconds ( 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-08-02 04:57:06 -07:00
AutoCloseDelayModifier = 0.5f ;
DoorComponent . RefreshAutoClose ( ) ;
2020-07-17 10:51:43 +02:00
break ;
case Wires . Safety :
2021-08-02 04:57:06 -07: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-08-02 04:57:06 -07:00
AutoClose = true ;
DoorComponent . RefreshAutoClose ( ) ;
2020-07-17 10:51:43 +02:00
break ;
case Wires . Safety :
2021-08-02 04:57:06 -07: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-08-02 04:57:06 -07:00
AutoClose = false ;
DoorComponent . RefreshAutoClose ( ) ;
2020-07-17 10:51:43 +02:00
break ;
case Wires . Safety :
2021-08-02 04:57:06 -07: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-08-02 04:57:06 -07:00
SoundSystem . Play ( Filter . Broadcast ( ) , newBolts ? BoltDownSound . GetSound ( ) : BoltUpSound . GetSound ( ) , Owner ) ;
2020-07-02 15:31:06 +02:00
}
2019-09-06 10:05:02 +02:00
}
}