Makes adjustment to macro bomb implants and how mobstate trigger handles suicide (#12682)

This commit is contained in:
keronshb
2022-11-20 21:51:44 -05:00
committed by GitHub
parent d1b5630648
commit 21c1cb57ce
12 changed files with 122 additions and 71 deletions

View File

@@ -27,26 +27,27 @@ namespace Content.Server.Chat
{ {
// Checks to see if the CannotSuicide tag exits, ghosts instead. // Checks to see if the CannotSuicide tag exits, ghosts instead.
if (_tagSystem.HasTag(victim, "CannotSuicide")) if (_tagSystem.HasTag(victim, "CannotSuicide"))
{
return false; return false;
}
// Checks to see if the player is dead. // Checks to see if the player is dead.
if (!TryComp<MobStateComponent>(victim, out var mobState) || _mobState.IsDead(victim, mobState)) if (!TryComp<MobStateComponent>(victim, out var mobState) || _mobState.IsDead(victim, mobState))
{
return false; return false;
}
_adminLogger.Add(LogType.Suicide, _adminLogger.Add(LogType.Suicide, $"{EntityManager.ToPrettyString(victim):player} is committing suicide");
$"{EntityManager.ToPrettyString(victim):player} is committing suicide");
var suicideEvent = new SuicideEvent(victim); 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 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)) if (!_mobState.IsCritical(victim, mobState))
{
EnvironmentSuicideHandler(victim, suicideEvent); EnvironmentSuicideHandler(victim, suicideEvent);
}
if (suicideEvent.AttemptBlocked)
return false;
DefaultSuicideHandler(victim, suicideEvent); DefaultSuicideHandler(victim, suicideEvent);
ApplyDeath(victim, suicideEvent.Kind!.Value); ApplyDeath(victim, suicideEvent.Kind!.Value);
@@ -58,7 +59,9 @@ namespace Content.Server.Chat
/// </summary> /// </summary>
private static void DefaultSuicideHandler(EntityUid victim, SuicideEvent suicideEvent) 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)); var othersMessage = Loc.GetString("suicide-command-default-text-others", ("name", victim));
victim.PopupMessageOtherClients(othersMessage); victim.PopupMessageOtherClients(othersMessage);
@@ -68,10 +71,26 @@ namespace Content.Server.Chat
} }
/// <summary> /// <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> /// </summary>
private void EnvironmentSuicideHandler(EntityUid victim, SuicideEvent suicideEvent) private void EnvironmentSuicideHandler(EntityUid victim, SuicideEvent suicideEvent)
{ {
var itemQuery = GetEntityQuery<ItemComponent>();
// Suicide by held item // Suicide by held item
if (EntityManager.TryGetComponent(victim, out HandsComponent? handsComponent) if (EntityManager.TryGetComponent(victim, out HandsComponent? handsComponent)
&& handsComponent.ActiveHandEntity is { } item) && handsComponent.ActiveHandEntity is { } item)
@@ -82,8 +101,6 @@ namespace Content.Server.Chat
return; return;
} }
var itemQuery = GetEntityQuery<ItemComponent>();
// Suicide by nearby entity (ex: Microwave) // Suicide by nearby entity (ex: Microwave)
foreach (var entity in _entityLookupSystem.GetEntitiesInRange(victim, 1, LookupFlags.Approximate | LookupFlags.Anchored)) 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)) if (!_prototypeManager.TryIndex<DamageTypePrototype>(kind.ToString(), out var damagePrototype))
{ {
const SuicideKind fallback = SuicideKind.Blunt; const SuicideKind fallback = SuicideKind.Blunt;
Logger.Error( Logger.Error($"{nameof(SuicideSystem)} could not find the damage type prototype associated with {kind}. Falling back to {fallback}");
$"{nameof(SuicideSystem)} could not find the damage type prototype associated with {kind}. Falling back to {fallback}");
damagePrototype = _prototypeManager.Index<DamageTypePrototype>(fallback.ToString()); damagePrototype = _prototypeManager.Index<DamageTypePrototype>(fallback.ToString());
} }
const int lethalAmountOfDamage = 200; // TODO: Would be nice to get this number from somewhere else const int lethalAmountOfDamage = 200; // TODO: Would be nice to get this number from somewhere else

View File

@@ -11,6 +11,14 @@ public sealed class TriggerOnMobstateChangeComponent : Component
/// <summary> /// <summary>
/// What state should trigger this? /// What state should trigger this?
/// </summary> /// </summary>
[ViewVariables]
[DataField("mobState", required: true)] [DataField("mobState", required: true)]
public DamageState MobState = DamageState.Alive; 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;
} }

View File

@@ -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);
}
}
}

View File

@@ -1,9 +1,8 @@
using Content.Server.Explosion.Components; using Content.Server.Explosion.Components;
using Content.Server.Sticky.Events; using Content.Server.Sticky.Events;
using Content.Shared.Examine; using Content.Shared.Examine;
using Content.Shared.Popups;
using Content.Shared.Interaction.Events; using Content.Shared.Interaction.Events;
using Content.Shared.MobState; using Content.Shared.Popups;
using Content.Shared.Verbs; using Content.Shared.Verbs;
using Robust.Shared.Player; using Robust.Shared.Player;
@@ -142,7 +141,8 @@ public sealed partial class TriggerSystem
private void OnTimerUse(EntityUid uid, OnUseTimerTriggerComponent component, UseInHandEvent args) private void OnTimerUse(EntityUid uid, OnUseTimerTriggerComponent component, UseInHandEvent args)
{ {
if (args.Handled) return; if (args.Handled)
return;
HandleTimerTrigger( HandleTimerTrigger(
uid, uid,

View File

@@ -5,26 +5,18 @@ using Content.Server.Chemistry.Components.SolutionManager;
using Content.Server.Explosion.Components; using Content.Server.Explosion.Components;
using Content.Server.Flash; using Content.Server.Flash;
using Content.Server.Flash.Components; 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.Database;
using Content.Shared.Explosion;
using Content.Shared.Implants.Components; using Content.Shared.Implants.Components;
using Content.Shared.Interaction; using Content.Shared.Interaction;
using Content.Shared.MobState;
using Content.Shared.Payload.Components; using Content.Shared.Payload.Components;
using Content.Shared.StepTrigger.Systems; 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.Containers;
using Robust.Shared.Physics.Events; using Robust.Shared.Physics.Events;
using Robust.Shared.Physics.Systems; using Robust.Shared.Physics.Systems;
using Robust.Shared.Player;
namespace Content.Server.Explosion.EntitySystems namespace Content.Server.Explosion.EntitySystems
{ {
@@ -63,12 +55,12 @@ namespace Content.Server.Explosion.EntitySystems
InitializeSignal(); InitializeSignal();
InitializeTimedCollide(); InitializeTimedCollide();
InitializeVoice(); InitializeVoice();
InitializeMobstate();
SubscribeLocalEvent<TriggerOnCollideComponent, StartCollideEvent>(OnTriggerCollide); SubscribeLocalEvent<TriggerOnCollideComponent, StartCollideEvent>(OnTriggerCollide);
SubscribeLocalEvent<TriggerOnActivateComponent, ActivateInWorldEvent>(OnActivate); SubscribeLocalEvent<TriggerOnActivateComponent, ActivateInWorldEvent>(OnActivate);
SubscribeLocalEvent<TriggerImplantActionComponent, ActivateImplantEvent>(OnImplantTrigger); SubscribeLocalEvent<TriggerImplantActionComponent, ActivateImplantEvent>(OnImplantTrigger);
SubscribeLocalEvent<TriggerOnStepTriggerComponent, StepTriggeredEvent>(OnStepTriggered); SubscribeLocalEvent<TriggerOnStepTriggerComponent, StepTriggeredEvent>(OnStepTriggered);
SubscribeLocalEvent<TriggerOnMobstateChangeComponent, MobStateChangedEvent>(OnMobStateChanged);
SubscribeLocalEvent<DeleteOnTriggerComponent, TriggerEvent>(HandleDeleteTrigger); SubscribeLocalEvent<DeleteOnTriggerComponent, TriggerEvent>(HandleDeleteTrigger);
SubscribeLocalEvent<ExplodeOnTriggerComponent, TriggerEvent>(HandleExplodeTrigger); SubscribeLocalEvent<ExplodeOnTriggerComponent, TriggerEvent>(HandleExplodeTrigger);
@@ -130,29 +122,6 @@ namespace Content.Server.Explosion.EntitySystems
Trigger(uid, args.Tripper); 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) public bool Trigger(EntityUid trigger, EntityUid? user = null)
{ {
var triggerEvent = new TriggerEvent(trigger, user); var triggerEvent = new TriggerEvent(trigger, user);

View File

@@ -1,6 +1,7 @@
using Content.Server.Cuffs.Components; using Content.Server.Cuffs.Components;
using Content.Shared.Implants; using Content.Shared.Implants;
using Content.Shared.Implants.Components; using Content.Shared.Implants.Components;
using Content.Shared.Interaction.Events;
using Content.Shared.MobState; using Content.Shared.MobState;
using Robust.Shared.Containers; using Robust.Shared.Containers;
@@ -17,6 +18,7 @@ public sealed class SubdermalImplantSystem : SharedSubdermalImplantSystem
SubscribeLocalEvent<SubdermalImplantComponent, UseFreedomImplantEvent>(OnFreedomImplant); SubscribeLocalEvent<SubdermalImplantComponent, UseFreedomImplantEvent>(OnFreedomImplant);
SubscribeLocalEvent<ImplantedComponent, MobStateChangedEvent>(RelayToImplantEvent); SubscribeLocalEvent<ImplantedComponent, MobStateChangedEvent>(RelayToImplantEvent);
SubscribeLocalEvent<ImplantedComponent, SuicideEvent>(RelayToImplantEvent);
} }
private void OnFreedomImplant(EntityUid uid, SubdermalImplantComponent component, UseFreedomImplantEvent args) private void OnFreedomImplant(EntityUid uid, SubdermalImplantComponent component, UseFreedomImplantEvent args)

View File

@@ -11,12 +11,21 @@ namespace Content.Shared.Interaction.Events
} }
public void SetHandled(SuicideKind kind) 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; Kind = kind;
} }
public void BlockSuicideAttempt(bool suicideAttempt)
{
if (suicideAttempt)
AttemptBlocked = suicideAttempt;
}
public SuicideKind? Kind { get; private set; } public SuicideKind? Kind { get; private set; }
public EntityUid Victim { get; private set; } public EntityUid Victim { get; private set; }
public bool AttemptBlocked { get; private set; }
public bool Handled => Kind != null; public bool Handled => Kind != null;
} }

View File

@@ -0,0 +1 @@
suicide-prevented = You tried to suicide, but only your spirit escapes.

View File

@@ -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. 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 productEntity: MacroBombImplanter
cost: cost:
Telecrystal: 20 Telecrystal: 25
categories: categories:
- UplinkUtility - UplinkUtility
conditions: conditions:
- !type:StoreWhitelistCondition - !type:StoreWhitelistCondition
blacklist: whitelist:
tags: tags:
- TraitorUplink - NukeOpsUplink
- !type:BuyerWhitelistCondition
blacklist:
components:
- SurplusBundle
# Bundles # Bundles

View File

@@ -154,8 +154,9 @@
permanent: true permanent: true
- type: TriggerOnMobstateChange #Chains with OnUseTimerTrigger - type: TriggerOnMobstateChange #Chains with OnUseTimerTrigger
mobState: Dead mobState: Dead
preventSuicide: true
- type: OnUseTimerTrigger - type: OnUseTimerTrigger
delay: 5 delay: 7
initialBeepDelay: 0 initialBeepDelay: 0
beepSound: /Audio/Machines/Nuke/general_beep.ogg beepSound: /Audio/Machines/Nuke/general_beep.ogg
- type: ExplodeOnTrigger - type: ExplodeOnTrigger
@@ -163,9 +164,9 @@
deleteItems: true deleteItems: true
- type: Explosive - type: Explosive
explosionType: Default explosionType: Default
totalIntensity: 4000 totalIntensity: 3500
intensitySlope: 5 intensitySlope: 15
maxIntensity: 50 maxIntensity: 70
canCreateVacuum: true canCreateVacuum: true
- type: Tag - type: Tag
tags: tags:

View File

@@ -82,9 +82,6 @@
preset: StorePresetUplink preset: StorePresetUplink
balance: balance:
Telecrystal: 20 Telecrystal: 20
- type: Tag
tags:
- TraitorUplink
- type: entity - type: entity
parent: BaseUplinkRadio parent: BaseUplinkRadio
@@ -95,9 +92,6 @@
preset: StorePresetUplink preset: StorePresetUplink
balance: balance:
Telecrystal: 25 Telecrystal: 25
- type: Tag
tags:
- TraitorUplink
#this uplink MUST be used for nukeops, as it has the tag for filtering the listing. #this uplink MUST be used for nukeops, as it has the tag for filtering the listing.
- type: entity - type: entity

View File

@@ -380,9 +380,6 @@
- type: Tag - type: Tag
id: NoSpinOnThrow id: NoSpinOnThrow
- type: Tag
id: TraitorUplink
- type: Tag - type: Tag
id: NoBlockAnchoring id: NoBlockAnchoring