ResearchConsoleMenu.xaml.cs 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183
  1. using System.Linq;
  2. using System.Numerics;
  3. using Content.Client.UserInterface.Controls;
  4. using Content.Shared.Access.Components;
  5. using Content.Shared.Access.Systems;
  6. using Content.Shared.Research.Components;
  7. using Content.Shared.Research.Prototypes;
  8. using Robust.Client.AutoGenerated;
  9. using Robust.Client.GameObjects;
  10. using Robust.Client.Player;
  11. using Robust.Client.UserInterface;
  12. using Robust.Client.UserInterface.Controls;
  13. using Robust.Client.UserInterface.XAML;
  14. using Robust.Shared.Prototypes;
  15. using Robust.Shared.Utility;
  16. namespace Content.Client.Research.UI;
  17. [GenerateTypedNameReferences]
  18. public sealed partial class ResearchConsoleMenu : FancyWindow
  19. {
  20. public Action<string>? OnTechnologyCardPressed;
  21. public Action? OnServerButtonPressed;
  22. [Dependency] private readonly IEntityManager _entity = default!;
  23. [Dependency] private readonly IPrototypeManager _prototype = default!;
  24. [Dependency] private readonly IPlayerManager _player = default!;
  25. private readonly ResearchSystem _research;
  26. private readonly SpriteSystem _sprite;
  27. private readonly AccessReaderSystem _accessReader;
  28. public EntityUid Entity;
  29. public ResearchConsoleMenu()
  30. {
  31. RobustXamlLoader.Load(this);
  32. IoCManager.InjectDependencies(this);
  33. _research = _entity.System<ResearchSystem>();
  34. _sprite = _entity.System<SpriteSystem>();
  35. _accessReader = _entity.System<AccessReaderSystem>();
  36. ServerButton.OnPressed += _ => OnServerButtonPressed?.Invoke();
  37. }
  38. public void SetEntity(EntityUid entity)
  39. {
  40. Entity = entity;
  41. }
  42. public void UpdatePanels(ResearchConsoleBoundInterfaceState state)
  43. {
  44. TechnologyCardsContainer.Children.Clear();
  45. var availableTech = _research.GetAvailableTechnologies(Entity);
  46. SyncTechnologyList(AvailableCardsContainer, availableTech);
  47. if (!_entity.TryGetComponent(Entity, out TechnologyDatabaseComponent? database))
  48. return;
  49. // i can't figure out the spacing so here you go
  50. TechnologyCardsContainer.AddChild(new Control
  51. {
  52. MinHeight = 10
  53. });
  54. var hasAccess = _player.LocalEntity is not { } local ||
  55. !_entity.TryGetComponent<AccessReaderComponent>(Entity, out var access) ||
  56. _accessReader.IsAllowed(local, Entity, access);
  57. foreach (var techId in database.CurrentTechnologyCards)
  58. {
  59. var tech = _prototype.Index<TechnologyPrototype>(techId);
  60. var cardControl = new TechnologyCardControl(tech, _prototype, _sprite, _research.GetTechnologyDescription(tech, includeTier: false), state.Points, hasAccess);
  61. cardControl.OnPressed += () => OnTechnologyCardPressed?.Invoke(techId);
  62. TechnologyCardsContainer.AddChild(cardControl);
  63. }
  64. var unlockedTech = database.UnlockedTechnologies.Select(x => _prototype.Index<TechnologyPrototype>(x));
  65. SyncTechnologyList(UnlockedCardsContainer, unlockedTech);
  66. }
  67. public void UpdateInformationPanel(ResearchConsoleBoundInterfaceState state)
  68. {
  69. var amountMsg = new FormattedMessage();
  70. amountMsg.AddMarkupOrThrow(Loc.GetString("research-console-menu-research-points-text",
  71. ("points", state.Points)));
  72. ResearchAmountLabel.SetMessage(amountMsg);
  73. if (!_entity.TryGetComponent(Entity, out TechnologyDatabaseComponent? database))
  74. return;
  75. var disciplineText = Loc.GetString("research-discipline-none");
  76. var disciplineColor = Color.Gray;
  77. if (database.MainDiscipline != null)
  78. {
  79. var discipline = _prototype.Index<TechDisciplinePrototype>(database.MainDiscipline);
  80. disciplineText = Loc.GetString(discipline.Name);
  81. disciplineColor = discipline.Color;
  82. }
  83. var msg = new FormattedMessage();
  84. msg.AddMarkupOrThrow(Loc.GetString("research-console-menu-main-discipline",
  85. ("name", disciplineText), ("color", disciplineColor)));
  86. MainDisciplineLabel.SetMessage(msg);
  87. TierDisplayContainer.Children.Clear();
  88. foreach (var disciplineId in database.SupportedDisciplines)
  89. {
  90. var discipline = _prototype.Index<TechDisciplinePrototype>(disciplineId);
  91. var tier = _research.GetHighestDisciplineTier(database, discipline);
  92. // don't show tiers with no available tech
  93. if (tier == 0)
  94. continue;
  95. // i'm building the small-ass control here to spare me some mild annoyance in making a new file
  96. var texture = new TextureRect
  97. {
  98. TextureScale = new Vector2( 2, 2 ),
  99. VerticalAlignment = VAlignment.Center
  100. };
  101. var label = new RichTextLabel();
  102. texture.Texture = _sprite.Frame0(discipline.Icon);
  103. label.SetMessage(Loc.GetString("research-console-tier-info-small", ("tier", tier)));
  104. var control = new BoxContainer
  105. {
  106. Children =
  107. {
  108. texture,
  109. label,
  110. new Control
  111. {
  112. MinWidth = 10
  113. }
  114. }
  115. };
  116. TierDisplayContainer.AddChild(control);
  117. }
  118. }
  119. /// <summary>
  120. /// Synchronize a container for technology cards with a list of technologies,
  121. /// creating or removing UI cards as appropriate.
  122. /// </summary>
  123. /// <param name="container">The container which contains the UI cards</param>
  124. /// <param name="technologies">The current set of technologies for which there should be cards</param>
  125. private void SyncTechnologyList(BoxContainer container, IEnumerable<TechnologyPrototype> technologies)
  126. {
  127. // For the cards which already exist, build a map from technology prototype to the UI card
  128. var currentTechControls = new Dictionary<TechnologyPrototype, Control>();
  129. foreach (var child in container.Children)
  130. {
  131. if (child is MiniTechnologyCardControl)
  132. {
  133. currentTechControls.Add((child as MiniTechnologyCardControl)!.Technology, child);
  134. }
  135. }
  136. foreach (var tech in technologies)
  137. {
  138. if (!currentTechControls.ContainsKey(tech))
  139. {
  140. // Create a card for any technology which doesn't already have one.
  141. var mini = new MiniTechnologyCardControl(tech, _prototype, _sprite, _research.GetTechnologyDescription(tech));
  142. container.AddChild(mini);
  143. }
  144. else
  145. {
  146. // The tech already exists in the UI; remove it from the set, so we won't revisit it below
  147. currentTechControls.Remove(tech);
  148. }
  149. }
  150. // Now, any items left in the dictionary are technologies which were previously
  151. // available, but now are not. Remove them.
  152. foreach (var (tech, techControl) in currentTechControls)
  153. {
  154. container.Children.Remove(techControl);
  155. }
  156. }
  157. }