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 + } + ] +}