Gives all nuclear bombs unique codes (#11665)
Co-authored-by: Kara <lunarautomaton6@gmail.com>
This commit is contained in:
@@ -10,12 +10,22 @@ namespace Content.Server.Nuke.Commands
|
|||||||
public sealed class SendNukeCodesCommand : IConsoleCommand
|
public sealed class SendNukeCodesCommand : IConsoleCommand
|
||||||
{
|
{
|
||||||
public string Command => "nukecodes";
|
public string Command => "nukecodes";
|
||||||
public string Description => "Send nuke codes to the communication console";
|
public string Description => "Send nuke codes to a station's communication consoles";
|
||||||
public string Help => "nukecodes";
|
public string Help => "nukecodes [station EntityUid]";
|
||||||
|
|
||||||
public void Execute(IConsoleShell shell, string argStr, string[] args)
|
public void Execute(IConsoleShell shell, string argStr, string[] args)
|
||||||
{
|
{
|
||||||
EntitySystem.Get<NukeCodeSystem>().SendNukeCodes();
|
if (args.Length != 1)
|
||||||
|
{
|
||||||
|
shell.WriteError("shell-need-exactly-one-argument");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!EntityUid.TryParse(args[0], out var uid))
|
||||||
|
{
|
||||||
|
shell.WriteError(Loc.GetString("shell-entity-uid-must-be-number"));
|
||||||
|
}
|
||||||
|
|
||||||
|
IoCManager.Resolve<EntityManager>().System<NukeCodePaperSystem>().SendNukeCodes(uid);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,24 +1,90 @@
|
|||||||
|
using Content.Server.Chat.Systems;
|
||||||
|
using Content.Server.Communications;
|
||||||
using Content.Server.Paper;
|
using Content.Server.Paper;
|
||||||
|
using Content.Server.Station.Components;
|
||||||
|
using Content.Server.Station.Systems;
|
||||||
|
|
||||||
namespace Content.Server.Nuke
|
namespace Content.Server.Nuke
|
||||||
{
|
{
|
||||||
public sealed class NukeCodePaperSystem : EntitySystem
|
public sealed class NukeCodePaperSystem : EntitySystem
|
||||||
{
|
{
|
||||||
[Dependency] private readonly NukeCodeSystem _codes = default!;
|
[Dependency] private readonly ChatSystem _chatSystem = default!;
|
||||||
|
[Dependency] private readonly StationSystem _station = default!;
|
||||||
|
|
||||||
|
private const string NukePaperPrototype = "NukeCodePaper";
|
||||||
|
|
||||||
public override void Initialize()
|
public override void Initialize()
|
||||||
{
|
{
|
||||||
base.Initialize();
|
base.Initialize();
|
||||||
SubscribeLocalEvent<NukeCodePaperComponent, MapInitEvent>(OnMapInit);
|
SubscribeLocalEvent<NukeCodePaperComponent, MapInitEvent>(OnMapInit,
|
||||||
|
after: new []{ typeof(NukeLabelSystem) });
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnMapInit(EntityUid uid, NukeCodePaperComponent component, MapInitEvent args)
|
private void OnMapInit(EntityUid uid, NukeCodePaperComponent component, MapInitEvent args)
|
||||||
{
|
{
|
||||||
PaperComponent? paper = null;
|
SetupPaper(uid);
|
||||||
if (!Resolve(uid, ref paper))
|
}
|
||||||
return;
|
|
||||||
|
|
||||||
paper.Content += _codes.Code;
|
private void SetupPaper(EntityUid uid, EntityUid? station = null, PaperComponent? paper = null)
|
||||||
|
{
|
||||||
|
if (!Resolve(uid, ref paper))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var owningStation = station ?? _station.GetOwningStation(uid);
|
||||||
|
var transform = Transform(uid);
|
||||||
|
|
||||||
|
// Find the first nuke that matches the paper's location.
|
||||||
|
foreach (var nuke in EntityQuery<NukeComponent>())
|
||||||
|
{
|
||||||
|
if (owningStation == null && nuke.OriginMapGrid != (transform.MapID, transform.GridUid)
|
||||||
|
|| nuke.OriginStation != owningStation)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
paper.Content += $"{MetaData(nuke.Owner).EntityName} - {nuke.Code}";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Send a nuclear code to all communication consoles
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>True if at least one console received codes</returns>
|
||||||
|
public bool SendNukeCodes(EntityUid station)
|
||||||
|
{
|
||||||
|
if (!HasComp<StationDataComponent>(station))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// todo: this should probably be handled by fax system
|
||||||
|
var wasSent = false;
|
||||||
|
var consoles = EntityQuery<CommunicationsConsoleComponent, TransformComponent>();
|
||||||
|
foreach (var (console, transform) in consoles)
|
||||||
|
{
|
||||||
|
var owningStation = _station.GetOwningStation(console.Owner);
|
||||||
|
if (owningStation == null || owningStation != station)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
var consolePos = transform.MapPosition;
|
||||||
|
var uid = Spawn(NukePaperPrototype, consolePos);
|
||||||
|
SetupPaper(uid, station);
|
||||||
|
|
||||||
|
wasSent = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (wasSent)
|
||||||
|
{
|
||||||
|
var msg = Loc.GetString("nuke-component-announcement-send-codes");
|
||||||
|
_chatSystem.DispatchStationAnnouncement(station, msg, colorOverride: Color.Red);
|
||||||
|
}
|
||||||
|
|
||||||
|
return wasSent;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,88 +0,0 @@
|
|||||||
using Content.Server.Chat;
|
|
||||||
using Content.Server.Chat.Systems;
|
|
||||||
using Content.Server.Communications;
|
|
||||||
using Content.Server.Station.Systems;
|
|
||||||
using Content.Shared.GameTicking;
|
|
||||||
using Robust.Shared.Random;
|
|
||||||
|
|
||||||
namespace Content.Server.Nuke
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Nuclear code is generated once per round
|
|
||||||
/// One code works for all nukes
|
|
||||||
/// </summary>
|
|
||||||
public sealed class NukeCodeSystem : EntitySystem
|
|
||||||
{
|
|
||||||
[Dependency] private readonly IRobustRandom _random = default!;
|
|
||||||
[Dependency] private readonly ChatSystem _chatSystem = default!;
|
|
||||||
|
|
||||||
private const int CodeLength = 6;
|
|
||||||
public string Code { get; private set; } = default!;
|
|
||||||
|
|
||||||
public override void Initialize()
|
|
||||||
{
|
|
||||||
base.Initialize();
|
|
||||||
GenerateNewCode();
|
|
||||||
|
|
||||||
SubscribeLocalEvent<RoundRestartCleanupEvent>(OnRestart);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnRestart(RoundRestartCleanupEvent ev)
|
|
||||||
{
|
|
||||||
GenerateNewCode();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Checks if code is equal to current bombs code
|
|
||||||
/// </summary>
|
|
||||||
public bool IsCodeValid(string code)
|
|
||||||
{
|
|
||||||
return code == Code;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Generate a new nuclear bomb code. Replacing old one.
|
|
||||||
/// </summary>
|
|
||||||
public void GenerateNewCode()
|
|
||||||
{
|
|
||||||
var ret = "";
|
|
||||||
for (var i = 0; i < CodeLength; i++)
|
|
||||||
{
|
|
||||||
var c = (char) _random.Next('0', '9' + 1);
|
|
||||||
ret += c;
|
|
||||||
}
|
|
||||||
|
|
||||||
Code = ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Send a nuclear code to all communication consoles
|
|
||||||
/// </summary>
|
|
||||||
/// <returns>True if at least one console received codes</returns>
|
|
||||||
public bool SendNukeCodes()
|
|
||||||
{
|
|
||||||
// todo: this should probably be handled by fax system
|
|
||||||
var wasSent = false;
|
|
||||||
var consoles = EntityManager.EntityQuery<CommunicationsConsoleComponent>();
|
|
||||||
foreach (var console in consoles)
|
|
||||||
{
|
|
||||||
if (!EntityManager.TryGetComponent((console).Owner, out TransformComponent? transform))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
var consolePos = transform.MapPosition;
|
|
||||||
EntityManager.SpawnEntity("NukeCodePaper", consolePos);
|
|
||||||
|
|
||||||
wasSent = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: Allow selecting a station for nuke codes
|
|
||||||
if (wasSent)
|
|
||||||
{
|
|
||||||
var msg = Loc.GetString("nuke-component-announcement-send-codes");
|
|
||||||
_chatSystem.DispatchGlobalAnnouncement(msg, colorOverride: Color.Red);
|
|
||||||
}
|
|
||||||
|
|
||||||
return wasSent;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -3,6 +3,7 @@ using Content.Shared.Containers.ItemSlots;
|
|||||||
using Content.Shared.Explosion;
|
using Content.Shared.Explosion;
|
||||||
using Content.Shared.Nuke;
|
using Content.Shared.Nuke;
|
||||||
using Robust.Shared.Audio;
|
using Robust.Shared.Audio;
|
||||||
|
using Robust.Shared.Map;
|
||||||
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype;
|
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype;
|
||||||
|
|
||||||
namespace Content.Server.Nuke
|
namespace Content.Server.Nuke
|
||||||
@@ -121,6 +122,22 @@ namespace Content.Server.Nuke
|
|||||||
public bool Exploded;
|
public bool Exploded;
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Origin station of this bomb, if it exists.
|
||||||
|
/// If this doesn't exist, then the origin grid and map will be filled in, instead.
|
||||||
|
/// </summary>
|
||||||
|
public EntityUid? OriginStation;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 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.
|
||||||
|
/// </summary>
|
||||||
|
public (MapId, EntityUid?)? OriginMapGrid;
|
||||||
|
|
||||||
|
[DataField("codeLength")] public int CodeLength = 6;
|
||||||
|
[ViewVariables] public string Code = string.Empty;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Time until explosion in seconds.
|
/// Time until explosion in seconds.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
14
Content.Server/Nuke/NukeLabelComponent.cs
Normal file
14
Content.Server/Nuke/NukeLabelComponent.cs
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
namespace Content.Server.Nuke;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// This generates a label for a nuclear bomb.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// This is a separate component because the fake nuclear bomb keg exists.
|
||||||
|
/// </remarks>
|
||||||
|
[RegisterComponent]
|
||||||
|
public sealed class NukeLabelComponent : Component
|
||||||
|
{
|
||||||
|
[DataField("prefix")] public string NukeLabel = "nuke-label-nanotrasen";
|
||||||
|
[DataField("serialLength")] public int SerialLength = 6;
|
||||||
|
}
|
||||||
21
Content.Server/Nuke/NukeLabelSystem.cs
Normal file
21
Content.Server/Nuke/NukeLabelSystem.cs
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
namespace Content.Server.Nuke;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// This handles labelling an entity with a nuclear bomb label.
|
||||||
|
/// </summary>
|
||||||
|
public sealed class NukeLabelSystem : EntitySystem
|
||||||
|
{
|
||||||
|
[Dependency] private readonly NukeSystem _nuke = default!;
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public override void Initialize()
|
||||||
|
{
|
||||||
|
SubscribeLocalEvent<NukeLabelComponent, MapInitEvent>(OnMapInit);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnMapInit(EntityUid uid, NukeLabelComponent nuke, MapInitEvent args)
|
||||||
|
{
|
||||||
|
var label = Loc.GetString(nuke.NukeLabel, ("serial", _nuke.GenerateRandomNumberString(nuke.SerialLength)));
|
||||||
|
var meta = MetaData(uid);
|
||||||
|
meta.EntityName = $"{meta.EntityName} ({label})";
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,3 +1,4 @@
|
|||||||
|
using System.Text;
|
||||||
using Content.Server.AlertLevel;
|
using Content.Server.AlertLevel;
|
||||||
using Content.Server.Audio;
|
using Content.Server.Audio;
|
||||||
using Content.Server.Chat;
|
using Content.Server.Chat;
|
||||||
@@ -17,13 +18,13 @@ using Content.Shared.Popups;
|
|||||||
using Robust.Shared.Audio;
|
using Robust.Shared.Audio;
|
||||||
using Robust.Shared.Containers;
|
using Robust.Shared.Containers;
|
||||||
using Robust.Shared.Player;
|
using Robust.Shared.Player;
|
||||||
|
using Robust.Shared.Random;
|
||||||
using Robust.Shared.Timing;
|
using Robust.Shared.Timing;
|
||||||
|
|
||||||
namespace Content.Server.Nuke
|
namespace Content.Server.Nuke
|
||||||
{
|
{
|
||||||
public sealed class NukeSystem : EntitySystem
|
public sealed class NukeSystem : EntitySystem
|
||||||
{
|
{
|
||||||
[Dependency] private readonly NukeCodeSystem _codes = default!;
|
|
||||||
[Dependency] private readonly ItemSlotsSystem _itemSlots = default!;
|
[Dependency] private readonly ItemSlotsSystem _itemSlots = default!;
|
||||||
[Dependency] private readonly PopupSystem _popups = default!;
|
[Dependency] private readonly PopupSystem _popups = default!;
|
||||||
[Dependency] private readonly ExplosionSystem _explosions = default!;
|
[Dependency] private readonly ExplosionSystem _explosions = default!;
|
||||||
@@ -32,6 +33,7 @@ namespace Content.Server.Nuke
|
|||||||
[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!;
|
[Dependency] private readonly DoAfterSystem _doAfterSystem = default!;
|
||||||
|
[Dependency] private readonly IRobustRandom _random = default!;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Used to calculate when the nuke song should start playing for maximum kino with the nuke sfx
|
/// Used to calculate when the nuke song should start playing for maximum kino with the nuke sfx
|
||||||
@@ -48,6 +50,7 @@ namespace Content.Server.Nuke
|
|||||||
base.Initialize();
|
base.Initialize();
|
||||||
SubscribeLocalEvent<NukeComponent, ComponentInit>(OnInit);
|
SubscribeLocalEvent<NukeComponent, ComponentInit>(OnInit);
|
||||||
SubscribeLocalEvent<NukeComponent, ComponentRemove>(OnRemove);
|
SubscribeLocalEvent<NukeComponent, ComponentRemove>(OnRemove);
|
||||||
|
SubscribeLocalEvent<NukeComponent, MapInitEvent>(OnMapInit);
|
||||||
SubscribeLocalEvent<NukeComponent, EntInsertedIntoContainerMessage>(OnItemSlotChanged);
|
SubscribeLocalEvent<NukeComponent, EntInsertedIntoContainerMessage>(OnItemSlotChanged);
|
||||||
SubscribeLocalEvent<NukeComponent, EntRemovedFromContainerMessage>(OnItemSlotChanged);
|
SubscribeLocalEvent<NukeComponent, EntRemovedFromContainerMessage>(OnItemSlotChanged);
|
||||||
|
|
||||||
@@ -97,6 +100,23 @@ namespace Content.Server.Nuke
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void OnMapInit(EntityUid uid, NukeComponent nuke, MapInitEvent args)
|
||||||
|
{
|
||||||
|
var originStation = _stationSystem.GetOwningStation(uid);
|
||||||
|
|
||||||
|
if (originStation != null)
|
||||||
|
{
|
||||||
|
nuke.OriginStation = originStation;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var transform = Transform(uid);
|
||||||
|
nuke.OriginMapGrid = (transform.MapID, transform.GridUid);
|
||||||
|
}
|
||||||
|
|
||||||
|
nuke.Code = GenerateRandomNumberString(nuke.CodeLength);
|
||||||
|
}
|
||||||
|
|
||||||
private void OnRemove(EntityUid uid, NukeComponent component, ComponentRemove args)
|
private void OnRemove(EntityUid uid, NukeComponent component, ComponentRemove args)
|
||||||
{
|
{
|
||||||
_itemSlots.RemoveItemSlot(uid, component.DiskSlot);
|
_itemSlots.RemoveItemSlot(uid, component.DiskSlot);
|
||||||
@@ -185,7 +205,7 @@ namespace Content.Server.Nuke
|
|||||||
if (component.Status != NukeStatus.AWAIT_CODE)
|
if (component.Status != NukeStatus.AWAIT_CODE)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (component.EnteredCode.Length >= _codes.Code.Length)
|
if (component.EnteredCode.Length >= component.CodeLength)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
component.EnteredCode += args.Value.ToString();
|
component.EnteredCode += args.Value.ToString();
|
||||||
@@ -309,8 +329,8 @@ namespace Content.Server.Nuke
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
var isValid = _codes.IsCodeValid(component.EnteredCode);
|
// var isValid = _codes.IsCodeValid(uid, component.EnteredCode);
|
||||||
if (isValid)
|
if (component.EnteredCode == component.Code)
|
||||||
{
|
{
|
||||||
component.Status = NukeStatus.AWAIT_ARM;
|
component.Status = NukeStatus.AWAIT_ARM;
|
||||||
component.RemainingTime = component.Timer;
|
component.RemainingTime = component.Timer;
|
||||||
@@ -358,7 +378,7 @@ namespace Content.Server.Nuke
|
|||||||
IsAnchored = anchored,
|
IsAnchored = anchored,
|
||||||
AllowArm = allowArm,
|
AllowArm = allowArm,
|
||||||
EnteredCodeLength = component.EnteredCode.Length,
|
EnteredCodeLength = component.EnteredCode.Length,
|
||||||
MaxCodeLength = _codes.Code.Length,
|
MaxCodeLength = component.CodeLength,
|
||||||
CooldownTime = (int) component.CooldownTime
|
CooldownTime = (int) component.CooldownTime
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -406,6 +426,18 @@ namespace Content.Server.Nuke
|
|||||||
Filter.Pvs(uid), uid, AudioHelpers.WithVariation(varyPitch).WithVolume(-5f));
|
Filter.Pvs(uid), uid, AudioHelpers.WithVariation(varyPitch).WithVolume(-5f));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public string GenerateRandomNumberString(int length)
|
||||||
|
{
|
||||||
|
var ret = "";
|
||||||
|
for (var i = 0; i < length; i++)
|
||||||
|
{
|
||||||
|
var c = (char) _random.Next('0', '9' + 1);
|
||||||
|
ret += c;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
#region Public API
|
#region Public API
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
@@ -26,4 +26,9 @@ nuke-user-interface-second-status-time = TIME: {$time}
|
|||||||
nuke-user-interface-second-status-current-code = CODE: {$code}
|
nuke-user-interface-second-status-current-code = CODE: {$code}
|
||||||
nuke-user-interface-second-status-cooldown-time = WAIT: {$time}
|
nuke-user-interface-second-status-cooldown-time = WAIT: {$time}
|
||||||
|
|
||||||
|
## Nuke labels
|
||||||
|
nuke-label-nanotrasen = NT-{$serial}
|
||||||
|
|
||||||
|
# do you even need this one? It's more funnier to say that
|
||||||
|
# the Syndicate stole a NT nuke
|
||||||
|
nuke-label-syndicate = SYN-{$serial}
|
||||||
|
|||||||
@@ -23,6 +23,7 @@
|
|||||||
- MachineMask
|
- MachineMask
|
||||||
layer:
|
layer:
|
||||||
- HalfWallLayer
|
- HalfWallLayer
|
||||||
|
- type: NukeLabel
|
||||||
- type: Nuke
|
- type: Nuke
|
||||||
explosionType: Default
|
explosionType: Default
|
||||||
maxIntensity: 100
|
maxIntensity: 100
|
||||||
@@ -69,6 +70,7 @@
|
|||||||
suffix: keg
|
suffix: keg
|
||||||
description: You probably shouldn't stick around to see if this is armed. It has a tap on the side.
|
description: You probably shouldn't stick around to see if this is armed. It has a tap on the side.
|
||||||
components:
|
components:
|
||||||
|
- type: NukeLabel
|
||||||
- type: Sprite
|
- type: Sprite
|
||||||
sprite: Objects/Devices/nuke.rsi
|
sprite: Objects/Devices/nuke.rsi
|
||||||
netsync: false
|
netsync: false
|
||||||
|
|||||||
Reference in New Issue
Block a user