diff --git a/Content.Shared/Whistle/WhistleComponent.cs b/Content.Shared/Whistle/WhistleComponent.cs new file mode 100644 index 00000000000000..5004711514f522 --- /dev/null +++ b/Content.Shared/Whistle/WhistleComponent.cs @@ -0,0 +1,25 @@ +using Robust.Shared.GameStates; +using Content.Shared.Humanoid; +using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype; +using Robust.Shared.Prototypes; + +namespace Content.Shared.Whistle; + +/// +/// Spawn attached entity for entities in range with . +/// +[RegisterComponent, NetworkedComponent] +public sealed partial class WhistleComponent : Component +{ + /// + /// Entity prototype to spawn + /// + [DataField] + public EntProtoId Effect = "WhistleExclamation"; + + /// + /// Range value. + /// + [DataField] + public float Distance = 0; +} diff --git a/Content.Shared/Whistle/WhistleSystem.cs b/Content.Shared/Whistle/WhistleSystem.cs new file mode 100644 index 00000000000000..9db7ffa0bf0b79 --- /dev/null +++ b/Content.Shared/Whistle/WhistleSystem.cs @@ -0,0 +1,64 @@ +using Content.Shared.Coordinates; +using Content.Shared.Humanoid; +using Content.Shared.Interaction.Events; +using Content.Shared.Stealth.Components; +using JetBrains.Annotations; +using Robust.Shared.Timing; + +namespace Content.Shared.Whistle; + +public sealed class WhistleSystem : EntitySystem +{ + [Dependency] private readonly EntityLookupSystem _entityLookup = default!; + [Dependency] private readonly IGameTiming _timing = default!; + [Dependency] private readonly SharedTransformSystem _transform = default!; + + public override void Initialize() + { + base.Initialize(); + + SubscribeLocalEvent(OnUseInHand); + } + + private void ExclamateTarget(EntityUid target, WhistleComponent component) + { + SpawnAttachedTo(component.Effect, target.ToCoordinates()); + } + + public void OnUseInHand(EntityUid uid, WhistleComponent component, UseInHandEvent args) + { + if (!_timing.IsFirstTimePredicted) + return; + + TryMakeLoudWhistle(uid, args.User, component); + args.Handled = true; + } + + public bool TryMakeLoudWhistle(EntityUid uid, EntityUid owner, WhistleComponent? component = null) + { + if (!Resolve(uid, ref component, false) || component.Distance <= 0) + return false; + + MakeLoudWhistle(uid, owner, component); + return true; + } + + private void MakeLoudWhistle(EntityUid uid, EntityUid owner, WhistleComponent component) + { + StealthComponent? stealth = null; + + foreach (var iterator in + _entityLookup.GetEntitiesInRange(_transform.GetMapCoordinates(uid), component.Distance)) + { + //Avoid pinging invisible entities + if (TryComp(iterator, out stealth) && stealth.Enabled) + continue; + + //We don't want to ping user of whistle + if (iterator.Owner == owner) + continue; + + ExclamateTarget(iterator, component); + } + } +} diff --git a/Resources/Audio/Items/Whistle/attributions.yml b/Resources/Audio/Items/Whistle/attributions.yml new file mode 100644 index 00000000000000..25a3da91744e59 --- /dev/null +++ b/Resources/Audio/Items/Whistle/attributions.yml @@ -0,0 +1,11 @@ +- files: + - "whistle_1.ogg" + - "whistle_2.ogg" + - "whistle_3.ogg" + - "whistle_4.ogg" + - "whistle_5.ogg" + - "whistle_6.ogg" + - "whistle_7.ogg" + license: "CC0-1.0" + copyright: "User strongbot on freesound.org. Modified by Fahasor on github" + source: "https://freesound.org/people/strongbot/sounds/568995/" \ No newline at end of file diff --git a/Resources/Audio/Items/Whistle/whistle_1.ogg b/Resources/Audio/Items/Whistle/whistle_1.ogg new file mode 100644 index 00000000000000..5951dc89cbbd3a Binary files /dev/null and b/Resources/Audio/Items/Whistle/whistle_1.ogg differ diff --git a/Resources/Audio/Items/Whistle/whistle_2.ogg b/Resources/Audio/Items/Whistle/whistle_2.ogg new file mode 100644 index 00000000000000..8af0d9ef54725a Binary files /dev/null and b/Resources/Audio/Items/Whistle/whistle_2.ogg differ diff --git a/Resources/Audio/Items/Whistle/whistle_3.ogg b/Resources/Audio/Items/Whistle/whistle_3.ogg new file mode 100644 index 00000000000000..f8b53be200ab48 Binary files /dev/null and b/Resources/Audio/Items/Whistle/whistle_3.ogg differ diff --git a/Resources/Audio/Items/Whistle/whistle_4.ogg b/Resources/Audio/Items/Whistle/whistle_4.ogg new file mode 100644 index 00000000000000..cecdbca65224e4 Binary files /dev/null and b/Resources/Audio/Items/Whistle/whistle_4.ogg differ diff --git a/Resources/Audio/Items/Whistle/whistle_5.ogg b/Resources/Audio/Items/Whistle/whistle_5.ogg new file mode 100644 index 00000000000000..feca849a5e7954 Binary files /dev/null and b/Resources/Audio/Items/Whistle/whistle_5.ogg differ diff --git a/Resources/Audio/Items/Whistle/whistle_6.ogg b/Resources/Audio/Items/Whistle/whistle_6.ogg new file mode 100644 index 00000000000000..8db768776f7f0c Binary files /dev/null and b/Resources/Audio/Items/Whistle/whistle_6.ogg differ diff --git a/Resources/Audio/Items/Whistle/whistle_7.ogg b/Resources/Audio/Items/Whistle/whistle_7.ogg new file mode 100644 index 00000000000000..787463fe78c582 Binary files /dev/null and b/Resources/Audio/Items/Whistle/whistle_7.ogg differ diff --git a/Resources/Prototypes/Catalog/VendingMachines/Inventories/sec.yml b/Resources/Prototypes/Catalog/VendingMachines/Inventories/sec.yml index 75f0cad84b8d75..227d8767e83cc7 100644 --- a/Resources/Prototypes/Catalog/VendingMachines/Inventories/sec.yml +++ b/Resources/Prototypes/Catalog/VendingMachines/Inventories/sec.yml @@ -1,6 +1,7 @@ - type: vendingMachineInventory id: SecTechInventory startingInventory: + SecurityWhistle: 5 Handcuffs: 8 GrenadeFlashBang: 4 TearGasGrenade: 4 diff --git a/Resources/Prototypes/Entities/Effects/exclamation.yml b/Resources/Prototypes/Entities/Effects/exclamation.yml new file mode 100644 index 00000000000000..cfe1cbc7f22e7f --- /dev/null +++ b/Resources/Prototypes/Entities/Effects/exclamation.yml @@ -0,0 +1,39 @@ +- type: entity + id: Exclamation + name: exclamation + noSpawn: true + save: false + components: + - type: Transform + noRot: true + - type: Sprite + sprite: Structures/Storage/closet.rsi + drawdepth: Effects + noRot: true + layers: + - state: "cardboard_special" + - type: TimedDespawn + lifetime: 1 + - type: Tag + tags: + - HideContextMenu + + +- type: entity + id: WhistleExclamation + name: exclamation + noSpawn: true + components: + - type: Sprite + sprite: Structures/Storage/closet.rsi + state: cardboard_special + drawdepth: Effects + offset: 0, 1 + noRot: true + - type: Transform + noRot: true + - type: TimedDespawn + lifetime: 0.8 + - type: Tag + tags: + - HideContextMenu \ No newline at end of file diff --git a/Resources/Prototypes/Entities/Objects/Fun/whistles.yml b/Resources/Prototypes/Entities/Objects/Fun/whistles.yml new file mode 100644 index 00000000000000..4281f0c4d4f488 --- /dev/null +++ b/Resources/Prototypes/Entities/Objects/Fun/whistles.yml @@ -0,0 +1,30 @@ +- type: entity + abstract: true + parent: BaseItem + id: BaseWhistle + name: whistle + description: Someone forgot to turn off kettle? + components: + - type: Item + size: Tiny + - type: Clothing + quickEquip: false + slots: neck + - type: UseDelay + delay: 3 + - type: EmitSoundOnUse + sound: + collection: BaseWhistle + - type: Whistle + distance: 5 + +- type: entity + parent: BaseWhistle + id: SecurityWhistle + description: Sound of it make you feel fear. + components: + - type: Sprite + sprite: Objects/Fun/whistle.rsi + state: securityWhistle + - type: Item + sprite: Objects/Fun/whistle.rsi \ No newline at end of file diff --git a/Resources/Prototypes/Entities/Structures/Storage/Closets/big_boxes.yml b/Resources/Prototypes/Entities/Structures/Storage/Closets/big_boxes.yml index 040aff42b456bb..ac7f053b631aca 100644 --- a/Resources/Prototypes/Entities/Structures/Storage/Closets/big_boxes.yml +++ b/Resources/Prototypes/Entities/Structures/Storage/Closets/big_boxes.yml @@ -107,25 +107,4 @@ - type: EntityStorage isCollidableWhenOpen: false openOnMove: false - airtight: false - -#Exclamation effect for box opening -- type: entity - id: Exclamation - name: exclamation - noSpawn: true - save: false - components: - - type: Transform - noRot: true - - type: Sprite - sprite: Structures/Storage/closet.rsi - drawdepth: Effects - noRot: true - layers: - - state: "cardboard_special" - - type: TimedDespawn - lifetime: 1 - - type: Tag - tags: - - HideContextMenu + airtight: false \ No newline at end of file diff --git a/Resources/Prototypes/SoundCollections/whistle.yml b/Resources/Prototypes/SoundCollections/whistle.yml new file mode 100644 index 00000000000000..f7d0dc9a1da9f7 --- /dev/null +++ b/Resources/Prototypes/SoundCollections/whistle.yml @@ -0,0 +1,10 @@ +- type: soundCollection + id: BaseWhistle + files: + - /Audio/Items/Whistle/whistle_1.ogg + - /Audio/Items/Whistle/whistle_2.ogg + - /Audio/Items/Whistle/whistle_3.ogg + - /Audio/Items/Whistle/whistle_4.ogg + - /Audio/Items/Whistle/whistle_5.ogg + - /Audio/Items/Whistle/whistle_6.ogg + - /Audio/Items/Whistle/whistle_7.ogg diff --git a/Resources/Textures/Objects/Fun/whistle.rsi/meta.json b/Resources/Textures/Objects/Fun/whistle.rsi/meta.json new file mode 100644 index 00000000000000..59159ff6170f9d --- /dev/null +++ b/Resources/Textures/Objects/Fun/whistle.rsi/meta.json @@ -0,0 +1,14 @@ +{ + "version": 1, + "license": "CC-BY-SA-3.0", + "copyright": "Made by Foleps (discord)", + "size": { + "x": 32, + "y": 32 + }, + "states": [ + { + "name": "securityWhistle" + } + ] +} diff --git a/Resources/Textures/Objects/Fun/whistle.rsi/securityWhistle.png b/Resources/Textures/Objects/Fun/whistle.rsi/securityWhistle.png new file mode 100644 index 00000000000000..81e43549b1d1e6 Binary files /dev/null and b/Resources/Textures/Objects/Fun/whistle.rsi/securityWhistle.png differ