Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Gibbing refactor (Per-part gibbing and giblet throwing!) #24989

Merged
merged 9 commits into from
Feb 10, 2024
38 changes: 15 additions & 23 deletions Content.Server/Body/Systems/BodySystem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
using Robust.Shared.Random;
using Robust.Shared.Timing;
using System.Numerics;
using Content.Shared.Gibbing.Components;
using Content.Shared.Movement.Systems;
using Robust.Shared.Audio.Systems;

Expand Down Expand Up @@ -106,7 +107,18 @@ protected override void RemovePart(
_humanoidSystem.SetLayersVisibility(bodyUid, layers, false, true, humanoid);
}

public override HashSet<EntityUid> GibBody(EntityUid bodyId, bool gibOrgans = false, BodyComponent? body = null, bool deleteItems = false, bool deleteBrain = false)
public override HashSet<EntityUid> GibBody(
EntityUid bodyId,
bool gibOrgans = false,
BodyComponent? body = null ,
bool deleteItems = false,
bool launchGibs = true,
Vector2? splatDirection = null,
float splatModifier = 1,
Angle splatCone = default,
SoundSpecifier? gibSound = null,
AudioParams? gibAudioParams = null
)
{
if (!Resolve(bodyId, ref body, false))
return new HashSet<EntityUid>();
Expand All @@ -118,28 +130,8 @@ public override HashSet<EntityUid> GibBody(EntityUid bodyId, bool gibOrgans = fa
if (xform.MapUid == null)
return new HashSet<EntityUid>();

var gibs = base.GibBody(bodyId, gibOrgans, body, deleteItems, deleteBrain);

var coordinates = xform.Coordinates;
var filter = Filter.Pvs(bodyId, entityManager: EntityManager);
var audio = AudioParams.Default.WithVariation(0.025f);

_audio.PlayStatic(body.GibSound, filter, coordinates, true, audio);

foreach (var entity in gibs)
{
if (deleteItems)
{
if (!HasComp<BrainComponent>(entity) || deleteBrain)
{
QueueDel(entity);
}
}
else
{
SharedTransform.SetCoordinates(entity, coordinates.Offset(_random.NextVector2(.3f)));
}
}
var gibs = base.GibBody(bodyId, gibOrgans, body, deleteItems, launchGibs: launchGibs,
splatDirection: splatDirection, splatModifier: splatModifier, splatCone:splatCone);
RaiseLocalEvent(bodyId, new BeingGibbedEvent(gibs));
QueueDel(bodyId);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ public void FinishCrushing(Entity<ArtifactCrusherComponent, EntityStorageCompone
if (!TryComp<BodyComponent>(contained, out var body))
Del(contained);

var gibs = _body.GibBody(contained, body: body, gibOrgans: true, deleteBrain: true);
var gibs = _body.GibBody(contained, body: body, gibOrgans: true);
foreach (var gib in gibs)
{
ContainerSystem.Insert((gib, null, null, null), crusher.OutputContainer);
Expand Down
43 changes: 35 additions & 8 deletions Content.Shared/Body/Systems/SharedBodySystem.Body.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,13 @@
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.Inventory;
using Content.Shared.Inventory.Events;
using Robust.Shared.Audio;
using Robust.Shared.Audio.Systems;
using Robust.Shared.Containers;
using Robust.Shared.Map;
using Robust.Shared.Utility;
Expand All @@ -23,7 +28,10 @@ public partial class SharedBodySystem
*/

[Dependency] private readonly InventorySystem _inventory = default!;

[Dependency] private readonly GibbingSystem _gibbingSystem = default!;
[Dependency] private readonly SharedAudioSystem _audioSystem = default!;
private const float GibletLaunchImpulse = 8;
private const float GibletLaunchImpulseVariance = 3;
private void InitializeBody()
{
// Body here to handle root body parts.
Expand Down Expand Up @@ -263,29 +271,47 @@ public IEnumerable<BodyPartSlot> GetBodyAllSlots(EntityUid bodyId, BodyComponent
}
}

public virtual HashSet<EntityUid> GibBody(EntityUid bodyId, bool gibOrgans = false,
BodyComponent? body = null, bool deleteItems = false, bool deleteBrain = false)
public virtual HashSet<EntityUid> GibBody(
EntityUid bodyId,
bool gibOrgans = false,
BodyComponent? body = null ,
bool deleteItems = false,
bool launchGibs = true,
Vector2? splatDirection = null,
float splatModifier = 1,
Angle splatCone = default,
SoundSpecifier? gibSound = null,
AudioParams? gibAudioParams = null
)
{
var gibs = new HashSet<EntityUid>();

if (!Resolve(bodyId, ref body, false))
return gibs;

var root = GetRootPartOrNull(bodyId, body);
if (root != null && TryComp(root.Value.Entity, out GibbableComponent? gibbable))
{
gibSound ??= gibbable.GibSound;
gibAudioParams ??= gibbable.GibAudioParams;
}
var parts = GetBodyChildren(bodyId, body).ToArray();
gibs.EnsureCapacity(parts.Length);

foreach (var part in parts)
{
SharedTransform.AttachToGridOrMap(part.Id);
gibs.Add(part.Id);

_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))
{
SharedTransform.AttachToGridOrMap(organ.Id);
gibs.Add(organ.Id);
_gibbingSystem.TryGibEntityWithRef(bodyId, organ.Id, GibType.Drop, GibContentsOption.Skip,
ref gibs, playAudio: false, launchImpulse: GibletLaunchImpulse* splatModifier,
launchImpulseVariance:GibletLaunchImpulseVariance, launchCone: splatCone);
}
}
if(TryComp<InventoryComponent>(bodyId, out var inventory))
Expand All @@ -296,6 +322,7 @@ public virtual HashSet<EntityUid> GibBody(EntityUid bodyId, bool gibOrgans = fal
gibs.Add(item);
}
}
_audioSystem.PlayPredicted(gibSound, Transform(bodyId).Coordinates, null, gibAudioParams);
return gibs;
}
}
40 changes: 40 additions & 0 deletions Content.Shared/Gibbing/Components/GibbableComponent.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
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");

/// <summary>
/// Max distance giblets can be dropped from an entity when NOT using physics-based scattering
/// </summary>
[DataField, AutoNetworkedField]
public float GibScatterRange = 0.3f;

/// <summary>
/// Audio parameters for when the gibbing sound is played
/// </summary>
[DataField, AutoNetworkedField]
public AudioParams GibAudioParams = AudioParams.Default.WithVariation(0.025f);
}
33 changes: 33 additions & 0 deletions Content.Shared/Gibbing/Events/GibbingEvents.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
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="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
}
Loading
Loading