using Content.Shared.Weapons.Melee;
using Content.Shared.Weapons.Melee.Events;
using Robust.Shared.Audio;
+using Robust.Shared.Audio.Systems;
using Robust.Shared.Map;
using Robust.Shared.Player;
using Robust.Shared.Random;
public sealed class MeleeWeaponSystem : SharedMeleeWeaponSystem
{
- [Dependency] private readonly IRobustRandom _random = default!;
- [Dependency] private readonly BloodstreamSystem _bloodstream = default!;
- [Dependency] private readonly ChatSystem _chat = default!;
- [Dependency] private readonly DamageExamineSystem _damageExamine = default!;
- [Dependency] private readonly InventorySystem _inventory = default!;
- [Dependency] private readonly LagCompensationSystem _lag = default!;
- [Dependency] private readonly MobStateSystem _mobState = default!;
- [Dependency] private readonly SharedColorFlashEffectSystem _color = default!;
- [Dependency] private readonly SolutionContainerSystem _solutions = default!;
- [Dependency] private readonly TagSystem _tag = default!;
+ [Dependency] private readonly SharedAudioSystem _audio = default!;
+ [Dependency] private readonly IRobustRandom _random = default!;
+ [Dependency] private readonly BloodstreamSystem _bloodstream = default!;
+ [Dependency] private readonly ChatSystem _chat = default!;
+ [Dependency] private readonly DamageExamineSystem _damageExamine = default!;
+ [Dependency] private readonly InventorySystem _inventory = default!;
+ [Dependency] private readonly LagCompensationSystem _lag = default!;
+ [Dependency] private readonly MobStateSystem _mobState = default!;
+ [Dependency] private readonly SharedColorFlashEffectSystem _color = default!;
+ [Dependency] private readonly SolutionContainerSystem _solutions = default!;
+ [Dependency] private readonly TagSystem _tag = default!;
public override void Initialize()
{
return false;
}
- Audio.PlayPvs(combatMode.DisarmSuccessSound, user, AudioParams.Default.WithVariation(0.025f).WithVolume(5f));
+ _audio.PlayPvs(combatMode.DisarmSuccessSound, user, AudioParams.Default.WithVariation(0.025f).WithVolume(5f));
+ AdminLogger.Add(LogType.DisarmedAction, $"{ToPrettyString(user):user} used disarm on {ToPrettyString(target):target}");
var targetEnt = Identity.Entity(target, EntityManager);
var userEnt = Identity.Entity(user, EntityManager);
PopupSystem.PopupEntity(msgOther, user, filterOther, true);
PopupSystem.PopupEntity(msgUser, target, user);
-
if (eventArgs.IsStunned)
{
--- /dev/null
+using Content.Shared.Weapons.Melee.Components;
+using Robust.Shared.Audio;
+using Robust.Shared.Audio.Systems;
+
+namespace Content.Shared.Weapons.Melee;
+
+/// <summary>
+/// This handles <see cref="MeleeSoundComponent"/>
+/// </summary>
+public sealed class MeleeSoundSystem : EntitySystem
+{
+ [Dependency] private readonly SharedAudioSystem _audio = default!;
+
+ public const float DamagePitchVariation = 0.05f;
+
+ /// <summary>
+ /// Plays the SwingSound from a weapon component
+ /// for immediate feedback, misses and such
+ /// (Swinging a weapon goes "whoosh" whether it hits or not)
+ /// </summary>
+ public void PlaySwingSound(EntityUid userUid, EntityUid weaponUid, MeleeWeaponComponent weaponComponent)
+ {
+ _audio.PlayPredicted(weaponComponent.SwingSound, weaponUid, userUid);
+ }
+
+ /// <summary>
+ /// Takes a "damageType" string as an argument and uses it to
+ /// search one of the various Dictionaries in the MeleeSoundComponent
+ /// for a sound to play, and falls back if that fails
+ /// </summary>
+ /// <param name="damageType"> Serves as a lookup key for a hit sound </param>
+ /// <param name="hitSoundOverride"> A sound can be supplied by the <see cref="MeleeHitEvent"/> itself to override everything else </param>
+ public void PlayHitSound(EntityUid targetUid, EntityUid? userUid, string? damageType, SoundSpecifier? hitSoundOverride, MeleeWeaponComponent weaponComponent)
+ {
+ var hitSound = weaponComponent.HitSound;
+ var noDamageSound = weaponComponent.NoDamageSound;
+
+ var playedSound = false;
+
+ if (Deleted(targetUid))
+ return;
+
+ // hitting can obv destroy an entity so we play at coords and not following them
+ var coords = Transform(targetUid).Coordinates;
+ // Play sound based off of highest damage type.
+ if (TryComp<MeleeSoundComponent>(targetUid, out var damageSoundComp))
+ {
+ if (damageType == null && damageSoundComp.NoDamageSound != null)
+ {
+ _audio.PlayPredicted(damageSoundComp.NoDamageSound, coords, userUid, AudioParams.Default.WithVariation(DamagePitchVariation));
+ playedSound = true;
+ }
+ else if (damageType != null && damageSoundComp.SoundTypes?.TryGetValue(damageType, out var damageSoundType) == true)
+ {
+ _audio.PlayPredicted(damageSoundType, coords, userUid, AudioParams.Default.WithVariation(DamagePitchVariation));
+ playedSound = true;
+ }
+ else if (damageType != null && damageSoundComp.SoundGroups?.TryGetValue(damageType, out var damageSoundGroup) == true)
+ {
+ _audio.PlayPredicted(damageSoundGroup, coords, userUid, AudioParams.Default.WithVariation(DamagePitchVariation));
+ playedSound = true;
+ }
+ }
+
+ // Use weapon sounds if the thing being hit doesn't specify its own sounds.
+ if (!playedSound)
+ {
+ if (hitSoundOverride != null)
+ {
+ _audio.PlayPredicted(hitSoundOverride, coords, userUid, AudioParams.Default.WithVariation(DamagePitchVariation));
+ playedSound = true;
+ }
+ else if (hitSound != null)
+ {
+ _audio.PlayPredicted(hitSound, coords, userUid, AudioParams.Default.WithVariation(DamagePitchVariation));
+ playedSound = true;
+ }
+ else
+ {
+ _audio.PlayPredicted(noDamageSound, coords, userUid, AudioParams.Default.WithVariation(DamagePitchVariation));
+ playedSound = true;
+ }
+ }
+
+ // Fallback to generic sounds.
+ if (!playedSound)
+ {
+ switch (damageType)
+ {
+ // Unfortunately heat returns caustic group so can't just use the damagegroup in that instance.
+ case "Burn":
+ case "Heat":
+ case "Radiation":
+ case "Cold":
+ _audio.PlayPredicted(new SoundPathSpecifier("/Audio/Items/welder.ogg"), targetUid, userUid, AudioParams.Default.WithVariation(DamagePitchVariation));
+ break;
+ // No damage, fallback to tappies
+ case null:
+ _audio.PlayPredicted(new SoundCollectionSpecifier("WeakHit"), targetUid, userUid, AudioParams.Default.WithVariation(DamagePitchVariation));
+ break;
+ case "Brute":
+ _audio.PlayPredicted(new SoundCollectionSpecifier("MetalThud"), targetUid, userUid, AudioParams.Default.WithVariation(DamagePitchVariation));
+ break;
+ }
+ }
+ }
+
+}
using Content.Shared.Weapons.Ranged.Components;
using Content.Shared.Weapons.Ranged.Events;
using Content.Shared.Weapons.Ranged.Systems;
-using Robust.Shared.Audio;
-using Robust.Shared.Audio.Systems;
using Robust.Shared.Map;
using Robust.Shared.Physics;
using Robust.Shared.Physics.Systems;
public abstract class SharedMeleeWeaponSystem : EntitySystem
{
- [Dependency] protected readonly IGameTiming Timing = default!;
- [Dependency] protected readonly IMapManager MapManager = default!;
- [Dependency] private readonly IPrototypeManager _protoManager = default!;
- [Dependency] protected readonly ISharedAdminLogManager AdminLogger = default!;
- [Dependency] protected readonly ActionBlockerSystem Blocker = default!;
- [Dependency] protected readonly DamageableSystem Damageable = default!;
- [Dependency] private readonly InventorySystem _inventory = default!;
- [Dependency] protected readonly SharedAudioSystem Audio = default!;
- [Dependency] protected readonly SharedCombatModeSystem CombatMode = default!;
- [Dependency] protected readonly SharedInteractionSystem Interaction = default!;
- [Dependency] private readonly SharedPhysicsSystem _physics = default!;
- [Dependency] protected readonly SharedPopupSystem PopupSystem = default!;
- [Dependency] protected readonly SharedTransformSystem TransformSystem = default!;
- [Dependency] private readonly StaminaSystem _stamina = default!;
-
- public const float DamagePitchVariation = 0.05f;
+ [Dependency] protected readonly ISharedAdminLogManager AdminLogger = default!;
+ [Dependency] protected readonly ActionBlockerSystem Blocker = default!;
+ [Dependency] protected readonly SharedCombatModeSystem CombatMode = default!;
+ [Dependency] protected readonly DamageableSystem Damageable = default!;
+ [Dependency] protected readonly SharedInteractionSystem Interaction = default!;
+ [Dependency] protected readonly IMapManager MapManager = default!;
+ [Dependency] protected readonly SharedPopupSystem PopupSystem = default!;
+ [Dependency] protected readonly IGameTiming Timing = default!;
+ [Dependency] protected readonly SharedTransformSystem TransformSystem = default!;
+ [Dependency] private readonly InventorySystem _inventory = default!;
+ [Dependency] private readonly MeleeSoundSystem _meleeSound = default!;
+ [Dependency] private readonly SharedPhysicsSystem _physics = default!;
+ [Dependency] private readonly IPrototypeManager _protoManager = default!;
+ [Dependency] private readonly StaminaSystem _stamina = default!;
+
private const int AttackMask = (int) (CollisionGroup.MobMask | CollisionGroup.Opaque);
/// <summary>
SubscribeAllEvent<StopAttackEvent>(OnStopAttack);
#if DEBUG
- SubscribeLocalEvent<MeleeWeaponComponent, MapInitEvent>(OnMapInit);
+ SubscribeLocalEvent<MeleeWeaponComponent,
+ MapInitEvent> (OnMapInit);
}
private void OnMapInit(EntityUid uid, MeleeWeaponComponent component, MapInitEvent args)
}
var missEvent = new MeleeHitEvent(new List<EntityUid>(), user, meleeUid, damage, null);
RaiseLocalEvent(meleeUid, missEvent);
- Audio.PlayPredicted(component.SwingSound, meleeUid, user);
+ _meleeSound.PlaySwingSound(user, meleeUid, component);
return;
}
}
- PlayHitSound(target.Value, user, GetHighestDamageSound(modifiedDamage, _protoManager), hitEvent.HitSoundOverride, component.HitSound, component.NoDamageSound);
+ _meleeSound.PlayHitSound(target.Value, user, GetHighestDamageSound(modifiedDamage, _protoManager), hitEvent.HitSoundOverride, component);
if (damageResult?.GetTotal() > FixedPoint2.Zero)
{
var missEvent = new MeleeHitEvent(new List<EntityUid>(), user, meleeUid, damage, direction);
RaiseLocalEvent(meleeUid, missEvent);
- Audio.PlayPredicted(component.SwingSound, meleeUid, user);
+ // immediate audio feedback
+ _meleeSound.PlaySwingSound(user, meleeUid, component);
+
return true;
}
if (entities.Count != 0)
{
var target = entities.First();
- PlayHitSound(target, user, GetHighestDamageSound(appliedDamage, _protoManager), hitEvent.HitSoundOverride, component.HitSound, component.NoDamageSound);
+ _meleeSound.PlayHitSound(target, user, GetHighestDamageSound(appliedDamage, _protoManager), hitEvent.HitSoundOverride, component);
}
if (appliedDamage.GetTotal() > FixedPoint2.Zero)
return true;
}
- public void PlayHitSound(EntityUid target, EntityUid? user, string? type, SoundSpecifier? hitSoundOverride, SoundSpecifier? hitSound, SoundSpecifier? noDamageSound)
- {
- var playedSound = false;
-
- if (Deleted(target))
- return;
-
- // hitting can obv destroy an entity so we play at coords and not following them
- var coords = Transform(target).Coordinates;
- // Play sound based off of highest damage type.
- if (TryComp<MeleeSoundComponent>(target, out var damageSoundComp))
- {
- if (type == null && damageSoundComp.NoDamageSound != null)
- {
- Audio.PlayPredicted(damageSoundComp.NoDamageSound, coords, user, AudioParams.Default.WithVariation(DamagePitchVariation));
- playedSound = true;
- }
- else if (type != null && damageSoundComp.SoundTypes?.TryGetValue(type, out var damageSoundType) == true)
- {
- Audio.PlayPredicted(damageSoundType, coords, user, AudioParams.Default.WithVariation(DamagePitchVariation));
- playedSound = true;
- }
- else if (type != null && damageSoundComp.SoundGroups?.TryGetValue(type, out var damageSoundGroup) == true)
- {
- Audio.PlayPredicted(damageSoundGroup, coords, user, AudioParams.Default.WithVariation(DamagePitchVariation));
- playedSound = true;
- }
- }
-
- // Use weapon sounds if the thing being hit doesn't specify its own sounds.
- if (!playedSound)
- {
- if (hitSoundOverride != null)
- {
- Audio.PlayPredicted(hitSoundOverride, coords, user, AudioParams.Default.WithVariation(DamagePitchVariation));
- playedSound = true;
- }
- else if (hitSound != null)
- {
- Audio.PlayPredicted(hitSound, coords, user, AudioParams.Default.WithVariation(DamagePitchVariation));
- playedSound = true;
- }
- else if (noDamageSound != null)
- {
- Audio.PlayPredicted(noDamageSound, coords, user, AudioParams.Default.WithVariation(DamagePitchVariation));
- playedSound = true;
- }
- }
-
- // Fallback to generic sounds.
- if (!playedSound)
- {
- switch (type)
- {
- // Unfortunately heat returns caustic group so can't just use the damagegroup in that instance.
- case "Burn":
- case "Heat":
- case "Radiation":
- case "Cold":
- Audio.PlayPredicted(new SoundPathSpecifier("/Audio/Items/welder.ogg"), target, user, AudioParams.Default.WithVariation(DamagePitchVariation));
- break;
- // No damage, fallback to tappies
- case null:
- Audio.PlayPredicted(new SoundCollectionSpecifier("WeakHit"), target, user, AudioParams.Default.WithVariation(DamagePitchVariation));
- break;
- case "Brute":
- Audio.PlayPredicted(new SoundCollectionSpecifier("MetalThud"), target, user, AudioParams.Default.WithVariation(DamagePitchVariation));
- break;
- }
- }
- }
public static string? GetHighestDamageSound(DamageSpecifier modifiedDamage, IPrototypeManager protoManager)
{
}
// Play a sound to give instant feedback; same with playing the animations
- Audio.PlayPredicted(component.SwingSound, meleeUid, user);
+ _meleeSound.PlaySwingSound(user, meleeUid, component);
return true;
}