1
0

ParticleAcceleratorControlMenu.xaml.cs 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322
  1. using System.Numerics;
  2. using Content.Client.Message;
  3. using Content.Client.Resources;
  4. using Content.Client.UserInterface.Controls;
  5. using Content.Shared.Singularity.Components;
  6. using Content.Shared.Access.Systems;
  7. using Robust.Client.Animations;
  8. using Robust.Client.AutoGenerated;
  9. using Robust.Client.Graphics;
  10. using Robust.Client.ResourceManagement;
  11. using Robust.Client.UserInterface;
  12. using Robust.Client.UserInterface.Controls;
  13. using Robust.Client.UserInterface.XAML;
  14. using Robust.Shared.Noise;
  15. using Robust.Shared.Prototypes;
  16. using Robust.Shared.Timing;
  17. using Robust.Client.Player;
  18. namespace Content.Client.ParticleAccelerator.UI;
  19. [GenerateTypedNameReferences]
  20. public sealed partial class ParticleAcceleratorControlMenu : FancyWindow
  21. {
  22. [Dependency] private readonly IResourceCache _cache = default!;
  23. [Dependency] private readonly IEntityManager _entityManager = default!;
  24. [Dependency] private readonly IPlayerManager _player = default!;
  25. private readonly AccessReaderSystem _accessReader;
  26. private readonly FastNoiseLite _drawNoiseGenerator;
  27. private readonly Animation _alarmControlAnimation;
  28. private float _time;
  29. private int _lastDraw;
  30. private int _lastReceive;
  31. private bool _assembled;
  32. private bool _shouldContinueAnimating;
  33. private int _maxStrength = 3;
  34. public event Action<bool>? OnOverallState;
  35. public event Action? OnScan;
  36. public event Action<ParticleAcceleratorPowerState>? OnPowerState;
  37. private EntityUid _entity;
  38. public ParticleAcceleratorControlMenu()
  39. {
  40. RobustXamlLoader.Load(this);
  41. IoCManager.InjectDependencies(this);
  42. _accessReader = _entityManager.System<AccessReaderSystem>();
  43. _drawNoiseGenerator = new();
  44. _drawNoiseGenerator.SetFractalType(FastNoiseLite.FractalType.FBm);
  45. _drawNoiseGenerator.SetFrequency(0.5f);
  46. var panelTex = _cache.GetTexture("/Textures/Interface/Nano/button.svg.96dpi.png");
  47. MouseFilter = MouseFilterMode.Stop;
  48. _alarmControlAnimation = new Animation
  49. {
  50. Length = TimeSpan.FromSeconds(1),
  51. AnimationTracks =
  52. {
  53. new AnimationTrackControlProperty
  54. {
  55. Property = nameof(Visible),
  56. KeyFrames =
  57. {
  58. new AnimationTrackProperty.KeyFrame(true, 0),
  59. new AnimationTrackProperty.KeyFrame(false, 0.75f),
  60. }
  61. }
  62. }
  63. };
  64. if (BackPanel.PanelOverride is StyleBoxTexture tex)
  65. tex.Texture = panelTex;
  66. StatusLabel.SetMarkup(Loc.GetString("particle-accelerator-control-menu-status-label"));
  67. StatusStateLabel.SetMarkup(Loc.GetString("particle-accelerator-control-menu-status-unknown"));
  68. PowerLabel.SetMarkup(Loc.GetString("particle-accelerator-control-menu-power-label"));
  69. StrengthLabel.SetMarkup(Loc.GetString("particle-accelerator-control-menu-strength-label"));
  70. BigAlarmLabel.SetMarkup(Loc.GetString("particle-accelerator-control-menu-alarm-control-1"));
  71. BigAlarmLabelTwo.SetMarkup(Loc.GetString("particle-accelerator-control-menu-alarm-control-2"));
  72. DrawLabel.SetMarkup(Loc.GetString("particle-accelerator-control-menu-draw"));
  73. StateSpinBox.IsValid = StrengthSpinBoxValid;
  74. StateSpinBox.InitDefaultButtons();
  75. StateSpinBox.ValueChanged += PowerStateChanged;
  76. StateSpinBox.LineEditDisabled = true;
  77. OffButton.OnPressed += _ =>
  78. {
  79. OnOverallState?.Invoke(false);
  80. };
  81. OnButton.OnPressed += _ =>
  82. {
  83. OnOverallState?.Invoke(true);
  84. };
  85. ScanButton.OnPressed += _ =>
  86. {
  87. OnScan?.Invoke();
  88. };
  89. AlarmControl.AnimationCompleted += _ =>
  90. {
  91. if (_shouldContinueAnimating)
  92. {
  93. AlarmControl.PlayAnimation(_alarmControlAnimation, "warningAnim");
  94. }
  95. else
  96. {
  97. AlarmControl.Visible = false;
  98. }
  99. };
  100. UpdateUI(false, false, false, false);
  101. }
  102. public void SetEntity(EntityUid uid)
  103. {
  104. _entity = uid;
  105. }
  106. private void PowerStateChanged(ValueChangedEventArgs e)
  107. {
  108. ParticleAcceleratorPowerState newState;
  109. switch (e.Value)
  110. {
  111. case 0:
  112. newState = ParticleAcceleratorPowerState.Standby;
  113. break;
  114. case 1:
  115. newState = ParticleAcceleratorPowerState.Level0;
  116. break;
  117. case 2:
  118. newState = ParticleAcceleratorPowerState.Level1;
  119. break;
  120. case 3:
  121. newState = ParticleAcceleratorPowerState.Level2;
  122. break;
  123. case 4:
  124. newState = ParticleAcceleratorPowerState.Level3;
  125. break;
  126. default:
  127. return;
  128. }
  129. StateSpinBox.SetButtonDisabled(true);
  130. OnPowerState?.Invoke(newState);
  131. }
  132. private bool StrengthSpinBoxValid(int n)
  133. {
  134. return n >= 0 && n <= _maxStrength;
  135. }
  136. protected override DragMode GetDragModeFor(Vector2 relativeMousePos)
  137. {
  138. return DragMode.Move;
  139. }
  140. public void DataUpdate(ParticleAcceleratorUIState uiState)
  141. {
  142. _assembled = uiState.Assembled;
  143. UpdateUI(uiState.Assembled,
  144. uiState.InterfaceBlock,
  145. uiState.Enabled,
  146. uiState.WirePowerBlock);
  147. StatusStateLabel.SetMarkup(Loc.GetString(uiState.Assembled
  148. ? "particle-accelerator-control-menu-status-operational"
  149. : "particle-accelerator-control-menu-status-incomplete"));
  150. UpdatePowerState(uiState.State, uiState.Enabled, uiState.Assembled, uiState.MaxLevel);
  151. UpdatePreview(uiState);
  152. _lastDraw = uiState.PowerDraw;
  153. _lastReceive = uiState.PowerReceive;
  154. }
  155. private void UpdatePowerState(ParticleAcceleratorPowerState state, bool enabled, bool assembled, ParticleAcceleratorPowerState maxState)
  156. {
  157. var value = state switch
  158. {
  159. ParticleAcceleratorPowerState.Standby => 0,
  160. ParticleAcceleratorPowerState.Level0 => 1,
  161. ParticleAcceleratorPowerState.Level1 => 2,
  162. ParticleAcceleratorPowerState.Level2 => 3,
  163. ParticleAcceleratorPowerState.Level3 => 4,
  164. _ => 0
  165. };
  166. StateSpinBox.OverrideValue(value);
  167. _maxStrength = maxState == ParticleAcceleratorPowerState.Level3 ? 4 : 3;
  168. if (_maxStrength > 3 && enabled && assembled)
  169. {
  170. _shouldContinueAnimating = true;
  171. if (!AlarmControl.HasRunningAnimation("warningAnim"))
  172. AlarmControl.PlayAnimation(_alarmControlAnimation, "warningAnim");
  173. }
  174. else
  175. _shouldContinueAnimating = false;
  176. }
  177. private void UpdateUI(bool assembled, bool blocked, bool enabled, bool powerBlock)
  178. {
  179. bool hasAccess = _player.LocalSession?.AttachedEntity is {} player
  180. && _accessReader.IsAllowed(player, _entity);
  181. OnButton.Pressed = enabled;
  182. OffButton.Pressed = !enabled;
  183. var cantUse = !assembled || blocked || powerBlock || !hasAccess;
  184. OnButton.Disabled = cantUse;
  185. OffButton.Disabled = cantUse;
  186. ScanButton.Disabled = blocked || !hasAccess;
  187. var cantChangeLevel = !assembled || blocked || !enabled || cantUse;
  188. StateSpinBox.SetButtonDisabled(cantChangeLevel);
  189. }
  190. private void UpdatePreview(ParticleAcceleratorUIState updateMessage)
  191. {
  192. EndCapTexture.SetPowerState(updateMessage, updateMessage.EndCapExists);
  193. ControlBoxTexture.SetPowerState(updateMessage, true);
  194. FuelChamberTexture.SetPowerState(updateMessage, updateMessage.FuelChamberExists);
  195. PowerBoxTexture.SetPowerState(updateMessage, updateMessage.PowerBoxExists);
  196. EmitterStarboardTexture.SetPowerState(updateMessage, updateMessage.EmitterStarboardExists);
  197. EmitterForeTexture.SetPowerState(updateMessage, updateMessage.EmitterForeExists);
  198. EmitterPortTexture.SetPowerState(updateMessage, updateMessage.EmitterPortExists);
  199. }
  200. protected override void FrameUpdate(FrameEventArgs args)
  201. {
  202. base.FrameUpdate(args);
  203. if (!_assembled)
  204. {
  205. DrawValueLabel.SetMarkup(Loc.GetString("particle-accelerator-control-menu-draw-not-available"));
  206. return;
  207. }
  208. _time += args.DeltaSeconds;
  209. var watts = 0;
  210. if (_lastDraw != 0)
  211. {
  212. var val = _drawNoiseGenerator.GetNoise(_time, 0f);
  213. watts = (int) (_lastDraw + val * 5);
  214. }
  215. DrawValueLabel.SetMarkup(Loc.GetString("particle-accelerator-control-menu-draw-value",
  216. ("watts", $"{watts:##,##0}"),
  217. ("lastReceive", $"{_lastReceive:##,##0}")));
  218. }
  219. }
  220. public sealed class PASegmentControl : Control
  221. {
  222. private readonly ShaderInstance _greyScaleShader;
  223. private readonly TextureRect _base;
  224. private readonly TextureRect _unlit;
  225. private RSI? _rsi;
  226. public string BaseState { get; set; } = "control_box";
  227. public PASegmentControl()
  228. {
  229. _greyScaleShader = IoCManager.Resolve<IPrototypeManager>().Index<ShaderPrototype>("Greyscale").Instance();
  230. AddChild(_base = new TextureRect());
  231. AddChild(_unlit = new TextureRect());
  232. }
  233. protected override void EnteredTree()
  234. {
  235. base.EnteredTree();
  236. _rsi = IoCManager.Resolve<IResourceCache>().GetResource<RSIResource>($"/Textures/Structures/Power/Generation/PA/{BaseState}.rsi").RSI;
  237. MinSize = _rsi.Size;
  238. _base.Texture = _rsi["completed"].Frame0;
  239. }
  240. public void SetPowerState(ParticleAcceleratorUIState state, bool exists)
  241. {
  242. _base.ShaderOverride = exists ? null : _greyScaleShader;
  243. _base.ModulateSelfOverride = exists ? null : new Color(127, 127, 127);
  244. if (!state.Enabled || !exists)
  245. {
  246. _unlit.Visible = false;
  247. return;
  248. }
  249. _unlit.Visible = true;
  250. var suffix = state.State switch
  251. {
  252. ParticleAcceleratorPowerState.Standby => "_unlitp",
  253. ParticleAcceleratorPowerState.Level0 => "_unlitp0",
  254. ParticleAcceleratorPowerState.Level1 => "_unlitp1",
  255. ParticleAcceleratorPowerState.Level2 => "_unlitp2",
  256. ParticleAcceleratorPowerState.Level3 => "_unlitp3",
  257. _ => ""
  258. };
  259. if (_rsi == null)
  260. return;
  261. if (!_rsi.TryGetState(BaseState + suffix, out var rState))
  262. {
  263. _unlit.Visible = false;
  264. return;
  265. }
  266. _unlit.Texture = rState.Frame0;
  267. }
  268. }