using System.Linq; using Content.Server.Store.Systems; using Content.Shared.PDA; using Content.Shared.PDA.Ringer; using Content.Shared.Store.Components; using Robust.Shared.Random; namespace Content.Server.PDA.Ringer; /// /// Handles the server-side logic for . /// public sealed class RingerSystem : SharedRingerSystem { [Dependency] private readonly IRobustRandom _random = default!; /// public override void Initialize() { base.Initialize(); SubscribeLocalEvent(OnMapInit); SubscribeLocalEvent(OnCurrencyInsert); SubscribeLocalEvent(OnGenerateUplinkCode); } /// /// Randomizes a ringtone for on . /// private void OnMapInit(Entity ent, ref MapInitEvent args) { UpdateRingerRingtone(ent, GenerateRingtone()); } /// /// Handles the for . /// private void OnCurrencyInsert(Entity ent, ref CurrencyInsertAttemptEvent args) { // TODO: Store isn't predicted, can't move it to shared if (!TryComp(ent, out var uplink)) { args.Cancel(); return; } // if the store can be locked, it must be unlocked first before inserting currency. Stops traitor checking. if (!uplink.Unlocked) args.Cancel(); } /// /// Handles the for generating an uplink code. /// private void OnGenerateUplinkCode(Entity ent, ref GenerateUplinkCodeEvent ev) { var code = GenerateRingtone(); // Set the code on the component ent.Comp.Code = code; // Return the code via the event ev.Code = code; } /// public override bool TryToggleUplink(EntityUid uid, Note[] ringtone, EntityUid? user = null) { if (!TryComp(uid, out var uplink)) return false; if (!HasComp(uid)) return false; // Wasn't generated yet if (uplink.Code is null) return false; // On the server, we always check if the code matches if (!uplink.Code.SequenceEqual(ringtone)) return false; return ToggleUplinkInternal((uid, uplink)); } /// /// Generates a random ringtone using the C pentatonic scale. /// /// An array of Notes representing the ringtone. /// The logic for this is on the Server so that we don't get a different result on the Client every time. private Note[] GenerateRingtone() { // Default to using C pentatonic so it at least sounds not terrible. return GenerateRingtone(new[] { Note.C, Note.D, Note.E, Note.G, Note.A }); } /// /// Generates a random ringtone using the specified notes. /// /// The notes to choose from when generating the ringtone. /// An array of Notes representing the ringtone. /// The logic for this is on the Server so that we don't get a different result on the Client every time. private Note[] GenerateRingtone(Note[] notes) { var ringtone = new Note[RingtoneLength]; for (var i = 0; i < RingtoneLength; i++) { ringtone[i] = _random.Pick(notes); } return ringtone; } } /// /// Event raised to generate a new uplink code for a PDA. /// [ByRefEvent] public record struct GenerateUplinkCodeEvent { /// /// The generated uplink code (filled in by the event handler). /// public Note[]? Code; }