diff --git a/Content.Server/Chat/Systems/ChatSystem.cs b/Content.Server/Chat/Systems/ChatSystem.cs
index 216c782ce1..89214cdc5e 100644
--- a/Content.Server/Chat/Systems/ChatSystem.cs
+++ b/Content.Server/Chat/Systems/ChatSystem.cs
@@ -750,7 +750,7 @@ public sealed partial class ChatSystem : SharedChatSystem
///
/// Sends a chat message to the given players in range of the source entity.
///
- private void SendInVoiceRange(ChatChannel channel, string message, string wrappedMessage, EntityUid source, ChatTransmitRange range, NetUserId? author = null)
+ public void SendInVoiceRange(ChatChannel channel, string message, string wrappedMessage, EntityUid source, ChatTransmitRange range, NetUserId? author = null)
{
foreach (var (session, data) in GetRecipients(source, VoiceRange))
{
diff --git a/Content.Server/White/Halt/HaltComponent.cs b/Content.Server/White/Halt/HaltComponent.cs
new file mode 100644
index 0000000000..11f71259fd
--- /dev/null
+++ b/Content.Server/White/Halt/HaltComponent.cs
@@ -0,0 +1,37 @@
+using Robust.Shared.Audio;
+
+namespace Content.Server.White.Halt;
+
+[RegisterComponent]
+public sealed partial class HaltComponent : Component
+{
+ [DataField("color"), ViewVariables(VVAccess.ReadWrite)]
+ public string ChatColor { get; private set; } = Color.Red.ToHex();
+
+ [DataField("locale"), ViewVariables(VVAccess.ReadWrite)]
+ public string ChatLoc { get; private set; } = "chat-manager-entity-say-hailer-wrap-message";
+
+ [DataField("actionEntity")] public EntityUid? ActionEntity;
+
+ public readonly Dictionary PhraseToSoundMap = new()
+ {
+ ["halt-phrase"] = new SoundPathSpecifier("/Audio/Voice/Complionator/halt.ogg"),
+ ["bobby-phrase"] = new SoundPathSpecifier("/Audio/Voice/Complionator/bobby.ogg"),
+ ["compliance-phrase"] = new SoundPathSpecifier("/Audio/Voice/Complionator/compliance.ogg"),
+ ["justice-phrase"] = new SoundPathSpecifier("/Audio/Voice/Complionator/justice.ogg"),
+ ["running-phrase"] = new SoundPathSpecifier("/Audio/Voice/Complionator/running.ogg"),
+ ["dontmove-phrase"] = new SoundPathSpecifier("/Audio/Voice/Complionator/dontmove.ogg"),
+ ["floor-phrase"] = new SoundPathSpecifier("/Audio/Voice/Complionator/floor.ogg"),
+ ["robocop-phrase"] = new SoundPathSpecifier("/Audio/Voice/Complionator/robocop.ogg"),
+ ["god-phrase"] = new SoundPathSpecifier("/Audio/Voice/Complionator/god.ogg"),
+ ["freeze-phrase"] = new SoundPathSpecifier("/Audio/Voice/Complionator/freeze.ogg"),
+ ["imperial-phrase"] = new SoundPathSpecifier("/Audio/Voice/Complionator/imperial.ogg"),
+ ["bash-phrase"] = new SoundPathSpecifier("/Audio/Voice/Complionator/bash.ogg"),
+ ["harry-phrase"] = new SoundPathSpecifier("/Audio/Voice/Complionator/harry.ogg"),
+ ["asshole-phrase"] = new SoundPathSpecifier("/Audio/Voice/Complionator/asshole.ogg"),
+ ["stfu-phrase"] = new SoundPathSpecifier("/Audio/Voice/Complionator/stfu.ogg"),
+ ["shutup-phrase"] = new SoundPathSpecifier("/Audio/Voice/Complionator/shutup.ogg"),
+ ["super-phrase"] = new SoundPathSpecifier("/Audio/Voice/Complionator/super.ogg"),
+ ["dredd-phrase"] = new SoundPathSpecifier("/Audio/Voice/Complionator/dredd.ogg")
+ };
+}
diff --git a/Content.Server/White/Halt/HaltSystem.cs b/Content.Server/White/Halt/HaltSystem.cs
new file mode 100644
index 0000000000..1aae23c1ef
--- /dev/null
+++ b/Content.Server/White/Halt/HaltSystem.cs
@@ -0,0 +1,62 @@
+using System.Linq;
+using Content.Shared.Actions;
+using Content.Server.Chat.Systems;
+using Robust.Shared.Utility;
+using Content.Shared.Chat;
+using Content.Shared.White.Other;
+using Robust.Shared.Audio.Systems;
+using Robust.Shared.Prototypes;
+using Robust.Shared.Random;
+
+namespace Content.Server.White.Halt
+{
+ public sealed class HaltSystem : EntitySystem
+ {
+ [Dependency] private readonly ChatSystem _chat = default!;
+ [Dependency] private readonly SharedAudioSystem _audio = default!;
+ [Dependency] private readonly IRobustRandom _random = default!;
+ [Dependency] private readonly IPrototypeManager _prototypeManager = default!;
+
+ public override void Initialize()
+ {
+ base.Initialize();
+ SubscribeLocalEvent(OnGetEquipped);
+ SubscribeLocalEvent(Act);
+ }
+
+ private void OnGetEquipped(EntityUid uid, HaltComponent component, GetItemActionsEvent args)
+ {
+ if (args.InHands)
+ return;
+
+ args.AddAction(ref component.ActionEntity, "Halt");
+ }
+
+ private void Act(EntityUid uid, HaltComponent component, HaltAction args)
+ {
+ if (args.Handled)
+ return;
+
+ if (!component.PhraseToSoundMap.Any())
+ return;
+
+ var randomIndex = _random.Next(component.PhraseToSoundMap.Count);
+ var selectedPhrase = component.PhraseToSoundMap.Keys.ElementAt(randomIndex);
+ var selectedSound = component.PhraseToSoundMap[selectedPhrase];
+
+ _audio.PlayPvs(selectedSound, uid);
+
+ var hMessage = Loc.GetString(selectedPhrase);
+ var wrappedMessage = Loc.GetString(
+ component.ChatLoc,
+ ("entityName", args.Performer),
+ ("hMessage", FormattedMessage.EscapeText(hMessage)),
+ ("color", component.ChatColor)
+ );
+
+ _chat.SendInVoiceRange(ChatChannel.Local, hMessage, wrappedMessage, args.Performer, ChatTransmitRange.Normal);
+
+ args.Handled = true;
+ }
+ }
+}
diff --git a/Content.Server/White/Other/CritSystem/CritSystem.cs b/Content.Server/White/Other/CritSystem/CritSystem.cs
index e14d7e5d95..26ef0cbf27 100644
--- a/Content.Server/White/Other/CritSystem/CritSystem.cs
+++ b/Content.Server/White/Other/CritSystem/CritSystem.cs
@@ -24,8 +24,9 @@ public sealed class CritSystem : EntitySystem
public override void Initialize()
{
base.Initialize();
- SubscribeLocalEvent(HandleHit);
+
SubscribeLocalEvent(OnExamine);
+ SubscribeLocalEvent(HandleHit);
}
private void OnExamine(EntityUid uid, CritComponent component, ExaminedEvent args)
@@ -33,7 +34,7 @@ public sealed class CritSystem : EntitySystem
if (component.IsBloodDagger)
{
args.PushMarkup(
- "[color=red]Критическая жажда: Кинжал Жажды обладает смертоносной точностью. Его владелец имеет 20% шанс нанести критический урон, поражая врага в его самые уязвимые места.\n" +
+ "[color=red]Критическая жажда: Кинжал Жажды обладает смертоносной точностью. Его владелец имеет 25% шанс нанести критический урон, поражая врага в его самые уязвимые места.\n" +
"Кровавый абсорб: При каждом успешном критическом ударе, кинжал извлекает кровь из цели, восстанавливая здоровье владельцу пропорционально количеству высосанной крови.[/color]"
);
}
diff --git a/Content.Shared/Mobs/Components/HaltAction.cs b/Content.Shared/Mobs/Components/HaltAction.cs
new file mode 100644
index 0000000000..6c0c19e9be
--- /dev/null
+++ b/Content.Shared/Mobs/Components/HaltAction.cs
@@ -0,0 +1,7 @@
+using Content.Shared.Actions;
+
+namespace Content.Shared.White.Other;
+
+public sealed partial class HaltAction : InstantActionEvent
+{
+}
diff --git a/Resources/Audio/Voice/Complionator/asshole.ogg b/Resources/Audio/Voice/Complionator/asshole.ogg
new file mode 100644
index 0000000000..a6a326abe4
Binary files /dev/null and b/Resources/Audio/Voice/Complionator/asshole.ogg differ
diff --git a/Resources/Audio/Voice/Complionator/bash.ogg b/Resources/Audio/Voice/Complionator/bash.ogg
new file mode 100644
index 0000000000..c14feb5b5f
Binary files /dev/null and b/Resources/Audio/Voice/Complionator/bash.ogg differ
diff --git a/Resources/Audio/Voice/Complionator/bobby.ogg b/Resources/Audio/Voice/Complionator/bobby.ogg
new file mode 100644
index 0000000000..b4a6a890f2
Binary files /dev/null and b/Resources/Audio/Voice/Complionator/bobby.ogg differ
diff --git a/Resources/Audio/Voice/Complionator/compliance.ogg b/Resources/Audio/Voice/Complionator/compliance.ogg
new file mode 100644
index 0000000000..231f70aa36
Binary files /dev/null and b/Resources/Audio/Voice/Complionator/compliance.ogg differ
diff --git a/Resources/Audio/Voice/Complionator/dontmove.ogg b/Resources/Audio/Voice/Complionator/dontmove.ogg
new file mode 100644
index 0000000000..cb3ee03f7b
Binary files /dev/null and b/Resources/Audio/Voice/Complionator/dontmove.ogg differ
diff --git a/Resources/Audio/Voice/Complionator/dredd.ogg b/Resources/Audio/Voice/Complionator/dredd.ogg
new file mode 100644
index 0000000000..8a3010489e
Binary files /dev/null and b/Resources/Audio/Voice/Complionator/dredd.ogg differ
diff --git a/Resources/Audio/Voice/Complionator/floor.ogg b/Resources/Audio/Voice/Complionator/floor.ogg
new file mode 100644
index 0000000000..0e29c78143
Binary files /dev/null and b/Resources/Audio/Voice/Complionator/floor.ogg differ
diff --git a/Resources/Audio/Voice/Complionator/freeze.ogg b/Resources/Audio/Voice/Complionator/freeze.ogg
new file mode 100644
index 0000000000..1be9ba7361
Binary files /dev/null and b/Resources/Audio/Voice/Complionator/freeze.ogg differ
diff --git a/Resources/Audio/Voice/Complionator/god.ogg b/Resources/Audio/Voice/Complionator/god.ogg
new file mode 100644
index 0000000000..a109e2a351
Binary files /dev/null and b/Resources/Audio/Voice/Complionator/god.ogg differ
diff --git a/Resources/Audio/Voice/Complionator/halt.ogg b/Resources/Audio/Voice/Complionator/halt.ogg
new file mode 100644
index 0000000000..457091f4ce
Binary files /dev/null and b/Resources/Audio/Voice/Complionator/halt.ogg differ
diff --git a/Resources/Audio/Voice/Complionator/harry.ogg b/Resources/Audio/Voice/Complionator/harry.ogg
new file mode 100644
index 0000000000..2ff2acc856
Binary files /dev/null and b/Resources/Audio/Voice/Complionator/harry.ogg differ
diff --git a/Resources/Audio/Voice/Complionator/imperial.ogg b/Resources/Audio/Voice/Complionator/imperial.ogg
new file mode 100644
index 0000000000..df40102de1
Binary files /dev/null and b/Resources/Audio/Voice/Complionator/imperial.ogg differ
diff --git a/Resources/Audio/Voice/Complionator/justice.ogg b/Resources/Audio/Voice/Complionator/justice.ogg
new file mode 100644
index 0000000000..14409495ca
Binary files /dev/null and b/Resources/Audio/Voice/Complionator/justice.ogg differ
diff --git a/Resources/Audio/Voice/Complionator/robocop.ogg b/Resources/Audio/Voice/Complionator/robocop.ogg
new file mode 100644
index 0000000000..f7a19c7850
Binary files /dev/null and b/Resources/Audio/Voice/Complionator/robocop.ogg differ
diff --git a/Resources/Audio/Voice/Complionator/running.ogg b/Resources/Audio/Voice/Complionator/running.ogg
new file mode 100644
index 0000000000..82d68cdf2f
Binary files /dev/null and b/Resources/Audio/Voice/Complionator/running.ogg differ
diff --git a/Resources/Audio/Voice/Complionator/shutup.ogg b/Resources/Audio/Voice/Complionator/shutup.ogg
new file mode 100644
index 0000000000..8ca70a0989
Binary files /dev/null and b/Resources/Audio/Voice/Complionator/shutup.ogg differ
diff --git a/Resources/Audio/Voice/Complionator/stfu.ogg b/Resources/Audio/Voice/Complionator/stfu.ogg
new file mode 100644
index 0000000000..44c878ac11
Binary files /dev/null and b/Resources/Audio/Voice/Complionator/stfu.ogg differ
diff --git a/Resources/Audio/Voice/Complionator/super.ogg b/Resources/Audio/Voice/Complionator/super.ogg
new file mode 100644
index 0000000000..2ec5183ae6
Binary files /dev/null and b/Resources/Audio/Voice/Complionator/super.ogg differ
diff --git a/Resources/Locale/ru-RU/white/hailer.ftl b/Resources/Locale/ru-RU/white/hailer.ftl
new file mode 100644
index 0000000000..ce2e0067ab
--- /dev/null
+++ b/Resources/Locale/ru-RU/white/hailer.ftl
@@ -0,0 +1,20 @@
+chat-manager-entity-say-hailer-wrap-message = { $entityName } командует, "[font size=13][color={ $color }]{ $hMessage }[/color][/size]"
+
+halt-phrase = СТОЯТЬ! СТОЯТЬ! СТОЯТЬ!
+bobby-phrase = Стоять! Во имя Закона!
+compliance-phrase = Сдаться в ваших интересах.
+justice-phrase = Приготовьтесь к справедливости!
+running-phrase = Бег только увеличит ваш срок.
+dontmove-phrase = Не двигаться, уёбок!
+floor-phrase = На пол, сука!
+robocop-phrase = Мёртвый или живой ты пойдешь со мной.
+god-phrase = Бог создал сегодня для жуликов, которых мы не могли поймать вчера.
+freeze-phrase = Замри, подонок!
+imperial-phrase = Стоять, преступная мразь!
+bash-phrase = Остановись или я тебя ударю.
+harry-phrase = Сделай мой день.
+asshole-phrase = Хватит нарушать закон, гадина.
+stfu-phrase = Вы имеете право завалить ебало.
+shutup-phrase = Заткнись нахуй!
+super-phrase = Сейчас ты познаешь гнев золотой сферы.
+dredd-phrase = Я ЗАКОН!
diff --git a/Resources/Prototypes/Actions/types.yml b/Resources/Prototypes/Actions/types.yml
index f301589879..427acd1863 100644
--- a/Resources/Prototypes/Actions/types.yml
+++ b/Resources/Prototypes/Actions/types.yml
@@ -315,3 +315,16 @@
event: !type:ToggleEyesActionEvent
useDelay: 1 # so u cant give yourself and observers eyestrain by rapidly spamming the action
+
+- type: entity
+ id: Halt
+ name: Halt!
+ description: Halt!
+ noSpawn: true
+ components:
+ - type: InstantAction
+ useDelay: 5
+ icon:
+ sprite: Objects/Weapons/Melee/stunbaton.rsi
+ state: stunbaton_off
+ event: !type:HaltAction
diff --git a/Resources/Prototypes/Entities/Clothing/Masks/masks.yml b/Resources/Prototypes/Entities/Clothing/Masks/masks.yml
index 59dfb526c5..bf3e9fcd20 100644
--- a/Resources/Prototypes/Entities/Clothing/Masks/masks.yml
+++ b/Resources/Prototypes/Entities/Clothing/Masks/masks.yml
@@ -36,6 +36,7 @@
Slash: 0.95
Piercing: 0.95
Heat: 0.95
+ - type: Halt
- type: entity
parent: ClothingMaskGas