VocalSystem.cs 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102
  1. using Content.Server.Actions;
  2. using Content.Server.Chat.Systems;
  3. using Content.Server.Speech.Components;
  4. using Content.Shared.Chat.Prototypes;
  5. using Content.Shared.Humanoid;
  6. using Content.Shared.Speech;
  7. using Content.Shared.Speech.Components;
  8. using Robust.Shared.Audio;
  9. using Robust.Shared.Audio.Systems;
  10. using Robust.Shared.Prototypes;
  11. using Robust.Shared.Random;
  12. namespace Content.Server.Speech.EntitySystems;
  13. public sealed class VocalSystem : EntitySystem
  14. {
  15. [Dependency] private readonly IRobustRandom _random = default!;
  16. [Dependency] private readonly IPrototypeManager _proto = default!;
  17. [Dependency] private readonly SharedAudioSystem _audio = default!;
  18. [Dependency] private readonly ChatSystem _chat = default!;
  19. [Dependency] private readonly ActionsSystem _actions = default!;
  20. public override void Initialize()
  21. {
  22. base.Initialize();
  23. SubscribeLocalEvent<VocalComponent, MapInitEvent>(OnMapInit);
  24. SubscribeLocalEvent<VocalComponent, ComponentShutdown>(OnShutdown);
  25. SubscribeLocalEvent<VocalComponent, SexChangedEvent>(OnSexChanged);
  26. SubscribeLocalEvent<VocalComponent, EmoteEvent>(OnEmote);
  27. SubscribeLocalEvent<VocalComponent, ScreamActionEvent>(OnScreamAction);
  28. }
  29. private void OnMapInit(EntityUid uid, VocalComponent component, MapInitEvent args)
  30. {
  31. // try to add scream action when vocal comp added
  32. _actions.AddAction(uid, ref component.ScreamActionEntity, component.ScreamAction);
  33. LoadSounds(uid, component);
  34. }
  35. private void OnShutdown(EntityUid uid, VocalComponent component, ComponentShutdown args)
  36. {
  37. // remove scream action when component removed
  38. if (component.ScreamActionEntity != null)
  39. {
  40. _actions.RemoveAction(uid, component.ScreamActionEntity);
  41. }
  42. }
  43. private void OnSexChanged(EntityUid uid, VocalComponent component, SexChangedEvent args)
  44. {
  45. LoadSounds(uid, component);
  46. }
  47. private void OnEmote(EntityUid uid, VocalComponent component, ref EmoteEvent args)
  48. {
  49. if (args.Handled || !args.Emote.Category.HasFlag(EmoteCategory.Vocal))
  50. return;
  51. // snowflake case for wilhelm scream easter egg
  52. if (args.Emote.ID == component.ScreamId)
  53. {
  54. args.Handled = TryPlayScreamSound(uid, component);
  55. return;
  56. }
  57. // just play regular sound based on emote proto
  58. args.Handled = _chat.TryPlayEmoteSound(uid, component.EmoteSounds, args.Emote);
  59. }
  60. private void OnScreamAction(EntityUid uid, VocalComponent component, ScreamActionEvent args)
  61. {
  62. if (args.Handled)
  63. return;
  64. _chat.TryEmoteWithChat(uid, component.ScreamId);
  65. args.Handled = true;
  66. }
  67. private bool TryPlayScreamSound(EntityUid uid, VocalComponent component)
  68. {
  69. if (_random.Prob(component.WilhelmProbability))
  70. {
  71. _audio.PlayPvs(component.Wilhelm, uid, component.Wilhelm.Params);
  72. return true;
  73. }
  74. return _chat.TryPlayEmoteSound(uid, component.EmoteSounds, component.ScreamId);
  75. }
  76. private void LoadSounds(EntityUid uid, VocalComponent component, Sex? sex = null)
  77. {
  78. if (component.Sounds == null)
  79. return;
  80. sex ??= CompOrNull<HumanoidAppearanceComponent>(uid)?.Sex ?? Sex.Unsexed;
  81. if (!component.Sounds.TryGetValue(sex.Value, out var protoId))
  82. return;
  83. _proto.TryIndex(protoId, out component.EmoteSounds);
  84. }
  85. }