using Content.Server.Chat.Systems; using Content.Shared.Chat; using Content.Shared.Speech.EntitySystems; using Robust.Shared.Random; using Robust.Shared.Timing; using Serilog.Events; namespace Content.Server.RuntimeFun; /// /// System for the . Deals with getting the latest error log and making /// entities with that component speak. /// public sealed partial class SpeakOnExceptionSystem : EntitySystem { [Dependency] private IGameTiming _timing = default!; [Dependency] private ILogManager _log = default!; [Dependency] private IRobustRandom _random = default!; [Dependency] private ChatSystem _chat = default!; // Special log handler that just saves the latest error. private SpeakOnExceptionLogHandler _logHandler = default!; public override void Initialize() { base.Initialize(); _logHandler = new SpeakOnExceptionLogHandler(); _log.RootSawmill.AddHandler(_logHandler); SubscribeLocalEvent(OnTransformSpeech, before: [ typeof(AccentSystem) ]); } public override void Shutdown() { _log.RootSawmill.RemoveHandler(_logHandler); } public override void Update(float frameTime) { if (!_logHandler.ErrorHasOccured) return; _logHandler.ErrorHasOccured = false; var query = EntityQueryEnumerator(); while (query.MoveNext(out var uid, out var comp)) { if (_timing.CurTime < comp.NextTimeCanSpeak) continue; if (_random.Prob(comp.ChanceSpeakNoAccent)) comp.BlockAccent = true; _chat.TrySendInGameICMessage(uid, CensorMessage(comp), InGameICChatType.Speak, ChatTransmitRange.Normal, true); comp.BlockAccent = false; comp.NextTimeCanSpeak += comp.SpeechCooldown; } } [SubscribeLocalEvent] private void OnMapInit(Entity ent, ref MapInitEvent args) { ent.Comp.NextTimeCanSpeak = _timing.CurTime; } private void OnTransformSpeech(Entity ent, ref TransformSpeechEvent args) { if (ent.Comp.BlockAccent) args.Cancel(); } private string CensorMessage(SpeakOnExceptionComponent comp) { return Loc.GetString(_random.Pick(ProtoMan.Index(comp.Dataset).Values)); } // Log handler for SpeakOnException entities. private sealed class SpeakOnExceptionLogHandler : ILogHandler { // Gets set to true if an error ever occurs - reset this to false if you want to see if another error has occurred! public bool ErrorHasOccured; public void Log(string sawmillName, LogEvent message) { if (message.Exception == null) return; ErrorHasOccured = true; } } }