Experimental nukie changes (#9428)

This commit is contained in:
Kara
2022-07-04 23:49:19 -07:00
committed by GitHub
parent 398f05657c
commit 69871ef73a
6 changed files with 122 additions and 30 deletions

View File

@@ -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;

View File

@@ -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;
} }
} }

View File

@@ -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 {}
} }

View File

@@ -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.

View File

@@ -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

View File

@@ -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: