Hardbombs & Defusables (#15380)
Co-authored-by: Kara <lunarautomaton6@gmail.com> Co-authored-by: Just-a-Unity-Dev <just-a-unity-dev@users.noreply.github.com> Co-authored-by: LankLTE <twlowe06@gmail.com> Co-authored-by: LankLTE <135308300+LankLTE@users.noreply.github.com>
76
Content.Server/Defusable/Components/DefusableComponent.cs
Normal file
@@ -0,0 +1,76 @@
|
||||
using Content.Server.Defusable.Systems;
|
||||
using Content.Server.Explosion.Components;
|
||||
using Robust.Shared.Audio;
|
||||
|
||||
namespace Content.Server.Defusable.Components;
|
||||
|
||||
/// <summary>
|
||||
/// This is used for bombs that should be defused. The explosion configuration should be handled by <see cref="ExplosiveComponent"/>.
|
||||
/// </summary>
|
||||
[RegisterComponent, Access(typeof(DefusableSystem))]
|
||||
public sealed partial class DefusableComponent : Component
|
||||
{
|
||||
/// <summary>
|
||||
/// The bomb will play this sound on defusal.
|
||||
/// </summary>
|
||||
[ViewVariables(VVAccess.ReadOnly), DataField("defusalSound")]
|
||||
public SoundSpecifier DefusalSound = new SoundPathSpecifier("/Audio/Misc/notice2.ogg");
|
||||
|
||||
/// <summary>
|
||||
/// The bomb will play this sound on bolt.
|
||||
/// </summary>
|
||||
[ViewVariables(VVAccess.ReadOnly), DataField("boltSound")]
|
||||
public SoundSpecifier BoltSound = new SoundPathSpecifier("/Audio/Machines/boltsdown.ogg");
|
||||
|
||||
/// <summary>
|
||||
/// Is this bomb one use?
|
||||
/// </summary>
|
||||
[ViewVariables(VVAccess.ReadWrite), DataField("disposable")]
|
||||
public bool Disposable = true;
|
||||
|
||||
/// <summary>
|
||||
/// Is the bomb live? This is different from BombUsable because this tracks whether the bomb is ticking down or not.
|
||||
/// </summary>
|
||||
[ViewVariables(VVAccess.ReadWrite), DataField("activated")]
|
||||
public bool Activated;
|
||||
|
||||
/// <summary>
|
||||
/// Is the bomb actually usable? This is different from Activated because this tracks whether the bomb can even start in the first place.
|
||||
/// </summary>
|
||||
[ViewVariables(VVAccess.ReadWrite)]
|
||||
public bool Usable = true;
|
||||
|
||||
/// <summary>
|
||||
/// Does the bomb show how much time remains?
|
||||
/// </summary>
|
||||
[ViewVariables(VVAccess.ReadWrite)]
|
||||
public bool DisplayTime = true;
|
||||
|
||||
/// <summary>
|
||||
/// Is this bomb supposed to be stuck to the ground?
|
||||
/// </summary>
|
||||
[ViewVariables(VVAccess.ReadWrite)]
|
||||
public bool Bolted;
|
||||
|
||||
/// <summary>
|
||||
/// How much time is added when the Activate wire is pulsed?
|
||||
/// </summary>
|
||||
[DataField("delayTime")]
|
||||
public int DelayTime = 30;
|
||||
|
||||
#region Wires
|
||||
// wires, this is so that they're one use
|
||||
[ViewVariables(VVAccess.ReadWrite), Access(Other=AccessPermissions.ReadWrite)]
|
||||
public bool DelayWireUsed;
|
||||
|
||||
[ViewVariables(VVAccess.ReadWrite), Access(Other=AccessPermissions.ReadWrite)]
|
||||
public bool ProceedWireCut;
|
||||
|
||||
[ViewVariables(VVAccess.ReadWrite), Access(Other=AccessPermissions.ReadWrite)]
|
||||
public bool ProceedWireUsed;
|
||||
|
||||
[ViewVariables(VVAccess.ReadWrite), Access(Other=AccessPermissions.ReadWrite)]
|
||||
public bool ActivatedWireUsed;
|
||||
|
||||
#endregion
|
||||
}
|
||||
435
Content.Server/Defusable/Systems/DefusableSystem.cs
Normal file
@@ -0,0 +1,435 @@
|
||||
using Content.Server.Defusable.Components;
|
||||
using Content.Server.Explosion.Components;
|
||||
using Content.Server.Explosion.EntitySystems;
|
||||
using Content.Server.Popups;
|
||||
using Content.Server.Wires;
|
||||
using Content.Shared.Administration.Logs;
|
||||
using Content.Shared.Construction.Components;
|
||||
using Content.Shared.Database;
|
||||
using Content.Shared.Defusable;
|
||||
using Content.Shared.Examine;
|
||||
using Content.Shared.Popups;
|
||||
using Content.Shared.Verbs;
|
||||
using Content.Shared.Wires;
|
||||
using Robust.Server.GameObjects;
|
||||
|
||||
namespace Content.Server.Defusable.Systems;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public sealed class DefusableSystem : SharedDefusableSystem
|
||||
{
|
||||
[Dependency] private readonly SharedAppearanceSystem _appearance = default!;
|
||||
[Dependency] private readonly ExplosionSystem _explosion = default!;
|
||||
[Dependency] private readonly PopupSystem _popup = default!;
|
||||
[Dependency] private readonly TriggerSystem _trigger = default!;
|
||||
[Dependency] private readonly SharedAudioSystem _audio = default!;
|
||||
[Dependency] private readonly TransformSystem _transform = default!;
|
||||
[Dependency] private readonly ISharedAdminLogManager _adminLogger = default!;
|
||||
[Dependency] private readonly WiresSystem _wiresSystem = default!;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
|
||||
SubscribeLocalEvent<DefusableComponent, ExaminedEvent>(OnExamine);
|
||||
SubscribeLocalEvent<DefusableComponent, GetVerbsEvent<AlternativeVerb>>(OnGetAltVerbs);
|
||||
SubscribeLocalEvent<DefusableComponent, AnchorAttemptEvent>(OnAnchorAttempt);
|
||||
SubscribeLocalEvent<DefusableComponent, UnanchorAttemptEvent>(OnUnanchorAttempt);
|
||||
}
|
||||
|
||||
#region Subscribed Events
|
||||
/// <summary>
|
||||
/// Adds a verb allowing for the bomb to be started easily.
|
||||
/// </summary>
|
||||
private void OnGetAltVerbs(EntityUid uid, DefusableComponent comp, GetVerbsEvent<AlternativeVerb> args)
|
||||
{
|
||||
if (!args.CanInteract || !args.CanAccess)
|
||||
return;
|
||||
|
||||
args.Verbs.Add(new AlternativeVerb
|
||||
{
|
||||
Text = Loc.GetString("defusable-verb-begin"),
|
||||
Disabled = comp is { Activated: true, Usable: true },
|
||||
Priority = 10,
|
||||
Act = () =>
|
||||
{
|
||||
TryStartCountdown(uid, args.User, comp);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void OnExamine(EntityUid uid, DefusableComponent comp, ExaminedEvent args)
|
||||
{
|
||||
if (!args.IsInDetailsRange)
|
||||
return;
|
||||
|
||||
if (!comp.Usable)
|
||||
{
|
||||
args.PushMarkup(Loc.GetString("defusable-examine-defused", ("name", uid)));
|
||||
}
|
||||
else if (comp.Activated && TryComp<ActiveTimerTriggerComponent>(uid, out var activeComp))
|
||||
{
|
||||
if (comp.DisplayTime)
|
||||
{
|
||||
args.PushMarkup(Loc.GetString("defusable-examine-live", ("name", uid),
|
||||
("time", MathF.Floor(activeComp.TimeRemaining))));
|
||||
}
|
||||
else
|
||||
{
|
||||
args.PushMarkup(Loc.GetString("defusable-examine-live-display-off", ("name", uid)));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
args.PushMarkup(Loc.GetString("defusable-examine-inactive", ("name", uid)));
|
||||
}
|
||||
|
||||
args.PushMarkup(Loc.GetString("defusable-examine-bolts", ("down", comp.Bolted)));
|
||||
}
|
||||
|
||||
private void OnAnchorAttempt(EntityUid uid, DefusableComponent component, AnchorAttemptEvent args)
|
||||
{
|
||||
if (CheckAnchorAttempt(uid, component, args))
|
||||
args.Cancel();
|
||||
}
|
||||
|
||||
private void OnUnanchorAttempt(EntityUid uid, DefusableComponent component, UnanchorAttemptEvent args)
|
||||
{
|
||||
if (CheckAnchorAttempt(uid, component, args))
|
||||
args.Cancel();
|
||||
}
|
||||
|
||||
private bool CheckAnchorAttempt(EntityUid uid, DefusableComponent component, BaseAnchoredAttemptEvent args)
|
||||
{
|
||||
// Don't allow the thing to be anchored if bolted to the ground
|
||||
if (!component.Bolted)
|
||||
return false;
|
||||
|
||||
var msg = Loc.GetString("defusable-popup-cant-anchor", ("name", uid));
|
||||
_popup.PopupEntity(msg, uid, args.User);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Public
|
||||
|
||||
public void TryStartCountdown(EntityUid uid, EntityUid user, DefusableComponent comp)
|
||||
{
|
||||
if (!comp.Usable)
|
||||
{
|
||||
_popup.PopupEntity(Loc.GetString("defusable-popup-fried", ("name", uid)), uid);
|
||||
return;
|
||||
}
|
||||
|
||||
var xform = Transform(uid);
|
||||
if (!xform.Anchored)
|
||||
_transform.AnchorEntity(uid, xform);
|
||||
|
||||
SetBolt(comp, true);
|
||||
SetActivated(comp, true);
|
||||
|
||||
_popup.PopupEntity(Loc.GetString("defusable-popup-begun", ("name", uid)), uid);
|
||||
if (TryComp<OnUseTimerTriggerComponent>(uid, out var timerTrigger))
|
||||
{
|
||||
_trigger.HandleTimerTrigger(
|
||||
uid,
|
||||
null,
|
||||
timerTrigger.Delay,
|
||||
timerTrigger.BeepInterval,
|
||||
timerTrigger.InitialBeepDelay,
|
||||
timerTrigger.BeepSound
|
||||
);
|
||||
}
|
||||
|
||||
RaiseLocalEvent(uid, new BombArmedEvent(uid));
|
||||
|
||||
_appearance.SetData(uid, DefusableVisuals.Active, comp.Activated);
|
||||
_adminLogger.Add(LogType.Explosion, LogImpact.High,
|
||||
$"{ToPrettyString(user):entity} begun a countdown on {ToPrettyString(uid):entity}");
|
||||
|
||||
if (TryComp<WiresPanelComponent>(uid, out var wiresPanelComponent))
|
||||
_wiresSystem.TogglePanel(uid, wiresPanelComponent, false);
|
||||
}
|
||||
|
||||
public void TryDetonateBomb(EntityUid uid, DefusableComponent comp)
|
||||
{
|
||||
if (!comp.Activated)
|
||||
return;
|
||||
|
||||
_popup.PopupEntity(Loc.GetString("defusable-popup-boom", ("name", uid)), uid, PopupType.LargeCaution);
|
||||
|
||||
RaiseLocalEvent(uid, new BombDetonatedEvent(uid));
|
||||
|
||||
_explosion.TriggerExplosive(uid);
|
||||
QueueDel(uid);
|
||||
|
||||
_appearance.SetData(uid, DefusableVisuals.Active, comp.Activated);
|
||||
|
||||
_adminLogger.Add(LogType.Explosion, LogImpact.High,
|
||||
$"{ToPrettyString(uid):entity} has been detonated.");
|
||||
}
|
||||
|
||||
public void TryDefuseBomb(EntityUid uid, DefusableComponent comp)
|
||||
{
|
||||
if (!comp.Activated)
|
||||
return;
|
||||
|
||||
_popup.PopupEntity(Loc.GetString("defusable-popup-defuse", ("name", uid)), uid);
|
||||
SetActivated(comp, false);
|
||||
|
||||
var xform = Transform(uid);
|
||||
|
||||
if (comp.Disposable)
|
||||
{
|
||||
SetUsable(comp, false);
|
||||
RemComp<ExplodeOnTriggerComponent>(uid);
|
||||
RemComp<OnUseTimerTriggerComponent>(uid);
|
||||
}
|
||||
RemComp<ActiveTimerTriggerComponent>(uid);
|
||||
|
||||
_audio.PlayPvs(comp.DefusalSound, uid);
|
||||
|
||||
RaiseLocalEvent(uid, new BombDefusedEvent(uid));
|
||||
|
||||
comp.ActivatedWireUsed = false;
|
||||
comp.DelayWireUsed = false;
|
||||
comp.ProceedWireCut = false;
|
||||
comp.ProceedWireUsed = false;
|
||||
comp.Bolted = false;
|
||||
|
||||
if (xform.Anchored)
|
||||
_transform.Unanchor(uid, xform);
|
||||
|
||||
_appearance.SetData(uid, DefusableVisuals.Active, comp.Activated);
|
||||
_adminLogger.Add(LogType.Explosion, LogImpact.High,
|
||||
$"{ToPrettyString(uid):entity} has been defused!");
|
||||
}
|
||||
|
||||
// jesus christ
|
||||
public void SetUsable(DefusableComponent component, bool value)
|
||||
{
|
||||
component.Usable = value;
|
||||
}
|
||||
|
||||
public void SetDisplayTime(DefusableComponent component, bool value)
|
||||
{
|
||||
component.DisplayTime = value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the Activated value of a component to a value.
|
||||
/// </summary>
|
||||
/// <param name="component"></param>
|
||||
/// <param name="value"></param>
|
||||
/// <remarks>
|
||||
/// Use <see cref="TryDefuseBomb"/> to defuse bomb. This is a setter.
|
||||
/// </remarks>
|
||||
public void SetActivated(DefusableComponent component, bool value)
|
||||
{
|
||||
component.Activated = value;
|
||||
}
|
||||
|
||||
public void SetBolt(DefusableComponent component, bool value)
|
||||
{
|
||||
component.Bolted = value;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Wires
|
||||
|
||||
public void DelayWirePulse(EntityUid user, Wire wire, DefusableComponent comp)
|
||||
{
|
||||
if (comp is not { Activated: true, DelayWireUsed: false })
|
||||
return;
|
||||
|
||||
_trigger.TryDelay(wire.Owner, 30f);
|
||||
_popup.PopupEntity(Loc.GetString("defusable-popup-wire-chirp", ("name", wire.Owner)), wire.Owner);
|
||||
comp.DelayWireUsed = true;
|
||||
|
||||
_adminLogger.Add(LogType.Explosion, LogImpact.High,
|
||||
$"{ToPrettyString(user):user} pulsed the DeLAY wire of {ToPrettyString(wire.Owner):entity}.");
|
||||
}
|
||||
|
||||
public bool ProceedWireCut(EntityUid user, Wire wire, DefusableComponent comp)
|
||||
{
|
||||
if (comp is not { Activated: true, ProceedWireCut: false })
|
||||
return true;
|
||||
|
||||
_popup.PopupEntity(Loc.GetString("defusable-popup-wire-proceed-pulse", ("name", wire.Owner)), wire.Owner);
|
||||
SetDisplayTime(comp, false);
|
||||
|
||||
_adminLogger.Add(LogType.Explosion, LogImpact.High,
|
||||
$"{ToPrettyString(user):user} cut the PRoCeeD wire of {ToPrettyString(wire.Owner):entity}.");
|
||||
|
||||
comp.ProceedWireCut = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
public void ProceedWirePulse(EntityUid user, Wire wire, DefusableComponent comp)
|
||||
{
|
||||
if (comp is { Activated: true, ProceedWireUsed: false })
|
||||
{
|
||||
comp.ProceedWireUsed = true;
|
||||
_trigger.TryDelay(wire.Owner, -15f);
|
||||
}
|
||||
|
||||
_adminLogger.Add(LogType.Explosion, LogImpact.High,
|
||||
$"{ToPrettyString(user):user} pulsed the PRoCeeD wire of {ToPrettyString(wire.Owner):entity}.");
|
||||
|
||||
_popup.PopupEntity(Loc.GetString("defusable-popup-wire-proceed-pulse", ("name", wire.Owner)), wire.Owner);
|
||||
}
|
||||
|
||||
public bool ActivateWireCut(EntityUid user, Wire wire, DefusableComponent comp)
|
||||
{
|
||||
// if you cut the wire it just defuses the bomb
|
||||
|
||||
if (comp.Activated)
|
||||
{
|
||||
TryDefuseBomb(wire.Owner, comp);
|
||||
|
||||
_adminLogger.Add(LogType.Explosion, LogImpact.High,
|
||||
$"{ToPrettyString(user):user} has defused {ToPrettyString(wire.Owner):entity}!");
|
||||
}
|
||||
|
||||
_adminLogger.Add(LogType.Explosion, LogImpact.High,
|
||||
$"{ToPrettyString(user):user} cut the LIVE wire of {ToPrettyString(wire.Owner):entity}.");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public void ActivateWirePulse(EntityUid user, Wire wire, DefusableComponent comp)
|
||||
{
|
||||
// if the component isnt active, just start the countdown
|
||||
// if it is and it isn't already used then delay it
|
||||
|
||||
if (comp.Activated)
|
||||
{
|
||||
if (!comp.ActivatedWireUsed)
|
||||
{
|
||||
_trigger.TryDelay(wire.Owner, 30f);
|
||||
_popup.PopupEntity(Loc.GetString("defusable-popup-wire-chirp", ("name", wire.Owner)), wire.Owner);
|
||||
comp.ActivatedWireUsed = true;
|
||||
_adminLogger.Add(LogType.Explosion, LogImpact.High,
|
||||
$"{ToPrettyString(user):user} pulsed the LIVE wire of {ToPrettyString(wire.Owner):entity}.");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
TryStartCountdown(wire.Owner, user, comp);
|
||||
_adminLogger.Add(LogType.Explosion, LogImpact.High,
|
||||
$"{ToPrettyString(user):user} pulsed the LIVE wire of {ToPrettyString(wire.Owner):entity} and begun the countdown.");
|
||||
}
|
||||
}
|
||||
|
||||
public bool BoomWireCut(EntityUid user, Wire wire, DefusableComponent comp)
|
||||
{
|
||||
if (comp.Activated)
|
||||
{
|
||||
EntityManager.System<DefusableSystem>().TryDetonateBomb(wire.Owner, comp);
|
||||
_adminLogger.Add(LogType.Explosion, LogImpact.Extreme,
|
||||
$"{ToPrettyString(user):user} cut the BOOM wire of {ToPrettyString(wire.Owner):entity} and caused it to detonate!");
|
||||
}
|
||||
else
|
||||
{
|
||||
EntityManager.System<DefusableSystem>().SetUsable(comp, false);
|
||||
_adminLogger.Add(LogType.Explosion, LogImpact.High,
|
||||
$"{ToPrettyString(user):user} cut the BOOM wire of {ToPrettyString(wire.Owner):entity}.");
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool BoomWireMend(EntityUid user, Wire wire, DefusableComponent comp)
|
||||
{
|
||||
if (comp is { Activated: false, Usable: false })
|
||||
{
|
||||
SetUsable(comp, true);
|
||||
|
||||
_adminLogger.Add(LogType.Explosion, LogImpact.High,
|
||||
$"{ToPrettyString(user):user} mended the BOOM wire of {ToPrettyString(wire.Owner):entity}.");
|
||||
}
|
||||
// you're already dead lol
|
||||
return true;
|
||||
}
|
||||
|
||||
public void BoomWirePulse(EntityUid user, Wire wire, DefusableComponent comp)
|
||||
{
|
||||
if (comp.Activated)
|
||||
{
|
||||
TryDetonateBomb(wire.Owner, comp);
|
||||
}
|
||||
_adminLogger.Add(LogType.Explosion, LogImpact.Extreme,
|
||||
$"{ToPrettyString(user):user} pulsed the BOOM wire of {ToPrettyString(wire.Owner):entity} and caused it to detonate!");
|
||||
}
|
||||
|
||||
public bool BoltWireMend(EntityUid user, Wire wire, DefusableComponent comp)
|
||||
{
|
||||
if (!comp.Activated)
|
||||
return true;
|
||||
|
||||
SetBolt(comp, true);
|
||||
_audio.PlayPvs(comp.BoltSound, wire.Owner);
|
||||
_popup.PopupEntity(Loc.GetString("defusable-popup-wire-bolt-pulse", ("name", wire.Owner)), wire.Owner);
|
||||
|
||||
_adminLogger.Add(LogType.Explosion, LogImpact.High,
|
||||
$"{ToPrettyString(user):user} mended the BOLT wire of {ToPrettyString(wire.Owner):entity}!");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool BoltWireCut(EntityUid user, Wire wire, DefusableComponent comp)
|
||||
{
|
||||
if (!comp.Activated)
|
||||
return true;
|
||||
|
||||
SetBolt(comp, false);
|
||||
_audio.PlayPvs(comp.BoltSound, wire.Owner);
|
||||
_popup.PopupEntity(Loc.GetString("defusable-popup-wire-bolt-pulse", ("name", wire.Owner)), wire.Owner);
|
||||
|
||||
_adminLogger.Add(LogType.Explosion, LogImpact.High,
|
||||
$"{ToPrettyString(user):user} cut the BOLT wire of {ToPrettyString(wire.Owner):entity}!");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public void BoltWirePulse(EntityUid user, Wire wire, DefusableComponent comp)
|
||||
{
|
||||
_popup.PopupEntity(Loc.GetString("defusable-popup-wire-bolt-pulse", ("name", wire.Owner)), wire.Owner);
|
||||
|
||||
_adminLogger.Add(LogType.Explosion, LogImpact.High,
|
||||
$"{ToPrettyString(user):user} pulsed the BOLT wire of {ToPrettyString(wire.Owner):entity}!");
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
public sealed class BombDefusedEvent : EntityEventArgs
|
||||
{
|
||||
public EntityUid Entity;
|
||||
|
||||
public BombDefusedEvent(EntityUid entity)
|
||||
{
|
||||
Entity = entity;
|
||||
}
|
||||
}
|
||||
public sealed class BombArmedEvent : EntityEventArgs
|
||||
{
|
||||
public EntityUid Entity;
|
||||
|
||||
public BombArmedEvent(EntityUid entity)
|
||||
{
|
||||
Entity = entity;
|
||||
}
|
||||
}
|
||||
public sealed class BombDetonatedEvent : EntityEventArgs
|
||||
{
|
||||
public EntityUid Entity;
|
||||
|
||||
public BombDetonatedEvent(EntityUid entity)
|
||||
{
|
||||
Entity = entity;
|
||||
}
|
||||
}
|
||||
42
Content.Server/Defusable/WireActions/ActivateWireAction.cs
Normal file
@@ -0,0 +1,42 @@
|
||||
using Content.Server.Defusable.Components;
|
||||
using Content.Server.Defusable.Systems;
|
||||
using Content.Server.Doors.Systems;
|
||||
using Content.Server.Explosion.EntitySystems;
|
||||
using Content.Server.Popups;
|
||||
using Content.Server.Wires;
|
||||
using Content.Shared.Defusable;
|
||||
using Content.Shared.Doors;
|
||||
using Content.Shared.Doors.Components;
|
||||
using Content.Shared.Wires;
|
||||
|
||||
namespace Content.Server.Defusable.WireActions;
|
||||
|
||||
public sealed partial class ActivateWireAction : ComponentWireAction<DefusableComponent>
|
||||
{
|
||||
public override Color Color { get; set; } = Color.Lime;
|
||||
public override string Name { get; set; } = "wire-name-bomb-live";
|
||||
|
||||
public override StatusLightState? GetLightState(Wire wire, DefusableComponent comp)
|
||||
{
|
||||
return comp.Activated ? StatusLightState.BlinkingFast : StatusLightState.Off;
|
||||
}
|
||||
|
||||
public override object StatusKey { get; } = DefusableWireStatus.LiveIndicator;
|
||||
|
||||
public override bool Cut(EntityUid user, Wire wire, DefusableComponent comp)
|
||||
{
|
||||
return EntityManager.System<DefusableSystem>().ActivateWireCut(user, wire, comp);
|
||||
}
|
||||
|
||||
public override bool Mend(EntityUid user, Wire wire, DefusableComponent comp)
|
||||
{
|
||||
// if its not disposable defusable system already handles* this
|
||||
// *probably
|
||||
return true;
|
||||
}
|
||||
|
||||
public override void Pulse(EntityUid user, Wire wire, DefusableComponent comp)
|
||||
{
|
||||
EntityManager.System<DefusableSystem>().ActivateWirePulse(user, wire, comp);
|
||||
}
|
||||
}
|
||||
38
Content.Server/Defusable/WireActions/BoltWireAction.cs
Normal file
@@ -0,0 +1,38 @@
|
||||
using Content.Server.Defusable.Components;
|
||||
using Content.Server.Defusable.Systems;
|
||||
using Content.Server.Popups;
|
||||
using Content.Server.Wires;
|
||||
using Content.Shared.Defusable;
|
||||
using Content.Shared.Wires;
|
||||
using Robust.Server.GameObjects;
|
||||
|
||||
namespace Content.Server.Defusable.WireActions;
|
||||
|
||||
public sealed partial class BoltWireAction : ComponentWireAction<DefusableComponent>
|
||||
{
|
||||
public override Color Color { get; set; } = Color.Red;
|
||||
public override string Name { get; set; } = "wire-name-bomb-bolt";
|
||||
public override bool LightRequiresPower { get; set; } = false;
|
||||
|
||||
public override StatusLightState? GetLightState(Wire wire, DefusableComponent comp)
|
||||
{
|
||||
return comp.Bolted ? StatusLightState.On : StatusLightState.Off;
|
||||
}
|
||||
|
||||
public override object StatusKey { get; } = DefusableWireStatus.BoltIndicator;
|
||||
|
||||
public override bool Cut(EntityUid user, Wire wire, DefusableComponent comp)
|
||||
{
|
||||
return EntityManager.System<DefusableSystem>().BoltWireCut(user, wire, comp);
|
||||
}
|
||||
|
||||
public override bool Mend(EntityUid user, Wire wire, DefusableComponent comp)
|
||||
{
|
||||
return EntityManager.System<DefusableSystem>().BoltWireMend(user, wire, comp);
|
||||
}
|
||||
|
||||
public override void Pulse(EntityUid user, Wire wire, DefusableComponent comp)
|
||||
{
|
||||
EntityManager.System<DefusableSystem>().BoltWirePulse(user, wire, comp);
|
||||
}
|
||||
}
|
||||
39
Content.Server/Defusable/WireActions/BoomWireAction.cs
Normal file
@@ -0,0 +1,39 @@
|
||||
using Content.Server.Defusable.Components;
|
||||
using Content.Server.Defusable.Systems;
|
||||
using Content.Server.Doors.Systems;
|
||||
using Content.Server.Wires;
|
||||
using Content.Shared.Defusable;
|
||||
using Content.Shared.Doors;
|
||||
using Content.Shared.Doors.Components;
|
||||
using Content.Shared.Wires;
|
||||
|
||||
namespace Content.Server.Defusable.WireActions;
|
||||
|
||||
public sealed partial class BoomWireAction : ComponentWireAction<DefusableComponent>
|
||||
{
|
||||
public override Color Color { get; set; } = Color.Red;
|
||||
public override string Name { get; set; } = "wire-name-bomb-boom";
|
||||
public override bool LightRequiresPower { get; set; } = false;
|
||||
|
||||
public override StatusLightState? GetLightState(Wire wire, DefusableComponent comp)
|
||||
{
|
||||
return comp.Activated ? StatusLightState.On : StatusLightState.Off;
|
||||
}
|
||||
|
||||
public override object StatusKey { get; } = DefusableWireStatus.BoomIndicator;
|
||||
|
||||
public override bool Cut(EntityUid user, Wire wire, DefusableComponent comp)
|
||||
{
|
||||
return EntityManager.System<DefusableSystem>().BoomWireCut(user, wire, comp);
|
||||
}
|
||||
|
||||
public override bool Mend(EntityUid user, Wire wire, DefusableComponent comp)
|
||||
{
|
||||
return EntityManager.System<DefusableSystem>().BoomWireMend(user, wire, comp);
|
||||
}
|
||||
|
||||
public override void Pulse(EntityUid user, Wire wire, DefusableComponent comp)
|
||||
{
|
||||
EntityManager.System<DefusableSystem>().BoomWirePulse(user, wire, comp);
|
||||
}
|
||||
}
|
||||
44
Content.Server/Defusable/WireActions/DelayWireAction.cs
Normal file
@@ -0,0 +1,44 @@
|
||||
using Content.Server.Defusable.Components;
|
||||
using Content.Server.Defusable.Systems;
|
||||
using Content.Server.Doors.Systems;
|
||||
using Content.Server.Explosion.EntitySystems;
|
||||
using Content.Server.Popups;
|
||||
using Content.Server.Wires;
|
||||
using Content.Shared.Administration.Logs;
|
||||
using Content.Shared.Database;
|
||||
using Content.Shared.Defusable;
|
||||
using Content.Shared.Doors;
|
||||
using Content.Shared.Doors.Components;
|
||||
using Content.Shared.Wires;
|
||||
using Robust.Server.GameObjects;
|
||||
|
||||
namespace Content.Server.Defusable.WireActions;
|
||||
|
||||
public sealed partial class DelayWireAction : ComponentWireAction<DefusableComponent>
|
||||
{
|
||||
public override Color Color { get; set; } = Color.Yellow;
|
||||
public override string Name { get; set; } = "wire-name-bomb-delay";
|
||||
public override bool LightRequiresPower { get; set; } = false;
|
||||
|
||||
public override StatusLightState? GetLightState(Wire wire, DefusableComponent comp)
|
||||
{
|
||||
return comp.DelayWireUsed ? StatusLightState.On : StatusLightState.Off;
|
||||
}
|
||||
|
||||
public override object StatusKey { get; } = DefusableWireStatus.DelayIndicator;
|
||||
|
||||
public override bool Cut(EntityUid user, Wire wire, DefusableComponent comp)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public override bool Mend(EntityUid user, Wire wire, DefusableComponent comp)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public override void Pulse(EntityUid user, Wire wire, DefusableComponent comp)
|
||||
{
|
||||
EntityManager.System<DefusableSystem>().DelayWirePulse(user, wire, comp);
|
||||
}
|
||||
}
|
||||
41
Content.Server/Defusable/WireActions/ProceedWireAction.cs
Normal file
@@ -0,0 +1,41 @@
|
||||
using Content.Server.Defusable.Components;
|
||||
using Content.Server.Defusable.Systems;
|
||||
using Content.Server.Doors.Systems;
|
||||
using Content.Server.Explosion.EntitySystems;
|
||||
using Content.Server.Popups;
|
||||
using Content.Server.Wires;
|
||||
using Content.Shared.Defusable;
|
||||
using Content.Shared.Doors;
|
||||
using Content.Shared.Doors.Components;
|
||||
using Content.Shared.Wires;
|
||||
|
||||
namespace Content.Server.Defusable.WireActions;
|
||||
|
||||
public sealed partial class ProceedWireAction : ComponentWireAction<DefusableComponent>
|
||||
{
|
||||
public override Color Color { get; set; } = Color.Blue;
|
||||
public override string Name { get; set; } = "wire-name-bomb-proceed";
|
||||
public override bool LightRequiresPower { get; set; } = false;
|
||||
|
||||
public override StatusLightState? GetLightState(Wire wire, DefusableComponent comp)
|
||||
{
|
||||
return comp.Activated ? StatusLightState.Off : StatusLightState.BlinkingFast;
|
||||
}
|
||||
|
||||
public override object StatusKey { get; } = DefusableWireStatus.ProceedIndicator;
|
||||
|
||||
public override bool Cut(EntityUid user, Wire wire, DefusableComponent comp)
|
||||
{
|
||||
return EntityManager.System<DefusableSystem>().ProceedWireCut(user, wire, comp);
|
||||
}
|
||||
|
||||
public override bool Mend(EntityUid user, Wire wire, DefusableComponent comp)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public override void Pulse(EntityUid user, Wire wire, DefusableComponent comp)
|
||||
{
|
||||
EntityManager.System<DefusableSystem>().ProceedWirePulse(user, wire, comp);
|
||||
}
|
||||
}
|
||||
@@ -221,6 +221,14 @@ namespace Content.Server.Explosion.EntitySystems
|
||||
return triggerEvent.Handled;
|
||||
}
|
||||
|
||||
public void TryDelay(EntityUid uid, float amount, ActiveTimerTriggerComponent? comp = null)
|
||||
{
|
||||
if (!Resolve(uid, ref comp, false))
|
||||
return;
|
||||
|
||||
comp.TimeRemaining += amount;
|
||||
}
|
||||
|
||||
public void HandleTimerTrigger(EntityUid uid, EntityUid? user, float delay , float beepInterval, float? initialBeepDelay, SoundSpecifier? beepSound)
|
||||
{
|
||||
if (delay <= 0)
|
||||
|
||||
30
Content.Shared/Defusable/SharedDefusableSystem.cs
Normal file
@@ -0,0 +1,30 @@
|
||||
using Robust.Shared.Serialization;
|
||||
|
||||
namespace Content.Shared.Defusable;
|
||||
|
||||
/// <summary>
|
||||
/// This handles defusable explosives, such as Syndicate Bombs.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Most of the logic is in the server
|
||||
/// </remarks>
|
||||
public abstract class SharedDefusableSystem : EntitySystem
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
[NetSerializable, Serializable]
|
||||
public enum DefusableVisuals
|
||||
{
|
||||
Active
|
||||
}
|
||||
|
||||
[NetSerializable, Serializable]
|
||||
public enum DefusableWireStatus
|
||||
{
|
||||
LiveIndicator,
|
||||
BoltIndicator,
|
||||
BoomIndicator,
|
||||
DelayIndicator,
|
||||
ProceedIndicator,
|
||||
}
|
||||
8
Resources/Locale/en-US/defusable/examine.ftl
Normal file
@@ -0,0 +1,8 @@
|
||||
defusable-examine-defused = {CAPITALIZE(THE($name))} is [color=lime]defused[/color].
|
||||
defusable-examine-live = {CAPITALIZE(THE($name))} is [color=red]ticking[/color] and has [color=red]{$time}[/color] seconds remaining.
|
||||
defusable-examine-live-display-off = {CAPITALIZE(THE($name))} is [color=red]ticking[/color], and the timer appears to be off.
|
||||
defusable-examine-inactive = {CAPITALIZE(THE($name))} is [color=lime]inactive[/color], but can still be armed.
|
||||
defusable-examine-bolts = The bolts are {$down ->
|
||||
[true] [color=red]down[/color]
|
||||
*[false] [color=green]up[/color]
|
||||
}.
|
||||
10
Resources/Locale/en-US/defusable/popup.ftl
Normal file
@@ -0,0 +1,10 @@
|
||||
defusable-popup-begun = {CAPITALIZE(THE($name))} beeps to life, it's light is on!
|
||||
defusable-popup-defuse = {CAPITALIZE(THE($name))} beeps one last time, as the light shuts off forever.
|
||||
defusable-popup-boom = {CAPITALIZE(THE($name))} roars as the internal bomb explodes!
|
||||
defusable-popup-fried = {CAPITALIZE(THE($name))} sparks, but fails to begin the countdown.
|
||||
defusable-popup-cant-anchor = {CAPITALIZE(THE($name))} appears to be bolted to the ground!
|
||||
|
||||
defusable-popup-wire-bolt-pulse = The bolts spin in place for a moment.
|
||||
defusable-popup-wire-proceed-pulse = {CAPITALIZE(THE($name))} buzzes ominously!
|
||||
defusable-popup-wire-proceed-cut = The digital display on {THE($name)} deactivates.
|
||||
defusable-popup-wire-chirp = {CAPITALIZE(THE($name))} chirps.
|
||||
1
Resources/Locale/en-US/defusable/verb.ftl
Normal file
@@ -0,0 +1 @@
|
||||
defusable-verb-begin = Begin countdown
|
||||
@@ -44,6 +44,8 @@ guide-entry-machine-upgrading = Machine Upgrading
|
||||
guide-entry-robotics = Robotics
|
||||
guide-entry-security = Security
|
||||
guide-entry-dna = DNA
|
||||
guide-entry-defusal = Large Bomb Defusal
|
||||
|
||||
guide-entry-antagonists = Antagonists
|
||||
guide-entry-nuclear-operatives = Nuclear Operatives
|
||||
guide-entry-traitors = Traitors
|
||||
|
||||
@@ -60,6 +60,9 @@ uplink-emp-grenade-desc = A grenade designed to disrupt electronic systems. Usef
|
||||
uplink-exploding-pen-name = Exploding pen
|
||||
uplink-exploding-pen-desc = A class IV explosive device contained within a standard pen. Comes with a 4 second fuse.
|
||||
|
||||
uplink-exploding-syndicate-bomb-name = Syndicate Bomb
|
||||
uplink-exploding-syndicate-bomb-desc = A reliable bomb that can put a big hole in the station. Useful as a distraction.
|
||||
|
||||
# Ammo
|
||||
uplink-pistol-magazine-name = Pistol Magazine (.35 auto)
|
||||
uplink-pistol-magazine-desc = Pistol magazine with 10 catridges. Compatible with the Viper.
|
||||
|
||||
@@ -54,3 +54,8 @@ wire-name-pa-keyboard = KEYB
|
||||
wire-name-pa-limiter = LIMT
|
||||
wire-name-pa-power = POWR
|
||||
wire-name-pa-strength = STRC
|
||||
wire-name-bomb-live = LIVE
|
||||
wire-name-bomb-delay = DLAY
|
||||
wire-name-bomb-proceed = PRCD
|
||||
wire-name-bomb-boom = BOOM
|
||||
wire-name-bomb-bolt = BOLT
|
||||
|
||||
@@ -239,6 +239,16 @@
|
||||
categories:
|
||||
- UplinkExplosives
|
||||
|
||||
- type: listing
|
||||
id: UplinkSyndicateBomb
|
||||
name: uplink-syndicate-bomb-name
|
||||
description: uplink-syndicate-bomb-desc
|
||||
productEntity: SyndicateBomb
|
||||
cost:
|
||||
Telecrystal: 11
|
||||
categories:
|
||||
- UplinkExplosives
|
||||
|
||||
# Ammo
|
||||
|
||||
- type: listing
|
||||
|
||||
156
Resources/Prototypes/Entities/Structures/Machines/bombs.yml
Normal file
@@ -0,0 +1,156 @@
|
||||
- type: entity
|
||||
abstract: true
|
||||
parent: BaseStructure
|
||||
id: BaseHardBomb
|
||||
description: Just keep talking and nobody will explode.
|
||||
name: hardbomb
|
||||
components:
|
||||
- type: Appearance
|
||||
- type: WiresVisuals
|
||||
- type: InteractionOutline
|
||||
- type: UserInterface
|
||||
interfaces:
|
||||
- key: enum.WiresUiKey.Key
|
||||
type: WiresBoundUserInterface
|
||||
- type: Wires
|
||||
LayoutId: Defusable
|
||||
alwaysRandomize: true
|
||||
- type: Defusable
|
||||
- type: Explosive
|
||||
explosionType: Default
|
||||
totalIntensity: 20.0
|
||||
intensitySlope: 5
|
||||
maxIntensity: 4
|
||||
- type: ExplodeOnTrigger
|
||||
- type: OnUseTimerTrigger
|
||||
delay: 90
|
||||
delayOptions: [90, 120, 150, 180, 210, 240, 270, 300]
|
||||
initialBeepDelay: 0
|
||||
beepSound: /Audio/Machines/Nuke/general_beep.ogg
|
||||
- type: Anchorable
|
||||
delay: 5
|
||||
- type: Physics
|
||||
bodyType: Static
|
||||
- type: Transform
|
||||
noRot: true
|
||||
- type: Fixtures
|
||||
fixtures:
|
||||
fix1:
|
||||
shape:
|
||||
!type:PhysShapeAabb
|
||||
bounds: "-0.45,-0.45,0.45,0.45"
|
||||
density: 190
|
||||
mask:
|
||||
- MachineMask
|
||||
layer:
|
||||
- MachineLayer
|
||||
- type: WiresPanel
|
||||
- type: Damageable
|
||||
damageContainer: Inorganic
|
||||
damageModifierSet: Metallic
|
||||
- type: Destructible
|
||||
thresholds:
|
||||
- trigger:
|
||||
!type:DamageTrigger
|
||||
damage: 100
|
||||
behaviors:
|
||||
- !type:DoActsBehavior
|
||||
acts: ["Destruction"]
|
||||
- !type:ExplodeBehavior
|
||||
- !type:PlaySoundBehavior
|
||||
sound:
|
||||
path: /Audio/Effects/metalbreak.ogg
|
||||
- type: GuideHelp
|
||||
openOnActivation: true
|
||||
guides:
|
||||
- Defusal
|
||||
|
||||
- type: entity
|
||||
parent: BaseHardBomb
|
||||
id: TrainingBomb
|
||||
name: training bomb
|
||||
description: A bomb for dummies, manual not included.
|
||||
components:
|
||||
- type: Wires
|
||||
LayoutId: TrainingDefusable
|
||||
alwaysRandomize: true
|
||||
- type: Sprite
|
||||
sprite: Structures/Machines/bomb.rsi
|
||||
layers:
|
||||
- state: training-bomb
|
||||
- state: training-bomb-active
|
||||
visible: false
|
||||
map: [ "primed" ]
|
||||
- state: training-bomb-wires
|
||||
visible: false
|
||||
map: [ "enum.WiresVisualLayers.MaintenancePanel" ]
|
||||
- type: GenericVisualizer
|
||||
visuals:
|
||||
enum.DefusableVisuals.Active:
|
||||
primed:
|
||||
True: { visible: true }
|
||||
False: { visible: false }
|
||||
enum.WiresVisualLayers.MaintenancePanel:
|
||||
enum.WiresVisualLayers.MaintenancePanel:
|
||||
True: { visible: true }
|
||||
False: { visible: false }
|
||||
- type: PointLight
|
||||
color: "#0063C7"
|
||||
radius: 1.1
|
||||
softness: 1
|
||||
- type: Explosive
|
||||
explosionType: Default
|
||||
totalIntensity: 5.0
|
||||
intensitySlope: 5
|
||||
maxIntensity: 4
|
||||
- type: Defusable
|
||||
disposable: false
|
||||
|
||||
- type: entity
|
||||
parent: BaseHardBomb
|
||||
id: SyndicateBomb
|
||||
name: syndicate bomb
|
||||
description: A bomb for Syndicate operatives and agents alike. The real deal, no more training, get to it!
|
||||
components:
|
||||
- type: Sprite
|
||||
sprite: Structures/Machines/bomb.rsi
|
||||
layers:
|
||||
- state: syndicate-bomb
|
||||
- state: syndicate-bomb-active
|
||||
visible: false
|
||||
map: [ "primed" ]
|
||||
- state: syndicate-bomb-wires
|
||||
visible: false
|
||||
map: [ "enum.WiresVisualLayers.MaintenancePanel" ]
|
||||
- type: GenericVisualizer
|
||||
visuals:
|
||||
enum.DefusableVisuals.Active:
|
||||
primed:
|
||||
True: { visible: true }
|
||||
False: { visible: false }
|
||||
enum.WiresVisualLayers.MaintenancePanel:
|
||||
enum.WiresVisualLayers.MaintenancePanel:
|
||||
True: { visible: true }
|
||||
False: { visible: false }
|
||||
- type: PointLight
|
||||
color: "#C7001B"
|
||||
radius: 1.1
|
||||
softness: 1
|
||||
- type: Explosive
|
||||
explosionType: HardBomb
|
||||
totalIntensity: 4000.0
|
||||
intensitySlope: 3
|
||||
maxIntensity: 400
|
||||
|
||||
- type: entity
|
||||
parent: SyndicateBomb
|
||||
id: DebugHardBomb
|
||||
name: debug bomb
|
||||
suffix: DEBUG
|
||||
description: Holy shit this is gonna explode
|
||||
components:
|
||||
- type: Defusable
|
||||
disposable: true
|
||||
- type: OnUseTimerTrigger
|
||||
delay: 10
|
||||
delayOptions: [10, 20, 30, 60, 90, 120, 150, 180, 210, 240, 270, 300]
|
||||
@@ -4,8 +4,14 @@
|
||||
text: "/ServerInfo/Guidebook/Security/Security.xml"
|
||||
children:
|
||||
- DNA
|
||||
- Defusal
|
||||
|
||||
- type: guideEntry
|
||||
id: DNA
|
||||
name: guide-entry-dna
|
||||
text: "/ServerInfo/Guidebook/Security/DNA.xml"
|
||||
|
||||
- type: guideEntry
|
||||
id: Defusal
|
||||
name: guide-entry-defusal
|
||||
text: "/ServerInfo/Guidebook/Security/Defusal.xml"
|
||||
|
||||
@@ -96,3 +96,25 @@
|
||||
- !type:DoorBoltLightWireAction
|
||||
- !type:DoorTimingWireAction
|
||||
- !type:DoorSafetyWireAction
|
||||
|
||||
- type: wireLayout
|
||||
id: Defusable
|
||||
dummyWires: 3
|
||||
wires:
|
||||
- !type:ActivateWireAction
|
||||
- !type:BoltWireAction
|
||||
- !type:DelayWireAction
|
||||
- !type:ProceedWireAction
|
||||
- !type:BoomWireAction
|
||||
- !type:BoomWireAction
|
||||
- !type:BoomWireAction
|
||||
|
||||
- type: wireLayout
|
||||
id: TrainingDefusable
|
||||
dummyWires: 0
|
||||
wires:
|
||||
- !type:ActivateWireAction
|
||||
- !type:BoltWireAction
|
||||
- !type:DelayWireAction
|
||||
- !type:ProceedWireAction
|
||||
- !type:BoomWireAction
|
||||
|
||||
@@ -101,3 +101,19 @@
|
||||
lightColor: Orange
|
||||
texturePath: /Textures/Effects/fire.rsi
|
||||
fireStates: 6
|
||||
|
||||
- type: explosion
|
||||
id: HardBomb
|
||||
damagePerIntensity:
|
||||
types:
|
||||
Heat: 15
|
||||
Blunt: 15
|
||||
Piercing: 6
|
||||
Structural: 15
|
||||
tileBreakChance: [ 0.75, 0.95, 1 ]
|
||||
tileBreakIntensity: [ 1, 10, 15 ]
|
||||
tileBreakRerollReduction: 30
|
||||
intensityPerState: 20
|
||||
lightColor: Orange
|
||||
texturePath: /Textures/Effects/fire.rsi
|
||||
fireStates: 6
|
||||
|
||||
73
Resources/ServerInfo/Guidebook/Security/Defusal.xml
Normal file
@@ -0,0 +1,73 @@
|
||||
<Document>
|
||||
# Large Bomb Defusal
|
||||
So, you found a large bomb and it's beeping. These bombs take a long time to detonate and punch a big hole into the hull. Just keep reading, and nobody will explode.
|
||||
|
||||
## Gear
|
||||
You require two essential tools to perform defusal, however, a multitool is extremely helpful in terms of identifying wires.
|
||||
<Box>
|
||||
<GuideEntityEmbed Entity="Wirecutter"/>
|
||||
<GuideEntityEmbed Entity="Screwdriver"/>
|
||||
<GuideEntityEmbed Entity="Multitool"/>
|
||||
</Box>
|
||||
|
||||
For protective equipment, a [color=yellow]bomb suit[/color] or any other protective equipment can assist you in not blowing into gibs.
|
||||
<Box>
|
||||
<GuideEntityEmbed Entity="ClothingHeadHelmetBombSuit"/>
|
||||
<GuideEntityEmbed Entity="ClothingOuterSuitBomb"/>
|
||||
<GuideEntityEmbed Entity="ClothingOuterHardsuitRd"/>
|
||||
<GuideEntityEmbed Entity="ClothingOuterHardsuitAtmos"/>
|
||||
</Box>
|
||||
|
||||
## Hardbombs
|
||||
Listed below are the two common types of bombs you will encounter while defusing. A training bomb will only provide minor hull damage and generally not kill you. A syndicate bomb however will punch a big hole into the hull, and gib you if you are not wearing protective gear.
|
||||
<Box>
|
||||
<GuideEntityEmbed Entity="SyndicateBomb"/>
|
||||
<GuideEntityEmbed Entity="TrainingBomb"/>
|
||||
</Box>
|
||||
|
||||
## Arming
|
||||
To arm a bomb, you can either [color=yellow]right click[/color] and click [color=yellow]Begin countdown[/click], or [color=yellow]alt-click[/color] the bomb. It will begin beeping.
|
||||
|
||||
## Time
|
||||
A bomb has a limited time, at a minimum of 90 and a maximum of 300. You can view the timer by examining it, unless the Proceed wire is cut. Once the timer hits zero, the bomb will detonate.
|
||||
|
||||
## Bolts
|
||||
By default, once armed, a bomb will bolt itself to the ground. You must find the BOLT wire and cut it to disable the bolts, after which you can unwrench it and throw it into space.
|
||||
|
||||
## Wires
|
||||
You must access the wiring in order to defuse a bomb. You can use a [color=yellow]screwdriver[/color] to open the access panel. Inside, you will find many types of wires. In a standard syndicate bomb, there are around [color=yellow]10 wires[/color], 3 are dummy wires, [color=red]3 will cause a detonation[/color], and the rest that weren't mentioned can be found below (alongside BOOM wires). With each wire, you can do 3 actions. You can:
|
||||
- [color=yellow]Pulse the wire[/color] with a multitool, this can help you safely identify most wires.
|
||||
- [color=red]Cut the wire[/color] with a wirecutter, this can trigger various effects, be cautious of cutting without reason!
|
||||
- [color=green]Mend the wire[/color] with a wirecutter, this can restore some functionality of the bomb if it isn't disposable.
|
||||
|
||||
Onward for the types of wires.
|
||||
|
||||
## Wire Types
|
||||
[color=#a4885c]Activation Wire (LIVE)[/color]
|
||||
- [color=yellow]Pulse the wire[/color]: Pulsing the wire will make the wire chirp and delay the bomb by 30 seconds.
|
||||
- [color=red]Cut the wire[/color]: Cutting the wire will defuse the bomb if active, otherwise, will begin the timer.
|
||||
- [color=green]Mend the wire[/color]: Nothing.
|
||||
|
||||
[color=#a4885c]Proceed Wire (PRCD)[/color]
|
||||
- [color=yellow]Pulse the wire[/color]: Pulsing the wire will forward the time by 15 seconds.
|
||||
- [color=red]Cut the wire[/color]: Cutting the wire will disable the timer display on examine.
|
||||
- [color=green]Mend the wire[/color]: Nothing.
|
||||
|
||||
[color=#a4885c]Delay Wire (DLAY)[/color]
|
||||
- [color=yellow]Pulse the wire[/color]: Pulsing the delay wire will delay the bomb by 30 seconds.
|
||||
- [color=red]Cut the wire[/color]: Nothing.
|
||||
- [color=green]Mend the wire[/color]: Nothing.
|
||||
|
||||
[color=#a4885c]Boom Wire (BOOM)[/color]
|
||||
- [color=yellow]Pulse the wire[/color]: [color=red]The bomb will explode if armed![/color]
|
||||
- [color=red]Cut the wire[/color]: [color=red]The bomb will explode if armed![/color] Otherwise, will disable the bomb.
|
||||
- [color=green]Mend the wire[/color]: Re-enables the bomb if disabled previously.
|
||||
|
||||
[color=#a4885c]Bolt Wire (BOLT)[/color]
|
||||
- [color=yellow]Pulse the wire[/color]: Pulsing the wire will make the bolts spin.
|
||||
- [color=red]Cut the wire[/color]: Cutting the wire will disable the bolts, throw it into space!
|
||||
- [color=green]Mend the wire[/color]: Mending the wire will re-enable the bolts.
|
||||
|
||||
[color=#a4885c]Dummy Wire[/color]
|
||||
- Dummy wires don't do anything. You can pulse, cut, and mend them freely and they will not affect the bomb at all.
|
||||
</Document>
|
||||
|
After Width: | Height: | Size: 622 B |
|
After Width: | Height: | Size: 154 B |
BIN
Resources/Textures/Structures/Machines/bomb.rsi/base-bomb.png
Normal file
|
After Width: | Height: | Size: 349 B |
59
Resources/Textures/Structures/Machines/bomb.rsi/meta.json
Normal file
@@ -0,0 +1,59 @@
|
||||
{
|
||||
"version": 1,
|
||||
"license": "CC-BY-SA-3.0",
|
||||
"copyright": "Taken from https://github.com/tgstation/tgstation/blob/fed8ed6d62de3003260303d021f6138bb90a60ce/icons/obj/assemblies/assemblies.dmi",
|
||||
"size": {
|
||||
"x": 32,
|
||||
"y": 32
|
||||
},
|
||||
"states": [
|
||||
{
|
||||
"name": "base-bomb"
|
||||
},
|
||||
{
|
||||
"name": "base-bomb-wires"
|
||||
},
|
||||
{
|
||||
"name": "base-bomb-active",
|
||||
"delays": [
|
||||
[
|
||||
0.25,
|
||||
0.25,
|
||||
0.25
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "syndicate-bomb"
|
||||
},
|
||||
{
|
||||
"name": "syndicate-bomb-wires"
|
||||
},
|
||||
{
|
||||
"name": "syndicate-bomb-active",
|
||||
"delays": [
|
||||
[
|
||||
0.25,
|
||||
0.25,
|
||||
0.25
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "training-bomb"
|
||||
},
|
||||
{
|
||||
"name": "training-bomb-wires"
|
||||
},
|
||||
{
|
||||
"name": "training-bomb-active",
|
||||
"delays": [
|
||||
[
|
||||
0.25,
|
||||
0.25,
|
||||
0.25
|
||||
]
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
After Width: | Height: | Size: 627 B |
|
After Width: | Height: | Size: 155 B |
|
After Width: | Height: | Size: 353 B |
|
After Width: | Height: | Size: 596 B |
|
After Width: | Height: | Size: 154 B |
|
After Width: | Height: | Size: 349 B |