]> git.smokeofanarchy.ru Git - space-station-14.git/commitdiff
Arcade machine improvements (#24200)
authorTayrtahn <tayrtahn@gmail.com>
Thu, 28 Mar 2024 06:28:45 +0000 (02:28 -0400)
committerGitHub <noreply@github.com>
Thu, 28 Mar 2024 06:28:45 +0000 (17:28 +1100)
* Give 'em something to talk about

* Wire panel visuals

* Wire graphics tweak

* More ads and thanks

* More ads for a noisy arcade

* New screen for space villain machines

* Implement EmitSoundIntervalComponent and a bunch of arcade noises

* Require power for sounds

* Allow earlier startup intervals

* Orange glow

* Audio attributions

* Include the PR link

* Replace EmitSoundInterval with expanded SpamEmitSound

* Remove pacman-themed arcade sounds

* Documentation good.

* Updated methods to use Entity<T>

* Refactored SpamEmitSound to get rid of accumulator and chance.

* Fixed prewarm logic

* Moved stuff to Shared

* Fix outdated YAML

* Better prediction, auto pause handling

* Make enable/disable reset the timer instead of trying to save it.

35 files changed:
Content.Server/Arcade/BlockGame/BlockGameArcadeComponent.cs
Content.Server/Arcade/BlockGame/BlockGameArcadeSystem.cs
Content.Server/Arcade/SpaceVillainGame/SpaceVillainArcadeComponent.cs
Content.Server/Arcade/SpaceVillainGame/SpaceVillainArcadeSystem.cs
Content.Server/Bed/Sleep/SleepingSystem.cs
Content.Server/Sound/Components/SpamEmitSoundComponent.cs [deleted file]
Content.Server/Sound/EmitSoundSystem.cs
Content.Server/Sound/SpamEmitSoundRequirePowerSystem.cs [new file with mode: 0644]
Content.Shared/Bed/Sleep/SleepEmitSoundComponent.cs
Content.Shared/Sound/Components/SpamEmitSoundComponent.cs [new file with mode: 0644]
Content.Shared/Sound/Components/SpamEmitSoundRequirePowerComponent.cs [new file with mode: 0644]
Content.Shared/Sound/SharedEmitSoundSystem.cs
Content.Shared/Sound/SharedSpamEmitSoundRequirePowerSystem.cs [new file with mode: 0644]
Resources/Audio/Machines/Arcade/attributions.yml [new file with mode: 0644]
Resources/Audio/Machines/Arcade/hahaha.ogg [new file with mode: 0644]
Resources/Audio/Machines/Arcade/pew_pew.ogg [new file with mode: 0644]
Resources/Audio/Machines/Arcade/sting_01.ogg [new file with mode: 0644]
Resources/Audio/Machines/Arcade/sting_02.ogg [new file with mode: 0644]
Resources/Audio/Machines/Arcade/sting_03.ogg [new file with mode: 0644]
Resources/Audio/Machines/Arcade/sting_04.ogg [new file with mode: 0644]
Resources/Audio/Machines/Arcade/sting_05.ogg [new file with mode: 0644]
Resources/Audio/Machines/Arcade/sting_06.ogg [new file with mode: 0644]
Resources/Locale/en-US/advertisements/arcade/blockgame.ftl [new file with mode: 0644]
Resources/Locale/en-US/advertisements/arcade/spacevillain.ftl [new file with mode: 0644]
Resources/Prototypes/Catalog/Arcade/Advertisements/blockgame.yml [new file with mode: 0644]
Resources/Prototypes/Catalog/Arcade/Advertisements/spacevillain.yml [new file with mode: 0644]
Resources/Prototypes/Entities/Structures/Machines/Computers/arcades.yml
Resources/Prototypes/Roles/Jobs/Civilian/clown.yml
Resources/Prototypes/SoundCollections/arcade.yml [new file with mode: 0644]
Resources/Prototypes/Wires/layouts.yml
Resources/Textures/Structures/Machines/arcade.rsi/meta.json
Resources/Textures/Structures/Machines/arcade.rsi/panel.png [new file with mode: 0644]
Resources/Textures/Structures/Machines/arcade.rsi/screen_blockgame.png [moved from Resources/Textures/Structures/Machines/arcade.rsi/blockgame.png with 100% similarity]
Resources/Textures/Structures/Machines/arcade.rsi/screen_invaders.png [moved from Resources/Textures/Structures/Machines/arcade.rsi/invaders.png with 100% similarity]
Resources/Textures/Structures/Machines/arcade.rsi/screen_spacevillain.png [new file with mode: 0644]

index 5613d9154441a5908b61317176be1f8aba3e6e2b..e2acec52a3a337b6a940ae3dd6c9cc25b5e1baa1 100644 (file)
@@ -19,4 +19,9 @@ public sealed partial class BlockGameArcadeComponent : Component
     /// The players currently viewing (but not playing) the active session of NT-BG.
     /// </summary>
     public readonly List<ICommonSession> Spectators = new();
+
+    /// <summary>
+    /// Whether the game machine should thank (or otherwise talk to) the player when they leave
+    /// </summary>
+    public bool ShouldSayThankYou;
 }
index 34a5689fd154d6e5bc5be2c2ce545df518616677..0d9487dab85131cada2e65f570297c62ad32853b 100644 (file)
@@ -1,5 +1,6 @@
 using Content.Server.Power.Components;
 using Content.Shared.UserInterface;
+using Content.Server.Advertise;
 using Content.Shared.Arcade;
 using Robust.Server.GameObjects;
 using Robust.Shared.Player;
@@ -9,6 +10,7 @@ namespace Content.Server.Arcade.BlockGame;
 public sealed class BlockGameArcadeSystem : EntitySystem
 {
     [Dependency] private readonly UserInterfaceSystem _uiSystem = default!;
+    [Dependency] private readonly AdvertiseSystem _advertise = default!;
 
     public override void Initialize()
     {
@@ -89,7 +91,15 @@ public sealed class BlockGameArcadeSystem : EntitySystem
             UpdatePlayerStatus(uid, component.Player, blockGame: component);
         }
         else
+        {
+            // Everybody's gone
             component.Player = null;
+            if (component.ShouldSayThankYou && TryComp<AdvertiseComponent>(uid, out var advertise))
+            {
+                _advertise.SayThankYou(uid, advertise);
+                component.ShouldSayThankYou = false;
+            }
+        }
 
         UpdatePlayerStatus(uid, temp, blockGame: component);
     }
@@ -103,6 +113,7 @@ public sealed class BlockGameArcadeSystem : EntitySystem
             _uiSystem.CloseAll(bui);
         component.Player = null;
         component.Spectators.Clear();
+        component.ShouldSayThankYou = false;
     }
 
     private void OnPlayerAction(EntityUid uid, BlockGameArcadeComponent component, BlockGameMessages.BlockGamePlayerActionMessage msg)
@@ -122,6 +133,8 @@ public sealed class BlockGameArcadeSystem : EntitySystem
             return;
         }
 
+        component.ShouldSayThankYou = true;
+
         component.Game.ProcessInput(msg.PlayerAction);
     }
 }
index e93fcc6e8f1957efdd8430391530646938720487..c3a8877393e44cbdc5415b2055d10812e6c2430b 100644 (file)
@@ -110,4 +110,9 @@ public sealed partial class SpaceVillainArcadeComponent : SharedSpaceVillainArca
     /// </summary>
     [ViewVariables(VVAccess.ReadWrite)]
     public int RewardAmount = 0;
+
+    /// <summary>
+    /// Whether the game machine should thank (or otherwise talk to) the player when they leave
+    /// </summary>
+    public bool ShouldSayThankYou;
 }
index d97c94fd9925e8583387763579213b3089e3f67a..24fa6e32d1980b4ae8086f625feb4618b7c945b0 100644 (file)
@@ -1,5 +1,6 @@
 using Content.Server.Power.Components;
 using Content.Shared.UserInterface;
+using Content.Server.Advertise;
 using static Content.Shared.Arcade.SharedSpaceVillainArcadeComponent;
 using Robust.Server.GameObjects;
 using Robust.Shared.Audio;
@@ -13,6 +14,7 @@ public sealed partial class SpaceVillainArcadeSystem : EntitySystem
     [Dependency] private readonly IRobustRandom _random = default!;
     [Dependency] private readonly SharedAudioSystem _audioSystem = default!;
     [Dependency] private readonly UserInterfaceSystem _uiSystem = default!;
+    [Dependency] private readonly AdvertiseSystem _advertise = default!;
 
     public override void Initialize()
     {
@@ -22,6 +24,7 @@ public sealed partial class SpaceVillainArcadeSystem : EntitySystem
         SubscribeLocalEvent<SpaceVillainArcadeComponent, AfterActivatableUIOpenEvent>(OnAfterUIOpenSV);
         SubscribeLocalEvent<SpaceVillainArcadeComponent, SpaceVillainArcadePlayerActionMessage>(OnSVPlayerAction);
         SubscribeLocalEvent<SpaceVillainArcadeComponent, PowerChangedEvent>(OnSVillainPower);
+        SubscribeLocalEvent<SpaceVillainArcadeComponent, BoundUIClosedEvent>(OnBoundUIClosed);
     }
 
     /// <summary>
@@ -79,6 +82,7 @@ public sealed partial class SpaceVillainArcadeSystem : EntitySystem
             case PlayerAction.Heal:
             case PlayerAction.Recharge:
                 component.Game.ExecutePlayerAction(uid, msg.PlayerAction, component);
+                component.ShouldSayThankYou = true; // Any sort of gameplay action counts
                 break;
             case PlayerAction.NewGame:
                 _audioSystem.PlayPvs(component.NewGameSound, uid, AudioParams.Default.WithVolume(-4f));
@@ -106,5 +110,19 @@ public sealed partial class SpaceVillainArcadeSystem : EntitySystem
 
         if (_uiSystem.TryGetUi(uid, SpaceVillainArcadeUiKey.Key, out var bui))
             _uiSystem.CloseAll(bui);
+
+        component.ShouldSayThankYou = false;
+    }
+
+    private void OnBoundUIClosed(Entity<SpaceVillainArcadeComponent> ent, ref BoundUIClosedEvent args)
+    {
+        if (args.UiKey is not SpaceVillainArcadeUiKey || (SpaceVillainArcadeUiKey) args.UiKey != SpaceVillainArcadeUiKey.Key)
+            return;
+
+        if (ent.Comp.ShouldSayThankYou && TryComp<AdvertiseComponent>(ent.Owner, out var advertise))
+        {
+            _advertise.SayThankYou(ent.Owner, advertise);
+            ent.Comp.ShouldSayThankYou = false;
+        }
     }
 }
index b4972544338598ae1b01303f226b6c648c0dfc62..5e4f0eddb526cead253d37b1f0b7d43c9b47cb08 100644 (file)
@@ -1,5 +1,6 @@
 using Content.Server.Popups;
-using Content.Server.Sound.Components;
+using Content.Server.Sound;
+using Content.Shared.Sound.Components;
 using Content.Shared.Actions;
 using Content.Shared.Audio;
 using Content.Shared.Bed.Sleep;
@@ -30,6 +31,7 @@ namespace Content.Server.Bed.Sleep
         [Dependency] private readonly PopupSystem _popupSystem = default!;
         [Dependency] private readonly SharedAudioSystem _audio = default!;
         [Dependency] private readonly StatusEffectsSystem _statusEffectsSystem = default!;
+        [Dependency] private readonly EmitSoundSystem _emitSound = default!;
 
         [ValidatePrototypeId<EntityPrototype>] public const string SleepActionId = "ActionSleep";
 
@@ -71,8 +73,8 @@ namespace Content.Server.Bed.Sleep
                     {
                         emitSound.Sound = sleepSound.Snore;
                     }
-                    emitSound.PlayChance = sleepSound.Chance;
-                    emitSound.RollInterval = sleepSound.Interval;
+                    emitSound.MinInterval = sleepSound.Interval;
+                    emitSound.MaxInterval = sleepSound.MaxInterval;
                     emitSound.PopUp = sleepSound.PopUp;
                 }
 
@@ -128,7 +130,7 @@ namespace Content.Server.Bed.Sleep
                 return;
             }
             if (TryComp<SpamEmitSoundComponent>(uid, out var spam))
-                spam.Enabled = args.NewMobState == MobState.Alive;
+                _emitSound.SetEnabled((uid, spam), args.NewMobState == MobState.Alive);
         }
 
         private void AddWakeVerb(EntityUid uid, SleepingComponent component, GetVerbsEvent<AlternativeVerb> args)
diff --git a/Content.Server/Sound/Components/SpamEmitSoundComponent.cs b/Content.Server/Sound/Components/SpamEmitSoundComponent.cs
deleted file mode 100644 (file)
index d17bbb9..0000000
+++ /dev/null
@@ -1,27 +0,0 @@
-using Content.Shared.Sound.Components;
-
-namespace Content.Server.Sound.Components
-{
-    /// <summary>
-    /// Rolls to play a sound every few seconds.
-    /// </summary>
-    [RegisterComponent]
-    public sealed partial class SpamEmitSoundComponent : BaseEmitSoundComponent
-    {
-        [DataField("accumulator")]
-        public float Accumulator = 0f;
-
-        [DataField("rollInterval")]
-        public float RollInterval = 2f;
-
-        [DataField("playChance")]
-        public float PlayChance = 0.5f;
-
-        // Always Pvs.
-        [DataField("popUp")]
-        public string? PopUp;
-
-        [DataField("enabled")]
-        public bool Enabled = true;
-    }
-}
index 059800c3f9d7b8c1966427d2ab217c6af7667406..5b9620990eb72f738035f9c07a121604b0010f5a 100644 (file)
@@ -2,12 +2,17 @@ using Content.Server.Explosion.EntitySystems;
 using Content.Server.Sound.Components;
 using Content.Shared.UserInterface;
 using Content.Shared.Sound;
-using Robust.Shared.Random;
+using Content.Shared.Sound.Components;
+using Robust.Shared.Timing;
+using Robust.Shared.Network;
 
 namespace Content.Server.Sound;
 
 public sealed class EmitSoundSystem : SharedEmitSoundSystem
 {
+    [Dependency] private readonly IGameTiming _timing = default!;
+    [Dependency] private readonly INetManager _net = default!;
+
     public override void Update(float frameTime)
     {
         base.Update(frameTime);
@@ -18,18 +23,13 @@ public sealed class EmitSoundSystem : SharedEmitSoundSystem
             if (!soundSpammer.Enabled)
                 continue;
 
-            soundSpammer.Accumulator += frameTime;
-            if (soundSpammer.Accumulator < soundSpammer.RollInterval)
-            {
-                continue;
-            }
-            soundSpammer.Accumulator -= soundSpammer.RollInterval;
-
-            if (Random.Prob(soundSpammer.PlayChance))
+            if (_timing.CurTime >= soundSpammer.NextSound)
             {
                 if (soundSpammer.PopUp != null)
                     Popup.PopupEntity(Loc.GetString(soundSpammer.PopUp), uid);
                 TryEmitSound(uid, soundSpammer, predict: false);
+
+                SpamEmitSoundReset((uid, soundSpammer));
             }
         }
     }
@@ -40,6 +40,8 @@ public sealed class EmitSoundSystem : SharedEmitSoundSystem
 
         SubscribeLocalEvent<EmitSoundOnTriggerComponent, TriggerEvent>(HandleEmitSoundOnTrigger);
         SubscribeLocalEvent<EmitSoundOnUIOpenComponent, AfterActivatableUIOpenEvent>(HandleEmitSoundOnUIOpen);
+
+        SubscribeLocalEvent<SpamEmitSoundComponent, MapInitEvent>(HandleSpamEmitSoundMapInit);
     }
 
     private void HandleEmitSoundOnUIOpen(EntityUid uid, EmitSoundOnUIOpenComponent component, AfterActivatableUIOpenEvent args)
@@ -52,4 +54,39 @@ public sealed class EmitSoundSystem : SharedEmitSoundSystem
         TryEmitSound(uid, component, args.User, false);
         args.Handled = true;
     }
+
+    private void HandleSpamEmitSoundMapInit(Entity<SpamEmitSoundComponent> entity, ref MapInitEvent args)
+    {
+        SpamEmitSoundReset(entity);
+
+        // Prewarm so multiple entities have more variation.
+        entity.Comp.NextSound -= Random.Next(entity.Comp.MaxInterval);
+        Dirty(entity);
+    }
+
+    private void SpamEmitSoundReset(Entity<SpamEmitSoundComponent> entity)
+    {
+        if (_net.IsClient)
+            return;
+
+        entity.Comp.NextSound = _timing.CurTime + ((entity.Comp.MinInterval < entity.Comp.MaxInterval)
+            ? Random.Next(entity.Comp.MinInterval, entity.Comp.MaxInterval)
+            : entity.Comp.MaxInterval);
+
+        Dirty(entity);
+    }
+
+    public override void SetEnabled(Entity<SpamEmitSoundComponent?> entity, bool enabled)
+    {
+        if (!Resolve(entity, ref entity.Comp, false))
+            return;
+
+        if (entity.Comp.Enabled == enabled)
+            return;
+
+        entity.Comp.Enabled = enabled;
+
+        if (enabled)
+            SpamEmitSoundReset((entity, entity.Comp));
+    }
 }
diff --git a/Content.Server/Sound/SpamEmitSoundRequirePowerSystem.cs b/Content.Server/Sound/SpamEmitSoundRequirePowerSystem.cs
new file mode 100644 (file)
index 0000000..9cc8506
--- /dev/null
@@ -0,0 +1,33 @@
+using Content.Server.Power.Components;
+using Content.Server.Power.EntitySystems;
+using Content.Shared.Sound;
+using Content.Shared.Sound.Components;
+
+namespace Content.Server.Sound;
+
+public sealed partial class SpamEmitSoundRequirePowerSystem : SharedSpamEmitSoundRequirePowerSystem
+{
+    public override void Initialize()
+    {
+        base.Initialize();
+
+        SubscribeLocalEvent<SpamEmitSoundRequirePowerComponent, PowerChangedEvent>(OnPowerChanged);
+        SubscribeLocalEvent<SpamEmitSoundRequirePowerComponent, PowerNetBatterySupplyEvent>(OnPowerSupply);
+    }
+
+    private void OnPowerChanged(Entity<SpamEmitSoundRequirePowerComponent> entity, ref PowerChangedEvent args)
+    {
+        if (TryComp<SpamEmitSoundComponent>(entity.Owner, out var comp))
+        {
+            EmitSound.SetEnabled((entity, comp), args.Powered);
+        }
+    }
+
+    private void OnPowerSupply(Entity<SpamEmitSoundRequirePowerComponent> entity, ref PowerNetBatterySupplyEvent args)
+    {
+        if (TryComp<SpamEmitSoundComponent>(entity.Owner, out var comp))
+        {
+            EmitSound.SetEnabled((entity, comp), args.Supply);
+        }
+    }
+}
index 6313f633f21677a8f9b1ee5cd843a23b7911e753..9250a330777349d0e1c5a953bbeeca56ec2507fa 100644 (file)
@@ -12,16 +12,16 @@ public sealed partial class SleepEmitSoundComponent : Component
     public SoundSpecifier Snore = new SoundCollectionSpecifier("Snores", AudioParams.Default.WithVariation(0.2f));
 
     /// <summary>
-    /// Interval between snore attempts in seconds
+    /// Minimum interval between snore attempts in seconds
     /// </summary>
     [DataField, ViewVariables(VVAccess.ReadWrite)]
-    public float Interval = 5f;
+    public TimeSpan Interval = TimeSpan.FromSeconds(5);
 
     /// <summary>
-    /// Chance for snore attempt to succeed
+    /// Maximum interval between snore attempts in seconds
     /// </summary>
     [DataField, ViewVariables(VVAccess.ReadWrite)]
-    public float Chance = 0.33f;
+    public TimeSpan MaxInterval = TimeSpan.FromSeconds(15);
 
     /// <summary>
     /// Popup for snore (e.g. Zzz...)
diff --git a/Content.Shared/Sound/Components/SpamEmitSoundComponent.cs b/Content.Shared/Sound/Components/SpamEmitSoundComponent.cs
new file mode 100644 (file)
index 0000000..149728a
--- /dev/null
@@ -0,0 +1,44 @@
+using Robust.Shared.GameStates;
+
+namespace Content.Shared.Sound.Components;
+
+/// <summary>
+/// Repeatedly plays a sound with a randomized delay.
+/// </summary>
+[RegisterComponent, NetworkedComponent]
+[AutoGenerateComponentState, AutoGenerateComponentPause]
+public sealed partial class SpamEmitSoundComponent : BaseEmitSoundComponent
+{
+    /// <summary>
+    /// The time at which the next sound will play.
+    /// </summary>
+    [DataField, AutoPausedField, AutoNetworkedField]
+    public TimeSpan NextSound;
+
+    /// <summary>
+    /// The minimum time in seconds between playing the sound.
+    /// </summary>
+    [DataField]
+    public TimeSpan MinInterval = TimeSpan.FromSeconds(2);
+
+    /// <summary>
+    /// The maximum time in seconds between playing the sound.
+    /// </summary>
+    [DataField]
+    public TimeSpan MaxInterval = TimeSpan.FromSeconds(2);
+
+    // Always Pvs.
+    /// <summary>
+    /// Content of a popup message to display whenever the sound plays.
+    /// </summary>
+    [DataField]
+    public LocId? PopUp;
+
+    /// <summary>
+    /// Whether the timer is currently running and sounds are being played.
+    /// Do not set this directly, use <see cref="EmitSoundSystem.SetEnabled"/>
+    /// </summary>
+    [DataField, AutoNetworkedField]
+    [Access(typeof(SharedEmitSoundSystem))]
+    public bool Enabled = true;
+}
diff --git a/Content.Shared/Sound/Components/SpamEmitSoundRequirePowerComponent.cs b/Content.Shared/Sound/Components/SpamEmitSoundRequirePowerComponent.cs
new file mode 100644 (file)
index 0000000..b0547ea
--- /dev/null
@@ -0,0 +1,10 @@
+namespace Content.Shared.Sound.Components;
+
+/// <summary>
+/// Enables or disables an SpamEmitSound component depending
+/// on the powered state of the entity.
+/// </summary>
+[RegisterComponent]
+public sealed partial class SpamEmitSoundRequirePowerComponent : Component
+{
+}
index 56a51744acfde94e4da749d36dff2e02e43049b3..cd7828fc6b35f579933b42e351a37987c0bd14c0 100644 (file)
@@ -24,7 +24,7 @@ namespace Content.Shared.Sound;
 [UsedImplicitly]
 public abstract class SharedEmitSoundSystem : EntitySystem
 {
-    [Dependency] private readonly IGameTiming _timing = default!;
+    [Dependency] protected readonly IGameTiming Timing = default!;
     [Dependency] private readonly INetManager _netMan = default!;
     [Dependency] private readonly ITileDefinitionManager _tileDefMan = default!;
     [Dependency] protected readonly IRobustRandom Random = default!;
@@ -124,7 +124,7 @@ public abstract class SharedEmitSoundSystem : EntitySystem
             !args.OtherFixture.Hard ||
             !TryComp<PhysicsComponent>(uid, out var physics) ||
             physics.LinearVelocity.Length() < component.MinimumVelocity ||
-            _timing.CurTime < component.NextSound ||
+            Timing.CurTime < component.NextSound ||
             MetaData(uid).EntityPaused)
         {
             return;
@@ -136,7 +136,7 @@ public abstract class SharedEmitSoundSystem : EntitySystem
 
         var fraction = MathF.Min(1f, (physics.LinearVelocity.Length() - component.MinimumVelocity) / MaxVolumeVelocity);
         var volume = MinVolume + (MaxVolume - MinVolume) * fraction;
-        component.NextSound = _timing.CurTime + EmitSoundOnCollideComponent.CollideCooldown;
+        component.NextSound = Timing.CurTime + EmitSoundOnCollideComponent.CollideCooldown;
         var sound = component.Sound;
 
         if (_netMan.IsServer && sound != null)
@@ -144,4 +144,8 @@ public abstract class SharedEmitSoundSystem : EntitySystem
             _audioSystem.PlayPvs(_audioSystem.GetSound(sound), uid, AudioParams.Default.WithVolume(volume));
         }
     }
+
+    public virtual void SetEnabled(Entity<SpamEmitSoundComponent?> entity, bool enabled)
+    {
+    }
 }
diff --git a/Content.Shared/Sound/SharedSpamEmitSoundRequirePowerSystem.cs b/Content.Shared/Sound/SharedSpamEmitSoundRequirePowerSystem.cs
new file mode 100644 (file)
index 0000000..ad44cba
--- /dev/null
@@ -0,0 +1,6 @@
+namespace Content.Shared.Sound;
+
+public abstract partial class SharedSpamEmitSoundRequirePowerSystem : EntitySystem
+{
+    [Dependency] protected readonly SharedEmitSoundSystem EmitSound = default!;
+}
diff --git a/Resources/Audio/Machines/Arcade/attributions.yml b/Resources/Audio/Machines/Arcade/attributions.yml
new file mode 100644 (file)
index 0000000..afb120b
--- /dev/null
@@ -0,0 +1,4 @@
+- files: ["hahaha.ogg", "pew_pew.ogg", "sting_*.ogg"]
+  license: "CC0-1.0"
+  copyright: "Recorded by https://github.com/Tayrtahn"
+  source: "https://github.com/space-wizards/space-station-14/pull/24200"
diff --git a/Resources/Audio/Machines/Arcade/hahaha.ogg b/Resources/Audio/Machines/Arcade/hahaha.ogg
new file mode 100644 (file)
index 0000000..8a01e5d
Binary files /dev/null and b/Resources/Audio/Machines/Arcade/hahaha.ogg differ
diff --git a/Resources/Audio/Machines/Arcade/pew_pew.ogg b/Resources/Audio/Machines/Arcade/pew_pew.ogg
new file mode 100644 (file)
index 0000000..7919ca1
Binary files /dev/null and b/Resources/Audio/Machines/Arcade/pew_pew.ogg differ
diff --git a/Resources/Audio/Machines/Arcade/sting_01.ogg b/Resources/Audio/Machines/Arcade/sting_01.ogg
new file mode 100644 (file)
index 0000000..e1b7e7f
Binary files /dev/null and b/Resources/Audio/Machines/Arcade/sting_01.ogg differ
diff --git a/Resources/Audio/Machines/Arcade/sting_02.ogg b/Resources/Audio/Machines/Arcade/sting_02.ogg
new file mode 100644 (file)
index 0000000..83651e3
Binary files /dev/null and b/Resources/Audio/Machines/Arcade/sting_02.ogg differ
diff --git a/Resources/Audio/Machines/Arcade/sting_03.ogg b/Resources/Audio/Machines/Arcade/sting_03.ogg
new file mode 100644 (file)
index 0000000..99bb725
Binary files /dev/null and b/Resources/Audio/Machines/Arcade/sting_03.ogg differ
diff --git a/Resources/Audio/Machines/Arcade/sting_04.ogg b/Resources/Audio/Machines/Arcade/sting_04.ogg
new file mode 100644 (file)
index 0000000..07d39ca
Binary files /dev/null and b/Resources/Audio/Machines/Arcade/sting_04.ogg differ
diff --git a/Resources/Audio/Machines/Arcade/sting_05.ogg b/Resources/Audio/Machines/Arcade/sting_05.ogg
new file mode 100644 (file)
index 0000000..2ebed2d
Binary files /dev/null and b/Resources/Audio/Machines/Arcade/sting_05.ogg differ
diff --git a/Resources/Audio/Machines/Arcade/sting_06.ogg b/Resources/Audio/Machines/Arcade/sting_06.ogg
new file mode 100644 (file)
index 0000000..6b369aa
Binary files /dev/null and b/Resources/Audio/Machines/Arcade/sting_06.ogg differ
diff --git a/Resources/Locale/en-US/advertisements/arcade/blockgame.ftl b/Resources/Locale/en-US/advertisements/arcade/blockgame.ftl
new file mode 100644 (file)
index 0000000..ec755ab
--- /dev/null
@@ -0,0 +1,26 @@
+advertisement-block-game-1 = Legally distinct!
+advertisement-block-game-2 = What the hell is a T-spin?
+advertisement-block-game-3 = These blocks aren't going to clear themselves!
+advertisement-block-game-4 = Beep boop! Bwoooop!
+advertisement-block-game-5 = Let's play a game!
+advertisement-block-game-6 = 6 whole colors of gameplay!
+advertisement-block-game-7 = Hot 8-bit action!
+advertisement-block-game-8 = Blocks, blocks, blocks!
+advertisement-block-game-9 = Think YOU can claim the high score?
+advertisement-block-game-10 = Nanotrasen Block Game IS what TetrISN'T!
+advertisement-block-game-11 = Now with blast processing!
+advertisement-block-game-12 = Our lawyers are standing by!
+advertisement-block-game-13 = Hallelujah, it's raining blocks!
+
+thankyou-block-game-1 = Play again soon!
+thankyou-block-game-2 = Well played!
+thankyou-block-game-3 = Just one more game?
+thankyou-block-game-4 = Stopping so soon?
+thankyou-block-game-5 = The blocks will miss you.
+thankyou-block-game-6 = Thanks for playin'!
+thankyou-block-game-7 = Come back soon!
+thankyou-block-game-8 = Beep bwooop!
+thankyou-block-game-9 = There's always time for another game!
+thankyou-block-game-10 = Don't give up now!
+thankyou-block-game-11 = There are always more blocks!
+thankyou-block-game-12 = The blocks await your return!
diff --git a/Resources/Locale/en-US/advertisements/arcade/spacevillain.ftl b/Resources/Locale/en-US/advertisements/arcade/spacevillain.ftl
new file mode 100644 (file)
index 0000000..145c380
--- /dev/null
@@ -0,0 +1,28 @@
+advertisement-space-villain-1 = Are you a bad enough dude to beat this game?
+advertisement-space-villain-2 = Beat the bad guy; win a prize!
+advertisement-space-villain-3 = FIGHT ME!
+advertisement-space-villain-4 = Space needs a hero!
+advertisement-space-villain-5 = I'm holding out for a hero!
+advertisement-space-villain-6 = Won't someone save us?
+advertisement-space-villain-7 = Mua-hah-hah-hah!
+advertisement-space-villain-8 = Spaaaaaaaace Villain!
+advertisement-space-villain-9 = No one can defeat me!
+advertisement-space-villain-10 = Tremble before me!
+advertisement-space-villain-11 = CHALLENGE ME!
+advertisement-space-villain-12 = FEAR ME!
+advertisement-space-villain-13 = Do you dare to face me in battle!?
+advertisement-space-villain-14 = Beware, I live!
+advertisement-space-villain-15 = I hunger!
+
+thankyou-space-villain-1 = And where do you think you're going, punk?
+thankyou-space-villain-2 = Is that all you've got?
+thankyou-space-villain-3 = This fight isn't over!
+thankyou-space-villain-4 = Challenge again soon!
+thankyou-space-villain-5 = Who dares to challenge me next?
+thankyou-space-villain-6 = I knew you couldn't defeat me!
+thankyou-space-villain-7 = Too much for you to handle?
+thankyou-space-villain-8 = Run, coward!
+thankyou-space-villain-9 = You never stood a chance.
+thankyou-space-villain-10 = Care for a rematch?
+thankyou-space-villain-11 = Fight me again!
+thankyou-space-villain-12 = Come back here and fight me!
diff --git a/Resources/Prototypes/Catalog/Arcade/Advertisements/blockgame.yml b/Resources/Prototypes/Catalog/Arcade/Advertisements/blockgame.yml
new file mode 100644 (file)
index 0000000..efcb893
--- /dev/null
@@ -0,0 +1,29 @@
+- type: advertisementsPack
+  id: BlockGameAds
+  advertisements:
+    - advertisement-block-game-1
+    - advertisement-block-game-2
+    - advertisement-block-game-3
+    - advertisement-block-game-4
+    - advertisement-block-game-5
+    - advertisement-block-game-6
+    - advertisement-block-game-7
+    - advertisement-block-game-8
+    - advertisement-block-game-9
+    - advertisement-block-game-10
+    - advertisement-block-game-11
+    - advertisement-block-game-12
+    - advertisement-block-game-13
+  thankyous:
+    - thankyou-block-game-1
+    - thankyou-block-game-2
+    - thankyou-block-game-3
+    - thankyou-block-game-4
+    - thankyou-block-game-5
+    - thankyou-block-game-6
+    - thankyou-block-game-7
+    - thankyou-block-game-8
+    - thankyou-block-game-9
+    - thankyou-block-game-10
+    - thankyou-block-game-11
+    - thankyou-block-game-12
diff --git a/Resources/Prototypes/Catalog/Arcade/Advertisements/spacevillain.yml b/Resources/Prototypes/Catalog/Arcade/Advertisements/spacevillain.yml
new file mode 100644 (file)
index 0000000..98063a6
--- /dev/null
@@ -0,0 +1,31 @@
+- type: advertisementsPack
+  id: SpaceVillainAds
+  advertisements:
+    - advertisement-space-villain-1
+    - advertisement-space-villain-2
+    - advertisement-space-villain-3
+    - advertisement-space-villain-4
+    - advertisement-space-villain-5
+    - advertisement-space-villain-6
+    - advertisement-space-villain-7
+    - advertisement-space-villain-8
+    - advertisement-space-villain-9
+    - advertisement-space-villain-10
+    - advertisement-space-villain-11
+    - advertisement-space-villain-12
+    - advertisement-space-villain-13
+    - advertisement-space-villain-14
+    - advertisement-space-villain-15
+  thankyous:
+    - thankyou-space-villain-1
+    - thankyou-space-villain-2
+    - thankyou-space-villain-3
+    - thankyou-space-villain-4
+    - thankyou-space-villain-5
+    - thankyou-space-villain-6
+    - thankyou-space-villain-7
+    - thankyou-space-villain-8
+    - thankyou-space-villain-9
+    - thankyou-space-villain-10
+    - thankyou-space-villain-11
+    - thankyou-space-villain-12
index 85f6dc689413d0f2531f95fc6e004e664e4b1a8f..2970e9f854d7b726fe9641a411c93fe1c1d89c75 100644 (file)
     priority: Low
   - type: ExtensionCableReceiver
   - type: PointLight
-    radius: 1.5
+    radius: 1.8
     energy: 1.6
     color: "#3db83b"
+  - type: LitOnPowered
   - type: Sprite
     sprite: Structures/Machines/arcade.rsi
     layers:
     - map: ["computerLayerBody"]
       state: arcade
     - map: ["computerLayerScreen"]
-      state: invaders
+      state: screen_invaders
+    - map: ["enum.WiresVisualLayers.MaintenancePanel"]
+      state: panel
+      visible: false
   - type: Icon
     sprite: Structures/Machines/arcade.rsi
     state: arcade
+  - type: WiresPanel
+  - type: Wires
+    layoutId: Arcade
+    boardName: wires-board-name-arcade
+  - type: WiresVisuals
+  - type: TypingIndicator
+    proto: robot
+  - type: Speech
+    speechVerb: Robotic
+    speechSounds: Vending
   - type: Anchorable
   - type: Pullable
   - type: StaticPrice
     price: 300
+  - type: SpamEmitSoundRequirePower
+  - type: SpamEmitSound
+    minInterval: 30
+    maxInterval: 90
+    sound:
+      collection: ArcadeNoise
+      params:
+        volume: -8
+        maxDistance: 10
+        variation: 0.05
 
 - type: entity
   id: SpaceVillainArcade
   name: space villain arcade
   parent: ArcadeBase
   components:
+  - type: Sprite
+    sprite: Structures/Machines/arcade.rsi
+    layers:
+    - map: ["computerLayerBody"]
+      state: arcade
+    - map: ["computerLayerScreen"]
+      state: screen_spacevillain
+    - map: ["enum.WiresVisualLayers.MaintenancePanel"]
+      state: panel
+      visible: false
+  - type: PointLight
+    color: "#e3a136"
   - type: SpaceVillainArcade
     rewardAmount: 0
     possibleRewards:
         type: WiresBoundUserInterface
   - type: Computer
     board: SpaceVillainArcadeComputerCircuitboard
+  - type: Advertise
+    pack: SpaceVillainAds
+    minWait: 60 # Arcades are noisy
+    maxWait: 240
 
 - type: entity
   id: SpaceVillainArcadeFilled
     - map: ["computerLayerBody"]
       state: arcade
     - map: ["computerLayerScreen"]
-      state: blockgame
+      state: screen_blockgame
+    - map: ["enum.WiresVisualLayers.MaintenancePanel"]
+      state: panel
+      visible: false
   - type: BlockGameArcade
   - type: ActivatableUI
     key: enum.BlockGameUiKey.Key
   - type: ActivatableUIRequiresPower
-  - type: WiresPanel
-  - type: Wires
-    layoutId: Arcade
-    boardName: wires-board-name-arcade
   - type: UserInterface
     interfaces:
       - key: enum.BlockGameUiKey.Key
         type: WiresBoundUserInterface
   - type: Computer
     board: BlockGameArcadeComputerCircuitboard
+  - type: Advertise
+    pack: BlockGameAds
+    minWait: 60 # Arcades are noisy
+    maxWait: 240
index 23c70d79cc558645b8817058c730e59e53fcc101..75c2ce352472d4e707e1d93110aa53f88f247c99 100644 (file)
@@ -22,7 +22,6 @@
     - type: SleepEmitSound
       snore: /Audio/Voice/Misc/silly_snore.ogg
       interval: 10
-      chance: 1.0
   - !type:AddImplantSpecial
     implants: [ SadTromboneImplant ]
 
diff --git a/Resources/Prototypes/SoundCollections/arcade.yml b/Resources/Prototypes/SoundCollections/arcade.yml
new file mode 100644 (file)
index 0000000..40c8a0b
--- /dev/null
@@ -0,0 +1,11 @@
+- type: soundCollection
+  id: ArcadeNoise
+  files:
+    - /Audio/Machines/Arcade/hahaha.ogg
+    - /Audio/Machines/Arcade/pew_pew.ogg
+    - /Audio/Machines/Arcade/sting_01.ogg
+    - /Audio/Machines/Arcade/sting_02.ogg
+    - /Audio/Machines/Arcade/sting_03.ogg
+    - /Audio/Machines/Arcade/sting_04.ogg
+    - /Audio/Machines/Arcade/sting_05.ogg
+    - /Audio/Machines/Arcade/sting_06.ogg
index b30e68545dfb54d15b8a271e72513b20bc6aadb4..8d6be674e809ffb473cb42554de63c70c5ee21f7 100644 (file)
@@ -87,6 +87,7 @@
   id: Arcade
   wires:
   - !type:PowerWireAction
+  - !type:SpeechWireAction
   - !type:ArcadeOverflowWireAction
   - !type:ArcadePlayerInvincibleWireAction
   - !type:ArcadeEnemyInvincibleWireAction
index 63820ec06a83f005062183f4a47167c3f4db4a88..38289e4b07c2bf4b8069535f4b600133e3046778 100644 (file)
       "directions": 4
     },
     {
-      "name": "invaders",
+        "name": "panel",
+        "directions": 4
+    },
+    {
+      "name": "screen_invaders",
       "directions": 4,
       "delays": [
         [
@@ -42,7 +46,7 @@
       ]
     },
     {
-      "name": "blockgame",
+      "name": "screen_blockgame",
       "directions": 4,
       "delays": [
         [
           4.8
         ]
       ]
+    },
+    {
+        "name": "screen_spacevillain",
+        "directions": 4,
+        "delays": [
+          [
+            1.0,
+            0.8,
+            0.2,
+            0.8,
+            0.5,
+            1.0,
+            0.1,
+            0.1,
+            0.1,
+            0.1,
+            0.1,
+            0.1,
+            0.1,
+            0.5,
+            1.0,
+            0.1,
+            0.1,
+            0.1,
+            0.1,
+            0.1,
+            0.2,
+            0.5,
+            0.1,
+            0.8,
+            1.0
+          ],
+          [
+            9.6
+          ],
+          [
+            9.6
+          ],
+          [
+            9.6
+          ]
+        ]
     }
   ]
 }
diff --git a/Resources/Textures/Structures/Machines/arcade.rsi/panel.png b/Resources/Textures/Structures/Machines/arcade.rsi/panel.png
new file mode 100644 (file)
index 0000000..fa65156
Binary files /dev/null and b/Resources/Textures/Structures/Machines/arcade.rsi/panel.png differ
diff --git a/Resources/Textures/Structures/Machines/arcade.rsi/screen_spacevillain.png b/Resources/Textures/Structures/Machines/arcade.rsi/screen_spacevillain.png
new file mode 100644 (file)
index 0000000..4935ac8
Binary files /dev/null and b/Resources/Textures/Structures/Machines/arcade.rsi/screen_spacevillain.png differ