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.
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

View File

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

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.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,

View File

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

View File

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

View File

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

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

View File

@@ -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:

View File

@@ -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

View File

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