using Content.Shared.Actions; using Content.Shared.Gravity; using Content.Shared.Interaction.Events; using Content.Shared.Inventory; using Content.Shared.Movement.Components; using Content.Shared.Movement.Events; using Robust.Shared.Containers; using Robust.Shared.Map; using Robust.Shared.Serialization; namespace Content.Shared.Movement.Systems; public abstract class SharedJetpackSystem : EntitySystem { [Dependency] protected readonly SharedContainerSystem Container = default!; [Dependency] protected readonly IMapManager MapManager = default!; [Dependency] protected readonly MovementSpeedModifierSystem MovementSpeedModifier = default!; public override void Initialize() { base.Initialize(); SubscribeLocalEvent(OnJetpackGetAction); SubscribeLocalEvent(OnJetpackDropped); SubscribeLocalEvent(OnJetpackToggle); SubscribeLocalEvent(OnJetpackUserCanWeightless); SubscribeLocalEvent(OnJetpackUserMovement); SubscribeLocalEvent(OnJetpackUserEntParentChanged); SubscribeLocalEvent(OnJetpackUserGravityChanged); } private void OnJetpackDropped(EntityUid uid, JetpackComponent component, DroppedEvent args) { SetEnabled(component, false, args.User); } private void OnJetpackUserMovement(EntityUid uid, JetpackUserComponent component, ref MobMovementProfileEvent args) { // Only overwrite jetpack movement if they're offgrid. if (args.Override || !args.Weightless) return; args.Override = true; args.Acceleration = component.Acceleration; args.WeightlessModifier = component.WeightlessModifier; args.Friction = component.Friction; } private void OnJetpackUserCanWeightless(EntityUid uid, JetpackUserComponent component, ref CanWeightlessMoveEvent args) { args.CanMove = true; } 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(transform.GridUid == gridUid) MovementSpeedModifier.RefreshMovementSpeedModifiers(transform.Owner); } } private void SetupUser(EntityUid uid, JetpackComponent component) { var user = EnsureComp(uid); user.Acceleration = component.Acceleration; user.Friction = component.Friction; user.WeightlessModifier = component.WeightlessModifier; } private void OnJetpackToggle(EntityUid uid, JetpackComponent component, ToggleJetpackEvent args) { if (args.Handled) return; SetEnabled(component, !IsEnabled(uid)); } private void OnJetpackGetAction(EntityUid uid, JetpackComponent component, GetItemActionsEvent args) { args.Actions.Add(component.ToggleAction); } private bool IsEnabled(EntityUid uid) { return HasComp(uid); } public void SetEnabled(JetpackComponent component, bool enabled, EntityUid? user = null) { if (IsEnabled(component.Owner) == enabled || enabled && !CanEnable(component)) return; if (enabled) { EnsureComp(component.Owner); } else { RemComp(component.Owner); } if (user == null) { Container.TryGetContainingContainer(component.Owner, out var container); user = container?.Owner; } // Can't activate if no one's using. if (user == null && enabled) return; if (user != null) { if (enabled) { SetupUser(user.Value, component); } else { RemComp(user.Value); } MovementSpeedModifier.RefreshMovementSpeedModifiers(user.Value); } TryComp(component.Owner, out var appearance); appearance?.SetData(JetpackVisuals.Enabled, enabled); Dirty(component); } public bool IsUserFlying(EntityUid uid) { return HasComp(uid) && TryComp(uid, out var physicsComponent) && uid.IsWeightless(physicsComponent, mapManager: MapManager, entityManager: EntityManager); } protected abstract bool CanEnable(JetpackComponent component); [Serializable, NetSerializable] protected sealed class JetpackComponentState : ComponentState { public bool Enabled; } } [Serializable, NetSerializable] public enum JetpackVisuals : byte { Enabled, }