Add wallbonk sound to BaseItem (#15689)

Uses a chisel sound.
This commit is contained in:
metalgearsloth
2023-04-24 03:42:09 +10:00
committed by GitHub
parent d496e2ff28
commit 04830bf704
12 changed files with 208 additions and 162 deletions

View File

@@ -11,7 +11,9 @@ public sealed class EmitSoundSystem : SharedEmitSoundSystem
public override void Update(float frameTime) public override void Update(float frameTime)
{ {
base.Update(frameTime); base.Update(frameTime);
foreach (var soundSpammer in EntityQuery<SpamEmitSoundComponent>()) var query = EntityQueryEnumerator<SpamEmitSoundComponent>();
while (query.MoveNext(out var uid, out var soundSpammer))
{ {
if (!soundSpammer.Enabled) if (!soundSpammer.Enabled)
continue; continue;
@@ -26,8 +28,8 @@ public sealed class EmitSoundSystem : SharedEmitSoundSystem
if (Random.Prob(soundSpammer.PlayChance)) if (Random.Prob(soundSpammer.PlayChance))
{ {
if (soundSpammer.PopUp != null) if (soundSpammer.PopUp != null)
Popup.PopupEntity(Loc.GetString(soundSpammer.PopUp), soundSpammer.Owner); Popup.PopupEntity(Loc.GetString(soundSpammer.PopUp), uid);
TryEmitSound(soundSpammer); TryEmitSound(uid, soundSpammer);
} }
} }
} }
@@ -40,14 +42,14 @@ public sealed class EmitSoundSystem : SharedEmitSoundSystem
SubscribeLocalEvent<EmitSoundOnUIOpenComponent, AfterActivatableUIOpenEvent>(HandleEmitSoundOnUIOpen); SubscribeLocalEvent<EmitSoundOnUIOpenComponent, AfterActivatableUIOpenEvent>(HandleEmitSoundOnUIOpen);
} }
private void HandleEmitSoundOnUIOpen(EntityUid eUI, EmitSoundOnUIOpenComponent component, AfterActivatableUIOpenEvent args) private void HandleEmitSoundOnUIOpen(EntityUid uid, EmitSoundOnUIOpenComponent component, AfterActivatableUIOpenEvent args)
{ {
TryEmitSound(component, args.User); TryEmitSound(uid, component, args.User);
} }
private void HandleEmitSoundOnTrigger(EntityUid uid, EmitSoundOnTriggerComponent component, TriggerEvent args) private void HandleEmitSoundOnTrigger(EntityUid uid, EmitSoundOnTriggerComponent component, TriggerEvent args)
{ {
TryEmitSound(component); TryEmitSound(uid, component);
args.Handled = true; args.Handled = true;
} }
} }

View File

@@ -1,23 +1,22 @@
using Robust.Shared.GameStates; using Robust.Shared.GameStates;
namespace Content.Shared.Sound.Components namespace Content.Shared.Sound.Components;
/// <summary>
/// Simple sound emitter that emits sound on ActivateInWorld
/// </summary>
[RegisterComponent, NetworkedComponent]
public sealed class EmitSoundOnActivateComponent : BaseEmitSoundComponent
{ {
/// <summary> /// <summary>
/// Simple sound emitter that emits sound on ActivateInWorld /// Whether or not to mark an interaction as handled after playing the sound. Useful if this component is
/// used to play sound for some other component with activation functionality.
/// </summary> /// </summary>
[RegisterComponent, NetworkedComponent] /// <remarks>
public sealed class EmitSoundOnActivateComponent : BaseEmitSoundComponent /// If false, you should be confident that the interaction will also be handled by some other system, as
{ /// otherwise this might enable sound spamming, as use-delays are only initiated if the interaction was
/// <summary> /// handled.
/// Whether or not to mark an interaction as handled after playing the sound. Useful if this component is /// </remarks>
/// used to play sound for some other component with activation functionality. [DataField("handle")]
/// </summary> public bool Handle = true;
/// <remarks>
/// If false, you should be confident that the interaction will also be handled by some other system, as
/// otherwise this might enable sound spamming, as use-delays are only initiated if the interaction was
/// handled.
/// </remarks>
[DataField("handle")]
public bool Handle = true;
}
} }

View File

@@ -0,0 +1,22 @@
using Robust.Shared.GameStates;
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom;
namespace Content.Shared.Sound.Components;
[RegisterComponent, NetworkedComponent]
public sealed class EmitSoundOnCollideComponent : BaseEmitSoundComponent
{
public static readonly TimeSpan CollideCooldown = TimeSpan.FromSeconds(0.2);
/// <summary>
/// Minimum velocity required for the sound to play.
/// </summary>
[ViewVariables(VVAccess.ReadWrite), DataField("minVelocity")]
public float MinimumVelocity = 0.25f;
/// <summary>
/// To avoid sound spam add a cooldown to it.
/// </summary>
[ViewVariables(VVAccess.ReadWrite), DataField("nextSound", customTypeSerializer:typeof(TimeOffsetSerializer))]
public TimeSpan NextSound;
}

View File

@@ -1,12 +1,11 @@
using Robust.Shared.GameStates; using Robust.Shared.GameStates;
namespace Content.Shared.Sound.Components namespace Content.Shared.Sound.Components;
/// <summary>
/// Simple sound emitter that emits sound on entity drop
/// </summary>
[RegisterComponent, NetworkedComponent]
public sealed class EmitSoundOnDropComponent : BaseEmitSoundComponent
{ {
/// <summary>
/// Simple sound emitter that emits sound on entity drop
/// </summary>
[RegisterComponent, NetworkedComponent]
public sealed class EmitSoundOnDropComponent : BaseEmitSoundComponent
{
}
} }

View File

@@ -1,12 +1,11 @@
using Robust.Shared.GameStates; using Robust.Shared.GameStates;
namespace Content.Shared.Sound.Components namespace Content.Shared.Sound.Components;
/// <summary>
/// Simple sound emitter that emits sound on LandEvent
/// </summary>
[RegisterComponent, NetworkedComponent]
public sealed class EmitSoundOnLandComponent : BaseEmitSoundComponent
{ {
/// <summary>
/// Simple sound emitter that emits sound on LandEvent
/// </summary>
[RegisterComponent, NetworkedComponent]
public sealed class EmitSoundOnLandComponent : BaseEmitSoundComponent
{
}
} }

View File

@@ -1,12 +1,11 @@
using Robust.Shared.GameStates; using Robust.Shared.GameStates;
namespace Content.Shared.Sound.Components namespace Content.Shared.Sound.Components;
/// <summary>
/// Simple sound emitter that emits sound on entity pickup
/// </summary>
[RegisterComponent, NetworkedComponent]
public sealed class EmitSoundOnPickupComponent : BaseEmitSoundComponent
{ {
/// <summary>
/// Simple sound emitter that emits sound on entity pickup
/// </summary>
[RegisterComponent, NetworkedComponent]
public sealed class EmitSoundOnPickupComponent : BaseEmitSoundComponent
{
}
} }

View File

@@ -1,12 +1,11 @@
using Robust.Shared.GameStates; using Robust.Shared.GameStates;
namespace Content.Shared.Sound.Components namespace Content.Shared.Sound.Components;
/// <summary>
/// Simple sound emitter that emits sound on ThrowEvent
/// </summary>
[RegisterComponent, NetworkedComponent]
public sealed class EmitSoundOnThrowComponent : BaseEmitSoundComponent
{ {
/// <summary>
/// Simple sound emitter that emits sound on ThrowEvent
/// </summary>
[RegisterComponent, NetworkedComponent]
public sealed class EmitSoundOnThrowComponent : BaseEmitSoundComponent
{
}
} }

View File

@@ -1,23 +1,22 @@
using Robust.Shared.GameStates; using Robust.Shared.GameStates;
namespace Content.Shared.Sound.Components namespace Content.Shared.Sound.Components;
/// <summary>
/// Simple sound emitter that emits sound on UseInHand
/// </summary>
[RegisterComponent]
public sealed class EmitSoundOnUseComponent : BaseEmitSoundComponent
{ {
/// <summary> /// <summary>
/// Simple sound emitter that emits sound on UseInHand /// Whether or not to mark an interaction as handled after playing the sound. Useful if this component is
/// used to play sound for some other component with on-use functionality
/// </summary> /// </summary>
[RegisterComponent] /// <remarks>
public sealed class EmitSoundOnUseComponent : BaseEmitSoundComponent /// If false, you should be confident that the interaction will also be handled by some other system, as
{ /// otherwise this might enable sound spamming, as use-delays are only initiated if the interaction was
/// <summary> /// handled.
/// Whether or not to mark an interaction as handled after playing the sound. Useful if this component is /// </remarks>
/// used to play sound for some other component with on-use functionality [DataField("handle")]
/// </summary> public bool Handle = true;
/// <remarks>
/// If false, you should be confident that the interaction will also be handled by some other system, as
/// otherwise this might enable sound spamming, as use-delays are only initiated if the interaction was
/// handled.
/// </remarks>
[DataField("handle")]
public bool Handle = true;
}
} }

View File

@@ -8,104 +8,122 @@ using Content.Shared.Throwing;
using JetBrains.Annotations; using JetBrains.Annotations;
using Robust.Shared.Map; using Robust.Shared.Map;
using Robust.Shared.Network; using Robust.Shared.Network;
using Robust.Shared.Physics.Components;
using Robust.Shared.Physics.Events;
using Robust.Shared.Random; using Robust.Shared.Random;
using Robust.Shared.Timing;
namespace Content.Shared.Sound namespace Content.Shared.Sound;
/// <summary>
/// Will play a sound on various events if the affected entity has a component derived from BaseEmitSoundComponent
/// </summary>
[UsedImplicitly]
public abstract class SharedEmitSoundSystem : EntitySystem
{ {
/// <summary> [Dependency] private readonly IGameTiming _timing = default!;
/// Will play a sound on various events if the affected entity has a component derived from BaseEmitSoundComponent [Dependency] private readonly INetManager _netMan = default!;
/// </summary> [Dependency] private readonly IMapManager _mapManager = default!;
[UsedImplicitly] [Dependency] private readonly ITileDefinitionManager _tileDefMan = default!;
public abstract class SharedEmitSoundSystem : EntitySystem [Dependency] protected readonly IRobustRandom Random = default!;
[Dependency] private readonly SharedAudioSystem _audioSystem = default!;
[Dependency] protected readonly SharedPopupSystem Popup = default!;
public override void Initialize()
{ {
[Dependency] private readonly INetManager _netMan = default!; base.Initialize();
[Dependency] private readonly IMapManager _mapManager = default!; SubscribeLocalEvent<EmitSoundOnSpawnComponent, ComponentInit>(OnEmitSpawnOnInit);
[Dependency] private readonly ITileDefinitionManager _tileDefMan = default!; SubscribeLocalEvent<EmitSoundOnLandComponent, LandEvent>(OnEmitSoundOnLand);
[Dependency] protected readonly IRobustRandom Random = default!; SubscribeLocalEvent<EmitSoundOnUseComponent, UseInHandEvent>(OnEmitSoundOnUseInHand);
[Dependency] private readonly SharedAudioSystem _audioSystem = default!; SubscribeLocalEvent<EmitSoundOnThrowComponent, ThrownEvent>(OnEmitSoundOnThrown);
[Dependency] protected readonly SharedPopupSystem Popup = default!; SubscribeLocalEvent<EmitSoundOnActivateComponent, ActivateInWorldEvent>(OnEmitSoundOnActivateInWorld);
SubscribeLocalEvent<EmitSoundOnPickupComponent, GotEquippedHandEvent>(OnEmitSoundOnPickup);
SubscribeLocalEvent<EmitSoundOnDropComponent, DroppedEvent>(OnEmitSoundOnDrop);
SubscribeLocalEvent<EmitSoundOnCollideComponent, StartCollideEvent>(OnEmitSoundOnCollide);
}
public override void Initialize() private void OnEmitSpawnOnInit(EntityUid uid, EmitSoundOnSpawnComponent component, ComponentInit args)
{
TryEmitSound(uid, component, predict: false);
}
private void OnEmitSoundOnLand(EntityUid uid, BaseEmitSoundComponent component, ref LandEvent args)
{
if (!TryComp<TransformComponent>(uid, out var xform) ||
!_mapManager.TryGetGrid(xform.GridUid, out var grid))
return;
var tile = grid.GetTileRef(xform.Coordinates);
// Handle maps being grids (we'll still emit the sound).
if (xform.GridUid != xform.MapUid && tile.IsSpace(_tileDefMan))
return;
// hand throwing not predicted sadly
TryEmitSound(uid, component, args.User, false);
}
private void OnEmitSoundOnUseInHand(EntityUid uid, EmitSoundOnUseComponent component, UseInHandEvent args)
{
// Intentionally not checking whether the interaction has already been handled.
TryEmitSound(uid, component, args.User);
if (component.Handle)
args.Handled = true;
}
private void OnEmitSoundOnThrown(EntityUid uid, BaseEmitSoundComponent component, ThrownEvent args)
{
TryEmitSound(uid, component, args.User, false);
}
private void OnEmitSoundOnActivateInWorld(EntityUid uid, EmitSoundOnActivateComponent component, ActivateInWorldEvent args)
{
// Intentionally not checking whether the interaction has already been handled.
TryEmitSound(uid, component, args.User);
if (component.Handle)
args.Handled = true;
}
private void OnEmitSoundOnPickup(EntityUid uid, EmitSoundOnPickupComponent component, GotEquippedHandEvent args)
{
TryEmitSound(uid, component, args.User);
}
private void OnEmitSoundOnDrop(EntityUid uid, EmitSoundOnDropComponent component, DroppedEvent args)
{
TryEmitSound(uid, component, args.User);
}
protected void TryEmitSound(EntityUid uid, BaseEmitSoundComponent component, EntityUid? user=null, bool predict=true)
{
if (component.Sound == null)
return;
if (predict)
{ {
base.Initialize(); _audioSystem.PlayPredicted(component.Sound, uid, user);
SubscribeLocalEvent<EmitSoundOnSpawnComponent, ComponentInit>(HandleEmitSpawnOnInit);
SubscribeLocalEvent<EmitSoundOnLandComponent, LandEvent>(OnEmitSoundOnLand);
SubscribeLocalEvent<EmitSoundOnUseComponent, UseInHandEvent>(HandleEmitSoundOnUseInHand);
SubscribeLocalEvent<EmitSoundOnThrowComponent, ThrownEvent>(HandleEmitSoundOnThrown);
SubscribeLocalEvent<EmitSoundOnActivateComponent, ActivateInWorldEvent>(HandleEmitSoundOnActivateInWorld);
SubscribeLocalEvent<EmitSoundOnPickupComponent, GotEquippedHandEvent>(HandleEmitSoundOnPickup);
SubscribeLocalEvent<EmitSoundOnDropComponent, DroppedEvent>(HandleEmitSoundOnDrop);
} }
else if (_netMan.IsServer)
private void HandleEmitSpawnOnInit(EntityUid uid, EmitSoundOnSpawnComponent component, ComponentInit args)
{ {
TryEmitSound(component, predict: false); // don't predict sounds that client couldn't have played already
} _audioSystem.PlayPvs(component.Sound, uid);
private void OnEmitSoundOnLand(EntityUid uid, BaseEmitSoundComponent component, ref LandEvent args)
{
if (!TryComp<TransformComponent>(uid, out var xform) ||
!_mapManager.TryGetGrid(xform.GridUid, out var grid))
return;
var tile = grid.GetTileRef(xform.Coordinates);
// Handle maps being grids (we'll still emit the sound).
if (xform.GridUid != xform.MapUid && tile.IsSpace(_tileDefMan))
return;
// hand throwing not predicted sadly
TryEmitSound(component, args.User, false);
}
private void HandleEmitSoundOnUseInHand(EntityUid eUI, EmitSoundOnUseComponent component, UseInHandEvent args)
{
// Intentionally not checking whether the interaction has already been handled.
TryEmitSound(component, args.User);
if (component.Handle)
args.Handled = true;
}
private void HandleEmitSoundOnThrown(EntityUid eUI, BaseEmitSoundComponent component, ThrownEvent args)
{
TryEmitSound(component, args.User, false);
}
private void HandleEmitSoundOnActivateInWorld(EntityUid eUI, EmitSoundOnActivateComponent component, ActivateInWorldEvent args)
{
// Intentionally not checking whether the interaction has already been handled.
TryEmitSound(component, args.User);
if (component.Handle)
args.Handled = true;
}
private void HandleEmitSoundOnPickup(EntityUid uid, EmitSoundOnPickupComponent component, GotEquippedHandEvent args)
{
TryEmitSound(component, args.User);
}
private void HandleEmitSoundOnDrop(EntityUid uid, EmitSoundOnDropComponent component, DroppedEvent args)
{
TryEmitSound(component, args.User);
}
protected void TryEmitSound(BaseEmitSoundComponent component, EntityUid? user=null, bool predict=true)
{
if (component.Sound == null)
return;
if (predict)
{
_audioSystem.PlayPredicted(component.Sound, component.Owner, user);
}
else if (_netMan.IsServer)
{
// don't predict sounds that client couldn't have played already
_audioSystem.PlayPvs(component.Sound, component.Owner);
}
} }
} }
}
private void OnEmitSoundOnCollide(EntityUid uid, EmitSoundOnCollideComponent component, ref StartCollideEvent args)
{
if (!args.OurFixture.Hard ||
!args.OtherFixture.Hard ||
!TryComp<PhysicsComponent>(uid, out var physics) ||
physics.LinearVelocity.Length < component.MinimumVelocity ||
_timing.CurTime < component.NextSound)
{
return;
}
component.NextSound = _timing.CurTime + EmitSoundOnCollideComponent.CollideCooldown;
TryEmitSound(uid, component, predict: false);
}
}

View File

@@ -50,4 +50,9 @@ box_deploy.ogg and chime.ogg taken from Citadel Station at commit: https://githu
license: "Royalty free" license: "Royalty free"
copyright: "Sonniss.com - GDC 2016 - Game Audio Bundle - Levan Nadashvili - Soldier Footsteps - FS Concrete Soldier Crouch N02, mixed from stereo to mono" copyright: "Sonniss.com - GDC 2016 - Game Audio Bundle - Levan Nadashvili - Soldier Footsteps - FS Concrete Soldier Crouch N02, mixed from stereo to mono"
- files:
- "wall_bonk.ogg"
license: "Royalty free"
copyright: "Sonniss.com - GDC 2023 - Game Audio Bundle - 344 Audio - Nuts and Bolts"
# Do not add to this list, I only did the above because yaml scheme validator doesn't like custom licenses. # Do not add to this list, I only did the above because yaml scheme validator doesn't like custom licenses.

Binary file not shown.

View File

@@ -8,6 +8,11 @@
- type: Clickable - type: Clickable
- type: InteractionOutline - type: InteractionOutline
- type: MovedByPressure - type: MovedByPressure
- type: EmitSoundOnCollide
sound:
path: /Audio/Effects/wall_bonk.ogg
params:
volume: 2
- type: EmitSoundOnLand - type: EmitSoundOnLand
sound: sound:
path: /Audio/Effects/drop.ogg path: /Audio/Effects/drop.ogg