HealthAnalyzerWindow.xaml.cs 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247
  1. using System.Linq;
  2. using System.Numerics;
  3. using Content.Client.Message;
  4. using Content.Shared.Atmos;
  5. using Content.Client.UserInterface.Controls;
  6. using Content.Shared.Alert;
  7. using Content.Shared.Damage;
  8. using Content.Shared.Damage.Prototypes;
  9. using Content.Shared.FixedPoint;
  10. using Content.Shared.Humanoid;
  11. using Content.Shared.Humanoid.Prototypes;
  12. using Content.Shared.IdentityManagement;
  13. using Content.Shared.Inventory;
  14. using Content.Shared.MedicalScanner;
  15. using Content.Shared.Mobs;
  16. using Content.Shared.Mobs.Components;
  17. using Content.Shared.Mobs.Systems;
  18. using Content.Shared.Nutrition.Components;
  19. using Robust.Client.AutoGenerated;
  20. using Robust.Client.UserInterface.XAML;
  21. using Robust.Client.GameObjects;
  22. using Robust.Client.Graphics;
  23. using Robust.Client.UserInterface.Controls;
  24. using Robust.Client.ResourceManagement;
  25. using Robust.Client.UserInterface;
  26. using Robust.Shared.Prototypes;
  27. using Robust.Shared.Utility;
  28. namespace Content.Client.HealthAnalyzer.UI
  29. {
  30. [GenerateTypedNameReferences]
  31. public sealed partial class HealthAnalyzerWindow : FancyWindow
  32. {
  33. private readonly IEntityManager _entityManager;
  34. private readonly SpriteSystem _spriteSystem;
  35. private readonly IPrototypeManager _prototypes;
  36. private readonly IResourceCache _cache;
  37. public HealthAnalyzerWindow()
  38. {
  39. RobustXamlLoader.Load(this);
  40. var dependencies = IoCManager.Instance!;
  41. _entityManager = dependencies.Resolve<IEntityManager>();
  42. _spriteSystem = _entityManager.System<SpriteSystem>();
  43. _prototypes = dependencies.Resolve<IPrototypeManager>();
  44. _cache = dependencies.Resolve<IResourceCache>();
  45. }
  46. public void Populate(HealthAnalyzerScannedUserMessage msg)
  47. {
  48. var target = _entityManager.GetEntity(msg.TargetEntity);
  49. if (target == null
  50. || !_entityManager.TryGetComponent<DamageableComponent>(target, out var damageable))
  51. {
  52. NoPatientDataText.Visible = true;
  53. return;
  54. }
  55. NoPatientDataText.Visible = false;
  56. // Scan Mode
  57. ScanModeLabel.Text = msg.ScanMode.HasValue
  58. ? msg.ScanMode.Value
  59. ? Loc.GetString("health-analyzer-window-scan-mode-active")
  60. : Loc.GetString("health-analyzer-window-scan-mode-inactive")
  61. : Loc.GetString("health-analyzer-window-entity-unknown-text");
  62. ScanModeLabel.FontColorOverride = msg.ScanMode.HasValue && msg.ScanMode.Value ? Color.Green : Color.Red;
  63. // Patient Information
  64. SpriteView.SetEntity(target.Value);
  65. SpriteView.Visible = msg.ScanMode.HasValue && msg.ScanMode.Value;
  66. NoDataTex.Visible = !SpriteView.Visible;
  67. var name = new FormattedMessage();
  68. name.PushColor(Color.White);
  69. name.AddText(_entityManager.HasComponent<MetaDataComponent>(target.Value)
  70. ? Identity.Name(target.Value, _entityManager)
  71. : Loc.GetString("health-analyzer-window-entity-unknown-text"));
  72. NameLabel.SetMessage(name);
  73. SpeciesLabel.Text =
  74. _entityManager.TryGetComponent<HumanoidAppearanceComponent>(target.Value,
  75. out var humanoidAppearanceComponent)
  76. ? Loc.GetString(_prototypes.Index<SpeciesPrototype>(humanoidAppearanceComponent.Species).Name)
  77. : Loc.GetString("health-analyzer-window-entity-unknown-species-text");
  78. // Basic Diagnostic
  79. TemperatureLabel.Text = !float.IsNaN(msg.Temperature)
  80. ? $"{msg.Temperature - Atmospherics.T0C:F1} °C ({msg.Temperature:F1} K)"
  81. : Loc.GetString("health-analyzer-window-entity-unknown-value-text");
  82. BloodLabel.Text = !float.IsNaN(msg.BloodLevel)
  83. ? $"{msg.BloodLevel * 100:F1} %"
  84. : Loc.GetString("health-analyzer-window-entity-unknown-value-text");
  85. StatusLabel.Text =
  86. _entityManager.TryGetComponent<MobStateComponent>(target.Value, out var mobStateComponent)
  87. ? GetStatus(mobStateComponent.CurrentState)
  88. : Loc.GetString("health-analyzer-window-entity-unknown-text");
  89. // Total Damage
  90. DamageLabel.Text = damageable.TotalDamage.ToString();
  91. // Alerts
  92. var showAlerts = msg.Unrevivable == true || msg.Bleeding == true;
  93. AlertsDivider.Visible = showAlerts;
  94. AlertsContainer.Visible = showAlerts;
  95. if (showAlerts)
  96. AlertsContainer.DisposeAllChildren();
  97. if (msg.Unrevivable == true)
  98. AlertsContainer.AddChild(new RichTextLabel
  99. {
  100. Text = Loc.GetString("health-analyzer-window-entity-unrevivable-text"),
  101. Margin = new Thickness(0, 4),
  102. MaxWidth = 300
  103. });
  104. if (msg.Bleeding == true)
  105. AlertsContainer.AddChild(new RichTextLabel
  106. {
  107. Text = Loc.GetString("health-analyzer-window-entity-bleeding-text"),
  108. Margin = new Thickness(0, 4),
  109. MaxWidth = 300
  110. });
  111. // Damage Groups
  112. var damageSortedGroups =
  113. damageable.DamagePerGroup.OrderByDescending(damage => damage.Value)
  114. .ToDictionary(x => x.Key, x => x.Value);
  115. IReadOnlyDictionary<string, FixedPoint2> damagePerType = damageable.Damage.DamageDict;
  116. DrawDiagnosticGroups(damageSortedGroups, damagePerType);
  117. }
  118. private static string GetStatus(MobState mobState)
  119. {
  120. return mobState switch
  121. {
  122. MobState.Alive => Loc.GetString("health-analyzer-window-entity-alive-text"),
  123. MobState.Critical => Loc.GetString("health-analyzer-window-entity-critical-text"),
  124. MobState.Dead => Loc.GetString("health-analyzer-window-entity-dead-text"),
  125. _ => Loc.GetString("health-analyzer-window-entity-unknown-text"),
  126. };
  127. }
  128. private void DrawDiagnosticGroups(
  129. Dictionary<string, FixedPoint2> groups,
  130. IReadOnlyDictionary<string, FixedPoint2> damageDict)
  131. {
  132. GroupsContainer.RemoveAllChildren();
  133. foreach (var (damageGroupId, damageAmount) in groups)
  134. {
  135. if (damageAmount == 0)
  136. continue;
  137. var groupTitleText = $"{Loc.GetString(
  138. "health-analyzer-window-damage-group-text",
  139. ("damageGroup", _prototypes.Index<DamageGroupPrototype>(damageGroupId).LocalizedName),
  140. ("amount", damageAmount)
  141. )}";
  142. var groupContainer = new BoxContainer
  143. {
  144. Align = BoxContainer.AlignMode.Begin,
  145. Orientation = BoxContainer.LayoutOrientation.Vertical,
  146. };
  147. groupContainer.AddChild(CreateDiagnosticGroupTitle(groupTitleText, damageGroupId));
  148. GroupsContainer.AddChild(groupContainer);
  149. // Show the damage for each type in that group.
  150. var group = _prototypes.Index<DamageGroupPrototype>(damageGroupId);
  151. foreach (var type in group.DamageTypes)
  152. {
  153. if (!damageDict.TryGetValue(type, out var typeAmount) || typeAmount <= 0)
  154. continue;
  155. var damageString = Loc.GetString(
  156. "health-analyzer-window-damage-type-text",
  157. ("damageType", _prototypes.Index<DamageTypePrototype>(type).LocalizedName),
  158. ("amount", typeAmount)
  159. );
  160. groupContainer.AddChild(CreateDiagnosticItemLabel(damageString.Insert(0, " · ")));
  161. }
  162. }
  163. }
  164. private Texture GetTexture(string texture)
  165. {
  166. var rsiPath = new ResPath("/Textures/Objects/Devices/health_analyzer.rsi");
  167. var rsiSprite = new SpriteSpecifier.Rsi(rsiPath, texture);
  168. var rsi = _cache.GetResource<RSIResource>(rsiSprite.RsiPath).RSI;
  169. if (!rsi.TryGetState(rsiSprite.RsiState, out var state))
  170. {
  171. rsiSprite = new SpriteSpecifier.Rsi(rsiPath, "unknown");
  172. }
  173. return _spriteSystem.Frame0(rsiSprite);
  174. }
  175. private static Label CreateDiagnosticItemLabel(string text)
  176. {
  177. return new Label
  178. {
  179. Text = text,
  180. };
  181. }
  182. private BoxContainer CreateDiagnosticGroupTitle(string text, string id)
  183. {
  184. var rootContainer = new BoxContainer
  185. {
  186. Margin = new Thickness(0, 6, 0, 0),
  187. VerticalAlignment = VAlignment.Bottom,
  188. Orientation = BoxContainer.LayoutOrientation.Horizontal,
  189. };
  190. rootContainer.AddChild(new TextureRect
  191. {
  192. SetSize = new Vector2(30, 30),
  193. Texture = GetTexture(id.ToLower())
  194. });
  195. rootContainer.AddChild(CreateDiagnosticItemLabel(text));
  196. return rootContainer;
  197. }
  198. }
  199. }