using System.Threading; using Content.Server.Explosion.EntitySystems; using Content.Shared.Containers.ItemSlots; using Content.Shared.Explosion; using Content.Shared.Nuke; using Robust.Shared.Audio; using Robust.Shared.Map; using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype; namespace Content.Server.Nuke { /// /// Nuclear device that can devastate an entire station. /// Basically a station self-destruction mechanism. /// To activate it, user needs to insert an authorization disk and enter a secret code. /// [RegisterComponent] [Access(typeof(NukeSystem))] public sealed partial class NukeComponent : SharedNukeComponent { /// /// Default bomb timer value in seconds. /// [DataField] public int Timer = 300; /// /// If the nuke is disarmed, this sets the minimum amount of time the timer can have. /// The remaining time will reset to this value if it is below it. /// [DataField] public int MinimumTime = 180; /// /// How long until the bomb can arm again after deactivation. /// Used to prevent announcements spam. /// [DataField] public int Cooldown = 30; /// /// The that stores the nuclear disk. The entity whitelist, sounds, and some other /// behaviours are specified by this definition. Make sure the whitelist, is correct /// otherwise a blank bit of paper will work as a "disk". /// [DataField("diskSlot")] public ItemSlot DiskSlot = new(); /// /// When this time is left, nuke will play last alert sound /// [DataField("alertTime")] public float AlertSoundTime = 10.0f; /// /// How long a user must wait to disarm the bomb. /// [DataField("disarmDoafterLength")] public float DisarmDoafterLength = 30.0f; [DataField("alertLevelOnActivate")] public string AlertLevelOnActivate = default!; [DataField("alertLevelOnDeactivate")] public string AlertLevelOnDeactivate = default!; /// /// This is stored so we can do a funny by making 0 shift the last played note up by 12 semitones (octave) /// public int LastPlayedKeypadSemitones = 0; [DataField("keypadPressSound")] public SoundSpecifier KeypadPressSound = new SoundPathSpecifier("/Audio/Machines/Nuke/general_beep.ogg"); [DataField("accessGrantedSound")] public SoundSpecifier AccessGrantedSound = new SoundPathSpecifier("/Audio/Machines/Nuke/confirm_beep.ogg"); [DataField("accessDeniedSound")] public SoundSpecifier AccessDeniedSound = new SoundPathSpecifier("/Audio/Machines/Nuke/angry_beep.ogg"); [DataField("alertSound")] public SoundSpecifier AlertSound = new SoundPathSpecifier("/Audio/Machines/Nuke/nuke_alarm.ogg"); [DataField("armSound")] public SoundSpecifier ArmSound = new SoundPathSpecifier("/Audio/Misc/notice1.ogg"); [DataField("disarmSound")] public SoundSpecifier DisarmSound = new SoundPathSpecifier("/Audio/Misc/notice2.ogg"); [DataField("armMusic")] public SoundSpecifier ArmMusic = new SoundCollectionSpecifier("NukeMusic"); // These datafields here are duplicates of those in explosive component. But I'm hesitant to use explosive // component, just in case at some point, somehow, when grenade crafting added in someone manages to wire up a // proximity trigger or something to the nuke and set it off prematurely. I want to make sure they MEAN to set of // the nuke. #region ExplosiveComponent /// /// The explosion prototype. This determines the damage types, the tile-break chance, and some visual /// information (e.g., the light that the explosion gives off). /// [ViewVariables(VVAccess.ReadWrite)] [DataField("explosionType", required: true, customTypeSerializer: typeof(PrototypeIdSerializer))] public string ExplosionType = default!; /// /// The maximum intensity the explosion can have on a single time. This limits the maximum damage and tile /// break chance the explosion can achieve at any given location. /// [ViewVariables(VVAccess.ReadWrite)] [DataField("maxIntensity")] public float MaxIntensity = 100; /// /// How quickly the intensity drops off as you move away from the epicenter. /// [ViewVariables(VVAccess.ReadWrite)] [DataField("intensitySlope")] public float IntensitySlope = 5; /// /// The total intensity of this explosion. The radius of the explosion scales like the cube root of this /// number (see ). /// [ViewVariables(VVAccess.ReadWrite)] [DataField("totalIntensity")] public float TotalIntensity = 100000; /// /// Avoid somehow double-triggering this explosion. /// public bool Exploded; #endregion /// /// Origin station of this bomb, if it exists. /// If this doesn't exist, then the origin grid and map will be filled in, instead. /// public EntityUid? OriginStation; /// /// Origin map and grid of this bomb. /// If a station wasn't tied to a given grid when the bomb was spawned, /// this will be filled in instead. /// public (MapId, EntityUid?)? OriginMapGrid; [DataField] public int CodeLength = 6; [DataField] public string Code = string.Empty; /// /// Time until explosion in seconds. /// [DataField] public float RemainingTime; /// /// Time until bomb cooldown will expire in seconds. /// [DataField] public float CooldownTime; /// /// Current nuclear code buffer. Entered manually by players. /// If valid it will allow arm/disarm bomb. /// [DataField] public string EnteredCode = ""; /// /// Current status of a nuclear bomb. /// [DataField] public NukeStatus Status = NukeStatus.AWAIT_DISK; /// /// Check if nuke has already played the nuke song so we don't do it again /// public bool PlayedNukeSong = false; /// /// Check if nuke has already played last alert sound /// public bool PlayedAlertSound = false; public EntityUid? AlertAudioStream = default; /// /// The radius from the nuke for which there must be floor tiles for it to be anchorable. /// [ViewVariables(VVAccess.ReadWrite)] [DataField("requiredFloorRadius")] public float RequiredFloorRadius = 5; } }