Arcade machine improvements (#24200)

* 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.
This commit is contained in:
Tayrtahn
2024-03-28 02:28:45 -04:00
committed by GitHub
parent a071bc5dbf
commit b1ba6b5bb6
35 changed files with 425 additions and 57 deletions

View File

@@ -19,4 +19,9 @@ public sealed partial class BlockGameArcadeComponent : Component
/// The players currently viewing (but not playing) the active session of NT-BG. /// The players currently viewing (but not playing) the active session of NT-BG.
/// </summary> /// </summary>
public readonly List<ICommonSession> Spectators = new(); 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;
} }

View File

@@ -1,5 +1,6 @@
using Content.Server.Power.Components; using Content.Server.Power.Components;
using Content.Shared.UserInterface; using Content.Shared.UserInterface;
using Content.Server.Advertise;
using Content.Shared.Arcade; using Content.Shared.Arcade;
using Robust.Server.GameObjects; using Robust.Server.GameObjects;
using Robust.Shared.Player; using Robust.Shared.Player;
@@ -9,6 +10,7 @@ namespace Content.Server.Arcade.BlockGame;
public sealed class BlockGameArcadeSystem : EntitySystem public sealed class BlockGameArcadeSystem : EntitySystem
{ {
[Dependency] private readonly UserInterfaceSystem _uiSystem = default!; [Dependency] private readonly UserInterfaceSystem _uiSystem = default!;
[Dependency] private readonly AdvertiseSystem _advertise = default!;
public override void Initialize() public override void Initialize()
{ {
@@ -89,7 +91,15 @@ public sealed class BlockGameArcadeSystem : EntitySystem
UpdatePlayerStatus(uid, component.Player, blockGame: component); UpdatePlayerStatus(uid, component.Player, blockGame: component);
} }
else else
{
// Everybody's gone
component.Player = null; component.Player = null;
if (component.ShouldSayThankYou && TryComp<AdvertiseComponent>(uid, out var advertise))
{
_advertise.SayThankYou(uid, advertise);
component.ShouldSayThankYou = false;
}
}
UpdatePlayerStatus(uid, temp, blockGame: component); UpdatePlayerStatus(uid, temp, blockGame: component);
} }
@@ -103,6 +113,7 @@ public sealed class BlockGameArcadeSystem : EntitySystem
_uiSystem.CloseAll(bui); _uiSystem.CloseAll(bui);
component.Player = null; component.Player = null;
component.Spectators.Clear(); component.Spectators.Clear();
component.ShouldSayThankYou = false;
} }
private void OnPlayerAction(EntityUid uid, BlockGameArcadeComponent component, BlockGameMessages.BlockGamePlayerActionMessage msg) private void OnPlayerAction(EntityUid uid, BlockGameArcadeComponent component, BlockGameMessages.BlockGamePlayerActionMessage msg)
@@ -122,6 +133,8 @@ public sealed class BlockGameArcadeSystem : EntitySystem
return; return;
} }
component.ShouldSayThankYou = true;
component.Game.ProcessInput(msg.PlayerAction); component.Game.ProcessInput(msg.PlayerAction);
} }
} }

View File

@@ -110,4 +110,9 @@ public sealed partial class SpaceVillainArcadeComponent : SharedSpaceVillainArca
/// </summary> /// </summary>
[ViewVariables(VVAccess.ReadWrite)] [ViewVariables(VVAccess.ReadWrite)]
public int RewardAmount = 0; public int RewardAmount = 0;
/// <summary>
/// Whether the game machine should thank (or otherwise talk to) the player when they leave
/// </summary>
public bool ShouldSayThankYou;
} }

View File

@@ -1,5 +1,6 @@
using Content.Server.Power.Components; using Content.Server.Power.Components;
using Content.Shared.UserInterface; using Content.Shared.UserInterface;
using Content.Server.Advertise;
using static Content.Shared.Arcade.SharedSpaceVillainArcadeComponent; using static Content.Shared.Arcade.SharedSpaceVillainArcadeComponent;
using Robust.Server.GameObjects; using Robust.Server.GameObjects;
using Robust.Shared.Audio; using Robust.Shared.Audio;
@@ -13,6 +14,7 @@ public sealed partial class SpaceVillainArcadeSystem : EntitySystem
[Dependency] private readonly IRobustRandom _random = default!; [Dependency] private readonly IRobustRandom _random = default!;
[Dependency] private readonly SharedAudioSystem _audioSystem = default!; [Dependency] private readonly SharedAudioSystem _audioSystem = default!;
[Dependency] private readonly UserInterfaceSystem _uiSystem = default!; [Dependency] private readonly UserInterfaceSystem _uiSystem = default!;
[Dependency] private readonly AdvertiseSystem _advertise = default!;
public override void Initialize() public override void Initialize()
{ {
@@ -22,6 +24,7 @@ public sealed partial class SpaceVillainArcadeSystem : EntitySystem
SubscribeLocalEvent<SpaceVillainArcadeComponent, AfterActivatableUIOpenEvent>(OnAfterUIOpenSV); SubscribeLocalEvent<SpaceVillainArcadeComponent, AfterActivatableUIOpenEvent>(OnAfterUIOpenSV);
SubscribeLocalEvent<SpaceVillainArcadeComponent, SpaceVillainArcadePlayerActionMessage>(OnSVPlayerAction); SubscribeLocalEvent<SpaceVillainArcadeComponent, SpaceVillainArcadePlayerActionMessage>(OnSVPlayerAction);
SubscribeLocalEvent<SpaceVillainArcadeComponent, PowerChangedEvent>(OnSVillainPower); SubscribeLocalEvent<SpaceVillainArcadeComponent, PowerChangedEvent>(OnSVillainPower);
SubscribeLocalEvent<SpaceVillainArcadeComponent, BoundUIClosedEvent>(OnBoundUIClosed);
} }
/// <summary> /// <summary>
@@ -79,6 +82,7 @@ public sealed partial class SpaceVillainArcadeSystem : EntitySystem
case PlayerAction.Heal: case PlayerAction.Heal:
case PlayerAction.Recharge: case PlayerAction.Recharge:
component.Game.ExecutePlayerAction(uid, msg.PlayerAction, component); component.Game.ExecutePlayerAction(uid, msg.PlayerAction, component);
component.ShouldSayThankYou = true; // Any sort of gameplay action counts
break; break;
case PlayerAction.NewGame: case PlayerAction.NewGame:
_audioSystem.PlayPvs(component.NewGameSound, uid, AudioParams.Default.WithVolume(-4f)); _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)) if (_uiSystem.TryGetUi(uid, SpaceVillainArcadeUiKey.Key, out var bui))
_uiSystem.CloseAll(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;
}
} }
} }

View File

@@ -1,5 +1,6 @@
using Content.Server.Popups; 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.Actions;
using Content.Shared.Audio; using Content.Shared.Audio;
using Content.Shared.Bed.Sleep; using Content.Shared.Bed.Sleep;
@@ -30,6 +31,7 @@ namespace Content.Server.Bed.Sleep
[Dependency] private readonly PopupSystem _popupSystem = default!; [Dependency] private readonly PopupSystem _popupSystem = default!;
[Dependency] private readonly SharedAudioSystem _audio = default!; [Dependency] private readonly SharedAudioSystem _audio = default!;
[Dependency] private readonly StatusEffectsSystem _statusEffectsSystem = default!; [Dependency] private readonly StatusEffectsSystem _statusEffectsSystem = default!;
[Dependency] private readonly EmitSoundSystem _emitSound = default!;
[ValidatePrototypeId<EntityPrototype>] public const string SleepActionId = "ActionSleep"; [ValidatePrototypeId<EntityPrototype>] public const string SleepActionId = "ActionSleep";
@@ -71,8 +73,8 @@ namespace Content.Server.Bed.Sleep
{ {
emitSound.Sound = sleepSound.Snore; emitSound.Sound = sleepSound.Snore;
} }
emitSound.PlayChance = sleepSound.Chance; emitSound.MinInterval = sleepSound.Interval;
emitSound.RollInterval = sleepSound.Interval; emitSound.MaxInterval = sleepSound.MaxInterval;
emitSound.PopUp = sleepSound.PopUp; emitSound.PopUp = sleepSound.PopUp;
} }
@@ -128,7 +130,7 @@ namespace Content.Server.Bed.Sleep
return; return;
} }
if (TryComp<SpamEmitSoundComponent>(uid, out var spam)) 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) private void AddWakeVerb(EntityUid uid, SleepingComponent component, GetVerbsEvent<AlternativeVerb> args)

View File

@@ -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;
}
}

View File

@@ -2,12 +2,17 @@ using Content.Server.Explosion.EntitySystems;
using Content.Server.Sound.Components; using Content.Server.Sound.Components;
using Content.Shared.UserInterface; using Content.Shared.UserInterface;
using Content.Shared.Sound; 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; namespace Content.Server.Sound;
public sealed class EmitSoundSystem : SharedEmitSoundSystem public sealed class EmitSoundSystem : SharedEmitSoundSystem
{ {
[Dependency] private readonly IGameTiming _timing = default!;
[Dependency] private readonly INetManager _net = default!;
public override void Update(float frameTime) public override void Update(float frameTime)
{ {
base.Update(frameTime); base.Update(frameTime);
@@ -18,18 +23,13 @@ public sealed class EmitSoundSystem : SharedEmitSoundSystem
if (!soundSpammer.Enabled) if (!soundSpammer.Enabled)
continue; continue;
soundSpammer.Accumulator += frameTime; if (_timing.CurTime >= soundSpammer.NextSound)
if (soundSpammer.Accumulator < soundSpammer.RollInterval)
{
continue;
}
soundSpammer.Accumulator -= soundSpammer.RollInterval;
if (Random.Prob(soundSpammer.PlayChance))
{ {
if (soundSpammer.PopUp != null) if (soundSpammer.PopUp != null)
Popup.PopupEntity(Loc.GetString(soundSpammer.PopUp), uid); Popup.PopupEntity(Loc.GetString(soundSpammer.PopUp), uid);
TryEmitSound(uid, soundSpammer, predict: false); TryEmitSound(uid, soundSpammer, predict: false);
SpamEmitSoundReset((uid, soundSpammer));
} }
} }
} }
@@ -40,6 +40,8 @@ public sealed class EmitSoundSystem : SharedEmitSoundSystem
SubscribeLocalEvent<EmitSoundOnTriggerComponent, TriggerEvent>(HandleEmitSoundOnTrigger); SubscribeLocalEvent<EmitSoundOnTriggerComponent, TriggerEvent>(HandleEmitSoundOnTrigger);
SubscribeLocalEvent<EmitSoundOnUIOpenComponent, AfterActivatableUIOpenEvent>(HandleEmitSoundOnUIOpen); SubscribeLocalEvent<EmitSoundOnUIOpenComponent, AfterActivatableUIOpenEvent>(HandleEmitSoundOnUIOpen);
SubscribeLocalEvent<SpamEmitSoundComponent, MapInitEvent>(HandleSpamEmitSoundMapInit);
} }
private void HandleEmitSoundOnUIOpen(EntityUid uid, EmitSoundOnUIOpenComponent component, AfterActivatableUIOpenEvent args) private void HandleEmitSoundOnUIOpen(EntityUid uid, EmitSoundOnUIOpenComponent component, AfterActivatableUIOpenEvent args)
@@ -52,4 +54,39 @@ public sealed class EmitSoundSystem : SharedEmitSoundSystem
TryEmitSound(uid, component, args.User, false); TryEmitSound(uid, component, args.User, false);
args.Handled = true; 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));
}
} }

View File

@@ -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);
}
}
}

View File

@@ -12,16 +12,16 @@ public sealed partial class SleepEmitSoundComponent : Component
public SoundSpecifier Snore = new SoundCollectionSpecifier("Snores", AudioParams.Default.WithVariation(0.2f)); public SoundSpecifier Snore = new SoundCollectionSpecifier("Snores", AudioParams.Default.WithVariation(0.2f));
/// <summary> /// <summary>
/// Interval between snore attempts in seconds /// Minimum interval between snore attempts in seconds
/// </summary> /// </summary>
[DataField, ViewVariables(VVAccess.ReadWrite)] [DataField, ViewVariables(VVAccess.ReadWrite)]
public float Interval = 5f; public TimeSpan Interval = TimeSpan.FromSeconds(5);
/// <summary> /// <summary>
/// Chance for snore attempt to succeed /// Maximum interval between snore attempts in seconds
/// </summary> /// </summary>
[DataField, ViewVariables(VVAccess.ReadWrite)] [DataField, ViewVariables(VVAccess.ReadWrite)]
public float Chance = 0.33f; public TimeSpan MaxInterval = TimeSpan.FromSeconds(15);
/// <summary> /// <summary>
/// Popup for snore (e.g. Zzz...) /// Popup for snore (e.g. Zzz...)

View File

@@ -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;
}

View File

@@ -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
{
}

View File

@@ -24,7 +24,7 @@ namespace Content.Shared.Sound;
[UsedImplicitly] [UsedImplicitly]
public abstract class SharedEmitSoundSystem : EntitySystem 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 INetManager _netMan = default!;
[Dependency] private readonly ITileDefinitionManager _tileDefMan = default!; [Dependency] private readonly ITileDefinitionManager _tileDefMan = default!;
[Dependency] protected readonly IRobustRandom Random = default!; [Dependency] protected readonly IRobustRandom Random = default!;
@@ -124,7 +124,7 @@ public abstract class SharedEmitSoundSystem : EntitySystem
!args.OtherFixture.Hard || !args.OtherFixture.Hard ||
!TryComp<PhysicsComponent>(uid, out var physics) || !TryComp<PhysicsComponent>(uid, out var physics) ||
physics.LinearVelocity.Length() < component.MinimumVelocity || physics.LinearVelocity.Length() < component.MinimumVelocity ||
_timing.CurTime < component.NextSound || Timing.CurTime < component.NextSound ||
MetaData(uid).EntityPaused) MetaData(uid).EntityPaused)
{ {
return; return;
@@ -136,7 +136,7 @@ public abstract class SharedEmitSoundSystem : EntitySystem
var fraction = MathF.Min(1f, (physics.LinearVelocity.Length() - component.MinimumVelocity) / MaxVolumeVelocity); var fraction = MathF.Min(1f, (physics.LinearVelocity.Length() - component.MinimumVelocity) / MaxVolumeVelocity);
var volume = MinVolume + (MaxVolume - MinVolume) * fraction; var volume = MinVolume + (MaxVolume - MinVolume) * fraction;
component.NextSound = _timing.CurTime + EmitSoundOnCollideComponent.CollideCooldown; component.NextSound = Timing.CurTime + EmitSoundOnCollideComponent.CollideCooldown;
var sound = component.Sound; var sound = component.Sound;
if (_netMan.IsServer && sound != null) if (_netMan.IsServer && sound != null)
@@ -144,4 +144,8 @@ public abstract class SharedEmitSoundSystem : EntitySystem
_audioSystem.PlayPvs(_audioSystem.GetSound(sound), uid, AudioParams.Default.WithVolume(volume)); _audioSystem.PlayPvs(_audioSystem.GetSound(sound), uid, AudioParams.Default.WithVolume(volume));
} }
} }
public virtual void SetEnabled(Entity<SpamEmitSoundComponent?> entity, bool enabled)
{
}
} }

View File

@@ -0,0 +1,6 @@
namespace Content.Shared.Sound;
public abstract partial class SharedSpamEmitSoundRequirePowerSystem : EntitySystem
{
[Dependency] protected readonly SharedEmitSoundSystem EmitSound = default!;
}

View File

@@ -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"

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -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!

View File

@@ -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!

View File

@@ -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

View File

@@ -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

View File

@@ -10,29 +10,65 @@
priority: Low priority: Low
- type: ExtensionCableReceiver - type: ExtensionCableReceiver
- type: PointLight - type: PointLight
radius: 1.5 radius: 1.8
energy: 1.6 energy: 1.6
color: "#3db83b" color: "#3db83b"
- type: LitOnPowered
- type: Sprite - type: Sprite
sprite: Structures/Machines/arcade.rsi sprite: Structures/Machines/arcade.rsi
layers: layers:
- map: ["computerLayerBody"] - map: ["computerLayerBody"]
state: arcade state: arcade
- map: ["computerLayerScreen"] - map: ["computerLayerScreen"]
state: invaders state: screen_invaders
- map: ["enum.WiresVisualLayers.MaintenancePanel"]
state: panel
visible: false
- type: Icon - type: Icon
sprite: Structures/Machines/arcade.rsi sprite: Structures/Machines/arcade.rsi
state: arcade 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: Anchorable
- type: Pullable - type: Pullable
- type: StaticPrice - type: StaticPrice
price: 300 price: 300
- type: SpamEmitSoundRequirePower
- type: SpamEmitSound
minInterval: 30
maxInterval: 90
sound:
collection: ArcadeNoise
params:
volume: -8
maxDistance: 10
variation: 0.05
- type: entity - type: entity
id: SpaceVillainArcade id: SpaceVillainArcade
name: space villain arcade name: space villain arcade
parent: ArcadeBase parent: ArcadeBase
components: 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 - type: SpaceVillainArcade
rewardAmount: 0 rewardAmount: 0
possibleRewards: possibleRewards:
@@ -108,6 +144,10 @@
type: WiresBoundUserInterface type: WiresBoundUserInterface
- type: Computer - type: Computer
board: SpaceVillainArcadeComputerCircuitboard board: SpaceVillainArcadeComputerCircuitboard
- type: Advertise
pack: SpaceVillainAds
minWait: 60 # Arcades are noisy
maxWait: 240
- type: entity - type: entity
id: SpaceVillainArcadeFilled id: SpaceVillainArcadeFilled
@@ -130,15 +170,14 @@
- map: ["computerLayerBody"] - map: ["computerLayerBody"]
state: arcade state: arcade
- map: ["computerLayerScreen"] - map: ["computerLayerScreen"]
state: blockgame state: screen_blockgame
- map: ["enum.WiresVisualLayers.MaintenancePanel"]
state: panel
visible: false
- type: BlockGameArcade - type: BlockGameArcade
- type: ActivatableUI - type: ActivatableUI
key: enum.BlockGameUiKey.Key key: enum.BlockGameUiKey.Key
- type: ActivatableUIRequiresPower - type: ActivatableUIRequiresPower
- type: WiresPanel
- type: Wires
layoutId: Arcade
boardName: wires-board-name-arcade
- type: UserInterface - type: UserInterface
interfaces: interfaces:
- key: enum.BlockGameUiKey.Key - key: enum.BlockGameUiKey.Key
@@ -147,3 +186,7 @@
type: WiresBoundUserInterface type: WiresBoundUserInterface
- type: Computer - type: Computer
board: BlockGameArcadeComputerCircuitboard board: BlockGameArcadeComputerCircuitboard
- type: Advertise
pack: BlockGameAds
minWait: 60 # Arcades are noisy
maxWait: 240

View File

@@ -22,7 +22,6 @@
- type: SleepEmitSound - type: SleepEmitSound
snore: /Audio/Voice/Misc/silly_snore.ogg snore: /Audio/Voice/Misc/silly_snore.ogg
interval: 10 interval: 10
chance: 1.0
- !type:AddImplantSpecial - !type:AddImplantSpecial
implants: [ SadTromboneImplant ] implants: [ SadTromboneImplant ]

View File

@@ -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

View File

@@ -87,6 +87,7 @@
id: Arcade id: Arcade
wires: wires:
- !type:PowerWireAction - !type:PowerWireAction
- !type:SpeechWireAction
- !type:ArcadeOverflowWireAction - !type:ArcadeOverflowWireAction
- !type:ArcadePlayerInvincibleWireAction - !type:ArcadePlayerInvincibleWireAction
- !type:ArcadeEnemyInvincibleWireAction - !type:ArcadeEnemyInvincibleWireAction

View File

@@ -19,7 +19,11 @@
"directions": 4 "directions": 4
}, },
{ {
"name": "invaders", "name": "panel",
"directions": 4
},
{
"name": "screen_invaders",
"directions": 4, "directions": 4,
"delays": [ "delays": [
[ [
@@ -42,7 +46,7 @@
] ]
}, },
{ {
"name": "blockgame", "name": "screen_blockgame",
"directions": 4, "directions": 4,
"delays": [ "delays": [
[ [
@@ -82,6 +86,48 @@
4.8 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
]
]
} }
] ]
} }

Binary file not shown.

After

Width:  |  Height:  |  Size: 236 B

View File

Before

Width:  |  Height:  |  Size: 6.6 KiB

After

Width:  |  Height:  |  Size: 6.6 KiB

View File

Before

Width:  |  Height:  |  Size: 6.0 KiB

After

Width:  |  Height:  |  Size: 6.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 930 B