Experimental nukie changes (#9428)
This commit is contained in:
@@ -103,7 +103,7 @@ namespace Content.Client.Nuke
|
|||||||
FirstStatusLabel.Text = firstMsg;
|
FirstStatusLabel.Text = firstMsg;
|
||||||
SecondStatusLabel.Text = secondMsg;
|
SecondStatusLabel.Text = secondMsg;
|
||||||
|
|
||||||
EjectButton.Disabled = !state.DiskInserted;
|
EjectButton.Disabled = !state.DiskInserted || state.Status == NukeStatus.ARMED;
|
||||||
AnchorButton.Disabled = !state.DiskInserted;
|
AnchorButton.Disabled = !state.DiskInserted;
|
||||||
AnchorButton.Pressed = state.IsAnchored;
|
AnchorButton.Pressed = state.IsAnchored;
|
||||||
ArmButton.Disabled = !state.AllowArm;
|
ArmButton.Disabled = !state.AllowArm;
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
using System.Threading;
|
||||||
using Content.Shared.Containers.ItemSlots;
|
using Content.Shared.Containers.ItemSlots;
|
||||||
using Content.Shared.Explosion;
|
using Content.Shared.Explosion;
|
||||||
using Content.Shared.Nuke;
|
using Content.Shared.Nuke;
|
||||||
@@ -18,11 +19,10 @@ namespace Content.Server.Nuke
|
|||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Default bomb timer value in seconds.
|
/// Default bomb timer value in seconds.
|
||||||
/// Must be shorter then the nuke alarm song.
|
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[DataField("timer")]
|
[DataField("timer")]
|
||||||
[ViewVariables(VVAccess.ReadWrite)]
|
[ViewVariables(VVAccess.ReadWrite)]
|
||||||
public int Timer = 120;
|
public int Timer = 300;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// How long until the bomb can arm again after deactivation.
|
/// How long until the bomb can arm again after deactivation.
|
||||||
@@ -40,11 +40,17 @@ namespace Content.Server.Nuke
|
|||||||
public ItemSlot DiskSlot = new();
|
public ItemSlot DiskSlot = new();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// After this time nuke will play last alert sound
|
/// When this time is left, nuke will play last alert sound
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[DataField("alertTime")]
|
[DataField("alertTime")]
|
||||||
public float AlertSoundTime = 10.0f;
|
public float AlertSoundTime = 10.0f;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// How long a user must wait to disarm the bomb.
|
||||||
|
/// </summary>
|
||||||
|
[DataField("disarmDoafterLength")]
|
||||||
|
public float DisarmDoafterLength = 30.0f;
|
||||||
|
|
||||||
[DataField("alertLevelOnActivate")] public string AlertLevelOnActivate = default!;
|
[DataField("alertLevelOnActivate")] public string AlertLevelOnActivate = default!;
|
||||||
[DataField("alertLevelOnDeactivate")] public string AlertLevelOnDeactivate = default!;
|
[DataField("alertLevelOnDeactivate")] public string AlertLevelOnDeactivate = default!;
|
||||||
|
|
||||||
@@ -136,11 +142,18 @@ namespace Content.Server.Nuke
|
|||||||
[ViewVariables]
|
[ViewVariables]
|
||||||
public NukeStatus Status = NukeStatus.AWAIT_DISK;
|
public NukeStatus Status = NukeStatus.AWAIT_DISK;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Check if nuke has already played the nuke song so we don't do it again
|
||||||
|
/// </summary>
|
||||||
|
public bool PlayedNukeSong = false;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Check if nuke has already played last alert sound
|
/// Check if nuke has already played last alert sound
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public bool PlayedAlertSound = false;
|
public bool PlayedAlertSound = false;
|
||||||
|
|
||||||
|
public CancellationToken? DisarmCancelToken = null;
|
||||||
|
|
||||||
public IPlayingAudioStream? AlertAudioStream = default;
|
public IPlayingAudioStream? AlertAudioStream = default;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ using Content.Server.Chat;
|
|||||||
using Content.Server.Chat.Managers;
|
using Content.Server.Chat.Managers;
|
||||||
using Content.Server.Chat.Systems;
|
using Content.Server.Chat.Systems;
|
||||||
using Content.Server.Coordinates.Helpers;
|
using Content.Server.Coordinates.Helpers;
|
||||||
|
using Content.Server.DoAfter;
|
||||||
using Content.Server.Explosion.EntitySystems;
|
using Content.Server.Explosion.EntitySystems;
|
||||||
using Content.Server.Popups;
|
using Content.Server.Popups;
|
||||||
using Content.Server.Station.Systems;
|
using Content.Server.Station.Systems;
|
||||||
@@ -30,6 +31,17 @@ namespace Content.Server.Nuke
|
|||||||
[Dependency] private readonly StationSystem _stationSystem = default!;
|
[Dependency] private readonly StationSystem _stationSystem = default!;
|
||||||
[Dependency] private readonly ServerGlobalSoundSystem _soundSystem = default!;
|
[Dependency] private readonly ServerGlobalSoundSystem _soundSystem = default!;
|
||||||
[Dependency] private readonly ChatSystem _chatSystem = default!;
|
[Dependency] private readonly ChatSystem _chatSystem = default!;
|
||||||
|
[Dependency] private readonly DoAfterSystem _doAfterSystem = default!;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Used to calculate when the nuke song should start playing for maximum kino with the nuke sfx
|
||||||
|
/// </summary>
|
||||||
|
private const float NukeSongLength = 60f + 51.6f;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Time to leave between the nuke song and the nuke alarm playing.
|
||||||
|
/// </summary>
|
||||||
|
private const float NukeSongBuffer = 1.5f;
|
||||||
|
|
||||||
public override void Initialize()
|
public override void Initialize()
|
||||||
{
|
{
|
||||||
@@ -51,6 +63,10 @@ namespace Content.Server.Nuke
|
|||||||
SubscribeLocalEvent<NukeComponent, NukeKeypadMessage>(OnKeypadButtonPressed);
|
SubscribeLocalEvent<NukeComponent, NukeKeypadMessage>(OnKeypadButtonPressed);
|
||||||
SubscribeLocalEvent<NukeComponent, NukeKeypadClearMessage>(OnClearButtonPressed);
|
SubscribeLocalEvent<NukeComponent, NukeKeypadClearMessage>(OnClearButtonPressed);
|
||||||
SubscribeLocalEvent<NukeComponent, NukeKeypadEnterMessage>(OnEnterButtonPressed);
|
SubscribeLocalEvent<NukeComponent, NukeKeypadEnterMessage>(OnEnterButtonPressed);
|
||||||
|
|
||||||
|
// Doafter events
|
||||||
|
SubscribeLocalEvent<NukeComponent, NukeDisarmSuccessEvent>(OnDisarmSuccess);
|
||||||
|
SubscribeLocalEvent<NukeComponent, NukeDisarmCancelledEvent>(OnDisarmCancelled);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnInit(EntityUid uid, NukeComponent component, ComponentInit args)
|
private void OnInit(EntityUid uid, NukeComponent component, ComponentInit args)
|
||||||
@@ -98,6 +114,7 @@ namespace Content.Server.Nuke
|
|||||||
}
|
}
|
||||||
|
|
||||||
#region Anchor
|
#region Anchor
|
||||||
|
|
||||||
private void OnAnchorAttempt(EntityUid uid, NukeComponent component, AnchorAttemptEvent args)
|
private void OnAnchorAttempt(EntityUid uid, NukeComponent component, AnchorAttemptEvent args)
|
||||||
{
|
{
|
||||||
CheckAnchorAttempt(uid, component, args);
|
CheckAnchorAttempt(uid, component, args);
|
||||||
@@ -124,9 +141,11 @@ namespace Content.Server.Nuke
|
|||||||
{
|
{
|
||||||
UpdateUserInterface(uid, component);
|
UpdateUserInterface(uid, component);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region UI Events
|
#region UI Events
|
||||||
|
|
||||||
private async void OnAnchorButtonPressed(EntityUid uid, NukeComponent component, NukeAnchorMessage args)
|
private async void OnAnchorButtonPressed(EntityUid uid, NukeComponent component, NukeAnchorMessage args)
|
||||||
{
|
{
|
||||||
if (!component.DiskSlot.HasItem)
|
if (!component.DiskSlot.HasItem)
|
||||||
@@ -188,9 +207,28 @@ namespace Content.Server.Nuke
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
DisarmBomb(uid, component);
|
if (args.Session.AttachedEntity is not { } user)
|
||||||
|
return;
|
||||||
|
|
||||||
|
DisarmBombDoafter(uid, user, component);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Doafter Events
|
||||||
|
|
||||||
|
private void OnDisarmSuccess(EntityUid uid, NukeComponent component, NukeDisarmSuccessEvent args)
|
||||||
|
{
|
||||||
|
component.DisarmCancelToken = null;
|
||||||
|
DisarmBomb(uid, component);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnDisarmCancelled(EntityUid uid, NukeComponent component, NukeDisarmCancelledEvent args)
|
||||||
|
{
|
||||||
|
component.DisarmCancelToken = null;
|
||||||
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
private void TickCooldown(EntityUid uid, float frameTime, NukeComponent? nuke = null)
|
private void TickCooldown(EntityUid uid, float frameTime, NukeComponent? nuke = null)
|
||||||
@@ -217,6 +255,14 @@ namespace Content.Server.Nuke
|
|||||||
|
|
||||||
nuke.RemainingTime -= frameTime;
|
nuke.RemainingTime -= frameTime;
|
||||||
|
|
||||||
|
// Start playing the nuke event song so that it ends a couple seconds before the alert sound
|
||||||
|
// should play
|
||||||
|
if (nuke.RemainingTime <= NukeSongLength + nuke.AlertSoundTime + NukeSongBuffer && !nuke.PlayedNukeSong)
|
||||||
|
{
|
||||||
|
_soundSystem.DispatchStationEventMusic(uid, nuke.ArmMusic, StationEventMusicType.Nuke);
|
||||||
|
nuke.PlayedNukeSong = true;
|
||||||
|
}
|
||||||
|
|
||||||
// play alert sound if time is running out
|
// play alert sound if time is running out
|
||||||
if (nuke.RemainingTime <= nuke.AlertSoundTime && !nuke.PlayedAlertSound)
|
if (nuke.RemainingTime <= nuke.AlertSoundTime && !nuke.PlayedAlertSound)
|
||||||
{
|
{
|
||||||
@@ -248,28 +294,29 @@ namespace Content.Server.Nuke
|
|||||||
component.Status = NukeStatus.AWAIT_CODE;
|
component.Status = NukeStatus.AWAIT_CODE;
|
||||||
break;
|
break;
|
||||||
case NukeStatus.AWAIT_CODE:
|
case NukeStatus.AWAIT_CODE:
|
||||||
|
{
|
||||||
|
if (!component.DiskSlot.HasItem)
|
||||||
{
|
{
|
||||||
if (!component.DiskSlot.HasItem)
|
component.Status = NukeStatus.AWAIT_DISK;
|
||||||
{
|
component.EnteredCode = "";
|
||||||
component.Status = NukeStatus.AWAIT_DISK;
|
|
||||||
component.EnteredCode = "";
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
var isValid = _codes.IsCodeValid(component.EnteredCode);
|
|
||||||
if (isValid)
|
|
||||||
{
|
|
||||||
component.Status = NukeStatus.AWAIT_ARM;
|
|
||||||
component.RemainingTime = component.Timer;
|
|
||||||
PlaySound(uid, component.AccessGrantedSound, 0, component);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
component.EnteredCode = "";
|
|
||||||
PlaySound(uid, component.AccessDeniedSound, 0, component);
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var isValid = _codes.IsCodeValid(component.EnteredCode);
|
||||||
|
if (isValid)
|
||||||
|
{
|
||||||
|
component.Status = NukeStatus.AWAIT_ARM;
|
||||||
|
component.RemainingTime = component.Timer;
|
||||||
|
PlaySound(uid, component.AccessGrantedSound, 0, component);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
component.EnteredCode = "";
|
||||||
|
PlaySound(uid, component.AccessDeniedSound, 0, component);
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
case NukeStatus.AWAIT_ARM:
|
case NukeStatus.AWAIT_ARM:
|
||||||
// do nothing, wait for arm button to be pressed
|
// do nothing, wait for arm button to be pressed
|
||||||
break;
|
break;
|
||||||
@@ -322,6 +369,7 @@ namespace Content.Server.Nuke
|
|||||||
}
|
}
|
||||||
|
|
||||||
#region Public API
|
#region Public API
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Force a nuclear bomb to start a countdown timer
|
/// Force a nuclear bomb to start a countdown timer
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -350,6 +398,7 @@ namespace Content.Server.Nuke
|
|||||||
|
|
||||||
NukeArmedAudio(component);
|
NukeArmedAudio(component);
|
||||||
|
|
||||||
|
_itemSlots.SetLock(uid, component.DiskSlot, true);
|
||||||
component.Status = NukeStatus.ARMED;
|
component.Status = NukeStatus.ARMED;
|
||||||
UpdateUserInterface(uid, component);
|
UpdateUserInterface(uid, component);
|
||||||
}
|
}
|
||||||
@@ -376,6 +425,7 @@ namespace Content.Server.Nuke
|
|||||||
var sender = Loc.GetString("nuke-component-announcement-sender");
|
var sender = Loc.GetString("nuke-component-announcement-sender");
|
||||||
_chatSystem.DispatchStationAnnouncement(uid, announcement, sender, false);
|
_chatSystem.DispatchStationAnnouncement(uid, announcement, sender, false);
|
||||||
|
|
||||||
|
component.PlayedNukeSong = false;
|
||||||
NukeDisarmedAudio(component);
|
NukeDisarmedAudio(component);
|
||||||
|
|
||||||
// disable sound and reset it
|
// disable sound and reset it
|
||||||
@@ -383,6 +433,7 @@ namespace Content.Server.Nuke
|
|||||||
component.AlertAudioStream?.Stop();
|
component.AlertAudioStream?.Stop();
|
||||||
|
|
||||||
// start bomb cooldown
|
// start bomb cooldown
|
||||||
|
_itemSlots.SetLock(uid, component.DiskSlot, false);
|
||||||
component.Status = NukeStatus.COOLDOWN;
|
component.Status = NukeStatus.COOLDOWN;
|
||||||
component.CooldownTime = component.Cooldown;
|
component.CooldownTime = component.Cooldown;
|
||||||
|
|
||||||
@@ -440,12 +491,30 @@ namespace Content.Server.Nuke
|
|||||||
component.RemainingTime = timer;
|
component.RemainingTime = timer;
|
||||||
UpdateUserInterface(uid, component);
|
UpdateUserInterface(uid, component);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
private void DisarmBombDoafter(EntityUid uid, EntityUid user, NukeComponent nuke)
|
||||||
|
{
|
||||||
|
nuke.DisarmCancelToken = new();
|
||||||
|
var doafter = new DoAfterEventArgs(user, nuke.DisarmDoafterLength, nuke.DisarmCancelToken.Value, uid)
|
||||||
|
{
|
||||||
|
TargetCancelledEvent = new NukeDisarmCancelledEvent(),
|
||||||
|
TargetFinishedEvent = new NukeDisarmSuccessEvent(),
|
||||||
|
BreakOnDamage = true,
|
||||||
|
BreakOnStun = true,
|
||||||
|
BreakOnTargetMove = true,
|
||||||
|
BreakOnUserMove = true,
|
||||||
|
NeedHand = true,
|
||||||
|
};
|
||||||
|
|
||||||
|
_doAfterSystem.DoAfter(doafter);
|
||||||
|
_popups.PopupEntity(Loc.GetString("nuke-component-doafter-warning"), user, Filter.Entities(user));
|
||||||
|
}
|
||||||
|
|
||||||
private void NukeArmedAudio(NukeComponent component)
|
private void NukeArmedAudio(NukeComponent component)
|
||||||
{
|
{
|
||||||
_soundSystem.PlayGlobalOnStation(component.Owner, component.ArmSound.GetSound());
|
_soundSystem.PlayGlobalOnStation(component.Owner, component.ArmSound.GetSound());
|
||||||
_soundSystem.DispatchStationEventMusic(component.Owner, component.ArmMusic, StationEventMusicType.Nuke);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void NukeDisarmedAudio(NukeComponent component)
|
private void NukeDisarmedAudio(NukeComponent component)
|
||||||
@@ -456,4 +525,15 @@ namespace Content.Server.Nuke
|
|||||||
}
|
}
|
||||||
|
|
||||||
public sealed class NukeExplodedEvent : EntityEventArgs {}
|
public sealed class NukeExplodedEvent : EntityEventArgs {}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Raised directed on the nuke when its disarm doafter is successful.
|
||||||
|
/// </summary>
|
||||||
|
public sealed class NukeDisarmSuccessEvent : EntityEventArgs {}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Raised directed on the nuke when its disarm doafter is cancelled.
|
||||||
|
/// </summary>
|
||||||
|
public sealed class NukeDisarmCancelledEvent : EntityEventArgs {}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -571,7 +571,7 @@ namespace Content.Shared.CCVar
|
|||||||
/// Actual area may be larger, as it currently doesn't terminate mid neighbor finding. I.e., area may be that of a ~51 tile radius circle instead.
|
/// Actual area may be larger, as it currently doesn't terminate mid neighbor finding. I.e., area may be that of a ~51 tile radius circle instead.
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
public static readonly CVarDef<int> ExplosionMaxArea =
|
public static readonly CVarDef<int> ExplosionMaxArea =
|
||||||
CVarDef.Create("explosion.max_area", (int) 3.14f * 50 * 50, CVar.SERVERONLY);
|
CVarDef.Create("explosion.max_area", (int) 3.14f * 256 * 256, CVar.SERVERONLY);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Upper limit on the number of neighbor finding steps for the explosion system neighbor-finding algorithm.
|
/// Upper limit on the number of neighbor finding steps for the explosion system neighbor-finding algorithm.
|
||||||
@@ -581,7 +581,7 @@ namespace Content.Shared.CCVar
|
|||||||
/// instances, <see cref="ExplosionMaxArea"/> will likely be hit before this becomes a limiting factor.
|
/// instances, <see cref="ExplosionMaxArea"/> will likely be hit before this becomes a limiting factor.
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
public static readonly CVarDef<int> ExplosionMaxIterations =
|
public static readonly CVarDef<int> ExplosionMaxIterations =
|
||||||
CVarDef.Create("explosion.max_iterations", 150, CVar.SERVERONLY);
|
CVarDef.Create("explosion.max_iterations", 500, CVar.SERVERONLY);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Max Time in milliseconds to spend processing explosions every tick.
|
/// Max Time in milliseconds to spend processing explosions every tick.
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ nuke-component-announcement-sender = Nuclear Fission Explosive
|
|||||||
nuke-component-announcement-armed = Attention! The station's self-destruct mechanism has been engaged. {$time} seconds until detonation.
|
nuke-component-announcement-armed = Attention! The station's self-destruct mechanism has been engaged. {$time} seconds until detonation.
|
||||||
nuke-component-announcement-unarmed = The station's self-destruct was deactivated! Have a nice day!
|
nuke-component-announcement-unarmed = The station's self-destruct was deactivated! Have a nice day!
|
||||||
nuke-component-announcement-send-codes = Attention! Requested self-destruction codes was sent to communication consoles.
|
nuke-component-announcement-send-codes = Attention! Requested self-destruction codes was sent to communication consoles.
|
||||||
|
nuke-component-doafter-warning = You start fiddling with wires and knobs in order to disarm the nuke.. This may take a while.
|
||||||
|
|
||||||
# Nuke UI
|
# Nuke UI
|
||||||
nuke-user-interface-title = Nuclear Fission Explosive
|
nuke-user-interface-title = Nuclear Fission Explosive
|
||||||
|
|||||||
@@ -23,12 +23,10 @@
|
|||||||
layer:
|
layer:
|
||||||
- HalfWallLayer
|
- HalfWallLayer
|
||||||
- type: Nuke
|
- type: Nuke
|
||||||
# ~50 tile radius in open space
|
|
||||||
# close to defaulkt max cap.
|
|
||||||
explosionType: Default
|
explosionType: Default
|
||||||
maxIntensity: 100
|
maxIntensity: 100
|
||||||
intensitySlope: 5
|
intensitySlope: 5
|
||||||
totalIntensity: 500000
|
totalIntensity: 5000000
|
||||||
diskSlot:
|
diskSlot:
|
||||||
name: Disk
|
name: Disk
|
||||||
insertSound:
|
insertSound:
|
||||||
|
|||||||
Reference in New Issue
Block a user