diff --git a/Content.Client/Movement/Systems/JetpackSystem.cs b/Content.Client/Movement/Systems/JetpackSystem.cs index 0a9b850e16..727c3cefa3 100644 --- a/Content.Client/Movement/Systems/JetpackSystem.cs +++ b/Content.Client/Movement/Systems/JetpackSystem.cs @@ -56,6 +56,12 @@ public sealed class JetpackSystem : SharedJetpackSystem private void CreateParticles(EntityUid uid) { + // Don't show particles unless the user is moving. + if (Container.TryGetContainingContainer(uid, out var container) && + TryComp(container.Owner, out var body) && + body.LinearVelocity.LengthSquared < 1f) + return; + var uidXform = Transform(uid); var coordinates = uidXform.Coordinates; var gridUid = coordinates.GetGridUid(EntityManager); diff --git a/Content.Server/Movement/Systems/JetpackSystem.cs b/Content.Server/Movement/Systems/JetpackSystem.cs index a25155dd80..7c15621992 100644 --- a/Content.Server/Movement/Systems/JetpackSystem.cs +++ b/Content.Server/Movement/Systems/JetpackSystem.cs @@ -11,7 +11,7 @@ public sealed class JetpackSystem : SharedJetpackSystem protected override bool CanEnable(JetpackComponent component) { - return TryComp(component.Owner, out var gasTank) && !(gasTank.Air.TotalMoles < component.MoleUsage); + return base.CanEnable(component) && TryComp(component.Owner, out var gasTank) && !(gasTank.Air.TotalMoles < component.MoleUsage); } public override void Update(float frameTime) diff --git a/Content.Shared/Movement/Components/JetpackUserComponent.cs b/Content.Shared/Movement/Components/JetpackUserComponent.cs index 05d99cf660..79a3b80969 100644 --- a/Content.Shared/Movement/Components/JetpackUserComponent.cs +++ b/Content.Shared/Movement/Components/JetpackUserComponent.cs @@ -11,4 +11,5 @@ public sealed class JetpackUserComponent : Component public float Acceleration = 1f; public float Friction = 0.3f; public float WeightlessModifier = 1.2f; + public EntityUid Jetpack; } diff --git a/Content.Shared/Movement/Systems/SharedJetpackSystem.cs b/Content.Shared/Movement/Systems/SharedJetpackSystem.cs index 199ff1ab8c..da00e68971 100644 --- a/Content.Shared/Movement/Systems/SharedJetpackSystem.cs +++ b/Content.Shared/Movement/Systems/SharedJetpackSystem.cs @@ -4,17 +4,24 @@ using Content.Shared.Interaction.Events; using Content.Shared.Inventory; using Content.Shared.Movement.Components; using Content.Shared.Movement.Events; +using Content.Shared.Popups; using Robust.Shared.Containers; +using Robust.Shared.GameStates; using Robust.Shared.Map; +using Robust.Shared.Network; +using Robust.Shared.Player; using Robust.Shared.Serialization; +using Robust.Shared.Timing; namespace Content.Shared.Movement.Systems; public abstract class SharedJetpackSystem : EntitySystem { + [Dependency] private readonly IGameTiming _timing = default!; + [Dependency] private readonly INetManager _network = default!; [Dependency] protected readonly SharedContainerSystem Container = default!; - [Dependency] protected readonly IMapManager MapManager = default!; - [Dependency] protected readonly MovementSpeedModifierSystem MovementSpeedModifier = default!; + [Dependency] private readonly MovementSpeedModifierSystem _movementSpeedModifier = default!; + [Dependency] private readonly SharedPopupSystem _popups = default!; public override void Initialize() { @@ -25,9 +32,44 @@ public abstract class SharedJetpackSystem : EntitySystem SubscribeLocalEvent(OnJetpackUserCanWeightless); SubscribeLocalEvent(OnJetpackUserMovement); SubscribeLocalEvent(OnJetpackUserEntParentChanged); + SubscribeLocalEvent(OnJetpackUserGetState); + SubscribeLocalEvent(OnJetpackUserHandleState); + SubscribeLocalEvent(OnJetpackUserGravityChanged); } + private void OnJetpackUserGravityChanged(GravityChangedMessage ev) + { + var gridUid = ev.ChangedGridIndex; + var jetpackQuery = GetEntityQuery(); + + foreach (var (user, transform) in EntityQuery(true)) + { + if (transform.GridUid == gridUid && ev.HasGravity && + jetpackQuery.TryGetComponent(user.Jetpack, out var jetpack)) + { + if (_timing.IsFirstTimePredicted) + _popups.PopupEntity(Loc.GetString("jetpack-to-grid"), user.Jetpack, Filter.Entities(user.Owner)); + + SetEnabled(jetpack, false, user.Owner); + } + } + } + + private void OnJetpackUserHandleState(EntityUid uid, JetpackUserComponent component, ref ComponentHandleState args) + { + if (args.Current is not JetpackUserComponentState state) return; + component.Jetpack = state.Jetpack; + } + + private void OnJetpackUserGetState(EntityUid uid, JetpackUserComponent component, ref ComponentGetState args) + { + args.State = new JetpackUserComponentState() + { + Jetpack = component.Jetpack, + }; + } + private void OnJetpackDropped(EntityUid uid, JetpackComponent component, DroppedEvent args) { SetEnabled(component, false, args.User); @@ -51,16 +93,13 @@ public abstract class SharedJetpackSystem : EntitySystem private void OnJetpackUserEntParentChanged(EntityUid uid, JetpackUserComponent component, ref EntParentChangedMessage args) { - MovementSpeedModifier.RefreshMovementSpeedModifiers(component.Owner); - } - - private void OnJetpackUserGravityChanged(GravityChangedMessage ev) - { - var gridUid = ev.ChangedGridIndex; - foreach (var (_, transform) in EntityQuery(true)) + if (TryComp(component.Jetpack, out var jetpack) && + !CanEnableOnGrid(args.Transform.GridUid)) { - if(transform.GridUid == gridUid) - MovementSpeedModifier.RefreshMovementSpeedModifiers(transform.Owner); + SetEnabled(jetpack, false, uid); + + if (_timing.IsFirstTimePredicted && _network.IsClient) + _popups.PopupEntity(Loc.GetString("jetpack-to-grid"), uid, Filter.Entities(uid)); } } @@ -70,15 +109,31 @@ public abstract class SharedJetpackSystem : EntitySystem user.Acceleration = component.Acceleration; user.Friction = component.Friction; user.WeightlessModifier = component.WeightlessModifier; + user.Jetpack = component.Owner; } private void OnJetpackToggle(EntityUid uid, JetpackComponent component, ToggleJetpackEvent args) { if (args.Handled) return; + if (TryComp(uid, out var xform) && !CanEnableOnGrid(xform.GridUid)) + { + if (_timing.IsFirstTimePredicted) + _popups.PopupEntity(Loc.GetString("jetpack-no-station"), uid, Filter.Entities(args.Performer)); + + return; + } + SetEnabled(component, !IsEnabled(uid)); } + private bool CanEnableOnGrid(EntityUid? gridUid) + { + return gridUid == null || + (TryComp(gridUid, out var gravity) && + !gravity.Enabled); + } + private void OnJetpackGetAction(EntityUid uid, JetpackComponent component, GetItemActionsEvent args) { args.Actions.Add(component.ToggleAction); @@ -123,7 +178,7 @@ public abstract class SharedJetpackSystem : EntitySystem RemComp(user.Value); } - MovementSpeedModifier.RefreshMovementSpeedModifiers(user.Value); + _movementSpeedModifier.RefreshMovementSpeedModifiers(user.Value); } TryComp(component.Owner, out var appearance); @@ -133,17 +188,18 @@ public abstract class SharedJetpackSystem : EntitySystem public bool IsUserFlying(EntityUid uid) { - return HasComp(uid) && - TryComp(uid, out var physicsComponent) && - uid.IsWeightless(physicsComponent, mapManager: MapManager, entityManager: EntityManager); + return HasComp(uid); } - protected abstract bool CanEnable(JetpackComponent component); + protected virtual bool CanEnable(JetpackComponent component) + { + return true; + } [Serializable, NetSerializable] - protected sealed class JetpackComponentState : ComponentState + protected sealed class JetpackUserComponentState : ComponentState { - public bool Enabled; + public EntityUid Jetpack; } } diff --git a/Resources/Locale/en-US/movement/jetpacks.ftl b/Resources/Locale/en-US/movement/jetpacks.ftl index c3f233d11d..20efababf4 100644 --- a/Resources/Locale/en-US/movement/jetpacks.ftl +++ b/Resources/Locale/en-US/movement/jetpacks.ftl @@ -1,2 +1,5 @@ action-name-jetpack-toggle = Toggle jetpack -action-description-jetpack-toggle = Toggles the jetpack, giving you movement outside the station. \ No newline at end of file +action-description-jetpack-toggle = Toggles the jetpack, giving you movement outside the station. + +jetpack-no-station = Can't use jetpacks under gravity +jetpack-to-grid = The jetpack turns off diff --git a/Resources/Prototypes/Entities/Objects/Tools/jetpacks.yml b/Resources/Prototypes/Entities/Objects/Tools/jetpacks.yml index c90cab40ca..db5b3b92f3 100644 --- a/Resources/Prototypes/Entities/Objects/Tools/jetpacks.yml +++ b/Resources/Prototypes/Entities/Objects/Tools/jetpacks.yml @@ -54,7 +54,7 @@ state: icon-on name: action-name-jetpack-toggle description: action-description-jetpack-toggle - itemIconStyle: NoItem + useDelay: 1.0 event: !type:ToggleJetpackEvent - type: Appearance