]> git.smokeofanarchy.ru Git - space-station-14.git/commitdiff
Let ghosts sometimes make certain devices say creepy things (#34368)
authorTayrtahn <tayrtahn@gmail.com>
Sat, 11 Jan 2025 02:48:13 +0000 (21:48 -0500)
committerGitHub <noreply@github.com>
Sat, 11 Jan 2025 02:48:13 +0000 (03:48 +0100)
* Add SpookySpeaker component/system

* Shuffle Boo action targets before trying to activate them

* Add SpookySpeaker to vending machines

* Fix chatcode eating messages starting with "..."

* Add SpookySpeaker to recycler

* Oops

* Decrease speak probability for vending machines

* Add spooky speaker to arcade machines

Content.Server/Ghost/Components/SpookySpeakerComponent.cs [new file with mode: 0644]
Content.Server/Ghost/GhostSystem.cs
Content.Server/Ghost/SpookySpeakerSystem.cs [new file with mode: 0644]
Resources/Locale/en-US/ghost/spooky-speaker.ftl [new file with mode: 0644]
Resources/Prototypes/Datasets/spooky_speakers.yml [new file with mode: 0644]
Resources/Prototypes/Entities/Structures/Machines/Computers/arcades.yml
Resources/Prototypes/Entities/Structures/Machines/recycler.yml
Resources/Prototypes/Entities/Structures/Machines/vending_machines.yml

diff --git a/Content.Server/Ghost/Components/SpookySpeakerComponent.cs b/Content.Server/Ghost/Components/SpookySpeakerComponent.cs
new file mode 100644 (file)
index 0000000..e843793
--- /dev/null
@@ -0,0 +1,37 @@
+using Content.Shared.Dataset;
+using Robust.Shared.Prototypes;
+
+namespace Content.Server.Ghost.Components;
+
+/// <summary>
+/// Causes this entity to react to ghost player using the "Boo!" action by speaking
+/// a randomly chosen message from a specified set.
+/// </summary>
+[RegisterComponent, AutoGenerateComponentPause]
+public sealed partial class SpookySpeakerComponent : Component
+{
+    /// <summary>
+    /// ProtoId of the LocalizedDataset to use for messages.
+    /// </summary>
+    [DataField(required: true)]
+    public ProtoId<LocalizedDatasetPrototype> MessageSet;
+
+    /// <summary>
+    /// Probability that this entity will speak if activated by a Boo action.
+    /// This is so whole banks of entities don't trigger at the same time.
+    /// </summary>
+    [DataField]
+    public float SpeakChance = 0.5f;
+
+    /// <summary>
+    /// Minimum time that must pass after speaking before this entity can speak again.
+    /// </summary>
+    [DataField]
+    public TimeSpan Cooldown = TimeSpan.FromSeconds(30);
+
+    /// <summary>
+    /// Time when the cooldown will have elapsed and the entity can speak again.
+    /// </summary>
+    [DataField, AutoPausedField]
+    public TimeSpan NextSpeakTime;
+}
index 71a75ee4c6e194ba8ae604080330173d82f43cc5..25319557ae165bc76540d0dacdf355c211538884 100644 (file)
@@ -34,6 +34,7 @@ using Robust.Shared.Physics.Components;
 using Robust.Shared.Physics.Systems;
 using Robust.Shared.Player;
 using Robust.Shared.Prototypes;
+using Robust.Shared.Random;
 using Robust.Shared.Timing;
 
 namespace Content.Server.Ghost
@@ -63,6 +64,7 @@ namespace Content.Server.Ghost
         [Dependency] private readonly GameTicker _gameTicker = default!;
         [Dependency] private readonly DamageableSystem _damageable = default!;
         [Dependency] private readonly SharedPopupSystem _popup = default!;
+        [Dependency] private readonly IRobustRandom _random = default!;
 
         private EntityQuery<GhostComponent> _ghostQuery;
         private EntityQuery<PhysicsComponent> _physicsQuery;
@@ -127,7 +129,9 @@ namespace Content.Server.Ghost
             if (args.Handled)
                 return;
 
-            var entities = _lookup.GetEntitiesInRange(args.Performer, component.BooRadius);
+            var entities = _lookup.GetEntitiesInRange(args.Performer, component.BooRadius).ToList();
+            // Shuffle the possible targets so we don't favor any particular entities
+            _random.Shuffle(entities);
 
             var booCounter = 0;
             foreach (var ent in entities)
diff --git a/Content.Server/Ghost/SpookySpeakerSystem.cs b/Content.Server/Ghost/SpookySpeakerSystem.cs
new file mode 100644 (file)
index 0000000..5a83ca3
--- /dev/null
@@ -0,0 +1,51 @@
+using Content.Server.Chat.Systems;
+using Content.Server.Ghost.Components;
+using Content.Shared.Random.Helpers;
+using Robust.Shared.Prototypes;
+using Robust.Shared.Random;
+using Robust.Shared.Timing;
+
+namespace Content.Server.Ghost;
+
+public sealed class SpookySpeakerSystem : EntitySystem
+{
+    [Dependency] private readonly IPrototypeManager _proto = default!;
+    [Dependency] private readonly IRobustRandom _random = default!;
+    [Dependency] private readonly IGameTiming _timing = default!;
+    [Dependency] private readonly ChatSystem _chat = default!;
+
+    public override void Initialize()
+    {
+        base.Initialize();
+
+        SubscribeLocalEvent<SpookySpeakerComponent, GhostBooEvent>(OnGhostBoo);
+    }
+
+    private void OnGhostBoo(Entity<SpookySpeakerComponent> entity, ref GhostBooEvent args)
+    {
+        // Only activate sometimes, so groups don't all trigger together
+        if (!_random.Prob(entity.Comp.SpeakChance))
+            return;
+
+        var curTime = _timing.CurTime;
+        // Enforce a delay between messages to prevent spam
+        if (curTime < entity.Comp.NextSpeakTime)
+            return;
+
+        if (!_proto.TryIndex(entity.Comp.MessageSet, out var messages))
+            return;
+
+        // Grab a random localized message from the set
+        var message = _random.Pick(messages);
+        // Chatcode moment: messages starting with '.' are considered radio messages unless prefixed with '>'
+        // So this is a stupid trick to make the "...Oooo"-style messages work.
+        message = '>' + message;
+        // Say the message
+        _chat.TrySendInGameICMessage(entity, message, InGameICChatType.Speak, hideChat: true);
+
+        // Set the delay for the next message
+        entity.Comp.NextSpeakTime = curTime + entity.Comp.Cooldown;
+
+        args.Handled = true;
+    }
+}
diff --git a/Resources/Locale/en-US/ghost/spooky-speaker.ftl b/Resources/Locale/en-US/ghost/spooky-speaker.ftl
new file mode 100644 (file)
index 0000000..9c962ee
--- /dev/null
@@ -0,0 +1,18 @@
+spooky-speaker-generic-1 = ...ooOoooOOoooo...
+spooky-speaker-generic-2 = ...can anyone hear me...?
+spooky-speaker-generic-3 = ...join us...
+spooky-speaker-generic-4 = ...come play with us...
+spooky-speaker-generic-5 = KkkhhkhKhhkhkKk
+spooky-speaker-generic-6 = Khhggkkghkk
+spooky-speaker-generic-7 = khhkkkkKkhkkHk
+spooky-speaker-generic-8 = ...
+spooky-speaker-generic-9 = ...h-h-hello...?
+spooky-speaker-generic-10 = Bzzzt
+spooky-speaker-generic-11 = Weh
+spooky-speaker-generic-12 = TREMBLE, MORTALS!
+spooky-speaker-generic-13 = 4444444444
+spooky-speaker-generic-14 = ...I found you...
+
+spooky-speaker-recycler-1 = I HUNGER
+spooky-speaker-recycler-2 = MORE! GIVE ME MORE!
+spooky-speaker-recycler-3 = FEED ME
diff --git a/Resources/Prototypes/Datasets/spooky_speakers.yml b/Resources/Prototypes/Datasets/spooky_speakers.yml
new file mode 100644 (file)
index 0000000..a64ab0a
--- /dev/null
@@ -0,0 +1,11 @@
+- type: localizedDataset
+  id: SpookySpeakerMessagesGeneric
+  values:
+    prefix: spooky-speaker-generic-
+    count: 14
+
+- type: localizedDataset
+  id: SpookySpeakerMessagesRecycler
+  values:
+    prefix: spooky-speaker-recycler-
+    count: 3
index d7f0297101a8b7918387885b6f27f03db2a04688..d57e1c4bf83b6ee1de1f2d17dafbc80abccb38f9 100644 (file)
@@ -36,6 +36,9 @@
   - type: Speech
     speechVerb: Robotic
     speechSounds: Vending
+  - type: SpookySpeaker
+    messageSet: SpookySpeakerMessagesGeneric
+    speakChance: 0.2
   - type: Anchorable
   - type: Pullable
   - type: StaticPrice
index f62923fe2af385c446d569c1f27307762eb7d81a..2058c3c0502322b61a39a6d0433b4821ff22ff15 100644 (file)
     interactFailureString: petting-failure-generic
     interactSuccessSound:
       path: /Audio/Items/drill_hit.ogg
+  - type: SpookySpeaker
+    speakChance: 0.1
+    cooldown: 120
+    messageSet: SpookySpeakerMessagesRecycler
+  - type: Speech
+    speechVerb: Robotic
+    speechSounds: SyndieBorg
index 108693242c160dfcc69afcc6655f503a2b1aed43..f66c58f199a702b6125a1bb8b79ed5f07b9803ff 100644 (file)
@@ -78,6 +78,9 @@
   - type: Speech
     speechVerb: Robotic
     speechSounds: Vending
+  - type: SpookySpeaker
+    messageSet: SpookySpeakerMessagesGeneric
+    speakChance: 0.2
   - type: IntrinsicRadioReceiver
   - type: ActiveRadio
     channels: