1
0

AutoEmoteSystem.cs 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141
  1. using System.Linq;
  2. using Content.Shared.Chat.Prototypes;
  3. using Robust.Shared.Prototypes;
  4. using Robust.Shared.Random;
  5. using Robust.Shared.Timing;
  6. using Robust.Shared.Utility;
  7. namespace Content.Server.Chat.Systems;
  8. public sealed class AutoEmoteSystem : EntitySystem
  9. {
  10. [Dependency] private readonly IGameTiming _gameTiming = default!;
  11. [Dependency] private readonly IPrototypeManager _prototypeManager = default!;
  12. [Dependency] private readonly IRobustRandom _random = default!;
  13. [Dependency] private readonly ChatSystem _chatSystem = default!;
  14. public override void Initialize()
  15. {
  16. base.Initialize();
  17. SubscribeLocalEvent<AutoEmoteComponent, MapInitEvent>(OnMapInit);
  18. SubscribeLocalEvent<AutoEmoteComponent, EntityUnpausedEvent>(OnUnpaused);
  19. }
  20. public override void Update(float frameTime)
  21. {
  22. base.Update(frameTime);
  23. var curTime = _gameTiming.CurTime;
  24. var query = EntityQueryEnumerator<AutoEmoteComponent>();
  25. while (query.MoveNext(out var uid, out var autoEmote))
  26. {
  27. if (autoEmote.NextEmoteTime > curTime)
  28. continue;
  29. foreach (var (key, time) in autoEmote.EmoteTimers)
  30. {
  31. if (time > curTime)
  32. continue;
  33. var autoEmotePrototype = _prototypeManager.Index<AutoEmotePrototype>(key);
  34. ResetTimer(uid, key, autoEmote, autoEmotePrototype);
  35. if (!_random.Prob(autoEmotePrototype.Chance))
  36. continue;
  37. if (autoEmotePrototype.WithChat)
  38. {
  39. _chatSystem.TryEmoteWithChat(uid, autoEmotePrototype.EmoteId, autoEmotePrototype.HiddenFromChatWindow ? ChatTransmitRange.HideChat : ChatTransmitRange.Normal);
  40. }
  41. else
  42. {
  43. _chatSystem.TryEmoteWithoutChat(uid, autoEmotePrototype.EmoteId);
  44. }
  45. }
  46. }
  47. }
  48. private void OnMapInit(EntityUid uid, AutoEmoteComponent autoEmote, MapInitEvent args)
  49. {
  50. // Start timers
  51. foreach (var autoEmotePrototypeId in autoEmote.Emotes)
  52. {
  53. ResetTimer(uid, autoEmotePrototypeId, autoEmote);
  54. }
  55. }
  56. private void OnUnpaused(EntityUid uid, AutoEmoteComponent autoEmote, ref EntityUnpausedEvent args)
  57. {
  58. foreach (var key in autoEmote.EmoteTimers.Keys)
  59. {
  60. autoEmote.EmoteTimers[key] += args.PausedTime;
  61. }
  62. autoEmote.NextEmoteTime += args.PausedTime;
  63. }
  64. /// <summary>
  65. /// Try to add an emote to the entity, which will be performed at an interval.
  66. /// </summary>
  67. public bool AddEmote(EntityUid uid, string autoEmotePrototypeId, AutoEmoteComponent? autoEmote = null)
  68. {
  69. if (!Resolve(uid, ref autoEmote, logMissing: false))
  70. return false;
  71. DebugTools.Assert(autoEmote.LifeStage <= ComponentLifeStage.Running);
  72. if (autoEmote.Emotes.Contains(autoEmotePrototypeId))
  73. return false;
  74. autoEmote.Emotes.Add(autoEmotePrototypeId);
  75. ResetTimer(uid, autoEmotePrototypeId, autoEmote);
  76. return true;
  77. }
  78. /// <summary>
  79. /// Stop preforming an emote. Note that by default this will queue empty components for removal.
  80. /// </summary>
  81. public bool RemoveEmote(EntityUid uid, string autoEmotePrototypeId, AutoEmoteComponent? autoEmote = null, bool removeEmpty = true)
  82. {
  83. if (!Resolve(uid, ref autoEmote, logMissing: false))
  84. return false;
  85. DebugTools.Assert(_prototypeManager.HasIndex<AutoEmotePrototype>(autoEmotePrototypeId), "Prototype not found. Did you make a typo?");
  86. if (!autoEmote.EmoteTimers.Remove(autoEmotePrototypeId))
  87. return false;
  88. if (autoEmote.EmoteTimers.Count > 0)
  89. autoEmote.NextEmoteTime = autoEmote.EmoteTimers.Values.Min();
  90. else if (removeEmpty)
  91. RemCompDeferred(uid, autoEmote);
  92. else
  93. autoEmote.NextEmoteTime = TimeSpan.MaxValue;
  94. return true;
  95. }
  96. /// <summary>
  97. /// Reset the timer for a specific emote, or return false if it doesn't exist.
  98. /// </summary>
  99. public bool ResetTimer(EntityUid uid, string autoEmotePrototypeId, AutoEmoteComponent? autoEmote = null, AutoEmotePrototype? autoEmotePrototype = null)
  100. {
  101. if (!Resolve(uid, ref autoEmote))
  102. return false;
  103. if (!autoEmote.Emotes.Contains(autoEmotePrototypeId))
  104. return false;
  105. autoEmotePrototype ??= _prototypeManager.Index<AutoEmotePrototype>(autoEmotePrototypeId);
  106. var curTime = _gameTiming.CurTime;
  107. var time = curTime + autoEmotePrototype.Interval;
  108. autoEmote.EmoteTimers[autoEmotePrototypeId] = time;
  109. if (autoEmote.NextEmoteTime > time || autoEmote.NextEmoteTime <= curTime)
  110. autoEmote.NextEmoteTime = time;
  111. return true;
  112. }
  113. }