using Content.Server.Chat.Systems;
-using Content.Server.NPC.Components;
+using Content.Shared.NPC.Components;
using Content.Shared.Chemistry.EntitySystems;
using Content.Shared.Damage;
using Content.Shared.Emag.Components;
if (!_entMan.TryGetComponent<MedibotComponent>(owner, out var botComp))
return HTNOperatorStatus.Failed;
-
- if (!_entMan.TryGetComponent<DamageableComponent>(target, out var damage))
- return HTNOperatorStatus.Failed;
-
- if (!_solutionContainer.TryGetInjectableSolution(target, out var injectable, out _))
+ if (!_medibot.CheckInjectable((owner, botComp), target) || !_medibot.TryInject((owner, botComp), target))
return HTNOperatorStatus.Failed;
- if (!_interaction.InRangeUnobstructed(owner, target))
- return HTNOperatorStatus.Failed;
-
- var total = damage.TotalDamage;
-
- // always inject healthy patients when emagged
- if (total == 0 && !_entMan.HasComponent<EmaggedComponent>(owner))
- return HTNOperatorStatus.Failed;
-
- if (!_entMan.TryGetComponent<MobStateComponent>(target, out var mobState))
- return HTNOperatorStatus.Failed;
-
- var state = mobState.CurrentState;
- if (!_medibot.TryGetTreatment(botComp, mobState.CurrentState, out var treatment) || !treatment.IsValid(total))
- return HTNOperatorStatus.Failed;
-
- _entMan.EnsureComponent<NPCRecentlyInjectedComponent>(target);
- _solutionContainer.TryAddReagent(injectable.Value, treatment.Reagent, treatment.Quantity, out _);
- _popup.PopupEntity(Loc.GetString("hypospray-component-feel-prick-message"), target, target);
- _audio.PlayPvs(botComp.InjectSound, target);
_chat.TrySendInGameICMessage(owner, Loc.GetString("medibot-finish-inject"), InGameICChatType.Speak, hideChat: true, hideLog: true);
+
return HTNOperatorStatus.Finished;
}
}
+using Content.Shared.Chemistry.EntitySystems;
+using Content.Shared.Damage;
+using Content.Shared.DoAfter;
+using Content.Shared.Emag.Components;
using Content.Shared.Emag.Systems;
+using Content.Shared.Interaction;
using Content.Shared.Mobs;
+using Content.Shared.Mobs.Components;
+using Content.Shared.NPC.Components;
+using Content.Shared.Popups;
using Robust.Shared.Audio.Systems;
+using Robust.Shared.Serialization;
using System.Diagnostics.CodeAnalysis;
namespace Content.Shared.Silicons.Bots;
public sealed class MedibotSystem : EntitySystem
{
[Dependency] private readonly SharedAudioSystem _audio = default!;
+ [Dependency] private SharedInteractionSystem _interaction = default!;
+ [Dependency] private SharedSolutionContainerSystem _solutionContainer = default!;
+ [Dependency] private SharedPopupSystem _popup = default!;
+ [Dependency] private SharedDoAfterSystem _doAfter = default!;
public override void Initialize()
{
base.Initialize();
SubscribeLocalEvent<EmaggableMedibotComponent, GotEmaggedEvent>(OnEmagged);
+ SubscribeLocalEvent<MedibotComponent, UserActivateInWorldEvent>(OnInteract);
+ SubscribeLocalEvent<MedibotComponent, MedibotInjectDoAfterEvent>(OnInject);
}
private void OnEmagged(EntityUid uid, EmaggableMedibotComponent comp, ref GotEmaggedEvent args)
args.Handled = true;
}
+ private void OnInteract(Entity<MedibotComponent> medibot, ref UserActivateInWorldEvent args)
+ {
+ if (!CheckInjectable(medibot!, args.Target, true)) return;
+
+ _doAfter.TryStartDoAfter(new DoAfterArgs(EntityManager, args.User, 2f, new MedibotInjectDoAfterEvent(), args.User, args.Target)
+ {
+ BlockDuplicate = true,
+ BreakOnMove = true,
+ });
+ }
+
+ private void OnInject(EntityUid uid, MedibotComponent comp, ref MedibotInjectDoAfterEvent args)
+ {
+ if (args.Cancelled) return;
+
+ if (args.Target is { } target)
+ TryInject(uid, target);
+ }
+
/// <summary>
/// Get a treatment for a given mob state.
/// </summary>
{
return comp.Treatments.TryGetValue(state, out treatment);
}
+
+ /// <summary>
+ /// Checks if the target can be injected.
+ /// </summary>
+ public bool CheckInjectable(Entity<MedibotComponent?> medibot, EntityUid target, bool manual = false)
+ {
+ if (!Resolve(medibot, ref medibot.Comp, false)) return false;
+
+ if (HasComp<NPCRecentlyInjectedComponent>(target))
+ {
+ _popup.PopupClient(Loc.GetString("medibot-recently-injected"), medibot, medibot);
+ return false;
+ }
+
+ if (!TryComp<MobStateComponent>(target, out var mobState)) return false;
+ if (!TryComp<DamageableComponent>(target, out var damageable)) return false;
+ if (!_solutionContainer.TryGetInjectableSolution(target, out _, out _)) return false;
+
+ if (mobState.CurrentState != MobState.Alive && mobState.CurrentState != MobState.Critical)
+ {
+ _popup.PopupClient(Loc.GetString("medibot-target-dead"), medibot, medibot);
+ return false;
+ }
+
+ var total = damageable.TotalDamage;
+ if (total == 0 && !HasComp<EmaggedComponent>(medibot))
+ {
+ _popup.PopupClient(Loc.GetString("medibot-target-healthy"), medibot, medibot);
+ return false;
+ }
+
+ if (!TryGetTreatment(medibot.Comp, mobState.CurrentState, out var treatment) || !treatment.IsValid(total) && !manual) return false;
+
+ return true;
+ }
+
+ /// <summary>
+ /// Tries to inject the target.
+ /// </summary>
+ public bool TryInject(Entity<MedibotComponent?> medibot, EntityUid target)
+ {
+ if (!Resolve(medibot, ref medibot.Comp, false)) return false;
+
+ if (!_interaction.InRangeUnobstructed(medibot.Owner, target)) return false;
+
+ if (!TryComp<MobStateComponent>(target, out var mobState)) return false;
+ if (!TryGetTreatment(medibot.Comp, mobState.CurrentState, out var treatment)) return false;
+ if (!_solutionContainer.TryGetInjectableSolution(target, out var injectable, out _)) return false;
+
+ EnsureComp<NPCRecentlyInjectedComponent>(target);
+ _solutionContainer.TryAddReagent(injectable.Value, treatment.Reagent, treatment.Quantity, out _);
+
+ _popup.PopupEntity(Loc.GetString("hypospray-component-feel-prick-message"), target, target);
+ _popup.PopupClient(Loc.GetString("medibot-target-injected"), medibot, medibot);
+
+ _audio.PlayPredicted(medibot.Comp.InjectSound, medibot, medibot);
+
+ return true;
+ }
}
+
+[Serializable, NetSerializable]
+public sealed partial class MedibotInjectDoAfterEvent : SimpleDoAfterEvent { }