Sentient medibot now can inject (#32110)
medibot player injection Co-authored-by: YourUsername <you@example.com>
This commit is contained in:
@@ -1,5 +1,5 @@
|
|||||||
using Content.Server.Chat.Systems;
|
using Content.Server.Chat.Systems;
|
||||||
using Content.Server.NPC.Components;
|
using Content.Shared.NPC.Components;
|
||||||
using Content.Shared.Chemistry.EntitySystems;
|
using Content.Shared.Chemistry.EntitySystems;
|
||||||
using Content.Shared.Damage;
|
using Content.Shared.Damage;
|
||||||
using Content.Shared.Emag.Components;
|
using Content.Shared.Emag.Components;
|
||||||
@@ -55,34 +55,11 @@ public sealed partial class MedibotInjectOperator : HTNOperator
|
|||||||
if (!_entMan.TryGetComponent<MedibotComponent>(owner, out var botComp))
|
if (!_entMan.TryGetComponent<MedibotComponent>(owner, out var botComp))
|
||||||
return HTNOperatorStatus.Failed;
|
return HTNOperatorStatus.Failed;
|
||||||
|
|
||||||
|
if (!_medibot.CheckInjectable((owner, botComp), target) || !_medibot.TryInject((owner, botComp), target))
|
||||||
if (!_entMan.TryGetComponent<DamageableComponent>(target, out var damage))
|
|
||||||
return HTNOperatorStatus.Failed;
|
return HTNOperatorStatus.Failed;
|
||||||
|
|
||||||
if (!_solutionContainer.TryGetInjectableSolution(target, out var injectable, out _))
|
|
||||||
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);
|
_chat.TrySendInGameICMessage(owner, Loc.GetString("medibot-finish-inject"), InGameICChatType.Speak, hideChat: true, hideLog: true);
|
||||||
|
|
||||||
return HTNOperatorStatus.Finished;
|
return HTNOperatorStatus.Finished;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Content.Server.NPC.Components;
|
using Content.Shared.NPC.Components;
|
||||||
using Content.Server.NPC.Pathfinding;
|
using Content.Server.NPC.Pathfinding;
|
||||||
using Content.Shared.Chemistry.Components.SolutionManager;
|
using Content.Shared.Chemistry.Components.SolutionManager;
|
||||||
using Content.Shared.Damage;
|
using Content.Shared.Damage;
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
using Content.Server.NPC.Components;
|
using Content.Shared.NPC.Components;
|
||||||
|
|
||||||
namespace Content.Server.NPC.Systems;
|
namespace Content.Server.NPC.Systems;
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,10 @@
|
|||||||
namespace Content.Server.NPC.Components
|
using Robust.Shared.GameStates;
|
||||||
|
|
||||||
|
namespace Content.Shared.NPC.Components
|
||||||
{
|
{
|
||||||
/// Added when a medibot injects someone
|
/// Added when a medibot injects someone
|
||||||
/// So they don't get injected again for at least a minute.
|
/// So they don't get injected again for at least a minute.
|
||||||
[RegisterComponent]
|
[RegisterComponent, NetworkedComponent]
|
||||||
public sealed partial class NPCRecentlyInjectedComponent : Component
|
public sealed partial class NPCRecentlyInjectedComponent : Component
|
||||||
{
|
{
|
||||||
[ViewVariables(VVAccess.ReadWrite), DataField("accumulator")]
|
[ViewVariables(VVAccess.ReadWrite), DataField("accumulator")]
|
||||||
@@ -1,6 +1,15 @@
|
|||||||
|
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.Emag.Systems;
|
||||||
|
using Content.Shared.Interaction;
|
||||||
using Content.Shared.Mobs;
|
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.Audio.Systems;
|
||||||
|
using Robust.Shared.Serialization;
|
||||||
using System.Diagnostics.CodeAnalysis;
|
using System.Diagnostics.CodeAnalysis;
|
||||||
|
|
||||||
namespace Content.Shared.Silicons.Bots;
|
namespace Content.Shared.Silicons.Bots;
|
||||||
@@ -11,12 +20,18 @@ namespace Content.Shared.Silicons.Bots;
|
|||||||
public sealed class MedibotSystem : EntitySystem
|
public sealed class MedibotSystem : EntitySystem
|
||||||
{
|
{
|
||||||
[Dependency] private readonly SharedAudioSystem _audio = default!;
|
[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()
|
public override void Initialize()
|
||||||
{
|
{
|
||||||
base.Initialize();
|
base.Initialize();
|
||||||
|
|
||||||
SubscribeLocalEvent<EmaggableMedibotComponent, GotEmaggedEvent>(OnEmagged);
|
SubscribeLocalEvent<EmaggableMedibotComponent, GotEmaggedEvent>(OnEmagged);
|
||||||
|
SubscribeLocalEvent<MedibotComponent, UserActivateInWorldEvent>(OnInteract);
|
||||||
|
SubscribeLocalEvent<MedibotComponent, MedibotInjectDoAfterEvent>(OnInject);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnEmagged(EntityUid uid, EmaggableMedibotComponent comp, ref GotEmaggedEvent args)
|
private void OnEmagged(EntityUid uid, EmaggableMedibotComponent comp, ref GotEmaggedEvent args)
|
||||||
@@ -34,6 +49,25 @@ public sealed class MedibotSystem : EntitySystem
|
|||||||
args.Handled = true;
|
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>
|
/// <summary>
|
||||||
/// Get a treatment for a given mob state.
|
/// Get a treatment for a given mob state.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -44,4 +78,66 @@ public sealed class MedibotSystem : EntitySystem
|
|||||||
{
|
{
|
||||||
return comp.Treatments.TryGetValue(state, out treatment);
|
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 { }
|
||||||
|
|||||||
@@ -1,2 +1,7 @@
|
|||||||
medibot-start-inject = Hold still, please.
|
medibot-start-inject = Hold still, please.
|
||||||
medibot-finish-inject = All done.
|
medibot-finish-inject = All done.
|
||||||
|
|
||||||
|
medibot-target-dead = The patient is dead.
|
||||||
|
medibot-target-healthy = The patient is already healthy.
|
||||||
|
medibot-target-injected = The patient was injected.
|
||||||
|
medibot-recently-injected = The patient was recently injected.
|
||||||
|
|||||||
@@ -351,6 +351,7 @@
|
|||||||
pack: MedibotAds
|
pack: MedibotAds
|
||||||
- type: Inventory
|
- type: Inventory
|
||||||
templateId: medibot
|
templateId: medibot
|
||||||
|
- type: DoAfter
|
||||||
|
|
||||||
- type: entity
|
- type: entity
|
||||||
parent:
|
parent:
|
||||||
|
|||||||
Reference in New Issue
Block a user