Decouple gibbing from the body system (#42405)
* Decouple gibbing from the body system * allow gibs that don't drop giblets * pass through user * prediction gon * comment * destructible * playpvs * very very very very very very very minor cleanup --------- Co-authored-by: Princess Cheeseballs <66055347+Pronana@users.noreply.github.com>
This commit is contained in:
parent
3f34d833fb
commit
66ddb7473f
|
|
@ -1,43 +0,0 @@
|
||||||
#nullable enable
|
|
||||||
using Content.Server.Body.Systems;
|
|
||||||
using Robust.Shared.GameObjects;
|
|
||||||
|
|
||||||
namespace Content.IntegrationTests.Tests.Body;
|
|
||||||
|
|
||||||
[TestFixture]
|
|
||||||
public sealed class GibTest
|
|
||||||
{
|
|
||||||
[Test]
|
|
||||||
public async Task TestGib()
|
|
||||||
{
|
|
||||||
await using var pair = await PoolManager.GetServerClient(new PoolSettings { Connected = true });
|
|
||||||
var (server, client) = (pair.Server, pair.Client);
|
|
||||||
var map = await pair.CreateTestMap();
|
|
||||||
|
|
||||||
EntityUid target1 = default;
|
|
||||||
EntityUid target2 = default;
|
|
||||||
|
|
||||||
await server.WaitAssertion(() => target1 = server.EntMan.Spawn("MobHuman", map.MapCoords));
|
|
||||||
await server.WaitAssertion(() => target2 = server.EntMan.Spawn("MobHuman", map.MapCoords));
|
|
||||||
await pair.WaitCommand($"setoutfit {server.EntMan.GetNetEntity(target1)} CaptainGear");
|
|
||||||
await pair.WaitCommand($"setoutfit {server.EntMan.GetNetEntity(target2)} CaptainGear");
|
|
||||||
|
|
||||||
await pair.RunTicksSync(5);
|
|
||||||
var nuid1 = pair.ToClientUid(target1);
|
|
||||||
var nuid2 = pair.ToClientUid(target2);
|
|
||||||
Assert.That(client.EntMan.EntityExists(nuid1));
|
|
||||||
Assert.That(client.EntMan.EntityExists(nuid2));
|
|
||||||
|
|
||||||
await server.WaitAssertion(() => server.System<BodySystem>().GibBody(target1, acidify: false));
|
|
||||||
await server.WaitAssertion(() => server.System<BodySystem>().GibBody(target2, acidify: true));
|
|
||||||
|
|
||||||
await pair.RunTicksSync(5);
|
|
||||||
await pair.WaitCommand("dirty");
|
|
||||||
await pair.RunTicksSync(5);
|
|
||||||
|
|
||||||
Assert.That(!client.EntMan.EntityExists(nuid1));
|
|
||||||
Assert.That(!client.EntMan.EntityExists(nuid2));
|
|
||||||
|
|
||||||
await pair.CleanReturnAsync();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -0,0 +1,36 @@
|
||||||
|
#nullable enable
|
||||||
|
using Content.Shared.Gibbing;
|
||||||
|
using Robust.Shared.GameObjects;
|
||||||
|
|
||||||
|
namespace Content.IntegrationTests.Tests.Body;
|
||||||
|
|
||||||
|
[TestFixture]
|
||||||
|
public sealed class GibTest
|
||||||
|
{
|
||||||
|
[Test]
|
||||||
|
public async Task TestGib()
|
||||||
|
{
|
||||||
|
await using var pair = await PoolManager.GetServerClient(new PoolSettings { Connected = true });
|
||||||
|
var (server, client) = (pair.Server, pair.Client);
|
||||||
|
var map = await pair.CreateTestMap();
|
||||||
|
|
||||||
|
EntityUid target = default;
|
||||||
|
|
||||||
|
await server.WaitAssertion(() => target = server.EntMan.Spawn("MobHuman", map.MapCoords));
|
||||||
|
await pair.WaitCommand($"setoutfit {server.EntMan.GetNetEntity(target)} CaptainGear");
|
||||||
|
|
||||||
|
await pair.RunTicksSync(5);
|
||||||
|
var nuid = pair.ToClientUid(target);
|
||||||
|
Assert.That(client.EntMan.EntityExists(nuid));
|
||||||
|
|
||||||
|
await server.WaitAssertion(() => server.System<GibbingSystem>().Gib(target));
|
||||||
|
|
||||||
|
await pair.RunTicksSync(5);
|
||||||
|
await pair.WaitCommand("dirty");
|
||||||
|
await pair.RunTicksSync(5);
|
||||||
|
|
||||||
|
Assert.That(!client.EntMan.EntityExists(nuid));
|
||||||
|
|
||||||
|
await pair.CleanReturnAsync();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -29,6 +29,7 @@ using Content.Shared.Damage.Components;
|
||||||
using Content.Shared.Damage.Systems;
|
using Content.Shared.Damage.Systems;
|
||||||
using Content.Shared.Database;
|
using Content.Shared.Database;
|
||||||
using Content.Shared.Electrocution;
|
using Content.Shared.Electrocution;
|
||||||
|
using Content.Shared.Gibbing;
|
||||||
using Content.Shared.Gravity;
|
using Content.Shared.Gravity;
|
||||||
using Content.Shared.Interaction.Components;
|
using Content.Shared.Interaction.Components;
|
||||||
using Content.Shared.Inventory;
|
using Content.Shared.Inventory;
|
||||||
|
|
@ -92,6 +93,7 @@ public sealed partial class AdminVerbSystem
|
||||||
[Dependency] private readonly SharedTransformSystem _transformSystem = default!;
|
[Dependency] private readonly SharedTransformSystem _transformSystem = default!;
|
||||||
[Dependency] private readonly SuperBonkSystem _superBonkSystem = default!;
|
[Dependency] private readonly SuperBonkSystem _superBonkSystem = default!;
|
||||||
[Dependency] private readonly SlipperySystem _slipperySystem = default!;
|
[Dependency] private readonly SlipperySystem _slipperySystem = default!;
|
||||||
|
[Dependency] private readonly GibbingSystem _gibbing = default!;
|
||||||
|
|
||||||
private readonly EntProtoId _actionViewLawsProtoId = "ActionViewLaws";
|
private readonly EntProtoId _actionViewLawsProtoId = "ActionViewLaws";
|
||||||
private readonly ProtoId<SiliconLawsetPrototype> _crewsimovLawset = "Crewsimov";
|
private readonly ProtoId<SiliconLawsetPrototype> _crewsimovLawset = "Crewsimov";
|
||||||
|
|
@ -128,7 +130,7 @@ public sealed partial class AdminVerbSystem
|
||||||
4, 1, 2, args.Target, maxTileBreak: 0), // it gibs, damage doesn't need to be high.
|
4, 1, 2, args.Target, maxTileBreak: 0), // it gibs, damage doesn't need to be high.
|
||||||
CancellationToken.None);
|
CancellationToken.None);
|
||||||
|
|
||||||
_bodySystem.GibBody(args.Target);
|
_gibbing.Gib(args.Target);
|
||||||
},
|
},
|
||||||
Impact = LogImpact.Extreme,
|
Impact = LogImpact.Extreme,
|
||||||
Message = string.Join(": ", explodeName, Loc.GetString("admin-smite-explode-description")) // we do this so the description tells admins the Text to run it via console.
|
Message = string.Join(": ", explodeName, Loc.GetString("admin-smite-explode-description")) // we do this so the description tells admins the Text to run it via console.
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,7 @@ using Content.Shared.Anomaly.Effects;
|
||||||
using Content.Shared.Body.Components;
|
using Content.Shared.Body.Components;
|
||||||
using Content.Shared.Chat;
|
using Content.Shared.Chat;
|
||||||
using Content.Shared.Database;
|
using Content.Shared.Database;
|
||||||
|
using Content.Shared.Gibbing;
|
||||||
using Content.Shared.Mobs;
|
using Content.Shared.Mobs;
|
||||||
using Content.Shared.Popups;
|
using Content.Shared.Popups;
|
||||||
using Content.Shared.Whitelist;
|
using Content.Shared.Whitelist;
|
||||||
|
|
@ -25,7 +26,7 @@ public sealed class InnerBodyAnomalySystem : SharedInnerBodyAnomalySystem
|
||||||
[Dependency] private readonly IAdminLogManager _adminLog = default!;
|
[Dependency] private readonly IAdminLogManager _adminLog = default!;
|
||||||
[Dependency] private readonly AnomalySystem _anomaly = default!;
|
[Dependency] private readonly AnomalySystem _anomaly = default!;
|
||||||
[Dependency] private readonly SharedAudioSystem _audio = default!;
|
[Dependency] private readonly SharedAudioSystem _audio = default!;
|
||||||
[Dependency] private readonly BodySystem _body = default!;
|
[Dependency] private readonly GibbingSystem _gibbing = default!;
|
||||||
[Dependency] private readonly IChatManager _chat = default!;
|
[Dependency] private readonly IChatManager _chat = default!;
|
||||||
[Dependency] private readonly ISharedPlayerManager _player = default!;
|
[Dependency] private readonly ISharedPlayerManager _player = default!;
|
||||||
[Dependency] private readonly EntityWhitelistSystem _whitelist = default!;
|
[Dependency] private readonly EntityWhitelistSystem _whitelist = default!;
|
||||||
|
|
@ -139,8 +140,7 @@ public sealed class InnerBodyAnomalySystem : SharedInnerBodyAnomalySystem
|
||||||
if (!TryComp<BodyComponent>(ent, out var body))
|
if (!TryComp<BodyComponent>(ent, out var body))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// DeltaV acidify: false preserves inventory items when anomaly goes supercritical
|
_gibbing.Gib(ent.Owner);
|
||||||
_body.GibBody(ent, false, body, splatModifier: 5f);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnSeverityChanged(Entity<InnerBodyAnomalyComponent> ent, ref AnomalySeverityChangedEvent args)
|
private void OnSeverityChanged(Entity<InnerBodyAnomalyComponent> ent, ref AnomalySeverityChangedEvent args)
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@ using Content.Shared.Atmos;
|
||||||
using Content.Shared.Atmos.Rotting;
|
using Content.Shared.Atmos.Rotting;
|
||||||
using Content.Shared.Body.Events;
|
using Content.Shared.Body.Events;
|
||||||
using Content.Shared.Damage.Systems;
|
using Content.Shared.Damage.Systems;
|
||||||
|
using Content.Shared.Gibbing;
|
||||||
using Content.Shared.Temperature.Components;
|
using Content.Shared.Temperature.Components;
|
||||||
using Robust.Server.Containers;
|
using Robust.Server.Containers;
|
||||||
using Robust.Shared.Physics.Components;
|
using Robust.Shared.Physics.Components;
|
||||||
|
|
@ -21,12 +22,12 @@ public sealed class RottingSystem : SharedRottingSystem
|
||||||
{
|
{
|
||||||
base.Initialize();
|
base.Initialize();
|
||||||
|
|
||||||
SubscribeLocalEvent<RottingComponent, BeingGibbedEvent>(OnGibbed);
|
SubscribeLocalEvent<RottingComponent, GibbedBeforeDeletionEvent>(OnGibbed);
|
||||||
|
|
||||||
SubscribeLocalEvent<TemperatureComponent, IsRottingEvent>(OnTempIsRotting);
|
SubscribeLocalEvent<TemperatureComponent, IsRottingEvent>(OnTempIsRotting);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnGibbed(EntityUid uid, RottingComponent component, BeingGibbedEvent args)
|
private void OnGibbed(EntityUid uid, RottingComponent component, GibbedBeforeDeletionEvent args)
|
||||||
{
|
{
|
||||||
if (!TryComp<PhysicsComponent>(uid, out var physics))
|
if (!TryComp<PhysicsComponent>(uid, out var physics))
|
||||||
return;
|
return;
|
||||||
|
|
|
||||||
|
|
@ -22,7 +22,6 @@ using Content.Shared.Damage.Components;
|
||||||
// Shitmed Change
|
// Shitmed Change
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using Content.Shared.Damage;
|
using Content.Shared.Damage;
|
||||||
using Content.Shared.Gibbing.Events;
|
|
||||||
|
|
||||||
namespace Content.Server.Body.Systems;
|
namespace Content.Server.Body.Systems;
|
||||||
|
|
||||||
|
|
@ -107,99 +106,7 @@ public sealed class BodySystem : SharedBodySystem
|
||||||
_appearance.SetData(bodyEnt, layer, true); // Shitmed Change
|
_appearance.SetData(bodyEnt, layer, true); // Shitmed Change
|
||||||
}
|
}
|
||||||
|
|
||||||
public override HashSet<EntityUid> GibBody(
|
|
||||||
EntityUid bodyId,
|
|
||||||
bool acidify = false, // DeltaV - Changed paramater from gibOrgans
|
|
||||||
BodyComponent? body = null,
|
|
||||||
bool launchGibs = true,
|
|
||||||
Vector2? splatDirection = null,
|
|
||||||
float splatModifier = 1,
|
|
||||||
Angle splatCone = default,
|
|
||||||
SoundSpecifier? gibSoundOverride = null,
|
|
||||||
// Shitmed Change
|
|
||||||
GibType gib = GibType.Gib,
|
|
||||||
GibContentsOption contents = GibContentsOption.Drop)
|
|
||||||
{
|
|
||||||
if (!Resolve(bodyId, ref body, logMissing: false)
|
|
||||||
|| TerminatingOrDeleted(bodyId)
|
|
||||||
|| EntityManager.IsQueuedForDeletion(bodyId))
|
|
||||||
{
|
|
||||||
return new HashSet<EntityUid>();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (HasComp<GodmodeComponent>(bodyId))
|
|
||||||
return new HashSet<EntityUid>();
|
|
||||||
|
|
||||||
// DeltaV - If a polymorph configured to revert on death is gibbed without dying,
|
|
||||||
// revert it then gib so the parent is gibbed instead of the polymorph.
|
|
||||||
if (TryComp<PolymorphedEntityComponent>(bodyId, out var polymorph)
|
|
||||||
&& !polymorph.Reverted
|
|
||||||
&& polymorph.Configuration.RevertOnDeath)
|
|
||||||
{
|
|
||||||
_polymorph.Revert(bodyId);
|
|
||||||
if (polymorph.Configuration.TransferDamage && polymorph.Parent.HasValue)
|
|
||||||
GibBody(polymorph.Parent.Value, acidify, null, launchGibs: launchGibs, splatDirection: splatDirection,
|
|
||||||
splatModifier: splatModifier, splatCone: splatCone);
|
|
||||||
return new HashSet<EntityUid>();
|
|
||||||
}
|
|
||||||
// END DeltaV
|
|
||||||
|
|
||||||
var xform = Transform(bodyId);
|
|
||||||
if (xform.MapUid is null)
|
|
||||||
return new HashSet<EntityUid>();
|
|
||||||
|
|
||||||
var gibs = base.GibBody(bodyId, acidify, body, launchGibs: launchGibs,
|
|
||||||
splatDirection: splatDirection, splatModifier: splatModifier, splatCone: splatCone,
|
|
||||||
gib: gib, contents: contents); // Shitmed Change
|
|
||||||
|
|
||||||
var ev = new BeingGibbedEvent(gibs);
|
|
||||||
RaiseLocalEvent(bodyId, ref ev);
|
|
||||||
|
|
||||||
QueueDel(bodyId);
|
|
||||||
|
|
||||||
return gibs;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Shitmed Change Start
|
// Shitmed Change Start
|
||||||
public override HashSet<EntityUid> GibPart(
|
|
||||||
EntityUid partId,
|
|
||||||
BodyPartComponent? part = null,
|
|
||||||
bool launchGibs = true,
|
|
||||||
Vector2? splatDirection = null,
|
|
||||||
float splatModifier = 1,
|
|
||||||
Angle splatCone = default,
|
|
||||||
SoundSpecifier? gibSoundOverride = null)
|
|
||||||
{
|
|
||||||
if (!Resolve(partId, ref part, logMissing: false)
|
|
||||||
|| TerminatingOrDeleted(partId)
|
|
||||||
|| EntityManager.IsQueuedForDeletion(partId))
|
|
||||||
return new HashSet<EntityUid>();
|
|
||||||
|
|
||||||
if (Transform(partId).MapUid is null)
|
|
||||||
return new HashSet<EntityUid>();
|
|
||||||
|
|
||||||
var gibs = base.GibPart(partId, part, launchGibs: launchGibs,
|
|
||||||
splatDirection: splatDirection, splatModifier: splatModifier, splatCone: splatCone);
|
|
||||||
|
|
||||||
var ev = new BeingGibbedEvent(gibs);
|
|
||||||
RaiseLocalEvent(partId, ref ev);
|
|
||||||
|
|
||||||
if (gibs.Any())
|
|
||||||
QueueDel(partId);
|
|
||||||
|
|
||||||
return gibs;
|
|
||||||
}
|
|
||||||
|
|
||||||
public override bool BurnPart(EntityUid partId, BodyPartComponent? part = null)
|
|
||||||
{
|
|
||||||
if (!Resolve(partId, ref part, logMissing: false)
|
|
||||||
|| TerminatingOrDeleted(partId)
|
|
||||||
|| EntityManager.IsQueuedForDeletion(partId))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
return base.BurnPart(partId, part);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void ApplyPartMarkings(EntityUid target, BodyPartAppearanceComponent component)
|
protected override void ApplyPartMarkings(EntityUid target, BodyPartAppearanceComponent component)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@ using System.Linq;
|
||||||
using Content.Server._DV.Administration; // DeltaV - Admin QOL
|
using Content.Server._DV.Administration; // DeltaV - Admin QOL
|
||||||
using Content.Server.Administration.Logs;
|
using Content.Server.Administration.Logs;
|
||||||
using Content.Server.Atmos.EntitySystems;
|
using Content.Server.Atmos.EntitySystems;
|
||||||
using Content.Server.Body.Systems;
|
using Content.Server.Body.Systems; // DeltaV Keep body here for shitmed
|
||||||
using Content.Server.Construction;
|
using Content.Server.Construction;
|
||||||
using Content.Server.Destructible.Thresholds;
|
using Content.Server.Destructible.Thresholds;
|
||||||
using Content.Server.Destructible.Thresholds.Behaviors;
|
using Content.Server.Destructible.Thresholds.Behaviors;
|
||||||
|
|
@ -17,6 +17,7 @@ using Content.Shared.Database;
|
||||||
using Content.Shared.Destructible;
|
using Content.Shared.Destructible;
|
||||||
using Content.Shared.Destructible.Thresholds.Triggers;
|
using Content.Shared.Destructible.Thresholds.Triggers;
|
||||||
using Content.Shared.FixedPoint;
|
using Content.Shared.FixedPoint;
|
||||||
|
using Content.Shared.Gibbing;
|
||||||
using Content.Shared.Humanoid;
|
using Content.Shared.Humanoid;
|
||||||
using Content.Shared.Trigger.Systems;
|
using Content.Shared.Trigger.Systems;
|
||||||
using JetBrains.Annotations;
|
using JetBrains.Annotations;
|
||||||
|
|
@ -35,7 +36,8 @@ namespace Content.Server.Destructible
|
||||||
|
|
||||||
[Dependency] public readonly AtmosphereSystem AtmosphereSystem = default!;
|
[Dependency] public readonly AtmosphereSystem AtmosphereSystem = default!;
|
||||||
[Dependency] public readonly AudioSystem AudioSystem = default!;
|
[Dependency] public readonly AudioSystem AudioSystem = default!;
|
||||||
[Dependency] public readonly BodySystem BodySystem = default!;
|
[Dependency] public readonly GibbingSystem Gibbing = default!;
|
||||||
|
[Dependency] public readonly BodySystem BodySystem = default!; // Delta-V - Keep body here for shitmed
|
||||||
[Dependency] public readonly ConstructionSystem ConstructionSystem = default!;
|
[Dependency] public readonly ConstructionSystem ConstructionSystem = default!;
|
||||||
[Dependency] public readonly ExplosionSystem ExplosionSystem = default!;
|
[Dependency] public readonly ExplosionSystem ExplosionSystem = default!;
|
||||||
[Dependency] public readonly StackSystem StackSystem = default!;
|
[Dependency] public readonly StackSystem StackSystem = default!;
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,5 @@
|
||||||
using Content.Shared.Body.Components;
|
using Content.Shared.Body.Components;
|
||||||
using Content.Shared.Database;
|
using Content.Shared.Database;
|
||||||
using Content.Shared.Gibbing.Events; // Shitmed Change
|
|
||||||
using JetBrains.Annotations;
|
using JetBrains.Annotations;
|
||||||
|
|
||||||
namespace Content.Server.Destructible.Thresholds.Behaviors
|
namespace Content.Server.Destructible.Thresholds.Behaviors
|
||||||
|
|
@ -9,18 +8,13 @@ namespace Content.Server.Destructible.Thresholds.Behaviors
|
||||||
[DataDefinition]
|
[DataDefinition]
|
||||||
public sealed partial class GibBehavior : IThresholdBehavior
|
public sealed partial class GibBehavior : IThresholdBehavior
|
||||||
{
|
{
|
||||||
[DataField] public GibType GibType = GibType.Gib; // Shitmed Change
|
|
||||||
[DataField] public GibContentsOption GibContents = GibContentsOption.Drop; // Shitmed Change
|
|
||||||
[DataField("recursive")] private bool _recursive = true;
|
[DataField("recursive")] private bool _recursive = true;
|
||||||
|
|
||||||
public LogImpact Impact => LogImpact.Extreme;
|
public LogImpact Impact => LogImpact.Extreme;
|
||||||
|
|
||||||
public void Execute(EntityUid owner, DestructibleSystem system, EntityUid? cause = null)
|
public void Execute(EntityUid owner, DestructibleSystem system, EntityUid? cause = null)
|
||||||
{
|
{
|
||||||
if (system.EntityManager.TryGetComponent(owner, out BodyComponent? body))
|
system.Gibbing.Gib(owner, _recursive);
|
||||||
{
|
|
||||||
system.BodySystem.GibBody(owner, _recursive, body, gib: GibType, contents: GibContents); // Shitmed Change
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -13,6 +13,7 @@ using Content.Shared.DoAfter;
|
||||||
using Content.Shared.Forensics;
|
using Content.Shared.Forensics;
|
||||||
using Content.Shared.Forensics.Components;
|
using Content.Shared.Forensics.Components;
|
||||||
using Content.Shared.Forensics.Systems;
|
using Content.Shared.Forensics.Systems;
|
||||||
|
using Content.Shared.Gibbing;
|
||||||
using Content.Shared.Interaction;
|
using Content.Shared.Interaction;
|
||||||
using Content.Shared.Interaction.Events;
|
using Content.Shared.Interaction.Events;
|
||||||
using Content.Shared.Inventory;
|
using Content.Shared.Inventory;
|
||||||
|
|
@ -40,7 +41,7 @@ namespace Content.Server.Forensics
|
||||||
// The solution entities are spawned on MapInit as well, so we have to wait for that to be able to set the DNA in the bloodstream correctly without ResolveSolution failing
|
// The solution entities are spawned on MapInit as well, so we have to wait for that to be able to set the DNA in the bloodstream correctly without ResolveSolution failing
|
||||||
SubscribeLocalEvent<DnaComponent, MapInitEvent>(OnDNAInit, after: new[] { typeof(BloodstreamSystem) });
|
SubscribeLocalEvent<DnaComponent, MapInitEvent>(OnDNAInit, after: new[] { typeof(BloodstreamSystem) });
|
||||||
|
|
||||||
SubscribeLocalEvent<ForensicsComponent, BeingGibbedEvent>(OnBeingGibbed);
|
SubscribeLocalEvent<ForensicsComponent, GibbedBeforeDeletionEvent>(OnBeingGibbed);
|
||||||
SubscribeLocalEvent<ForensicsComponent, MeleeHitEvent>(OnMeleeHit);
|
SubscribeLocalEvent<ForensicsComponent, MeleeHitEvent>(OnMeleeHit);
|
||||||
SubscribeLocalEvent<ForensicsComponent, GotRehydratedEvent>(OnRehydrated);
|
SubscribeLocalEvent<ForensicsComponent, GotRehydratedEvent>(OnRehydrated);
|
||||||
SubscribeLocalEvent<CleansForensicsComponent, AfterInteractEvent>(OnAfterInteract, after: new[] { typeof(AbsorbentSystem) });
|
SubscribeLocalEvent<CleansForensicsComponent, AfterInteractEvent>(OnAfterInteract, after: new[] { typeof(AbsorbentSystem) });
|
||||||
|
|
@ -94,14 +95,14 @@ namespace Content.Server.Forensics
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnBeingGibbed(EntityUid uid, ForensicsComponent component, BeingGibbedEvent args)
|
private void OnBeingGibbed(Entity<ForensicsComponent> ent, ref GibbedBeforeDeletionEvent args)
|
||||||
{
|
{
|
||||||
string dna = Loc.GetString("forensics-dna-unknown");
|
string dna = Loc.GetString("forensics-dna-unknown");
|
||||||
|
|
||||||
if (TryComp(uid, out DnaComponent? dnaComp) && dnaComp.DNA != null)
|
if (TryComp(ent, out DnaComponent? dnaComp) && dnaComp.DNA != null)
|
||||||
dna = dnaComp.DNA;
|
dna = dnaComp.DNA;
|
||||||
|
|
||||||
foreach (EntityUid part in args.GibbedParts)
|
foreach (var part in args.Giblets)
|
||||||
{
|
{
|
||||||
var partComp = EnsureComp<ForensicsComponent>(part);
|
var partComp = EnsureComp<ForensicsComponent>(part);
|
||||||
partComp.DNAs.Add(dna);
|
partComp.DNAs.Add(dna);
|
||||||
|
|
|
||||||
|
|
@ -2,12 +2,12 @@
|
||||||
using Content.Shared.Gibbing.Components;
|
using Content.Shared.Gibbing.Components;
|
||||||
using Content.Shared.Mind;
|
using Content.Shared.Mind;
|
||||||
using Content.Shared.Objectives.Systems;
|
using Content.Shared.Objectives.Systems;
|
||||||
using Content.Server.Body.Systems;
|
using Content.Shared.Gibbing;
|
||||||
|
|
||||||
namespace Content.Server.Gibbing.Systems;
|
namespace Content.Server.Gibbing.Systems;
|
||||||
public sealed class GibOnRoundEndSystem : EntitySystem
|
public sealed class GibOnRoundEndSystem : EntitySystem
|
||||||
{
|
{
|
||||||
[Dependency] private readonly BodySystem _body = default!;
|
[Dependency] private readonly GibbingSystem _gibbing = default!;
|
||||||
[Dependency] private readonly SharedMindSystem _mind = default!;
|
[Dependency] private readonly SharedMindSystem _mind = default!;
|
||||||
[Dependency] private readonly SharedObjectivesSystem _objectives = default!;
|
[Dependency] private readonly SharedObjectivesSystem _objectives = default!;
|
||||||
|
|
||||||
|
|
@ -49,7 +49,7 @@ public sealed class GibOnRoundEndSystem : EntitySystem
|
||||||
if (gibComp.SpawnProto != null)
|
if (gibComp.SpawnProto != null)
|
||||||
SpawnAtPosition(gibComp.SpawnProto, Transform(uid).Coordinates);
|
SpawnAtPosition(gibComp.SpawnProto, Transform(uid).Coordinates);
|
||||||
|
|
||||||
_body.GibBody(uid, splatModifier: 5f);
|
_gibbing.Gib(uid);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,9 @@
|
||||||
using Content.Server.Body.Systems;
|
|
||||||
using Content.Server.Popups;
|
using Content.Server.Popups;
|
||||||
using Content.Shared.Actions;
|
using Content.Shared.Actions;
|
||||||
using Content.Shared.Damage.Systems;
|
using Content.Shared.Damage.Systems;
|
||||||
using Content.Shared.DoAfter;
|
using Content.Shared.DoAfter;
|
||||||
using Content.Shared.Examine;
|
using Content.Shared.Examine;
|
||||||
|
using Content.Shared.Gibbing;
|
||||||
using Content.Shared.Guardian;
|
using Content.Shared.Guardian;
|
||||||
using Content.Shared.Hands.Components;
|
using Content.Shared.Hands.Components;
|
||||||
using Content.Shared.Hands.EntitySystems;
|
using Content.Shared.Hands.EntitySystems;
|
||||||
|
|
@ -31,7 +31,7 @@ namespace Content.Server.Guardian
|
||||||
[Dependency] private readonly SharedActionsSystem _actionSystem = default!;
|
[Dependency] private readonly SharedActionsSystem _actionSystem = default!;
|
||||||
[Dependency] private readonly SharedHandsSystem _handsSystem = default!;
|
[Dependency] private readonly SharedHandsSystem _handsSystem = default!;
|
||||||
[Dependency] private readonly SharedAudioSystem _audio = default!;
|
[Dependency] private readonly SharedAudioSystem _audio = default!;
|
||||||
[Dependency] private readonly BodySystem _bodySystem = default!;
|
[Dependency] private readonly GibbingSystem _gibbing = default!;
|
||||||
[Dependency] private readonly SharedContainerSystem _container = default!;
|
[Dependency] private readonly SharedContainerSystem _container = default!;
|
||||||
[Dependency] private readonly SharedTransformSystem _transform = default!;
|
[Dependency] private readonly SharedTransformSystem _transform = default!;
|
||||||
|
|
||||||
|
|
@ -130,7 +130,7 @@ namespace Content.Server.Guardian
|
||||||
|
|
||||||
// Ensure held items are dropped before deleting guardian.
|
// Ensure held items are dropped before deleting guardian.
|
||||||
if (HasComp<HandsComponent>(guardian))
|
if (HasComp<HandsComponent>(guardian))
|
||||||
_bodySystem.GibBody(component.HostedGuardian.Value);
|
_gibbing.Gib(component.HostedGuardian.Value);
|
||||||
|
|
||||||
QueueDel(guardian);
|
QueueDel(guardian);
|
||||||
QueueDel(component.ActionEntity);
|
QueueDel(component.ActionEntity);
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@ using Content.Server.Popups;
|
||||||
using Content.Shared.Body.Components;
|
using Content.Shared.Body.Components;
|
||||||
using Content.Shared.Damage.Systems;
|
using Content.Shared.Damage.Systems;
|
||||||
using Content.Shared.Examine;
|
using Content.Shared.Examine;
|
||||||
|
using Content.Shared.Gibbing;
|
||||||
using Content.Shared.Popups;
|
using Content.Shared.Popups;
|
||||||
using Robust.Shared.Audio.Systems;
|
using Robust.Shared.Audio.Systems;
|
||||||
using Robust.Shared.Map;
|
using Robust.Shared.Map;
|
||||||
|
|
@ -20,7 +21,7 @@ public sealed class ImmovableRodSystem : EntitySystem
|
||||||
{
|
{
|
||||||
[Dependency] private readonly IRobustRandom _random = default!;
|
[Dependency] private readonly IRobustRandom _random = default!;
|
||||||
|
|
||||||
[Dependency] private readonly BodySystem _bodySystem = default!;
|
[Dependency] private readonly GibbingSystem _gibbing = default!;
|
||||||
[Dependency] private readonly PopupSystem _popup = default!;
|
[Dependency] private readonly PopupSystem _popup = default!;
|
||||||
[Dependency] private readonly SharedPhysicsSystem _physics = default!;
|
[Dependency] private readonly SharedPhysicsSystem _physics = default!;
|
||||||
[Dependency] private readonly SharedAudioSystem _audio = default!;
|
[Dependency] private readonly SharedAudioSystem _audio = default!;
|
||||||
|
|
@ -125,7 +126,7 @@ public sealed class ImmovableRodSystem : EntitySystem
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
_bodySystem.GibBody(ent, body: body);
|
_gibbing.Gib(ent);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
using Content.Shared.Body.Events;
|
using Content.Shared.Body.Events;
|
||||||
|
using Content.Shared.Gibbing;
|
||||||
using Content.Shared.Implants.Components;
|
using Content.Shared.Implants.Components;
|
||||||
using Content.Shared.Storage;
|
using Content.Shared.Storage;
|
||||||
using Robust.Shared.Containers;
|
using Robust.Shared.Containers;
|
||||||
|
|
@ -11,7 +12,7 @@ public sealed partial class ImplanterSystem
|
||||||
{
|
{
|
||||||
SubscribeLocalEvent<ImplantedComponent, ComponentInit>(OnImplantedInit);
|
SubscribeLocalEvent<ImplantedComponent, ComponentInit>(OnImplantedInit);
|
||||||
SubscribeLocalEvent<ImplantedComponent, ComponentShutdown>(OnShutdown);
|
SubscribeLocalEvent<ImplantedComponent, ComponentShutdown>(OnShutdown);
|
||||||
SubscribeLocalEvent<ImplantedComponent, BeingGibbedEvent>(OnGibbed);
|
SubscribeLocalEvent<ImplantedComponent, GibbedBeforeDeletionEvent>(OnGibbed);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnImplantedInit(Entity<ImplantedComponent> ent, ref ComponentInit args)
|
private void OnImplantedInit(Entity<ImplantedComponent> ent, ref ComponentInit args)
|
||||||
|
|
@ -26,7 +27,7 @@ public sealed partial class ImplanterSystem
|
||||||
_container.CleanContainer(ent.Comp.ImplantContainer);
|
_container.CleanContainer(ent.Comp.ImplantContainer);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnGibbed(Entity<ImplantedComponent> ent, ref BeingGibbedEvent args)
|
private void OnGibbed(Entity<ImplantedComponent> ent, ref GibbedBeforeDeletionEvent args)
|
||||||
{
|
{
|
||||||
// Drop the storage implant contents before the implants are deleted by the body being gibbed
|
// Drop the storage implant contents before the implants are deleted by the body being gibbed
|
||||||
foreach (var implant in ent.Comp.ImplantContainer.ContainedEntities)
|
foreach (var implant in ent.Comp.ImplantContainer.ContainedEntities)
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,8 @@
|
||||||
using Content.Server.Body.Systems;
|
using Content.Shared.Administration.Logs;
|
||||||
using Content.Shared.Administration.Logs;
|
|
||||||
using Content.Shared.Body.Components;
|
|
||||||
using Content.Shared.Database;
|
using Content.Shared.Database;
|
||||||
using Content.Shared.Destructible;
|
using Content.Shared.Destructible;
|
||||||
using Content.Shared.DoAfter;
|
using Content.Shared.DoAfter;
|
||||||
|
using Content.Shared.Gibbing;
|
||||||
using Content.Shared.IdentityManagement;
|
using Content.Shared.IdentityManagement;
|
||||||
using Content.Shared.Interaction;
|
using Content.Shared.Interaction;
|
||||||
using Content.Shared.Kitchen;
|
using Content.Shared.Kitchen;
|
||||||
|
|
@ -24,7 +23,7 @@ namespace Content.Server.Kitchen.EntitySystems;
|
||||||
|
|
||||||
public sealed class SharpSystem : EntitySystem
|
public sealed class SharpSystem : EntitySystem
|
||||||
{
|
{
|
||||||
[Dependency] private readonly BodySystem _bodySystem = default!;
|
[Dependency] private readonly GibbingSystem _gibbing = default!;
|
||||||
[Dependency] private readonly SharedDestructibleSystem _destructibleSystem = default!;
|
[Dependency] private readonly SharedDestructibleSystem _destructibleSystem = default!;
|
||||||
[Dependency] private readonly SharedDoAfterSystem _doAfterSystem = default!;
|
[Dependency] private readonly SharedDoAfterSystem _doAfterSystem = default!;
|
||||||
[Dependency] private readonly SharedPopupSystem _popupSystem = default!;
|
[Dependency] private readonly SharedPopupSystem _popupSystem = default!;
|
||||||
|
|
@ -134,7 +133,7 @@ public sealed class SharpSystem : EntitySystem
|
||||||
args.Args.User,
|
args.Args.User,
|
||||||
popupType);
|
popupType);
|
||||||
|
|
||||||
_bodySystem.GibBody(args.Args.Target.Value); // does nothing if ent can't be gibbed
|
_gibbing.Gib(args.Args.Target.Value); // does nothing if ent can't be gibbed
|
||||||
_destructibleSystem.DestroyEntity(args.Args.Target.Value);
|
_destructibleSystem.DestroyEntity(args.Args.Target.Value);
|
||||||
|
|
||||||
args.Handled = true;
|
args.Handled = true;
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,6 @@ using Content.Server.Ghost;
|
||||||
using Content.Server.Popups;
|
using Content.Server.Popups;
|
||||||
using Content.Server.Stack;
|
using Content.Server.Stack;
|
||||||
using Content.Server.Wires;
|
using Content.Server.Wires;
|
||||||
using Content.Shared.Body.Systems;
|
|
||||||
using Content.Shared.Chemistry.Components;
|
using Content.Shared.Chemistry.Components;
|
||||||
using Content.Shared.Chemistry.Components.SolutionManager;
|
using Content.Shared.Chemistry.Components.SolutionManager;
|
||||||
using Content.Shared.Chemistry.EntitySystems;
|
using Content.Shared.Chemistry.EntitySystems;
|
||||||
|
|
@ -25,6 +24,7 @@ using Robust.Shared.Player;
|
||||||
using Robust.Shared.Prototypes;
|
using Robust.Shared.Prototypes;
|
||||||
using Robust.Shared.Utility;
|
using Robust.Shared.Utility;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using Content.Shared.Gibbing;
|
||||||
using Content.Shared.Humanoid;
|
using Content.Shared.Humanoid;
|
||||||
|
|
||||||
namespace Content.Server.Materials;
|
namespace Content.Server.Materials;
|
||||||
|
|
@ -39,7 +39,7 @@ public sealed class MaterialReclaimerSystem : SharedMaterialReclaimerSystem
|
||||||
[Dependency] private readonly OpenableSystem _openable = default!;
|
[Dependency] private readonly OpenableSystem _openable = default!;
|
||||||
[Dependency] private readonly PopupSystem _popup = default!;
|
[Dependency] private readonly PopupSystem _popup = default!;
|
||||||
[Dependency] private readonly SharedSolutionContainerSystem _solutionContainer = default!;
|
[Dependency] private readonly SharedSolutionContainerSystem _solutionContainer = default!;
|
||||||
[Dependency] private readonly SharedBodySystem _body = default!; //bobby
|
[Dependency] private readonly GibbingSystem _gibbing = default!;
|
||||||
[Dependency] private readonly PuddleSystem _puddle = default!;
|
[Dependency] private readonly PuddleSystem _puddle = default!;
|
||||||
[Dependency] private readonly StackSystem _stack = default!;
|
[Dependency] private readonly StackSystem _stack = default!;
|
||||||
[Dependency] private readonly SharedMindSystem _mind = default!;
|
[Dependency] private readonly SharedMindSystem _mind = default!;
|
||||||
|
|
@ -112,7 +112,7 @@ public sealed class MaterialReclaimerSystem : SharedMaterialReclaimerSystem
|
||||||
Filter.PvsExcept(victim, entityManager: EntityManager),
|
Filter.PvsExcept(victim, entityManager: EntityManager),
|
||||||
true);
|
true);
|
||||||
|
|
||||||
_body.GibBody(victim, true);
|
_gibbing.Gib(victim);
|
||||||
_appearance.SetData(entity.Owner, RecyclerVisuals.Bloody, true);
|
_appearance.SetData(entity.Owner, RecyclerVisuals.Bloody, true);
|
||||||
args.Handled = true;
|
args.Handled = true;
|
||||||
}
|
}
|
||||||
|
|
@ -193,7 +193,7 @@ public sealed class MaterialReclaimerSystem : SharedMaterialReclaimerSystem
|
||||||
_adminLogger.Add(LogType.Gib, logImpact, $"{ToPrettyString(item):victim} was gibbed by {ToPrettyString(uid):entity} ");
|
_adminLogger.Add(LogType.Gib, logImpact, $"{ToPrettyString(item):victim} was gibbed by {ToPrettyString(uid):entity} ");
|
||||||
if (component.ReclaimSolutions)
|
if (component.ReclaimSolutions)
|
||||||
SpawnChemicalsFromComposition(uid, item, completion, false, component, xform);
|
SpawnChemicalsFromComposition(uid, item, completion, false, component, xform);
|
||||||
_body.GibBody(item, true);
|
_gibbing.Gib(item);
|
||||||
_appearance.SetData(uid, RecyclerVisuals.Bloody, true);
|
_appearance.SetData(uid, RecyclerVisuals.Bloody, true);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using Content.Shared.Body.Events;
|
using Content.Shared.Gibbing;
|
||||||
using Content.Shared.Mind;
|
using Content.Shared.Mind;
|
||||||
using Content.Shared.Mind.Components;
|
using Content.Shared.Mind.Components;
|
||||||
using Content.Shared.Tag;
|
using Content.Shared.Tag;
|
||||||
|
|
@ -21,19 +21,19 @@ public sealed class TransferMindOnGibSystem : EntitySystem
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public override void Initialize()
|
public override void Initialize()
|
||||||
{
|
{
|
||||||
SubscribeLocalEvent<TransferMindOnGibComponent, BeingGibbedEvent>(OnGib);
|
SubscribeLocalEvent<TransferMindOnGibComponent, GibbedBeforeDeletionEvent>(OnGib);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnGib(EntityUid uid, TransferMindOnGibComponent component, BeingGibbedEvent args)
|
private void OnGib(Entity<TransferMindOnGibComponent> ent, ref GibbedBeforeDeletionEvent args)
|
||||||
{
|
{
|
||||||
if (!_mindSystem.TryGetMind(uid, out var mindId, out var mind))
|
if (!_mindSystem.TryGetMind(ent, out var mindId, out var mind))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var validParts = args.GibbedParts.Where(p => _tag.HasTag(p, component.TargetTag)).ToHashSet();
|
var validParts = args.Giblets.Where(p => _tag.HasTag(p, ent.Comp.TargetTag)).ToHashSet();
|
||||||
if (!validParts.Any())
|
if (!validParts.Any())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var ent = _random.Pick(validParts);
|
var transfer = _random.Pick(validParts);
|
||||||
_mindSystem.TransferTo(mindId, ent, mind: mind);
|
_mindSystem.TransferTo(mindId, transfer, mind: mind);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1004,7 +1004,7 @@ public sealed partial class ShuttleSystem
|
||||||
{
|
{
|
||||||
_logger.Add(LogType.Gib, LogImpact.Extreme, $"{ToPrettyString(ent):player} got gibbed by the shuttle" +
|
_logger.Add(LogType.Gib, LogImpact.Extreme, $"{ToPrettyString(ent):player} got gibbed by the shuttle" +
|
||||||
$" {ToPrettyString(uid)} arriving from FTL at {xform.Coordinates:coordinates}");
|
$" {ToPrettyString(uid)} arriving from FTL at {xform.Coordinates:coordinates}");
|
||||||
var gibs = _bobby.GibBody(ent, body: mob);
|
var gibs = _gibbing.Gib(ent);
|
||||||
_immuneEnts.UnionWith(gibs);
|
_immuneEnts.UnionWith(gibs);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,4 @@
|
||||||
using Content.Server.Administration.Logs;
|
using Content.Server.Administration.Logs;
|
||||||
using Content.Server.Body.Systems;
|
|
||||||
using Content.Server.Buckle.Systems;
|
using Content.Server.Buckle.Systems;
|
||||||
using Content.Server.Parallax;
|
using Content.Server.Parallax;
|
||||||
using Content.Server.Procedural;
|
using Content.Server.Procedural;
|
||||||
|
|
@ -9,6 +8,7 @@ using Content.Server.Station.Systems;
|
||||||
using Content.Server.Stunnable;
|
using Content.Server.Stunnable;
|
||||||
using Content.Shared.Buckle.Components;
|
using Content.Shared.Buckle.Components;
|
||||||
using Content.Shared.Damage.Systems;
|
using Content.Shared.Damage.Systems;
|
||||||
|
using Content.Shared.Gibbing;
|
||||||
using Content.Shared.Light.Components;
|
using Content.Shared.Light.Components;
|
||||||
using Content.Shared.Movement.Events;
|
using Content.Shared.Movement.Events;
|
||||||
using Content.Shared.Salvage;
|
using Content.Shared.Salvage;
|
||||||
|
|
@ -42,7 +42,7 @@ public sealed partial class ShuttleSystem : SharedShuttleSystem
|
||||||
[Dependency] private readonly IPrototypeManager _protoManager = default!;
|
[Dependency] private readonly IPrototypeManager _protoManager = default!;
|
||||||
[Dependency] private readonly IRobustRandom _random = default!;
|
[Dependency] private readonly IRobustRandom _random = default!;
|
||||||
[Dependency] private readonly BiomeSystem _biomes = default!;
|
[Dependency] private readonly BiomeSystem _biomes = default!;
|
||||||
[Dependency] private readonly BodySystem _bobby = default!;
|
[Dependency] private readonly GibbingSystem _gibbing = default!;
|
||||||
[Dependency] private readonly BuckleSystem _buckle = default!;
|
[Dependency] private readonly BuckleSystem _buckle = default!;
|
||||||
[Dependency] private readonly DamageableSystem _damageSys = default!;
|
[Dependency] private readonly DamageableSystem _damageSys = default!;
|
||||||
[Dependency] private readonly DockingSystem _dockSystem = default!;
|
[Dependency] private readonly DockingSystem _dockSystem = default!;
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
using Content.Server.Body.Systems;
|
using Content.Server.Body.Systems;
|
||||||
using Content.Server.Stack;
|
using Content.Server.Stack;
|
||||||
using Content.Shared.Body.Components;
|
using Content.Shared.Body.Components;
|
||||||
|
using Content.Shared.Gibbing;
|
||||||
using Content.Shared.Storage.Components;
|
using Content.Shared.Storage.Components;
|
||||||
using Content.Shared.Whitelist;
|
using Content.Shared.Whitelist;
|
||||||
using Content.Shared.Xenoarchaeology.Equipment;
|
using Content.Shared.Xenoarchaeology.Equipment;
|
||||||
|
|
@ -14,7 +15,7 @@ namespace Content.Server.Xenoarchaeology.Equipment.Systems;
|
||||||
public sealed class ArtifactCrusherSystem : SharedArtifactCrusherSystem
|
public sealed class ArtifactCrusherSystem : SharedArtifactCrusherSystem
|
||||||
{
|
{
|
||||||
[Dependency] private readonly IRobustRandom _random = default!;
|
[Dependency] private readonly IRobustRandom _random = default!;
|
||||||
[Dependency] private readonly BodySystem _body = default!;
|
[Dependency] private readonly GibbingSystem _gibbing = default!;
|
||||||
[Dependency] private readonly StackSystem _stack = default!;
|
[Dependency] private readonly StackSystem _stack = default!;
|
||||||
[Dependency] private readonly EntityWhitelistSystem _whitelistSystem = default!;
|
[Dependency] private readonly EntityWhitelistSystem _whitelistSystem = default!;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,7 +0,0 @@
|
||||||
namespace Content.Shared.Body.Events;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Raised when a body gets gibbed, before it is deleted.
|
|
||||||
/// </summary>
|
|
||||||
[ByRefEvent]
|
|
||||||
public readonly record struct BeingGibbedEvent(HashSet<EntityUid> GibbedParts);
|
|
||||||
|
|
@ -11,6 +11,7 @@ using Content.Shared.EntityEffects.Effects.Solution;
|
||||||
using Content.Shared.FixedPoint;
|
using Content.Shared.FixedPoint;
|
||||||
using Content.Shared.Fluids;
|
using Content.Shared.Fluids;
|
||||||
using Content.Shared.Forensics.Components;
|
using Content.Shared.Forensics.Components;
|
||||||
|
using Content.Shared.Gibbing;
|
||||||
using Content.Shared.HealthExaminable;
|
using Content.Shared.HealthExaminable;
|
||||||
using Content.Shared.Mobs.Systems;
|
using Content.Shared.Mobs.Systems;
|
||||||
using Content.Shared.Popups;
|
using Content.Shared.Popups;
|
||||||
|
|
@ -50,7 +51,7 @@ public abstract class SharedBloodstreamSystem : EntitySystem
|
||||||
SubscribeLocalEvent<BloodstreamComponent, SolutionRelayEvent<ReactionAttemptEvent>>(OnReactionAttempt);
|
SubscribeLocalEvent<BloodstreamComponent, SolutionRelayEvent<ReactionAttemptEvent>>(OnReactionAttempt);
|
||||||
SubscribeLocalEvent<BloodstreamComponent, DamageChangedEvent>(OnDamageChanged);
|
SubscribeLocalEvent<BloodstreamComponent, DamageChangedEvent>(OnDamageChanged);
|
||||||
SubscribeLocalEvent<BloodstreamComponent, HealthBeingExaminedEvent>(OnHealthBeingExamined);
|
SubscribeLocalEvent<BloodstreamComponent, HealthBeingExaminedEvent>(OnHealthBeingExamined);
|
||||||
SubscribeLocalEvent<BloodstreamComponent, BeingGibbedEvent>(OnBeingGibbed);
|
SubscribeLocalEvent<BloodstreamComponent, GibbedBeforeDeletionEvent>(OnBeingGibbed);
|
||||||
SubscribeLocalEvent<BloodstreamComponent, ApplyMetabolicMultiplierEvent>(OnApplyMetabolicMultiplier);
|
SubscribeLocalEvent<BloodstreamComponent, ApplyMetabolicMultiplierEvent>(OnApplyMetabolicMultiplier);
|
||||||
SubscribeLocalEvent<BloodstreamComponent, RejuvenateEvent>(OnRejuvenate);
|
SubscribeLocalEvent<BloodstreamComponent, RejuvenateEvent>(OnRejuvenate);
|
||||||
SubscribeLocalEvent<BloodstreamComponent, MetabolismExclusionEvent>(OnMetabolismExclusion);
|
SubscribeLocalEvent<BloodstreamComponent, MetabolismExclusionEvent>(OnMetabolismExclusion);
|
||||||
|
|
@ -262,7 +263,7 @@ public abstract class SharedBloodstreamSystem : EntitySystem
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnBeingGibbed(Entity<BloodstreamComponent> ent, ref BeingGibbedEvent args)
|
private void OnBeingGibbed(Entity<BloodstreamComponent> ent, ref GibbedBeforeDeletionEvent args)
|
||||||
{
|
{
|
||||||
SpillAllSolutions(ent.AsNullable());
|
SpillAllSolutions(ent.AsNullable());
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,9 +5,7 @@ using Content.Shared.Body.Organ;
|
||||||
using Content.Shared.Body.Part;
|
using Content.Shared.Body.Part;
|
||||||
using Content.Shared.Body.Prototypes;
|
using Content.Shared.Body.Prototypes;
|
||||||
using Content.Shared.DragDrop;
|
using Content.Shared.DragDrop;
|
||||||
using Content.Shared.Gibbing.Components;
|
using Content.Shared.Gibbing;
|
||||||
using Content.Shared.Gibbing.Events;
|
|
||||||
using Content.Shared.Gibbing.Systems;
|
|
||||||
using Content.Shared.Inventory;
|
using Content.Shared.Inventory;
|
||||||
using Robust.Shared.Audio;
|
using Robust.Shared.Audio;
|
||||||
using Robust.Shared.Audio.Systems;
|
using Robust.Shared.Audio.Systems;
|
||||||
|
|
@ -42,7 +40,6 @@ public partial class SharedBodySystem
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// [Dependency] private readonly InventorySystem _inventory = default!; // Shitmed - Declared in SharedBodySystem.cs
|
// [Dependency] private readonly InventorySystem _inventory = default!; // Shitmed - Declared in SharedBodySystem.cs
|
||||||
[Dependency] private readonly GibbingSystem _gibbingSystem = default!;
|
|
||||||
[Dependency] private readonly SharedAudioSystem _audioSystem = default!;
|
[Dependency] private readonly SharedAudioSystem _audioSystem = default!;
|
||||||
[Dependency] private readonly ItemSlotsSystem _slots = default!; // Shitmed Change
|
[Dependency] private readonly ItemSlotsSystem _slots = default!; // Shitmed Change
|
||||||
|
|
||||||
|
|
@ -62,6 +59,8 @@ public partial class SharedBodySystem
|
||||||
SubscribeLocalEvent<BodyComponent, ProfileLoadFinishedEvent>(OnProfileLoadFinished); // Shitmed change
|
SubscribeLocalEvent<BodyComponent, ProfileLoadFinishedEvent>(OnProfileLoadFinished); // Shitmed change
|
||||||
SubscribeLocalEvent<BodyComponent, IsEquippingAttemptEvent>(OnBeingEquippedAttempt); // Shitmed Change
|
SubscribeLocalEvent<BodyComponent, IsEquippingAttemptEvent>(OnBeingEquippedAttempt); // Shitmed Change
|
||||||
|
|
||||||
|
SubscribeLocalEvent<BodyComponent, BeingGibbedEvent>(OnBeingGibbed);
|
||||||
|
SubscribeLocalEvent<BodyPartComponent, BeingGibbedEvent>(OnPartBeingGibbed); // Shitmed Change
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnBodyInserted(Entity<BodyComponent> ent, ref EntInsertedIntoContainerMessage args)
|
private void OnBodyInserted(Entity<BodyComponent> ent, ref EntInsertedIntoContainerMessage args)
|
||||||
|
|
@ -309,153 +308,52 @@ public partial class SharedBodySystem
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public virtual HashSet<EntityUid> GibBody(
|
private void OnBeingGibbed(Entity<BodyComponent> ent, ref BeingGibbedEvent args)
|
||||||
EntityUid bodyId,
|
|
||||||
bool acidify = false,
|
|
||||||
BodyComponent? body = null,
|
|
||||||
bool launchGibs = true,
|
|
||||||
Vector2? splatDirection = null,
|
|
||||||
float splatModifier = 1,
|
|
||||||
Angle splatCone = default,
|
|
||||||
SoundSpecifier? gibSoundOverride = null,
|
|
||||||
// Shitmed Change
|
|
||||||
GibType gib = GibType.Gib,
|
|
||||||
GibContentsOption contents = GibContentsOption.Drop)
|
|
||||||
{
|
{
|
||||||
var gibs = new HashSet<EntityUid>();
|
var parts = GetBodyChildren(ent, ent).ToArray();
|
||||||
|
args.Giblets.EnsureCapacity(args.Giblets.Capacity + parts.Length);
|
||||||
if (!Resolve(bodyId, ref body, logMissing: false))
|
|
||||||
return gibs;
|
|
||||||
|
|
||||||
var root = GetRootPartOrNull(bodyId, body);
|
|
||||||
if (root != null && TryComp(root.Value.Entity, out GibbableComponent? gibbable))
|
|
||||||
{
|
|
||||||
gibSoundOverride ??= gibbable.GibSound;
|
|
||||||
}
|
|
||||||
var parts = GetBodyChildren(bodyId, body).ToArray();
|
|
||||||
gibs.EnsureCapacity(parts.Length);
|
|
||||||
foreach (var part in parts)
|
foreach (var part in parts)
|
||||||
{
|
{
|
||||||
|
|
||||||
_gibbingSystem.TryGibEntityWithRef(bodyId, part.Id, gib, contents, ref gibs, // Shitmed Change
|
|
||||||
playAudio: false, launchGibs: true, launchDirection: splatDirection, launchImpulse: GibletLaunchImpulse * splatModifier,
|
|
||||||
launchImpulseVariance: GibletLaunchImpulseVariance, launchCone: splatCone);
|
|
||||||
|
|
||||||
if (!acidify)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
foreach (var organ in GetPartOrgans(part.Id, part.Component))
|
foreach (var organ in GetPartOrgans(part.Id, part.Component))
|
||||||
{
|
{
|
||||||
_gibbingSystem.TryGibEntityWithRef(bodyId, organ.Id, GibType.Drop, GibContentsOption.Skip,
|
args.Giblets.Add(organ.Id);
|
||||||
ref gibs, playAudio: false, launchImpulse: GibletLaunchImpulse * splatModifier,
|
|
||||||
launchImpulseVariance:GibletLaunchImpulseVariance, launchCone: splatCone);
|
|
||||||
}
|
}
|
||||||
|
PredictedQueueDel(part.Id);
|
||||||
}
|
}
|
||||||
|
|
||||||
var bodyTransform = Transform(bodyId);
|
foreach (var item in _inventory.GetHandOrInventoryEntities(ent.Owner))
|
||||||
_audioSystem.PlayPredicted(gibSoundOverride, bodyTransform.Coordinates, null);
|
|
||||||
|
|
||||||
// Begin DeltaV Additions
|
|
||||||
var ev = new BodyGibbedEvent(gibs);
|
|
||||||
RaiseLocalEvent(bodyId, ref ev);
|
|
||||||
// End DeltaV Additions
|
|
||||||
|
|
||||||
if (acidify)
|
|
||||||
return gibs;
|
|
||||||
|
|
||||||
if (TryComp<InventoryComponent>(bodyId, out var inventory))
|
|
||||||
{
|
{
|
||||||
foreach (var item in _inventory.GetHandOrInventoryEntities(bodyId))
|
args.Giblets.Add(item);
|
||||||
{
|
|
||||||
SharedTransform.DropNextTo(item, (bodyId, bodyTransform));
|
|
||||||
gibs.Add(item);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return gibs;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Shitmed Change Start
|
// Shitmed Change Start
|
||||||
|
private void OnPartBeingGibbed(Entity<BodyPartComponent> part, ref BeingGibbedEvent args)
|
||||||
public virtual HashSet<EntityUid> GibPart(
|
|
||||||
EntityUid partId,
|
|
||||||
BodyPartComponent? part = null,
|
|
||||||
bool launchGibs = true,
|
|
||||||
Vector2? splatDirection = null,
|
|
||||||
float splatModifier = 1,
|
|
||||||
Angle splatCone = default,
|
|
||||||
SoundSpecifier? gibSoundOverride = null)
|
|
||||||
{
|
{
|
||||||
var gibs = new HashSet<EntityUid>();
|
if (part.Comp.Body is { } bodyEnt)
|
||||||
|
|
||||||
if (!Resolve(partId, ref part, logMissing: false))
|
|
||||||
return gibs;
|
|
||||||
|
|
||||||
if (part.Body is { } bodyEnt)
|
|
||||||
{
|
{
|
||||||
if (IsPartRoot(bodyEnt, partId, part: part) || !part.CanSever)
|
if (IsPartRoot(bodyEnt, part, part: part) || !part.Comp.CanSever)
|
||||||
return gibs;
|
return;
|
||||||
|
|
||||||
DropSlotContents((partId, part));
|
DropSlotContents(part);
|
||||||
RemovePartChildren((partId, part), bodyEnt);
|
RemovePartChildren(part, bodyEnt);
|
||||||
foreach (var organ in GetPartOrgans(partId, part))
|
|
||||||
|
var organs = GetPartOrgans(part, part).ToArray();
|
||||||
|
args.Giblets.EnsureCapacity(args.Giblets.Capacity + organs.Length);
|
||||||
|
foreach (var organ in organs)
|
||||||
{
|
{
|
||||||
_gibbingSystem.TryGibEntityWithRef(bodyEnt, organ.Id, GibType.Drop, GibContentsOption.Skip,
|
args.Giblets.Add(organ.Id);
|
||||||
ref gibs, playAudio: false, launchImpulse: GibletLaunchImpulse * splatModifier,
|
|
||||||
launchImpulseVariance: GibletLaunchImpulseVariance, launchCone: splatCone);
|
|
||||||
}
|
}
|
||||||
var ev = new BodyPartDroppedEvent((partId, part));
|
|
||||||
|
var ev = new BodyPartDroppedEvent(part);
|
||||||
RaiseLocalEvent(bodyEnt, ref ev);
|
RaiseLocalEvent(bodyEnt, ref ev);
|
||||||
}
|
}
|
||||||
|
|
||||||
_gibbingSystem.TryGibEntityWithRef(partId, partId, GibType.Gib, GibContentsOption.Drop, ref gibs,
|
foreach (var item in _inventory.GetHandOrInventoryEntities(part.Owner))
|
||||||
playAudio: true, launchGibs: true, launchDirection: splatDirection, launchImpulse: GibletLaunchImpulse * splatModifier,
|
|
||||||
launchImpulseVariance: GibletLaunchImpulseVariance, launchCone: splatCone);
|
|
||||||
|
|
||||||
|
|
||||||
if (HasComp<InventoryComponent>(partId))
|
|
||||||
{
|
{
|
||||||
foreach (var item in _inventory.GetHandOrInventoryEntities(partId))
|
args.Giblets.Add(item);
|
||||||
{
|
|
||||||
SharedTransform.AttachToGridOrMap(item);
|
|
||||||
gibs.Add(item);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_audioSystem.PlayPredicted(gibSoundOverride, Transform(partId).Coordinates, null);
|
|
||||||
return gibs;
|
|
||||||
}
|
|
||||||
|
|
||||||
public virtual bool BurnPart(EntityUid partId,
|
|
||||||
BodyPartComponent? part = null)
|
|
||||||
{
|
|
||||||
if (!Resolve(partId, ref part, logMissing: false))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if (part.Body is { } bodyEnt)
|
|
||||||
{
|
|
||||||
if (IsPartRoot(bodyEnt, partId, part: part))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
var gibs = new HashSet<EntityUid>();
|
|
||||||
// Todo: Kill this in favor of husking.
|
|
||||||
DropSlotContents((partId, part));
|
|
||||||
RemovePartChildren((partId, part), bodyEnt);
|
|
||||||
foreach (var organ in GetPartOrgans(partId, part))
|
|
||||||
_gibbingSystem.TryGibEntityWithRef(bodyEnt, organ.Id, GibType.Drop, GibContentsOption.Skip,
|
|
||||||
ref gibs, playAudio: false, launchImpulse: GibletLaunchImpulse, launchImpulseVariance: GibletLaunchImpulseVariance);
|
|
||||||
|
|
||||||
_gibbingSystem.TryGibEntityWithRef(partId, partId, GibType.Gib, GibContentsOption.Gib, ref gibs,
|
|
||||||
playAudio: false, launchGibs: true, launchImpulse: GibletLaunchImpulse, launchImpulseVariance: GibletLaunchImpulseVariance);
|
|
||||||
|
|
||||||
if (HasComp<InventoryComponent>(partId))
|
|
||||||
foreach (var item in _inventory.GetHandOrInventoryEntities(partId))
|
|
||||||
SharedTransform.AttachToGridOrMap(item);
|
|
||||||
|
|
||||||
QueueDel(partId);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnProfileLoadFinished(EntityUid uid, BodyComponent component, ProfileLoadFinishedEvent args)
|
private void OnProfileLoadFinished(EntityUid uid, BodyComponent component, ProfileLoadFinishedEvent args)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,10 @@
|
||||||
using Content.Shared._Goobstation.Devour;
|
using Content.Shared._Goobstation.Devour;
|
||||||
using Content.Shared.Actions;
|
using Content.Shared.Actions;
|
||||||
using Content.Shared.Body.Events;
|
|
||||||
using Content.Shared.Body.Systems;
|
using Content.Shared.Body.Systems;
|
||||||
using Content.Shared.Chemistry.Components;
|
using Content.Shared.Chemistry.Components;
|
||||||
using Content.Shared.Devour.Components;
|
using Content.Shared.Devour.Components;
|
||||||
using Content.Shared.DoAfter;
|
using Content.Shared.DoAfter;
|
||||||
|
using Content.Shared.Gibbing;
|
||||||
using Content.Shared.Mobs;
|
using Content.Shared.Mobs;
|
||||||
using Content.Shared.Mobs.Components;
|
using Content.Shared.Mobs.Components;
|
||||||
using Content.Shared.Popups;
|
using Content.Shared.Popups;
|
||||||
|
|
@ -34,7 +34,7 @@ public sealed class DevourSystem : EntitySystem
|
||||||
SubscribeLocalEvent<DevourerComponent, ComponentShutdown>(OnShutdown);
|
SubscribeLocalEvent<DevourerComponent, ComponentShutdown>(OnShutdown);
|
||||||
SubscribeLocalEvent<DevourerComponent, DevourActionEvent>(OnDevourAction);
|
SubscribeLocalEvent<DevourerComponent, DevourActionEvent>(OnDevourAction);
|
||||||
SubscribeLocalEvent<DevourerComponent, DevourDoAfterEvent>(OnDoAfter);
|
SubscribeLocalEvent<DevourerComponent, DevourDoAfterEvent>(OnDoAfter);
|
||||||
SubscribeLocalEvent<DevourerComponent, BeingGibbedEvent>(OnGibContents);
|
SubscribeLocalEvent<DevourerComponent, GibbedBeforeDeletionEvent>(OnGibContents);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnStartup(Entity<DevourerComponent> ent, ref ComponentStartup args)
|
private void OnStartup(Entity<DevourerComponent> ent, ref ComponentStartup args)
|
||||||
|
|
@ -135,13 +135,11 @@ public sealed class DevourSystem : EntitySystem
|
||||||
_audioSystem.PlayPredicted(ent.Comp.SoundDevour, ent.Owner, ent.Owner);
|
_audioSystem.PlayPredicted(ent.Comp.SoundDevour, ent.Owner, ent.Owner);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnGibContents(Entity<DevourerComponent> ent, ref BeingGibbedEvent args)
|
private void OnGibContents(Entity<DevourerComponent> ent, ref GibbedBeforeDeletionEvent args)
|
||||||
{
|
{
|
||||||
if (ent.Comp.StomachStorageWhitelist == null)
|
if (ent.Comp.StomachStorageWhitelist == null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// For some reason we have two different systems that should handle gibbing,
|
|
||||||
// and for some another reason GibbingSystem, which should empty all containers, doesn't get involved in this process
|
|
||||||
_containerSystem.EmptyContainer(ent.Comp.Stomach);
|
_containerSystem.EmptyContainer(ent.Comp.Stomach);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,34 +0,0 @@
|
||||||
using Content.Shared.Gibbing.Systems;
|
|
||||||
using Robust.Shared.Audio;
|
|
||||||
using Robust.Shared.GameStates;
|
|
||||||
using Robust.Shared.Prototypes;
|
|
||||||
|
|
||||||
namespace Content.Shared.Gibbing.Components;
|
|
||||||
|
|
||||||
[RegisterComponent, NetworkedComponent, AutoGenerateComponentState, Access(typeof(GibbingSystem))]
|
|
||||||
public sealed partial class GibbableComponent : Component
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Giblet entity prototypes to randomly select from when spawning additional giblets
|
|
||||||
/// </summary>
|
|
||||||
[DataField, AutoNetworkedField]
|
|
||||||
public List<EntProtoId> GibPrototypes = new();
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Number of giblet entities to spawn in addition to entity contents
|
|
||||||
/// </summary>
|
|
||||||
[DataField, AutoNetworkedField]
|
|
||||||
public int GibCount;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Sound to be played when this entity is gibbed, only played when playsound is true on the gibbing function
|
|
||||||
/// </summary>
|
|
||||||
[DataField, AutoNetworkedField]
|
|
||||||
public SoundSpecifier? GibSound = new SoundCollectionSpecifier("gib", AudioParams.Default.WithVariation(0.025f));
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Max distance giblets can be dropped from an entity when NOT using physics-based scattering
|
|
||||||
/// </summary>
|
|
||||||
[DataField, AutoNetworkedField]
|
|
||||||
public float GibScatterRange = 0.3f;
|
|
||||||
}
|
|
||||||
|
|
@ -1,50 +0,0 @@
|
||||||
using Robust.Shared.Serialization;
|
|
||||||
|
|
||||||
namespace Content.Shared.Gibbing.Events;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Called just before we actually gib the target entity
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="Target">The entity being gibed</param>
|
|
||||||
/// <param name="GibType">What type of gibbing is occuring</param>
|
|
||||||
/// <param name="AllowedContainers">Containers we are allow to gib</param>
|
|
||||||
/// <param name="ExcludedContainers">Containers we are allow not allowed to gib</param>
|
|
||||||
[ByRefEvent] public record struct AttemptEntityContentsGibEvent(
|
|
||||||
EntityUid Target,
|
|
||||||
GibContentsOption GibType,
|
|
||||||
List<string>? AllowedContainers,
|
|
||||||
List<string>? ExcludedContainers
|
|
||||||
);
|
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Called just before we actually gib the target entity
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="Target">The entity being gibed</param>
|
|
||||||
/// <param name="GibletCount">how many giblets to spawn</param>
|
|
||||||
/// <param name="GibType">What type of gibbing is occuring</param>
|
|
||||||
[ByRefEvent] public record struct AttemptEntityGibEvent(EntityUid Target, int GibletCount, GibType GibType);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Called immediately after we gib the target entity
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="Target">The entity being gibbed</param>
|
|
||||||
/// <param name="DroppedEntities">Any entities that are spilled out (if any)</param>
|
|
||||||
[ByRefEvent] public record struct EntityGibbedEvent(EntityUid Target, List<EntityUid> DroppedEntities);
|
|
||||||
|
|
||||||
[Serializable, NetSerializable]
|
|
||||||
public enum GibType : byte
|
|
||||||
{
|
|
||||||
Skip,
|
|
||||||
Drop,
|
|
||||||
Gib,
|
|
||||||
}
|
|
||||||
|
|
||||||
public enum GibContentsOption : byte
|
|
||||||
{
|
|
||||||
Skip,
|
|
||||||
Drop,
|
|
||||||
Gib
|
|
||||||
}
|
|
||||||
|
|
@ -0,0 +1,84 @@
|
||||||
|
using Content.Shared.Destructible;
|
||||||
|
using Robust.Shared.Audio.Systems;
|
||||||
|
using Robust.Shared.Audio;
|
||||||
|
using Robust.Shared.Network;
|
||||||
|
using Robust.Shared.Physics.Systems;
|
||||||
|
using Robust.Shared.Random;
|
||||||
|
|
||||||
|
namespace Content.Shared.Gibbing;
|
||||||
|
|
||||||
|
public sealed class GibbingSystem : EntitySystem
|
||||||
|
{
|
||||||
|
[Dependency] private readonly INetManager _net = default!;
|
||||||
|
[Dependency] private readonly IRobustRandom _random = default!;
|
||||||
|
[Dependency] private readonly SharedAudioSystem _audio = default!;
|
||||||
|
[Dependency] private readonly SharedDestructibleSystem _destructible = default!;
|
||||||
|
[Dependency] private readonly SharedPhysicsSystem _physics = default!;
|
||||||
|
[Dependency] private readonly SharedTransformSystem _transform = default!;
|
||||||
|
|
||||||
|
private static readonly SoundSpecifier? GibSound = new SoundCollectionSpecifier("gib", AudioParams.Default.WithVariation(0.025f));
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gibs an entity.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="ent">The entity to gib.</param>
|
||||||
|
/// <param name="dropGiblets">Whether or not to drop giblets.</param>
|
||||||
|
/// <param name="user">The user gibbing the entity, if any.</param>
|
||||||
|
/// <returns>The set of giblets for this entity, if any.</returns>
|
||||||
|
public HashSet<EntityUid> Gib(EntityUid ent, bool dropGiblets = true, EntityUid? user = null)
|
||||||
|
{
|
||||||
|
// user is unused because of prediction woes, eventually it'll be used for audio
|
||||||
|
|
||||||
|
// BodySystem handles prediction rather poorly and causes client-sided bugs when we gib on the client
|
||||||
|
// This guard can be removed once it is gone and replaced by a prediction-safe system.
|
||||||
|
if (!_net.IsServer)
|
||||||
|
return new();
|
||||||
|
|
||||||
|
if (!_destructible.DestroyEntity(ent))
|
||||||
|
return new();
|
||||||
|
|
||||||
|
_audio.PlayPvs(GibSound, ent);
|
||||||
|
|
||||||
|
var gibbed = new HashSet<EntityUid>();
|
||||||
|
var beingGibbed = new BeingGibbedEvent(gibbed);
|
||||||
|
RaiseLocalEvent(ent, ref beingGibbed);
|
||||||
|
|
||||||
|
if (dropGiblets)
|
||||||
|
{
|
||||||
|
foreach (var giblet in gibbed)
|
||||||
|
{
|
||||||
|
_transform.DropNextTo(giblet, ent);
|
||||||
|
FlingDroppedEntity(giblet);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var beforeDeletion = new GibbedBeforeDeletionEvent(gibbed);
|
||||||
|
RaiseLocalEvent(ent, ref beforeDeletion);
|
||||||
|
|
||||||
|
return gibbed;
|
||||||
|
}
|
||||||
|
|
||||||
|
private const float GibletLaunchImpulse = 8;
|
||||||
|
private const float GibletLaunchImpulseVariance = 3;
|
||||||
|
|
||||||
|
private void FlingDroppedEntity(EntityUid target)
|
||||||
|
{
|
||||||
|
var impulse = GibletLaunchImpulse + _random.NextFloat(GibletLaunchImpulseVariance);
|
||||||
|
var scatterVec = _random.NextAngle().ToVec() * impulse;
|
||||||
|
_physics.ApplyLinearImpulse(target, scatterVec);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Raised on an entity when it is being gibbed.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="Giblets">If a component wants to provide giblets to scatter, add them to this hashset.</param>
|
||||||
|
[ByRefEvent]
|
||||||
|
public readonly record struct BeingGibbedEvent(HashSet<EntityUid> Giblets);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Raised on an entity when it is about to be deleted after being gibbed.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="Giblets">The set of giblets this entity produced.</param>
|
||||||
|
[ByRefEvent]
|
||||||
|
public readonly record struct GibbedBeforeDeletionEvent(HashSet<EntityUid> Giblets);
|
||||||
|
|
@ -1,344 +0,0 @@
|
||||||
using System.Diagnostics.CodeAnalysis;
|
|
||||||
using System.Numerics;
|
|
||||||
using Content.Shared.Gibbing.Components;
|
|
||||||
using Content.Shared.Gibbing.Events;
|
|
||||||
using Robust.Shared.Audio.Systems;
|
|
||||||
using Robust.Shared.Containers;
|
|
||||||
using Robust.Shared.Map;
|
|
||||||
using Robust.Shared.Physics.Systems;
|
|
||||||
using Robust.Shared.Prototypes;
|
|
||||||
using Robust.Shared.Random;
|
|
||||||
|
|
||||||
namespace Content.Shared.Gibbing.Systems;
|
|
||||||
|
|
||||||
public sealed class GibbingSystem : EntitySystem
|
|
||||||
{
|
|
||||||
[Dependency] private readonly SharedContainerSystem _containerSystem = default!;
|
|
||||||
[Dependency] private readonly SharedTransformSystem _transformSystem = default!;
|
|
||||||
[Dependency] private readonly SharedAudioSystem _audioSystem = default!;
|
|
||||||
[Dependency] private readonly SharedPhysicsSystem _physicsSystem = default!;
|
|
||||||
[Dependency] private readonly IRobustRandom _random = default!;
|
|
||||||
|
|
||||||
//TODO: (future optimization) implement a system that "caps" giblet entities by deleting the oldest ones once we reach a certain limit, customizable via CVAR
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Attempt to gib a specified entity. That entity must have a gibable components. This method is NOT recursive will only
|
|
||||||
/// work on the target and any entities it contains (depending on gibContentsOption)
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="outerEntity">The outermost entity we care about, used to place the dropped items</param>
|
|
||||||
/// <param name="gibbable">Target entity/comp we wish to gib</param>
|
|
||||||
/// <param name="gibType">What type of gibing are we performing</param>
|
|
||||||
/// <param name="gibContentsOption">What type of gibing do we perform on any container contents?</param>
|
|
||||||
/// <param name="droppedEntities">a hashset containing all the entities that have been dropped/created</param>
|
|
||||||
/// <param name="randomSpreadMod">How much to multiply the random spread on dropped giblets(if we are dropping them!)</param>
|
|
||||||
/// <param name="playAudio">Should we play audio</param>
|
|
||||||
/// <param name="allowedContainers">A list of containerIds on the target that permit gibing</param>
|
|
||||||
/// <param name="excludedContainers">A list of containerIds on the target that DO NOT permit gibing</param>
|
|
||||||
/// <param name="launchCone">The cone we are launching giblets in (if we are launching them!)</param>
|
|
||||||
/// <param name="launchGibs">Should we launch giblets or just drop them</param>
|
|
||||||
/// <param name="launchDirection">The direction to launch giblets (if we are launching them!)</param>
|
|
||||||
/// <param name="launchImpulse">The impluse to launch giblets at(if we are launching them!)</param>
|
|
||||||
/// /// <param name="logMissingGibable">Should we log if we are missing a gibbableComp when we call this function</param>
|
|
||||||
/// <param name="launchImpulseVariance">The variation in giblet launch impulse (if we are launching them!)</param>
|
|
||||||
/// <returns>True if successful, false if not</returns>
|
|
||||||
public bool TryGibEntity(Entity<TransformComponent?> outerEntity, Entity<GibbableComponent?> gibbable, GibType gibType,
|
|
||||||
GibContentsOption gibContentsOption,
|
|
||||||
out HashSet<EntityUid> droppedEntities, bool launchGibs = true,
|
|
||||||
Vector2 launchDirection = default, float launchImpulse = 0f, float launchImpulseVariance = 0f,
|
|
||||||
Angle launchCone = default,
|
|
||||||
float randomSpreadMod = 1.0f, bool playAudio = true, List<string>? allowedContainers = null,
|
|
||||||
List<string>? excludedContainers = null, bool logMissingGibable = false)
|
|
||||||
{
|
|
||||||
droppedEntities = new();
|
|
||||||
return TryGibEntityWithRef(outerEntity, gibbable, gibType, gibContentsOption, ref droppedEntities,
|
|
||||||
launchGibs, launchDirection, launchImpulse, launchImpulseVariance, launchCone, randomSpreadMod, playAudio,
|
|
||||||
allowedContainers, excludedContainers, logMissingGibable);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Attempt to gib a specified entity. That entity must have a gibable components. This method is NOT recursive will only
|
|
||||||
/// work on the target and any entities it contains (depending on gibContentsOption)
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="outerEntity">The outermost entity we care about, used to place the dropped items</param>
|
|
||||||
/// <param name="gibbable">Target entity/comp we wish to gib</param>
|
|
||||||
/// <param name="gibType">What type of gibing are we performing</param>
|
|
||||||
/// <param name="gibContentsOption">What type of gibing do we perform on any container contents?</param>
|
|
||||||
/// <param name="droppedEntities">a hashset containing all the entities that have been dropped/created</param>
|
|
||||||
/// <param name="randomSpreadMod">How much to multiply the random spread on dropped giblets(if we are dropping them!)</param>
|
|
||||||
/// <param name="playAudio">Should we play audio</param>
|
|
||||||
/// <param name="allowedContainers">A list of containerIds on the target that permit gibing</param>
|
|
||||||
/// <param name="excludedContainers">A list of containerIds on the target that DO NOT permit gibing</param>
|
|
||||||
/// <param name="launchCone">The cone we are launching giblets in (if we are launching them!)</param>
|
|
||||||
/// <param name="launchGibs">Should we launch giblets or just drop them</param>
|
|
||||||
/// <param name="launchDirection">The direction to launch giblets (if we are launching them!)</param>
|
|
||||||
/// <param name="launchImpulse">The impluse to launch giblets at(if we are launching them!)</param>
|
|
||||||
/// <param name="launchImpulseVariance">The variation in giblet launch impulse (if we are launching them!)</param>
|
|
||||||
/// <param name="logMissingGibable">Should we log if we are missing a gibbableComp when we call this function</param>
|
|
||||||
/// <returns>True if successful, false if not</returns>
|
|
||||||
public bool TryGibEntityWithRef(
|
|
||||||
Entity<TransformComponent?> outerEntity,
|
|
||||||
Entity<GibbableComponent?> gibbable,
|
|
||||||
GibType gibType,
|
|
||||||
GibContentsOption gibContentsOption,
|
|
||||||
ref HashSet<EntityUid> droppedEntities,
|
|
||||||
bool launchGibs = true,
|
|
||||||
Vector2? launchDirection = null,
|
|
||||||
float launchImpulse = 0f,
|
|
||||||
float launchImpulseVariance = 0f,
|
|
||||||
Angle launchCone = default,
|
|
||||||
float randomSpreadMod = 1.0f,
|
|
||||||
bool playAudio = true,
|
|
||||||
List<string>? allowedContainers = null,
|
|
||||||
List<string>? excludedContainers = null,
|
|
||||||
bool logMissingGibable = false)
|
|
||||||
{
|
|
||||||
if (!Resolve(gibbable, ref gibbable.Comp, logMissing: false))
|
|
||||||
{
|
|
||||||
DropEntity(gibbable, (outerEntity, Transform(outerEntity)), randomSpreadMod, ref droppedEntities,
|
|
||||||
launchGibs, launchDirection, launchImpulse, launchImpulseVariance, launchCone);
|
|
||||||
if (logMissingGibable)
|
|
||||||
{
|
|
||||||
Log.Warning($"{ToPrettyString(gibbable)} does not have a GibbableComponent! " +
|
|
||||||
$"This is not required but may cause issues contained items to not be dropped.");
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (gibType == GibType.Skip && gibContentsOption == GibContentsOption.Skip)
|
|
||||||
return true;
|
|
||||||
if (launchGibs)
|
|
||||||
{
|
|
||||||
randomSpreadMod = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
HashSet<BaseContainer> validContainers = new();
|
|
||||||
var gibContentsAttempt =
|
|
||||||
new AttemptEntityContentsGibEvent(gibbable, gibContentsOption, allowedContainers, excludedContainers);
|
|
||||||
RaiseLocalEvent(gibbable, ref gibContentsAttempt);
|
|
||||||
|
|
||||||
foreach (var container in _containerSystem.GetAllContainers(gibbable))
|
|
||||||
{
|
|
||||||
var valid = true;
|
|
||||||
if (allowedContainers != null)
|
|
||||||
valid = allowedContainers.Contains(container.ID);
|
|
||||||
if (excludedContainers != null)
|
|
||||||
valid = valid && !excludedContainers.Contains(container.ID);
|
|
||||||
if (valid)
|
|
||||||
validContainers.Add(container);
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (gibContentsOption)
|
|
||||||
{
|
|
||||||
case GibContentsOption.Skip:
|
|
||||||
break;
|
|
||||||
case GibContentsOption.Drop:
|
|
||||||
{
|
|
||||||
foreach (var container in validContainers)
|
|
||||||
{
|
|
||||||
foreach (var ent in container.ContainedEntities)
|
|
||||||
{
|
|
||||||
DropEntity(new Entity<GibbableComponent?>(ent, null), outerEntity, randomSpreadMod,
|
|
||||||
ref droppedEntities, launchGibs,
|
|
||||||
launchDirection, launchImpulse, launchImpulseVariance, launchCone);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case GibContentsOption.Gib:
|
|
||||||
{
|
|
||||||
foreach (var container in validContainers)
|
|
||||||
{
|
|
||||||
foreach (var ent in container.ContainedEntities)
|
|
||||||
{
|
|
||||||
GibEntity(new Entity<GibbableComponent?>(ent, null), outerEntity, randomSpreadMod,
|
|
||||||
ref droppedEntities, launchGibs,
|
|
||||||
launchDirection, launchImpulse, launchImpulseVariance, launchCone);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (gibType)
|
|
||||||
{
|
|
||||||
case GibType.Skip:
|
|
||||||
break;
|
|
||||||
case GibType.Drop:
|
|
||||||
{
|
|
||||||
DropEntity(gibbable, outerEntity, randomSpreadMod, ref droppedEntities, launchGibs,
|
|
||||||
launchDirection, launchImpulse, launchImpulseVariance, launchCone);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case GibType.Gib:
|
|
||||||
{
|
|
||||||
GibEntity(gibbable, outerEntity, randomSpreadMod, ref droppedEntities, launchGibs,
|
|
||||||
launchDirection, launchImpulse, launchImpulseVariance, launchCone);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (playAudio)
|
|
||||||
{
|
|
||||||
_audioSystem.PlayPredicted(gibbable.Comp.GibSound, outerEntity, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (gibType == GibType.Gib)
|
|
||||||
PredictedQueueDel(gibbable.Owner);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void DropEntity(Entity<GibbableComponent?> gibbable, Entity<TransformComponent?> parent, float randomSpreadMod,
|
|
||||||
ref HashSet<EntityUid> droppedEntities, bool flingEntity, Vector2? scatterDirection, float scatterImpulse,
|
|
||||||
float scatterImpulseVariance, Angle scatterCone)
|
|
||||||
{
|
|
||||||
var gibCount = 0;
|
|
||||||
if (Resolve(gibbable, ref gibbable.Comp, logMissing: false))
|
|
||||||
{
|
|
||||||
gibCount = gibbable.Comp.GibCount;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!Resolve(parent, ref parent.Comp, logMissing: false))
|
|
||||||
return;
|
|
||||||
|
|
||||||
var gibAttemptEvent = new AttemptEntityGibEvent(gibbable, gibCount, GibType.Drop);
|
|
||||||
RaiseLocalEvent(gibbable, ref gibAttemptEvent);
|
|
||||||
switch (gibAttemptEvent.GibType)
|
|
||||||
{
|
|
||||||
case GibType.Skip:
|
|
||||||
return;
|
|
||||||
case GibType.Gib:
|
|
||||||
GibEntity(gibbable, parent, randomSpreadMod, ref droppedEntities, flingEntity, scatterDirection,
|
|
||||||
scatterImpulse, scatterImpulseVariance, scatterCone, deleteTarget: false);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
_transformSystem.DropNextTo(gibbable.Owner, parent);
|
|
||||||
_transformSystem.SetWorldRotation(gibbable, _random.NextAngle());
|
|
||||||
droppedEntities.Add(gibbable);
|
|
||||||
if (flingEntity)
|
|
||||||
{
|
|
||||||
FlingDroppedEntity(gibbable, scatterDirection, scatterImpulse, scatterImpulseVariance, scatterCone);
|
|
||||||
}
|
|
||||||
|
|
||||||
var gibbedEvent = new EntityGibbedEvent(gibbable, new List<EntityUid> {gibbable});
|
|
||||||
RaiseLocalEvent(gibbable, ref gibbedEvent);
|
|
||||||
}
|
|
||||||
|
|
||||||
private List<EntityUid> GibEntity(Entity<GibbableComponent?> gibbable, Entity<TransformComponent?> parent,
|
|
||||||
float randomSpreadMod,
|
|
||||||
ref HashSet<EntityUid> droppedEntities, bool flingEntity, Vector2? scatterDirection, float scatterImpulse,
|
|
||||||
float scatterImpulseVariance, Angle scatterCone, bool deleteTarget = true)
|
|
||||||
{
|
|
||||||
var localGibs = new List<EntityUid>();
|
|
||||||
var gibCount = 0;
|
|
||||||
var gibProtoCount = 0;
|
|
||||||
if (Resolve(gibbable, ref gibbable.Comp, logMissing: false))
|
|
||||||
{
|
|
||||||
gibCount = gibbable.Comp.GibCount;
|
|
||||||
gibProtoCount = gibbable.Comp.GibPrototypes.Count;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!Resolve(parent, ref parent.Comp, logMissing: false))
|
|
||||||
return [];
|
|
||||||
|
|
||||||
var gibAttemptEvent = new AttemptEntityGibEvent(gibbable, gibCount, GibType.Drop);
|
|
||||||
RaiseLocalEvent(gibbable, ref gibAttemptEvent);
|
|
||||||
switch (gibAttemptEvent.GibType)
|
|
||||||
{
|
|
||||||
case GibType.Skip:
|
|
||||||
return localGibs;
|
|
||||||
case GibType.Drop:
|
|
||||||
DropEntity(gibbable, parent, randomSpreadMod, ref droppedEntities, flingEntity,
|
|
||||||
scatterDirection, scatterImpulse, scatterImpulseVariance, scatterCone);
|
|
||||||
localGibs.Add(gibbable);
|
|
||||||
return localGibs;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (gibbable.Comp != null && gibProtoCount > 0)
|
|
||||||
{
|
|
||||||
if (flingEntity)
|
|
||||||
{
|
|
||||||
for (var i = 0; i < gibAttemptEvent.GibletCount; i++)
|
|
||||||
{
|
|
||||||
if (!TryCreateRandomGiblet(gibbable.Comp, parent.Comp.Coordinates, false, out var giblet,
|
|
||||||
randomSpreadMod))
|
|
||||||
continue;
|
|
||||||
FlingDroppedEntity(giblet.Value, scatterDirection, scatterImpulse, scatterImpulseVariance,
|
|
||||||
scatterCone);
|
|
||||||
droppedEntities.Add(giblet.Value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
for (var i = 0; i < gibAttemptEvent.GibletCount; i++)
|
|
||||||
{
|
|
||||||
if (TryCreateRandomGiblet(gibbable.Comp, parent.Comp.Coordinates, false, out var giblet,
|
|
||||||
randomSpreadMod))
|
|
||||||
droppedEntities.Add(giblet.Value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
_transformSystem.AttachToGridOrMap(gibbable, Transform(gibbable));
|
|
||||||
if (flingEntity)
|
|
||||||
{
|
|
||||||
FlingDroppedEntity(gibbable, scatterDirection, scatterImpulse, scatterImpulseVariance, scatterCone);
|
|
||||||
}
|
|
||||||
|
|
||||||
var gibbedEvent = new EntityGibbedEvent(gibbable, localGibs);
|
|
||||||
RaiseLocalEvent(gibbable, ref gibbedEvent);
|
|
||||||
if (deleteTarget)
|
|
||||||
PredictedQueueDel(gibbable.Owner);
|
|
||||||
return localGibs;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public bool TryCreateRandomGiblet(Entity<GibbableComponent?> gibbable, [NotNullWhen(true)] out EntityUid? gibletEntity,
|
|
||||||
float randomSpreadModifier = 1.0f, bool playSound = true)
|
|
||||||
{
|
|
||||||
gibletEntity = null;
|
|
||||||
return Resolve(gibbable, ref gibbable.Comp) && TryCreateRandomGiblet(gibbable.Comp, Transform(gibbable).Coordinates,
|
|
||||||
playSound, out gibletEntity, randomSpreadModifier);
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool TryCreateAndFlingRandomGiblet(Entity<GibbableComponent?> gibbable, [NotNullWhen(true)] out EntityUid? gibletEntity,
|
|
||||||
Vector2 scatterDirection, float force, float scatterImpulseVariance, Angle scatterCone = default,
|
|
||||||
bool playSound = true)
|
|
||||||
{
|
|
||||||
gibletEntity = null;
|
|
||||||
if (!Resolve(gibbable, ref gibbable.Comp) ||
|
|
||||||
!TryCreateRandomGiblet(gibbable.Comp, Transform(gibbable).Coordinates, playSound, out gibletEntity))
|
|
||||||
return false;
|
|
||||||
FlingDroppedEntity(gibletEntity.Value, scatterDirection, force, scatterImpulseVariance, scatterCone);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void FlingDroppedEntity(EntityUid target, Vector2? direction, float impulse, float impulseVariance,
|
|
||||||
Angle scatterConeAngle)
|
|
||||||
{
|
|
||||||
var scatterAngle = direction?.ToAngle() ?? _random.NextAngle();
|
|
||||||
var scatterVector = _random.NextAngle(scatterAngle - scatterConeAngle / 2, scatterAngle + scatterConeAngle / 2)
|
|
||||||
.ToVec() * (impulse + _random.NextFloat(impulseVariance));
|
|
||||||
_physicsSystem.ApplyLinearImpulse(target, scatterVector);
|
|
||||||
}
|
|
||||||
|
|
||||||
private bool TryCreateRandomGiblet(GibbableComponent gibbable, EntityCoordinates coords,
|
|
||||||
bool playSound, [NotNullWhen(true)] out EntityUid? gibletEntity, float? randomSpreadModifier = null)
|
|
||||||
{
|
|
||||||
gibletEntity = null;
|
|
||||||
if (gibbable.GibPrototypes.Count == 0)
|
|
||||||
return false;
|
|
||||||
gibletEntity = Spawn(gibbable.GibPrototypes[_random.Next(0, gibbable.GibPrototypes.Count)],
|
|
||||||
randomSpreadModifier == null
|
|
||||||
? coords
|
|
||||||
: coords.Offset(_random.NextVector2(gibbable.GibScatterRange * randomSpreadModifier.Value)));
|
|
||||||
if (playSound)
|
|
||||||
_audioSystem.PlayPredicted(gibbable.GibSound, coords, null);
|
|
||||||
_transformSystem.SetWorldRotation(gibletEntity.Value, _random.NextAngle());
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,12 +1,12 @@
|
||||||
using Content.Shared.Administration.Logs;
|
using Content.Shared.Administration.Logs;
|
||||||
using Content.Shared.Body.Part; // DeltaV
|
using Content.Shared.Body.Part; // DeltaV
|
||||||
using Content.Shared.Body.Systems;
|
|
||||||
using Content.Shared.Damage.Systems;
|
using Content.Shared.Damage.Systems;
|
||||||
using Content.Shared.Database;
|
using Content.Shared.Database;
|
||||||
using Content.Shared.Destructible;
|
using Content.Shared.Destructible;
|
||||||
using Content.Shared.DoAfter;
|
using Content.Shared.DoAfter;
|
||||||
using Content.Shared.DragDrop;
|
using Content.Shared.DragDrop;
|
||||||
using Content.Shared.Examine;
|
using Content.Shared.Examine;
|
||||||
|
using Content.Shared.Gibbing;
|
||||||
using Content.Shared.Hands;
|
using Content.Shared.Hands;
|
||||||
using Content.Shared.Humanoid;
|
using Content.Shared.Humanoid;
|
||||||
using Content.Shared.IdentityManagement;
|
using Content.Shared.IdentityManagement;
|
||||||
|
|
@ -44,7 +44,7 @@ public sealed class SharedKitchenSpikeSystem : EntitySystem
|
||||||
[Dependency] private readonly MobStateSystem _mobStateSystem = default!;
|
[Dependency] private readonly MobStateSystem _mobStateSystem = default!;
|
||||||
[Dependency] private readonly SharedAppearanceSystem _appearanceSystem = default!;
|
[Dependency] private readonly SharedAppearanceSystem _appearanceSystem = default!;
|
||||||
[Dependency] private readonly SharedAudioSystem _audioSystem = default!;
|
[Dependency] private readonly SharedAudioSystem _audioSystem = default!;
|
||||||
[Dependency] private readonly SharedBodySystem _bodySystem = default!;
|
[Dependency] private readonly GibbingSystem _gibbing = default!;
|
||||||
[Dependency] private readonly SharedContainerSystem _containerSystem = default!;
|
[Dependency] private readonly SharedContainerSystem _containerSystem = default!;
|
||||||
[Dependency] private readonly SharedDoAfterSystem _doAfterSystem = default!;
|
[Dependency] private readonly SharedDoAfterSystem _doAfterSystem = default!;
|
||||||
[Dependency] private readonly SharedInteractionSystem _interaction = default!;
|
[Dependency] private readonly SharedInteractionSystem _interaction = default!;
|
||||||
|
|
@ -339,8 +339,7 @@ public sealed class SharedKitchenSpikeSystem : EntitySystem
|
||||||
if (butcherable.SpawnedEntities.Count == 0)
|
if (butcherable.SpawnedEntities.Count == 0)
|
||||||
{
|
{
|
||||||
// DeltaV - Gib the body, then body parts, but leave the organs
|
// DeltaV - Gib the body, then body parts, but leave the organs
|
||||||
var gibs = _bodySystem.GibBody(args.Target.Value, true);
|
var gibs = _gibbing.Gib(args.Target.Value);
|
||||||
|
|
||||||
foreach (var gib in gibs)
|
foreach (var gib in gibs)
|
||||||
{
|
{
|
||||||
if (HasComp<BodyPartComponent>(gib))
|
if (HasComp<BodyPartComponent>(gib))
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,11 @@
|
||||||
using System.Numerics;
|
using System.Numerics;
|
||||||
using Content.Shared.Body.Components;
|
|
||||||
using Content.Shared.Body.Systems;
|
|
||||||
using Content.Shared.Charges.Components;
|
using Content.Shared.Charges.Components;
|
||||||
using Content.Shared.Charges.Systems;
|
using Content.Shared.Charges.Systems;
|
||||||
using Content.Shared.Coordinates.Helpers;
|
using Content.Shared.Coordinates.Helpers;
|
||||||
using Content.Shared.Doors.Components;
|
using Content.Shared.Doors.Components;
|
||||||
using Content.Shared.Doors.Systems;
|
using Content.Shared.Doors.Systems;
|
||||||
using Content.Shared.Examine;
|
using Content.Shared.Examine;
|
||||||
|
using Content.Shared.Gibbing;
|
||||||
using Content.Shared.Hands.Components;
|
using Content.Shared.Hands.Components;
|
||||||
using Content.Shared.Hands.EntitySystems;
|
using Content.Shared.Hands.EntitySystems;
|
||||||
using Content.Shared.Interaction;
|
using Content.Shared.Interaction;
|
||||||
|
|
@ -53,7 +52,7 @@ public abstract class SharedMagicSystem : EntitySystem
|
||||||
[Dependency] private readonly SharedPhysicsSystem _physics = default!;
|
[Dependency] private readonly SharedPhysicsSystem _physics = default!;
|
||||||
[Dependency] private readonly SharedTransformSystem _transform = default!;
|
[Dependency] private readonly SharedTransformSystem _transform = default!;
|
||||||
[Dependency] private readonly INetManager _net = default!;
|
[Dependency] private readonly INetManager _net = default!;
|
||||||
[Dependency] private readonly SharedBodySystem _body = default!;
|
[Dependency] private readonly GibbingSystem _gibbing = default!;
|
||||||
[Dependency] private readonly EntityLookupSystem _lookup = default!;
|
[Dependency] private readonly EntityLookupSystem _lookup = default!;
|
||||||
[Dependency] private readonly SharedDoorSystem _door = default!;
|
[Dependency] private readonly SharedDoorSystem _door = default!;
|
||||||
[Dependency] private readonly InventorySystem _inventory = default!;
|
[Dependency] private readonly InventorySystem _inventory = default!;
|
||||||
|
|
@ -390,11 +389,7 @@ public abstract class SharedMagicSystem : EntitySystem
|
||||||
var impulseVector = direction * 10000;
|
var impulseVector = direction * 10000;
|
||||||
|
|
||||||
_physics.ApplyLinearImpulse(ev.Target, impulseVector);
|
_physics.ApplyLinearImpulse(ev.Target, impulseVector);
|
||||||
|
_gibbing.Gib(ev.Target);
|
||||||
if (!TryComp<BodyComponent>(ev.Target, out var body))
|
|
||||||
return;
|
|
||||||
|
|
||||||
_body.GibBody(ev.Target, true, body);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// End Touch Spells
|
// End Touch Spells
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@ using Content.Shared.Administration.Logs;
|
||||||
using Content.Shared.Body.Events;
|
using Content.Shared.Body.Events;
|
||||||
using Content.Shared.Containers.ItemSlots;
|
using Content.Shared.Containers.ItemSlots;
|
||||||
using Content.Shared.Database;
|
using Content.Shared.Database;
|
||||||
|
using Content.Shared.Gibbing;
|
||||||
using Content.Shared.Hands.EntitySystems;
|
using Content.Shared.Hands.EntitySystems;
|
||||||
using Content.Shared.IdentityManagement;
|
using Content.Shared.IdentityManagement;
|
||||||
using Content.Shared.Interaction;
|
using Content.Shared.Interaction;
|
||||||
|
|
@ -88,7 +89,7 @@ public abstract partial class SharedBorgSystem : EntitySystem
|
||||||
SubscribeLocalEvent<BorgChassisComponent, RefreshMovementSpeedModifiersEvent>(OnRefreshMovementSpeedModifiers);
|
SubscribeLocalEvent<BorgChassisComponent, RefreshMovementSpeedModifiersEvent>(OnRefreshMovementSpeedModifiers);
|
||||||
SubscribeLocalEvent<BorgChassisComponent, ActivatableUIOpenAttemptEvent>(OnUIOpenAttempt);
|
SubscribeLocalEvent<BorgChassisComponent, ActivatableUIOpenAttemptEvent>(OnUIOpenAttempt);
|
||||||
SubscribeLocalEvent<BorgChassisComponent, MobStateChangedEvent>(OnMobStateChanged);
|
SubscribeLocalEvent<BorgChassisComponent, MobStateChangedEvent>(OnMobStateChanged);
|
||||||
SubscribeLocalEvent<BorgChassisComponent, BeingGibbedEvent>(OnBeingGibbed);
|
SubscribeLocalEvent<BorgChassisComponent, GibbedBeforeDeletionEvent>(OnBeingGibbed);
|
||||||
SubscribeLocalEvent<BorgChassisComponent, GetCharactedDeadIcEvent>(OnGetDeadIC);
|
SubscribeLocalEvent<BorgChassisComponent, GetCharactedDeadIcEvent>(OnGetDeadIC);
|
||||||
SubscribeLocalEvent<BorgChassisComponent, GetCharacterUnrevivableIcEvent>(OnGetUnrevivableIC);
|
SubscribeLocalEvent<BorgChassisComponent, GetCharacterUnrevivableIcEvent>(OnGetUnrevivableIC);
|
||||||
SubscribeLocalEvent<BorgChassisComponent, PowerCellSlotEmptyEvent>(OnPowerCellSlotEmpty);
|
SubscribeLocalEvent<BorgChassisComponent, PowerCellSlotEmptyEvent>(OnPowerCellSlotEmpty);
|
||||||
|
|
@ -293,7 +294,7 @@ public abstract partial class SharedBorgSystem : EntitySystem
|
||||||
SetActive(chassis, false, user: args.Origin);
|
SetActive(chassis, false, user: args.Origin);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnBeingGibbed(Entity<BorgChassisComponent> chassis, ref BeingGibbedEvent args)
|
private void OnBeingGibbed(Entity<BorgChassisComponent> chassis, ref GibbedBeforeDeletionEvent args)
|
||||||
{
|
{
|
||||||
// Don't use the ItemSlotsSystem eject method since we don't want to play a sound and want we to eject the battery even if the slot is locked.
|
// Don't use the ItemSlotsSystem eject method since we don't want to play a sound and want we to eject the battery even if the slot is locked.
|
||||||
if (TryComp<PowerCellSlotComponent>(chassis, out var slotComp) &&
|
if (TryComp<PowerCellSlotComponent>(chassis, out var slotComp) &&
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
using Content.Shared.Species.Components;
|
using Content.Shared.Species.Components;
|
||||||
using Content.Shared.Actions;
|
using Content.Shared.Actions;
|
||||||
using Content.Shared.Body.Systems;
|
using Content.Shared.Body.Systems;
|
||||||
|
using Content.Shared.Gibbing;
|
||||||
using Content.Shared.Mobs;
|
using Content.Shared.Mobs;
|
||||||
using Content.Shared.Mobs.Components;
|
using Content.Shared.Mobs.Components;
|
||||||
using Content.Shared.Popups;
|
using Content.Shared.Popups;
|
||||||
|
|
@ -12,7 +13,7 @@ namespace Content.Shared.Species;
|
||||||
public sealed partial class GibActionSystem : EntitySystem
|
public sealed partial class GibActionSystem : EntitySystem
|
||||||
{
|
{
|
||||||
[Dependency] private readonly SharedActionsSystem _actionsSystem = default!;
|
[Dependency] private readonly SharedActionsSystem _actionsSystem = default!;
|
||||||
[Dependency] private readonly SharedBodySystem _bodySystem = default!;
|
[Dependency] private readonly GibbingSystem _gibbing = default!;
|
||||||
[Dependency] private readonly IPrototypeManager _protoManager = default!;
|
[Dependency] private readonly IPrototypeManager _protoManager = default!;
|
||||||
[Dependency] private readonly SharedPopupSystem _popupSystem = default!;
|
[Dependency] private readonly SharedPopupSystem _popupSystem = default!;
|
||||||
|
|
||||||
|
|
@ -52,8 +53,7 @@ public sealed partial class GibActionSystem : EntitySystem
|
||||||
{
|
{
|
||||||
// When they use the action, gib them.
|
// When they use the action, gib them.
|
||||||
_popupSystem.PopupClient(Loc.GetString(comp.PopupText, ("name", uid)), uid, uid);
|
_popupSystem.PopupClient(Loc.GetString(comp.PopupText, ("name", uid)), uid, uid);
|
||||||
// DeltaV acidify: false drops inventory items instead of deleting them
|
_gibbing.Gib(uid, user: args.Performer);
|
||||||
_bodySystem.GibBody(uid, false);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
using Content.Shared.Body.Systems;
|
using Content.Shared.Gibbing;
|
||||||
using Content.Shared.Inventory;
|
using Content.Shared.Inventory;
|
||||||
using Content.Shared.Trigger.Components.Effects;
|
using Content.Shared.Trigger.Components.Effects;
|
||||||
|
|
||||||
|
|
@ -6,7 +6,7 @@ namespace Content.Shared.Trigger.Systems;
|
||||||
|
|
||||||
public sealed class GibOnTriggerSystem : XOnTriggerSystem<GibOnTriggerComponent>
|
public sealed class GibOnTriggerSystem : XOnTriggerSystem<GibOnTriggerComponent>
|
||||||
{
|
{
|
||||||
[Dependency] private readonly SharedBodySystem _body = default!;
|
[Dependency] private readonly GibbingSystem _gibbing = default!;
|
||||||
[Dependency] private readonly InventorySystem _inventory = default!;
|
[Dependency] private readonly InventorySystem _inventory = default!;
|
||||||
|
|
||||||
protected override void OnTrigger(Entity<GibOnTriggerComponent> ent, EntityUid target, ref TriggerEvent args)
|
protected override void OnTrigger(Entity<GibOnTriggerComponent> ent, EntityUid target, ref TriggerEvent args)
|
||||||
|
|
@ -20,7 +20,7 @@ public sealed class GibOnTriggerSystem : XOnTriggerSystem<GibOnTriggerComponent>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_body.GibBody(target, true);
|
_gibbing.Gib(target, user: args.User);
|
||||||
args.Handled = true;
|
args.Handled = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
- type: entity
|
- type: entity
|
||||||
id: BaseAnimalOrganUnGibbable
|
id: BaseAnimalOrgan
|
||||||
parent: BaseItem
|
parent: BaseItem
|
||||||
abstract: true
|
abstract: true
|
||||||
components:
|
components:
|
||||||
|
|
@ -23,13 +23,6 @@
|
||||||
tags:
|
tags:
|
||||||
- Meat
|
- Meat
|
||||||
|
|
||||||
- type: entity
|
|
||||||
id: BaseAnimalOrgan
|
|
||||||
parent: BaseAnimalOrganUnGibbable
|
|
||||||
abstract: true
|
|
||||||
components:
|
|
||||||
- type: Gibbable
|
|
||||||
|
|
||||||
- type: entity
|
- type: entity
|
||||||
id: OrganAnimalLungs
|
id: OrganAnimalLungs
|
||||||
parent: BaseAnimalOrgan
|
parent: BaseAnimalOrgan
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
- type: entity
|
- type: entity
|
||||||
id: BaseHumanOrganUnGibbable
|
id: BaseHumanOrgan
|
||||||
parent: BaseItem
|
parent: BaseItem
|
||||||
abstract: true
|
abstract: true
|
||||||
components:
|
components:
|
||||||
|
|
@ -27,16 +27,9 @@
|
||||||
tags:
|
tags:
|
||||||
- Meat
|
- Meat
|
||||||
|
|
||||||
- type: entity
|
|
||||||
id: BaseHumanOrgan
|
|
||||||
parent: BaseHumanOrganUnGibbable
|
|
||||||
abstract: true
|
|
||||||
components:
|
|
||||||
- type: Gibbable
|
|
||||||
|
|
||||||
- type: entity
|
- type: entity
|
||||||
id: OrganHumanBrain
|
id: OrganHumanBrain
|
||||||
parent: BaseHumanOrganUnGibbable
|
parent: BaseHumanOrgan
|
||||||
name: brain
|
name: brain
|
||||||
description: "The source of incredible, unending intelligence. Honk."
|
description: "The source of incredible, unending intelligence. Honk."
|
||||||
components:
|
components:
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,6 @@
|
||||||
path: /Audio/_Shitmed/Medical/Surgery/organ1.ogg
|
path: /Audio/_Shitmed/Medical/Surgery/organ1.ogg
|
||||||
endSound:
|
endSound:
|
||||||
path: /Audio/_Shitmed/Medical/Surgery/organ2.ogg
|
path: /Audio/_Shitmed/Medical/Surgery/organ2.ogg
|
||||||
- type: Gibbable
|
|
||||||
- type: ContainerContainer
|
- type: ContainerContainer
|
||||||
containers:
|
containers:
|
||||||
bodypart: !type:Container
|
bodypart: !type:Container
|
||||||
|
|
|
||||||
|
|
@ -440,7 +440,6 @@
|
||||||
damage: 10
|
damage: 10
|
||||||
behaviors:
|
behaviors:
|
||||||
- !type:GibBehavior
|
- !type:GibBehavior
|
||||||
gibContents: Skip # Shitmed Change
|
|
||||||
recursive: false
|
recursive: false
|
||||||
- type: NonSpreaderZombie
|
- type: NonSpreaderZombie
|
||||||
- type: StepTrigger
|
- type: StepTrigger
|
||||||
|
|
|
||||||
|
|
@ -40,7 +40,6 @@
|
||||||
damage: 150
|
damage: 150
|
||||||
behaviors:
|
behaviors:
|
||||||
- !type:GibBehavior # Shitmed Change
|
- !type:GibBehavior # Shitmed Change
|
||||||
gibContents: Skip # Shitmed Change
|
|
||||||
- type: SlowOnDamage #modified speeds because they're so weak
|
- type: SlowOnDamage #modified speeds because they're so weak
|
||||||
speedModifierThresholds:
|
speedModifierThresholds:
|
||||||
60: 0.9
|
60: 0.9
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
- type: entity
|
- type: entity
|
||||||
id: OrganAnimalBrain
|
id: OrganAnimalBrain
|
||||||
parent: BaseAnimalOrganUnGibbable
|
parent: BaseAnimalOrgan
|
||||||
name: animal brain
|
name: animal brain
|
||||||
description: "Not so intelligence, not so honk."
|
description: "Not so intelligence, not so honk."
|
||||||
components:
|
components:
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue