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