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:
@@ -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"));
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user