Skip to content
Open
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion Content.Server/Chat/Systems/ChatSystem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -770,7 +770,7 @@ private string SanitizeInGameOOCMessage(string message)
public string TransformSpeech(EntityUid sender, string message)
{
var ev = new TransformSpeechEvent(sender, message);
RaiseLocalEvent(ev);
RaiseLocalEvent(sender, ev, true);

return ev.Message;
}
Expand Down Expand Up @@ -912,11 +912,13 @@ public sealed class TransformSpeechEvent : EntityEventArgs
{
public EntityUid Sender;
public string Message;
public bool Cancelled;

public TransformSpeechEvent(EntityUid sender, string message)
{
Sender = sender;
Message = message;
Cancelled = false;
}
}

Expand Down
37 changes: 37 additions & 0 deletions Content.Server/RuntimeFun/SpeakOnExceptionComponent.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
namespace Content.Server.RuntimeFun;

/// <summary>
/// Entities with this component will speak everytime an error occurs. They will say the exception
/// </summary>
[RegisterComponent]
public sealed partial class SpeakOnExceptionComponent : Component
{
/// <summary>
/// The last log that was spoken, used to ensure you don't repeat logs
/// </summary>
[DataField]
public string? LastLog;

/// <summary>
/// Minimum time between error speech events.
/// </summary>
[DataField]
public TimeSpan SpeechCooldown = TimeSpan.FromMinutes(1);

/// <summary>
/// The chance to speak without an accent.
/// </summary>
[DataField]
public float ChanceSpeakNoAccent = 0.005f;

/// <summary>
/// The next time the entity can say another error.
/// </summary>
[DataField]
public TimeSpan? NextTimeCanSpeak;

/// <summary>
/// If this component is currently trying to block accents from working.
/// </summary>
public bool BlockAccent;
}
96 changes: 96 additions & 0 deletions Content.Server/RuntimeFun/SpeakOnExceptionSystem.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
using System.Threading;
using Content.Server.Chat.Systems;
using Content.Server.Speech;
using Content.Shared.CCVar;
using Robust.Shared.Configuration;
using Robust.Shared.Random;
using Robust.Shared.Timing;
using Serilog.Events;

namespace Content.Server.RuntimeFun;

public sealed class SpeakOnExceptionSystem : EntitySystem
{
[Dependency] private readonly ILogManager _log = default!;
[Dependency] private readonly ChatSystem _chat = default!;
[Dependency] private readonly IGameTiming _timing = default!;
[Dependency] private readonly IConfigurationManager _config = default!;
[Dependency] private readonly IRobustRandom _random = default!;

// Special log handler that just saves the latest error.
private SpeakOnExceptionLogHandler _logHandler = default!;

private bool _censor;

public override void Initialize()
{
base.Initialize();

_logHandler = new SpeakOnExceptionLogHandler();
_log.RootSawmill.AddHandler(_logHandler);

SubscribeLocalEvent<SpeakOnExceptionComponent, MapInitEvent>(OnMapInit);
SubscribeLocalEvent<SpeakOnExceptionComponent, TransformSpeechEvent>(OnTransformSpeech, before: [ typeof(AccentSystem) ]);

Subs.CVar(_config, CCVars.CensorExceptionsInChat, x => _censor = x, true);
}

private void OnMapInit(Entity<SpeakOnExceptionComponent> ent, ref MapInitEvent args)
{
ent.Comp.NextTimeCanSpeak = _timing.CurTime;

// Make sure you don't speak when spawned if an error already occured
ent.Comp.LastLog = _logHandler.LastLog;
}

public override void Update(float frameTime)
{
var log = _logHandler.LastLog;
if (log == null)
return;

var query = EntityQueryEnumerator<SpeakOnExceptionComponent>();

while (query.MoveNext(out var uid, out var comp))
{
if (_timing.CurTime >= comp.NextTimeCanSpeak && log != comp.LastLog)
{
if (_random.Prob(comp.ChanceSpeakNoAccent))
comp.BlockAccent = true;

_chat.TrySendInGameICMessage(uid, TryCensorMessage(log), InGameICChatType.Speak, ChatTransmitRange.Normal);
comp.BlockAccent = false;

comp.NextTimeCanSpeak += comp.SpeechCooldown;
}

// If the log changes when your in cooldown, you still want to update the log so it won't trigger immediately
comp.LastLog = log;
}
}

private void OnTransformSpeech(Entity<SpeakOnExceptionComponent> ent, ref TransformSpeechEvent args)
{
args.Cancelled |= ent.Comp.BlockAccent;
}

private string TryCensorMessage(string message)
{
return _censor ? Loc.GetString("speak-on-exception-censor-text") : message;
}
}

// Log handler for SpeakOnException entities.
public sealed class SpeakOnExceptionLogHandler : ILogHandler
{
// Last error log that occured
public string? LastLog;

public void Log(string sawmillName, LogEvent message)
{
if (message.Exception == null)
return;

LastLog = message.Exception.Message;
}
}
3 changes: 3 additions & 0 deletions Content.Server/Speech/AccentSystem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@ public override void Initialize()

private void AccentHandler(TransformSpeechEvent args)
{
if (args.Cancelled)
return;

var accentEvent = new AccentGetEvent(args.Sender, args.Message);

RaiseLocalEvent(args.Sender, accentEvent, true);
Expand Down
6 changes: 6 additions & 0 deletions Content.Shared/CCVar/CCVars.Game.cs
Original file line number Diff line number Diff line change
Expand Up @@ -403,4 +403,10 @@ public static readonly CVarDef<bool>
/// </summary>
public static readonly CVarDef<bool> GameHostnameInTitlebar =
CVarDef.Create("game.hostname_in_titlebar", true, CVar.SERVER | CVar.REPLICATED);

/// <summary>
/// Should exceptions be censored when spoken to in game chat?
/// </summary>
public static readonly CVarDef<bool> CensorExceptionsInChat =
CVarDef.Create("game.censor_exceptions_in_chat", false, CVar.SERVER | CVar.REPLICATED);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
speak-on-exception-censor-text = 1984
4 changes: 4 additions & 0 deletions Resources/Prototypes/Entities/Mobs/NPCs/pets.yml
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,7 @@
attributes:
proper: true
gender: female
- type: SpeakOnException

- type: entity
name: Puppy Ian
Expand Down Expand Up @@ -186,6 +187,9 @@
- type: NpcFactionMember
factions:
- PetsNT
- type: SpeakOnException
speechCooldown: 50s
chanceSpeakNoAccent: 0.007
- type: Grammar
attributes:
proper: true
Expand Down
Loading