Delta-v/Content.Server/LegallyDistinctSpaceFerret/BrainrotSystem.cs

155 lines
5.0 KiB
C#

using System.Threading;
using Content.Server.Popups;
using Content.Server.Speech;
using Content.Shared.LegallyDistinctSpaceFerret;
using Content.Shared.Mind;
using Content.Shared.Physics;
using Robust.Shared.Physics.Collision.Shapes;
using Robust.Shared.Physics.Components;
using Robust.Shared.Physics.Events;
using Robust.Shared.Physics.Systems;
using Robust.Shared.Random;
using Timer = Robust.Shared.Timing.Timer;
namespace Content.Server.LegallyDistinctSpaceFerret;
/// <summary>
/// Raised locally when a mind gets too close to a Brainrot-causer.
/// </summary>
/// <param name="target">Who got brainrot</param>
/// <param name="cause">Who caused brainrot</param>
/// <param name="time">How long will they have it for</param>
public struct EntityGivenBrainrotEvent(EntityUid target, EntityUid cause, float time)
{
public EntityUid Cause = cause;
public EntityUid Target = target;
public float Time = time;
}
/// <summary>
/// Raised locally when a mind is freed from brainrot
/// </summary>
/// <param name="target">Who had brainrot</param>
public struct EntityLostBrainrotEvent(EntityUid target)
{
public EntityUid Target = target;
}
public sealed class BrainrotSystem : EntitySystem
{
[Dependency] private readonly PopupSystem _popup = default!;
[Dependency] private readonly IRobustRandom _random = default!;
[Dependency] private readonly FixtureSystem _fixtures = default!;
[Dependency] private readonly SharedMindSystem _mind = default!;
public const string BrainrotFixture = "brainrot";
public const string BrainRotApplied = "brainrot-applied";
public const string BrainRotLost = "brainrot-lost";
public readonly string[] BrainRotReplacementStrings =
[
"brainrot-replacement-1",
"brainrot-replacement-2",
"brainrot-replacement-3",
"brainrot-replacement-4",
"brainrot-replacement-5",
"brainrot-replacement-6"
];
public override void Initialize()
{
base.Initialize();
SubscribeLocalEvent<BrainrotAuraComponent, ComponentStartup>(OnStartup);
SubscribeLocalEvent<BrainrotAuraComponent, ComponentShutdown>(OnShutdown);
SubscribeLocalEvent<BrainrotAuraComponent, StartCollideEvent>(OnCollide);
SubscribeLocalEvent<EntityGivenBrainrotEvent>(EntityGivenBrainrot);
SubscribeLocalEvent<EntityLostBrainrotEvent>(EntityLostBrainrot);
SubscribeLocalEvent<BrainrotComponent, AccentGetEvent>(ApplyBrainRot);
}
private void OnStartup(EntityUid uid, BrainrotAuraComponent component, ComponentStartup args)
{
if (!TryComp<PhysicsComponent>(uid, out var body))
return;
var shape = new PhysShapeCircle(component.Range);
_fixtures.TryCreateFixture(uid, shape, BrainrotFixture, collisionLayer: (int) CollisionGroup.MobMask, hard: false, body: body);
}
private void OnShutdown(EntityUid uid, BrainrotAuraComponent component, ComponentShutdown args)
{
if (!TryComp<PhysicsComponent>(uid, out var body) ||
MetaData(uid).EntityLifeStage >= EntityLifeStage.Terminating)
{
return;
}
_fixtures.DestroyFixture(uid, BrainrotFixture, body: body);
}
private void OnCollide(EntityUid uid, BrainrotAuraComponent component, ref StartCollideEvent args)
{
// No effect if the mob is mindless
if (!_mind.TryGetMind(args.OtherEntity, out _, out _))
{
return;
}
// No effect if the mob has brainrot or causes brainrot
if (HasComp<BrainrotAuraComponent>(args.OtherEntity) || HasComp<BrainrotComponent>(args.OtherEntity))
{
return;
}
RaiseLocalEvent(new EntityGivenBrainrotEvent(args.OtherEntity, uid, component.Time));
}
private void EntityGivenBrainrot(EntityGivenBrainrotEvent args)
{
if (TryComp<BrainrotComponent>(args.Target, out var comp))
{
comp.Duration += args.Time;
}
else
{
comp = EnsureComp<BrainrotComponent>(args.Target);
}
var cancel = new CancellationTokenSource();
Timer.Spawn(TimeSpan.FromSeconds(comp.Duration), () =>
{
comp.Duration -= args.Time;
if (comp.Duration <= 0.0f)
{
RaiseLocalEvent(new EntityLostBrainrotEvent(args.Target));
}
}, cancel.Token);
comp.Cancels.Add(cancel);
_popup.PopupEntity(Loc.GetString(BrainRotApplied), args.Target, args.Target);
}
private void EntityLostBrainrot(EntityLostBrainrotEvent args)
{
if (TryComp<BrainrotComponent>(args.Target, out var comp))
{
foreach (var cancel in comp.Cancels)
{
cancel.Cancel();
}
}
RemComp<BrainrotComponent>(args.Target);
_popup.PopupEntity(Loc.GetString(BrainRotLost), args.Target, args.Target);
}
private void ApplyBrainRot(EntityUid entity, BrainrotComponent comp, AccentGetEvent args)
{
args.Message = Loc.GetString(_random.Pick(BrainRotReplacementStrings));
}
}