1
0

AdvertiseSystem.cs 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106
  1. using Content.Server.Advertise.Components;
  2. using Content.Server.Chat.Systems;
  3. using Content.Server.Power.Components;
  4. using Content.Shared.VendingMachines;
  5. using Robust.Shared.Prototypes;
  6. using Robust.Shared.Random;
  7. using Robust.Shared.Timing;
  8. namespace Content.Server.Advertise.EntitySystems;
  9. public sealed class AdvertiseSystem : EntitySystem
  10. {
  11. [Dependency] private readonly IPrototypeManager _prototypeManager = default!;
  12. [Dependency] private readonly IRobustRandom _random = default!;
  13. [Dependency] private readonly IGameTiming _gameTiming = default!;
  14. [Dependency] private readonly ChatSystem _chat = default!;
  15. /// <summary>
  16. /// The maximum amount of time between checking if advertisements should be displayed
  17. /// </summary>
  18. private readonly TimeSpan _maximumNextCheckDuration = TimeSpan.FromSeconds(15);
  19. /// <summary>
  20. /// The next time the game will check if advertisements should be displayed
  21. /// </summary>
  22. private TimeSpan _nextCheckTime = TimeSpan.MinValue;
  23. public override void Initialize()
  24. {
  25. SubscribeLocalEvent<AdvertiseComponent, MapInitEvent>(OnMapInit);
  26. SubscribeLocalEvent<ApcPowerReceiverComponent, AttemptAdvertiseEvent>(OnPowerReceiverAttemptAdvertiseEvent);
  27. SubscribeLocalEvent<VendingMachineComponent, AttemptAdvertiseEvent>(OnVendingAttemptAdvertiseEvent);
  28. _nextCheckTime = TimeSpan.MinValue;
  29. }
  30. private void OnMapInit(EntityUid uid, AdvertiseComponent advert, MapInitEvent args)
  31. {
  32. var prewarm = advert.Prewarm;
  33. RandomizeNextAdvertTime(advert, prewarm);
  34. _nextCheckTime = MathHelper.Min(advert.NextAdvertisementTime, _nextCheckTime);
  35. }
  36. private void RandomizeNextAdvertTime(AdvertiseComponent advert, bool prewarm = false)
  37. {
  38. var minDuration = prewarm ? 0 : Math.Max(1, advert.MinimumWait);
  39. var maxDuration = Math.Max(minDuration, advert.MaximumWait);
  40. var waitDuration = TimeSpan.FromSeconds(_random.Next(minDuration, maxDuration));
  41. advert.NextAdvertisementTime = _gameTiming.CurTime + waitDuration;
  42. }
  43. public void SayAdvertisement(EntityUid uid, AdvertiseComponent? advert = null)
  44. {
  45. if (!Resolve(uid, ref advert))
  46. return;
  47. var attemptEvent = new AttemptAdvertiseEvent(uid);
  48. RaiseLocalEvent(uid, ref attemptEvent);
  49. if (attemptEvent.Cancelled)
  50. return;
  51. if (_prototypeManager.TryIndex(advert.Pack, out var advertisements))
  52. _chat.TrySendInGameICMessage(uid, Loc.GetString(_random.Pick(advertisements.Values)), InGameICChatType.Speak, hideChat: true);
  53. }
  54. public override void Update(float frameTime)
  55. {
  56. var currentGameTime = _gameTiming.CurTime;
  57. if (_nextCheckTime > currentGameTime)
  58. return;
  59. // _nextCheckTime starts at TimeSpan.MinValue, so this has to SET the value, not just increment it.
  60. _nextCheckTime = currentGameTime + _maximumNextCheckDuration;
  61. var query = EntityQueryEnumerator<AdvertiseComponent>();
  62. while (query.MoveNext(out var uid, out var advert))
  63. {
  64. if (currentGameTime > advert.NextAdvertisementTime)
  65. {
  66. SayAdvertisement(uid, advert);
  67. // The timer is always refreshed when it expires, to prevent mass advertising (ex: all the vending machines have no power, and get it back at the same time).
  68. RandomizeNextAdvertTime(advert);
  69. }
  70. _nextCheckTime = MathHelper.Min(advert.NextAdvertisementTime, _nextCheckTime);
  71. }
  72. }
  73. private static void OnPowerReceiverAttemptAdvertiseEvent(EntityUid uid, ApcPowerReceiverComponent powerReceiver, ref AttemptAdvertiseEvent args)
  74. {
  75. args.Cancelled |= !powerReceiver.Powered;
  76. }
  77. private static void OnVendingAttemptAdvertiseEvent(EntityUid uid, VendingMachineComponent machine, ref AttemptAdvertiseEvent args)
  78. {
  79. args.Cancelled |= machine.Broken;
  80. }
  81. }
  82. [ByRefEvent]
  83. public record struct AttemptAdvertiseEvent(EntityUid? Advertiser)
  84. {
  85. public bool Cancelled = false;
  86. }