Skip to content
Open
Show file tree
Hide file tree
Changes from all 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
1 change: 1 addition & 0 deletions Content.Server/Chat/Managers/ChatSanitizationManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@ private static readonly (Regex regex, string emoteKey)[] ShorthandToEmote =
Entry("[':", "chatsan-tearfully-smiles"),
Entry("('=", "chatsan-tearfully-smiles"),
Entry("['=", "chatsan-tearfully-smiles"),
Entry("?", "chatsan-confused"), //DeltaV
];

[Dependency] private readonly IConfigurationManager _configurationManager = default!;
Expand Down
90 changes: 82 additions & 8 deletions Content.Server/Chat/Systems/ChatSystem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
using Robust.Shared.Random;
using Robust.Shared.Replays;
using Robust.Shared.Utility;
using Content.Shared._DV.Chat; // DeltaV - chat enhancements

namespace Content.Server.Chat.Systems;

Expand Down Expand Up @@ -248,7 +249,7 @@ public void TrySendInGameICMessage(
// Was there an emote in the message? If so, send it.
if (player != null && emoteStr != message && emoteStr != null)
{
SendEntityEmote(source, emoteStr, range, nameOverride, ignoreActionBlocker);
SendEntityEmote(source, emoteStr, range, nameOverride, null, ignoreActionBlocker); // DeltaV - Had to change up for SendEntityEmote
}

// This can happen if the entire string is sanitized out.
Expand Down Expand Up @@ -311,9 +312,18 @@ public void TrySendInGameICMessage(
case InGameICChatType.Whisper:
SendEntityWhisper(source, message, range, null, nameOverride, language, hideLog, ignoreActionBlocker);
break;
case InGameICChatType.Emote:
SendEntityEmote(source, message, range, nameOverride, hideLog, ignoreActionBlocker: ignoreActionBlocker);
break;
case InGameICChatType.Emote: // DeltaV - Emote now has different types of emotes.
var type = ProcessEmoteMessage(source, message, out var modMessage);
if (type == EmoteType.Audible || type == EmoteType.AudiblePossessive)
{
if (checkRadioPrefix && TryProccessRadioMessage(source, modMessage, out var outputMessage, out var channel, capitalize: false))
SendAudibleEntityEmote(source, outputMessage, range, nameOverride, channel, type, hideLog: hideLog, ignoreActionBlocker: ignoreActionBlocker);
else
SendAudibleEntityEmote(source, modMessage, range, nameOverride, null, type, hideLog: hideLog, ignoreActionBlocker: ignoreActionBlocker);
}
else
SendEntityEmote(source, modMessage, range, nameOverride, type, hideLog, ignoreActionBlocker: ignoreActionBlocker);
break; // DeltaV - End
// Floofstation section
case InGameICChatType.Subtle:
SendEntitySubtle(source, message, range, nameOverride, hideLog: hideLog, ignoreActionBlocker);
Expand Down Expand Up @@ -819,6 +829,7 @@ protected override void SendEntityEmote(
string action,
ChatTransmitRange range,
string? nameOverride,
EmoteType? emoteType, // DeltaV
bool hideLog = false,
bool checkEmote = true,
bool ignoreActionBlocker = false,
Expand All @@ -832,23 +843,86 @@ protected override void SendEntityEmote(
var ent = Identity.Entity(source, EntityManager);
string name = FormattedMessage.EscapeText(nameOverride ?? Name(ent));

// Begin DeltaV
string wrappedMessage;

// Emotes use Identity.Name, since it doesn't actually involve your voice at all.
var wrappedMessage = Loc.GetString("chat-manager-entity-me-wrap-message",
("entityName", name),
("entity", ent),
("message", FormattedMessage.RemoveMarkupOrThrow(action)));
if (emoteType == EmoteType.Possessive) // DeltaV - Emote types now get checked.
wrappedMessage = Loc.GetString("chat-manager-entity-me-possessive-wrap-message",
("entityName", name),
("entity", ent),
("message", FormattedMessage.RemoveMarkupOrThrow(action)));
else
wrappedMessage = Loc.GetString("chat-manager-entity-me-wrap-message",
("entityName", name),
("entity", ent),
("message", FormattedMessage.RemoveMarkupOrThrow(action)));
// End DeltaV

if (checkEmote &&
!TryEmoteChatInput(source, action))
return;

SendInVoiceRange(ChatChannel.Emotes, name, action, wrappedMessage, obfuscated: "", obfuscatedWrappedMessage: "", source, range, author);
if (!hideLog)
if (name != Name(source))
_adminLogger.Add(LogType.Chat, LogImpact.Low, $"Emote from {source} as {name}: {action}");
else
_adminLogger.Add(LogType.Chat, LogImpact.Low, $"Emote from {source}: {action}");
}

// DeltaV - Added this to differentiate between emotes that can be heard over radio and those which can't.
protected override void SendAudibleEntityEmote(
EntityUid source,
string action,
ChatTransmitRange range,
string? nameOverride,
RadioChannelPrototype? channel,
EmoteType? emoteType,
bool hideLog = false,
bool checkEmote = true,
bool ignoreActionBlocker = false,
NetUserId? author = null
)
{
if (!_actionBlocker.CanSpeak(source) && !ignoreActionBlocker)
return;

EmoteType type = emoteType ?? EmoteType.Audible;

// get the entity's apparent name (if no override provided).
var ent = Identity.Entity(source, EntityManager);
string name = FormattedMessage.EscapeText(nameOverride ?? Name(ent));

string wrappedMessage;

// Audible emotes use Identity.Name, since that is the status quo. Emotes like scream doesn't currently reveal identities so this won't either. [This may be changed with feedback as you can audibly emote over radios]
if (emoteType == EmoteType.AudiblePossessive)
wrappedMessage = Loc.GetString("chat-manager-entity-me-audible-possessive-wrap-message",
("entityName", name),
("entity", ent),
("message", FormattedMessage.RemoveMarkupOrThrow(action)));
else
wrappedMessage = Loc.GetString("chat-manager-entity-me-audible-wrap-message",
("entityName", name),
("entity", ent),
("message", FormattedMessage.RemoveMarkupOrThrow(action)));

if (checkEmote &&
!TryEmoteChatInput(source, action))
return;

SendInVoiceRange(ChatChannel.Emotes, name, action, wrappedMessage, obfuscated: "", obfuscatedWrappedMessage: "", source, range, author);

var ev = new EntityAudiblyEmotedEvent(source, action, channel, type);
RaiseLocalEvent(source, ref ev, true);
if (!hideLog)
if (name != Name(source))
_adminLogger.Add(LogType.Chat, LogImpact.Low, $"Emote from {source} as {name}: {action}");
else
_adminLogger.Add(LogType.Chat, LogImpact.Low, $"Emote from {source}: {action}");
}
// DeltaV - End

// ReSharper disable once InconsistentNaming
private void SendLOOC(EntityUid source, ICommonSession player, string message, bool hideChat)
Expand Down
40 changes: 36 additions & 4 deletions Content.Server/Radio/EntitySystems/HeadsetSystem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
using Content.Shared.Radio.EntitySystems;
using Robust.Shared.Network;
using Robust.Shared.Player;
using Content.Shared._DV.Chat;

namespace Content.Server.Radio.EntitySystems;

Expand All @@ -27,6 +28,7 @@ public override void Initialize()
SubscribeLocalEvent<HeadsetComponent, EncryptionChannelsChangedEvent>(OnKeysChanged);

SubscribeLocalEvent<WearingHeadsetComponent, EntitySpokeEvent>(OnSpeak);
SubscribeLocalEvent<WearingHeadsetComponent, EntityAudiblyEmotedEvent>(OnAudibleEmote); // DeltaV

SubscribeLocalEvent<HeadsetComponent, EmpPulseEvent>(OnEmpPulse);
}
Expand All @@ -51,13 +53,43 @@ private void UpdateRadioChannels(EntityUid uid, HeadsetComponent headset, Encryp
EnsureComp<ActiveRadioComponent>(uid).Channels = new(keyHolder.Channels);
}

// DeltaV
// WARNING - Be very careful when modifying this method.
// The implementation right now has null forgiving operatiors in OnSpeak() and OnAudibleEmote() since this only returns true if channel is not null
private bool CheckRadioCapable(EntityUid uid, WearingHeadsetComponent headset, RadioChannelPrototype? channel)
{
if (channel != null
&& TryComp(headset.Headset, out EncryptionKeyHolderComponent? keys)
&& keys.Channels.Contains(channel.ID))
{
// if (!TryComp<HandsComponent>(uid, out var hands) || hands.Count < 1 ||
// TryComp<CuffableComponent>(uid, out var cuffable) && _cuffable.IsCuffed((uid, cuffable)))
// {
// _popup.PopupEntity(Loc.GetString("headset-cant-reach"), uid, uid, PopupType.SmallCaution);
// return false;
// }

return true;
}

return false;
}

private void OnAudibleEmote(EntityUid uid, WearingHeadsetComponent component, EntityAudiblyEmotedEvent args)
{
if (CheckRadioCapable(uid, component, args.Channel))
{
_radio.SendRadioMessage(uid, args.Message, args.Channel!, component.Headset, emType: args.Type);
args.Channel = null;
}
}
// DeltaV - End

private void OnSpeak(EntityUid uid, WearingHeadsetComponent component, EntitySpokeEvent args)
{
if (args.Channel != null
&& TryComp(component.Headset, out EncryptionKeyHolderComponent? keys)
&& keys.Channels.Contains(args.Channel.ID))
if (CheckRadioCapable(uid, component, args.Channel)) // DeltaV - Put all the radio checks into the CheckRadioCapable() method.
{
_radio.SendRadioMessage(uid, args.Message, args.Channel, component.Headset);
_radio.SendRadioMessage(uid, args.Message, args.Channel!, component.Headset); // DeltaV - Made the args.Channel null ignorant as CheckRadioCapable() guarantees it not null.
args.Channel = null; // prevent duplicate messages from other listeners.
}
}
Expand Down
8 changes: 8 additions & 0 deletions Content.Server/Radio/EntitySystems/RadioDeviceSystem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
using Content.Shared.Power;
using Content.Shared.Radio;
using Content.Shared.Chat;
using Content.Shared._DV.Chat; //Delta-V
using Content.Shared.UserInterface; // Nuclear-14
using Content.Shared._NC.Radio; // Nuclear-14
using Robust.Server.GameObjects; // Nuclear-14
Expand Down Expand Up @@ -207,6 +208,13 @@ private void OnReceiveRadio(EntityUid uid, RadioSpeakerComponent component, ref

// log to chat so people can identity the speaker/source, but avoid clogging ghost chat if there are many radios
var message = args.OriginalChatMsg.Message; // The chat system will handle the rest and re-obfuscate if needed.

// Triad - Prevent speaking emotes
if (args.emType == EmoteType.Audible || args.emType == EmoteType.AudiblePossessive)
{_chat.TrySendInGameICMessage(uid, message, InGameICChatType.Emote, ChatTransmitRange.GhostRangeLimitNoAdminCheck,
nameOverride: name, checkRadioPrefix: false, languageOverride: args.Language);
return;}

_chat.TrySendInGameICMessage(uid, message, component.OutputChatType, ChatTransmitRange.GhostRangeLimitNoAdminCheck,
nameOverride: name, checkRadioPrefix: false, languageOverride: args.Language); // Einstein Engines - Languages / Frontier: GhostRangeLimit<GhostRangeLimitNoAdminCheck, InGameICChatType.Whisper<component.OutputChatType
}
Expand Down
64 changes: 47 additions & 17 deletions Content.Server/Radio/EntitySystems/RadioSystem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
using Content.Server._EinsteinEngines.Language;
using Content.Server.Power.Components;
using Content.Shared._Mono.Radio;
using Content.Shared._DV.Chat;
using Content.Shared.Chat;
using Content.Shared.Database;
using Content.Shared._EinsteinEngines.Language;
Expand Down Expand Up @@ -45,6 +46,7 @@ public override void Initialize()
base.Initialize();
SubscribeLocalEvent<IntrinsicRadioReceiverComponent, RadioReceiveEvent>(OnIntrinsicReceive);
SubscribeLocalEvent<IntrinsicRadioTransmitterComponent, EntitySpokeEvent>(OnIntrinsicSpeak);
SubscribeLocalEvent<IntrinsicRadioTransmitterComponent, EntityAudiblyEmotedEvent>(OnIntrinsicAudibleEmote); // DeltaV - Robots should be allowed to emote over radio.

_exemptQuery = GetEntityQuery<TelecomExemptComponent>();
}
Expand Down Expand Up @@ -90,6 +92,16 @@ private void OnIntrinsicReceive(EntityUid uid, IntrinsicRadioReceiverComponent c
}
}

// DeltaV
private void OnIntrinsicAudibleEmote(EntityUid uid, IntrinsicRadioTransmitterComponent component, EntityAudiblyEmotedEvent args)
{
if (args.Channel != null && component.Channels.Contains(args.Channel.ID))
{
SendRadioMessage(uid, args.Message, args.Channel, uid, emType: args.Type);
}
}
// DeltaV - End

/// <summary>
/// Send radio message to all active radio listeners
/// </summary>
Expand All @@ -100,9 +112,10 @@ public void SendRadioMessage(
EntityUid radioSource,
int? frequency = null,
LanguagePrototype? language = null,
bool escapeMarkup = true) // Frontier: added frequency
bool escapeMarkup = true,
EmoteType? emType = null) // Frontier: added frequency // DeltaV - EmoteType? added.
{
SendRadioMessage(messageSource, message, _prototype.Index(channel), radioSource, frequency: frequency, escapeMarkup: escapeMarkup, language: language); // Frontier: added frequency / Einstein Engines - Language
SendRadioMessage(messageSource, message, _prototype.Index(channel), radioSource, frequency: frequency, escapeMarkup: escapeMarkup, language: language, emType: emType); // Frontier: added frequency / Einstein Engines - Language
}

/// <summary>
Expand All @@ -117,7 +130,8 @@ public void SendRadioMessage(
EntityUid radioSource,
int? frequency = null,
LanguagePrototype? language = null,
bool escapeMarkup = true) // Nuclear-14: add frequency
bool escapeMarkup = true,
EmoteType? emType = null) // DeltaV - EmoteType? added. // Nuclear-14: add frequency
{
// Einstein Engines - Language begin
if (language == null)
Expand Down Expand Up @@ -170,7 +184,7 @@ public void SendRadioMessage(
// ("channel", channelText), // Frontier: $"\\[{channel.LocalizedName}\\]"<channelText
// ("name", name),
// ("message", content));
var wrappedMessage = WrapRadioMessage(messageSource, channel, name, content, language); // Einstein Engines - Language
var wrappedMessage = WrapRadioMessage(messageSource, channel, name, content, language, emType); // Einstein Engines - Language

// most radios are relayed to chat, so lets parse the chat message beforehand
// var chat = new ChatMessage(
Expand All @@ -186,9 +200,9 @@ public void SendRadioMessage(

// Einstein Engines - Language begin
var obfuscated = _language.ObfuscateSpeech(content, language);
var obfuscatedWrapped = WrapRadioMessage(messageSource, channel, name, obfuscated, language);
var obfuscatedWrapped = WrapRadioMessage(messageSource, channel, name, obfuscated, language, emType);
var notUdsMsg = new ChatMessage(ChatChannel.Radio, obfuscated, obfuscatedWrapped, NetEntity.Invalid, null);
var ev = new RadioReceiveEvent(messageSource, channel, msg, notUdsMsg, language, radioSource);
var ev = new RadioReceiveEvent(messageSource, channel, msg, notUdsMsg, language, radioSource, emType);
// Einstein Engines - Language end

var sendAttemptEv = new RadioSendAttemptEvent(channel, radioSource);
Expand Down Expand Up @@ -262,7 +276,8 @@ private string WrapRadioMessage(
RadioChannelPrototype channel,
string name,
string message,
LanguagePrototype language)
LanguagePrototype language,
EmoteType? emType)
{
// TODO: code duplication with ChatSystem.WrapMessage
var speech = _chat.GetSpeechVerb(source, message);
Expand All @@ -275,16 +290,31 @@ private string WrapRadioMessage(
? Loc.GetString("chat-manager-language-prefix", ("language", language.ChatName))
: "";

return Loc.GetString(speech.Bold ? "chat-radio-message-wrap-bold" : "chat-radio-message-wrap",
("color", channel.Color),
("languageColor", languageColor),
("fontType", language.SpeechOverride.FontId ?? speech.FontId),
("fontSize", language.SpeechOverride.FontSize ?? speech.FontSize),
("verb", Loc.GetString(_random.Pick(speech.SpeechVerbStrings))),
("channel", $"\\[{channel.LocalizedName}\\]"),
("name", name),
("message", message),
("language", languageDisplay));
// Triad - Integrated from SendRadioMessage
if (emType == EmoteType.Audible)
return Loc.GetString("chat-radio-message-audible-emote-wrap",
("color", channel.Color),
("channel", $"\\[{channel.LocalizedName}\\]"),
("name", name),
("message", message));
else if (emType == EmoteType.AudiblePossessive)
return Loc.GetString("chat-radio-message-audible-possessive-emote-wrap",
("color", channel.Color),
("channel", $"\\[{channel.LocalizedName}\\]"),
("name", name),
("message", message));
else
return Loc.GetString(speech.Bold ? "chat-radio-message-wrap-bold" : "chat-radio-message-wrap",
("color", channel.Color),
("languageColor", languageColor),
("fontType", language.SpeechOverride.FontId ?? speech.FontId),
("fontSize", language.SpeechOverride.FontSize ?? speech.FontSize),
("verb", Loc.GetString(_random.Pick(speech.SpeechVerbStrings))),
("channel", $"\\[{channel.LocalizedName}\\]"),
("name", name),
("message", message),
("language", languageDisplay));
// Triad - End
}
// Einstein Engines - Language end

Expand Down
4 changes: 3 additions & 1 deletion Content.Server/Radio/RadioEvent.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using Content.Shared.Chat;
using Content.Shared._DV.Chat; //Triad
using Content.Shared._EinsteinEngines.Language;
using Content.Shared.Radio;

Expand All @@ -16,7 +17,8 @@ public readonly record struct RadioReceiveEvent(
ChatMessage OriginalChatMsg,
ChatMessage LanguageObfuscatedChatMsg,
LanguagePrototype Language,
EntityUid RadioSource
EntityUid RadioSource,
EmoteType? emType //Triad
);
// Einstein Engines - Language end

Expand Down
Loading
Loading