Makes adjustment to macro bomb implants and how mobstate trigger handles suicide (#12682)
This commit is contained in:
@@ -27,26 +27,27 @@ namespace Content.Server.Chat
|
||||
{
|
||||
// Checks to see if the CannotSuicide tag exits, ghosts instead.
|
||||
if (_tagSystem.HasTag(victim, "CannotSuicide"))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Checks to see if the player is dead.
|
||||
if (!TryComp<MobStateComponent>(victim, out var mobState) || _mobState.IsDead(victim, mobState))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
_adminLogger.Add(LogType.Suicide,
|
||||
$"{EntityManager.ToPrettyString(victim):player} is committing suicide");
|
||||
_adminLogger.Add(LogType.Suicide, $"{EntityManager.ToPrettyString(victim):player} is committing suicide");
|
||||
|
||||
var suicideEvent = new SuicideEvent(victim);
|
||||
|
||||
//Check to see if there were any systems blocking this suicide
|
||||
if (SuicideAttemptBlocked(victim, suicideEvent))
|
||||
return false;
|
||||
|
||||
// If you are critical, you wouldn't be able to use your surroundings to suicide, so you do the default suicide
|
||||
if (!_mobState.IsCritical(victim, mobState))
|
||||
{
|
||||
EnvironmentSuicideHandler(victim, suicideEvent);
|
||||
}
|
||||
|
||||
if (suicideEvent.AttemptBlocked)
|
||||
return false;
|
||||
|
||||
DefaultSuicideHandler(victim, suicideEvent);
|
||||
|
||||
ApplyDeath(victim, suicideEvent.Kind!.Value);
|
||||
@@ -58,7 +59,9 @@ namespace Content.Server.Chat
|
||||
/// </summary>
|
||||
private static void DefaultSuicideHandler(EntityUid victim, SuicideEvent suicideEvent)
|
||||
{
|
||||
if (suicideEvent.Handled) return;
|
||||
if (suicideEvent.Handled)
|
||||
return;
|
||||
|
||||
var othersMessage = Loc.GetString("suicide-command-default-text-others", ("name", victim));
|
||||
victim.PopupMessageOtherClients(othersMessage);
|
||||
|
||||
@@ -68,10 +71,26 @@ namespace Content.Server.Chat
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Raise event to attempt to use held item, or surrounding entities to commit suicide
|
||||
/// Checks to see if there are any other systems that prevent suicide
|
||||
/// </summary>
|
||||
/// <returns>Returns true if there was a blocked attempt</returns>
|
||||
private bool SuicideAttemptBlocked(EntityUid victim, SuicideEvent suicideEvent)
|
||||
{
|
||||
RaiseLocalEvent(victim, suicideEvent, false);
|
||||
|
||||
if (suicideEvent.AttemptBlocked)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Raise event to attempt to use held item, or surrounding entities to attempt to commit suicide
|
||||
/// </summary>
|
||||
private void EnvironmentSuicideHandler(EntityUid victim, SuicideEvent suicideEvent)
|
||||
{
|
||||
var itemQuery = GetEntityQuery<ItemComponent>();
|
||||
|
||||
// Suicide by held item
|
||||
if (EntityManager.TryGetComponent(victim, out HandsComponent? handsComponent)
|
||||
&& handsComponent.ActiveHandEntity is { } item)
|
||||
@@ -82,8 +101,6 @@ namespace Content.Server.Chat
|
||||
return;
|
||||
}
|
||||
|
||||
var itemQuery = GetEntityQuery<ItemComponent>();
|
||||
|
||||
// Suicide by nearby entity (ex: Microwave)
|
||||
foreach (var entity in _entityLookupSystem.GetEntitiesInRange(victim, 1, LookupFlags.Approximate | LookupFlags.Anchored))
|
||||
{
|
||||
@@ -106,8 +123,7 @@ namespace Content.Server.Chat
|
||||
if (!_prototypeManager.TryIndex<DamageTypePrototype>(kind.ToString(), out var damagePrototype))
|
||||
{
|
||||
const SuicideKind fallback = SuicideKind.Blunt;
|
||||
Logger.Error(
|
||||
$"{nameof(SuicideSystem)} could not find the damage type prototype associated with {kind}. Falling back to {fallback}");
|
||||
Logger.Error($"{nameof(SuicideSystem)} could not find the damage type prototype associated with {kind}. Falling back to {fallback}");
|
||||
damagePrototype = _prototypeManager.Index<DamageTypePrototype>(fallback.ToString());
|
||||
}
|
||||
const int lethalAmountOfDamage = 200; // TODO: Would be nice to get this number from somewhere else
|
||||
|
||||
@@ -11,6 +11,14 @@ public sealed class TriggerOnMobstateChangeComponent : Component
|
||||
/// <summary>
|
||||
/// What state should trigger this?
|
||||
/// </summary>
|
||||
[ViewVariables]
|
||||
[DataField("mobState", required: true)]
|
||||
public DamageState MobState = DamageState.Alive;
|
||||
|
||||
/// <summary>
|
||||
/// If true, prevents suicide attempts for the trigger to prevent cheese.
|
||||
/// </summary>
|
||||
[ViewVariables]
|
||||
[DataField("preventSuicide")]
|
||||
public bool PreventSuicide = false;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
using Content.Server.Explosion.Components;
|
||||
using Content.Shared.Interaction.Events;
|
||||
using Content.Shared.MobState;
|
||||
using Robust.Shared.Player;
|
||||
|
||||
namespace Content.Server.Explosion.EntitySystems;
|
||||
|
||||
public sealed partial class TriggerSystem
|
||||
{
|
||||
private void InitializeMobstate()
|
||||
{
|
||||
SubscribeLocalEvent<TriggerOnMobstateChangeComponent, MobStateChangedEvent>(OnMobStateChanged);
|
||||
SubscribeLocalEvent<TriggerOnMobstateChangeComponent, SuicideEvent>(OnSuicide);
|
||||
}
|
||||
|
||||
private void OnMobStateChanged(EntityUid uid, TriggerOnMobstateChangeComponent component, MobStateChangedEvent args)
|
||||
{
|
||||
if (component.MobState < args.CurrentMobState)
|
||||
return;
|
||||
|
||||
//This chains Mobstate Changed triggers with OnUseTimerTrigger if they have it
|
||||
//Very useful for things that require a mobstate change and a timer
|
||||
if (TryComp<OnUseTimerTriggerComponent>(uid, out var timerTrigger))
|
||||
{
|
||||
HandleTimerTrigger(
|
||||
uid,
|
||||
args.Origin,
|
||||
timerTrigger.Delay,
|
||||
timerTrigger.BeepInterval,
|
||||
timerTrigger.InitialBeepDelay,
|
||||
timerTrigger.BeepSound,
|
||||
timerTrigger.BeepParams);
|
||||
}
|
||||
|
||||
else
|
||||
Trigger(uid);
|
||||
}
|
||||
|
||||
private void OnSuicide(EntityUid uid, TriggerOnMobstateChangeComponent component, SuicideEvent args)
|
||||
{
|
||||
if (args.Handled)
|
||||
return;
|
||||
|
||||
if (component.PreventSuicide)
|
||||
{
|
||||
_popupSystem.PopupEntity(Loc.GetString("suicide-prevented"), args.Victim, Filter.Entities(args.Victim));
|
||||
args.BlockSuicideAttempt(component.PreventSuicide);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,9 +1,8 @@
|
||||
using Content.Server.Explosion.Components;
|
||||
using Content.Server.Sticky.Events;
|
||||
using Content.Shared.Examine;
|
||||
using Content.Shared.Popups;
|
||||
using Content.Shared.Interaction.Events;
|
||||
using Content.Shared.MobState;
|
||||
using Content.Shared.Popups;
|
||||
using Content.Shared.Verbs;
|
||||
using Robust.Shared.Player;
|
||||
|
||||
@@ -142,7 +141,8 @@ public sealed partial class TriggerSystem
|
||||
|
||||
private void OnTimerUse(EntityUid uid, OnUseTimerTriggerComponent component, UseInHandEvent args)
|
||||
{
|
||||
if (args.Handled) return;
|
||||
if (args.Handled)
|
||||
return;
|
||||
|
||||
HandleTimerTrigger(
|
||||
uid,
|
||||
|
||||
@@ -5,26 +5,18 @@ using Content.Server.Chemistry.Components.SolutionManager;
|
||||
using Content.Server.Explosion.Components;
|
||||
using Content.Server.Flash;
|
||||
using Content.Server.Flash.Components;
|
||||
using Content.Server.Sticky.Events;
|
||||
using Content.Shared.Actions;
|
||||
using Content.Shared.Body.Components;
|
||||
using JetBrains.Annotations;
|
||||
using Robust.Shared.Audio;
|
||||
using Robust.Shared.Physics;
|
||||
using Robust.Shared.Physics.Dynamics;
|
||||
using Robust.Shared.Player;
|
||||
using Content.Shared.Trigger;
|
||||
using Content.Shared.Database;
|
||||
using Content.Shared.Explosion;
|
||||
using Content.Shared.Implants.Components;
|
||||
using Content.Shared.Interaction;
|
||||
using Content.Shared.MobState;
|
||||
using Content.Shared.Payload.Components;
|
||||
using Content.Shared.StepTrigger.Systems;
|
||||
using Robust.Server.Containers;
|
||||
using Content.Shared.Trigger;
|
||||
using JetBrains.Annotations;
|
||||
using Robust.Shared.Audio;
|
||||
using Robust.Shared.Containers;
|
||||
using Robust.Shared.Physics.Events;
|
||||
using Robust.Shared.Physics.Systems;
|
||||
using Robust.Shared.Player;
|
||||
|
||||
namespace Content.Server.Explosion.EntitySystems
|
||||
{
|
||||
@@ -63,12 +55,12 @@ namespace Content.Server.Explosion.EntitySystems
|
||||
InitializeSignal();
|
||||
InitializeTimedCollide();
|
||||
InitializeVoice();
|
||||
InitializeMobstate();
|
||||
|
||||
SubscribeLocalEvent<TriggerOnCollideComponent, StartCollideEvent>(OnTriggerCollide);
|
||||
SubscribeLocalEvent<TriggerOnActivateComponent, ActivateInWorldEvent>(OnActivate);
|
||||
SubscribeLocalEvent<TriggerImplantActionComponent, ActivateImplantEvent>(OnImplantTrigger);
|
||||
SubscribeLocalEvent<TriggerOnStepTriggerComponent, StepTriggeredEvent>(OnStepTriggered);
|
||||
SubscribeLocalEvent<TriggerOnMobstateChangeComponent, MobStateChangedEvent>(OnMobStateChanged);
|
||||
|
||||
SubscribeLocalEvent<DeleteOnTriggerComponent, TriggerEvent>(HandleDeleteTrigger);
|
||||
SubscribeLocalEvent<ExplodeOnTriggerComponent, TriggerEvent>(HandleExplodeTrigger);
|
||||
@@ -130,29 +122,6 @@ namespace Content.Server.Explosion.EntitySystems
|
||||
Trigger(uid, args.Tripper);
|
||||
}
|
||||
|
||||
private void OnMobStateChanged(EntityUid uid, TriggerOnMobstateChangeComponent component, MobStateChangedEvent args)
|
||||
{
|
||||
if (component.MobState < args.CurrentMobState)
|
||||
return;
|
||||
|
||||
//This chains Mobstate Changed triggers with OnUseTimerTrigger if they have it
|
||||
//Very useful for things that require a mobstate change and a timer
|
||||
if (TryComp<OnUseTimerTriggerComponent>(uid, out var timerTrigger))
|
||||
{
|
||||
HandleTimerTrigger(
|
||||
uid,
|
||||
args.Origin,
|
||||
timerTrigger.Delay,
|
||||
timerTrigger.BeepInterval,
|
||||
timerTrigger.InitialBeepDelay,
|
||||
timerTrigger.BeepSound,
|
||||
timerTrigger.BeepParams);
|
||||
}
|
||||
|
||||
else
|
||||
Trigger(uid);
|
||||
}
|
||||
|
||||
public bool Trigger(EntityUid trigger, EntityUid? user = null)
|
||||
{
|
||||
var triggerEvent = new TriggerEvent(trigger, user);
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using Content.Server.Cuffs.Components;
|
||||
using Content.Shared.Implants;
|
||||
using Content.Shared.Implants.Components;
|
||||
using Content.Shared.Interaction.Events;
|
||||
using Content.Shared.MobState;
|
||||
using Robust.Shared.Containers;
|
||||
|
||||
@@ -17,6 +18,7 @@ public sealed class SubdermalImplantSystem : SharedSubdermalImplantSystem
|
||||
SubscribeLocalEvent<SubdermalImplantComponent, UseFreedomImplantEvent>(OnFreedomImplant);
|
||||
|
||||
SubscribeLocalEvent<ImplantedComponent, MobStateChangedEvent>(RelayToImplantEvent);
|
||||
SubscribeLocalEvent<ImplantedComponent, SuicideEvent>(RelayToImplantEvent);
|
||||
}
|
||||
|
||||
private void OnFreedomImplant(EntityUid uid, SubdermalImplantComponent component, UseFreedomImplantEvent args)
|
||||
|
||||
@@ -11,12 +11,21 @@ namespace Content.Shared.Interaction.Events
|
||||
}
|
||||
public void SetHandled(SuicideKind kind)
|
||||
{
|
||||
if (Handled) throw new InvalidOperationException("Suicide was already handled");
|
||||
if (Handled)
|
||||
throw new InvalidOperationException("Suicide was already handled");
|
||||
|
||||
Kind = kind;
|
||||
}
|
||||
|
||||
public void BlockSuicideAttempt(bool suicideAttempt)
|
||||
{
|
||||
if (suicideAttempt)
|
||||
AttemptBlocked = suicideAttempt;
|
||||
}
|
||||
|
||||
public SuicideKind? Kind { get; private set; }
|
||||
public EntityUid Victim { get; private set; }
|
||||
public bool AttemptBlocked { get; private set; }
|
||||
public bool Handled => Kind != null;
|
||||
}
|
||||
|
||||
|
||||
1
Resources/Locale/en-US/suicide/suicide.ftl
Normal file
1
Resources/Locale/en-US/suicide/suicide.ftl
Normal file
@@ -0,0 +1 @@
|
||||
suicide-prevented = You tried to suicide, but only your spirit escapes.
|
||||
@@ -321,14 +321,18 @@
|
||||
description: Inject this and on death you'll create a large explosion. Huge team casualty cost, use at own risk. Replaces internal micro bomb.
|
||||
productEntity: MacroBombImplanter
|
||||
cost:
|
||||
Telecrystal: 20
|
||||
Telecrystal: 25
|
||||
categories:
|
||||
- UplinkUtility
|
||||
conditions:
|
||||
- !type:StoreWhitelistCondition
|
||||
blacklist:
|
||||
whitelist:
|
||||
tags:
|
||||
- TraitorUplink
|
||||
- NukeOpsUplink
|
||||
- !type:BuyerWhitelistCondition
|
||||
blacklist:
|
||||
components:
|
||||
- SurplusBundle
|
||||
|
||||
# Bundles
|
||||
|
||||
|
||||
@@ -154,8 +154,9 @@
|
||||
permanent: true
|
||||
- type: TriggerOnMobstateChange #Chains with OnUseTimerTrigger
|
||||
mobState: Dead
|
||||
preventSuicide: true
|
||||
- type: OnUseTimerTrigger
|
||||
delay: 5
|
||||
delay: 7
|
||||
initialBeepDelay: 0
|
||||
beepSound: /Audio/Machines/Nuke/general_beep.ogg
|
||||
- type: ExplodeOnTrigger
|
||||
@@ -163,9 +164,9 @@
|
||||
deleteItems: true
|
||||
- type: Explosive
|
||||
explosionType: Default
|
||||
totalIntensity: 4000
|
||||
intensitySlope: 5
|
||||
maxIntensity: 50
|
||||
totalIntensity: 3500
|
||||
intensitySlope: 15
|
||||
maxIntensity: 70
|
||||
canCreateVacuum: true
|
||||
- type: Tag
|
||||
tags:
|
||||
|
||||
@@ -82,9 +82,6 @@
|
||||
preset: StorePresetUplink
|
||||
balance:
|
||||
Telecrystal: 20
|
||||
- type: Tag
|
||||
tags:
|
||||
- TraitorUplink
|
||||
|
||||
- type: entity
|
||||
parent: BaseUplinkRadio
|
||||
@@ -95,9 +92,6 @@
|
||||
preset: StorePresetUplink
|
||||
balance:
|
||||
Telecrystal: 25
|
||||
- type: Tag
|
||||
tags:
|
||||
- TraitorUplink
|
||||
|
||||
#this uplink MUST be used for nukeops, as it has the tag for filtering the listing.
|
||||
- type: entity
|
||||
|
||||
@@ -380,9 +380,6 @@
|
||||
- type: Tag
|
||||
id: NoSpinOnThrow
|
||||
|
||||
- type: Tag
|
||||
id: TraitorUplink
|
||||
|
||||
- type: Tag
|
||||
id: NoBlockAnchoring
|
||||
|
||||
|
||||
Reference in New Issue
Block a user