diff --git a/Content.Client/MobState/States/DeadMobState.cs b/Content.Client/MobState/States/DeadMobState.cs index 3001f5be7b..d33840bc13 100644 --- a/Content.Client/MobState/States/DeadMobState.cs +++ b/Content.Client/MobState/States/DeadMobState.cs @@ -1,6 +1,6 @@ -using Content.Client.Standing; -using Content.Shared.MobState; +using Content.Shared.MobState; using Content.Shared.MobState.State; +using Content.Shared.Standing; using Robust.Client.GameObjects; using Robust.Shared.GameObjects; @@ -16,25 +16,6 @@ namespace Content.Client.MobState.States { appearance.SetData(DamageStateVisuals.State, DamageState.Dead); } - - EntitySystem.Get().Down(entity); - - if (entity.TryGetComponent(out PhysicsComponent? physics)) - { - physics.CanCollide = false; - } - } - - public override void ExitState(IEntity entity) - { - base.ExitState(entity); - - EntitySystem.Get().Standing(entity); - - if (entity.TryGetComponent(out PhysicsComponent? physics)) - { - physics.CanCollide = true; - } } } } diff --git a/Content.Client/MobState/States/NormalMobState.cs b/Content.Client/MobState/States/NormalMobState.cs index 19f55075c4..50ff19f492 100644 --- a/Content.Client/MobState/States/NormalMobState.cs +++ b/Content.Client/MobState/States/NormalMobState.cs @@ -7,14 +7,5 @@ namespace Content.Client.MobState.States { public class NormalMobState : SharedNormalMobState { - public override void EnterState(IEntity entity) - { - base.EnterState(entity); - - if (entity.TryGetComponent(out AppearanceComponent? appearance)) - { - appearance.SetData(DamageStateVisuals.State, DamageState.Alive); - } - } } } diff --git a/Content.Client/Standing/StandingStateSystem.cs b/Content.Client/Standing/StandingStateSystem.cs deleted file mode 100644 index 0268055fcc..0000000000 --- a/Content.Client/Standing/StandingStateSystem.cs +++ /dev/null @@ -1,42 +0,0 @@ -using Content.Shared.Rotation; -using Content.Shared.Standing; -using Robust.Client.GameObjects; -using Robust.Shared.GameObjects; - -namespace Content.Client.Standing -{ - public class StandingStateSystem : SharedStandingStateSystem - { - protected override bool OnDown(IEntity entity, bool playSound = true, bool dropItems = true, bool force = false) - { - if (!entity.TryGetComponent(out AppearanceComponent? appearance)) - { - return false; - } - - var newState = RotationState.Horizontal; - appearance.TryGetData(RotationVisuals.RotationState, out var oldState); - - if (newState != oldState) - { - appearance.SetData(RotationVisuals.RotationState, newState); - } - - return true; - } - - protected override bool OnStand(IEntity entity) - { - if (!entity.TryGetComponent(out AppearanceComponent? appearance)) return false; - - appearance.TryGetData(RotationVisuals.RotationState, out var oldState); - var newState = RotationState.Vertical; - - if (newState == oldState) return false; - - appearance.SetData(RotationVisuals.RotationState, newState); - - return true; - } - } -} diff --git a/Content.IntegrationTests/Tests/Body/LegTest.cs b/Content.IntegrationTests/Tests/Body/LegTest.cs index e85fed07bb..2153606b5b 100644 --- a/Content.IntegrationTests/Tests/Body/LegTest.cs +++ b/Content.IntegrationTests/Tests/Body/LegTest.cs @@ -27,6 +27,7 @@ namespace Content.IntegrationTests.Tests.Body template: HumanoidTemplate preset: HumanPreset centerSlot: torso + - type: StandingState "; [Test] diff --git a/Content.IntegrationTests/Tests/Buckle/BuckleTest.cs b/Content.IntegrationTests/Tests/Buckle/BuckleTest.cs index c196876916..8f1fde6b2f 100644 --- a/Content.IntegrationTests/Tests/Buckle/BuckleTest.cs +++ b/Content.IntegrationTests/Tests/Buckle/BuckleTest.cs @@ -39,6 +39,7 @@ namespace Content.IntegrationTests.Tests.Buckle template: HumanoidTemplate preset: HumanPreset centerSlot: torso + - type: StandingState - type: entity name: {StrapDummyId} diff --git a/Content.Server/Buckle/Components/BuckleComponent.cs b/Content.Server/Buckle/Components/BuckleComponent.cs index d4b7da3142..2291bbb4e0 100644 --- a/Content.Server/Buckle/Components/BuckleComponent.cs +++ b/Content.Server/Buckle/Components/BuckleComponent.cs @@ -5,14 +5,13 @@ using Content.Server.Alert; using Content.Server.Hands.Components; using Content.Server.MobState.States; using Content.Server.Pulling; -using Content.Server.Standing; using Content.Server.Stunnable.Components; using Content.Shared.ActionBlocker; using Content.Shared.Alert; using Content.Shared.Buckle.Components; -using Content.Shared.Interaction.Events; using Content.Shared.Interaction.Helpers; using Content.Shared.Notification.Managers; +using Content.Shared.Standing; using Content.Shared.Verbs; using Robust.Server.GameObjects; using Robust.Shared.Audio; @@ -130,12 +129,12 @@ namespace Content.Server.Buckle.Components ownTransform.WorldRotation = strapTransform.WorldRotation; break; case StrapPosition.Stand: - EntitySystem.Get().Standing(Owner); + EntitySystem.Get().Stand(Owner); ownTransform.WorldRotation = strapTransform.WorldRotation; break; case StrapPosition.Down: - EntitySystem.Get().Down(Owner, force: true); - ownTransform.WorldRotation = Angle.South; + EntitySystem.Get().Down(Owner, false, false); + ownTransform.LocalRotation = Angle.Zero; break; } @@ -343,7 +342,7 @@ namespace Content.Server.Buckle.Components } else { - EntitySystem.Get().Standing(Owner); + EntitySystem.Get().Stand(Owner); } _mobState?.CurrentState?.EnterState(Owner); diff --git a/Content.Server/Hands/HandsSystem.cs b/Content.Server/Hands/HandsSystem.cs index a96c8e2693..86c07fa909 100644 --- a/Content.Server/Hands/HandsSystem.cs +++ b/Content.Server/Hands/HandsSystem.cs @@ -50,6 +50,18 @@ namespace Content.Server.Hands CommandBinds.Unregister(); } + protected override void DropAllItemsInHands(IEntity entity, bool doMobChecks = true) + { + base.DropAllItemsInHands(entity, doMobChecks); + + if (!entity.TryGetComponent(out IHandsComponent? hands)) return; + + foreach (var heldItem in hands.GetAllHeldItems()) + { + hands.Drop(heldItem.Owner, doMobChecks, intentional:false); + } + } + //TODO: Actually shows all items/clothing/etc. private void HandleExamined(EntityUid uid, HandsComponent component, ExaminedEvent args) { diff --git a/Content.Server/Instruments/InstrumentComponent.cs b/Content.Server/Instruments/InstrumentComponent.cs index e9099119f8..62749507e2 100644 --- a/Content.Server/Instruments/InstrumentComponent.cs +++ b/Content.Server/Instruments/InstrumentComponent.cs @@ -1,7 +1,6 @@ #nullable enable using System; using System.Linq; -using Content.Server.Standing; using Content.Server.Stunnable.Components; using Content.Server.UserInterface; using Content.Shared.ActionBlocker; @@ -9,8 +8,8 @@ using Content.Shared.DragDrop; using Content.Shared.Hands; using Content.Shared.Instruments; using Content.Shared.Interaction; -using Content.Shared.Interaction.Events; using Content.Shared.Notification.Managers; +using Content.Shared.Standing; using Content.Shared.Throwing; using Robust.Server.GameObjects; using Robust.Server.Player; @@ -357,7 +356,7 @@ namespace Content.Server.Instruments if (mob != null) { if (Handheld) - EntitySystem.Get().DropAllItemsInHands(mob, false); + EntitySystem.Get().Down(mob, false); if (mob.TryGetComponent(out StunnableComponent? stun)) { diff --git a/Content.Server/MobState/States/CriticalMobState.cs b/Content.Server/MobState/States/CriticalMobState.cs index 3b0afbc510..17a03ac1ee 100644 --- a/Content.Server/MobState/States/CriticalMobState.cs +++ b/Content.Server/MobState/States/CriticalMobState.cs @@ -1,8 +1,5 @@ -using Content.Server.Standing; -using Content.Server.Stunnable.Components; -using Content.Shared.MobState; +using Content.Server.Stunnable.Components; using Content.Shared.MobState.State; -using Robust.Server.GameObjects; using Robust.Shared.GameObjects; namespace Content.Server.MobState.States @@ -13,17 +10,10 @@ namespace Content.Server.MobState.States { base.EnterState(entity); - if (entity.TryGetComponent(out AppearanceComponent? appearance)) - { - appearance.SetData(DamageStateVisuals.State, DamageState.Critical); - } - if (entity.TryGetComponent(out StunnableComponent? stun)) { stun.CancelAll(); } - - EntitySystem.Get().Down(entity); } } } diff --git a/Content.Server/MobState/States/DeadMobState.cs b/Content.Server/MobState/States/DeadMobState.cs index 1cad5f05d0..2379afe0ef 100644 --- a/Content.Server/MobState/States/DeadMobState.cs +++ b/Content.Server/MobState/States/DeadMobState.cs @@ -1,5 +1,4 @@ using Content.Server.Alert; -using Content.Server.Standing; using Content.Server.Stunnable.Components; using Content.Shared.Alert; using Content.Shared.MobState; @@ -15,11 +14,6 @@ namespace Content.Server.MobState.States { base.EnterState(entity); - if (entity.TryGetComponent(out AppearanceComponent? appearance)) - { - appearance.SetData(DamageStateVisuals.State, DamageState.Dead); - } - if (entity.TryGetComponent(out ServerAlertsComponent? status)) { status.ShowAlert(AlertType.HumanDead); @@ -29,8 +23,6 @@ namespace Content.Server.MobState.States { stun.CancelAll(); } - - EntitySystem.Get().Down(entity); } } } diff --git a/Content.Server/MobState/States/NormalMobState.cs b/Content.Server/MobState/States/NormalMobState.cs index 1b7aeb03a4..780bee0cbf 100644 --- a/Content.Server/MobState/States/NormalMobState.cs +++ b/Content.Server/MobState/States/NormalMobState.cs @@ -1,29 +1,15 @@ #nullable enable using Content.Server.Alert; -using Content.Server.Standing; using Content.Shared.Alert; using Content.Shared.Damage.Components; using Content.Shared.MobState; using Content.Shared.MobState.State; -using Robust.Server.GameObjects; using Robust.Shared.GameObjects; namespace Content.Server.MobState.States { public class NormalMobState : SharedNormalMobState { - public override void EnterState(IEntity entity) - { - base.EnterState(entity); - - EntitySystem.Get().Standing(entity); - - if (entity.TryGetComponent(out AppearanceComponent? appearance)) - { - appearance.SetData(DamageStateVisuals.State, DamageState.Alive); - } - } - public override void UpdateState(IEntity entity, int threshold) { base.UpdateState(entity, threshold); diff --git a/Content.Server/Morgue/Components/BodyBagEntityStorageComponent.cs b/Content.Server/Morgue/Components/BodyBagEntityStorageComponent.cs index 7ab3aa7997..e35bcc1fb4 100644 --- a/Content.Server/Morgue/Components/BodyBagEntityStorageComponent.cs +++ b/Content.Server/Morgue/Components/BodyBagEntityStorageComponent.cs @@ -3,15 +3,14 @@ using System.Threading.Tasks; using Content.Server.Hands.Components; using Content.Server.Items; using Content.Server.Paper; -using Content.Server.Standing; using Content.Server.Storage.Components; using Content.Shared.ActionBlocker; using Content.Shared.Body.Components; using Content.Shared.Examine; using Content.Shared.Interaction; -using Content.Shared.Interaction.Events; using Content.Shared.Morgue; using Content.Shared.Notification.Managers; +using Content.Shared.Standing; using Content.Shared.Verbs; using Robust.Server.GameObjects; using Robust.Shared.Containers; @@ -39,7 +38,7 @@ namespace Content.Server.Morgue.Components { base.Initialize(); _appearance?.SetData(BodyBagVisuals.Label, false); - LabelContainer = ContainerHelpers.EnsureContainer(Owner, "body_bag_label", out _); + LabelContainer = Owner.EnsureContainer("body_bag_label", out _); } protected override bool AddToContents(IEntity entity) diff --git a/Content.Server/Morgue/Components/CrematoriumEntityStorageComponent.cs b/Content.Server/Morgue/Components/CrematoriumEntityStorageComponent.cs index e98d5d8ca9..cd254c9e70 100644 --- a/Content.Server/Morgue/Components/CrematoriumEntityStorageComponent.cs +++ b/Content.Server/Morgue/Components/CrematoriumEntityStorageComponent.cs @@ -131,11 +131,11 @@ namespace Content.Server.Morgue.Components } victim.PopupMessageOtherClients(Loc.GetString("crematorium-entity-storage-component-suicide-message-others", ("victim", victim))); - EntitySystem.Get().Down(victim, false, false, true); if (CanInsert(victim)) { Insert(victim); + EntitySystem.Get().Down(victim, false); } else { diff --git a/Content.Server/Morgue/Components/MorgueEntityStorageComponent.cs b/Content.Server/Morgue/Components/MorgueEntityStorageComponent.cs index 41d40c471c..5c6d77b47c 100644 --- a/Content.Server/Morgue/Components/MorgueEntityStorageComponent.cs +++ b/Content.Server/Morgue/Components/MorgueEntityStorageComponent.cs @@ -1,5 +1,4 @@ #nullable enable -using Content.Server.Standing; using Content.Server.Storage.Components; using Content.Shared.Body.Components; using Content.Shared.Directions; @@ -9,6 +8,7 @@ using Content.Shared.Interaction.Helpers; using Content.Shared.Morgue; using Content.Shared.Notification.Managers; using Content.Shared.Physics; +using Content.Shared.Standing; using Robust.Server.GameObjects; using Robust.Shared.Audio; using Robust.Shared.Containers; @@ -51,7 +51,7 @@ namespace Content.Server.Morgue.Components { base.Initialize(); Appearance?.SetData(MorgueVisuals.Open, false); - TrayContainer = ContainerHelpers.EnsureContainer(Owner, "morgue_tray", out _); + TrayContainer = Owner.EnsureContainer("morgue_tray", out _); } public override Vector2 ContentsDumpPosition() diff --git a/Content.Server/Standing/StandingStateSystem.cs b/Content.Server/Standing/StandingStateSystem.cs deleted file mode 100644 index b96a965abe..0000000000 --- a/Content.Server/Standing/StandingStateSystem.cs +++ /dev/null @@ -1,83 +0,0 @@ -#nullable enable -using Content.Server.Hands.Components; -using Content.Shared.Audio; -using Content.Shared.Rotation; -using Content.Shared.Standing; -using JetBrains.Annotations; -using Robust.Server.GameObjects; -using Robust.Shared.Audio; -using Robust.Shared.GameObjects; -using Robust.Shared.Player; - -namespace Content.Server.Standing -{ - [UsedImplicitly] - public class StandingStateSystem : SharedStandingStateSystem - { - protected override bool OnDown(IEntity entity, bool playSound = true, bool dropItems = true, bool force = false) - { - if (!entity.TryGetComponent(out AppearanceComponent? appearance)) - { - return false; - } - - var newState = RotationState.Horizontal; - appearance.TryGetData(RotationVisuals.RotationState, out var oldState); - - if (newState != oldState) - { - appearance.SetData(RotationVisuals.RotationState, newState); - - if (playSound) - { - var file = AudioHelpers.GetRandomFileFromSoundCollection("bodyfall"); - SoundSystem.Play(Filter.Pvs(entity), file, entity, AudioHelpers.WithVariation(0.25f)); - } - } - - return true; - } - - protected override bool OnStand(IEntity entity) - { - if (!entity.TryGetComponent(out AppearanceComponent? appearance)) return false; - - appearance.TryGetData(RotationVisuals.RotationState, out var oldState); - var newState = RotationState.Vertical; - - if (newState == oldState) return false; - - appearance.SetData(RotationVisuals.RotationState, newState); - - return true; - } - - public override void DropAllItemsInHands(IEntity entity, bool doMobChecks = true) - { - base.DropAllItemsInHands(entity, doMobChecks); - - if (!entity.TryGetComponent(out IHandsComponent? hands)) return; - - foreach (var heldItem in hands.GetAllHeldItems()) - { - hands.Drop(heldItem.Owner, doMobChecks, intentional:false); - } - } - - //TODO: RotationState can be null and I want to burn all lifeforms in the universe for this!!! - //If you use these it's atleast slightly less painful (null is treated as false) - public bool IsStanding(IEntity entity) - { - return entity.TryGetComponent(out var appearance) - && appearance.TryGetData(RotationVisuals.RotationState, out var rotation) - && rotation == RotationState.Vertical; - } - - public bool IsDown(IEntity entity) - { - return entity.TryGetComponent(out var appearance) - && appearance.TryGetData(RotationVisuals.RotationState, out var rotation) - && rotation == RotationState.Horizontal; - } - } -} diff --git a/Content.Server/Stunnable/Components/StunnableComponent.cs b/Content.Server/Stunnable/Components/StunnableComponent.cs index 29982e02ce..1fec345fdb 100644 --- a/Content.Server/Stunnable/Components/StunnableComponent.cs +++ b/Content.Server/Stunnable/Components/StunnableComponent.cs @@ -1,11 +1,10 @@ #nullable enable using Content.Server.Act; using Content.Server.Notification; -using Content.Server.Standing; using Content.Shared.Audio; using Content.Shared.MobState; -using Content.Shared.Notification; using Content.Shared.Notification.Managers; +using Content.Shared.Standing; using Content.Shared.Stunnable; using Robust.Shared.Audio; using Robust.Shared.GameObjects; @@ -28,7 +27,7 @@ namespace Content.Server.Stunnable.Components protected override void OnKnockdownEnd() { if(Owner.TryGetComponent(out IMobStateComponent? mobState) && !mobState.IsIncapacitated()) - EntitySystem.Get().Standing(Owner); + EntitySystem.Get().Stand(Owner); } public void CancelAll() @@ -46,7 +45,7 @@ namespace Content.Server.Stunnable.Components if (KnockedDown && Owner.TryGetComponent(out IMobStateComponent? mobState) && !mobState.IsIncapacitated()) { - EntitySystem.Get().Standing(Owner); + EntitySystem.Get().Stand(Owner); } KnockdownTimer = null; diff --git a/Content.Shared/Body/Components/SharedBodyComponent.cs b/Content.Shared/Body/Components/SharedBodyComponent.cs index b31e67f6a6..a0c67dafeb 100644 --- a/Content.Shared/Body/Components/SharedBodyComponent.cs +++ b/Content.Shared/Body/Components/SharedBodyComponent.cs @@ -189,7 +189,7 @@ namespace Content.Shared.Body.Components if (part.PartType == BodyPartType.Leg && GetPartsOfType(BodyPartType.Leg).ToArray().Length == 0) { - EntitySystem.Get().Down(Owner); + EntitySystem.Get().Down(Owner); } // creadth: immediately kill entity if last vital part removed diff --git a/Content.Shared/Buckle/Components/SharedBuckleComponent.cs b/Content.Shared/Buckle/Components/SharedBuckleComponent.cs index 6a9201f2fd..528c6eea74 100644 --- a/Content.Shared/Buckle/Components/SharedBuckleComponent.cs +++ b/Content.Shared/Buckle/Components/SharedBuckleComponent.cs @@ -48,10 +48,7 @@ namespace Content.Shared.Buckle.Components return !Buckled; } - bool IEffectBlocker.CanFall() - { - return !Buckled; - } + bool IEffectBlocker.CanFall() => !Buckled; bool IDraggable.CanDrop(CanDropEvent args) { diff --git a/Content.Shared/Buckle/SharedBuckleSystem.cs b/Content.Shared/Buckle/SharedBuckleSystem.cs index a15cf2ce17..2072ca2d2d 100644 --- a/Content.Shared/Buckle/SharedBuckleSystem.cs +++ b/Content.Shared/Buckle/SharedBuckleSystem.cs @@ -1,4 +1,5 @@ using Content.Shared.Buckle.Components; +using Content.Shared.Standing; using Robust.Shared.GameObjects; using Robust.Shared.Physics.Dynamics; @@ -10,6 +11,24 @@ namespace Content.Shared.Buckle { base.Initialize(); SubscribeLocalEvent(PreventCollision); + SubscribeLocalEvent(HandleDown); + SubscribeLocalEvent(HandleStand); + } + + private void HandleStand(EntityUid uid, SharedBuckleComponent component, StandAttemptEvent args) + { + if (component.Buckled) + { + args.Cancel(); + } + } + + private void HandleDown(EntityUid uid, SharedBuckleComponent component, DownAttemptEvent args) + { + if (component.Buckled) + { + args.Cancel(); + } } private void PreventCollision(EntityUid uid, SharedBuckleComponent component, PreventCollideEvent args) diff --git a/Content.Shared/EffectBlocker/EffectBlockerSystem.cs b/Content.Shared/EffectBlocker/EffectBlockerSystem.cs index 2a03ee2834..9494427f10 100644 --- a/Content.Shared/EffectBlocker/EffectBlockerSystem.cs +++ b/Content.Shared/EffectBlocker/EffectBlockerSystem.cs @@ -1,4 +1,5 @@ #nullable enable +using System; using Content.Shared.ActionBlocker; using JetBrains.Annotations; using Robust.Shared.GameObjects; diff --git a/Content.Shared/Hands/SharedHandsSystem.cs b/Content.Shared/Hands/SharedHandsSystem.cs index 923b864887..9a9bdec3d8 100644 --- a/Content.Shared/Hands/SharedHandsSystem.cs +++ b/Content.Shared/Hands/SharedHandsSystem.cs @@ -23,6 +23,38 @@ namespace Content.Shared.Hands SubscribeNetworkEvent(HandleDrop); } + public void DropHandItems(IEntity entity, bool doMobChecks = true) + { + if (!entity.TryGetComponent(out SharedHandsComponent? handsComponent)) return; + DropHandItems(handsComponent, doMobChecks); + } + + private void DropHandItems(SharedHandsComponent handsComponent, bool doMobChecks = true) + { + var msg = new DropHandItemsAttemptEvent(); + var entity = handsComponent.Owner; + var uid = entity.Uid; + var eventBus = EntityManager.EventBus; + + eventBus.RaiseLocalEvent(uid, msg); + + if (msg.Cancelled) return; + + if (entity.TryGetContainerMan(out var containerManager)) + { + var parentMsg = new ContainedEntityDropHandItemsAttemptEvent(uid); + eventBus.RaiseLocalEvent(containerManager.Owner.Uid, parentMsg); + + if (parentMsg.Cancelled) return; + } + + DropAllItemsInHands(entity, doMobChecks); + } + + protected virtual void DropAllItemsInHands(IEntity entity, bool doMobChecks = true) + { + } + private void HandleSetHand(RequestSetHandEvent msg, EntitySessionEventArgs eventArgs) { var entity = eventArgs.SenderSession?.AttachedEntity; @@ -46,6 +78,18 @@ namespace Content.Shared.Hands protected abstract void HandleContainerModified(EntityUid uid, SharedHandsComponent component, ContainerModifiedMessage args); } + public sealed class ContainedEntityDropHandItemsAttemptEvent : CancellableEntityEventArgs + { + public EntityUid EntityUid { get; } + + public ContainedEntityDropHandItemsAttemptEvent(EntityUid uid) + { + EntityUid = uid; + } + } + + public sealed class DropHandItemsAttemptEvent : CancellableEntityEventArgs {} + [Serializable, NetSerializable] public class RequestSetHandEvent : EntityEventArgs { diff --git a/Content.Shared/MobState/State/SharedCriticalMobState.cs b/Content.Shared/MobState/State/SharedCriticalMobState.cs index 663cb2e4ab..01ba1c36cb 100644 --- a/Content.Shared/MobState/State/SharedCriticalMobState.cs +++ b/Content.Shared/MobState/State/SharedCriticalMobState.cs @@ -1,5 +1,6 @@ #nullable enable using Content.Shared.Alert; +using Content.Shared.Hands; using Content.Shared.Standing; using Robust.Shared.GameObjects; @@ -20,13 +21,20 @@ namespace Content.Shared.MobState.State { status.ShowAlert(AlertType.HumanCrit); // TODO: combine humancrit-0 and humancrit-1 into a gif and display it } + + EntitySystem.Get().Down(entity); + + if (entity.TryGetComponent(out SharedAppearanceComponent? appearance)) + { + appearance.SetData(DamageStateVisuals.State, DamageState.Critical); + } } public override void ExitState(IEntity entity) { base.ExitState(entity); - EntitySystem.Get().Standing(entity); + EntitySystem.Get().Stand(entity); } public override bool CanInteract() diff --git a/Content.Shared/MobState/State/SharedDeadMobState.cs b/Content.Shared/MobState/State/SharedDeadMobState.cs index 81534db826..a511b3463a 100644 --- a/Content.Shared/MobState/State/SharedDeadMobState.cs +++ b/Content.Shared/MobState/State/SharedDeadMobState.cs @@ -1,4 +1,6 @@ -using Robust.Shared.GameObjects; +using Content.Shared.Hands; +using Content.Shared.Standing; +using Robust.Shared.GameObjects; namespace Content.Shared.MobState.State { @@ -11,6 +13,18 @@ namespace Content.Shared.MobState.State base.EnterState(entity); var wake = entity.EnsureComponent(); wake.Enabled = true; + var standingState = EntitySystem.Get(); + standingState.Down(entity); + + if (standingState.IsDown(entity) && entity.TryGetComponent(out PhysicsComponent? physics)) + { + physics.CanCollide = false; + } + + if (entity.TryGetComponent(out SharedAppearanceComponent? appearance)) + { + appearance.SetData(DamageStateVisuals.State, DamageState.Dead); + } } public override void ExitState(IEntity entity) @@ -20,6 +34,14 @@ namespace Content.Shared.MobState.State { entity.RemoveComponent(); } + + var standingState = EntitySystem.Get(); + standingState.Stand(entity); + + if (!standingState.IsDown(entity) && entity.TryGetComponent(out PhysicsComponent? physics)) + { + physics.CanCollide = true; + } } public override bool CanInteract() diff --git a/Content.Shared/MobState/State/SharedNormalMobState.cs b/Content.Shared/MobState/State/SharedNormalMobState.cs index eb5b069c8f..5f2b968bed 100644 --- a/Content.Shared/MobState/State/SharedNormalMobState.cs +++ b/Content.Shared/MobState/State/SharedNormalMobState.cs @@ -1,4 +1,7 @@ -#nullable enable +using Content.Shared.Standing; +using Robust.Shared.GameObjects; + +#nullable enable namespace Content.Shared.MobState.State { @@ -9,6 +12,17 @@ namespace Content.Shared.MobState.State { protected override DamageState DamageState => DamageState.Alive; + public override void EnterState(IEntity entity) + { + base.EnterState(entity); + EntitySystem.Get().Stand(entity); + + if (entity.TryGetComponent(out SharedAppearanceComponent? appearance)) + { + appearance.SetData(DamageStateVisuals.State, DamageState.Alive); + } + } + public override bool CanInteract() { return true; diff --git a/Content.Shared/NetIDs/ContentNetIDs.cs b/Content.Shared/NetIDs/ContentNetIDs.cs index 3a253444d0..6de59e53ac 100644 --- a/Content.Shared/NetIDs/ContentNetIDs.cs +++ b/Content.Shared/NetIDs/ContentNetIDs.cs @@ -100,6 +100,7 @@ namespace Content.Shared.NetIDs public const uint LIGHT_REPLACER = 1090; public const uint SINGULARITY_DISTORTION = 1091; public const uint GRAVITY = 1092; + public const uint STANDING_STATE = 1093; // Net IDs for integration tests. public const uint PREDICTION_TEST = 10001; diff --git a/Content.Shared/Standing/SharedStandingStateSystem.cs b/Content.Shared/Standing/SharedStandingStateSystem.cs deleted file mode 100644 index e03d302232..0000000000 --- a/Content.Shared/Standing/SharedStandingStateSystem.cs +++ /dev/null @@ -1,51 +0,0 @@ -#nullable enable -using Content.Shared.EffectBlocker; -using Robust.Shared.GameObjects; - -namespace Content.Shared.Standing -{ - public abstract class SharedStandingStateSystem : EntitySystem - { - protected abstract bool OnDown(IEntity entity, bool playSound = true, bool dropItems = true, - bool force = false); - - protected abstract bool OnStand(IEntity entity); - - /// - /// Set's the mob standing state to down. - /// - /// The mob in question - /// Whether to play a sound when falling down or not - /// Whether to make the mob drop all the items on his hands - /// Whether or not to check if the entity can fall. - /// False if the mob was already downed or couldn't set the state - public bool Down(IEntity entity, bool playSound = true, bool dropItems = true, bool force = false) - { - if (dropItems) - { - DropAllItemsInHands(entity, false); - } - - if (!force && !EffectBlockerSystem.CanFall(entity)) - { - return false; - } - - return OnDown(entity, playSound, dropItems, force); - } - - /// - /// Sets the mob's standing state to standing. - /// - /// The mob in question. - /// False if the mob was already standing or couldn't set the state - public bool Standing(IEntity entity) - { - return OnStand(entity); - } - - public virtual void DropAllItemsInHands(IEntity entity, bool doMobChecks = true) - { - } - } -} diff --git a/Content.Shared/Standing/StandingStateComponent.cs b/Content.Shared/Standing/StandingStateComponent.cs new file mode 100644 index 0000000000..1ed4fcd8c0 --- /dev/null +++ b/Content.Shared/Standing/StandingStateComponent.cs @@ -0,0 +1,54 @@ +using System; +using Content.Shared.EffectBlocker; +using Content.Shared.NetIDs; +using Robust.Shared.GameObjects; +using Robust.Shared.Players; +using Robust.Shared.Serialization; +using Robust.Shared.Serialization.Manager.Attributes; +using Robust.Shared.ViewVariables; + +namespace Content.Shared.Standing +{ + [RegisterComponent] + public sealed class StandingStateComponent : Component, IEffectBlocker + { + public override string Name => "StandingState"; + + public override uint? NetID => ContentNetIDs.STANDING_STATE; + + [ViewVariables(VVAccess.ReadWrite)] + [DataField("downSoundCollection")] + public string? DownSoundCollection { get; } = "BodyFall"; + + [ViewVariables] + [DataField("standing")] + public bool Standing { get; set; } = true; + + public bool CanFall() => Standing; + + public override ComponentState GetComponentState(ICommonSession player) + { + return new StandingComponentState(Standing); + } + + public override void HandleComponentState(ComponentState? curState, ComponentState? nextState) + { + base.HandleComponentState(curState, nextState); + if (curState is not StandingComponentState state) return; + + Standing = state.Standing; + } + + // I'm not calling it StandingStateComponentState + [Serializable, NetSerializable] + private sealed class StandingComponentState : ComponentState + { + public bool Standing { get; } + + public StandingComponentState(bool standing) : base(ContentNetIDs.STANDING_STATE) + { + Standing = standing; + } + } + } +} diff --git a/Content.Shared/Standing/StandingStateSystem.cs b/Content.Shared/Standing/StandingStateSystem.cs new file mode 100644 index 0000000000..51b98b7070 --- /dev/null +++ b/Content.Shared/Standing/StandingStateSystem.cs @@ -0,0 +1,126 @@ +#nullable enable +using Content.Shared.Audio; +using Content.Shared.Hands; +using Content.Shared.Rotation; +using Robust.Shared.Audio; +using Robust.Shared.GameObjects; +using Robust.Shared.Player; + +namespace Content.Shared.Standing +{ + public sealed class StandingStateSystem : EntitySystem + { + public bool IsDown(IEntity entity) + { + if (entity.TryGetComponent(out StandingStateComponent? standingState) && + standingState.Standing) return true; + + return false; + } + + public void Down(IEntity entity, bool playSound = true, bool dropHeldItems = true) + { + if (!entity.TryGetComponent(out StandingStateComponent? comp)) return; + Down(comp, playSound, dropHeldItems); + } + + public void Stand(IEntity entity) + { + if (!entity.TryGetComponent(out StandingStateComponent? comp)) return; + Stand(comp); + } + + public void Down(StandingStateComponent component, bool playSound = true, bool dropHeldItems = true) + { + if (!component.Standing) return; + + var entity = component.Owner; + var uid = entity.Uid; + + // This is just to avoid most callers doing this manually saving boilerplate + // 99% of the time you'll want to drop items but in some scenarios (e.g. buckling) you don't want to. + // We do this BEFORE downing because something like buckle may be blocking downing but we want to drop hand items anyway + // and ultimately this is just to avoid boilerplate in Down callers + keep their behavior consistent. + if (dropHeldItems) + { + Get().DropHandItems(entity, false); + } + + var msg = new DownAttemptEvent(); + EntityManager.EventBus.RaiseLocalEvent(uid, msg); + + if (msg.Cancelled) return; + + component.Standing = false; + component.Dirty(); + EntityManager.EventBus.RaiseLocalEvent(uid, new DownedEvent()); + + // Seemed like the best place to put it + if (entity.TryGetComponent(out SharedAppearanceComponent? appearance)) + { + appearance.SetData(RotationVisuals.RotationState, RotationState.Horizontal); + } + + // Currently shit is only downed by server but when it's predicted we can probably only play this on server / client + var sound = component.DownSoundCollection; + + if (playSound && !string.IsNullOrEmpty(sound)) + { + var file = AudioHelpers.GetRandomFileFromSoundCollection(sound); + SoundSystem.Play(Filter.Pvs(entity), file, entity, AudioHelpers.WithVariation(0.25f)); + } + } + + public void Stand(StandingStateComponent component) + { + if (component.Standing) return; + + var entity = component.Owner; + var uid = entity.Uid; + + var msg = new StandAttemptEvent(); + EntityManager.EventBus.RaiseLocalEvent(uid, msg); + + if (msg.Cancelled) return; + + component.Standing = true; + component.Dirty(); + EntityManager.EventBus.RaiseLocalEvent(uid, new StoodEvent()); + + if (entity.TryGetComponent(out SharedAppearanceComponent? appearance)) + { + appearance.SetData(RotationVisuals.RotationState, RotationState.Vertical); + } + } + } + + /// + /// Subscribe if you can potentially block a down attempt. + /// + public sealed class DownAttemptEvent : CancellableEntityEventArgs + { + + } + + /// + /// Subscribe if you can potentially block a stand attempt. + /// + public sealed class StandAttemptEvent : CancellableEntityEventArgs + { + + } + + /// + /// Raised when an entity becomes standing + /// + public sealed class StoodEvent : EntityEventArgs + { + } + + /// + /// Raised when an entity is not standing + /// + public sealed class DownedEvent : EntityEventArgs + { + } +} diff --git a/Resources/Prototypes/Entities/Mobs/Species/human.yml b/Resources/Prototypes/Entities/Mobs/Species/human.yml index 8c7b2f7b00..e4ee7b4b08 100644 --- a/Resources/Prototypes/Entities/Mobs/Species/human.yml +++ b/Resources/Prototypes/Entities/Mobs/Species/human.yml @@ -237,7 +237,7 @@ - type: Grammar attributes: proper: true - + - type: StandingState - type: entity save: false diff --git a/Resources/Prototypes/SoundCollections/body_fall.yml b/Resources/Prototypes/SoundCollections/body_fall.yml index c8f7097d58..1e74fb83f2 100644 --- a/Resources/Prototypes/SoundCollections/body_fall.yml +++ b/Resources/Prototypes/SoundCollections/body_fall.yml @@ -1,5 +1,5 @@ - type: soundCollection - id: bodyfall + id: BodyFall files: - /Audio/Effects/bodyfall1.ogg - /Audio/Effects/bodyfall2.ogg