Skip to content

Commit

Permalink
Merge pull request #1290 from TheGrimbeeper/roachdefib
Browse files Browse the repository at this point in the history
Multitools can act as defibrillators for cockroaches
  • Loading branch information
hivehum authored Jan 10, 2025
2 parents 797141b + 3f96009 commit 72347a4
Show file tree
Hide file tree
Showing 10 changed files with 168 additions and 34 deletions.
95 changes: 65 additions & 30 deletions Content.Server/Medical/DefibrillatorSystem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
using Robust.Shared.Player;
using Robust.Shared.Random;
using Robust.Shared.Timing;
using Content.Shared.Whitelist;

namespace Content.Server.Medical;

Expand All @@ -50,6 +51,7 @@ public sealed class DefibrillatorSystem : EntitySystem
[Dependency] private readonly SharedAudioSystem _audio = default!;
[Dependency] private readonly SharedMindSystem _mind = default!;
[Dependency] private readonly IRobustRandom _random = default!;
[Dependency] private readonly EntityWhitelistSystem _whitelist = default!;

/// <inheritdoc/>
public override void Initialize()
Expand Down Expand Up @@ -98,7 +100,7 @@ public bool CanZap(EntityUid uid, EntityUid target, EntityUid? user = null, Defi
if (!Resolve(uid, ref component))
return false;

if (!_toggle.IsActivated(uid))
if (!_toggle.IsActivated(uid) && !component.IgnoreToggle)
{
if (user != null)
_popup.PopupEntity(Loc.GetString("defibrillator-not-on"), uid, user.Value);
Expand All @@ -111,7 +113,7 @@ public bool CanZap(EntityUid uid, EntityUid target, EntityUid? user = null, Defi
if (!TryComp<MobStateComponent>(target, out var mobState))
return false;

if (!_powerCell.HasActivatableCharge(uid, user: user))
if (!_powerCell.HasActivatableCharge(uid, user: user) && !component.IgnorePowerCell)
return false;

if (!targetCanBeAlive && _mobState.IsAlive(target, mobState))
Expand All @@ -120,7 +122,8 @@ public bool CanZap(EntityUid uid, EntityUid target, EntityUid? user = null, Defi
if (!targetCanBeAlive && !component.CanDefibCrit && _mobState.IsCritical(target, mobState))
return false;

return true;
// imp
return _whitelist.IsWhitelistPassOrNull(component.Whitelist, target);
}

/// <summary>
Expand All @@ -141,8 +144,15 @@ public bool TryStartZap(EntityUid uid, EntityUid target, EntityUid user, Defibri
if (!CanZap(uid, target, user, component))
return false;

_audio.PlayPvs(component.ChargeSound, uid);
return _doAfter.TryStartDoAfter(new DoAfterArgs(EntityManager, user, component.DoAfterDuration, new DefibrillatorZapDoAfterEvent(),
if (component.SkipDoAfter)
{
Zap(uid, target, user, component);
return false;
}

if (component.PlayChargeSound)
_audio.PlayPvs(component.ChargeSound, uid);
return _doAfter.TryStartDoAfter(new DoAfterArgs(EntityManager, user, TimeSpan.FromSeconds(component.DoAfterDuration), new DefibrillatorZapDoAfterEvent(),
uid, target, uid)
{
NeedHand = true,
Expand All @@ -158,8 +168,11 @@ public void Zap(EntityUid uid, EntityUid target, EntityUid user, DefibrillatorCo
if (!Resolve(uid, ref component))
return;

if (!_powerCell.TryUseActivatableCharge(uid, user: user))
return;
if (!component.IgnorePowerCell)
{
if (!_powerCell.TryUseActivatableCharge(uid, user: user))
return;
}

var selfEvent = new SelfBeforeDefibrillatorZapsEvent(user, uid, target);
RaiseLocalEvent(user, selfEvent);
Expand All @@ -182,11 +195,12 @@ public void Zap(EntityUid uid, EntityUid target, EntityUid user, DefibrillatorCo
!TryComp<MobThresholdsComponent>(target, out var thresholds))
return;

_audio.PlayPvs(component.ZapSound, uid);
if (component.PlayZapSound)
_audio.PlayPvs(component.ZapSound, uid);
_electrocution.TryDoElectrocution(target,
null,
component.ZapDamage,
component.WritheDuration,
TimeSpan.FromSeconds(component.WritheDuration),
true,
ignoreInsulation: true);
component.NextZapTime = _timing.CurTime + component.ZapDelay;
Expand All @@ -197,16 +211,19 @@ public void Zap(EntityUid uid, EntityUid target, EntityUid user, DefibrillatorCo
var dead = true;
if (_rotting.IsRotten(target))
{
_chatManager.TrySendInGameICMessage(uid,
Loc.GetString("defibrillator-rotten"),
InGameICChatType.Speak,
true);
if (component.ShowMessages)
return;
_chatManager.TrySendInGameICMessage(uid,
Loc.GetString("defibrillator-rotten"),
InGameICChatType.Speak,
true);
return;
}

if (HasComp<UnrevivableComponent>(target))
{
_chatManager.TrySendInGameICMessage(uid,
if (!component.ShowMessages)
_chatManager.TrySendInGameICMessage(uid,
Loc.GetString("defibrillator-unrevivable"),
InGameICChatType.Speak,
true);
Expand All @@ -219,9 +236,10 @@ public void Zap(EntityUid uid, EntityUid target, EntityUid user, DefibrillatorCo

if (dnrComponent.Chance < _random.NextDouble())
{
_chatManager.TrySendInGameICMessage(uid, Loc.GetString("defibrillator-unrevivable"), InGameICChatType.Speak, true);
dnrComponent.Chance = 0f;
AddComp<UnrevivableComponent>(target);
if (component.ShowMessages)
_chatManager.TrySendInGameICMessage(uid, Loc.GetString("defibrillator-unrevivable"), InGameICChatType.Speak, true);
dnrComponent.Chance = 0f;
AddComp<UnrevivableComponent>(target);
return;
}
else
Expand All @@ -237,8 +255,16 @@ public void Zap(EntityUid uid, EntityUid target, EntityUid user, DefibrillatorCo
TryComp<DamageableComponent>(target, out var damageableComponent) &&
damageableComponent.TotalDamage < threshold)
{
_mobState.ChangeMobState(target, MobState.Critical, mob, uid);
dead = false;
if (component.AllowSkipCrit &&
(!_mobThreshold.TryGetThresholdForState(target, MobState.Critical, out var critThreshold) ||
damageableComponent.TotalDamage < critThreshold))
{
_mobState.ChangeMobState(target, MobState.Alive, mob, uid);
dead = false;
} else {
_mobState.ChangeMobState(target, MobState.Critical, mob, uid);
dead = false;
}
}

if (_mind.TryGetMind(target, out _, out var mind) &&
Expand All @@ -253,19 +279,27 @@ public void Zap(EntityUid uid, EntityUid target, EntityUid user, DefibrillatorCo
}
else
{
_chatManager.TrySendInGameICMessage(uid,
Loc.GetString("defibrillator-no-mind"),
InGameICChatType.Speak,
true);
if (component.ShowMessages)
_chatManager.TrySendInGameICMessage(uid,
Loc.GetString("defibrillator-no-mind"),
InGameICChatType.Speak,
true);

var sound = dead || session == null
? component.FailureSound
: component.SuccessSound;
_audio.PlayPvs(sound, uid);
if (dead || session == null)
{
if (component.PlayFailureSound)
_audio.PlayPvs(component.FailureSound, uid);
} else {
if (component.PlaySuccessSound)
_audio.PlayPvs(component.SuccessSound, uid);
}

// if we don't have enough power left for another shot, turn it off
if (!_powerCell.HasActivatableCharge(uid))
_toggle.TryDeactivate(uid);
if (!component.IgnorePowerCell)
{
if (!_powerCell.HasActivatableCharge(uid) && !component.IgnoreToggle)
_toggle.TryDeactivate(uid);
}

// TODO clean up this clown show above
var ev = new TargetDefibrillatedEvent(user, (uid, component));
Expand All @@ -283,7 +317,8 @@ public override void Update(float frameTime)
if (defib.NextZapTime == null || _timing.CurTime < defib.NextZapTime)
continue;

_audio.PlayPvs(defib.ReadySound, uid);
if(defib.PlayReadySound)
_audio.PlayPvs(defib.ReadySound, uid);
_appearance.SetData(uid, DefibrillatorVisuals.Ready, true);
defib.NextZapTime = null;
}
Expand Down
56 changes: 54 additions & 2 deletions Content.Shared/Medical/DefibrillatorComponent.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
using Robust.Shared.GameStates;
using Robust.Shared.Serialization;
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom;
using Content.Shared.Whitelist;

namespace Content.Shared.Medical;

Expand Down Expand Up @@ -44,7 +45,7 @@ public sealed partial class DefibrillatorComponent : Component
/// How long the victim will be electrocuted after getting zapped.
/// </summary>
[DataField("writheDuration"), ViewVariables(VVAccess.ReadWrite)]
public TimeSpan WritheDuration = TimeSpan.FromSeconds(3);
public float WritheDuration = 3f;

/// <summary>
/// How long the doafter for zapping someone takes
Expand All @@ -53,29 +54,80 @@ public sealed partial class DefibrillatorComponent : Component
/// This is synced with the audio; do not change one but not the other.
/// </remarks>
[DataField("doAfterDuration"), ViewVariables(VVAccess.ReadWrite)]
public TimeSpan DoAfterDuration = TimeSpan.FromSeconds(3);
public float DoAfterDuration = 3f;

/// <summary>
/// Defib only works on mobs with id in this list, or works for anything if this list is null #IMP
/// </summary>
[DataField("whitelist"), ViewVariables(VVAccess.ReadWrite)]
public EntityWhitelist? Whitelist;

/// <summary>
/// Whether or not to have the defib pop up text, such as body composition, rot, intelligence, etc. #IMP
/// </summary>
[ViewVariables(VVAccess.ReadWrite), DataField("showMessages")]
public bool ShowMessages = true;

/// <summary>
/// Can we skip the doafter. #IMP
/// </summary>
[ViewVariables(VVAccess.ReadWrite), DataField("skipDoAfter")]
public bool SkipDoAfter = false;

/// <summary>
/// Can we ignore the toggle. #IMP
/// </summary>
[ViewVariables(VVAccess.ReadWrite), DataField("ignoreToggle")]
public bool IgnoreToggle = false;

/// <summary>
/// Can we ignore the powercell. #IMP
/// </summary>
[ViewVariables(VVAccess.ReadWrite), DataField("ignorePowerCell")]
public bool IgnorePowerCell = false;

/// <summary>
/// Can the defibbed entity skip the critical state and go straight to alive if they have low enough damage?. #IMP
/// </summary>
[ViewVariables(VVAccess.ReadWrite), DataField("allowSkipCrit")]
public bool AllowSkipCrit = false;

[DataField]
public bool AllowDoAfterMovement = true;

[DataField]
public bool CanDefibCrit = true;

[ViewVariables(VVAccess.ReadWrite), DataField("playZapSound")]
public bool PlayZapSound = true;

/// <summary>
/// The sound when someone is zapped.
/// </summary>
[ViewVariables(VVAccess.ReadWrite), DataField("zapSound")]
public SoundSpecifier? ZapSound = new SoundPathSpecifier("/Audio/Items/Defib/defib_zap.ogg");

[ViewVariables(VVAccess.ReadWrite), DataField("playChargeSound")]
public bool PlayChargeSound = true;

[ViewVariables(VVAccess.ReadWrite), DataField("chargeSound")]
public SoundSpecifier? ChargeSound = new SoundPathSpecifier("/Audio/Items/Defib/defib_charge.ogg");

[ViewVariables(VVAccess.ReadWrite), DataField("playFailureSound")]
public bool PlayFailureSound = true;

[ViewVariables(VVAccess.ReadWrite), DataField("failureSound")]
public SoundSpecifier? FailureSound = new SoundPathSpecifier("/Audio/Items/Defib/defib_failed.ogg");

[ViewVariables(VVAccess.ReadWrite), DataField("playSuccessSound")]
public bool PlaySuccessSound = true;

[ViewVariables(VVAccess.ReadWrite), DataField("successSound")]
public SoundSpecifier? SuccessSound = new SoundPathSpecifier("/Audio/Items/Defib/defib_success.ogg");

[ViewVariables(VVAccess.ReadWrite), DataField("playReadySound")]
public bool PlayReadySound = true;

[ViewVariables(VVAccess.ReadWrite), DataField("readySound")]
public SoundSpecifier? ReadySound = new SoundPathSpecifier("/Audio/Items/Defib/defib_ready.ogg");
}
Expand Down
Loading

0 comments on commit 72347a4

Please sign in to comment.