using Content.Server.Body.Components; using Content.Server.Ghost; using Content.Server.Humanoid; using Content.Shared.Body.Components; using Content.Shared.Body.Part; using Content.Shared.Body.Systems; using Content.Shared.Humanoid; using Content.Shared.Mind; using Content.Shared.Mobs.Systems; using Content.Shared.Movement.Events; using Content.Shared.Movement.Systems; using Robust.Shared.Audio; using Robust.Shared.Timing; using System.Numerics; namespace Content.Server.Body.Systems; public sealed class BodySystem : SharedBodySystem { [Dependency] private readonly GhostSystem _ghostSystem = default!; [Dependency] private readonly IGameTiming _gameTiming = default!; [Dependency] private readonly HumanoidAppearanceSystem _humanoidSystem = default!; [Dependency] private readonly MobStateSystem _mobState = default!; [Dependency] private readonly SharedMindSystem _mindSystem = default!; public override void Initialize() { base.Initialize(); SubscribeLocalEvent(OnRelayMoveInput); SubscribeLocalEvent(OnApplyMetabolicMultiplier); } private void OnRelayMoveInput(Entity ent, ref MoveInputEvent args) { // If they haven't actually moved then ignore it. if ((args.Entity.Comp.HeldMoveButtons & (MoveButtons.Down | MoveButtons.Left | MoveButtons.Up | MoveButtons.Right)) == 0x0) { return; } if (_mobState.IsDead(ent) && _mindSystem.TryGetMind(ent, out var mindId, out var mind)) { mind.TimeOfDeath ??= _gameTiming.RealTime; _ghostSystem.OnGhostAttempt(mindId, canReturnGlobal: true, mind: mind); } } private void OnApplyMetabolicMultiplier( Entity ent, ref ApplyMetabolicMultiplierEvent args) { foreach (var organ in GetBodyOrgans(ent, ent)) { RaiseLocalEvent(organ.Id, ref args); } } protected override void AddPart( Entity bodyEnt, Entity partEnt, string slotId) { // TODO: Predict this probably. base.AddPart(bodyEnt, partEnt, slotId); var layer = partEnt.Comp.ToHumanoidLayers(); if (layer != null) { var layers = HumanoidVisualLayersExtension.Sublayers(layer.Value); _humanoidSystem.SetLayersVisibility(bodyEnt.Owner, layers, visible: true); } } protected override void RemovePart( Entity bodyEnt, Entity partEnt, string slotId) { base.RemovePart(bodyEnt, partEnt, slotId); if (!TryComp(bodyEnt, out var humanoid)) return; var layer = partEnt.Comp.ToHumanoidLayers(); if (layer is null) return; var layers = HumanoidVisualLayersExtension.Sublayers(layer.Value); _humanoidSystem.SetLayersVisibility((bodyEnt, humanoid), layers, visible: false); } public override HashSet 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(); } var xform = Transform(bodyId); if (xform.MapUid is null) return new HashSet(); 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; } }