+++ /dev/null
-#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, gibOrgans: false));
- await server.WaitAssertion(() => server.System<BodySystem>().GibBody(target2, gibOrgans: 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();
- }
-}
--- /dev/null
+#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();
+ }
+}
using Content.Shared.Damage.Systems;
using Content.Shared.Database;
using Content.Shared.Electrocution;
+using Content.Shared.Gibbing;
using Content.Shared.Gravity;
using Content.Shared.Interaction.Components;
using Content.Shared.Inventory;
[Dependency] private readonly SharedTransformSystem _transformSystem = default!;
[Dependency] private readonly SuperBonkSystem _superBonkSystem = default!;
[Dependency] private readonly SlipperySystem _slipperySystem = default!;
+ [Dependency] private readonly GibbingSystem _gibbing = default!;
private readonly EntProtoId _actionViewLawsProtoId = "ActionViewLaws";
private readonly ProtoId<SiliconLawsetPrototype> _crewsimovLawset = "Crewsimov";
4, 1, 2, args.Target, maxTileBreak: 0), // it gibs, damage doesn't need to be high.
CancellationToken.None);
- _bodySystem.GibBody(args.Target);
+ _gibbing.Gib(args.Target);
},
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.
using Content.Shared.Body.Components;
using Content.Shared.Chat;
using Content.Shared.Database;
+using Content.Shared.Gibbing;
using Content.Shared.Mobs;
using Content.Shared.Popups;
using Content.Shared.Whitelist;
[Dependency] private readonly IAdminLogManager _adminLog = default!;
[Dependency] private readonly AnomalySystem _anomaly = 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 ISharedPlayerManager _player = default!;
[Dependency] private readonly EntityWhitelistSystem _whitelist = default!;
if (!TryComp<BodyComponent>(ent, out var body))
return;
- _body.GibBody(ent, true, body, splatModifier: 5f);
+ _gibbing.Gib(ent.Owner);
}
private void OnSeverityChanged(Entity<InnerBodyAnomalyComponent> ent, ref AnomalySeverityChangedEvent args)
using Content.Shared.Atmos.Rotting;
using Content.Shared.Body.Events;
using Content.Shared.Damage.Systems;
+using Content.Shared.Gibbing;
using Content.Shared.Temperature.Components;
using Robust.Server.Containers;
using Robust.Shared.Physics.Components;
{
base.Initialize();
- SubscribeLocalEvent<RottingComponent, BeingGibbedEvent>(OnGibbed);
+ SubscribeLocalEvent<RottingComponent, GibbedBeforeDeletionEvent>(OnGibbed);
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))
return;
var layers = HumanoidVisualLayersExtension.Sublayers(layer.Value);
_humanoidSystem.SetLayersVisibility((bodyEnt, humanoid), layers, visible: false);
}
-
- public override HashSet<EntityUid> GibBody(
- EntityUid bodyId,
- bool gibOrgans = false,
- BodyComponent? body = null,
- bool launchGibs = true,
- Vector2? splatDirection = null,
- float splatModifier = 1,
- Angle splatCone = default,
- SoundSpecifier? gibSoundOverride = null
- )
- {
- if (!Resolve(bodyId, ref body, logMissing: false)
- || TerminatingOrDeleted(bodyId)
- || EntityManager.IsQueuedForDeletion(bodyId))
- {
- return new HashSet<EntityUid>();
- }
-
- if (HasComp<GodmodeComponent>(bodyId))
- return new HashSet<EntityUid>();
-
- var xform = Transform(bodyId);
- if (xform.MapUid is null)
- return new HashSet<EntityUid>();
-
- var gibs = base.GibBody(bodyId, gibOrgans, body, launchGibs: launchGibs,
- splatDirection: splatDirection, splatModifier: splatModifier, splatCone:splatCone);
-
- var ev = new BeingGibbedEvent(gibs);
- RaiseLocalEvent(bodyId, ref ev);
-
- QueueDel(bodyId);
-
- return gibs;
- }
}
using System.Linq;
using Content.Server.Administration.Logs;
using Content.Server.Atmos.EntitySystems;
-using Content.Server.Body.Systems;
using Content.Server.Construction;
using Content.Server.Destructible.Thresholds;
using Content.Server.Destructible.Thresholds.Behaviors;
using Content.Shared.Destructible;
using Content.Shared.Destructible.Thresholds.Triggers;
using Content.Shared.FixedPoint;
+using Content.Shared.Gibbing;
using Content.Shared.Humanoid;
using Content.Shared.Trigger.Systems;
using JetBrains.Annotations;
[Dependency] public readonly AtmosphereSystem AtmosphereSystem = default!;
[Dependency] public readonly AudioSystem AudioSystem = default!;
- [Dependency] public readonly BodySystem BodySystem = default!;
+ [Dependency] public readonly GibbingSystem Gibbing = default!;
[Dependency] public readonly ConstructionSystem ConstructionSystem = default!;
[Dependency] public readonly ExplosionSystem ExplosionSystem = default!;
[Dependency] public readonly StackSystem StackSystem = default!;
public void Execute(EntityUid owner, DestructibleSystem system, EntityUid? cause = null)
{
- if (system.EntityManager.TryGetComponent(owner, out BodyComponent? body))
- {
- system.BodySystem.GibBody(owner, _recursive, body);
- }
+ system.Gibbing.Gib(owner, _recursive);
}
}
}
using Content.Shared.Forensics;
using Content.Shared.Forensics.Components;
using Content.Shared.Forensics.Systems;
+using Content.Shared.Gibbing;
using Content.Shared.Interaction;
using Content.Shared.Interaction.Events;
using Content.Shared.Inventory;
// 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<ForensicsComponent, BeingGibbedEvent>(OnBeingGibbed);
+ SubscribeLocalEvent<ForensicsComponent, GibbedBeforeDeletionEvent>(OnBeingGibbed);
SubscribeLocalEvent<ForensicsComponent, MeleeHitEvent>(OnMeleeHit);
SubscribeLocalEvent<ForensicsComponent, GotRehydratedEvent>(OnRehydrated);
SubscribeLocalEvent<CleansForensicsComponent, AfterInteractEvent>(OnAfterInteract, after: new[] { typeof(AbsorbentSystem) });
}
}
- 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");
- if (TryComp(uid, out DnaComponent? dnaComp) && dnaComp.DNA != null)
+ if (TryComp(ent, out DnaComponent? dnaComp) && dnaComp.DNA != null)
dna = dnaComp.DNA;
- foreach (EntityUid part in args.GibbedParts)
+ foreach (var part in args.Giblets)
{
var partComp = EnsureComp<ForensicsComponent>(part);
partComp.DNAs.Add(dna);
using Content.Shared.Gibbing.Components;
using Content.Shared.Mind;
using Content.Shared.Objectives.Systems;
-using Content.Server.Body.Systems;
+using Content.Shared.Gibbing;
namespace Content.Server.Gibbing.Systems;
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 SharedObjectivesSystem _objectives = default!;
if (gibComp.SpawnProto != null)
SpawnAtPosition(gibComp.SpawnProto, Transform(uid).Coordinates);
- _body.GibBody(uid, splatModifier: 5f);
+ _gibbing.Gib(uid);
}
}
}
-using Content.Server.Body.Systems;
using Content.Server.Popups;
using Content.Shared.Actions;
using Content.Shared.Damage.Systems;
using Content.Shared.DoAfter;
using Content.Shared.Examine;
+using Content.Shared.Gibbing;
using Content.Shared.Guardian;
using Content.Shared.Hands.Components;
using Content.Shared.Hands.EntitySystems;
[Dependency] private readonly SharedActionsSystem _actionSystem = default!;
[Dependency] private readonly SharedHandsSystem _handsSystem = 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 SharedTransformSystem _transform = default!;
// Ensure held items are dropped before deleting guardian.
if (HasComp<HandsComponent>(guardian))
- _bodySystem.GibBody(component.HostedGuardian.Value);
+ _gibbing.Gib(component.HostedGuardian.Value);
QueueDel(guardian);
QueueDel(component.ActionEntity);
using Content.Shared.Body.Components;
using Content.Shared.Damage.Systems;
using Content.Shared.Examine;
+using Content.Shared.Gibbing;
using Content.Shared.Popups;
using Robust.Shared.Audio.Systems;
using Robust.Shared.Map;
{
[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 SharedPhysicsSystem _physics = default!;
[Dependency] private readonly SharedAudioSystem _audio = default!;
return;
}
- _bodySystem.GibBody(ent, body: body);
+ _gibbing.Gib(ent);
return;
}
using Content.Shared.Body.Events;
+using Content.Shared.Gibbing;
using Content.Shared.Implants.Components;
using Content.Shared.Storage;
using Robust.Shared.Containers;
{
SubscribeLocalEvent<ImplantedComponent, ComponentInit>(OnImplantedInit);
SubscribeLocalEvent<ImplantedComponent, ComponentShutdown>(OnShutdown);
- SubscribeLocalEvent<ImplantedComponent, BeingGibbedEvent>(OnGibbed);
+ SubscribeLocalEvent<ImplantedComponent, GibbedBeforeDeletionEvent>(OnGibbed);
}
private void OnImplantedInit(Entity<ImplantedComponent> ent, ref ComponentInit args)
_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
foreach (var implant in ent.Comp.ImplantContainer.ContainedEntities)
-using Content.Server.Body.Systems;
-using Content.Shared.Administration.Logs;
-using Content.Shared.Body.Components;
+using Content.Shared.Administration.Logs;
using Content.Shared.Database;
using Content.Shared.Destructible;
using Content.Shared.DoAfter;
+using Content.Shared.Gibbing;
using Content.Shared.IdentityManagement;
using Content.Shared.Interaction;
using Content.Shared.Kitchen;
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 SharedDoAfterSystem _doAfterSystem = default!;
[Dependency] private readonly SharedPopupSystem _popupSystem = default!;
args.Args.User,
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);
args.Handled = true;
using Content.Server.Popups;
using Content.Server.Stack;
using Content.Server.Wires;
-using Content.Shared.Body.Systems;
using Content.Shared.Chemistry.Components;
using Content.Shared.Chemistry.Components.SolutionManager;
using Content.Shared.Chemistry.EntitySystems;
using Robust.Shared.Prototypes;
using Robust.Shared.Utility;
using System.Linq;
+using Content.Shared.Gibbing;
using Content.Shared.Humanoid;
namespace Content.Server.Materials;
[Dependency] private readonly OpenableSystem _openable = default!;
[Dependency] private readonly PopupSystem _popup = 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 StackSystem _stack = default!;
[Dependency] private readonly SharedMindSystem _mind = default!;
Filter.PvsExcept(victim, entityManager: EntityManager),
true);
- _body.GibBody(victim, true);
+ _gibbing.Gib(victim);
_appearance.SetData(entity.Owner, RecyclerVisuals.Bloody, true);
args.Handled = true;
}
_adminLogger.Add(LogType.Gib, logImpact, $"{ToPrettyString(item):victim} was gibbed by {ToPrettyString(uid):entity} ");
if (component.ReclaimSolutions)
SpawnChemicalsFromComposition(uid, item, completion, false, component, xform);
- _body.GibBody(item, true);
+ _gibbing.Gib(item);
_appearance.SetData(uid, RecyclerVisuals.Bloody, true);
}
else
using System.Linq;
-using Content.Shared.Body.Events;
+using Content.Shared.Gibbing;
using Content.Shared.Mind;
using Content.Shared.Mind.Components;
using Content.Shared.Tag;
/// <inheritdoc/>
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;
- 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())
return;
- var ent = _random.Pick(validParts);
- _mindSystem.TransferTo(mindId, ent, mind: mind);
+ var transfer = _random.Pick(validParts);
+ _mindSystem.TransferTo(mindId, transfer, mind: mind);
}
}
{
_logger.Add(LogType.Gib, LogImpact.Extreme, $"{ToPrettyString(ent):player} got gibbed by the shuttle" +
$" {ToPrettyString(uid)} arriving from FTL at {xform.Coordinates:coordinates}");
- var gibs = _bobby.GibBody(ent, body: mob);
+ var gibs = _gibbing.Gib(ent);
_immuneEnts.UnionWith(gibs);
continue;
}
using Content.Server.Administration.Logs;
-using Content.Server.Body.Systems;
using Content.Server.Buckle.Systems;
using Content.Server.Parallax;
using Content.Server.Procedural;
using Content.Server.Stunnable;
using Content.Shared.Buckle.Components;
using Content.Shared.Damage.Systems;
+using Content.Shared.Gibbing;
using Content.Shared.Light.Components;
using Content.Shared.Movement.Events;
using Content.Shared.Salvage;
[Dependency] private readonly IPrototypeManager _protoManager = default!;
[Dependency] private readonly IRobustRandom _random = 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 DamageableSystem _damageSys = default!;
[Dependency] private readonly DockingSystem _dockSystem = default!;
using Content.Server.Body.Systems;
using Content.Server.Stack;
using Content.Shared.Body.Components;
+using Content.Shared.Gibbing;
using Content.Shared.Storage.Components;
using Content.Shared.Whitelist;
using Content.Shared.Xenoarchaeology.Equipment;
public sealed class ArtifactCrusherSystem : SharedArtifactCrusherSystem
{
[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 EntityWhitelistSystem _whitelistSystem = default!;
if (!TryComp<BodyComponent>(contained, out var body))
Del(contained);
- var gibs = _body.GibBody(contained, body: body, gibOrgans: true);
+ var gibs = _gibbing.Gib(contained);
foreach (var gib in gibs)
{
ContainerSystem.Insert((gib, null, null, null), crusher.OutputContainer);
+++ /dev/null
-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);
using Content.Shared.FixedPoint;
using Content.Shared.Fluids;
using Content.Shared.Forensics.Components;
+using Content.Shared.Gibbing;
using Content.Shared.HealthExaminable;
using Content.Shared.Mobs.Systems;
using Content.Shared.Popups;
SubscribeLocalEvent<BloodstreamComponent, SolutionRelayEvent<ReactionAttemptEvent>>(OnReactionAttempt);
SubscribeLocalEvent<BloodstreamComponent, DamageChangedEvent>(OnDamageChanged);
SubscribeLocalEvent<BloodstreamComponent, HealthBeingExaminedEvent>(OnHealthBeingExamined);
- SubscribeLocalEvent<BloodstreamComponent, BeingGibbedEvent>(OnBeingGibbed);
+ SubscribeLocalEvent<BloodstreamComponent, GibbedBeforeDeletionEvent>(OnBeingGibbed);
SubscribeLocalEvent<BloodstreamComponent, ApplyMetabolicMultiplierEvent>(OnApplyMetabolicMultiplier);
SubscribeLocalEvent<BloodstreamComponent, RejuvenateEvent>(OnRejuvenate);
SubscribeLocalEvent<BloodstreamComponent, MetabolismExclusionEvent>(OnMetabolismExclusion);
}
}
- private void OnBeingGibbed(Entity<BloodstreamComponent> ent, ref BeingGibbedEvent args)
+ private void OnBeingGibbed(Entity<BloodstreamComponent> ent, ref GibbedBeforeDeletionEvent args)
{
SpillAllSolutions(ent.AsNullable());
}
using Content.Shared.Body.Part;
using Content.Shared.Body.Prototypes;
using Content.Shared.DragDrop;
-using Content.Shared.Gibbing.Components;
-using Content.Shared.Gibbing.Events;
-using Content.Shared.Gibbing.Systems;
+using Content.Shared.Gibbing;
using Content.Shared.Inventory;
-using Robust.Shared.Audio;
using Robust.Shared.Audio.Systems;
using Robust.Shared.Containers;
using Robust.Shared.Map;
*/
[Dependency] private readonly InventorySystem _inventory = default!;
- [Dependency] private readonly GibbingSystem _gibbingSystem = default!;
[Dependency] private readonly SharedAudioSystem _audioSystem = default!;
private const float GibletLaunchImpulse = 8;
SubscribeLocalEvent<BodyComponent, ComponentInit>(OnBodyInit);
SubscribeLocalEvent<BodyComponent, MapInitEvent>(OnBodyMapInit);
SubscribeLocalEvent<BodyComponent, CanDragEvent>(OnBodyCanDrag);
+ SubscribeLocalEvent<BodyComponent, BeingGibbedEvent>(OnBeingGibbed);
}
private void OnBodyInserted(Entity<BodyComponent> ent, ref EntInsertedIntoContainerMessage args)
}
}
- public virtual HashSet<EntityUid> GibBody(
- EntityUid bodyId,
- bool gibOrgans = false,
- BodyComponent? body = null,
- bool launchGibs = true,
- Vector2? splatDirection = null,
- float splatModifier = 1,
- Angle splatCone = default,
- SoundSpecifier? gibSoundOverride = null)
+ private void OnBeingGibbed(Entity<BodyComponent> ent, ref BeingGibbedEvent args)
{
- var gibs = new HashSet<EntityUid>();
-
- 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);
+ var parts = GetBodyChildren(ent, ent).ToArray();
+ args.Giblets.EnsureCapacity(args.Giblets.Capacity + parts.Length);
foreach (var part in parts)
{
-
- _gibbingSystem.TryGibEntityWithRef(bodyId, part.Id, GibType.Gib, GibContentsOption.Skip, ref gibs,
- playAudio: false, launchGibs:true, launchDirection:splatDirection, launchImpulse: GibletLaunchImpulse * splatModifier,
- launchImpulseVariance:GibletLaunchImpulseVariance, launchCone: splatCone);
-
- if (!gibOrgans)
- continue;
-
foreach (var organ in GetPartOrgans(part.Id, part.Component))
{
- _gibbingSystem.TryGibEntityWithRef(bodyId, organ.Id, GibType.Drop, GibContentsOption.Skip,
- ref gibs, playAudio: false, launchImpulse: GibletLaunchImpulse * splatModifier,
- launchImpulseVariance:GibletLaunchImpulseVariance, launchCone: splatCone);
+ args.Giblets.Add(organ.Id);
}
+ PredictedQueueDel(part.Id);
}
- var bodyTransform = Transform(bodyId);
- if (TryComp<InventoryComponent>(bodyId, out var inventory))
+ foreach (var item in _inventory.GetHandOrInventoryEntities(ent.Owner))
{
- foreach (var item in _inventory.GetHandOrInventoryEntities(bodyId))
- {
- SharedTransform.DropNextTo(item, (bodyId, bodyTransform));
- gibs.Add(item);
- }
+ args.Giblets.Add(item);
}
- _audioSystem.PlayPredicted(gibSoundOverride, bodyTransform.Coordinates, null);
- return gibs;
}
}
using Content.Shared.Actions;
-using Content.Shared.Body.Events;
using Content.Shared.Body.Systems;
using Content.Shared.Chemistry.Components;
using Content.Shared.Devour.Components;
using Content.Shared.DoAfter;
+using Content.Shared.Gibbing;
using Content.Shared.Mobs;
using Content.Shared.Mobs.Components;
using Content.Shared.Popups;
SubscribeLocalEvent<DevourerComponent, ComponentShutdown>(OnShutdown);
SubscribeLocalEvent<DevourerComponent, DevourActionEvent>(OnDevourAction);
SubscribeLocalEvent<DevourerComponent, DevourDoAfterEvent>(OnDoAfter);
- SubscribeLocalEvent<DevourerComponent, BeingGibbedEvent>(OnGibContents);
+ SubscribeLocalEvent<DevourerComponent, GibbedBeforeDeletionEvent>(OnGibContents);
}
private void OnStartup(Entity<DevourerComponent> ent, ref ComponentStartup args)
_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)
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);
}
}
+++ /dev/null
-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;
-}
+++ /dev/null
-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
-}
--- /dev/null
+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);
+++ /dev/null
-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;
- }
-}
using Content.Shared.Administration.Logs;
-using Content.Shared.Body.Systems;
using Content.Shared.Damage.Systems;
using Content.Shared.Database;
using Content.Shared.Destructible;
using Content.Shared.DoAfter;
using Content.Shared.DragDrop;
using Content.Shared.Examine;
+using Content.Shared.Gibbing;
using Content.Shared.Hands;
using Content.Shared.Humanoid;
using Content.Shared.IdentityManagement;
[Dependency] private readonly MobStateSystem _mobStateSystem = default!;
[Dependency] private readonly SharedAppearanceSystem _appearanceSystem = 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 SharedDoAfterSystem _doAfterSystem = default!;
[Dependency] private readonly SharedInteractionSystem _interaction = default!;
// Gib the victim if there is nothing else to butcher.
if (butcherable.SpawnedEntities.Count == 0)
{
- _bodySystem.GibBody(args.Target.Value, true);
+ _gibbing.Gib(args.Target.Value);
var logSeverity = HasComp<HumanoidAppearanceComponent>(args.Target) ? LogImpact.Extreme : LogImpact.High;
using System.Numerics;
-using Content.Shared.Body.Components;
-using Content.Shared.Body.Systems;
using Content.Shared.Charges.Components;
using Content.Shared.Charges.Systems;
using Content.Shared.Coordinates.Helpers;
using Content.Shared.Doors.Components;
using Content.Shared.Doors.Systems;
using Content.Shared.Examine;
+using Content.Shared.Gibbing;
using Content.Shared.Hands.Components;
using Content.Shared.Hands.EntitySystems;
using Content.Shared.Interaction;
[Dependency] private readonly SharedPhysicsSystem _physics = default!;
[Dependency] private readonly SharedTransformSystem _transform = 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 SharedDoorSystem _door = default!;
[Dependency] private readonly InventorySystem _inventory = default!;
var impulseVector = direction * 10000;
_physics.ApplyLinearImpulse(ev.Target, impulseVector);
-
- if (!TryComp<BodyComponent>(ev.Target, out var body))
- return;
-
- _body.GibBody(ev.Target, true, body);
+ _gibbing.Gib(ev.Target);
}
// End Touch Spells
using Content.Shared.Body.Events;
using Content.Shared.Containers.ItemSlots;
using Content.Shared.Database;
+using Content.Shared.Gibbing;
using Content.Shared.Hands.EntitySystems;
using Content.Shared.IdentityManagement;
using Content.Shared.Interaction;
SubscribeLocalEvent<BorgChassisComponent, RefreshMovementSpeedModifiersEvent>(OnRefreshMovementSpeedModifiers);
SubscribeLocalEvent<BorgChassisComponent, ActivatableUIOpenAttemptEvent>(OnUIOpenAttempt);
SubscribeLocalEvent<BorgChassisComponent, MobStateChangedEvent>(OnMobStateChanged);
- SubscribeLocalEvent<BorgChassisComponent, BeingGibbedEvent>(OnBeingGibbed);
+ SubscribeLocalEvent<BorgChassisComponent, GibbedBeforeDeletionEvent>(OnBeingGibbed);
SubscribeLocalEvent<BorgChassisComponent, GetCharactedDeadIcEvent>(OnGetDeadIC);
SubscribeLocalEvent<BorgChassisComponent, GetCharacterUnrevivableIcEvent>(OnGetUnrevivableIC);
SubscribeLocalEvent<BorgChassisComponent, PowerCellSlotEmptyEvent>(OnPowerCellSlotEmpty);
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.
if (TryComp<PowerCellSlotComponent>(chassis, out var slotComp) &&
using Content.Shared.Species.Components;
using Content.Shared.Actions;
using Content.Shared.Body.Systems;
+using Content.Shared.Gibbing;
using Content.Shared.Mobs;
using Content.Shared.Mobs.Components;
using Content.Shared.Popups;
public sealed partial class GibActionSystem : EntitySystem
{
[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 SharedPopupSystem _popupSystem = default!;
private void OnMobStateChanged(EntityUid uid, GibActionComponent comp, MobStateChangedEvent args)
{
- // When the mob changes state, check if they're dead and give them the action if so.
+ // When the mob changes state, check if they're dead and give them the action if so.
if (!TryComp<MobStateComponent>(uid, out var mobState))
return;
// If they aren't given the action, remove it.
_actionsSystem.RemoveAction(uid, comp.ActionEntity);
}
-
+
private void OnGibAction(EntityUid uid, GibActionComponent comp, GibActionEvent args)
{
// When they use the action, gib them.
_popupSystem.PopupClient(Loc.GetString(comp.PopupText, ("name", uid)), uid, uid);
- _bodySystem.GibBody(uid, true);
+ _gibbing.Gib(uid, user: args.Performer);
}
-
- public sealed partial class GibActionEvent : InstantActionEvent { }
+
+ public sealed partial class GibActionEvent : InstantActionEvent { }
}
-using Content.Shared.Body.Systems;
+using Content.Shared.Gibbing;
using Content.Shared.Inventory;
using Content.Shared.Trigger.Components.Effects;
public sealed class GibOnTriggerSystem : XOnTriggerSystem<GibOnTriggerComponent>
{
- [Dependency] private readonly SharedBodySystem _body = default!;
+ [Dependency] private readonly GibbingSystem _gibbing = default!;
[Dependency] private readonly InventorySystem _inventory = default!;
protected override void OnTrigger(Entity<GibOnTriggerComponent> ent, EntityUid target, ref TriggerEvent args)
}
}
- _body.GibBody(target, true);
+ _gibbing.Gib(target, user: args.User);
args.Handled = true;
}
}
- type: entity
- id: BaseAnimalOrganUnGibbable
+ id: BaseAnimalOrgan
parent: BaseItem
abstract: true
components:
tags:
- Meat
-- type: entity
- id: BaseAnimalOrgan
- parent: BaseAnimalOrganUnGibbable
- abstract: true
- components:
- - type: Gibbable
-
- type: entity
id: OrganAnimalLungs
parent: BaseAnimalOrgan
- type: entity
- id: BaseHumanOrganUnGibbable
+ id: BaseHumanOrgan
parent: BaseItem
abstract: true
components:
tags:
- Meat
-- type: entity
- id: BaseHumanOrgan
- parent: BaseHumanOrganUnGibbable
- abstract: true
- components:
- - type: Gibbable
-
- type: entity
id: OrganHumanBrain
- parent: BaseHumanOrganUnGibbable
+ parent: BaseHumanOrgan
name: brain
description: "The source of incredible, unending intelligence. Honk."
components:
- type: Tag
tags:
- Trash
- - type: Gibbable
- type: Extractable
juiceSolution:
reagents:
- type: Damageable
damageContainer: Biological
- type: BodyPart
- - type: Gibbable
- type: ContainerContainer
containers:
bodypart: !type:Container