1
0

DisposalUnitSystem.cs 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187
  1. using System.Diagnostics.CodeAnalysis;
  2. using Content.Shared.Disposal;
  3. using Content.Shared.Disposal.Components;
  4. using Content.Shared.DragDrop;
  5. using Content.Shared.Emag.Systems;
  6. using Robust.Client.GameObjects;
  7. using Robust.Client.Animations;
  8. using Robust.Client.Graphics;
  9. using Robust.Shared.Audio;
  10. using Robust.Shared.Audio.Systems;
  11. using Robust.Shared.GameStates;
  12. using Robust.Shared.Physics.Events;
  13. using static Content.Shared.Disposal.Components.SharedDisposalUnitComponent;
  14. namespace Content.Client.Disposal.Systems;
  15. public sealed class DisposalUnitSystem : SharedDisposalUnitSystem
  16. {
  17. [Dependency] private readonly AppearanceSystem _appearanceSystem = default!;
  18. [Dependency] private readonly AnimationPlayerSystem _animationSystem = default!;
  19. [Dependency] private readonly SharedAudioSystem _audioSystem = default!;
  20. private const string AnimationKey = "disposal_unit_animation";
  21. private const string DefaultFlushState = "disposal-flush";
  22. private const string DefaultChargeState = "disposal-charging";
  23. public override void Initialize()
  24. {
  25. base.Initialize();
  26. SubscribeLocalEvent<DisposalUnitComponent, ComponentHandleState>(OnHandleState);
  27. SubscribeLocalEvent<DisposalUnitComponent, PreventCollideEvent>(OnPreventCollide);
  28. SubscribeLocalEvent<DisposalUnitComponent, CanDropTargetEvent>(OnCanDragDropOn);
  29. SubscribeLocalEvent<DisposalUnitComponent, GotEmaggedEvent>(OnEmagged);
  30. SubscribeLocalEvent<DisposalUnitComponent, ComponentInit>(OnComponentInit);
  31. SubscribeLocalEvent<DisposalUnitComponent, AppearanceChangeEvent>(OnAppearanceChange);
  32. }
  33. private void OnHandleState(EntityUid uid, DisposalUnitComponent component, ref ComponentHandleState args)
  34. {
  35. if (args.Current is not DisposalUnitComponentState state)
  36. return;
  37. component.FlushSound = state.FlushSound;
  38. component.State = state.State;
  39. component.NextPressurized = state.NextPressurized;
  40. component.AutomaticEngageTime = state.AutomaticEngageTime;
  41. component.NextFlush = state.NextFlush;
  42. component.Powered = state.Powered;
  43. component.Engaged = state.Engaged;
  44. component.RecentlyEjected.Clear();
  45. component.RecentlyEjected.AddRange(EnsureEntityList<DisposalUnitComponent>(state.RecentlyEjected, uid));
  46. }
  47. public override bool HasDisposals(EntityUid? uid)
  48. {
  49. return HasComp<DisposalUnitComponent>(uid);
  50. }
  51. public override bool ResolveDisposals(EntityUid uid, [NotNullWhen(true)] ref SharedDisposalUnitComponent? component)
  52. {
  53. if (component != null)
  54. return true;
  55. TryComp<DisposalUnitComponent>(uid, out var storage);
  56. component = storage;
  57. return component != null;
  58. }
  59. public override void DoInsertDisposalUnit(EntityUid uid, EntityUid toInsert, EntityUid user, SharedDisposalUnitComponent? disposal = null)
  60. {
  61. return;
  62. }
  63. private void OnComponentInit(EntityUid uid, SharedDisposalUnitComponent sharedDisposalUnit, ComponentInit args)
  64. {
  65. if (!TryComp<SpriteComponent>(uid, out var sprite) || !TryComp<AppearanceComponent>(uid, out var appearance))
  66. return;
  67. UpdateState(uid, sharedDisposalUnit, sprite, appearance);
  68. }
  69. private void OnAppearanceChange(EntityUid uid, SharedDisposalUnitComponent unit, ref AppearanceChangeEvent args)
  70. {
  71. if (args.Sprite == null)
  72. return;
  73. UpdateState(uid, unit, args.Sprite, args.Component);
  74. }
  75. /// <summary>
  76. /// Update visuals and tick animation
  77. /// </summary>
  78. private void UpdateState(EntityUid uid, SharedDisposalUnitComponent unit, SpriteComponent sprite, AppearanceComponent appearance)
  79. {
  80. if (!_appearanceSystem.TryGetData<VisualState>(uid, Visuals.VisualState, out var state, appearance))
  81. return;
  82. sprite.LayerSetVisible(DisposalUnitVisualLayers.Unanchored, state == VisualState.UnAnchored);
  83. sprite.LayerSetVisible(DisposalUnitVisualLayers.Base, state == VisualState.Anchored);
  84. sprite.LayerSetVisible(DisposalUnitVisualLayers.OverlayFlush, state is VisualState.OverlayFlushing or VisualState.OverlayCharging);
  85. var chargingState = sprite.LayerMapTryGet(DisposalUnitVisualLayers.BaseCharging, out var chargingLayer)
  86. ? sprite.LayerGetState(chargingLayer)
  87. : new RSI.StateId(DefaultChargeState);
  88. // This is a transient state so not too worried about replaying in range.
  89. if (state == VisualState.OverlayFlushing)
  90. {
  91. if (!_animationSystem.HasRunningAnimation(uid, AnimationKey))
  92. {
  93. var flushState = sprite.LayerMapTryGet(DisposalUnitVisualLayers.OverlayFlush, out var flushLayer)
  94. ? sprite.LayerGetState(flushLayer)
  95. : new RSI.StateId(DefaultFlushState);
  96. // Setup the flush animation to play
  97. var anim = new Animation
  98. {
  99. Length = unit.FlushDelay,
  100. AnimationTracks =
  101. {
  102. new AnimationTrackSpriteFlick
  103. {
  104. LayerKey = DisposalUnitVisualLayers.OverlayFlush,
  105. KeyFrames =
  106. {
  107. // Play the flush animation
  108. new AnimationTrackSpriteFlick.KeyFrame(flushState, 0),
  109. // Return to base state (though, depending on how the unit is
  110. // configured we might get an appearance change event telling
  111. // us to go to charging state)
  112. new AnimationTrackSpriteFlick.KeyFrame(chargingState, (float) unit.FlushDelay.TotalSeconds)
  113. }
  114. },
  115. }
  116. };
  117. if (unit.FlushSound != null)
  118. {
  119. anim.AnimationTracks.Add(
  120. new AnimationTrackPlaySound
  121. {
  122. KeyFrames =
  123. {
  124. new AnimationTrackPlaySound.KeyFrame(_audioSystem.ResolveSound(unit.FlushSound), 0)
  125. }
  126. });
  127. }
  128. _animationSystem.Play(uid, anim, AnimationKey);
  129. }
  130. }
  131. else if (state == VisualState.OverlayCharging)
  132. sprite.LayerSetState(DisposalUnitVisualLayers.OverlayFlush, chargingState);
  133. else
  134. _animationSystem.Stop(uid, AnimationKey);
  135. if (!_appearanceSystem.TryGetData<HandleState>(uid, Visuals.Handle, out var handleState, appearance))
  136. handleState = HandleState.Normal;
  137. sprite.LayerSetVisible(DisposalUnitVisualLayers.OverlayEngaged, handleState != HandleState.Normal);
  138. if (!_appearanceSystem.TryGetData<LightStates>(uid, Visuals.Light, out var lightState, appearance))
  139. lightState = LightStates.Off;
  140. sprite.LayerSetVisible(DisposalUnitVisualLayers.OverlayCharging,
  141. (lightState & LightStates.Charging) != 0);
  142. sprite.LayerSetVisible(DisposalUnitVisualLayers.OverlayReady,
  143. (lightState & LightStates.Ready) != 0);
  144. sprite.LayerSetVisible(DisposalUnitVisualLayers.OverlayFull,
  145. (lightState & LightStates.Full) != 0);
  146. }
  147. }
  148. public enum DisposalUnitVisualLayers : byte
  149. {
  150. Unanchored,
  151. Base,
  152. BaseCharging,
  153. OverlayFlush,
  154. OverlayCharging,
  155. OverlayReady,
  156. OverlayFull,
  157. OverlayEngaged
  158. }