using System.Linq;
using Content.Server.Access.Systems;
using Content.Server.Administration.Logs;
using Content.Server.Kitchen.Components;
using Content.Server.NameIdentifier;
using Content.Shared.Database;
using Content.Shared.DeltaV.CartridgeLoader.Cartridges;
using Content.Shared.DeltaV.NanoChat;
using Content.Shared.NameIdentifier;
using Content.Shared.PDA;
using Robust.Shared.Containers;
using Robust.Shared.Prototypes;
using Robust.Shared.Random;
namespace Content.Server.DeltaV.NanoChat;
///
/// Handles NanoChat features that are specific to the server but not related to the cartridge itself.
///
public sealed class NanoChatSystem : SharedNanoChatSystem
{
[Dependency] private readonly IAdminLogManager _adminLogger = default!;
[Dependency] private readonly IRobustRandom _random = default!;
[Dependency] private readonly NameIdentifierSystem _name = default!;
private readonly ProtoId _nameIdentifierGroup = "NanoChat";
public override void Initialize()
{
base.Initialize();
SubscribeLocalEvent(OnInserted);
SubscribeLocalEvent(OnRemoved);
SubscribeLocalEvent(OnCardInit);
SubscribeLocalEvent(OnMicrowaved, after: [typeof(IdCardSystem)]);
}
private void OnInserted(Entity ent, ref EntGotInsertedIntoContainerMessage args)
{
if (args.Container.ID != PdaComponent.PdaIdSlotId)
return;
ent.Comp.PdaUid = args.Container.Owner;
Dirty(ent);
}
private void OnRemoved(Entity ent, ref EntGotRemovedFromContainerMessage args)
{
if (args.Container.ID != PdaComponent.PdaIdSlotId)
return;
ent.Comp.PdaUid = null;
Dirty(ent);
}
private void OnMicrowaved(Entity ent, ref BeingMicrowavedEvent args)
{
// Skip if the entity was deleted (e.g., by ID card system burning it)
if (Deleted(ent))
return;
if (!TryComp(args.Microwave, out var micro) || micro.Broken)
return;
var randomPick = _random.NextFloat();
// Super lucky - erase all messages (10% chance)
if (randomPick <= 0.10f)
{
ent.Comp.Messages.Clear();
// TODO: these shouldn't be shown at the same time as the popups from IdCardSystem
// _popup.PopupEntity(Loc.GetString("nanochat-card-microwave-erased", ("card", ent)),
// ent,
// PopupType.Medium);
_adminLogger.Add(LogType.Action,
LogImpact.Medium,
$"{ToPrettyString(args.Microwave)} erased all messages on {ToPrettyString(ent)}");
}
else
{
// Scramble random messages for random recipients
ScrambleMessages(ent);
// _popup.PopupEntity(Loc.GetString("nanochat-card-microwave-scrambled", ("card", ent)),
// ent,
// PopupType.Medium);
_adminLogger.Add(LogType.Action,
LogImpact.Medium,
$"{ToPrettyString(args.Microwave)} scrambled messages on {ToPrettyString(ent)}");
}
Dirty(ent);
}
private void ScrambleMessages(NanoChatCardComponent component)
{
foreach (var (recipientNumber, messages) in component.Messages)
{
for (var i = 0; i < messages.Count; i++)
{
// 50% chance to scramble each message
if (!_random.Prob(0.5f))
continue;
var message = messages[i];
message.Content = ScrambleText(message.Content);
messages[i] = message;
}
// 25% chance to reassign the conversation to a random recipient
if (_random.Prob(0.25f) && component.Recipients.Count > 0)
{
var newRecipient = _random.Pick(component.Recipients.Keys.ToList());
if (newRecipient == recipientNumber)
continue;
if (!component.Messages.ContainsKey(newRecipient))
component.Messages[newRecipient] = new List();
component.Messages[newRecipient].AddRange(messages);
component.Messages[recipientNumber].Clear();
}
}
}
private string ScrambleText(string text)
{
var chars = text.ToCharArray();
var n = chars.Length;
// Fisher-Yates shuffle of characters
while (n > 1)
{
n--;
var k = _random.Next(n + 1);
(chars[k], chars[n]) = (chars[n], chars[k]);
}
return new string(chars);
}
private void OnCardInit(Entity ent, ref MapInitEvent args)
{
if (ent.Comp.Number != null)
return;
// Assign a random number
_name.GenerateUniqueName(ent, _nameIdentifierGroup, out var number);
ent.Comp.Number = (uint)number;
Dirty(ent);
}
}