using Content.Server.Chat.Systems; using Content.Server.GameTicking; using Content.Server.Ninja.Systems; using Content.Shared.Communications; using Content.Shared.DoAfter; using Content.Shared.Interaction; using Content.Shared.Random; using Content.Shared.Random.Helpers; using Robust.Shared.Prototypes; using Robust.Shared.Random; using Robust.Shared.Serialization; namespace Content.Server.Communications; public sealed class CommsHackerSystem : SharedCommsHackerSystem { [Dependency] private readonly ChatSystem _chat = default!; [Dependency] private readonly GameTicker _gameTicker = default!; [Dependency] private readonly IPrototypeManager _proto = default!; [Dependency] private readonly IRobustRandom _random = default!; // TODO: remove when generic check event is used [Dependency] private readonly NinjaGlovesSystem _gloves = default!; [Dependency] private readonly SharedDoAfterSystem _doAfter = default!; public override void Initialize() { base.Initialize(); SubscribeLocalEvent(OnBeforeInteractHand); SubscribeLocalEvent(OnDoAfter); } /// /// Start the doafter to hack a comms console /// private void OnBeforeInteractHand(EntityUid uid, CommsHackerComponent comp, BeforeInteractHandEvent args) { if (args.Handled || !HasComp(args.Target)) return; // TODO: generic check event if (!_gloves.AbilityCheck(uid, args, out var target)) return; var doAfterArgs = new DoAfterArgs(EntityManager, uid, comp.Delay, new TerrorDoAfterEvent(), target: target, used: uid, eventTarget: uid) { BreakOnDamage = true, BreakOnMove = true, MovementThreshold = 0.5f, CancelDuplicate = false }; _doAfter.TryStartDoAfter(doAfterArgs); args.Handled = true; } /// /// Call in a random threat and do cleanup. /// private void OnDoAfter(EntityUid uid, CommsHackerComponent comp, TerrorDoAfterEvent args) { if (args.Cancelled || args.Handled || args.Target == null) return; var threats = _proto.Index(comp.Threats); var threat = threats.Pick(_random); CallInThreat(_proto.Index(threat)); // prevent calling in multiple threats RemComp(uid); var ev = new ThreatCalledInEvent(uid, args.Target.Value); RaiseLocalEvent(args.User, ref ev); } /// /// Makes announcement and adds game rule of the threat. /// public void CallInThreat(NinjaHackingThreatPrototype ninjaHackingThreat) { _gameTicker.StartGameRule(ninjaHackingThreat.Rule, out _); _chat.DispatchGlobalAnnouncement(Loc.GetString(ninjaHackingThreat.Announcement), playSound: true, colorOverride: Color.Red); } } /// /// Raised on the user when a threat is called in on the communications console. /// /// /// If you add , make sure to use this event to prevent adding it twice. /// For example, you could add a marker component after a threat is called in then check if the user doesn't have that marker before adding CommsHackerComponent. /// [ByRefEvent] public record struct ThreatCalledInEvent(EntityUid Used, EntityUid Target);