diff --git a/Content.Server/Tiles/LavaSystem.cs b/Content.Server/Tiles/LavaSystem.cs index bdba76784e..7aee0b6501 100644 --- a/Content.Server/Tiles/LavaSystem.cs +++ b/Content.Server/Tiles/LavaSystem.cs @@ -15,7 +15,6 @@ public sealed class LavaSystem : EntitySystem SubscribeLocalEvent(OnLavaStepTriggerAttempt); } - private void OnLavaStepTriggerAttempt(EntityUid uid, LavaComponent component, ref StepTriggerAttemptEvent args) { if (!HasComp(args.Tripper)) diff --git a/Content.Shared/Chasm/ChasmSystem.cs b/Content.Shared/Chasm/ChasmSystem.cs index 123fa5b998..7353bd0e9c 100644 --- a/Content.Shared/Chasm/ChasmSystem.cs +++ b/Content.Shared/Chasm/ChasmSystem.cs @@ -1,4 +1,5 @@ using Content.Shared.ActionBlocker; +using Content.Shared.Buckle.Components; using Content.Shared.Movement.Events; using Content.Shared.StepTrigger.Systems; using Robust.Shared.Network; @@ -51,18 +52,22 @@ public sealed class ChasmSystem : EntitySystem if (HasComp(args.Tripper)) return; - var falling = AddComp(args.Tripper); + StartFalling(uid, component, args.Tripper); + } + + public void StartFalling(EntityUid chasm, ChasmComponent component, EntityUid tripper, bool playSound = true) + { + var falling = AddComp(tripper); falling.NextDeletionTime = _timing.CurTime + falling.DeletionTime; - _blocker.UpdateCanMove(args.Tripper); - _audio.PlayPredicted(component.FallingSound, uid, args.Tripper); + _blocker.UpdateCanMove(tripper); + + if (playSound) + _audio.PlayPredicted(component.FallingSound, chasm, tripper); } private void OnStepTriggerAttempt(EntityUid uid, ChasmComponent component, ref StepTriggerAttemptEvent args) { - if (TryComp(args.Tripper, out var physics) && physics.BodyStatus == BodyStatus.InAir) - return; - args.Continue = true; } diff --git a/Content.Shared/Movement/Components/CanMoveInAirComponent.cs b/Content.Shared/Movement/Components/CanMoveInAirComponent.cs new file mode 100644 index 0000000000..9d24661700 --- /dev/null +++ b/Content.Shared/Movement/Components/CanMoveInAirComponent.cs @@ -0,0 +1,12 @@ +using Robust.Shared.GameStates; +using Robust.Shared.Physics.Components; + +namespace Content.Shared.Movement.Components; + +/// +/// On mobs that are allowed to move while their body status is +/// +[RegisterComponent, NetworkedComponent] +public sealed partial class CanMoveInAirComponent : Component +{ +} diff --git a/Content.Shared/Movement/Systems/SharedJetpackSystem.cs b/Content.Shared/Movement/Systems/SharedJetpackSystem.cs index f5516d9ec9..26373da256 100644 --- a/Content.Shared/Movement/Systems/SharedJetpackSystem.cs +++ b/Content.Shared/Movement/Systems/SharedJetpackSystem.cs @@ -6,6 +6,8 @@ using Content.Shared.Movement.Events; using Content.Shared.Popups; using Robust.Shared.Containers; using Robust.Shared.GameStates; +using Robust.Shared.Physics.Components; +using Robust.Shared.Physics.Systems; using Robust.Shared.Serialization; namespace Content.Shared.Movement.Systems; @@ -17,6 +19,7 @@ public abstract class SharedJetpackSystem : EntitySystem [Dependency] protected readonly SharedContainerSystem Container = default!; [Dependency] private readonly SharedMoverController _mover = default!; [Dependency] private readonly SharedPopupSystem _popup = default!; + [Dependency] private readonly SharedPhysicsSystem _physics = default!; public override void Initialize() { @@ -98,6 +101,10 @@ public abstract class SharedJetpackSystem : EntitySystem { var userComp = EnsureComp(user); _mover.SetRelay(user, jetpackUid); + + if (TryComp(user, out var physics)) + _physics.SetBodyStatus(physics, BodyStatus.InAir); + userComp.Jetpack = jetpackUid; } @@ -106,6 +113,9 @@ public abstract class SharedJetpackSystem : EntitySystem if (!RemComp(uid)) return; + if (TryComp(uid, out var physics)) + _physics.SetBodyStatus(physics, BodyStatus.OnGround); + RemComp(uid); } diff --git a/Content.Shared/Movement/Systems/SharedMoverController.cs b/Content.Shared/Movement/Systems/SharedMoverController.cs index 725cc274c0..2b95b5909f 100644 --- a/Content.Shared/Movement/Systems/SharedMoverController.cs +++ b/Content.Shared/Movement/Systems/SharedMoverController.cs @@ -53,6 +53,7 @@ namespace Content.Shared.Movement.Systems protected EntityQuery RelayQuery; protected EntityQuery PullableQuery; protected EntityQuery XformQuery; + protected EntityQuery CanMoveInAirQuery; private const float StepSoundMoveDistanceRunning = 2; private const float StepSoundMoveDistanceWalking = 1.5f; @@ -83,6 +84,7 @@ namespace Content.Shared.Movement.Systems RelayQuery = GetEntityQuery(); PullableQuery = GetEntityQuery(); XformQuery = GetEntityQuery(); + CanMoveInAirQuery = GetEntityQuery(); InitializeFootsteps(); InitializeInput(); @@ -150,27 +152,16 @@ namespace Content.Shared.Movement.Systems LerpRotation(uid, mover, frameTime); if (!canMove - || physicsComponent.BodyStatus != BodyStatus.OnGround + || physicsComponent.BodyStatus != BodyStatus.OnGround && !CanMoveInAirQuery.HasComponent(uid) || PullableQuery.TryGetComponent(uid, out var pullable) && pullable.BeingPulled) { UsedMobMovement[uid] = false; return; } - // Get current tile def for things like speed/weightless mods - ContentTileDefinition? tileDef = null; - - if (_mapManager.TryFindGridAt(xform.MapPosition, out var grid, out var gridComp) - && _mapSystem.TryGetTileRef(grid, gridComp, xform.Coordinates, out var tile)) - { - tileDef = (ContentTileDefinition) _tileDefinitionManager[tile.Tile.TypeId]; - } UsedMobMovement[uid] = true; // Specifically don't use mover.Owner because that may be different to the actual physics body being moved. - - // We differentiate between grav/other sources of weightless for tiles which want to use weightless accel (like ice) - // but don't care about requiring touching etc var weightless = _gravity.IsWeightless(physicsUid, physicsComponent, xform); var (walkDir, sprintDir) = GetVelocityInput(mover); var touching = false; @@ -193,6 +184,18 @@ namespace Content.Shared.Movement.Systems } } + // Get current tile def for things like speed/friction mods + ContentTileDefinition? tileDef = null; + + // Don't bother getting the tiledef here if we're weightless or in-air + // since no tile-based modifiers should be applying in that situation + if (_mapManager.TryFindGridAt(xform.MapPosition, out var grid, out var gridComp) + && _mapSystem.TryGetTileRef(grid, gridComp, xform.Coordinates, out var tile) + && !(weightless || physicsComponent.BodyStatus == BodyStatus.InAir)) + { + tileDef = (ContentTileDefinition) _tileDefinitionManager[tile.Tile.TypeId]; + } + // Regular movement. // Target velocity. // This is relative to the map / grid we're on. diff --git a/Content.Shared/Singularity/EntitySystems/SharedSingularitySystem.cs b/Content.Shared/Singularity/EntitySystems/SharedSingularitySystem.cs index 676987b017..56be197e1d 100644 --- a/Content.Shared/Singularity/EntitySystems/SharedSingularitySystem.cs +++ b/Content.Shared/Singularity/EntitySystems/SharedSingularitySystem.cs @@ -354,7 +354,6 @@ public abstract class SharedSingularitySystem : EntitySystem /// The event arguments. private void UpdateBody(EntityUid uid, PhysicsComponent comp, SingularityLevelChangedEvent args) { - _physics.SetBodyStatus(comp, (args.NewValue > 1) ? BodyStatus.InAir : BodyStatus.OnGround); if (args.NewValue <= 1 && args.OldValue > 1) // Apparently keeps singularities from getting stuck in the corners of containment fields. _physics.SetLinearVelocity(uid, Vector2.Zero, body: comp); // No idea how stopping the singularities movement keeps it from getting stuck though. } diff --git a/Content.Shared/StepTrigger/Components/StepTriggerComponent.cs b/Content.Shared/StepTrigger/Components/StepTriggerComponent.cs index 7c84e54bdc..21cf5397a1 100644 --- a/Content.Shared/StepTrigger/Components/StepTriggerComponent.cs +++ b/Content.Shared/StepTrigger/Components/StepTriggerComponent.cs @@ -42,10 +42,17 @@ public sealed partial class StepTriggerComponent : Component public float RequiredTriggerSpeed = 3.5f; /// - /// If any entities occupy the blacklist on the same tile then steptrigger won't work. + /// If any entities occupy the blacklist on the same tile then steptrigger won't work. /// [DataField("blacklist")] public EntityWhitelist? Blacklist; + + /// + /// If this is true, steptrigger will still occur on entities that are in air / weightless. They do not + /// by default. + /// + [DataField("ignoreWeightless")] + public bool IgnoreWeightless = false; } [RegisterComponent] diff --git a/Content.Shared/StepTrigger/Systems/StepTriggerSystem.cs b/Content.Shared/StepTrigger/Systems/StepTriggerSystem.cs index 081262de0f..335d9bea9f 100644 --- a/Content.Shared/StepTrigger/Systems/StepTriggerSystem.cs +++ b/Content.Shared/StepTrigger/Systems/StepTriggerSystem.cs @@ -1,3 +1,4 @@ +using Content.Shared.Gravity; using Content.Shared.StepTrigger.Components; using Robust.Shared.GameStates; using Robust.Shared.Map.Components; @@ -10,6 +11,7 @@ namespace Content.Shared.StepTrigger.Systems; public sealed class StepTriggerSystem : EntitySystem { [Dependency] private readonly EntityLookupSystem _entityLookup = default!; + [Dependency] private readonly SharedGravitySystem _gravity = default!; public override void Initialize() { @@ -121,6 +123,13 @@ public sealed class StepTriggerSystem : EntitySystem if (!component.Active || component.CurrentlySteppedOn.Contains(otherUid)) return false; + // Can't trigger if we don't ignore weightless entities + // and the entity is flying or currently weightless + // Makes sense simulation wise to have this be part of steptrigger directly IMO + if (!component.IgnoreWeightless && TryComp(otherUid, out var physics) && + (physics.BodyStatus == BodyStatus.InAir || _gravity.IsWeightless(otherUid, physics))) + return false; + var msg = new StepTriggerAttemptEvent { Source = uid, Tripper = otherUid }; RaiseLocalEvent(uid, ref msg, true); diff --git a/Resources/Prototypes/Entities/Mobs/NPCs/animals.yml b/Resources/Prototypes/Entities/Mobs/NPCs/animals.yml index 7ff922bc01..bd339291f0 100644 --- a/Resources/Prototypes/Entities/Mobs/NPCs/animals.yml +++ b/Resources/Prototypes/Entities/Mobs/NPCs/animals.yml @@ -1,6 +1,6 @@ - type: entity name: bat - parent: SimpleMobBase + parent: [ SimpleMobBase, FlyingMobBase ] id: MobBat description: Some cultures find them terrifying, others crunchy on the teeth. components: @@ -13,7 +13,6 @@ - map: ["enum.DamageStateVisualLayers.Base"] state: bat sprite: Mobs/Animals/bat.rsi - - type: Physics - type: Speech speechSounds: Squeak speechVerb: SmallMob @@ -59,7 +58,6 @@ damage: types: Piercing: 5 - - type: NoSlip - type: Puller needsHands: true - type: Tag @@ -68,7 +66,7 @@ - type: entity name: bee - parent: SimpleMobBase + parent: [ SimpleMobBase, FlyingMobBase ] id: MobBee description: Nice to have, but you can't build a civilization on a foundation of honey alone. components: @@ -82,7 +80,6 @@ - map: ["enum.DamageStateVisualLayers.Base"] state: 0 sprite: Mobs/Animals/bee.rsi - - type: Physics - type: Fixtures fixtures: fix1: @@ -112,7 +109,6 @@ - Bee - type: Bloodstream bloodMaxVolume: 0.1 - - type: NoSlip - type: MobPrice price: 50 - type: Puller @@ -354,7 +350,7 @@ - type: entity name: butterfly - parent: SimpleMobBase + parent: [ SimpleMobBase, FlyingMobBase ] id: MobButterfly description: Despite popular misconceptions, it's not actually made of butter. components: @@ -367,7 +363,6 @@ - map: ["enum.DamageStateVisualLayers.Base"] state: butterfly sprite: Mobs/Animals/butterfly.rsi - - type: Physics - type: Fixtures fixtures: fix1: @@ -396,7 +391,6 @@ Base: dead - type: Bloodstream bloodMaxVolume: 0.1 - - type: NoSlip - type: MobPrice price: 50 - type: Puller @@ -1233,7 +1227,7 @@ # Would be cool to have some functionality for the parrot to be able to sit on stuff - type: entity name: parrot - parent: SimpleMobBase + parent: [ SimpleMobBase, FlyingMobBase ] id: MobParrot description: Infiltrates your domain, spies on you, and somehow still a cool pet. components: @@ -1246,7 +1240,6 @@ - map: ["enum.DamageStateVisualLayers.Base"] state: parrot sprite: Mobs/Animals/parrot.rsi - - type: Physics - type: Fixtures fixtures: fix1: @@ -1276,7 +1269,6 @@ path: /Audio/Animals/parrot_raught.ogg - type: Bloodstream bloodMaxVolume: 50 - - type: NoSlip - type: entity name: penguin diff --git a/Resources/Prototypes/Entities/Mobs/NPCs/behonker.yml b/Resources/Prototypes/Entities/Mobs/NPCs/behonker.yml index a613c7c4ad..cb7b9f4c01 100644 --- a/Resources/Prototypes/Entities/Mobs/NPCs/behonker.yml +++ b/Resources/Prototypes/Entities/Mobs/NPCs/behonker.yml @@ -1,6 +1,6 @@ - type: entity name: behonker - parent: SimpleSpaceMobBase + parent: [ SimpleSpaceMobBase, FlyingMobBase ] id: BaseMobBehonker abstract: true description: A floating demon aspect of the honkmother. @@ -70,8 +70,6 @@ groups: - id: Medicine - id: Poison - - type: MovementAlwaysTouching - - type: NoSlip - type: Butcherable spawned: - id: MaterialBananium1 diff --git a/Resources/Prototypes/Entities/Mobs/NPCs/carp.yml b/Resources/Prototypes/Entities/Mobs/NPCs/carp.yml index 6c088d7f75..2d490ddb1c 100644 --- a/Resources/Prototypes/Entities/Mobs/NPCs/carp.yml +++ b/Resources/Prototypes/Entities/Mobs/NPCs/carp.yml @@ -1,7 +1,7 @@ - type: entity name: space carp id: BaseMobCarp - parent: SimpleSpaceMobBase + parent: [ SimpleSpaceMobBase, FlyingMobBase ] description: It's a space carp. abstract: true components: @@ -42,7 +42,6 @@ 50: Dead - type: Stamina critThreshold: 100 - - type: MovementAlwaysTouching - type: DamageStateVisuals states: Alive: @@ -68,7 +67,6 @@ Slash: 10 - type: TypingIndicator proto: alien - - type: NoSlip - type: Tag tags: - Carp diff --git a/Resources/Prototypes/Entities/Mobs/NPCs/flying_animals.yml b/Resources/Prototypes/Entities/Mobs/NPCs/flying_animals.yml new file mode 100644 index 0000000000..c6846b8ef4 --- /dev/null +++ b/Resources/Prototypes/Entities/Mobs/NPCs/flying_animals.yml @@ -0,0 +1,11 @@ +# Used for entities that are considered flying, +# i.e. shouldnt slip, have free movement in weightlesness, and should go over chasms/lava +- type: entity + id: FlyingMobBase + abstract: true + components: + - type: Physics + bodyStatus: InAir + - type: NoSlip + - type: MovementAlwaysTouching + - type: CanMoveInAir diff --git a/Resources/Prototypes/Entities/Mobs/NPCs/lavaland.yml b/Resources/Prototypes/Entities/Mobs/NPCs/lavaland.yml index aa6d63820b..23cc31a179 100644 --- a/Resources/Prototypes/Entities/Mobs/NPCs/lavaland.yml +++ b/Resources/Prototypes/Entities/Mobs/NPCs/lavaland.yml @@ -1,7 +1,7 @@ - type: entity name: watcher id: MobWatcherBase - parent: SimpleSpaceMobBase + parent: [ SimpleSpaceMobBase, FlyingMobBase ] abstract: true description: It's like its staring right through you. components: @@ -46,8 +46,6 @@ - type: MovementSpeedModifier baseWalkSpeed: 5 baseSprintSpeed: 7 - - type: MovementAlwaysTouching - - type: NoSlip - type: ProjectileBatteryAmmoProvider proto: WatcherBolt fireCost: 50 diff --git a/Resources/Prototypes/Entities/Mobs/Player/dragon.yml b/Resources/Prototypes/Entities/Mobs/Player/dragon.yml index 9ef481583f..2d64a0a531 100644 --- a/Resources/Prototypes/Entities/Mobs/Player/dragon.yml +++ b/Resources/Prototypes/Entities/Mobs/Player/dragon.yml @@ -1,5 +1,5 @@ - type: entity - parent: SimpleSpaceMobBase + parent: [ SimpleSpaceMobBase, FlyingMobBase ] id: BaseMobDragon suffix: "" name: space dragon @@ -90,8 +90,6 @@ groups: - id: Medicine - id: Poison - - type: MovementAlwaysTouching - - type: NoSlip - type: Butcherable spawned: - id: FoodMeatDragon diff --git a/Resources/Prototypes/Entities/Mobs/Player/observer.yml b/Resources/Prototypes/Entities/Mobs/Player/observer.yml index 9752d45c35..1a90b0cb50 100644 --- a/Resources/Prototypes/Entities/Mobs/Player/observer.yml +++ b/Resources/Prototypes/Entities/Mobs/Player/observer.yml @@ -10,9 +10,6 @@ - type: MindContainer - type: Clickable - type: InteractionOutline - - type: Physics - bodyType: KinematicController - fixedRotation: true - type: Fixtures fixtures: fix1: @@ -60,6 +57,10 @@ baseSprintSpeed: 12 baseWalkSpeed: 8 - type: MovementIgnoreGravity + - type: Physics + bodyType: KinematicController + bodyStatus: InAir + - type: CanMoveInAir - type: Tag tags: - BypassInteractionRangeChecks diff --git a/Resources/Prototypes/Entities/Objects/Tools/jetpacks.yml b/Resources/Prototypes/Entities/Objects/Tools/jetpacks.yml index 6870ca5f0d..cbe47a17bd 100644 --- a/Resources/Prototypes/Entities/Objects/Tools/jetpacks.yml +++ b/Resources/Prototypes/Entities/Objects/Tools/jetpacks.yml @@ -31,6 +31,7 @@ weightlessAcceleration: 1 weightlessFriction: 0.3 weightlessModifier: 1.2 + - type: CanMoveInAir - type: Sprite sprite: Objects/Tanks/Jetpacks/blue.rsi state: icon diff --git a/Resources/Prototypes/Entities/Structures/Power/Generation/Singularity/singularity.yml b/Resources/Prototypes/Entities/Structures/Power/Generation/Singularity/singularity.yml index d2fea2870a..25d219ab94 100644 --- a/Resources/Prototypes/Entities/Structures/Power/Generation/Singularity/singularity.yml +++ b/Resources/Prototypes/Entities/Structures/Power/Generation/Singularity/singularity.yml @@ -11,6 +11,8 @@ path: /Audio/Effects/singularity.ogg - type: Physics bodyType: Dynamic + bodyStatus: InAir + - type: CanMoveInAir - type: EventHorizon # To make the singularity consume things. radius: 0.5 canBreachContainment: false