ShowHealthIconsSystem.cs 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990
  1. using Content.Shared.Atmos.Rotting;
  2. using Content.Shared.Damage;
  3. using Content.Shared.Inventory.Events;
  4. using Content.Shared.Mobs.Components;
  5. using Content.Shared.Overlays;
  6. using Content.Shared.StatusIcon;
  7. using Content.Shared.StatusIcon.Components;
  8. using Robust.Shared.Prototypes;
  9. using System.Linq;
  10. namespace Content.Client.Overlays;
  11. /// <summary>
  12. /// Shows a healthy icon on mobs.
  13. /// </summary>
  14. public sealed class ShowHealthIconsSystem : EquipmentHudSystem<ShowHealthIconsComponent>
  15. {
  16. [Dependency] private readonly IPrototypeManager _prototypeMan = default!;
  17. [ViewVariables]
  18. public HashSet<string> DamageContainers = new();
  19. public override void Initialize()
  20. {
  21. base.Initialize();
  22. SubscribeLocalEvent<DamageableComponent, GetStatusIconsEvent>(OnGetStatusIconsEvent);
  23. SubscribeLocalEvent<ShowHealthIconsComponent, AfterAutoHandleStateEvent>(OnHandleState);
  24. }
  25. protected override void UpdateInternal(RefreshEquipmentHudEvent<ShowHealthIconsComponent> component)
  26. {
  27. base.UpdateInternal(component);
  28. foreach (var damageContainerId in component.Components.SelectMany(x => x.DamageContainers))
  29. {
  30. DamageContainers.Add(damageContainerId);
  31. }
  32. }
  33. protected override void DeactivateInternal()
  34. {
  35. base.DeactivateInternal();
  36. DamageContainers.Clear();
  37. }
  38. private void OnHandleState(Entity<ShowHealthIconsComponent> ent, ref AfterAutoHandleStateEvent args)
  39. {
  40. RefreshOverlay();
  41. }
  42. private void OnGetStatusIconsEvent(Entity<DamageableComponent> entity, ref GetStatusIconsEvent args)
  43. {
  44. if (!IsActive)
  45. return;
  46. var healthIcons = DecideHealthIcons(entity);
  47. args.StatusIcons.AddRange(healthIcons);
  48. }
  49. private IReadOnlyList<HealthIconPrototype> DecideHealthIcons(Entity<DamageableComponent> entity)
  50. {
  51. var damageableComponent = entity.Comp;
  52. if (damageableComponent.DamageContainerID == null ||
  53. !DamageContainers.Contains(damageableComponent.DamageContainerID))
  54. {
  55. return Array.Empty<HealthIconPrototype>();
  56. }
  57. var result = new List<HealthIconPrototype>();
  58. // Here you could check health status, diseases, mind status, etc. and pick a good icon, or multiple depending on whatever.
  59. if (damageableComponent?.DamageContainerID == "Biological")
  60. {
  61. if (TryComp<MobStateComponent>(entity, out var state))
  62. {
  63. // Since there is no MobState for a rotting mob, we have to deal with this case first.
  64. if (HasComp<RottingComponent>(entity) && _prototypeMan.TryIndex(damageableComponent.RottingIcon, out var rottingIcon))
  65. result.Add(rottingIcon);
  66. else if (damageableComponent.HealthIcons.TryGetValue(state.CurrentState, out var value) && _prototypeMan.TryIndex(value, out var icon))
  67. result.Add(icon);
  68. }
  69. }
  70. return result;
  71. }
  72. }