From e45dd96af9dbdb59bbdef657542b5d977ab59d3c Mon Sep 17 00:00:00 2001
From: HerCoyote23 <131214189+HerCoyote23@users.noreply.github.com>
Date: Tue, 23 May 2023 11:12:30 -0700
Subject: [PATCH] Northstar Gloves (#16021)
* Added Gloves of North Star, no sprite or talking yet...
* Added sprites for the gloves of the north star...
* Replaced more placeholder sprites for northstar gloves...
* Added gloves of the north star to uplink...
* Added speech on hit, not yet configureable
* Not functional yet, but a step in the right direction I hope...
* IT WORKS!!
* Licensing and cleanup
* Reduced attack speed, changed from chat to popup, added some admin logging. It was causing too much adminlog spam otherwise
* Reorganized some files, final build??
* Changed the adminlog type from Verb to new type ItemConfigure
* More cleanup, fix sprite reference maybe
* Keronshb's suggestions, fixed some stuff, made hit sound use the meaty punch sfx
* Adds support for hiding speak/whisper/emote from adminlogs, makes northstar speak again!
* Some file shuffling, some of Keronshb's requests. Might appear a bit funky in github because vscode kept duplicating files for some reason and I had to delete them
* Made it work with the latest changes on Master
* Final? cleanup, upped dmg to 8, made ui not activate on activateinhand, instead you need to right click
* Set value to 0 credits, that's all
* Well that was much easier than I made it out to be. Now you can only activate the gloves with right click, no more mispredicts.
* Update MeleeWeaponSystem.cs
Iunno why this got changed in the first place, but I'm changin it back
* emptycommit
* emptycommit
* The tiny fixening
---
.../Melee/UI/MeleeSpeechBoundUserInterface.cs | 56 +++++++++++++++
.../Weapons/Melee/UI/MeleeSpeechWindow.xaml | 8 +++
.../Melee/UI/MeleeSpeechWindow.xaml.cs | 28 ++++++++
Content.Server/Chat/Commands/MeCommand.cs | 2 +-
Content.Server/Chat/Commands/SayCommand.cs | 2 +-
.../Chat/Commands/WhisperCommand.cs | 2 +-
.../Chat/Systems/ChatSystem.Emote.cs | 11 +--
Content.Server/Chat/Systems/ChatSystem.cs | 68 +++++++++---------
.../Speech/EntitySystems/MeleeSpeechSystem.cs | 66 +++++++++++++++++
.../UserInterface/ActivatableUIComponent.cs | 7 ++
.../UserInterface/ActivatableUISystem.cs | 1 +
.../Weapons/Melee/MeleeWeaponSystem.cs | 30 ++++++--
Content.Shared.Database/LogType.cs | 1 +
.../Components/ChameleonClothingComponent.cs | 4 +-
.../Speech/Components/MeleeSpeechComponent.cs | 51 +++++++++++++
.../EntitySystems/SharedMeleeSpeechSystem.cs | 7 ++
Content.Shared/Speech/SpeechSystem.cs | 2 +-
.../Weapons/Melee/MeleeWeaponComponent.cs | 1 +
.../Weapons/Melee/SharedMeleeSpeechSystem.cs | 7 ++
.../components/northstar-component.ftl | 2 +
.../Locale/en-US/store/uplink-catalog.ftl | 3 +
.../Prototypes/Catalog/uplink_catalog.yml | 10 +++
.../Entities/Clothing/Hands/gloves.yml | 35 +++++++++
.../Gloves/northstar.rsi/equipped-HAND.png | Bin 0 -> 434 bytes
.../Hands/Gloves/northstar.rsi/icon.png | Bin 0 -> 289 bytes
.../Gloves/northstar.rsi/inhand-left.png | Bin 0 -> 933 bytes
.../Gloves/northstar.rsi/inhand-right.png | Bin 0 -> 881 bytes
.../Hands/Gloves/northstar.rsi/meta.json | 26 +++++++
28 files changed, 383 insertions(+), 47 deletions(-)
create mode 100644 Content.Client/Weapons/Melee/UI/MeleeSpeechBoundUserInterface.cs
create mode 100644 Content.Client/Weapons/Melee/UI/MeleeSpeechWindow.xaml
create mode 100644 Content.Client/Weapons/Melee/UI/MeleeSpeechWindow.xaml.cs
create mode 100644 Content.Server/Speech/EntitySystems/MeleeSpeechSystem.cs
create mode 100644 Content.Shared/Speech/Components/MeleeSpeechComponent.cs
create mode 100644 Content.Shared/Speech/EntitySystems/SharedMeleeSpeechSystem.cs
create mode 100644 Content.Shared/Weapons/Melee/SharedMeleeSpeechSystem.cs
create mode 100644 Resources/Locale/en-US/clothing/components/northstar-component.ftl
create mode 100644 Resources/Textures/Clothing/Hands/Gloves/northstar.rsi/equipped-HAND.png
create mode 100644 Resources/Textures/Clothing/Hands/Gloves/northstar.rsi/icon.png
create mode 100644 Resources/Textures/Clothing/Hands/Gloves/northstar.rsi/inhand-left.png
create mode 100644 Resources/Textures/Clothing/Hands/Gloves/northstar.rsi/inhand-right.png
create mode 100644 Resources/Textures/Clothing/Hands/Gloves/northstar.rsi/meta.json
diff --git a/Content.Client/Weapons/Melee/UI/MeleeSpeechBoundUserInterface.cs b/Content.Client/Weapons/Melee/UI/MeleeSpeechBoundUserInterface.cs
new file mode 100644
index 0000000000..56079652bd
--- /dev/null
+++ b/Content.Client/Weapons/Melee/UI/MeleeSpeechBoundUserInterface.cs
@@ -0,0 +1,56 @@
+using Robust.Client.GameObjects;
+using Content.Shared.Speech.Components;
+
+namespace Content.Client.Weapons.Melee.UI;
+
+///
+/// Initializes a and updates it when new server messages are received.
+///
+public sealed class MeleeSpeechBoundUserInterface : BoundUserInterface
+{
+ private MeleeSpeechWindow? _window;
+
+ public MeleeSpeechBoundUserInterface(ClientUserInterfaceComponent owner, Enum uiKey) : base(owner, uiKey)
+ {
+ }
+
+ protected override void Open()
+ {
+ base.Open();
+
+ _window = new MeleeSpeechWindow();
+ if (State != null)
+ UpdateState(State);
+
+ _window.OpenCentered();
+
+ _window.OnClose += Close;
+ _window.OnBattlecryEntered += OnBattlecryChanged;
+ }
+
+
+ private void OnBattlecryChanged(string newBattlecry)
+ {
+ SendMessage(new MeleeSpeechBattlecryChangedMessage(newBattlecry));
+ }
+
+ ///
+ /// Update the UI state based on server-sent info
+ ///
+ ///
+ protected override void UpdateState(BoundUserInterfaceState state)
+ {
+ base.UpdateState(state);
+ if (_window == null || state is not MeleeSpeechBoundUserInterfaceState cast)
+ return;
+
+ _window.SetCurrentBattlecry(cast.CurrentBattlecry);
+ }
+
+ protected override void Dispose(bool disposing)
+ {
+ base.Dispose(disposing);
+ if (!disposing) return;
+ _window?.Dispose();
+ }
+}
diff --git a/Content.Client/Weapons/Melee/UI/MeleeSpeechWindow.xaml b/Content.Client/Weapons/Melee/UI/MeleeSpeechWindow.xaml
new file mode 100644
index 0000000000..5f5e324962
--- /dev/null
+++ b/Content.Client/Weapons/Melee/UI/MeleeSpeechWindow.xaml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
diff --git a/Content.Client/Weapons/Melee/UI/MeleeSpeechWindow.xaml.cs b/Content.Client/Weapons/Melee/UI/MeleeSpeechWindow.xaml.cs
new file mode 100644
index 0000000000..e09de0b260
--- /dev/null
+++ b/Content.Client/Weapons/Melee/UI/MeleeSpeechWindow.xaml.cs
@@ -0,0 +1,28 @@
+using Robust.Client.AutoGenerated;
+using Robust.Client.UserInterface.CustomControls;
+using Robust.Client.UserInterface.XAML;
+
+namespace Content.Client.Weapons.Melee.UI;
+
+[GenerateTypedNameReferences]
+public sealed partial class MeleeSpeechWindow : DefaultWindow
+{
+
+ public event Action? OnBattlecryEntered;
+
+ public MeleeSpeechWindow()
+ {
+ RobustXamlLoader.Load(this);
+
+ BattlecryLineEdit.OnTextEntered += e => OnBattlecryEntered?.Invoke(e.Text);
+ }
+
+
+ public void SetCurrentBattlecry(string battlecry)
+ {
+ BattlecryLineEdit.Text = battlecry;
+ }
+
+}
+
+
diff --git a/Content.Server/Chat/Commands/MeCommand.cs b/Content.Server/Chat/Commands/MeCommand.cs
index 66576d1ea6..36f86cf4d6 100644
--- a/Content.Server/Chat/Commands/MeCommand.cs
+++ b/Content.Server/Chat/Commands/MeCommand.cs
@@ -38,7 +38,7 @@ namespace Content.Server.Chat.Commands
return;
IoCManager.Resolve().GetEntitySystem()
- .TrySendInGameICMessage(playerEntity, message, InGameICChatType.Emote, ChatTransmitRange.Normal, shell, player);
+ .TrySendInGameICMessage(playerEntity, message, InGameICChatType.Emote, ChatTransmitRange.Normal, false, shell, player);
}
}
}
diff --git a/Content.Server/Chat/Commands/SayCommand.cs b/Content.Server/Chat/Commands/SayCommand.cs
index 4cf3d507d2..7c2125d8c1 100644
--- a/Content.Server/Chat/Commands/SayCommand.cs
+++ b/Content.Server/Chat/Commands/SayCommand.cs
@@ -38,7 +38,7 @@ namespace Content.Server.Chat.Commands
return;
IoCManager.Resolve().GetEntitySystem()
- .TrySendInGameICMessage(playerEntity, message, InGameICChatType.Speak, ChatTransmitRange.Normal, shell, player);
+ .TrySendInGameICMessage(playerEntity, message, InGameICChatType.Speak, ChatTransmitRange.Normal, false, shell, player);
}
}
}
diff --git a/Content.Server/Chat/Commands/WhisperCommand.cs b/Content.Server/Chat/Commands/WhisperCommand.cs
index dac3592562..41eba8b384 100644
--- a/Content.Server/Chat/Commands/WhisperCommand.cs
+++ b/Content.Server/Chat/Commands/WhisperCommand.cs
@@ -38,7 +38,7 @@ namespace Content.Server.Chat.Commands
return;
IoCManager.Resolve().GetEntitySystem()
- .TrySendInGameICMessage(playerEntity, message, InGameICChatType.Whisper, ChatTransmitRange.Normal, shell, player);
+ .TrySendInGameICMessage(playerEntity, message, InGameICChatType.Whisper, ChatTransmitRange.Normal, false, shell, player);
}
}
}
diff --git a/Content.Server/Chat/Systems/ChatSystem.Emote.cs b/Content.Server/Chat/Systems/ChatSystem.Emote.cs
index 5210b366ab..df13db7af1 100644
--- a/Content.Server/Chat/Systems/ChatSystem.Emote.cs
+++ b/Content.Server/Chat/Systems/ChatSystem.Emote.cs
@@ -52,13 +52,14 @@ public partial class ChatSystem
///
/// The entity that is speaking
/// The id of emote prototype. Should has valid
+ /// Whether or not this message should appear in the adminlog window
/// Conceptual range of transmission, if it shows in the chat window, if it shows to far-away ghosts or ghosts at all...
/// The name to use for the speaking entity. Usually this should just be modified via . If this is set, the event will not get raised.
- public void TryEmoteWithChat(EntityUid source, string emoteId, ChatTransmitRange range = ChatTransmitRange.Normal, string? nameOverride = null)
+ public void TryEmoteWithChat(EntityUid source, string emoteId, ChatTransmitRange range = ChatTransmitRange.Normal, bool hideLog = false, string? nameOverride = null)
{
if (!_prototypeManager.TryIndex(emoteId, out var proto))
return;
- TryEmoteWithChat(source, proto, range, nameOverride);
+ TryEmoteWithChat(source, proto, range, hideLog, nameOverride);
}
///
@@ -66,15 +67,17 @@ public partial class ChatSystem
///
/// The entity that is speaking
/// The emote prototype. Should has valid
+ /// Whether or not this message should appear in the adminlog window
+ /// Whether or not this message should appear in the chat window
/// Conceptual range of transmission, if it shows in the chat window, if it shows to far-away ghosts or ghosts at all...
/// The name to use for the speaking entity. Usually this should just be modified via . If this is set, the event will not get raised.
- public void TryEmoteWithChat(EntityUid source, EmotePrototype emote, ChatTransmitRange range = ChatTransmitRange.Normal, string? nameOverride = null)
+ public void TryEmoteWithChat(EntityUid source, EmotePrototype emote, ChatTransmitRange range = ChatTransmitRange.Normal, bool hideLog = false, string? nameOverride = null)
{
// check if proto has valid message for chat
if (emote.ChatMessages.Count != 0)
{
var action = _random.Pick(emote.ChatMessages);
- SendEntityEmote(source, action, range, nameOverride, false);
+ SendEntityEmote(source, action, range, nameOverride, false, hideLog);
}
// do the rest of emote event logic here
diff --git a/Content.Server/Chat/Systems/ChatSystem.cs b/Content.Server/Chat/Systems/ChatSystem.cs
index 4eda021b2e..39aa207466 100644
--- a/Content.Server/Chat/Systems/ChatSystem.cs
+++ b/Content.Server/Chat/Systems/ChatSystem.cs
@@ -100,14 +100,14 @@ public sealed partial class ChatSystem : SharedChatSystem
private void OnGameChange(GameRunLevelChangedEvent ev)
{
- switch(ev.New)
+ switch (ev.New)
{
case GameRunLevel.InRound:
- if(!_configurationManager.GetCVar(CCVars.OocEnableDuringRound))
+ if (!_configurationManager.GetCVar(CCVars.OocEnableDuringRound))
_configurationManager.SetCVar(CCVars.OocEnabled, false);
break;
case GameRunLevel.PostRound:
- if(!_configurationManager.GetCVar(CCVars.OocEnableDuringRound))
+ if (!_configurationManager.GetCVar(CCVars.OocEnableDuringRound))
_configurationManager.SetCVar(CCVars.OocEnabled, true);
break;
}
@@ -120,13 +120,14 @@ public sealed partial class ChatSystem : SharedChatSystem
/// The message being spoken or emoted
/// The chat type
/// Whether or not this message should appear in the chat window
+ /// Whether or not this message should appear in the adminlog window
///
/// The player doing the speaking
/// The name to use for the speaking entity. Usually this should just be modified via . If this is set, the event will not get raised.
- public void TrySendInGameICMessage(EntityUid source, string message, InGameICChatType desiredType, bool hideChat,
+ public void TrySendInGameICMessage(EntityUid source, string message, InGameICChatType desiredType, bool hideChat, bool hideLog = false,
IConsoleShell? shell = null, IPlayerSession? player = null, string? nameOverride = null, bool checkRadioPrefix = true)
{
- TrySendInGameICMessage(source, message, desiredType, hideChat ? ChatTransmitRange.HideChat : ChatTransmitRange.Normal, shell, player, nameOverride, checkRadioPrefix);
+ TrySendInGameICMessage(source, message, desiredType, hideChat ? ChatTransmitRange.HideChat : ChatTransmitRange.Normal, hideLog, shell, player, nameOverride, checkRadioPrefix);
}
///
@@ -139,7 +140,7 @@ public sealed partial class ChatSystem : SharedChatSystem
///
/// The player doing the speaking
/// The name to use for the speaking entity. Usually this should just be modified via . If this is set, the event will not get raised.
- public void TrySendInGameICMessage(EntityUid source, string message, InGameICChatType desiredType, ChatTransmitRange range,
+ public void TrySendInGameICMessage(EntityUid source, string message, InGameICChatType desiredType, ChatTransmitRange range, bool hideLog = false,
IConsoleShell? shell = null, IPlayerSession? player = null, string? nameOverride = null, bool checkRadioPrefix = true)
{
if (HasComp(source))
@@ -194,13 +195,13 @@ public sealed partial class ChatSystem : SharedChatSystem
switch (desiredType)
{
case InGameICChatType.Speak:
- SendEntitySpeak(source, message, range, nameOverride);
+ SendEntitySpeak(source, message, range, nameOverride, hideLog);
break;
case InGameICChatType.Whisper:
- SendEntityWhisper(source, message, range, null, nameOverride);
+ SendEntityWhisper(source, message, range, null, nameOverride, hideLog);
break;
case InGameICChatType.Emote:
- SendEntityEmote(source, message, range, nameOverride);
+ SendEntityEmote(source, message, range, nameOverride, hideLog);
break;
}
}
@@ -294,7 +295,7 @@ public sealed partial class ChatSystem : SharedChatSystem
#region Private API
- private void SendEntitySpeak(EntityUid source, string originalMessage, ChatTransmitRange range, string? nameOverride)
+ private void SendEntitySpeak(EntityUid source, string originalMessage, ChatTransmitRange range, string? nameOverride, bool hideLog = false)
{
if (!_actionBlocker.CanSpeak(source))
return;
@@ -326,7 +327,8 @@ public sealed partial class ChatSystem : SharedChatSystem
RaiseLocalEvent(source, ev, true);
// To avoid logging any messages sent by entities that are not players, like vendors, cloning, etc.
- if (!HasComp(source))
+ // Also doesn't log if hideLog is true.
+ if (!HasComp(source) || hideLog == true)
return;
if (originalMessage == message)
@@ -347,7 +349,7 @@ public sealed partial class ChatSystem : SharedChatSystem
}
}
- private void SendEntityWhisper(EntityUid source, string originalMessage, ChatTransmitRange range, RadioChannelPrototype? channel, string? nameOverride)
+ private void SendEntityWhisper(EntityUid source, string originalMessage, ChatTransmitRange range, RadioChannelPrototype? channel, string? nameOverride, bool hideLog = false)
{
if (!_actionBlocker.CanSpeak(source))
return;
@@ -399,26 +401,26 @@ public sealed partial class ChatSystem : SharedChatSystem
var ev = new EntitySpokeEvent(source, message, channel, obfuscatedMessage);
RaiseLocalEvent(source, ev, true);
-
- if (originalMessage == message)
- {
- if (name != Name(source))
- _adminLogger.Add(LogType.Chat, LogImpact.Low, $"Whisper from {ToPrettyString(source):user} as {name}: {originalMessage}.");
+ if (!hideLog)
+ if (originalMessage == message)
+ {
+ if (name != Name(source))
+ _adminLogger.Add(LogType.Chat, LogImpact.Low, $"Whisper from {ToPrettyString(source):user} as {name}: {originalMessage}.");
+ else
+ _adminLogger.Add(LogType.Chat, LogImpact.Low, $"Whisper from {ToPrettyString(source):user}: {originalMessage}.");
+ }
else
- _adminLogger.Add(LogType.Chat, LogImpact.Low, $"Whisper from {ToPrettyString(source):user}: {originalMessage}.");
- }
- else
- {
- if (name != Name(source))
- _adminLogger.Add(LogType.Chat, LogImpact.Low,
+ {
+ if (name != Name(source))
+ _adminLogger.Add(LogType.Chat, LogImpact.Low,
$"Whisper from {ToPrettyString(source):user} as {name}, original: {originalMessage}, transformed: {message}.");
- else
- _adminLogger.Add(LogType.Chat, LogImpact.Low,
+ else
+ _adminLogger.Add(LogType.Chat, LogImpact.Low,
$"Whisper from {ToPrettyString(source):user}, original: {originalMessage}, transformed: {message}.");
- }
+ }
}
- private void SendEntityEmote(EntityUid source, string action, ChatTransmitRange range, string? nameOverride, bool checkEmote = true)
+ private void SendEntityEmote(EntityUid source, string action, ChatTransmitRange range, string? nameOverride, bool hideLog = false, bool checkEmote = true)
{
if (!_actionBlocker.CanEmote(source)) return;
@@ -433,11 +435,11 @@ public sealed partial class ChatSystem : SharedChatSystem
if (checkEmote)
TryEmoteChatInput(source, action);
SendInVoiceRange(ChatChannel.Emotes, action, wrappedMessage, source, range);
-
- if (name != Name(source))
- _adminLogger.Add(LogType.Chat, LogImpact.Low, $"Emote from {ToPrettyString(source):user} as {name}: {action}");
- else
- _adminLogger.Add(LogType.Chat, LogImpact.Low, $"Emote from {ToPrettyString(source):user}: {action}");
+ if (!hideLog)
+ if (name != Name(source))
+ _adminLogger.Add(LogType.Chat, LogImpact.Low, $"Emote from {ToPrettyString(source):user} as {name}: {action}");
+ else
+ _adminLogger.Add(LogType.Chat, LogImpact.Low, $"Emote from {ToPrettyString(source):user}: {action}");
}
// ReSharper disable once InconsistentNaming
@@ -714,7 +716,7 @@ public sealed class TransformSpeakerNameEvent : EntityEventArgs
}
///
-/// Raised broadcast in order to transform speech.
+/// Raised broadcast in order to transform speech.transmit
///
public sealed class TransformSpeechEvent : EntityEventArgs
{
diff --git a/Content.Server/Speech/EntitySystems/MeleeSpeechSystem.cs b/Content.Server/Speech/EntitySystems/MeleeSpeechSystem.cs
new file mode 100644
index 0000000000..95fcf8f2d1
--- /dev/null
+++ b/Content.Server/Speech/EntitySystems/MeleeSpeechSystem.cs
@@ -0,0 +1,66 @@
+using Content.Server.Administration.Logs;
+using Content.Shared.Speech.Components;
+using Content.Shared.Weapons.Melee;
+using Content.Shared.Database;
+
+
+namespace Content.Server.Speech.EntitySystems;
+
+public sealed class MeleeSpeechSystem : SharedMeleeSpeechSystem
+{
+
+ [Dependency] private readonly IAdminLogManager _adminLogger = default!;
+
+
+ public override void Initialize()
+ {
+ base.Initialize();
+ SubscribeLocalEvent(OnBattlecryChanged);
+ }
+
+
+ private void OnBattlecryChanged(EntityUid uid, MeleeSpeechComponent comp, MeleeSpeechBattlecryChangedMessage args)
+ {
+
+ if (!TryComp(uid, out var meleeSpeechUser))
+ return;
+
+ TryChangeBattlecry(uid, args.Battlecry, meleeSpeechUser);
+ }
+
+
+
+
+ ///
+ /// Attempts to change the battlecry of an entity.
+ /// Returns true/false.
+ ///
+ ///
+ /// If provided with a player's EntityUid to the player parameter, adds the change to the admin logs.
+ ///
+ public bool TryChangeBattlecry(EntityUid uid, string? battlecry, MeleeSpeechComponent? meleeSpeechComp = null)
+ {
+
+ if (!Resolve(uid, ref meleeSpeechComp))
+ return false;
+
+ if (!string.IsNullOrWhiteSpace(battlecry))
+ {
+ battlecry = battlecry.Trim();
+ }
+ else
+ {
+ battlecry = null;
+ }
+
+ if (meleeSpeechComp.Battlecry == battlecry)
+
+ return true;
+ meleeSpeechComp.Battlecry = battlecry;
+ Dirty(meleeSpeechComp);
+
+ _adminLogger.Add(LogType.ItemConfigure, LogImpact.Medium, $" {ToPrettyString(uid):entity}'s battlecry has been changed to {battlecry}");
+ return true;
+ }
+}
+
diff --git a/Content.Server/UserInterface/ActivatableUIComponent.cs b/Content.Server/UserInterface/ActivatableUIComponent.cs
index bcd34708db..5116331456 100644
--- a/Content.Server/UserInterface/ActivatableUIComponent.cs
+++ b/Content.Server/UserInterface/ActivatableUIComponent.cs
@@ -42,6 +42,13 @@ namespace Content.Server.UserInterface
[DataField("requireHands")]
public bool RequireHands = true;
+ ///
+ /// Whether you can activate this ui with activateinhand or not
+ ///
+ [ViewVariables(VVAccess.ReadWrite)]
+ [DataField("rightClickOnly")]
+ public bool rightClickOnly = false;
+
///
/// Whether spectators (non-admin ghosts) should be allowed to view this UI.
///
diff --git a/Content.Server/UserInterface/ActivatableUISystem.cs b/Content.Server/UserInterface/ActivatableUISystem.cs
index b947aac89f..8730c347dc 100644
--- a/Content.Server/UserInterface/ActivatableUISystem.cs
+++ b/Content.Server/UserInterface/ActivatableUISystem.cs
@@ -91,6 +91,7 @@ public sealed partial class ActivatableUISystem : EntitySystem
private void OnUseInHand(EntityUid uid, ActivatableUIComponent component, UseInHandEvent args)
{
if (args.Handled) return;
+ if (component.rightClickOnly) return;
args.Handled = InteractUI(args.User, component);
}
diff --git a/Content.Server/Weapons/Melee/MeleeWeaponSystem.cs b/Content.Server/Weapons/Melee/MeleeWeaponSystem.cs
index 60fa69649e..39c40854ea 100644
--- a/Content.Server/Weapons/Melee/MeleeWeaponSystem.cs
+++ b/Content.Server/Weapons/Melee/MeleeWeaponSystem.cs
@@ -1,14 +1,16 @@
using System.Linq;
using Content.Server.Body.Components;
using Content.Server.Body.Systems;
+using Content.Server.Chat.Systems;
using Content.Server.Chemistry.Components;
using Content.Server.Chemistry.EntitySystems;
using Content.Server.CombatMode.Disarm;
using Content.Server.Contests;
using Content.Server.Examine;
using Content.Server.Movement.Systems;
-using Content.Shared.Actions.Events;
+using Content.Server.Popups;
using Content.Shared.Administration.Components;
+using Content.Shared.Actions.Events;
using Content.Shared.CombatMode;
using Content.Shared.Damage;
using Content.Shared.Database;
@@ -17,6 +19,7 @@ using Content.Shared.Hands.Components;
using Content.Shared.IdentityManagement;
using Content.Shared.Inventory;
using Content.Shared.Popups;
+using Content.Shared.Speech.Components;
using Content.Shared.StatusEffect;
using Content.Shared.Tag;
using Content.Shared.Verbs;
@@ -42,11 +45,15 @@ public sealed class MeleeWeaponSystem : SharedMeleeWeaponSystem
[Dependency] private readonly LagCompensationSystem _lag = default!;
[Dependency] private readonly SolutionContainerSystem _solutions = default!;
[Dependency] private readonly TagSystem _tag = default!;
+ [Dependency] private readonly ChatSystem _chat = default!;
+ [Dependency] private readonly PopupSystem _popupSystem = default!;
+
public override void Initialize()
{
base.Initialize();
SubscribeLocalEvent(OnChemicalInjectorHit);
+ SubscribeLocalEvent(OnSpeechHit);
SubscribeLocalEvent>(OnMeleeExaminableVerb);
}
@@ -79,7 +86,7 @@ public sealed class MeleeWeaponSystem : SharedMeleeWeaponSystem
Text = Loc.GetString("damage-examinable-verb-text"),
Message = Loc.GetString("damage-examinable-verb-message"),
Category = VerbCategory.Examine,
- Icon = new SpriteSpecifier.Texture(new ("/Textures/Interface/VerbIcons/smite.svg.192dpi.png")),
+ Icon = new SpriteSpecifier.Texture(new("/Textures/Interface/VerbIcons/smite.svg.192dpi.png")),
};
args.Verbs.Add(verb);
@@ -189,7 +196,7 @@ public sealed class MeleeWeaponSystem : SharedMeleeWeaponSystem
("performerName", Identity.Entity(user, EntityManager)),
("targetName", Identity.Entity(target, EntityManager)));
- var msgUser = Loc.GetString(msgPrefix + "popup-message-cursor", ("targetName", Identity.Entity(target, EntityManager)));
+ var msgUser = Loc.GetString(msgPrefix + "popup-message-cursor", ("targetName", Identity.Entity(target, EntityManager)));
PopupSystem.PopupEntity(msgOther, user, filterOther, true);
PopupSystem.PopupEntity(msgUser, target, user);
@@ -200,7 +207,7 @@ public sealed class MeleeWeaponSystem : SharedMeleeWeaponSystem
var eventArgs = new DisarmedEvent { Target = target, Source = user, PushProbability = 1 - chance };
RaiseLocalEvent(target, eventArgs);
- RaiseNetworkEvent(new DamageEffectEvent(Color.Aqua, new List() {target}));
+ RaiseNetworkEvent(new DamageEffectEvent(Color.Aqua, new List() { target }));
return true;
}
@@ -265,6 +272,21 @@ public sealed class MeleeWeaponSystem : SharedMeleeWeaponSystem
RaiseNetworkEvent(new MeleeLungeEvent(user, angle, localPos, animation), filter);
}
+ private void OnSpeechHit(EntityUid owner, MeleeSpeechComponent comp, MeleeHitEvent args)
+ {
+ if (!args.IsHit ||
+ !args.HitEntities.Any())
+ {
+ return;
+ }
+
+ if (comp.Battlecry != null)//If the battlecry is set to empty, doesn't speak
+ {
+ _chat.TrySendInGameICMessage(args.User, comp.Battlecry, InGameICChatType.Speak, true, true); //Speech that isn't sent to chat or adminlogs
+ }
+
+ }
+
private void OnChemicalInjectorHit(EntityUid owner, MeleeChemicalInjectorComponent comp, MeleeHitEvent args)
{
if (!args.IsHit ||
diff --git a/Content.Shared.Database/LogType.cs b/Content.Shared.Database/LogType.cs
index 652ef0d7b5..4b69a0bb44 100644
--- a/Content.Shared.Database/LogType.cs
+++ b/Content.Shared.Database/LogType.cs
@@ -86,4 +86,5 @@ public enum LogType
Teleport = 81,
EntityDelete = 82,
Vote = 83,
+ ItemConfigure = 84,
}
diff --git a/Content.Shared/Clothing/Components/ChameleonClothingComponent.cs b/Content.Shared/Clothing/Components/ChameleonClothingComponent.cs
index 6ecd7cba33..56f5d3646e 100644
--- a/Content.Shared/Clothing/Components/ChameleonClothingComponent.cs
+++ b/Content.Shared/Clothing/Components/ChameleonClothingComponent.cs
@@ -1,4 +1,4 @@
-using Content.Shared.Clothing.EntitySystems;
+using Content.Shared.Clothing.EntitySystems;
using Content.Shared.Inventory;
using Robust.Shared.GameStates;
using Robust.Shared.Prototypes;
@@ -55,7 +55,7 @@ public sealed class ChameleonBoundUserInterfaceState : BoundUserInterfaceState
}
[Serializable, NetSerializable]
-public sealed class ChameleonPrototypeSelectedMessage: BoundUserInterfaceMessage
+public sealed class ChameleonPrototypeSelectedMessage : BoundUserInterfaceMessage
{
public readonly string SelectedId;
diff --git a/Content.Shared/Speech/Components/MeleeSpeechComponent.cs b/Content.Shared/Speech/Components/MeleeSpeechComponent.cs
new file mode 100644
index 0000000000..25815f1d84
--- /dev/null
+++ b/Content.Shared/Speech/Components/MeleeSpeechComponent.cs
@@ -0,0 +1,51 @@
+using Content.Shared.Speech.EntitySystems;
+using Robust.Shared.Serialization;
+
+namespace Content.Shared.Speech.Components;
+
+[RegisterComponent]
+[AutoGenerateComponentState]
+[Access(typeof(SharedMeleeSpeechSystem), Other = AccessPermissions.ReadWrite)]
+public sealed partial class MeleeSpeechComponent : Component
+{
+
+ [ViewVariables(VVAccess.ReadWrite)]
+ [DataField("Battlecry")]
+ [AutoNetworkedField]
+ [Access(typeof(SharedMeleeSpeechSystem), Other = AccessPermissions.ReadWrite)]
+ public string? Battlecry;
+}
+
+///
+/// Key representing which is currently open.
+/// Useful when there are multiple UI for an object. Here it's future-proofing only.
+///
+[Serializable, NetSerializable]
+public enum MeleeSpeechUiKey : byte
+{
+ Key,
+}
+
+///
+/// Represents an state that can be sent to the client
+///
+[Serializable, NetSerializable]
+public sealed class MeleeSpeechBoundUserInterfaceState : BoundUserInterfaceState
+{
+ public string CurrentBattlecry { get; }
+
+ public MeleeSpeechBoundUserInterfaceState(string currentBattlecry)
+ {
+ CurrentBattlecry = currentBattlecry;
+ }
+}
+
+[Serializable, NetSerializable]
+public sealed class MeleeSpeechBattlecryChangedMessage : BoundUserInterfaceMessage
+{
+ public string Battlecry { get; }
+ public MeleeSpeechBattlecryChangedMessage(string battlecry)
+ {
+ Battlecry = battlecry;
+ }
+}
diff --git a/Content.Shared/Speech/EntitySystems/SharedMeleeSpeechSystem.cs b/Content.Shared/Speech/EntitySystems/SharedMeleeSpeechSystem.cs
new file mode 100644
index 0000000000..4713ab3c5e
--- /dev/null
+++ b/Content.Shared/Speech/EntitySystems/SharedMeleeSpeechSystem.cs
@@ -0,0 +1,7 @@
+using Robust.Shared.Serialization;
+
+namespace Content.Shared.Weapons.Melee;
+
+public abstract class SharedMeleeSpeechSystem : EntitySystem
+{
+}
diff --git a/Content.Shared/Speech/SpeechSystem.cs b/Content.Shared/Speech/SpeechSystem.cs
index b1a3a39cd3..a21158aa9e 100644
--- a/Content.Shared/Speech/SpeechSystem.cs
+++ b/Content.Shared/Speech/SpeechSystem.cs
@@ -1,4 +1,4 @@
-using Robust.Shared.GameStates;
+using Robust.Shared.GameStates;
using Robust.Shared.Serialization;
namespace Content.Shared.Speech
diff --git a/Content.Shared/Weapons/Melee/MeleeWeaponComponent.cs b/Content.Shared/Weapons/Melee/MeleeWeaponComponent.cs
index 4936cc2e26..2ee18740fd 100644
--- a/Content.Shared/Weapons/Melee/MeleeWeaponComponent.cs
+++ b/Content.Shared/Weapons/Melee/MeleeWeaponComponent.cs
@@ -53,6 +53,7 @@ public sealed class MeleeWeaponComponent : Component
///
[ViewVariables(VVAccess.ReadWrite)]
public bool Attacking = false;
+
///
/// When did we start a heavy attack.
diff --git a/Content.Shared/Weapons/Melee/SharedMeleeSpeechSystem.cs b/Content.Shared/Weapons/Melee/SharedMeleeSpeechSystem.cs
new file mode 100644
index 0000000000..21841ef0ac
--- /dev/null
+++ b/Content.Shared/Weapons/Melee/SharedMeleeSpeechSystem.cs
@@ -0,0 +1,7 @@
+using Robust.Shared.Serialization;
+
+namespace Content.Shared.Speech.EntitySystems;
+
+public abstract class SharedMeleeSpeechSystem : EntitySystem
+{
+}
diff --git a/Resources/Locale/en-US/clothing/components/northstar-component.ftl b/Resources/Locale/en-US/clothing/components/northstar-component.ftl
new file mode 100644
index 0000000000..ba54ed3c11
--- /dev/null
+++ b/Resources/Locale/en-US/clothing/components/northstar-component.ftl
@@ -0,0 +1,2 @@
+north-star-current-battlecry = Battlecry:
+north-star-menu-title = Set Battlecry
diff --git a/Resources/Locale/en-US/store/uplink-catalog.ftl b/Resources/Locale/en-US/store/uplink-catalog.ftl
index 08b103c8d3..ea7e797f0b 100644
--- a/Resources/Locale/en-US/store/uplink-catalog.ftl
+++ b/Resources/Locale/en-US/store/uplink-catalog.ftl
@@ -20,6 +20,9 @@ uplink-edagger-desc = A small energy blade conveniently disguised in the form of
uplink-fire-axe-flaming-name = Fire Axe
uplink-fire-axe-flaming-desc = A classic-style weapon infused with advanced atmos technology to allow it to set targets on fire.
+uplink-gloves-north-star-name = Gloves of the North Star
+uplink-gloves-north-star-desc = A pair of gloves that reduce your punching cooldown drastically, allowing you to beat people to death in a flurry of punches.
+
# Explosives
uplink-explosive-grenade-name = Explosive Grenade
uplink-explosive-grenade-desc = Grenade that creates a small but devastating explosion.
diff --git a/Resources/Prototypes/Catalog/uplink_catalog.yml b/Resources/Prototypes/Catalog/uplink_catalog.yml
index c8ab68bfc3..9b5ae9e8b1 100644
--- a/Resources/Prototypes/Catalog/uplink_catalog.yml
+++ b/Resources/Prototypes/Catalog/uplink_catalog.yml
@@ -75,6 +75,16 @@
categories:
- UplinkWeapons
+- type: listing
+ id: UplinkGlovesNorthStar
+ name: uplink-gloves-north-star-name
+ description: uplink-gloves-north-star-desc
+ productEntity: ClothingHandsGlovesNorthStar
+ cost:
+ Telecrystal: 8
+ categories:
+ - UplinkWeapons
+
# Explosives
- type: listing
diff --git a/Resources/Prototypes/Entities/Clothing/Hands/gloves.yml b/Resources/Prototypes/Entities/Clothing/Hands/gloves.yml
index a738bb5cab..e401c397aa 100644
--- a/Resources/Prototypes/Entities/Clothing/Hands/gloves.yml
+++ b/Resources/Prototypes/Entities/Clothing/Hands/gloves.yml
@@ -293,6 +293,40 @@
components:
- type: Unremoveable
+- type: entity
+ parent: ClothingHandsBase
+ id: ClothingHandsGlovesNorthStar
+ name: gloves of the north star
+ description: These gloves allow you to punch incredibly fast
+ components:
+ - type: Sprite
+ sprite: Clothing/Hands/Gloves/northstar.rsi
+ - type: Clothing
+ sprite: Clothing/Hands/Gloves/northstar.rsi
+ - type: MeleeWeapon
+ attackRate: 4
+ damage:
+ types:
+ Blunt: 8
+ soundHit:
+ collection: Punch
+ animation: WeaponArcFist
+ - type: Fiber
+ fiberMaterial: fibers-leather
+ fiberColor: fibers-blue
+ - type: FingerprintMask
+ - type: MeleeSpeech
+ - type: ActivatableUI
+ key: enum.MeleeSpeechUiKey.Key
+ closeOnHandDeselect: false
+ rightClickOnly: true
+ - type: UserInterface
+ interfaces:
+ - key: enum.MeleeSpeechUiKey.Key
+ type: MeleeSpeechBoundUserInterface
+ - type: StaticPrice
+ price: 0
+
- type: entity
parent: ClothingHandsBase
id: ForensicGloves
@@ -304,3 +338,4 @@
- type: Clothing
sprite: Clothing/Hands/Gloves/forensic.rsi
- type: FingerprintMask
+
diff --git a/Resources/Textures/Clothing/Hands/Gloves/northstar.rsi/equipped-HAND.png b/Resources/Textures/Clothing/Hands/Gloves/northstar.rsi/equipped-HAND.png
new file mode 100644
index 0000000000000000000000000000000000000000..79bdc9ce46a417184f720e45d250062664fcff04
GIT binary patch
literal 434
zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I1|(Ny7TyC=jKx9jP7LeL$-D$|SkfJR9T^xl
z_H+M9WCij$3p^r=85sBugD~Uq{1quc4ep*Ujv*CsZ*ML1W^oib{;~a`i@@Q|jt#D7
z#BMG)s=}dtLP_Eech2^^1rM8QZ?pbqp8a%7luq{z@rlj4N@5#lxZN{o*LZ%TN=acNDQIFXr6mRr!8P0-;@(0?PK
zcE*w*zhDN3XE)M-oXMUpjv*GkZ~IRRH7oEi82-o-;P~jurt$cj0;KUn0
zhGe-qKlMA64B6FtB^sLR=3H5H`_GEEH}-}$MgHlw<(V#5zMl1w`p4_$2|MKzrd`~b
zYRTHs`@PXpL?YScV}wm0$2!hM4P~E?)tgnk&ziJ}<*0PhNx}J24(BS5zW3PF$k*?~
kpm}xTjLY`XfBW|^e%Z;!!qfIa3FtfqPgg&ebxsLQ0Mlx6I{*Lx
literal 0
HcmV?d00001
diff --git a/Resources/Textures/Clothing/Hands/Gloves/northstar.rsi/inhand-left.png b/Resources/Textures/Clothing/Hands/Gloves/northstar.rsi/inhand-left.png
new file mode 100644
index 0000000000000000000000000000000000000000..01f8ee66a934b31210dea7cd808913a97e1172d7
GIT binary patch
literal 933
zcmV;W16urvP)Px#1ZP1_K>z@;j|==^1poj532;bRa{vGi!vFvd!vV){sAK>D13F1WK~#8N?U`Lj
zQ(+j#pQ9;bYHq2ktc{5mNt19HW*B`SnotWAyvU%dVAyRJ1zpswH$fja-UjV97!^f?
zHw#l@Zkj>srgTIUXx2Eoxp{h@w|6mgiyhyy?8x(j!+FogUiSRokHLOG5ClOG1VIo4
zK@bE%5R!PVX#6mUP$=XP&61#qvoWy3ov9Sm+U&5fqb%`xe56J^(Z$$UXv$`*YV&%%
z#(uv%l!>!Etax`a3HF`U(ACuf!-JjGP2D#(H4_{Tds`$D5myBiRGZS!VJ9?CI0$GZo-y
za6r$Qb~w=Dfa&lYM57--O{RGf;cz%0-Y$y%{(c)<`vK4STi{}|3X8|SOMzSftav=R
z_qyQt$yPYj+6b>g?_uK2TSzP~!|m%wU~+O26h*nf-`9cv=A)t9V4co7@x)l9XF!Ge
z6&iNip}DyM9tI|0d}10tF3iKdk+Xan;}MU?pX=Jq3j|vVqynh?F$ZOtRe1U00X%&Y
zf!C2ReEJ>-`0`8{7#QHwm>qY0K3|`zs`tgmiXvaIg$M?NO`@qAshzaadXSHl#p-}`
zIti+!mKV<-{v8Z{?RRq{*sr3Lvt4ctx_d71U>8@G{`9SB?6IQcZi0A!Q=6jnPf0ce
zB&EKS?hla&RyRg;TFwp}%}tF!AxaVKmLRb{FM)78-4|YzSrwfZOJosd;Xn(L$q*
zMk_6YDFQ&djFuT~b2J*`_8BcSN>h}l_3oh!v!GZPX^H^QE~8~e+lPx#1ZP1_K>z@;j|==^1poj532;bRa{vGi!vFvd!vV){sAK>D0|rS%K~#8N?V3$!
z6G0e;-?XWgShTT8)Jj514;B-oTB((aKa^HM6nf~v7CZ?{y?F4T;6blm1kp>bLUR?0
z2Sucph_*<6S|b=Q(&iv4N@z)wXuIyWJ1N~}Ya60CTfYaEnVp$kX5QUQAWy(B48t%C
z!!QiPFbujq
zpU>SXPAjkspsnwgIy%(T)Z5zu_s%8+i$&XnaQN7DW1gW=HJwhY-QC^DWHLFu%>v5+
zN?#T*lbA&yxEm)=cfsA#j6ksfv=2!iLjTz=J%oVv&_WmQ&|VN792{&G-4&Puh{xkm
zN-bafiB#$XrsK0X(Bac>>ht>GS!w|Go|8HRzrV#aU*-1WVbNuYDFBDVacOF53ioav
z#lqquCf~fp%h-Dy3b*3KsW5{30>(gzL#TGXrU0_p>@)hz(DC5z`P|2Eb9gm5jj`w?
z+S|SG?s20b|5=PS7#|;R6IChLXufN4h;oHUBywLXJc^=>=nYzW?#5l{={$lL&mUEyRm^wOi`eEmxbl>xUcBH>
z%$F{zH>$Qp`Uh1rvTefug026Q8HQmPhG7_nVHk#CWk6<`3^SQ#F;r?S15j1f)Sl1hABw7BTD61BD;Zcav1DY)B$H7lvrLAW
zOtZK`YSw!L)YZaaU|`^ksOpe$CG$!KmP{-eSu)9Fl*@LROtTm+HNV@fsjs}5QBccN
zA?N0B)N38f=DcJ&5>qC=k0_Wrksx{{i3^wWcbwO6HSG00000NkvXX
Hu0mjf+Vz%a
literal 0
HcmV?d00001
diff --git a/Resources/Textures/Clothing/Hands/Gloves/northstar.rsi/meta.json b/Resources/Textures/Clothing/Hands/Gloves/northstar.rsi/meta.json
new file mode 100644
index 0000000000..f2957ffbb2
--- /dev/null
+++ b/Resources/Textures/Clothing/Hands/Gloves/northstar.rsi/meta.json
@@ -0,0 +1,26 @@
+{
+ "version": 1,
+ "license": "CC-BY-SA-3.0",
+ "copyright": "Taken from tgstation at https://github.com/tgstation/tgstation/pull/37864/commits/efdef3f1f997d1c0575c36cd31a5db575d1df0ca#diff-a4eb7c89f7231f0aaf0c2f69d730dea56383019f2aa5c6a1d91a82c781b528e6. Modified by hercoyote23 (github) for SS14",
+ "size": {
+ "x": 32,
+ "y": 32
+ },
+ "states": [
+ {
+ "name": "icon"
+ },
+ {
+ "name": "equipped-HAND",
+ "directions": 4
+ },
+ {
+ "name": "inhand-left",
+ "directions": 4
+ },
+ {
+ "name": "inhand-right",
+ "directions": 4
+ }
+ ]
+}