StethoscopeSystem.cs 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153
  1. using Content.Server.Body.Components;
  2. using Content.Server.Medical.Components;
  3. using Content.Server.Medical.Stethoscope.Components;
  4. using Content.Server.Popups;
  5. using Content.Shared.Actions;
  6. using Content.Shared.Clothing;
  7. using Content.Shared.Damage;
  8. using Content.Shared.DoAfter;
  9. using Content.Shared.FixedPoint;
  10. using Content.Shared.Medical;
  11. using Content.Shared.Medical.Stethoscope;
  12. using Content.Shared.Mobs.Components;
  13. using Content.Shared.Mobs.Systems;
  14. using Content.Shared.Verbs;
  15. using Robust.Shared.Utility;
  16. namespace Content.Server.Medical.Stethoscope
  17. {
  18. public sealed class StethoscopeSystem : EntitySystem
  19. {
  20. [Dependency] private readonly PopupSystem _popupSystem = default!;
  21. [Dependency] private readonly SharedDoAfterSystem _doAfterSystem = default!;
  22. [Dependency] private readonly MobStateSystem _mobStateSystem = default!;
  23. public override void Initialize()
  24. {
  25. base.Initialize();
  26. SubscribeLocalEvent<StethoscopeComponent, ClothingGotEquippedEvent>(OnEquipped);
  27. SubscribeLocalEvent<StethoscopeComponent, ClothingGotUnequippedEvent>(OnUnequipped);
  28. SubscribeLocalEvent<WearingStethoscopeComponent, GetVerbsEvent<InnateVerb>>(AddStethoscopeVerb);
  29. SubscribeLocalEvent<StethoscopeComponent, GetItemActionsEvent>(OnGetActions);
  30. SubscribeLocalEvent<StethoscopeComponent, StethoscopeActionEvent>(OnStethoscopeAction);
  31. SubscribeLocalEvent<StethoscopeComponent, StethoscopeDoAfterEvent>(OnDoAfter);
  32. }
  33. /// <summary>
  34. /// Add the component the verb event subs to if the equippee is wearing the stethoscope.
  35. /// </summary>
  36. private void OnEquipped(EntityUid uid, StethoscopeComponent component, ref ClothingGotEquippedEvent args)
  37. {
  38. component.IsActive = true;
  39. var wearingComp = EnsureComp<WearingStethoscopeComponent>(args.Wearer);
  40. wearingComp.Stethoscope = uid;
  41. }
  42. private void OnUnequipped(EntityUid uid, StethoscopeComponent component, ref ClothingGotUnequippedEvent args)
  43. {
  44. if (!component.IsActive)
  45. return;
  46. RemComp<WearingStethoscopeComponent>(args.Wearer);
  47. component.IsActive = false;
  48. }
  49. /// <summary>
  50. /// This is raised when someone with WearingStethoscopeComponent requests verbs on an item.
  51. /// It returns if the target is not a mob.
  52. /// </summary>
  53. private void AddStethoscopeVerb(EntityUid uid, WearingStethoscopeComponent component, GetVerbsEvent<InnateVerb> args)
  54. {
  55. if (!args.CanInteract || !args.CanAccess)
  56. return;
  57. if (!HasComp<MobStateComponent>(args.Target))
  58. return;
  59. if (component.CancelToken != null)
  60. return;
  61. if (!TryComp<StethoscopeComponent>(component.Stethoscope, out var stetho))
  62. return;
  63. InnateVerb verb = new()
  64. {
  65. Act = () =>
  66. {
  67. StartListening(component.Stethoscope, uid, args.Target, stetho); // start doafter
  68. },
  69. Text = Loc.GetString("stethoscope-verb"),
  70. Icon = new SpriteSpecifier.Rsi(new ("Clothing/Neck/Misc/stethoscope.rsi"), "icon"),
  71. Priority = 2
  72. };
  73. args.Verbs.Add(verb);
  74. }
  75. private void OnStethoscopeAction(EntityUid uid, StethoscopeComponent component, StethoscopeActionEvent args)
  76. {
  77. StartListening(uid, args.Performer, args.Target, component);
  78. }
  79. private void OnGetActions(EntityUid uid, StethoscopeComponent component, GetItemActionsEvent args)
  80. {
  81. args.AddAction(ref component.ActionEntity, component.Action);
  82. }
  83. // construct the doafter and start it
  84. private void StartListening(EntityUid scope, EntityUid user, EntityUid target, StethoscopeComponent comp)
  85. {
  86. _doAfterSystem.TryStartDoAfter(new DoAfterArgs(EntityManager, user, comp.Delay, new StethoscopeDoAfterEvent(), scope, target: target, used: scope)
  87. {
  88. NeedHand = true,
  89. BreakOnMove = true,
  90. });
  91. }
  92. private void OnDoAfter(EntityUid uid, StethoscopeComponent component, DoAfterEvent args)
  93. {
  94. if (args.Handled || args.Cancelled || args.Args.Target == null)
  95. return;
  96. ExamineWithStethoscope(args.Args.User, args.Args.Target.Value);
  97. }
  98. /// <summary>
  99. /// Return a value based on the total oxyloss of the target.
  100. /// Could be expanded in the future with reagent effects etc.
  101. /// The loc lines are taken from the goon wiki.
  102. /// </summary>
  103. public void ExamineWithStethoscope(EntityUid user, EntityUid target)
  104. {
  105. // The mob check seems a bit redundant but (1) they could conceivably have lost it since when the doafter started and (2) I need it for .IsDead()
  106. if (!HasComp<RespiratorComponent>(target) || !TryComp<MobStateComponent>(target, out var mobState) || _mobStateSystem.IsDead(target, mobState))
  107. {
  108. _popupSystem.PopupEntity(Loc.GetString("stethoscope-dead"), target, user);
  109. return;
  110. }
  111. if (!TryComp<DamageableComponent>(target, out var damage))
  112. return;
  113. // these should probably get loc'd at some point before a non-english fork accidentally breaks a bunch of stuff that does this
  114. if (!damage.Damage.DamageDict.TryGetValue("Asphyxiation", out var value))
  115. return;
  116. var message = GetDamageMessage(value);
  117. _popupSystem.PopupEntity(Loc.GetString(message), target, user);
  118. }
  119. private string GetDamageMessage(FixedPoint2 totalOxyloss)
  120. {
  121. var msg = (int) totalOxyloss switch
  122. {
  123. < 20 => "stethoscope-normal",
  124. < 60 => "stethoscope-hyper",
  125. < 80 => "stethoscope-irregular",
  126. _ => "stethoscope-fucked"
  127. };
  128. return msg;
  129. }
  130. }
  131. }