using Content.Shared.Access;
using Content.Shared.Access.Components;
using Content.Shared.Access.Systems;
+using Content.Shared.Chat;
using Content.Shared.Database;
using Content.Shared.Popups;
using Robust.Shared.Prototypes;
using Content.Shared.Body.Components;
using Content.Shared.Body.Events;
using Content.Shared.Body.Prototypes;
+using Content.Shared.Chat;
using Content.Shared.Chemistry.Components;
using Content.Shared.Chemistry.EntitySystems;
using Content.Shared.Chemistry.Reagent;
using Content.Server.Chat.Systems;
using Content.Shared.Administration;
+using Content.Shared.Chat;
using Robust.Shared.Console;
using Robust.Shared.Enums;
using Content.Server.Chat.Systems;
using Content.Shared.Administration;
+using Content.Shared.Chat;
using Robust.Shared.Console;
using Robust.Shared.Enums;
using Content.Server.Chat.Systems;
using Content.Shared.Administration;
+using Content.Shared.Chat;
using Robust.Shared.Console;
using Robust.Shared.Enums;
using System.Linq;
+using Content.Shared.Chat;
using Content.Shared.Chat.Prototypes;
using Robust.Shared.Prototypes;
using Robust.Shared.Random;
public override void Initialize()
{
base.Initialize();
- CacheEmotes();
+
Subs.CVar(_configurationManager, CCVars.LoocEnabled, OnLoocEnabledChanged, true);
Subs.CVar(_configurationManager, CCVars.DeadLoocEnabled, OnDeadLoocEnabledChanged, true);
Subs.CVar(_configurationManager, CCVars.CritLoocEnabled, OnCritLoocEnabledChanged, true);
}
}
- private void SendEntityEmote(
+ protected override void SendEntityEmote(
EntityUid source,
string action,
ChatTransmitRange range,
Looc,
Dead
}
-
-/// <summary>
-/// Controls transmission of chat.
-/// </summary>
-public enum ChatTransmitRange : byte
-{
- /// Acts normal, ghosts can hear across the map, etc.
- Normal,
- /// Normal but ghosts are still range-limited.
- GhostRangeLimit,
- /// Hidden from the chat window.
- HideChat,
- /// Ghosts can't hear or see it at all. Regular players can if in-range.
- NoGhosts
-}
namespace Content.Server.Chat.Systems;
+using Content.Shared.Chat;
using Content.Shared.Chat.Prototypes;
using Content.Shared.Damage;
using Robust.Shared.Prototypes;
-using Content.Server.Popups;
-using Content.Shared.Popups;
-using Content.Shared.Mobs;
using Content.Server.Chat;
using Content.Server.Chat.Systems;
-using Content.Server.Clothing.Systems;
-using Content.Shared.Chat.Prototypes;
-using Robust.Shared.Random;
-using Content.Shared.Stunnable;
-using Content.Shared.Damage;
-using Robust.Shared.Prototypes;
using Content.Server.Emoting.Systems;
+using Content.Server.Clothing.Systems;
+using Content.Server.Popups;
using Content.Server.Speech.EntitySystems;
+using Content.Shared.Chat;
+using Content.Shared.Chat.Prototypes;
+using Content.Shared.Clumsy;
using Content.Shared.Cluwne;
-using Robust.Shared.Audio.Systems;
+using Content.Shared.Damage;
+using Content.Shared.Mobs;
using Content.Shared.NameModifier.EntitySystems;
-using Content.Shared.Clumsy;
+using Content.Shared.Popups;
+using Content.Shared.Stunnable;
+using Robust.Shared.Audio.Systems;
+using Robust.Shared.Random;
+using Robust.Shared.Prototypes;
namespace Content.Server.Cluwne;
EnsureComp<AutoEmoteComponent>(ent.Owner);
_autoEmote.AddEmote(ent.Owner, ent.Comp.AutoEmoteId);
}
-
+
EnsureComp<ClumsyComponent>(ent.Owner);
var transformMessage = Loc.GetString(ent.Comp.TransformMessage, ("target", ent.Owner));
using Content.Server.Chat.Systems;
using Content.Server.Emoting.Components;
+using Content.Shared.Chat;
using Content.Shared.Chat.Prototypes;
using Content.Shared.Hands.Components;
using Robust.Shared.Prototypes;
+++ /dev/null
-using Content.Server.Chat.Systems;
-using Content.Shared.EntityEffects;
-using Content.Shared.EntityEffects.Effects;
-
-namespace Content.Server.EntityEffects.Effects;
-
-/// <summary>
-/// Makes this entity emote.
-/// </summary>
-/// <inheritdoc cref="EntityEffectSystem{T,TEffect}"/>
-public sealed partial class EmoteEntityEffectSystem : EntityEffectSystem<MetaDataComponent, Emote>
-{
- [Dependency] private readonly ChatSystem _chat = default!;
-
- protected override void Effect(Entity<MetaDataComponent> entity, ref EntityEffectEvent<Emote> args)
- {
- if (args.Effect.ShowInChat)
- _chat.TryEmoteWithChat(entity, args.Effect.EmoteId, ChatTransmitRange.GhostRangeLimit, forceEmote: args.Effect.Force);
- else
- _chat.TryEmoteWithoutChat(entity, args.Effect.EmoteId);
- }
-}
using Content.Server.Telephone;
using Content.Shared.Access.Systems;
using Content.Shared.Audio;
+using Content.Shared.Chat;
using Content.Shared.Chat.TypingIndicator;
using Content.Shared.Holopad;
using Content.Shared.IdentityManagement;
using Content.Server.Administration;
using Content.Server.Chat.Systems;
using Content.Server.Popups;
-using Content.Server.Speech.Muting;
+using Content.Shared.Chat;
using Content.Shared.Mobs;
using Content.Shared.Mobs.Components;
using Content.Shared.Mobs.Systems;
-using Content.Server.Chat.Systems;
-using Content.Shared.Chat;
+using Content.Shared.Chat;
+using Content.Server.Chat.Systems;
using Robust.Shared.Prototypes;
namespace Content.Server.Speech;
using Content.Server.Chat.Systems;
using Content.Server.Speech.Components;
+using Content.Shared.Chat;
using Content.Shared.Chat.Prototypes;
using Content.Shared.Speech;
using Content.Shared.Speech.Components;
using Content.Server.Actions;
using Content.Server.Chat.Systems;
-using Content.Server.Speech.Components;
+using Content.Shared.Chat;
using Content.Shared.Chat.Prototypes;
-using Content.Shared.Cloning.Events;
using Content.Shared.Humanoid;
using Content.Shared.Speech;
using Content.Shared.Speech.Components;
-using Robust.Shared.Audio;
using Robust.Shared.Audio.Systems;
using Robust.Shared.Prototypes;
using Robust.Shared.Random;
-using Content.Shared.Abilities.Mime;
-using Content.Server.Chat.Systems;
using Content.Server.Popups;
-using Content.Server.Speech.Components;
using Content.Server.Speech.EntitySystems;
+using Content.Shared.Abilities.Mime;
+using Content.Shared.Chat;
using Content.Shared.Chat.Prototypes;
using Content.Shared.Puppet;
using Content.Shared.Speech;
using Content.Server.Chat.Systems;
+using Content.Shared.Chat;
using Content.Shared.Teleportation;
using Content.Shared.Teleportation.Components;
using Content.Shared.Teleportation.Systems;
using Content.Server.Power.Components;
using Content.Server.Vocalization.Components;
using Content.Shared.ActionBlocker;
+using Content.Shared.Chat;
using Robust.Shared.Random;
using Robust.Shared.Timing;
using Content.Shared.Armor;
using Content.Shared.Bed.Sleep;
using Content.Shared.Cloning.Events;
+using Content.Shared.Chat;
using Content.Shared.Damage;
using Content.Shared.Humanoid;
using Content.Shared.Inventory;
-using Content.Shared.Chat.Prototypes;
+using Content.Shared.Chat.Prototypes;
+using Content.Shared.Inventory;
using Robust.Shared.Prototypes;
using Robust.Shared.Serialization;
namespace Content.Shared.Chat;
+/// <summary>
+/// An event raised just before an emote is performed, providing systems with an opportunity to cancel the emote's performance.
+/// </summary>
+[ByRefEvent]
+public sealed class BeforeEmoteEvent(EntityUid source, EmotePrototype emote)
+ : CancellableEntityEventArgs, IInventoryRelayEvent
+{
+ public readonly EntityUid Source = source;
+ public readonly EmotePrototype Emote = emote;
+
+ /// <summary>
+ /// The equipment that is blocking emoting. Should only be non-null if the event was canceled.
+ /// </summary>
+ public EntityUid? Blocker = null;
+
+ public SlotFlags TargetSlots => SlotFlags.WITHOUT_POCKET;
+}
+
+/// <summary>
+/// Raised by the chat system when an entity made some emote.
+/// Use it to play sound, change sprite or something else.
+/// </summary>
+[ByRefEvent]
+public record struct EmoteEvent(EmotePrototype Emote)
+{
+ /// <summary>
+ /// The used emote.
+ /// </summary>
+ public EmotePrototype Emote = Emote;
+
+ /// <summary>
+ /// If this message has already been "handled" by a previous system.
+ /// </summary>
+ public bool Handled;
+}
+
+/// <summary>
+/// Sent by the client when requesting the server to play a specific emote selected from the emote radial menu.
+/// </summary>
[Serializable, NetSerializable]
public sealed class PlayEmoteMessage(ProtoId<EmotePrototype> protoId) : EntityEventArgs
{
using System.Collections.Frozen;
-using Content.Server.Popups;
using Content.Shared.Chat.Prototypes;
-using Content.Shared.Emoting;
using Content.Shared.Speech;
using Robust.Shared.Audio;
-using Robust.Shared.Prototypes;
using Robust.Shared.Random;
-namespace Content.Server.Chat.Systems;
+namespace Content.Shared.Chat;
-// emotes using emote prototype
-public partial class ChatSystem
+public abstract partial class SharedChatSystem
{
- [Dependency] private readonly PopupSystem _popupSystem = default!;
-
private FrozenDictionary<string, EmotePrototype> _wordEmoteDict = FrozenDictionary<string, EmotePrototype>.Empty;
- protected override void OnPrototypeReload(PrototypesReloadedEventArgs obj)
- {
- base.OnPrototypeReload(obj);
- if (obj.WasModified<EmotePrototype>())
- CacheEmotes();
- }
-
private void CacheEmotes()
{
var dict = new Dictionary<string, EmotePrototype>();
}
/// <summary>
- /// Makes selected entity to emote using <see cref="EmotePrototype"/> and sends message to chat.
+ /// Makes the selected entity emote using the given <see cref="EmotePrototype"/> and sends a message to chat.
/// </summary>
/// <param name="source">The entity that is speaking</param>
- /// <param name="emoteId">The id of emote prototype. Should has valid <see cref="EmotePrototype.ChatMessages"/></param>
- /// <param name="hideLog">Whether or not this message should appear in the adminlog window</param>
+ /// <param name="emoteId">The id of emote prototype. Should have valid <see cref="EmotePrototype.ChatMessages"/></param>
+ /// <param name="hideLog">Whether this message should appear in the adminlog window, or not.</param>
/// <param name="range">Conceptual range of transmission, if it shows in the chat window, if it shows to far-away ghosts or ghosts at all...</param>
- /// <param name="nameOverride">The name to use for the speaking entity. Usually this should just be modified via <see cref="TransformSpeakerNameEvent"/>. If this is set, the event will not get raised.</param>
+ /// <param name="ignoreActionBlocker">Whether emote action blocking should be ignored or not.</param>
+ /// <param name="nameOverride">
+ /// The name to use for the speaking entity. Usually this should just be modified via <see cref="TransformSpeakerNameEvent"/>.
+ /// If this is set, the event will not get raised.
+ /// </param>
/// <param name="forceEmote">Bypasses whitelist/blacklist/availibility checks for if the entity can use this emote</param>
- /// <returns>True if an emote was performed. False if the emote is unvailable, cancelled, etc.</returns>
+ /// <returns>True if an emote was performed. False if the emote is unavailable, cancelled, etc.</returns>
public bool TryEmoteWithChat(
EntityUid source,
string emoteId,
string? nameOverride = null,
bool ignoreActionBlocker = false,
bool forceEmote = false
- )
+ )
{
- if (!_prototypeManager.TryIndex<EmotePrototype>(emoteId, out var proto))
+ if (!_prototypeManager.Resolve<EmotePrototype>(emoteId, out var proto))
return false;
+
return TryEmoteWithChat(source, proto, range, hideLog: hideLog, nameOverride, ignoreActionBlocker: ignoreActionBlocker, forceEmote: forceEmote);
}
/// <summary>
- /// Makes selected entity to emote using <see cref="EmotePrototype"/> and sends message to chat.
+ /// Makes the selected entity emote using the given <see cref="EmotePrototype"/> and sends a message to chat.
/// </summary>
- /// <param name="source">The entity that is speaking</param>
- /// <param name="emote">The emote prototype. Should has valid <see cref="EmotePrototype.ChatMessages"/></param>
- /// <param name="hideLog">Whether or not this message should appear in the adminlog window</param>
- /// <param name="hideChat">Whether or not this message should appear in the chat window</param>
+ /// <param name="source">The entity that is speaking.</param>
+ /// <param name="emote">The emote prototype. Should have valid <see cref="EmotePrototype.ChatMessages"/>.</param>
+ /// <param name="hideLog">Whether this message should appear in the adminlog window or not.</param>
+ /// <param name="ignoreActionBlocker">Whether emote action blocking should be ignored or not.</param>
/// <param name="range">Conceptual range of transmission, if it shows in the chat window, if it shows to far-away ghosts or ghosts at all...</param>
- /// <param name="nameOverride">The name to use for the speaking entity. Usually this should just be modified via <see cref="TransformSpeakerNameEvent"/>. If this is set, the event will not get raised.</param>
+ /// <param name="nameOverride">
+ /// The name to use for the speaking entity. Usually this should just be modified via <see cref="TransformSpeakerNameEvent"/>.
+ /// If this is set, the event will not get raised.
+ /// </param>
/// <param name="forceEmote">Bypasses whitelist/blacklist/availibility checks for if the entity can use this emote</param>
- /// <returns>True if an emote was performed. False if the emote is unvailable, cancelled, etc.</returns>
+ /// <returns>True if an emote was performed. False if the emote is unavailable, cancelled, etc.</returns>
public bool TryEmoteWithChat(
EntityUid source,
EmotePrototype emote,
}
/// <summary>
- /// Makes selected entity to emote using <see cref="EmotePrototype"/> without sending any messages to chat.
+ /// Makes the selected entity emote using the given <see cref="EmotePrototype"/> without sending any messages to chat.
/// </summary>
- /// <returns>True if an emote was performed. False if the emote is unvailable, cancelled, etc.</returns>
+ /// <returns>True if an emote was performed. False if the emote is unavailable, cancelled, etc.</returns>
public bool TryEmoteWithoutChat(EntityUid uid, string emoteId, bool ignoreActionBlocker = false)
{
- if (!_prototypeManager.TryIndex<EmotePrototype>(emoteId, out var proto))
+ if (!_prototypeManager.Resolve<EmotePrototype>(emoteId, out var proto))
return false;
return TryEmoteWithoutChat(uid, proto, ignoreActionBlocker);
}
/// <summary>
- /// Makes selected entity to emote using <see cref="EmotePrototype"/> without sending any messages to chat.
+ /// Makes the selected entity emote using the given <see cref="EmotePrototype"/> without sending any messages to chat.
/// </summary>
- /// <returns>True if an emote was performed. False if the emote is unvailable, cancelled, etc.</returns>
+ /// <returns>True if an emote was performed. False if the emote is unavailable, cancelled, etc.</returns>
public bool TryEmoteWithoutChat(EntityUid uid, EmotePrototype proto, bool ignoreActionBlocker = false)
{
if (!_actionBlocker.CanEmote(uid) && !ignoreActionBlocker)
}
/// <summary>
- /// Tries to find and play relevant emote sound in emote sounds collection.
+ /// Tries to find and play the relevant emote sound in an emote sounds collection.
/// </summary>
/// <returns>True if emote sound was played.</returns>
public bool TryPlayEmoteSound(EntityUid uid, EmoteSoundsPrototype? proto, EmotePrototype emote, AudioParams? audioParams = null)
}
/// <summary>
- /// Tries to find and play relevant emote sound in emote sounds collection.
+ /// Tries to find and play the relevant emote sound in an emote sounds collection.
/// </summary>
/// <returns>True if emote sound was played.</returns>
public bool TryPlayEmoteSound(EntityUid uid, EmoteSoundsPrototype? proto, string emoteId, AudioParams? audioParams = null)
/// <summary>
/// Checks if a valid emote was typed, to play sounds and etc and invokes an event.
/// </summary>
- /// <param name="uid"></param>
- /// <param name="textInput"></param>
+ /// <param name="source">The entity that is speaking</param>
+ /// <param name="textInput">Formatted emote message.</param>
/// <returns>True if the chat message should be displayed (because the emote was explicitly cancelled), false if it should not be.</returns>
- private bool TryEmoteChatInput(EntityUid uid, string textInput)
+ protected bool TryEmoteChatInput(EntityUid source, string textInput)
{
var actionTrimmedLower = TrimPunctuation(textInput.ToLower());
if (!_wordEmoteDict.TryGetValue(actionTrimmedLower, out var emote))
return true;
- if (!AllowedToUseEmote(uid, emote))
+ if (!AllowedToUseEmote(source, emote))
return true;
- return TryInvokeEmoteEvent(uid, emote);
+ return TryInvokeEmoteEvent(source, emote);
- static string TrimPunctuation(string textInput)
- {
- var trimEnd = textInput.Length;
- while (trimEnd > 0 && char.IsPunctuation(textInput[trimEnd - 1]))
- {
- trimEnd--;
- }
-
- var trimStart = 0;
- while (trimStart < trimEnd && char.IsPunctuation(textInput[trimStart]))
- {
- trimStart++;
- }
-
- return textInput[trimStart..trimEnd];
- }
}
/// <summary>
- /// Checks if we can use this emote based on the emotes whitelist, blacklist, and availibility to the entity.
+ /// Checks if we can use this emote based on the emotes whitelist, blacklist, and availability to the entity.
/// </summary>
/// <param name="source">The entity that is speaking</param>
/// <param name="emote">The emote being used</param>
- /// <returns></returns>
- private bool AllowedToUseEmote(EntityUid source, EmotePrototype emote)
+ public bool AllowedToUseEmote(EntityUid source, EmotePrototype emote)
{
// If emote is in AllowedEmotes, it will bypass whitelist and blacklist
if (TryComp<SpeechComponent>(source, out var speech) &&
}
// Check the whitelist and blacklist
- if (_whitelistSystem.IsWhitelistFail(emote.Whitelist, source) ||
- _whitelistSystem.IsBlacklistPass(emote.Blacklist, source))
+ if (_whitelist.IsWhitelistFail(emote.Whitelist, source) ||
+ _whitelist.IsBlacklistPass(emote.Blacklist, source))
{
return false;
}
if (beforeEv.Cancelled)
{
+ // Chat is not predicted anyways, so no need to predict this popup either.
+ if (_net.IsClient)
+ return false;
+
if (beforeEv.Blocker != null)
{
- _popupSystem.PopupEntity(
+ _popup.PopupEntity(
Loc.GetString(
"chat-system-emote-cancelled-blocked",
("emote", Loc.GetString(proto.Name).ToLower()),
}
else
{
- _popupSystem.PopupEntity(
+ _popup.PopupEntity(
Loc.GetString("chat-system-emote-cancelled-generic",
("emote", Loc.GetString(proto.Name).ToLower())),
uid,
return true;
}
-}
-
-/// <summary>
-/// Raised by chat system when entity made some emote.
-/// Use it to play sound, change sprite or something else.
-/// </summary>
-[ByRefEvent]
-public sealed class EmoteEvent : HandledEntityEventArgs
-{
- public readonly EmotePrototype Emote;
- public EmoteEvent(EmotePrototype emote)
+ private string TrimPunctuation(string textInput)
{
- Emote = emote;
- Handled = false;
+ var trimEnd = textInput.Length;
+ while (trimEnd > 0 && char.IsPunctuation(textInput[trimEnd - 1]))
+ {
+ trimEnd--;
+ }
+
+ var trimStart = 0;
+ while (trimStart < trimEnd && char.IsPunctuation(textInput[trimStart]))
+ {
+ trimStart++;
+ }
+
+ return textInput[trimStart..trimEnd];
}
}
using System.Collections.Frozen;
using System.Text.RegularExpressions;
+using Content.Shared.ActionBlocker;
+using Content.Shared.Chat.Prototypes;
using Content.Shared.Popups;
using Content.Shared.Radio;
using Content.Shared.Speech;
+using Content.Shared.Whitelist;
using Robust.Shared.Audio;
+using Robust.Shared.Audio.Systems;
+using Robust.Shared.Network;
using Robust.Shared.Prototypes;
+using Robust.Shared.Random;
using Robust.Shared.Utility;
namespace Content.Shared.Chat;
-public abstract class SharedChatSystem : EntitySystem
+public abstract partial class SharedChatSystem : EntitySystem
{
public const char RadioCommonPrefix = ';';
public const char RadioChannelPrefix = ':';
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
[Dependency] private readonly SharedPopupSystem _popup = default!;
+ [Dependency] private readonly EntityWhitelistSystem _whitelist = default!;
+ [Dependency] private readonly ActionBlockerSystem _actionBlocker = default!;
+ [Dependency] private readonly SharedAudioSystem _audio = default!;
+ [Dependency] private readonly IRobustRandom _random = default!;
+ [Dependency] private readonly INetManager _net = default!;
/// <summary>
/// Cache of the keycodes for faster lookup.
public override void Initialize()
{
base.Initialize();
+
DebugTools.Assert(_prototypeManager.HasIndex(CommonChannel));
+
SubscribeLocalEvent<PrototypesReloadedEventArgs>(OnPrototypeReload);
CacheRadios();
+ CacheEmotes();
}
protected virtual void OnPrototypeReload(PrototypesReloadedEventArgs obj)
{
if (obj.WasModified<RadioChannelPrototype>())
CacheRadios();
+
+ if (obj.WasModified<EmotePrototype>())
+ CacheEmotes();
}
private void CacheRadios()
tagStart += tag.Length + 2;
return rawmsg.Substring(tagStart, tagEnd - tagStart);
}
+
+ protected virtual void SendEntityEmote(
+ EntityUid source,
+ string action,
+ ChatTransmitRange range,
+ string? nameOverride,
+ bool hideLog = false,
+ bool checkEmote = true,
+ bool ignoreActionBlocker = false,
+ NetUserId? author = null
+ )
+ { }
+}
+
+/// <summary>
+/// Controls transmission of chat.
+/// </summary>
+public enum ChatTransmitRange : byte
+{
+ /// Acts normal, ghosts can hear across the map, etc.
+ Normal,
+ /// Normal but ghosts are still range-limited.
+ GhostRangeLimit,
+ /// Hidden from the chat window.
+ HideChat,
+ /// Ghosts can't hear or see it at all. Regular players can if in-range.
+ NoGhosts
}
-using Content.Shared.Chat.Prototypes;
-using Content.Shared.Inventory;
-
-namespace Content.Shared.Emoting;
+namespace Content.Shared.Emoting;
public sealed class EmoteAttemptEvent(EntityUid uid) : CancellableEntityEventArgs
{
public EntityUid Uid { get; } = uid;
}
-
-/// <summary>
-/// An event raised just before an emote is performed, providing systems with an opportunity to cancel the emote's performance.
-/// </summary>
-[ByRefEvent]
-public sealed class BeforeEmoteEvent(EntityUid source, EmotePrototype emote)
- : CancellableEntityEventArgs, IInventoryRelayEvent
-{
- public readonly EntityUid Source = source;
- public readonly EmotePrototype Emote = emote;
-
- /// <summary>
- /// The equipment that is blocking emoting. Should only be non-null if the event was canceled.
- /// </summary>
- public EntityUid? Blocker = null;
-
- public SlotFlags TargetSlots => SlotFlags.WITHOUT_POCKET;
-}
-using Content.Shared.Chat.Prototypes;
+using Content.Shared.Chat;
+using Content.Shared.Chat.Prototypes;
using Robust.Shared.Prototypes;
namespace Content.Shared.EntityEffects.Effects;
+/// <summary>
+/// Makes this entity emote.
+/// </summary>
+/// <inheritdoc cref="EntityEffectSystem{T,TEffect}"/>
+public sealed partial class EmoteEntityEffectSystem : EntityEffectSystem<MetaDataComponent, Emote>
+{
+ [Dependency] private readonly SharedChatSystem _chat = default!;
+
+ protected override void Effect(Entity<MetaDataComponent> entity, ref EntityEffectEvent<Emote> args)
+ {
+ if (args.Effect.ShowInChat)
+ _chat.TryEmoteWithChat(entity, args.Effect.EmoteId, ChatTransmitRange.GhostRangeLimit, forceEmote: args.Effect.Force);
+ else
+ _chat.TryEmoteWithoutChat(entity, args.Effect.EmoteId);
+ }
+}
+
/// <inheritdoc cref="EntityEffect"/>
public sealed partial class Emote : EntityEffectBase<Emote>
{
using Content.Shared.Damage;
using Content.Shared.Damage.Events;
using Content.Shared.Electrocution;
-using Content.Shared.Emoting;
using Content.Shared.Explosion;
using Content.Shared.Eye.Blinding.Systems;
using Content.Shared.Flash;
using Content.Shared.Chat.Prototypes;
+using Robust.Shared.GameStates;
using Robust.Shared.Prototypes;
-namespace Content.Server.Speech.Components;
+namespace Content.Shared.Speech.Components;
/// <summary>
/// Suppresses emotes with the given categories or ID.
/// Additionally, if the Scream Emote would be blocked, also blocks the Scream Action.
/// </summary>
-[RegisterComponent]
+[RegisterComponent, NetworkedComponent, AutoGenerateComponentState]
public sealed partial class EmoteBlockerComponent : Component
{
/// <summary>
/// Which categories of emotes are blocked by this component.
/// </summary>
- [DataField]
+ [DataField, AutoNetworkedField]
public HashSet<EmoteCategory> BlocksCategories = [];
/// <summary>
/// IDs of which specific emotes are blocked by this component.
/// </summary>
- [DataField]
+ [DataField, AutoNetworkedField]
public HashSet<ProtoId<EmotePrototype>> BlocksEmotes = [];
}
-using Content.Server.Speech.Components;
-using Content.Shared.Emoting;
+using Content.Shared.Chat;
using Content.Shared.Inventory;
+using Content.Shared.Speech.Components;
-namespace Content.Server.Speech.EntitySystems;
+namespace Content.Shared.Speech.EntitySystems;
public sealed class EmoteBlockerSystem : EntitySystem
{