From: Nemanja <98561806+EmoGarbage404@users.noreply.github.com> Date: Wed, 6 Aug 2025 19:01:20 +0000 (-0400) Subject: Miscellaneous Body Decoupling (#38958) X-Git-Url: https://git.smokeofanarchy.ru/gitweb.cgi?a=commitdiff_plain;h=9872a28d7f9c877ac3368be528cb11605b444636;p=space-station-14.git Miscellaneous Body Decoupling (#38958) --- diff --git a/Content.Client/Anomaly/Effects/ClientInnerBodySystem.cs b/Content.Client/Anomaly/Effects/ClientInnerBodySystem.cs index 15ebc8a993..d96980fb1d 100644 --- a/Content.Client/Anomaly/Effects/ClientInnerBodySystem.cs +++ b/Content.Client/Anomaly/Effects/ClientInnerBodySystem.cs @@ -1,6 +1,6 @@ using Content.Shared.Anomaly.Components; using Content.Shared.Anomaly.Effects; -using Content.Shared.Body.Components; +using Content.Shared.Humanoid; using Robust.Client.GameObjects; namespace Content.Client.Anomaly.Effects; @@ -25,9 +25,8 @@ public sealed class ClientInnerBodyAnomalySystem : SharedInnerBodyAnomalySystem var index = _sprite.LayerMapReserve((ent.Owner, sprite), ent.Comp.LayerMap); - if (TryComp(ent, out var body) && - body.Prototype is not null && - ent.Comp.SpeciesSprites.TryGetValue(body.Prototype.Value, out var speciesSprite)) + if (TryComp(ent, out var humanoidAppearance) && + ent.Comp.SpeciesSprites.TryGetValue(humanoidAppearance.Species, out var speciesSprite)) { _sprite.LayerSetSprite((ent.Owner, sprite), index, speciesSprite); } diff --git a/Content.Client/CardboardBox/CardboardBoxSystem.cs b/Content.Client/CardboardBox/CardboardBoxSystem.cs index e52ce03a76..ecebe16727 100644 --- a/Content.Client/CardboardBox/CardboardBoxSystem.cs +++ b/Content.Client/CardboardBox/CardboardBoxSystem.cs @@ -1,8 +1,8 @@ using System.Numerics; -using Content.Shared.Body.Components; using Content.Shared.CardboardBox; using Content.Shared.CardboardBox.Components; using Content.Shared.Examine; +using Content.Shared.Mobs.Components; using Content.Shared.Movement.Components; using Robust.Client.GameObjects; @@ -15,13 +15,13 @@ public sealed class CardboardBoxSystem : SharedCardboardBoxSystem [Dependency] private readonly ExamineSystemShared _examine = default!; [Dependency] private readonly SpriteSystem _sprite = default!; - private EntityQuery _bodyQuery; + private EntityQuery _mobStateQuery; public override void Initialize() { base.Initialize(); - _bodyQuery = GetEntityQuery(); + _mobStateQuery = GetEntityQuery(); SubscribeNetworkEvent(OnBoxEffect); } @@ -66,8 +66,8 @@ public sealed class CardboardBoxSystem : SharedCardboardBoxSystem if (!_examine.InRangeUnOccluded(sourcePos, mapPos, box.Distance, null)) continue; - // no effect for anything too exotic - if (!_bodyQuery.HasComp(mob)) + // no effect for non-mobs that have MobMover, such as mechs and vehicles. + if (!_mobStateQuery.HasComp(mob)) continue; var ent = Spawn(box.Effect, mapPos); diff --git a/Content.IntegrationTests/Tests/GameObjects/Components/ActionBlocking/HandCuffTest.cs b/Content.IntegrationTests/Tests/GameObjects/Components/ActionBlocking/HandCuffTest.cs index 2570e2246a..dae3203f9f 100644 --- a/Content.IntegrationTests/Tests/GameObjects/Components/ActionBlocking/HandCuffTest.cs +++ b/Content.IntegrationTests/Tests/GameObjects/Components/ActionBlocking/HandCuffTest.cs @@ -1,11 +1,9 @@ #nullable enable using Content.Server.Cuffs; -using Content.Shared.Body.Components; using Content.Shared.Cuffs.Components; using Content.Shared.Hands.Components; using Robust.Server.Console; using Robust.Shared.GameObjects; -using Robust.Shared.Map; namespace Content.IntegrationTests.Tests.GameObjects.Components.ActionBlocking { @@ -22,9 +20,15 @@ namespace Content.IntegrationTests.Tests.GameObjects.Components.ActionBlocking components: - type: Cuffable - type: Hands + hands: + hand_right: + location: Right + hand_left: + location: Left + sortedHands: + - hand_right + - hand_left - type: ComplexInteraction - - type: Body - prototype: Human - type: entity name: HandcuffsDummy @@ -47,7 +51,6 @@ namespace Content.IntegrationTests.Tests.GameObjects.Components.ActionBlocking HandsComponent hands = default!; var entityManager = server.ResolveDependency(); - var mapManager = server.ResolveDependency(); var host = server.ResolveDependency(); var map = await pair.CreateTestMap(); @@ -73,7 +76,6 @@ namespace Content.IntegrationTests.Tests.GameObjects.Components.ActionBlocking { Assert.That(entityManager.TryGetComponent(human, out cuffed!), $"Human has no {nameof(CuffableComponent)}"); Assert.That(entityManager.TryGetComponent(human, out hands!), $"Human has no {nameof(HandsComponent)}"); - Assert.That(entityManager.TryGetComponent(human, out BodyComponent? _), $"Human has no {nameof(BodyComponent)}"); Assert.That(entityManager.TryGetComponent(cuffs, out HandcuffComponent? _), $"Handcuff has no {nameof(HandcuffComponent)}"); Assert.That(entityManager.TryGetComponent(secondCuffs, out HandcuffComponent? _), $"Second handcuffs has no {nameof(HandcuffComponent)}"); }); diff --git a/Content.Server/Body/Systems/BrainSystem.cs b/Content.Server/Body/Systems/BrainSystem.cs index 86d2cb61ff..e916849a81 100644 --- a/Content.Server/Body/Systems/BrainSystem.cs +++ b/Content.Server/Body/Systems/BrainSystem.cs @@ -1,47 +1,46 @@ using Content.Server.Body.Components; using Content.Server.Ghost.Components; -using Content.Shared.Body.Components; using Content.Shared.Body.Events; using Content.Shared.Mind; using Content.Shared.Mind.Components; +using Content.Shared.Mobs.Components; using Content.Shared.Pointing; -namespace Content.Server.Body.Systems +namespace Content.Server.Body.Systems; + +public sealed class BrainSystem : EntitySystem { - public sealed class BrainSystem : EntitySystem - { - [Dependency] private readonly SharedMindSystem _mindSystem = default!; + [Dependency] private readonly SharedMindSystem _mindSystem = default!; - public override void Initialize() - { - base.Initialize(); + public override void Initialize() + { + base.Initialize(); - SubscribeLocalEvent((uid, _, args) => HandleMind(args.Body, uid)); - SubscribeLocalEvent((uid, _, args) => HandleMind(uid, args.OldBody)); - SubscribeLocalEvent(OnPointAttempt); - } + SubscribeLocalEvent((uid, _, args) => HandleMind(args.Body, uid)); + SubscribeLocalEvent((uid, _, args) => HandleMind(uid, args.OldBody)); + SubscribeLocalEvent(OnPointAttempt); + } - private void HandleMind(EntityUid newEntity, EntityUid oldEntity) - { - if (TerminatingOrDeleted(newEntity) || TerminatingOrDeleted(oldEntity)) - return; + private void HandleMind(EntityUid newEntity, EntityUid oldEntity) + { + if (TerminatingOrDeleted(newEntity) || TerminatingOrDeleted(oldEntity)) + return; - EnsureComp(newEntity); - EnsureComp(oldEntity); + EnsureComp(newEntity); + EnsureComp(oldEntity); - var ghostOnMove = EnsureComp(newEntity); - if (HasComp(newEntity)) - ghostOnMove.MustBeDead = true; + var ghostOnMove = EnsureComp(newEntity); + ghostOnMove.MustBeDead = HasComp(newEntity); // Don't ghost living players out of their bodies. - if (!_mindSystem.TryGetMind(oldEntity, out var mindId, out var mind)) - return; + if (!_mindSystem.TryGetMind(oldEntity, out var mindId, out var mind)) + return; - _mindSystem.TransferTo(mindId, newEntity, mind: mind); - } + _mindSystem.TransferTo(mindId, newEntity, mind: mind); + } - private void OnPointAttempt(Entity ent, ref PointAttemptEvent args) - { - args.Cancel(); - } + private void OnPointAttempt(Entity ent, ref PointAttemptEvent args) + { + args.Cancel(); } } + diff --git a/Content.Server/Cargo/Systems/PricingSystem.cs b/Content.Server/Cargo/Systems/PricingSystem.cs index 5e449eb8da..24ee4ffaf2 100644 --- a/Content.Server/Cargo/Systems/PricingSystem.cs +++ b/Content.Server/Cargo/Systems/PricingSystem.cs @@ -90,19 +90,22 @@ public sealed class PricingSystem : EntitySystem if (args.Handled) return; - if (!TryComp(uid, out var body) || !TryComp(uid, out var state)) + if (!TryComp(uid, out var state)) { - Log.Error($"Tried to get the mob price of {ToPrettyString(uid)}, which has no {nameof(BodyComponent)} and no {nameof(MobStateComponent)}."); + Log.Error($"Tried to get the mob price of {ToPrettyString(uid)}, which has no {nameof(MobStateComponent)}."); return; } - // TODO: Better handling of missing. - var partList = _bodySystem.GetBodyChildren(uid, body).ToList(); - var totalPartsPresent = partList.Sum(_ => 1); - var totalParts = partList.Count; + var partPenalty = 0.0; + if (TryComp(uid, out var body)) + { + var partList = _bodySystem.GetBodyChildren(uid, body).ToList(); + var totalPartsPresent = partList.Sum(_ => 1); + var totalParts = partList.Count; - var partRatio = totalPartsPresent / (double) totalParts; - var partPenalty = component.Price * (1 - partRatio) * component.MissingBodyPartPenalty; + var partRatio = totalPartsPresent / (double) totalParts; + partPenalty = component.Price * (1 - partRatio) * component.MissingBodyPartPenalty; + } args.Price += (component.Price - partPenalty) * (_mobStateSystem.IsAlive(uid, state) ? 1.0 : component.DeathPenalty); } diff --git a/Content.Server/Kitchen/EntitySystems/SharpSystem.cs b/Content.Server/Kitchen/EntitySystems/SharpSystem.cs index 0ba9d0990a..0275e4d1a7 100644 --- a/Content.Server/Kitchen/EntitySystems/SharpSystem.cs +++ b/Content.Server/Kitchen/EntitySystems/SharpSystem.cs @@ -117,19 +117,18 @@ public sealed class SharpSystem : EntitySystem popupEnt = Spawn(proto, coords.Offset(_robustRandom.NextVector2(0.25f))); } - var hasBody = TryComp(args.Args.Target.Value, out var body); - // only show a big popup when butchering living things. - var popupType = PopupType.Small; - if (hasBody) - popupType = PopupType.LargeCaution; + // Meant to differentiate cutting up clothes and cutting up your boss. + var popupType = HasComp(args.Args.Target.Value) + ? PopupType.LargeCaution + : PopupType.Small; _popupSystem.PopupEntity(Loc.GetString("butcherable-knife-butchered-success", ("target", args.Args.Target.Value), ("knife", Identity.Entity(uid, EntityManager))), - popupEnt, args.Args.User, popupType); - - if (hasBody) - _bodySystem.GibBody(args.Args.Target.Value, body: body); + popupEnt, + args.Args.User, + popupType); + _bodySystem.GibBody(args.Args.Target.Value); // does nothing if ent can't be gibbed _destructibleSystem.DestroyEntity(args.Args.Target.Value); args.Handled = true; diff --git a/Content.Server/Morgue/MorgueSystem.cs b/Content.Server/Morgue/MorgueSystem.cs index a07accf777..92ed16a06b 100644 --- a/Content.Server/Morgue/MorgueSystem.cs +++ b/Content.Server/Morgue/MorgueSystem.cs @@ -1,6 +1,6 @@ using Content.Server.Storage.Components; -using Content.Shared.Body.Components; using Content.Shared.Examine; +using Content.Shared.Mobs.Components; using Content.Shared.Morgue; using Content.Shared.Morgue.Components; using Robust.Shared.Audio.Systems; @@ -59,7 +59,7 @@ public sealed class MorgueSystem : EntitySystem foreach (var ent in storage.Contents.ContainedEntities) { - if (!hasMob && HasComp(ent)) + if (!hasMob && HasComp(ent)) hasMob = true; if (HasComp(ent)) diff --git a/Content.Shared/Anomaly/Components/InnerBodyAnomalyComponent.cs b/Content.Shared/Anomaly/Components/InnerBodyAnomalyComponent.cs index a7e07ae2b5..dfc1d561c4 100644 --- a/Content.Shared/Anomaly/Components/InnerBodyAnomalyComponent.cs +++ b/Content.Shared/Anomaly/Components/InnerBodyAnomalyComponent.cs @@ -1,5 +1,6 @@ using Content.Shared.Anomaly.Effects; using Content.Shared.Body.Prototypes; +using Content.Shared.Humanoid.Prototypes; using Robust.Shared.Audio; using Robust.Shared.GameStates; using Robust.Shared.Prototypes; @@ -62,7 +63,7 @@ public sealed partial class InnerBodyAnomalyComponent : Component /// Ability to use unique sprites for different body types /// [DataField, AutoNetworkedField] - public Dictionary, SpriteSpecifier> SpeciesSprites = new(); + public Dictionary, SpriteSpecifier> SpeciesSprites = new(); /// /// The key of the entity layer into which the sprite will be inserted diff --git a/Content.Shared/Disposal/Unit/SharedDisposalUnitSystem.cs b/Content.Shared/Disposal/Unit/SharedDisposalUnitSystem.cs index bdf8b5ba07..292cfd2b3c 100644 --- a/Content.Shared/Disposal/Unit/SharedDisposalUnitSystem.cs +++ b/Content.Shared/Disposal/Unit/SharedDisposalUnitSystem.cs @@ -1,7 +1,6 @@ using System.Linq; using Content.Shared.ActionBlocker; using Content.Shared.Administration.Logs; -using Content.Shared.Body.Components; using Content.Shared.Climbing.Systems; using Content.Shared.Containers; using Content.Shared.Database; @@ -15,6 +14,7 @@ using Content.Shared.Hands.EntitySystems; using Content.Shared.IdentityManagement; using Content.Shared.Interaction; using Content.Shared.Item; +using Content.Shared.Mobs.Components; using Content.Shared.Movement.Events; using Content.Shared.Popups; using Content.Shared.Power; @@ -450,7 +450,7 @@ public abstract class SharedDisposalUnitSystem : EntitySystem return false; var storable = HasComp(entity); - if (!storable && !HasComp(entity)) + if (!storable && !HasComp(entity)) return false; if (_whitelistSystem.IsBlacklistPass(component.Blacklist, entity) || diff --git a/Content.Shared/Morgue/EntityStorageLayingDownOverrideSystem.cs b/Content.Shared/Morgue/EntityStorageLayingDownOverrideSystem.cs index 9341168ba3..630135f36a 100644 --- a/Content.Shared/Morgue/EntityStorageLayingDownOverrideSystem.cs +++ b/Content.Shared/Morgue/EntityStorageLayingDownOverrideSystem.cs @@ -1,4 +1,3 @@ -using Content.Shared.Body.Components; using Content.Shared.Morgue.Components; using Content.Shared.Standing; using Content.Shared.Storage.Components; @@ -20,7 +19,9 @@ public sealed class EntityStorageLayingDownOverrideSystem : EntitySystem { foreach (var ent in args.Contents) { - if (HasComp(ent) && !_standing.IsDown(ent)) + // Explicitly check for standing state component, as entities without it will return false for IsDown() + // which prevents inserting any kind of non-mobs into this container (which is unintended) + if (TryComp(ent, out var standingState) && !_standing.IsDown(ent, standingState)) args.Contents.Remove(ent); } } diff --git a/Content.Shared/Storage/EntitySystems/SharedEntityStorageSystem.cs b/Content.Shared/Storage/EntitySystems/SharedEntityStorageSystem.cs index 2b73a9349f..fd7cb87b2a 100644 --- a/Content.Shared/Storage/EntitySystems/SharedEntityStorageSystem.cs +++ b/Content.Shared/Storage/EntitySystems/SharedEntityStorageSystem.cs @@ -16,6 +16,7 @@ using Content.Shared.Verbs; using Content.Shared.Wall; using Content.Shared.Whitelist; using Content.Shared.ActionBlocker; +using Content.Shared.Mobs.Components; using Robust.Shared.Audio.Systems; using Robust.Shared.Containers; using Robust.Shared.GameStates; @@ -355,7 +356,7 @@ public abstract class SharedEntityStorageSystem : EntitySystem return _whitelistSystem.IsValid(component.Whitelist, toInsert); // The inserted entity must be a mob or an item. - return HasComp(toInsert) || HasComp(toInsert); + return HasComp(toInsert) || HasComp(toInsert); } public bool TryOpenStorage(EntityUid user, EntityUid target, bool silent = false) diff --git a/Resources/Prototypes/Entities/Objects/Misc/implanters.yml b/Resources/Prototypes/Entities/Objects/Misc/implanters.yml index 79432e6fc1..e1918ef5e6 100644 --- a/Resources/Prototypes/Entities/Objects/Misc/implanters.yml +++ b/Resources/Prototypes/Entities/Objects/Misc/implanters.yml @@ -13,7 +13,7 @@ - type: Implanter whitelist: components: - - Body # no chair microbomb + - MobState # no chair microbomb blacklist: components: - Guardian # no holoparasite macrobomb wombo combo diff --git a/Resources/Prototypes/Entities/Objects/Weapons/Bombs/spider.yml b/Resources/Prototypes/Entities/Objects/Weapons/Bombs/spider.yml index d00297a723..3d7991cf0f 100644 --- a/Resources/Prototypes/Entities/Objects/Weapons/Bombs/spider.yml +++ b/Resources/Prototypes/Entities/Objects/Weapons/Bombs/spider.yml @@ -28,7 +28,7 @@ components: - Anchorable - Item - - Body + - MobState - type: Explosive # Powerful explosion in a large radius. Will break underplating. explosionType: DemolitionCharge totalIntensity: 360 diff --git a/Resources/Prototypes/Entities/Objects/Weapons/Guns/Projectiles/magic.yml b/Resources/Prototypes/Entities/Objects/Weapons/Guns/Projectiles/magic.yml index 9e2b6d76c1..d1b50429f9 100644 --- a/Resources/Prototypes/Entities/Objects/Weapons/Guns/Projectiles/magic.yml +++ b/Resources/Prototypes/Entities/Objects/Weapons/Guns/Projectiles/magic.yml @@ -93,7 +93,7 @@ disableWhenFirstOpened: true whitelist: components: - - Body + - MobState - type: LockVisuals stateLocked: cursed_door stateUnlocked: decursed_door @@ -191,7 +191,7 @@ - type: WhitelistTriggerCondition userWhitelist: components: - - Body + - MobState - type: entity id: ProjectilePolyboltMonkey @@ -205,7 +205,7 @@ - type: WhitelistTriggerCondition userWhitelist: components: - - Body + - MobState - type: entity id: ProjectilePolyboltDoor @@ -275,7 +275,7 @@ - type: WhitelistTriggerCondition userWhitelist: components: - - Body + - MobState - type: entity id: ProjectileIcicle @@ -305,4 +305,4 @@ - type: WhitelistTriggerCondition userWhitelist: components: - - Body + - MobState diff --git a/Resources/Prototypes/Magic/mindswap_spell.yml b/Resources/Prototypes/Magic/mindswap_spell.yml index 8039f12074..0a28a9683b 100644 --- a/Resources/Prototypes/Magic/mindswap_spell.yml +++ b/Resources/Prototypes/Magic/mindswap_spell.yml @@ -14,7 +14,7 @@ - type: EntityTargetAction whitelist: components: - - Body # this also allows borgs because that supercode uses Body for no reason + - MobState - PAI # intended to mindswap pAIs and AIs - StationAiCore event: !type:MindSwapSpellEvent diff --git a/Resources/Prototypes/Magic/touch_spells.yml b/Resources/Prototypes/Magic/touch_spells.yml index ba62a76421..f3b44eabb1 100644 --- a/Resources/Prototypes/Magic/touch_spells.yml +++ b/Resources/Prototypes/Magic/touch_spells.yml @@ -12,7 +12,7 @@ - type: EntityTargetAction whitelist: components: - - Body + - MobState canTargetSelf: false - type: entity