Melee Executions (#30104)

* melee executions

* fix damage bug

* cleanup

* address reviews hopefully

* resistance bypass mechanic

* component changes

* self executions (not finished yet)

* self execs part two

* ok i fixed things (still not finished)

* finish everything

* review stuff

* nuke if (kind = special)

* more review stuffs

* Make suicide system much less hardcoded and make much more use of events

* Fix a dumb bug I introduced

* self execution popups

* Integration tests

* Why did they even take 0.5 blunt damage?

* More consistent integration tests

* Destructive equals true

* Allow it to dirty-dispose

* IS THIS WHAT YOU WANT?

* FRESH AND CLEAN

* modifier to multiplier

* don't jinx the integration tests

* no file-scoped namespace

* Move the rest of execution to shared, create SuicideGhostEvent

* handled

* Get rid of unused code and add a comment

* ghost before suicide

* stop cat suicides

* popup fix + small suicide change

* make it a bit better

---------

Co-authored-by: Plykiya <58439124+Plykiya@users.noreply.github.com>
This commit is contained in:
Scribbles0
2024-08-10 20:05:54 -07:00
committed by GitHub
parent c25c5ec666
commit 220aff21eb
26 changed files with 1048 additions and 219 deletions

View File

@@ -1,6 +1,7 @@
using Content.Server.GameTicking;
using Content.Server.Popups;
using Content.Shared.Administration;
using Content.Shared.Chat;
using Content.Shared.Mind;
using Robust.Shared.Console;
using Robust.Shared.Enums;
@@ -32,15 +33,13 @@ namespace Content.Server.Chat.Commands
var minds = _e.System<SharedMindSystem>();
// This check also proves mind not-null for at the end when the mob is ghosted.
if (!minds.TryGetMind(player, out var mindId, out var mind) ||
mind.OwnedEntity is not { Valid: true } victim)
if (!minds.TryGetMind(player, out var mindId, out var mindComp) ||
mindComp.OwnedEntity is not { Valid: true } victim)
{
shell.WriteLine(Loc.GetString("suicide-command-no-mind"));
return;
}
var gameTicker = _e.System<GameTicker>();
var suicideSystem = _e.System<SuicideSystem>();
if (_e.HasComponent<AdminFrozenComponent>(victim))
@@ -53,14 +52,6 @@ namespace Content.Server.Chat.Commands
}
if (suicideSystem.Suicide(victim))
{
// Prevent the player from returning to the body.
// Note that mind cannot be null because otherwise victim would be null.
gameTicker.OnGhostAttempt(mindId, false, mind: mind);
return;
}
if (gameTicker.OnGhostAttempt(mindId, true, mind: mind))
return;
shell.WriteLine(Loc.GetString("ghost-command-denied"));

View File

@@ -1,141 +1,154 @@
using Content.Server.Administration.Logs;
using Content.Server.Popups;
using Content.Server.GameTicking;
using Content.Shared.Damage;
using Content.Shared.Damage.Prototypes;
using Content.Shared.Database;
using Content.Shared.Hands.Components;
using Content.Shared.Interaction.Events;
using Content.Shared.Item;
using Content.Shared.Mind;
using Content.Shared.Mobs.Components;
using Content.Shared.Mobs.Systems;
using Content.Shared.Popups;
using Content.Shared.Tag;
using Robust.Shared.Player;
using Robust.Shared.Prototypes;
using Content.Shared.Administration.Logs;
using Content.Shared.Chat;
using Content.Shared.Mind.Components;
namespace Content.Server.Chat
namespace Content.Server.Chat;
public sealed class SuicideSystem : EntitySystem
{
public sealed class SuicideSystem : EntitySystem
[Dependency] private readonly EntityLookupSystem _entityLookupSystem = default!;
[Dependency] private readonly ISharedAdminLogManager _adminLogger = default!;
[Dependency] private readonly TagSystem _tagSystem = default!;
[Dependency] private readonly MobStateSystem _mobState = default!;
[Dependency] private readonly SharedPopupSystem _popup = default!;
[Dependency] private readonly GameTicker _gameTicker = default!;
[Dependency] private readonly SharedSuicideSystem _suicide = default!;
public override void Initialize()
{
[Dependency] private readonly DamageableSystem _damageableSystem = default!;
[Dependency] private readonly EntityLookupSystem _entityLookupSystem = default!;
[Dependency] private readonly IAdminLogManager _adminLogger = default!;
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
[Dependency] private readonly TagSystem _tagSystem = default!;
[Dependency] private readonly MobStateSystem _mobState = default!;
[Dependency] private readonly SharedPopupSystem _popup = default!;
base.Initialize();
public bool Suicide(EntityUid victim)
{
// 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.Mind, $"{EntityManager.ToPrettyString(victim):player} is attempting to suicide");
var suicideEvent = new SuicideEvent(victim);
//Check to see if there were any systems blocking this suicide
if (SuicideAttemptBlocked(victim, suicideEvent))
return false;
bool environmentSuicide = 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))
{
environmentSuicide = EnvironmentSuicideHandler(victim, suicideEvent);
}
if (suicideEvent.AttemptBlocked)
return false;
DefaultSuicideHandler(victim, suicideEvent);
ApplyDeath(victim, suicideEvent.Kind!.Value);
_adminLogger.Add(LogType.Mind, $"{EntityManager.ToPrettyString(victim):player} suicided{(environmentSuicide ? " (environment)" : "")}");
return true;
}
/// <summary>
/// If not handled, does the default suicide, which is biting your own tongue
/// </summary>
private void DefaultSuicideHandler(EntityUid victim, SuicideEvent suicideEvent)
{
if (suicideEvent.Handled)
return;
var othersMessage = Loc.GetString("suicide-command-default-text-others", ("name", victim));
_popup.PopupEntity(othersMessage, victim, Filter.PvsExcept(victim), true);
var selfMessage = Loc.GetString("suicide-command-default-text-self");
_popup.PopupEntity(selfMessage, victim, victim);
suicideEvent.SetHandled(SuicideKind.Bloodloss);
}
/// <summary>
/// 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, true);
if (suicideEvent.AttemptBlocked)
return true;
SubscribeLocalEvent<DamageableComponent, SuicideEvent>(OnDamageableSuicide);
SubscribeLocalEvent<MobStateComponent, SuicideEvent>(OnEnvironmentalSuicide);
SubscribeLocalEvent<MindContainerComponent, SuicideGhostEvent>(OnSuicideGhost);
}
/// <summary>
/// Calling this function will attempt to kill the user by suiciding on objects in the surrounding area
/// or by applying a lethal amount of damage to the user with the default method.
/// Used when writing /suicide
/// </summary>
public bool Suicide(EntityUid victim)
{
// Can't suicide if we're already dead
if (!TryComp<MobStateComponent>(victim, out var mobState) || _mobState.IsDead(victim, mobState))
return false;
}
/// <summary>
/// Raise event to attempt to use held item, or surrounding entities to attempt to commit suicide
/// </summary>
private bool EnvironmentSuicideHandler(EntityUid victim, SuicideEvent suicideEvent)
{
var itemQuery = GetEntityQuery<ItemComponent>();
// Suicide by held item
if (EntityManager.TryGetComponent(victim, out HandsComponent? handsComponent)
&& handsComponent.ActiveHandEntity is { } item)
{
RaiseLocalEvent(item, suicideEvent, false);
if (suicideEvent.Handled)
return true;
}
// Suicide by nearby entity (ex: Microwave)
foreach (var entity in _entityLookupSystem.GetEntitiesInRange(victim, 1, LookupFlags.Approximate | LookupFlags.Static))
{
// Skip any nearby items that can be picked up, we already checked the active held item above
if (itemQuery.HasComponent(entity))
continue;
RaiseLocalEvent(entity, suicideEvent);
if (suicideEvent.Handled)
return true;
}
var suicideGhostEvent = new SuicideGhostEvent(victim);
RaiseLocalEvent(victim, suicideGhostEvent);
// Suicide is considered a fail if the user wasn't able to ghost
// Suiciding with the CannotSuicide tag will ghost the player but not kill the body
if (!suicideGhostEvent.Handled || _tagSystem.HasTag(victim, "CannotSuicide"))
return false;
_adminLogger.Add(LogType.Mind, $"{EntityManager.ToPrettyString(victim):player} is attempting to suicide");
var suicideEvent = new SuicideEvent(victim);
RaiseLocalEvent(victim, suicideEvent);
_adminLogger.Add(LogType.Mind, $"{EntityManager.ToPrettyString(victim):player} suicided.");
return true;
}
/// <summary>
/// Event subscription created to handle the ghosting aspect relating to suicides
/// Mainly useful when you can raise an event in Shared and can't call Suicide() directly
/// </summary>
private void OnSuicideGhost(Entity<MindContainerComponent> victim, ref SuicideGhostEvent args)
{
if (args.Handled)
return;
if (victim.Comp.Mind == null)
return;
if (!TryComp<MindComponent>(victim.Comp.Mind, out var mindComponent))
return;
// CannotSuicide tag will allow the user to ghost, but also return to their mind
// This is kind of weird, not sure what it applies to?
if (_tagSystem.HasTag(victim, "CannotSuicide"))
args.CanReturnToBody = true;
if (_gameTicker.OnGhostAttempt(victim.Comp.Mind.Value, args.CanReturnToBody, mind: mindComponent))
args.Handled = true;
}
/// <summary>
/// Raise event to attempt to use held item, or surrounding entities to attempt to commit suicide
/// </summary>
private void OnEnvironmentalSuicide(Entity<MobStateComponent> victim, ref SuicideEvent args)
{
if (args.Handled || _mobState.IsCritical(victim))
return;
var suicideByEnvironmentEvent = new SuicideByEnvironmentEvent(victim);
// Try to suicide by raising an event on the held item
if (EntityManager.TryGetComponent(victim, out HandsComponent? handsComponent)
&& handsComponent.ActiveHandEntity is { } item)
{
RaiseLocalEvent(item, suicideByEnvironmentEvent);
if (suicideByEnvironmentEvent.Handled)
{
args.Handled = suicideByEnvironmentEvent.Handled;
return;
}
}
private void ApplyDeath(EntityUid target, SuicideKind kind)
// Try to suicide by nearby entities, like Microwaves or Crematoriums, by raising an event on it
// Returns upon being handled by any entity
var itemQuery = GetEntityQuery<ItemComponent>();
foreach (var entity in _entityLookupSystem.GetEntitiesInRange(victim, 1, LookupFlags.Approximate | LookupFlags.Static))
{
if (kind == SuicideKind.Special)
return;
// Skip any nearby items that can be picked up, we already checked the active held item above
if (itemQuery.HasComponent(entity))
continue;
if (!_prototypeManager.TryIndex<DamageTypePrototype>(kind.ToString(), out var damagePrototype))
{
const SuicideKind fallback = SuicideKind.Blunt;
Log.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
_damageableSystem.TryChangeDamage(target, new(damagePrototype, lethalAmountOfDamage), true, origin: target);
RaiseLocalEvent(entity, suicideByEnvironmentEvent);
if (!suicideByEnvironmentEvent.Handled)
continue;
args.Handled = suicideByEnvironmentEvent.Handled;
return;
}
}
/// <summary>
/// Default suicide behavior for any kind of entity that can take damage
/// </summary>
private void OnDamageableSuicide(Entity<DamageableComponent> victim, ref SuicideEvent args)
{
if (args.Handled)
return;
var othersMessage = Loc.GetString("suicide-command-default-text-others", ("name", victim));
_popup.PopupEntity(othersMessage, victim, Filter.PvsExcept(victim), true);
var selfMessage = Loc.GetString("suicide-command-default-text-self");
_popup.PopupEntity(selfMessage, victim, victim);
if (args.DamageSpecifier != null)
{
_suicide.ApplyLethalDamage(victim, args.DamageSpecifier);
args.Handled = true;
return;
}
args.DamageType ??= "Bloodloss";
_suicide.ApplyLethalDamage(victim, args.DamageType);
args.Handled = true;
}
}

View File

@@ -38,16 +38,20 @@ public sealed partial class TriggerSystem
Trigger(uid);
}
/// <summary>
/// Checks if the user has any implants that prevent suicide to avoid some cheesy strategies
/// Prevents suicide by handling the event without killing the user
/// </summary>
private void OnSuicide(EntityUid uid, TriggerOnMobstateChangeComponent component, SuicideEvent args)
{
if (args.Handled)
return;
if (component.PreventSuicide)
{
_popupSystem.PopupEntity(Loc.GetString("suicide-prevented"), args.Victim, args.Victim);
args.BlockSuicideAttempt(component.PreventSuicide);
}
if (!component.PreventSuicide)
return;
_popupSystem.PopupEntity(Loc.GetString("suicide-prevented"), args.Victim, args.Victim);
args.Handled = true;
}
private void OnSuicideRelay(EntityUid uid, TriggerOnMobstateChangeComponent component, ImplantRelayEvent<SuicideEvent> args)

View File

@@ -2,6 +2,8 @@ using Content.Server.Administration.Logs;
using Content.Server.Body.Systems;
using Content.Server.Kitchen.Components;
using Content.Server.Popups;
using Content.Shared.Chat;
using Content.Shared.Damage;
using Content.Shared.Database;
using Content.Shared.DoAfter;
using Content.Shared.DragDrop;
@@ -16,7 +18,6 @@ using Content.Shared.Nutrition.Components;
using Content.Shared.Popups;
using Content.Shared.Storage;
using Robust.Server.GameObjects;
using Robust.Shared.Audio;
using Robust.Shared.Audio.Systems;
using Robust.Shared.Player;
using Robust.Shared.Random;
@@ -36,6 +37,7 @@ namespace Content.Server.Kitchen.EntitySystems
[Dependency] private readonly SharedAppearanceSystem _appearance = default!;
[Dependency] private readonly SharedAudioSystem _audio = default!;
[Dependency] private readonly MetaDataSystem _metaData = default!;
[Dependency] private readonly SharedSuicideSystem _suicide = default!;
public override void Initialize()
{
@@ -48,31 +50,38 @@ namespace Content.Server.Kitchen.EntitySystems
//DoAfter
SubscribeLocalEvent<KitchenSpikeComponent, SpikeDoAfterEvent>(OnDoAfter);
SubscribeLocalEvent<KitchenSpikeComponent, SuicideEvent>(OnSuicide);
SubscribeLocalEvent<KitchenSpikeComponent, SuicideByEnvironmentEvent>(OnSuicideByEnvironment);
SubscribeLocalEvent<ButcherableComponent, CanDropDraggedEvent>(OnButcherableCanDrop);
}
private void OnButcherableCanDrop(EntityUid uid, ButcherableComponent component, ref CanDropDraggedEvent args)
private void OnButcherableCanDrop(Entity<ButcherableComponent> entity, ref CanDropDraggedEvent args)
{
args.Handled = true;
args.CanDrop |= component.Type != ButcheringType.Knife;
args.CanDrop |= entity.Comp.Type != ButcheringType.Knife;
}
private void OnSuicide(EntityUid uid, KitchenSpikeComponent component, SuicideEvent args)
/// <summary>
/// TODO: Update this so it actually meatspikes the user instead of applying lethal damage to them.
/// </summary>
private void OnSuicideByEnvironment(Entity<KitchenSpikeComponent> entity, ref SuicideByEnvironmentEvent args)
{
if (args.Handled)
return;
args.SetHandled(SuicideKind.Piercing);
var victim = args.Victim;
var othersMessage = Loc.GetString("comp-kitchen-spike-suicide-other", ("victim", victim));
_popupSystem.PopupEntity(othersMessage, victim);
if (!TryComp<DamageableComponent>(args.Victim, out var damageableComponent))
return;
_suicide.ApplyLethalDamage((args.Victim, damageableComponent), "Piercing");
var othersMessage = Loc.GetString("comp-kitchen-spike-suicide-other", ("victim", args.Victim));
_popupSystem.PopupEntity(othersMessage, args.Victim, Filter.PvsExcept(args.Victim), true);
var selfMessage = Loc.GetString("comp-kitchen-spike-suicide-self");
_popupSystem.PopupEntity(selfMessage, victim, victim);
_popupSystem.PopupEntity(selfMessage, args.Victim, args.Victim);
args.Handled = true;
}
private void OnDoAfter(EntityUid uid, KitchenSpikeComponent component, DoAfterEvent args)
private void OnDoAfter(Entity<KitchenSpikeComponent> entity, ref SpikeDoAfterEvent args)
{
if (args.Args.Target == null)
return;
@@ -82,49 +91,49 @@ namespace Content.Server.Kitchen.EntitySystems
if (args.Cancelled)
{
component.InUse = false;
entity.Comp.InUse = false;
return;
}
if (args.Handled)
return;
if (Spikeable(uid, args.Args.User, args.Args.Target.Value, component, butcherable))
Spike(uid, args.Args.User, args.Args.Target.Value, component);
if (Spikeable(entity, args.Args.User, args.Args.Target.Value, entity.Comp, butcherable))
Spike(entity, args.Args.User, args.Args.Target.Value, entity.Comp);
component.InUse = false;
entity.Comp.InUse = false;
args.Handled = true;
}
private void OnDragDrop(EntityUid uid, KitchenSpikeComponent component, ref DragDropTargetEvent args)
private void OnDragDrop(Entity<KitchenSpikeComponent> entity, ref DragDropTargetEvent args)
{
if (args.Handled)
return;
args.Handled = true;
if (Spikeable(uid, args.User, args.Dragged, component))
TrySpike(uid, args.User, args.Dragged, component);
if (Spikeable(entity, args.User, args.Dragged, entity.Comp))
TrySpike(entity, args.User, args.Dragged, entity.Comp);
}
private void OnInteractHand(EntityUid uid, KitchenSpikeComponent component, InteractHandEvent args)
private void OnInteractHand(Entity<KitchenSpikeComponent> entity, ref InteractHandEvent args)
{
if (args.Handled)
return;
if (component.PrototypesToSpawn?.Count > 0)
if (entity.Comp.PrototypesToSpawn?.Count > 0)
{
_popupSystem.PopupEntity(Loc.GetString("comp-kitchen-spike-knife-needed"), uid, args.User);
_popupSystem.PopupEntity(Loc.GetString("comp-kitchen-spike-knife-needed"), entity, args.User);
args.Handled = true;
}
}
private void OnInteractUsing(EntityUid uid, KitchenSpikeComponent component, InteractUsingEvent args)
private void OnInteractUsing(Entity<KitchenSpikeComponent> entity, ref InteractUsingEvent args)
{
if (args.Handled)
return;
if (TryGetPiece(uid, args.User, args.Used))
if (TryGetPiece(entity, args.User, args.Used))
args.Handled = true;
}

View File

@@ -39,6 +39,8 @@ using Robust.Shared.Prototypes;
using Robust.Shared.Timing;
using Content.Shared.Stacks;
using Content.Server.Construction.Components;
using Content.Shared.Chat;
using Content.Shared.Damage;
namespace Content.Server.Kitchen.EntitySystems
{
@@ -65,6 +67,7 @@ namespace Content.Server.Kitchen.EntitySystems
[Dependency] private readonly SharedStackSystem _stack = default!;
[Dependency] private readonly IPrototypeManager _prototype = default!;
[Dependency] private readonly IAdminLogManager _adminLogger = default!;
[Dependency] private readonly SharedSuicideSystem _suicide = default!;
[ValidatePrototypeId<EntityPrototype>]
private const string MalfunctionSpark = "Spark";
@@ -83,7 +86,7 @@ namespace Content.Server.Kitchen.EntitySystems
SubscribeLocalEvent<MicrowaveComponent, BreakageEventArgs>(OnBreak);
SubscribeLocalEvent<MicrowaveComponent, PowerChangedEvent>(OnPowerChanged);
SubscribeLocalEvent<MicrowaveComponent, AnchorStateChangedEvent>(OnAnchorChanged);
SubscribeLocalEvent<MicrowaveComponent, SuicideEvent>(OnSuicide);
SubscribeLocalEvent<MicrowaveComponent, SuicideByEnvironmentEvent>(OnSuicideByEnvironment);
SubscribeLocalEvent<MicrowaveComponent, SignalReceivedEvent>(OnSignalReceived);
@@ -260,12 +263,22 @@ namespace Content.Server.Kitchen.EntitySystems
_deviceLink.EnsureSinkPorts(ent, ent.Comp.OnPort);
}
private void OnSuicide(Entity<MicrowaveComponent> ent, ref SuicideEvent args)
/// <summary>
/// Kills the user by microwaving their head
/// TODO: Make this not awful, it keeps any items attached to your head still on and you can revive someone and cogni them so you have some dumb headless fuck running around. I've seen it happen.
/// </summary>
private void OnSuicideByEnvironment(Entity<MicrowaveComponent> ent, ref SuicideByEnvironmentEvent args)
{
if (args.Handled)
return;
args.SetHandled(SuicideKind.Heat);
// The act of getting your head microwaved doesn't actually kill you
if (!TryComp<DamageableComponent>(args.Victim, out var damageableComponent))
return;
// The application of lethal damage is what kills you...
_suicide.ApplyLethalDamage((args.Victim, damageableComponent), "Heat");
var victim = args.Victim;
var headCount = 0;
@@ -295,6 +308,7 @@ namespace Content.Server.Kitchen.EntitySystems
ent.Comp.CurrentCookTimerTime = 10;
Wzhzhzh(ent.Owner, ent.Comp, args.Victim);
UpdateUserInterfaceState(ent.Owner, ent.Comp);
args.Handled = true;
}
private void OnSolutionChange(Entity<MicrowaveComponent> ent, ref SolutionContainerChangedEvent args)

View File

@@ -1,4 +1,4 @@
using Content.Server.Chemistry.Containers.EntitySystems;
using Content.Server.Chemistry.Containers.EntitySystems;
using Content.Server.Fluids.EntitySystems;
using Content.Server.GameTicking;
using Content.Server.Popups;
@@ -48,7 +48,7 @@ public sealed class MaterialReclaimerSystem : SharedMaterialReclaimerSystem
SubscribeLocalEvent<MaterialReclaimerComponent, PowerChangedEvent>(OnPowerChanged);
SubscribeLocalEvent<MaterialReclaimerComponent, InteractUsingEvent>(OnInteractUsing,
before: new []{typeof(WiresSystem), typeof(SolutionTransferSystem)});
SubscribeLocalEvent<MaterialReclaimerComponent, SuicideEvent>(OnSuicide);
SubscribeLocalEvent<MaterialReclaimerComponent, SuicideByEnvironmentEvent>(OnSuicideByEnvironment);
SubscribeLocalEvent<ActiveMaterialReclaimerComponent, PowerChangedEvent>(OnActivePowerChanged);
}
private void OnStartup(Entity<MaterialReclaimerComponent> entity, ref ComponentStartup args)
@@ -86,12 +86,11 @@ public sealed class MaterialReclaimerSystem : SharedMaterialReclaimerSystem
args.Handled = TryStartProcessItem(entity.Owner, args.Used, entity.Comp, args.User);
}
private void OnSuicide(Entity<MaterialReclaimerComponent> entity, ref SuicideEvent args)
private void OnSuicideByEnvironment(Entity<MaterialReclaimerComponent> entity, ref SuicideByEnvironmentEvent args)
{
if (args.Handled)
return;
args.SetHandled(SuicideKind.Bloodloss);
var victim = args.Victim;
if (TryComp(victim, out ActorComponent? actor) &&
_mind.TryGetMind(actor.PlayerSession, out var mindId, out var mind))
@@ -103,12 +102,15 @@ public sealed class MaterialReclaimerSystem : SharedMaterialReclaimerSystem
}
}
_popup.PopupEntity(Loc.GetString("recycler-component-suicide-message-others", ("victim", Identity.Entity(victim, EntityManager))),
_popup.PopupEntity(Loc.GetString("recycler-component-suicide-message-others",
("victim", Identity.Entity(victim, EntityManager))),
victim,
Filter.PvsExcept(victim, entityManager: EntityManager), true);
Filter.PvsExcept(victim, entityManager: EntityManager),
true);
_body.GibBody(victim, true);
_appearance.SetData(entity.Owner, RecyclerVisuals.Bloody, true);
args.Handled = true;
}
private void OnActivePowerChanged(Entity<ActiveMaterialReclaimerComponent> entity, ref PowerChangedEvent args)

View File

@@ -106,11 +106,11 @@ namespace Content.Server.Medical.BiomassReclaimer
SubscribeLocalEvent<BiomassReclaimerComponent, AfterInteractUsingEvent>(OnAfterInteractUsing);
SubscribeLocalEvent<BiomassReclaimerComponent, ClimbedOnEvent>(OnClimbedOn);
SubscribeLocalEvent<BiomassReclaimerComponent, PowerChangedEvent>(OnPowerChanged);
SubscribeLocalEvent<BiomassReclaimerComponent, SuicideEvent>(OnSuicide);
SubscribeLocalEvent<BiomassReclaimerComponent, SuicideByEnvironmentEvent>(OnSuicideByEnvironment);
SubscribeLocalEvent<BiomassReclaimerComponent, ReclaimerDoAfterEvent>(OnDoAfter);
}
private void OnSuicide(Entity<BiomassReclaimerComponent> ent, ref SuicideEvent args)
private void OnSuicideByEnvironment(Entity<BiomassReclaimerComponent> ent, ref SuicideByEnvironmentEvent args)
{
if (args.Handled)
return;
@@ -123,7 +123,7 @@ namespace Content.Server.Medical.BiomassReclaimer
_popup.PopupEntity(Loc.GetString("biomass-reclaimer-suicide-others", ("victim", args.Victim)), ent, PopupType.LargeCaution);
StartProcessing(args.Victim, ent);
args.SetHandled(SuicideKind.Blunt);
args.Handled = true;
}
private void OnInit(EntityUid uid, ActiveBiomassReclaimerComponent component, ComponentInit args)

View File

@@ -38,7 +38,7 @@ public sealed class CrematoriumSystem : EntitySystem
SubscribeLocalEvent<CrematoriumComponent, ExaminedEvent>(OnExamine);
SubscribeLocalEvent<CrematoriumComponent, GetVerbsEvent<AlternativeVerb>>(AddCremateVerb);
SubscribeLocalEvent<CrematoriumComponent, SuicideEvent>(OnSuicide);
SubscribeLocalEvent<CrematoriumComponent, SuicideByEnvironmentEvent>(OnSuicideByEnvironment);
SubscribeLocalEvent<ActiveCrematoriumComponent, StorageOpenAttemptEvent>(OnAttemptOpen);
}
@@ -146,11 +146,10 @@ public sealed class CrematoriumSystem : EntitySystem
_audio.PlayPvs(component.CremateFinishSound, uid);
}
private void OnSuicide(EntityUid uid, CrematoriumComponent component, SuicideEvent args)
private void OnSuicideByEnvironment(EntityUid uid, CrematoriumComponent component, SuicideByEnvironmentEvent args)
{
if (args.Handled)
return;
args.SetHandled(SuicideKind.Heat);
var victim = args.Victim;
if (TryComp(victim, out ActorComponent? actor) && _minds.TryGetMind(victim, out var mindId, out var mind))
@@ -179,6 +178,7 @@ public sealed class CrematoriumSystem : EntitySystem
}
_entityStorage.CloseStorage(uid);
Cremate(uid, component);
args.Handled = true;
}
public override void Update(float frameTime)