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 string Command => "nukecodes";
|
||||
public string Description => "Send nuke codes to the communication console";
|
||||
public string Help => "nukecodes";
|
||||
public string Description => "Send nuke codes to a station's communication consoles";
|
||||
public string Help => "nukecodes [station EntityUid]";
|
||||
|
||||
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.Station.Components;
|
||||
using Content.Server.Station.Systems;
|
||||
|
||||
namespace Content.Server.Nuke
|
||||
{
|
||||
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()
|
||||
{
|
||||
base.Initialize();
|
||||
SubscribeLocalEvent<NukeCodePaperComponent, MapInitEvent>(OnMapInit);
|
||||
SubscribeLocalEvent<NukeCodePaperComponent, MapInitEvent>(OnMapInit,
|
||||
after: new []{ typeof(NukeLabelSystem) });
|
||||
}
|
||||
|
||||
private void OnMapInit(EntityUid uid, NukeCodePaperComponent component, MapInitEvent args)
|
||||
{
|
||||
PaperComponent? paper = null;
|
||||
if (!Resolve(uid, ref paper))
|
||||
return;
|
||||
SetupPaper(uid);
|
||||
}
|
||||
|
||||
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.Nuke;
|
||||
using Robust.Shared.Audio;
|
||||
using Robust.Shared.Map;
|
||||
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype;
|
||||
|
||||
namespace Content.Server.Nuke
|
||||
@@ -121,6 +122,22 @@ namespace Content.Server.Nuke
|
||||
public bool Exploded;
|
||||
#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>
|
||||
/// Time until explosion in seconds.
|
||||
/// </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.Audio;
|
||||
using Content.Server.Chat;
|
||||
@@ -17,13 +18,13 @@ using Content.Shared.Popups;
|
||||
using Robust.Shared.Audio;
|
||||
using Robust.Shared.Containers;
|
||||
using Robust.Shared.Player;
|
||||
using Robust.Shared.Random;
|
||||
using Robust.Shared.Timing;
|
||||
|
||||
namespace Content.Server.Nuke
|
||||
{
|
||||
public sealed class NukeSystem : EntitySystem
|
||||
{
|
||||
[Dependency] private readonly NukeCodeSystem _codes = default!;
|
||||
[Dependency] private readonly ItemSlotsSystem _itemSlots = default!;
|
||||
[Dependency] private readonly PopupSystem _popups = default!;
|
||||
[Dependency] private readonly ExplosionSystem _explosions = default!;
|
||||
@@ -32,6 +33,7 @@ namespace Content.Server.Nuke
|
||||
[Dependency] private readonly ServerGlobalSoundSystem _soundSystem = default!;
|
||||
[Dependency] private readonly ChatSystem _chatSystem = default!;
|
||||
[Dependency] private readonly DoAfterSystem _doAfterSystem = default!;
|
||||
[Dependency] private readonly IRobustRandom _random = default!;
|
||||
|
||||
/// <summary>
|
||||
/// 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();
|
||||
SubscribeLocalEvent<NukeComponent, ComponentInit>(OnInit);
|
||||
SubscribeLocalEvent<NukeComponent, ComponentRemove>(OnRemove);
|
||||
SubscribeLocalEvent<NukeComponent, MapInitEvent>(OnMapInit);
|
||||
SubscribeLocalEvent<NukeComponent, EntInsertedIntoContainerMessage>(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)
|
||||
{
|
||||
_itemSlots.RemoveItemSlot(uid, component.DiskSlot);
|
||||
@@ -185,7 +205,7 @@ namespace Content.Server.Nuke
|
||||
if (component.Status != NukeStatus.AWAIT_CODE)
|
||||
return;
|
||||
|
||||
if (component.EnteredCode.Length >= _codes.Code.Length)
|
||||
if (component.EnteredCode.Length >= component.CodeLength)
|
||||
return;
|
||||
|
||||
component.EnteredCode += args.Value.ToString();
|
||||
@@ -309,8 +329,8 @@ namespace Content.Server.Nuke
|
||||
break;
|
||||
}
|
||||
|
||||
var isValid = _codes.IsCodeValid(component.EnteredCode);
|
||||
if (isValid)
|
||||
// var isValid = _codes.IsCodeValid(uid, component.EnteredCode);
|
||||
if (component.EnteredCode == component.Code)
|
||||
{
|
||||
component.Status = NukeStatus.AWAIT_ARM;
|
||||
component.RemainingTime = component.Timer;
|
||||
@@ -358,7 +378,7 @@ namespace Content.Server.Nuke
|
||||
IsAnchored = anchored,
|
||||
AllowArm = allowArm,
|
||||
EnteredCodeLength = component.EnteredCode.Length,
|
||||
MaxCodeLength = _codes.Code.Length,
|
||||
MaxCodeLength = component.CodeLength,
|
||||
CooldownTime = (int) component.CooldownTime
|
||||
};
|
||||
|
||||
@@ -406,6 +426,18 @@ namespace Content.Server.Nuke
|
||||
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
|
||||
|
||||
/// <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-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
|
||||
layer:
|
||||
- HalfWallLayer
|
||||
- type: NukeLabel
|
||||
- type: Nuke
|
||||
explosionType: Default
|
||||
maxIntensity: 100
|
||||
@@ -69,6 +70,7 @@
|
||||
suffix: keg
|
||||
description: You probably shouldn't stick around to see if this is armed. It has a tap on the side.
|
||||
components:
|
||||
- type: NukeLabel
|
||||
- type: Sprite
|
||||
sprite: Objects/Devices/nuke.rsi
|
||||
netsync: false
|
||||
|
||||
Reference in New Issue
Block a user