Files
space-station-14/Content.IntegrationTests/Tests/Commands/SuicideCommandTests.cs
T
Moony d42adbf05d Gametest Part 2: Preliminary refactor every test to use GameTest as the framework. (#43207)
* Pass 1.

* i'm FREE

* Prevent hangups.

* okay fine here's an attribute for settings, will polish later and prolly remove the overridable thing.

* sigh.

* fix singular trigger bug so LatheTest doesn't flake.

* Remove SystemAttribute usage.

* Poke

* I used the shotgun. You know why? Cause the shot gun doesn’t miss, and unlike the shitty hybrid taser it stops a criminal in their tracks in two hits. Bang, bang, and they’re fucking done. I use four shots just to make damn sure. Because, once again, I’m not there to coddle a buncha criminal scum sucking f------, I’m there to 1) Survive the fucking round. 2) Guard the armory. So you can absolutely get fucked. If I get unbanned, which I won’t, you can guarantee I will continue to use the shotgun to apprehend criminals. Because it’s quick, clean and effective as fuck. Why in the seven hells would I fuck around with the disabler shots, which take half a clip just to bring someone down, or with the tazer bolts which are slow as balls, impossible to aim and do about next to jack shit, fuck all. The shotgun is the superior law enforcement weapon. Because it stops crime. And it stops crime by reducing the number of criminals roaming the fucking halls.

* Change the faulty store test into two tests, one of which is ignored for failing.
2026-04-01 16:06:26 +00:00

347 lines
14 KiB
C#

using System.Linq;
using Content.IntegrationTests.Fixtures;
using Content.Shared.Damage;
using Content.Shared.Damage.Components;
using Content.Shared.Damage.Prototypes;
using Content.Shared.Damage.Systems;
using Content.Shared.Execution;
using Content.Shared.FixedPoint;
using Content.Shared.Ghost;
using Content.Shared.Hands.Components;
using Content.Shared.Hands.EntitySystems;
using Content.Shared.Mind;
using Content.Shared.Mobs.Components;
using Content.Shared.Mobs.Systems;
using Content.Shared.Tag;
using Robust.Server.GameObjects;
using Robust.Server.Player;
using Robust.Shared.Console;
using Robust.Shared.GameObjects;
using Robust.Shared.Prototypes;
namespace Content.IntegrationTests.Tests.Commands;
[TestFixture]
public sealed class SuicideCommandTests : GameTest
{
[TestPrototypes]
private const string Prototypes = @"
- type: entity
id: SharpTestObject
name: very sharp test object
components:
- type: Item
- type: MeleeWeapon
damage:
types:
Slash: 5
- type: Execution
- type: entity
id: MixedDamageTestObject
name: mixed damage test object
components:
- type: Item
- type: MeleeWeapon
damage:
types:
Slash: 5
Blunt: 5
- type: Execution
- type: entity
id: TestMaterialReclaimer
name: test version of the material reclaimer
components:
- type: MaterialReclaimer";
private static readonly ProtoId<TagPrototype> CannotSuicideTag = "CannotSuicide";
private static readonly ProtoId<DamageTypePrototype> DamageType = "Slash";
public override PoolSettings PoolSettings => new PoolSettings
{
Connected = true,
Dirty = true,
DummyTicker = false
};
/// <summary>
/// Run the suicide command in the console
/// Should successfully kill the player and ghost them
/// </summary>
[Test]
public async Task TestSuicide()
{
var pair = Pair;
var server = pair.Server;
var consoleHost = server.ResolveDependency<IConsoleHost>();
var entManager = server.ResolveDependency<IEntityManager>();
var playerMan = server.ResolveDependency<IPlayerManager>();
var mindSystem = entManager.System<SharedMindSystem>();
var mobStateSystem = entManager.System<MobStateSystem>();
// We need to know the player and whether they can be hurt, killed, and whether they have a mind
var player = playerMan.Sessions.First().AttachedEntity!.Value;
var mind = mindSystem.GetMind(player);
MindComponent mindComponent = default;
MobStateComponent mobStateComp = default;
await server.WaitPost(() =>
{
if (mind != null)
mindComponent = entManager.GetComponent<MindComponent>(mind.Value);
mobStateComp = entManager.GetComponent<MobStateComponent>(player);
});
// Check that running the suicide command kills the player
// and properly ghosts them without them being able to return to their body
await server.WaitAssertion(() =>
{
consoleHost.GetSessionShell(playerMan.Sessions.First()).ExecuteCommand("suicide");
Assert.Multiple(() =>
{
Assert.That(mobStateSystem.IsDead(player, mobStateComp));
Assert.That(entManager.TryGetComponent<GhostComponent>(mindComponent.CurrentEntity, out var ghostComp) &&
!ghostComp.CanReturnToBody);
});
});
}
/// <summary>
/// Run the suicide command while the player is already injured
/// This should only deal as much damage as necessary to get to the dead threshold
/// </summary>
[Test]
public async Task TestSuicideWhileDamaged()
{
var pair = Pair;
var server = pair.Server;
var consoleHost = server.ResolveDependency<IConsoleHost>();
var entManager = server.ResolveDependency<IEntityManager>();
var playerMan = server.ResolveDependency<IPlayerManager>();
var protoMan = server.ResolveDependency<IPrototypeManager>();
var damageableSystem = entManager.System<DamageableSystem>();
var mindSystem = entManager.System<SharedMindSystem>();
var mobStateSystem = entManager.System<MobStateSystem>();
// We need to know the player and whether they can be hurt, killed, and whether they have a mind
var player = playerMan.Sessions.First().AttachedEntity!.Value;
var mind = mindSystem.GetMind(player);
MindComponent mindComponent = default;
MobStateComponent mobStateComp = default;
MobThresholdsComponent mobThresholdsComp = default;
await server.WaitPost(() =>
{
if (mind != null)
mindComponent = entManager.GetComponent<MindComponent>(mind.Value);
mobStateComp = entManager.GetComponent<MobStateComponent>(player);
mobThresholdsComp = entManager.GetComponent<MobThresholdsComponent>(player);
var slashProto = protoMan.Index(DamageType);
damageableSystem.TryChangeDamage(player, new DamageSpecifier(slashProto, FixedPoint2.New(46.5)));
});
// Check that running the suicide command kills the player
// and properly ghosts them without them being able to return to their body
// and that all the damage is concentrated in the Slash category
await server.WaitAssertion(() =>
{
consoleHost.GetSessionShell(playerMan.Sessions.First()).ExecuteCommand("suicide");
var lethalDamageThreshold = mobThresholdsComp.Thresholds.Keys.Last();
Assert.Multiple(() =>
{
Assert.That(mobStateSystem.IsDead(player, mobStateComp));
Assert.That(entManager.TryGetComponent<GhostComponent>(mindComponent.CurrentEntity, out var ghostComp) &&
!ghostComp.CanReturnToBody);
Assert.That(damageableSystem.GetTotalDamage(player), Is.EqualTo(lethalDamageThreshold));
});
});
}
/// <summary>
/// Run the suicide command in the console
/// Should only ghost the player but not kill them
/// </summary>
[Test]
public async Task TestSuicideWhenCannotSuicide()
{
var pair = Pair;
var server = pair.Server;
var consoleHost = server.ResolveDependency<IConsoleHost>();
var entManager = server.ResolveDependency<IEntityManager>();
var playerMan = server.ResolveDependency<IPlayerManager>();
var mindSystem = entManager.System<SharedMindSystem>();
var mobStateSystem = entManager.System<MobStateSystem>();
var tagSystem = entManager.System<TagSystem>();
// We need to know the player and whether they can be hurt, killed, and whether they have a mind
var player = playerMan.Sessions.First().AttachedEntity!.Value;
var mind = mindSystem.GetMind(player);
MindComponent mindComponent = default;
MobStateComponent mobStateComp = default;
await server.WaitPost(() =>
{
if (mind != null)
mindComponent = entManager.GetComponent<MindComponent>(mind.Value);
mobStateComp = entManager.GetComponent<MobStateComponent>(player);
});
tagSystem.AddTag(player, CannotSuicideTag);
// Check that running the suicide command kills the player
// and properly ghosts them without them being able to return to their body
await server.WaitAssertion(() =>
{
consoleHost.GetSessionShell(playerMan.Sessions.First()).ExecuteCommand("suicide");
Assert.Multiple(() =>
{
Assert.That(mobStateSystem.IsAlive(player, mobStateComp));
Assert.That(entManager.TryGetComponent<GhostComponent>(mindComponent.CurrentEntity, out var ghostComp) &&
!ghostComp.CanReturnToBody);
});
});
}
/// <summary>
/// Run the suicide command while the player is holding an execution-capable weapon
/// </summary>
[Test]
public async Task TestSuicideByHeldItem()
{
var pair = Pair;
var server = pair.Server;
var consoleHost = server.ResolveDependency<IConsoleHost>();
var entManager = server.ResolveDependency<IEntityManager>();
var playerMan = server.ResolveDependency<IPlayerManager>();
var handsSystem = entManager.System<SharedHandsSystem>();
var mindSystem = entManager.System<SharedMindSystem>();
var mobStateSystem = entManager.System<MobStateSystem>();
var transformSystem = entManager.System<TransformSystem>();
var damageableSystem = entManager.System<DamageableSystem>();
// We need to know the player and whether they can be hurt, killed, and whether they have a mind
var player = playerMan.Sessions.First().AttachedEntity!.Value;
var mind = mindSystem.GetMind(player);
MindComponent mindComponent = default;
MobStateComponent mobStateComp = default;
MobThresholdsComponent mobThresholdsComp = default;
DamageableComponent damageableComp = default;
HandsComponent handsComponent = default;
await server.WaitPost(() =>
{
if (mind != null)
mindComponent = entManager.GetComponent<MindComponent>(mind.Value);
mobStateComp = entManager.GetComponent<MobStateComponent>(player);
mobThresholdsComp = entManager.GetComponent<MobThresholdsComponent>(player);
damageableComp = entManager.GetComponent<DamageableComponent>(player);
handsComponent = entManager.GetComponent<HandsComponent>(player);
});
// Spawn the weapon of choice and put it in the player's hands
await server.WaitPost(() =>
{
var item = entManager.SpawnEntity("SharpTestObject", transformSystem.GetMapCoordinates(player));
Assert.That(handsSystem.TryPickup(player, item, handsComponent.ActiveHandId!));
entManager.TryGetComponent<ExecutionComponent>(item, out var executionComponent);
Assert.That(executionComponent, Is.Not.EqualTo(null));
});
// Check that running the suicide command kills the player
// and properly ghosts them without them being able to return to their body
// and that all the damage is concentrated in the Slash category
await server.WaitAssertion(() =>
{
// Heal all damage first (possible low pressure damage taken)
damageableSystem.ClearAllDamage((player, damageableComp));
consoleHost.GetSessionShell(playerMan.Sessions.First()).ExecuteCommand("suicide");
var lethalDamageThreshold = mobThresholdsComp.Thresholds.Keys.Last();
Assert.Multiple(() =>
{
Assert.That(mobStateSystem.IsDead(player, mobStateComp));
Assert.That(entManager.TryGetComponent<GhostComponent>(mindComponent.CurrentEntity, out var ghostComp) &&
!ghostComp.CanReturnToBody);
Assert.That(damageableSystem.GetAllDamage((player, damageableComp)).DamageDict["Slash"], Is.EqualTo(lethalDamageThreshold));
});
});
}
/// <summary>
/// Run the suicide command while the player is holding an execution-capable weapon
/// with damage spread between slash and blunt
/// </summary>
[Test]
public async Task TestSuicideByHeldItemSpreadDamage()
{
var pair = Pair;
var server = pair.Server;
var consoleHost = server.ResolveDependency<IConsoleHost>();
var entManager = server.ResolveDependency<IEntityManager>();
var playerMan = server.ResolveDependency<IPlayerManager>();
var handsSystem = entManager.System<SharedHandsSystem>();
var mindSystem = entManager.System<SharedMindSystem>();
var mobStateSystem = entManager.System<MobStateSystem>();
var transformSystem = entManager.System<TransformSystem>();
var damageableSystem = entManager.System<DamageableSystem>();
// We need to know the player and whether they can be hurt, killed, and whether they have a mind
var player = playerMan.Sessions.First().AttachedEntity!.Value;
var mind = mindSystem.GetMind(player);
MindComponent mindComponent = default;
MobStateComponent mobStateComp = default;
MobThresholdsComponent mobThresholdsComp = default;
DamageableComponent damageableComp = default;
HandsComponent handsComponent = default;
await server.WaitPost(() =>
{
if (mind != null)
mindComponent = entManager.GetComponent<MindComponent>(mind.Value);
mobStateComp = entManager.GetComponent<MobStateComponent>(player);
mobThresholdsComp = entManager.GetComponent<MobThresholdsComponent>(player);
damageableComp = entManager.GetComponent<DamageableComponent>(player);
handsComponent = entManager.GetComponent<HandsComponent>(player);
});
// Spawn the weapon of choice and put it in the player's hands
await server.WaitPost(() =>
{
var item = entManager.SpawnEntity("MixedDamageTestObject", transformSystem.GetMapCoordinates(player));
Assert.That(handsSystem.TryPickup(player, item, handsComponent.ActiveHandId!));
entManager.TryGetComponent<ExecutionComponent>(item, out var executionComponent);
Assert.That(executionComponent, Is.Not.EqualTo(null));
});
// Check that running the suicide command kills the player
// and properly ghosts them without them being able to return to their body
// and that slash damage is split in half
await server.WaitAssertion(() =>
{
// Heal all damage first (possible low pressure damage taken)
damageableSystem.ClearAllDamage((player, damageableComp));
consoleHost.GetSessionShell(playerMan.Sessions.First()).ExecuteCommand("suicide");
var lethalDamageThreshold = mobThresholdsComp.Thresholds.Keys.Last();
Assert.Multiple(() =>
{
Assert.That(mobStateSystem.IsDead(player, mobStateComp));
Assert.That(entManager.TryGetComponent<GhostComponent>(mindComponent.CurrentEntity, out var ghostComp) &&
!ghostComp.CanReturnToBody);
Assert.That(damageableSystem.GetAllDamage((player, damageableComp)).DamageDict["Slash"], Is.EqualTo(lethalDamageThreshold / 2));
});
});
}
}