+using System.Linq;
using System.Numerics;
-using System.Text;
using Content.Shared.Damage;
using Content.Shared.Damage.Prototypes;
using Content.Shared.FixedPoint;
using Robust.Client.AutoGenerated;
using Robust.Client.UserInterface.CustomControls;
using Robust.Client.UserInterface.XAML;
+using Robust.Client.GameObjects;
+using Robust.Client.Graphics;
+using Robust.Client.UserInterface.Controls;
+using Robust.Client.ResourceManagement;
using Robust.Shared.Prototypes;
+using Robust.Shared.Utility;
namespace Content.Client.HealthAnalyzer.UI
{
[GenerateTypedNameReferences]
public sealed partial class HealthAnalyzerWindow : DefaultWindow
{
+ private readonly IEntityManager _entityManager;
+ private readonly SpriteSystem _spriteSystem;
+ private readonly IPrototypeManager _prototypes;
+ private readonly IResourceCache _cache;
+
+ private const int AnalyzerHeight = 430;
+ private const int AnalyzerWidth = 300;
+
public HealthAnalyzerWindow()
{
RobustXamlLoader.Load(this);
+
+ var dependencies = IoCManager.Instance!;
+ _entityManager = dependencies.Resolve<IEntityManager>();
+ _spriteSystem = _entityManager.System<SpriteSystem>();
+ _prototypes = dependencies.Resolve<IPrototypeManager>();
+ _cache = dependencies.Resolve<IResourceCache>();
}
public void Populate(HealthAnalyzerScannedUserMessage msg)
{
- var text = new StringBuilder();
- var entities = IoCManager.Resolve<IEntityManager>();
- var target = entities.GetEntity(msg.TargetEntity);
+ GroupsContainer.RemoveAllChildren();
- if (msg.TargetEntity != null && entities.TryGetComponent<DamageableComponent>(target, out var damageable))
+ var target = _entityManager.GetEntity(msg.TargetEntity);
+
+ if (target == null
+ || !_entityManager.TryGetComponent<DamageableComponent>(target, out var damageable))
{
- string entityName = "Unknown";
- if (msg.TargetEntity != null &&
- entities.HasComponent<MetaDataComponent>(target.Value))
- {
- entityName = Identity.Name(target.Value, entities);
- }
+ NoPatientDataText.Visible = true;
+ return;
+ }
+
+ NoPatientDataText.Visible = false;
+
+ string entityName = Loc.GetString("health-analyzer-window-entity-unknown-text");
+ if (_entityManager.HasComponent<MetaDataComponent>(target.Value))
+ {
+ entityName = Identity.Name(target.Value, _entityManager);
+ }
- IReadOnlyDictionary<string, FixedPoint2> damagePerGroup = damageable.DamagePerGroup;
- IReadOnlyDictionary<string, FixedPoint2> damagePerType = damageable.Damage.DamageDict;
+ PatientName.Text = Loc.GetString(
+ "health-analyzer-window-entity-health-text",
+ ("entityName", entityName)
+ );
- text.Append($"{Loc.GetString("health-analyzer-window-entity-health-text", ("entityName", entityName))}\n\n");
+ Temperature.Text = Loc.GetString("health-analyzer-window-entity-temperature-text",
+ ("temperature", float.IsNaN(msg.Temperature) ? "N/A" : $"{msg.Temperature - 273f:F1} °C")
+ );
+ BloodLevel.Text = Loc.GetString("health-analyzer-window-entity-blood-level-text",
+ ("bloodLevel", float.IsNaN(msg.BloodLevel) ? "N/A" : $"{msg.BloodLevel * 100:F1} %")
+ );
- text.Append($"{Loc.GetString("health-analyzer-window-entity-temperature-text", ("temperature", float.IsNaN(msg.Temperature) ? "N/A" : $"{msg.Temperature - 273f:F1} °C"))}\n");
+ patientDamageAmount.Text = Loc.GetString(
+ "health-analyzer-window-entity-damage-total-text",
+ ("amount", damageable.TotalDamage)
+ );
+ var damageSortedGroups =
+ damageable.DamagePerGroup.OrderBy(damage => damage.Value)
+ .ToDictionary(x => x.Key, x => x.Value);
+ IReadOnlyDictionary<string, FixedPoint2> damagePerType = damageable.Damage.DamageDict;
- text.Append($"{Loc.GetString("health-analyzer-window-entity-blood-level-text", ("bloodLevel", float.IsNaN(msg.BloodLevel) ? "N/A" : $"{msg.BloodLevel * 100:F1} %"))}\n\n");
+ DrawDiagnosticGroups(damageSortedGroups, damagePerType);
+ SetHeight = AnalyzerHeight;
+ SetWidth = AnalyzerWidth;
+ }
- // Damage
- text.Append($"{Loc.GetString("health-analyzer-window-entity-damage-total-text", ("amount", damageable.TotalDamage))}\n");
+ private void DrawDiagnosticGroups(
+ Dictionary<string, FixedPoint2> groups, IReadOnlyDictionary<string, FixedPoint2> damageDict)
+ {
+ HashSet<string> shownTypes = new();
- HashSet<string> shownTypes = new();
+ // Show the total damage and type breakdown for each damage group.
+ foreach (var (damageGroupId, damageAmount) in groups.Reverse())
+ {
+ if (damageAmount == 0)
+ continue;
- var protos = IoCManager.Resolve<IPrototypeManager>();
+ var groupTitleText = $"{Loc.GetString(
+ "health-analyzer-window-damage-group-text",
+ ("damageGroup", Loc.GetString("health-analyzer-window-damage-group-" + damageGroupId)),
+ ("amount", damageAmount)
+ )}";
- // Show the total damage and type breakdown for each damage group.
- foreach (var (damageGroupId, damageAmount) in damagePerGroup)
+ var groupContainer = new BoxContainer
{
- if (damageAmount == 0)
- {
- continue;
- }
- text.Append($"\n{Loc.GetString("health-analyzer-window-damage-group-text", ("damageGroup", Loc.GetString("health-analyzer-window-damage-group-" + damageGroupId)), ("amount", damageAmount))}");
+ Margin = new Thickness(0, 0, 0, 15),
+ Align = BoxContainer.AlignMode.Begin,
+ Orientation = BoxContainer.LayoutOrientation.Vertical,
+ };
+
+ groupContainer.AddChild(CreateDiagnosticGroupTitle(groupTitleText, damageGroupId, damageAmount.Int()));
+
+ GroupsContainer.AddChild(groupContainer);
- // Show the damage for each type in that group.
- var group = protos.Index<DamageGroupPrototype>(damageGroupId);
- foreach (var type in group.DamageTypes)
+ // Show the damage for each type in that group.
+ var group = _prototypes.Index<DamageGroupPrototype>(damageGroupId);
+
+ foreach (var type in group.DamageTypes)
+ {
+ if (damageDict.TryGetValue(type, out var typeAmount) && typeAmount > 0)
{
- if (damagePerType.TryGetValue(type, out var typeAmount) )
- {
- // If damage types are allowed to belong to more than one damage group, they may appear twice here. Mark them as duplicate.
- if (!shownTypes.Contains(type) && typeAmount > 0)
- {
- shownTypes.Add(type);
- text.Append($"\n- {Loc.GetString("health-analyzer-window-damage-type-text", ("damageType", Loc.GetString("health-analyzer-window-damage-type-" + type)), ("amount", typeAmount))}");
- }
- }
+ // If damage types are allowed to belong to more than one damage group,
+ // they may appear twice here. Mark them as duplicate.
+ if (shownTypes.Contains(type))
+ continue;
+
+ shownTypes.Add(type);
+
+ var damageString = Loc.GetString(
+ "health-analyzer-window-damage-type-text",
+ ("damageType", Loc.GetString("health-analyzer-window-damage-type-" + type)),
+ ("amount", typeAmount)
+ );
+
+ groupContainer.AddChild(CreateDiagnosticItemLabel(damageString.Insert(0, "- ")));
}
- text.AppendLine();
}
- Diagnostics.Text = text.ToString();
- SetSize = new Vector2(250, 600);
}
- else
+ }
+
+ private Texture GetTexture(string texture)
+ {
+ var rsiPath = new ResPath("/Textures/Objects/Devices/health_analyzer.rsi");
+ var rsiSprite = new SpriteSpecifier.Rsi(rsiPath, texture);
+
+ var rsi = _cache.GetResource<RSIResource>(rsiSprite.RsiPath).RSI;
+ if (!rsi.TryGetState(rsiSprite.RsiState, out var state))
{
- Diagnostics.Text = Loc.GetString("health-analyzer-window-no-patient-data-text");
- SetSize = new Vector2(250, 100);
+ rsiSprite = new SpriteSpecifier.Rsi(rsiPath, "unknown");
}
+
+ return _spriteSystem.Frame0(rsiSprite);
+ }
+
+ private static Label CreateDiagnosticItemLabel(string text)
+ {
+ return new Label
+ {
+ Margin = new Thickness(2, 2),
+ Text = text,
+ };
+ }
+
+ private BoxContainer CreateDiagnosticGroupTitle(string text, string id, int damageAmount)
+ {
+ var rootContainer = new BoxContainer
+ {
+ VerticalAlignment = VAlignment.Bottom,
+ Orientation = BoxContainer.LayoutOrientation.Horizontal
+ };
+
+ rootContainer.AddChild(new TextureRect
+ {
+ Margin = new Thickness(0, 3),
+ SetSize = new Vector2(30, 30),
+ Texture = GetTexture(id.ToLower())
+ });
+
+ rootContainer.AddChild(CreateDiagnosticItemLabel(text));
+
+ return rootContainer;
}
}
}