More robust bullet impact sounds (#8325)
This commit is contained in:
@@ -350,6 +350,7 @@ namespace Content.Client.Entry
|
||||
"RandomArtifactSprite",
|
||||
"EnergySword",
|
||||
"MeleeSound",
|
||||
"RangedDamageSound",
|
||||
"DoorRemote",
|
||||
"InteractionPopup",
|
||||
"HealthAnalyzer",
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
using Content.Server.Weapon.Ranged;
|
||||
using Content.Shared.Damage;
|
||||
using Content.Shared.Physics;
|
||||
using Content.Shared.Sound;
|
||||
@@ -38,8 +39,12 @@ namespace Content.Server.Projectiles.Components
|
||||
private string? _muzzleFlash;
|
||||
[DataField("impactFlash")]
|
||||
private string? _impactFlash;
|
||||
[DataField("soundHitWall")]
|
||||
private SoundSpecifier _soundHitWall = new SoundPathSpecifier("/Audio/Weapons/Guns/Hits/laser_sear_wall.ogg");
|
||||
|
||||
[DataField("soundHit")]
|
||||
public SoundSpecifier? SoundHit;
|
||||
|
||||
[DataField("soundForce")]
|
||||
public bool ForceSound = false;
|
||||
|
||||
public void FireEffects(EntityUid user, float distance, Angle angle, EntityUid? hitEntity = null)
|
||||
{
|
||||
@@ -80,14 +85,6 @@ namespace Content.Server.Projectiles.Components
|
||||
}
|
||||
}
|
||||
|
||||
if (hitEntity != null && _soundHitWall != null)
|
||||
{
|
||||
// TODO: No wall component so ?
|
||||
var offset = localAngle.ToVec().Normalized / 2;
|
||||
var coordinates = localCoordinates.Offset(offset);
|
||||
SoundSystem.Play(Filter.Pvs(coordinates), _soundHitWall.GetSound(), coordinates);
|
||||
}
|
||||
|
||||
Owner.SpawnTimer((int) _deathTime.TotalMilliseconds, () =>
|
||||
{
|
||||
if (!_entMan.Deleted(Owner))
|
||||
|
||||
@@ -17,7 +17,9 @@ namespace Content.Server.Projectiles.Components
|
||||
|
||||
// Get that juicy FPS hit sound
|
||||
[DataField("soundHit")] public SoundSpecifier? SoundHit;
|
||||
[DataField("soundHitSpecies")] public SoundSpecifier? SoundHitSpecies;
|
||||
|
||||
[DataField("soundForce")]
|
||||
public bool ForceSound = false;
|
||||
|
||||
public bool DamagedEntity;
|
||||
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
using Content.Server.Administration.Logs;
|
||||
using Content.Server.Projectiles.Components;
|
||||
using Content.Server.Weapon.Melee;
|
||||
using Content.Server.Weapon.Ranged;
|
||||
using Content.Shared.Audio;
|
||||
using Content.Shared.Body.Components;
|
||||
using Content.Shared.Camera;
|
||||
using Content.Shared.Damage;
|
||||
@@ -10,6 +13,7 @@ using Robust.Server.GameObjects;
|
||||
using Robust.Shared.Audio;
|
||||
using Robust.Shared.Physics.Dynamics;
|
||||
using Robust.Shared.Player;
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
namespace Content.Server.Projectiles
|
||||
{
|
||||
@@ -19,6 +23,7 @@ namespace Content.Server.Projectiles
|
||||
[Dependency] private readonly DamageableSystem _damageableSystem = default!;
|
||||
[Dependency] private readonly AdminLogSystem _adminLogSystem = default!;
|
||||
[Dependency] private readonly CameraRecoilSystem _cameraRecoil = default!;
|
||||
[Dependency] private readonly GunSystem _guns = default!;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
@@ -36,42 +41,27 @@ namespace Content.Server.Projectiles
|
||||
|
||||
var otherEntity = args.OtherFixture.Body.Owner;
|
||||
|
||||
var coordinates = EntityManager.GetComponent<TransformComponent>(args.OtherFixture.Body.Owner).Coordinates;
|
||||
var playerFilter = Filter.Pvs(coordinates, entityMan: EntityManager);
|
||||
|
||||
if (!EntityManager.GetComponent<MetaDataComponent>(otherEntity).EntityDeleted && component.SoundHitSpecies != null &&
|
||||
EntityManager.HasComponent<SharedBodyComponent>(otherEntity))
|
||||
{
|
||||
SoundSystem.Play(playerFilter, component.SoundHitSpecies.GetSound(), coordinates);
|
||||
}
|
||||
else
|
||||
{
|
||||
var soundHit = component.SoundHit?.GetSound();
|
||||
|
||||
if (!string.IsNullOrEmpty(soundHit))
|
||||
SoundSystem.Play(playerFilter, soundHit, coordinates);
|
||||
}
|
||||
|
||||
if (!EntityManager.GetComponent<MetaDataComponent>(otherEntity).EntityDeleted)
|
||||
{
|
||||
var dmg = _damageableSystem.TryChangeDamage(otherEntity, component.Damage);
|
||||
var modifiedDamage = _damageableSystem.TryChangeDamage(otherEntity, component.Damage);
|
||||
component.DamagedEntity = true;
|
||||
|
||||
if (dmg is not null && EntityManager.EntityExists(component.Shooter))
|
||||
if (modifiedDamage is not null && EntityManager.EntityExists(component.Shooter))
|
||||
{
|
||||
_adminLogSystem.Add(LogType.BulletHit,
|
||||
HasComp<ActorComponent>(otherEntity) ? LogImpact.Extreme : LogImpact.High,
|
||||
$"Projectile {ToPrettyString(component.Owner):projectile} shot by {ToPrettyString(component.Shooter):user} hit {ToPrettyString(otherEntity):target} and dealt {dmg.Total:damage} damage");
|
||||
$"Projectile {ToPrettyString(component.Owner):projectile} shot by {ToPrettyString(component.Shooter):user} hit {ToPrettyString(otherEntity):target} and dealt {modifiedDamage.Total:damage} damage");
|
||||
}
|
||||
|
||||
_guns.PlaySound(otherEntity, modifiedDamage, component.SoundHit, component.ForceSound);
|
||||
|
||||
// Damaging it can delete it
|
||||
if (!Deleted(otherEntity) && HasComp<CameraRecoilComponent>(otherEntity))
|
||||
if (HasComp<CameraRecoilComponent>(otherEntity))
|
||||
{
|
||||
var direction = args.OurFixture.Body.LinearVelocity.Normalized;
|
||||
_cameraRecoil.KickCamera(otherEntity, direction);
|
||||
}
|
||||
|
||||
if (component.DeleteOnCollide)
|
||||
EntityManager.QueueDeleteEntity(uid);
|
||||
QueueDel(uid);
|
||||
}
|
||||
|
||||
public override void Update(float frameTime)
|
||||
|
||||
@@ -33,7 +33,7 @@ namespace Content.Server.Weapon.Melee
|
||||
[Dependency] private readonly AdminLogSystem _logSystem = default!;
|
||||
[Dependency] private readonly BloodstreamSystem _bloodstreamSystem = default!;
|
||||
|
||||
private const float DamagePitchVariation = 0.15f;
|
||||
public const float DamagePitchVariation = 0.15f;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
@@ -107,7 +107,7 @@ namespace Content.Server.Weapon.Melee
|
||||
$"{ToPrettyString(args.User):user} melee attacked {ToPrettyString(args.Target.Value):target} using {ToPrettyString(args.Used):used} and dealt {damageResult.Total:damage} damage");
|
||||
}
|
||||
|
||||
PlayHitSound(target, GetHighestDamageSound(modifiedDamage), hitEvent.HitSoundOverride, comp.HitSound);
|
||||
PlayHitSound(target, GetHighestDamageSound(modifiedDamage, _protoManager), hitEvent.HitSoundOverride, comp.HitSound);
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -165,7 +165,7 @@ namespace Content.Server.Weapon.Melee
|
||||
var target = entities.First();
|
||||
TryComp<MeleeWeaponComponent>(target, out var meleeWeapon);
|
||||
|
||||
PlayHitSound(target, GetHighestDamageSound(modifiedDamage), hitEvent.HitSoundOverride, meleeWeapon?.HitSound);
|
||||
PlayHitSound(target, GetHighestDamageSound(modifiedDamage, _protoManager), hitEvent.HitSoundOverride, meleeWeapon?.HitSound);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -196,9 +196,9 @@ namespace Content.Server.Weapon.Melee
|
||||
RaiseLocalEvent(owner, new RefreshItemCooldownEvent(comp.LastAttackTime, comp.CooldownEnd), false);
|
||||
}
|
||||
|
||||
private string? GetHighestDamageSound(DamageSpecifier modifiedDamage)
|
||||
public static string? GetHighestDamageSound(DamageSpecifier modifiedDamage, IPrototypeManager protoManager)
|
||||
{
|
||||
var groups = modifiedDamage.GetDamagePerGroup(_protoManager);
|
||||
var groups = modifiedDamage.GetDamagePerGroup(protoManager);
|
||||
|
||||
// Use group if it's exclusive, otherwise fall back to type.
|
||||
if (groups.Count == 1)
|
||||
|
||||
@@ -3,12 +3,16 @@ using Content.Server.CombatMode;
|
||||
using Content.Server.Hands.Components;
|
||||
using Content.Server.Interaction.Components;
|
||||
using Content.Server.Projectiles.Components;
|
||||
using Content.Server.Weapon.Melee;
|
||||
using Content.Server.Weapon.Ranged.Ammunition.Components;
|
||||
using Content.Server.Weapon.Ranged.Barrels.Components;
|
||||
using Content.Shared.Audio;
|
||||
using Content.Shared.Camera;
|
||||
using Content.Shared.Damage;
|
||||
using Content.Shared.Database;
|
||||
using Content.Shared.Interaction.Events;
|
||||
using Content.Shared.Popups;
|
||||
using Content.Shared.Sound;
|
||||
using Robust.Shared.Audio;
|
||||
using Robust.Shared.Map;
|
||||
using Robust.Shared.Physics;
|
||||
@@ -239,10 +243,12 @@ public sealed partial class GunSystem
|
||||
var result = rayCastResults[0];
|
||||
var distance = result.Distance;
|
||||
hitscan.FireEffects(shooter, distance, angle, result.HitEntity);
|
||||
var dmg = _damageable.TryChangeDamage(result.HitEntity, hitscan.Damage);
|
||||
if (dmg != null)
|
||||
var modifiedDamage = _damageable.TryChangeDamage(result.HitEntity, hitscan.Damage);
|
||||
if (modifiedDamage != null)
|
||||
_logs.Add(LogType.HitScanHit,
|
||||
$"{EntityManager.ToPrettyString(shooter):user} hit {EntityManager.ToPrettyString(result.HitEntity):target} using {EntityManager.ToPrettyString(hitscan.Owner):used} and dealt {dmg.Total:damage} damage");
|
||||
$"{EntityManager.ToPrettyString(shooter):user} hit {EntityManager.ToPrettyString(result.HitEntity):target} using {EntityManager.ToPrettyString(hitscan.Owner):used} and dealt {modifiedDamage.Total:damage} damage");
|
||||
|
||||
PlaySound(rayCastResults[0].HitEntity, modifiedDamage, hitscan.SoundHit, hitscan.ForceSound);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -251,4 +257,46 @@ public sealed partial class GunSystem
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Impact sounds
|
||||
|
||||
public void PlaySound(EntityUid otherEntity, DamageSpecifier? modifiedDamage, SoundSpecifier? weaponSound, bool forceWeaponSound)
|
||||
{
|
||||
// Like projectiles and melee,
|
||||
// 1. Entity specific sound
|
||||
// 2. Ammo's sound
|
||||
// 3. Nothing
|
||||
var playedSound = false;
|
||||
|
||||
if (!forceWeaponSound && modifiedDamage != null && modifiedDamage.Total > 0 && TryComp<RangedDamageSoundComponent>(otherEntity, out var rangedSound))
|
||||
{
|
||||
var type = MeleeWeaponSystem.GetHighestDamageSound(modifiedDamage, _protoManager);
|
||||
|
||||
if (type != null && rangedSound.SoundTypes?.TryGetValue(type, out var damageSoundType) == true)
|
||||
{
|
||||
SoundSystem.Play(
|
||||
Filter.Pvs(otherEntity, entityManager: EntityManager),
|
||||
damageSoundType!.GetSound(),
|
||||
otherEntity,
|
||||
AudioHelpers.WithVariation(DamagePitchVariation));
|
||||
|
||||
playedSound = true;
|
||||
}
|
||||
else if (type != null && rangedSound.SoundGroups?.TryGetValue(type, out var damageSoundGroup) == true)
|
||||
{
|
||||
SoundSystem.Play(
|
||||
Filter.Pvs(otherEntity, entityManager: EntityManager),
|
||||
damageSoundGroup!.GetSound(),
|
||||
otherEntity,
|
||||
AudioHelpers.WithVariation(DamagePitchVariation));
|
||||
|
||||
playedSound = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!playedSound && weaponSound != null)
|
||||
SoundSystem.Play(Filter.Pvs(otherEntity, entityManager: EntityManager), weaponSound.GetSound(), otherEntity);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ using Content.Server.Atmos.EntitySystems;
|
||||
using Content.Server.Hands.Components;
|
||||
using Content.Server.PowerCell;
|
||||
using Content.Server.Stunnable;
|
||||
using Content.Server.Weapon.Melee;
|
||||
using Content.Server.Weapon.Ranged.Ammunition.Components;
|
||||
using Content.Server.Weapon.Ranged.Barrels.Components;
|
||||
using Content.Shared.ActionBlocker;
|
||||
@@ -22,6 +23,7 @@ using Robust.Shared.Containers;
|
||||
using Robust.Shared.GameStates;
|
||||
using Robust.Shared.Map;
|
||||
using Robust.Shared.Player;
|
||||
using Robust.Shared.Prototypes;
|
||||
using Robust.Shared.Random;
|
||||
using Robust.Shared.Timing;
|
||||
|
||||
@@ -30,6 +32,7 @@ namespace Content.Server.Weapon.Ranged;
|
||||
public sealed partial class GunSystem : EntitySystem
|
||||
{
|
||||
[Dependency] private readonly IGameTiming _gameTiming = default!;
|
||||
[Dependency] private readonly IPrototypeManager _protoManager = default!;
|
||||
[Dependency] private readonly IRobustRandom _random = default!;
|
||||
[Dependency] private readonly ActionBlockerSystem _blocker = default!;
|
||||
[Dependency] private readonly AdminLogSystem _logs = default!;
|
||||
@@ -44,6 +47,8 @@ public sealed partial class GunSystem : EntitySystem
|
||||
[Dependency] private readonly StunSystem _stun = default!;
|
||||
[Dependency] private readonly SharedHandsSystem _handsSystem = default!;
|
||||
|
||||
public const float DamagePitchVariation = MeleeWeaponSystem.DamagePitchVariation;
|
||||
|
||||
/// <summary>
|
||||
/// How many sounds are allowed to be played on ejecting multiple casings.
|
||||
/// </summary>
|
||||
|
||||
30
Content.Server/Weapon/Ranged/RangedDamageSoundComponent.cs
Normal file
30
Content.Server/Weapon/Ranged/RangedDamageSoundComponent.cs
Normal file
@@ -0,0 +1,30 @@
|
||||
using Content.Shared.Damage.Prototypes;
|
||||
using Content.Shared.Sound;
|
||||
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype.Dictionary;
|
||||
|
||||
namespace Content.Server.Weapon.Ranged;
|
||||
|
||||
/// <summary>
|
||||
/// Plays the specified sound upon receiving damage of that type.
|
||||
/// </summary>
|
||||
[RegisterComponent]
|
||||
public sealed class RangedDamageSoundComponent : Component
|
||||
{
|
||||
// TODO: Limb damage changing sound type.
|
||||
|
||||
/// <summary>
|
||||
/// Specified sounds to apply when the entity takes damage with the specified group.
|
||||
/// Will fallback to defaults if none specified.
|
||||
/// </summary>
|
||||
[ViewVariables, DataField("soundGroups",
|
||||
customTypeSerializer: typeof(PrototypeIdDictionarySerializer<SoundSpecifier, DamageGroupPrototype>))]
|
||||
public Dictionary<string, SoundSpecifier>? SoundGroups;
|
||||
|
||||
/// <summary>
|
||||
/// Specified sounds to apply when the entity takes damage with the specified type.
|
||||
/// Will fallback to defaults if none specified.
|
||||
/// </summary>
|
||||
[ViewVariables, DataField("soundTypes",
|
||||
customTypeSerializer: typeof(PrototypeIdDictionarySerializer<SoundSpecifier, DamageTypePrototype>))]
|
||||
public Dictionary<string, SoundSpecifier>? SoundTypes;
|
||||
}
|
||||
BIN
Resources/Audio/Weapons/Guns/Hits/bullet_meat1.ogg
Normal file
BIN
Resources/Audio/Weapons/Guns/Hits/bullet_meat1.ogg
Normal file
Binary file not shown.
BIN
Resources/Audio/Weapons/Guns/Hits/bullet_meat2.ogg
Normal file
BIN
Resources/Audio/Weapons/Guns/Hits/bullet_meat2.ogg
Normal file
Binary file not shown.
BIN
Resources/Audio/Weapons/Guns/Hits/bullet_meat3.ogg
Normal file
BIN
Resources/Audio/Weapons/Guns/Hits/bullet_meat3.ogg
Normal file
Binary file not shown.
BIN
Resources/Audio/Weapons/Guns/Hits/bullet_meat4.ogg
Normal file
BIN
Resources/Audio/Weapons/Guns/Hits/bullet_meat4.ogg
Normal file
Binary file not shown.
BIN
Resources/Audio/Weapons/Guns/Hits/energy_meat1.ogg
Normal file
BIN
Resources/Audio/Weapons/Guns/Hits/energy_meat1.ogg
Normal file
Binary file not shown.
BIN
Resources/Audio/Weapons/Guns/Hits/energy_meat2.ogg
Normal file
BIN
Resources/Audio/Weapons/Guns/Hits/energy_meat2.ogg
Normal file
Binary file not shown.
BIN
Resources/Audio/Weapons/Guns/Hits/energy_metal1.ogg
Normal file
BIN
Resources/Audio/Weapons/Guns/Hits/energy_metal1.ogg
Normal file
Binary file not shown.
BIN
Resources/Audio/Weapons/Guns/Hits/energy_metal2.ogg
Normal file
BIN
Resources/Audio/Weapons/Guns/Hits/energy_metal2.ogg
Normal file
Binary file not shown.
16
Resources/Audio/Weapons/Guns/Hits/licenses.txt
Normal file
16
Resources/Audio/Weapons/Guns/Hits/licenses.txt
Normal file
@@ -0,0 +1,16 @@
|
||||
Taken from https://github.com/Citadel-Station-13/Citadel-Station-13-RP/tree/cc701aedb633d83eae8339a8b3712ad8ad99cca0/sound licensed under CC BY-SA 3.0. Remixed to mono where it was stereo by metalgearsloth:
|
||||
- bullet_meat1.ogg
|
||||
- bullet_meat2.ogg
|
||||
- bullet_meat3.ogg
|
||||
- bullet_meat4.ogg
|
||||
- energy_meat1.ogg
|
||||
- energy_meat2.ogg
|
||||
- energy_metal1.ogg
|
||||
- energy_metal2.ogg
|
||||
|
||||
Taken from https://github.com/tgstation/tgstation/tree/7501504b0ea029d2cf1c0336d09db5c0959aa412/sound/weapons/effects CC BY-SA 3.0.
|
||||
- ric1.ogg
|
||||
- ric2.ogg
|
||||
- ric3.ogg
|
||||
- ric4.ogg
|
||||
- ric5.ogg
|
||||
BIN
Resources/Audio/Weapons/Guns/Hits/ric1.ogg
Normal file
BIN
Resources/Audio/Weapons/Guns/Hits/ric1.ogg
Normal file
Binary file not shown.
BIN
Resources/Audio/Weapons/Guns/Hits/ric2.ogg
Normal file
BIN
Resources/Audio/Weapons/Guns/Hits/ric2.ogg
Normal file
Binary file not shown.
BIN
Resources/Audio/Weapons/Guns/Hits/ric3.ogg
Normal file
BIN
Resources/Audio/Weapons/Guns/Hits/ric3.ogg
Normal file
Binary file not shown.
BIN
Resources/Audio/Weapons/Guns/Hits/ric4.ogg
Normal file
BIN
Resources/Audio/Weapons/Guns/Hits/ric4.ogg
Normal file
Binary file not shown.
BIN
Resources/Audio/Weapons/Guns/Hits/ric5.ogg
Normal file
BIN
Resources/Audio/Weapons/Guns/Hits/ric5.ogg
Normal file
Binary file not shown.
@@ -6,6 +6,15 @@
|
||||
description: A miserable pile of secrets.
|
||||
noSpawn: true
|
||||
components:
|
||||
- type: RangedDamageSound
|
||||
soundGroups:
|
||||
Brute:
|
||||
collection:
|
||||
MeatBulletImpact
|
||||
soundTypes:
|
||||
Heat:
|
||||
collection:
|
||||
MeatLaserImpact
|
||||
- type: Tag
|
||||
tags:
|
||||
- CanPilot
|
||||
|
||||
@@ -147,6 +147,7 @@
|
||||
Heat: 5
|
||||
soundHit:
|
||||
path: "/Audio/Weapons/Guns/Hits/taser_hit.ogg"
|
||||
soundForce: true
|
||||
- type: StunOnCollide
|
||||
stunAmount: 5
|
||||
knockdownAmount: 5
|
||||
|
||||
@@ -9,6 +9,15 @@
|
||||
snap:
|
||||
- Wall
|
||||
components:
|
||||
- type: RangedDamageSound
|
||||
soundGroups:
|
||||
Brute:
|
||||
collection:
|
||||
MetalBulletImpact
|
||||
soundTypes:
|
||||
Heat:
|
||||
collection:
|
||||
MetalLaserImpact
|
||||
- type: Tag
|
||||
tags:
|
||||
- Wall
|
||||
|
||||
29
Resources/Prototypes/SoundCollections/impacts.yml
Normal file
29
Resources/Prototypes/SoundCollections/impacts.yml
Normal file
@@ -0,0 +1,29 @@
|
||||
- type: soundCollection
|
||||
id: MeatBulletImpact
|
||||
files:
|
||||
- "/Audio/Weapons/Guns/Hits/bullet_meat1.ogg"
|
||||
- "/Audio/Weapons/Guns/Hits/bullet_meat2.ogg"
|
||||
- "/Audio/Weapons/Guns/Hits/bullet_meat3.ogg"
|
||||
- "/Audio/Weapons/Guns/Hits/bullet_meat4.ogg"
|
||||
|
||||
- type: soundCollection
|
||||
id: MeatLaserImpact
|
||||
files:
|
||||
- "/Audio/Weapons/Guns/Hits/energy_meat1.ogg"
|
||||
- "/Audio/Weapons/Guns/Hits/energy_meat2.ogg"
|
||||
|
||||
- type: soundCollection
|
||||
id: MetalBulletImpact
|
||||
files:
|
||||
- "/Audio/Weapons/Guns/Hits/ric1.ogg"
|
||||
- "/Audio/Weapons/Guns/Hits/ric2.ogg"
|
||||
- "/Audio/Weapons/Guns/Hits/ric3.ogg"
|
||||
- "/Audio/Weapons/Guns/Hits/ric4.ogg"
|
||||
- "/Audio/Weapons/Guns/Hits/ric5.ogg"
|
||||
|
||||
- type: soundCollection
|
||||
id: MetalLaserImpact
|
||||
files:
|
||||
- "/Audio/Weapons/Guns/Hits/energy_metal1.ogg"
|
||||
- "/Audio/Weapons/Guns/Hits/energy_metal2.ogg"
|
||||
|
||||
Reference in New Issue
Block a user