From b0f71ae934fd2d3024c4e6072f80212bb3c8f0f0 Mon Sep 17 00:00:00 2001 From: Acensti Date: Sat, 6 Jul 2024 21:43:14 +0200 Subject: [PATCH 1/8] maybe buckle better, vehicle prepare and key seperation sharedbucklesystem.buckle.cs and strap moved into sharedbucklesystem.cs. In TG, Mobs were (if i remember right) assigned a entity that was able to be mounted or buckled upon, so just toss that onto a robot, cat or a fridge and you can buckle it. TODO: alot GOALS? Goals: Remove the hard requirement of keys from vehicles. Split key logic into a separate component. cars vehicles buckle to ian --- .../Systems/VehicleDestructionSystem.cs | 21 + .../Vehicles/Systems/VehicleKeySystem.cs | 48 ++ .../Vehicles/Systems/VehicleSystem.cs | 59 ++ .../Vehicles/UI/VehicleControlUI.cs | 31 ++ .../Buckle/Components/BuckleComponent.cs | 26 +- .../Buckle/Components/StrapComponent.cs | 109 +--- .../Buckle/SharedBuckleSystem.Buckle.cs | 525 ------------------ .../Buckle/SharedBuckleSystem.Strap.cs | 318 ----------- Content.Shared/Buckle/SharedBuckleSystem.cs | 239 +++++++- .../Components/VehicleKeyComponent.cs | 16 + .../Prototypes/Entities/Vehicles/vehicles.yml | 26 + 11 files changed, 468 insertions(+), 950 deletions(-) create mode 100644 Content.Server/Vehicles/Systems/VehicleDestructionSystem.cs create mode 100644 Content.Server/Vehicles/Systems/VehicleKeySystem.cs create mode 100644 Content.Server/Vehicles/Systems/VehicleSystem.cs create mode 100644 Content.Server/Vehicles/UI/VehicleControlUI.cs delete mode 100644 Content.Shared/Buckle/SharedBuckleSystem.Buckle.cs delete mode 100644 Content.Shared/Buckle/SharedBuckleSystem.Strap.cs create mode 100644 Content.Shared/Vehicles/Components/VehicleKeyComponent.cs create mode 100644 Resources/Prototypes/Entities/Vehicles/vehicles.yml diff --git a/Content.Server/Vehicles/Systems/VehicleDestructionSystem.cs b/Content.Server/Vehicles/Systems/VehicleDestructionSystem.cs new file mode 100644 index 00000000000..667348dec05 --- /dev/null +++ b/Content.Server/Vehicles/Systems/VehicleDestructionSystem.cs @@ -0,0 +1,21 @@ +// /Content.Server/Vehicles/Systems/VehicleDestructionSystem.cs +using Content.Server.Vehicles.Components; +using Robust.Shared.GameObjects; +using Robust.Shared.Physics; + +namespace Content.Server.Vehicles.Systems +{ + public sealed class VehicleDestructionSystem : EntitySystem + { + public override void Initialize() + { + base.Initialize(); + SubscribeLocalEvent(OnVehicleDestroyed); + } + + private void OnVehicleDestroyed(EntityUid uid, VehicleComponent component, DestructionEventArgs args) + { + // Logic for vehicle destruction, e.g., explosion, dropping items, etc. + } + } +} diff --git a/Content.Server/Vehicles/Systems/VehicleKeySystem.cs b/Content.Server/Vehicles/Systems/VehicleKeySystem.cs new file mode 100644 index 00000000000..cfdca5751e5 --- /dev/null +++ b/Content.Server/Vehicles/Systems/VehicleKeySystem.cs @@ -0,0 +1,48 @@ +// /Content.Server/Vehicles/Systems/VehicleKeySystem.cs +using Content.Shared.Vehicles.Components; +using Robust.Shared.GameObjects; +using Robust.Shared.IoC; + +namespace Content.Server.Vehicles.Systems +{ + public sealed class VehicleKeySystem : EntitySystem + { + public override void Initialize() + { + base.Initialize(); + SubscribeLocalEvent(OnComponentStartup); + SubscribeLocalEvent(OnComponentShutdown); + } + + private void OnComponentStartup(EntityUid uid, VehicleKeyComponent component, ComponentStartup args) + { + // logic for vehicle keys + } + + private void OnComponentShutdown(EntityUid uid, VehicleKeyComponent component, ComponentShutdown args) + { + // Cleanup logic for vehicle keys (e.g., removing the key from the vehicle ? I dont fucking know man clown car needs car keys) + } + + public bool IsVehicleLocked(EntityUid uid) + { + return TryComp(uid, out var keyComp) && keyComp.IsLocked; + } + + public void LockVehicle(EntityUid uid) + { + if (TryComp(uid, out var keyComp)) + { + keyComp.IsLocked = true; + } + } + + public void UnlockVehicle(EntityUid uid) + { + if (TryComp(uid, out var keyComp)) + { + keyComp.IsLocked = false; + } + } + } +} diff --git a/Content.Server/Vehicles/Systems/VehicleSystem.cs b/Content.Server/Vehicles/Systems/VehicleSystem.cs new file mode 100644 index 00000000000..fe54fac0b81 --- /dev/null +++ b/Content.Server/Vehicles/Systems/VehicleSystem.cs @@ -0,0 +1,59 @@ +// /Content.Server/Vehicles/Systems/VehicleSystem.cs +using Content.Server.Vehicles.Components; +using Robust.Shared.GameObjects; +using Robust.Shared.Map; +using Robust.Shared.Physics; +using Robust.Shared.Player; +using Robust.Shared.Timing; + +namespace Content.Server.Vehicles.Systems +{ + public sealed class VehicleSystem : EntitySystem + { + [Dependency] private readonly IGameTiming _gameTiming = default!; + [Dependency] private readonly IMapManager _mapManager = default!; + [Dependency] private readonly IEntityManager _entityManager = default!; + + public override void Initialize() + { + base.Initialize(); + SubscribeLocalEvent>(AddEnterVehicleVerb); + SubscribeLocalEvent(OnMoveInput); + } + + private void AddEnterVehicleVerb(EntityUid uid, VehicleComponent component, GetVerbsEvent args) + { + if (!args.CanInteract || !args.CanAccess) + return; + + if (component.Occupants.Count >= component.MaxOccupants) + return; + + AlternativeVerb verb = new() + { + Act = () => EnterVehicle(args.User, uid, component), + Text = Loc.GetString("enter-vehicle-verb"), + Priority = 2 + }; + args.Verbs.Add(verb); + } + + private void EnterVehicle(EntityUid user, EntityUid vehicle, VehicleComponent component) + { + component.Occupants.Add(user); + if (component.Driver == null) + { + component.Driver = user; + } + //TODO Additional logic to attach user to vehicle, update UI, etc maybe. + } + + private void OnMoveInput(EntityUid uid, VehicleComponent component, ref MoveInputEvent args) + { + if (component.Driver == null || component.Driver != args.User) + return; + + // Handle vehicle movement logic here. Surely theres a component for that im just tossing ideas + } + } +} diff --git a/Content.Server/Vehicles/UI/VehicleControlUI.cs b/Content.Server/Vehicles/UI/VehicleControlUI.cs new file mode 100644 index 00000000000..0a42af2ed2b --- /dev/null +++ b/Content.Server/Vehicles/UI/VehicleControlUI.cs @@ -0,0 +1,31 @@ +// /Content.Client/Vehicles/UI/VehicleControlUI.cs +using Robust.Client.UserInterface; +using Robust.Client.UserInterface.Controls; + +namespace Content.Client.Vehicles.UI +{ + public sealed class VehicleControlUI : Control + { + + //TODO insert sad face + public VehicleControlUI() + { + var enterButton = new Button { Text = "Enter Vehicle" }; + enterButton.OnPressed += _ => EnterVehicle(); + AddChild(enterButton); + + var exitButton = new Button { Text = "Exit Vehicle" }; + exitButton.OnPressed += _ => ExitVehicle(); + AddChild(exitButton); + } + + private void EnterVehicle() + { + + + private void ExitVehicle() + { + + } + } + } diff --git a/Content.Shared/Buckle/Components/BuckleComponent.cs b/Content.Shared/Buckle/Components/BuckleComponent.cs index cf28b56d51f..ff304d46f24 100644 --- a/Content.Shared/Buckle/Components/BuckleComponent.cs +++ b/Content.Shared/Buckle/Components/BuckleComponent.cs @@ -24,57 +24,64 @@ public sealed partial class BuckleComponent : Component [AutoNetworkedField] public bool Buckled; + /// + /// The last entity this component was buckled to. + /// [ViewVariables] [AutoNetworkedField] public EntityUid? LastEntityBuckledTo; /// - /// Whether or not collisions should be possible with the entity we are strapped to + /// Whether or not collisions should be possible with the entity we are strapped to. /// [ViewVariables(VVAccess.ReadWrite)] [DataField, AutoNetworkedField] public bool DontCollide; /// - /// Whether or not we should be allowed to pull the entity we are strapped to + /// Whether or not we should be allowed to pull the entity we are strapped to. /// [ViewVariables(VVAccess.ReadWrite)] [DataField] public bool PullStrap; /// - /// The amount of time that must pass for this entity to - /// be able to unbuckle after recently buckling. + /// The delay before the buckle/unbuckle action is completed. /// [DataField] [ViewVariables(VVAccess.ReadWrite)] public TimeSpan Delay = TimeSpan.FromSeconds(0.25f); /// - /// The time that this entity buckled at. + /// The time when the buckle/unbuckle action was initiated. /// [ViewVariables] public TimeSpan BuckleTime; /// - /// The strap that this component is buckled to. + /// The entity this component is currently buckled to. /// [ViewVariables] [AutoNetworkedField] public EntityUid? BuckledTo; /// - /// The amount of space that this entity occupies in a - /// . + /// The maximum size of entities that can be buckled to this component. /// [DataField] [ViewVariables(VVAccess.ReadWrite)] public int Size = 100; /// - /// Used for client rendering + /// The original draw depth of the entity before it was buckled. /// [ViewVariables] public int? OriginalDrawDepth; + + [DataField] + + [ViewVariables(VVAccess.ReadWrite)] + + public EntityWhitelist? AllowedBuckleTypes; } [ByRefEvent] @@ -88,3 +95,4 @@ public enum BuckleVisuals { Buckled } + diff --git a/Content.Shared/Buckle/Components/StrapComponent.cs b/Content.Shared/Buckle/Components/StrapComponent.cs index f25e1b03741..7585ba0fe88 100644 --- a/Content.Shared/Buckle/Components/StrapComponent.cs +++ b/Content.Shared/Buckle/Components/StrapComponent.cs @@ -1,146 +1,87 @@ -using System.Numerics; -using Content.Shared.Alert; -using Content.Shared.Whitelist; -using Robust.Shared.Audio; using Robust.Shared.GameStates; using Robust.Shared.Serialization; namespace Content.Shared.Buckle.Components; -[RegisterComponent, NetworkedComponent, AutoGenerateComponentState] +/// +/// Component that allows entities to be buckled to it. +/// +[RegisterComponent, NetworkedComponent, AutoGenerateComponentState(true)] [Access(typeof(SharedBuckleSystem))] public sealed partial class StrapComponent : Component { /// - /// The entities that are currently buckled + /// The entities that are currently buckled to this strap. /// - [AutoNetworkedField] - [ViewVariables] // TODO serialization + [ViewVariables] public HashSet BuckledEntities = new(); /// - /// Entities that this strap accepts and can buckle - /// If null it accepts any entity + /// The maximum distance from which entities can buckle to this strap. /// [DataField] - [ViewVariables] - public EntityWhitelist? AllowedEntities; - - /// - /// The change in position to the strapped mob - /// - [DataField, AutoNetworkedField] [ViewVariables(VVAccess.ReadWrite)] - public StrapPosition Position = StrapPosition.None; - - /// - /// The distance above which a buckled entity will be automatically unbuckled. - /// Don't change it unless you really have to - /// - /// - /// Dont set this below 0.2 because that causes audio issues with - /// My guess after testing is that the client sets BuckledTo to the strap in *some* ticks for some reason - /// whereas the server doesnt, thus the client tries to unbuckle like 15 times because it passes the strap null check - /// This is why this needs to be above 0.1 to make the InRange check fail in both client and server. - /// - [DataField, AutoNetworkedField] - [ViewVariables(VVAccess.ReadWrite)] - public float MaxBuckleDistance = 0.2f; - - /// - /// Gets and clamps the buckle offset to MaxBuckleDistance - /// - [ViewVariables] - public Vector2 BuckleOffsetClamped => Vector2.Clamp( - BuckleOffset, - Vector2.One * -MaxBuckleDistance, - Vector2.One * MaxBuckleDistance); + public float MaxBuckleDistance = 1.0f; /// - /// The buckled entity will be offset by this amount from the center of the strap object. - /// If this offset it too big, it will be clamped to + /// The position that entities will be in when buckled to this strap. /// - [DataField, AutoNetworkedField] + [DataField] [ViewVariables(VVAccess.ReadWrite)] - public Vector2 BuckleOffset = Vector2.Zero; + public StrapPosition Position = StrapPosition.Stand; /// - /// The angle to rotate the player by when they get strapped + /// The offset from the strap's position where entities will be buckled. /// [DataField] [ViewVariables(VVAccess.ReadWrite)] - public Angle Rotation; + public Vector2 BuckleOffset = Vector2.Zero; /// - /// The size of the strap which is compared against when buckling entities + /// The maximum size of entities that can be buckled to this strap. /// [DataField] [ViewVariables(VVAccess.ReadWrite)] public int Size = 100; /// - /// If disabled, nothing can be buckled on this object, and it will unbuckle anything that's already buckled + /// The current occupied size of this strap. /// [ViewVariables] - public bool Enabled = true; + public int OccupiedSize; /// - /// You can specify the offset the entity will have after unbuckling. + /// Whether this strap is enabled or not. /// [DataField] [ViewVariables(VVAccess.ReadWrite)] - public Vector2 UnbuckleOffset = Vector2.Zero; + public bool Enabled = true; /// - /// The sound to be played when a mob is buckled + /// The alert type to show when an entity is buckled to this strap. /// [DataField] [ViewVariables(VVAccess.ReadWrite)] - public SoundSpecifier BuckleSound = new SoundPathSpecifier("/Audio/Effects/buckle.ogg"); + public AlertType BuckledAlertType = AlertType.Buckled; /// - /// The sound to be played when a mob is unbuckled + /// The sound to play when an entity is buckled to this strap. /// [DataField] [ViewVariables(VVAccess.ReadWrite)] - public SoundSpecifier UnbuckleSound = new SoundPathSpecifier("/Audio/Effects/unbuckle.ogg"); + public SoundSpecifier BuckleSound = new SoundPathSpecifier("/Audio/Effects/buckle.ogg"); /// - /// ID of the alert to show when buckled + /// The sound to play when an entity is unbuckled from this strap. /// [DataField] [ViewVariables(VVAccess.ReadWrite)] - public AlertType BuckledAlertType = AlertType.Buckled; - - /// - /// The sum of the sizes of all the buckled entities in this strap - /// - [AutoNetworkedField] - [ViewVariables] - public int OccupiedSize; + public SoundSpecifier UnbuckleSound = new SoundPathSpecifier("/Audio/Effects/unbuckle.ogg"); } public enum StrapPosition { - /// - /// (Default) Makes no change to the buckled mob - /// - None = 0, - - /// - /// Makes the mob stand up - /// + None, Stand, - - /// - /// Makes the mob lie down - /// Down } - -[Serializable, NetSerializable] -public enum StrapVisuals : byte -{ - RotationAngle, - State -} diff --git a/Content.Shared/Buckle/SharedBuckleSystem.Buckle.cs b/Content.Shared/Buckle/SharedBuckleSystem.Buckle.cs deleted file mode 100644 index 8172947a039..00000000000 --- a/Content.Shared/Buckle/SharedBuckleSystem.Buckle.cs +++ /dev/null @@ -1,525 +0,0 @@ -using System.Diagnostics.CodeAnalysis; -using System.Numerics; -using Content.Shared.Alert; -using Content.Shared.Bed.Sleep; -using Content.Shared.Buckle.Components; -using Content.Shared.Database; -using Content.Shared.Hands.Components; -using Content.Shared.IdentityManagement; -using Content.Shared.Interaction; -using Content.Shared.Mobs.Components; -using Content.Shared.Movement.Events; -using Content.Shared.Popups; -using Content.Shared.Pulling.Components; -using Content.Shared.Standing; -using Content.Shared.Storage.Components; -using Content.Shared.Stunnable; -using Content.Shared.Throwing; -using Content.Shared.Verbs; -using Robust.Shared.Physics.Components; -using Robust.Shared.Physics.Events; -using Robust.Shared.Utility; - -namespace Content.Shared.Buckle; - -public abstract partial class SharedBuckleSystem -{ - private void InitializeBuckle() - { - SubscribeLocalEvent(OnBuckleComponentStartup); - SubscribeLocalEvent(OnBuckleComponentShutdown); - SubscribeLocalEvent(OnBuckleMove); - SubscribeLocalEvent(OnBuckleInteractHand); - SubscribeLocalEvent>(AddUnbuckleVerb); - SubscribeLocalEvent(OnBuckleInsertIntoEntityStorageAttempt); - - SubscribeLocalEvent(OnBucklePreventCollide); - SubscribeLocalEvent(OnBuckleDownAttempt); - SubscribeLocalEvent(OnBuckleStandAttempt); - SubscribeLocalEvent(OnBuckleThrowPushbackAttempt); - SubscribeLocalEvent(OnBuckleUpdateCanMove); - } - - private void OnBuckleComponentStartup(EntityUid uid, BuckleComponent component, ComponentStartup args) - { - UpdateBuckleStatus(uid, component); - } - - private void OnBuckleComponentShutdown(EntityUid uid, BuckleComponent component, ComponentShutdown args) - { - TryUnbuckle(uid, uid, true, component); - - component.BuckleTime = default; - } - - private void OnBuckleMove(EntityUid uid, BuckleComponent component, ref MoveEvent ev) - { - if (component.BuckledTo is not {} strapUid) - return; - - if (!TryComp(strapUid, out var strapComp)) - return; - - var strapPosition = Transform(strapUid).Coordinates; - if (ev.NewPosition.InRange(EntityManager, _transform, strapPosition, strapComp.MaxBuckleDistance)) - return; - - TryUnbuckle(uid, uid, true, component); - } - - private void OnBuckleInteractHand(EntityUid uid, BuckleComponent component, InteractHandEvent args) - { - if (!component.Buckled) - return; - - if (TryUnbuckle(uid, args.User, buckleComp: component)) - args.Handled = true; - } - - private void AddUnbuckleVerb(EntityUid uid, BuckleComponent component, GetVerbsEvent args) - { - if (!args.CanAccess || !args.CanInteract || !component.Buckled) - return; - - InteractionVerb verb = new() - { - Act = () => TryUnbuckle(uid, args.User, buckleComp: component), - Text = Loc.GetString("verb-categories-unbuckle"), - Icon = new SpriteSpecifier.Texture(new ("/Textures/Interface/VerbIcons/unbuckle.svg.192dpi.png")) - }; - - if (args.Target == args.User && args.Using == null) - { - // A user is left clicking themselves with an empty hand, while buckled. - // It is very likely they are trying to unbuckle themselves. - verb.Priority = 1; - } - - args.Verbs.Add(verb); - } - - private void OnBuckleInsertIntoEntityStorageAttempt(EntityUid uid, BuckleComponent component, ref InsertIntoEntityStorageAttemptEvent args) - { - if (component.Buckled) - args.Cancelled = true; - } - - private void OnBucklePreventCollide(EntityUid uid, BuckleComponent component, ref PreventCollideEvent args) - { - if (args.OtherEntity != component.BuckledTo) - return; - - if (component.Buckled || component.DontCollide) - args.Cancelled = true; - } - - private void OnBuckleDownAttempt(EntityUid uid, BuckleComponent component, DownAttemptEvent args) - { - if (component.Buckled) - args.Cancel(); - } - - private void OnBuckleStandAttempt(EntityUid uid, BuckleComponent component, StandAttemptEvent args) - { - if (component.Buckled) - args.Cancel(); - } - - private void OnBuckleThrowPushbackAttempt(EntityUid uid, BuckleComponent component, ThrowPushbackAttemptEvent args) - { - if (component.Buckled) - args.Cancel(); - } - - private void OnBuckleUpdateCanMove(EntityUid uid, BuckleComponent component, UpdateCanMoveEvent args) - { - if (component.LifeStage > ComponentLifeStage.Running) - return; - - if (component.Buckled) // buckle shitcode - args.Cancel(); - } - - public bool IsBuckled(EntityUid uid, BuckleComponent? component = null) - { - return Resolve(uid, ref component, false) && component.Buckled; - } - - /// - /// Shows or hides the buckled status effect depending on if the - /// entity is buckled or not. - /// - /// Entity that we want to show the alert - /// buckle component of the entity - /// strap component of the thing we are strapping to - private void UpdateBuckleStatus(EntityUid uid, BuckleComponent buckleComp, StrapComponent? strapComp = null) - { - Appearance.SetData(uid, StrapVisuals.State, buckleComp.Buckled); - if (buckleComp.BuckledTo != null) - { - if (!Resolve(buckleComp.BuckledTo.Value, ref strapComp)) - return; - - var alertType = strapComp.BuckledAlertType; - _alerts.ShowAlert(uid, alertType); - } - else - { - _alerts.ClearAlertCategory(uid, AlertCategory.Buckled); - } - } - - /// - /// Sets the field in the component to a value - /// - /// Value tat with be assigned to the field - private void SetBuckledTo(EntityUid buckleUid, EntityUid? strapUid, StrapComponent? strapComp, BuckleComponent buckleComp) - { - buckleComp.BuckledTo = strapUid; - - if (strapUid == null) - { - buckleComp.Buckled = false; - } - else - { - buckleComp.LastEntityBuckledTo = strapUid; - buckleComp.DontCollide = true; - buckleComp.Buckled = true; - buckleComp.BuckleTime = _gameTiming.CurTime; - } - - ActionBlocker.UpdateCanMove(buckleUid); - UpdateBuckleStatus(buckleUid, buckleComp, strapComp); - Dirty(buckleComp); - } - - /// - /// Checks whether or not buckling is possible - /// - /// Uid of the owner of BuckleComponent - /// - /// Uid of a third party entity, - /// i.e, the uid of someone else you are dragging to a chair. - /// Can equal buckleUid sometimes - /// - /// Uid of the owner of strap component - private bool CanBuckle( - EntityUid buckleUid, - EntityUid userUid, - EntityUid strapUid, - [NotNullWhen(true)] out StrapComponent? strapComp, - BuckleComponent? buckleComp = null) - { - strapComp = null; - - if (userUid == strapUid || - !Resolve(buckleUid, ref buckleComp, false) || - !Resolve(strapUid, ref strapComp, false)) - { - return false; - } - - // Does it pass the Whitelist - if (strapComp.AllowedEntities != null && - !strapComp.AllowedEntities.IsValid(userUid, EntityManager)) - { - if (_netManager.IsServer) - _popup.PopupEntity(Loc.GetString("buckle-component-cannot-fit-message"), userUid, buckleUid, PopupType.Medium); - return false; - } - - // Is it within range - bool Ignored(EntityUid entity) => entity == buckleUid || entity == userUid || entity == strapUid; - - if (!_interaction.InRangeUnobstructed(buckleUid, strapUid, buckleComp.Range, predicate: Ignored, - popup: true)) - { - return false; - } - - // If in a container - if (_container.TryGetContainingContainer(buckleUid, out var ownerContainer)) - { - // And not in the same container as the strap - if (!_container.TryGetContainingContainer(strapUid, out var strapContainer) || - ownerContainer != strapContainer) - { - return false; - } - } - - if (!HasComp(userUid)) - { - // PopupPredicted when - if (_netManager.IsServer) - _popup.PopupEntity(Loc.GetString("buckle-component-no-hands-message"), userUid, userUid); - return false; - } - - if (buckleComp.Buckled) - { - var message = Loc.GetString(buckleUid == userUid - ? "buckle-component-already-buckled-message" - : "buckle-component-other-already-buckled-message", - ("owner", Identity.Entity(buckleUid, EntityManager))); - if (_netManager.IsServer) - _popup.PopupEntity(message, userUid, userUid); - - return false; - } - - var parent = Transform(strapUid).ParentUid; - while (parent.IsValid()) - { - if (parent == userUid) - { - var message = Loc.GetString(buckleUid == userUid - ? "buckle-component-cannot-buckle-message" - : "buckle-component-other-cannot-buckle-message", ("owner", Identity.Entity(buckleUid, EntityManager))); - if (_netManager.IsServer) - _popup.PopupEntity(message, userUid, userUid); - - return false; - } - - parent = Transform(parent).ParentUid; - } - - if (!StrapHasSpace(strapUid, buckleComp, strapComp)) - { - var message = Loc.GetString(buckleUid == userUid - ? "buckle-component-cannot-fit-message" - : "buckle-component-other-cannot-fit-message", ("owner", Identity.Entity(buckleUid, EntityManager))); - if (_netManager.IsServer) - _popup.PopupEntity(message, userUid, userUid); - - return false; - } - - var attemptEvent = new BuckleAttemptEvent(strapUid, buckleUid, userUid, true); - RaiseLocalEvent(attemptEvent.BuckledEntity, ref attemptEvent); - RaiseLocalEvent(attemptEvent.StrapEntity, ref attemptEvent); - if (attemptEvent.Cancelled) - return false; - - return true; - } - - /// - /// Attempts to buckle an entity to a strap - /// - /// Uid of the owner of BuckleComponent - /// - /// Uid of a third party entity, - /// i.e, the uid of someone else you are dragging to a chair. - /// Can equal buckleUid sometimes - /// - /// Uid of the owner of strap component - public bool TryBuckle(EntityUid buckleUid, EntityUid userUid, EntityUid strapUid, BuckleComponent? buckleComp = null) - { - if (!Resolve(buckleUid, ref buckleComp, false)) - return false; - - if (!CanBuckle(buckleUid, userUid, strapUid, out var strapComp, buckleComp)) - return false; - - if (!StrapTryAdd(strapUid, buckleUid, buckleComp, false, strapComp)) - { - var message = Loc.GetString(buckleUid == userUid - ? "buckle-component-cannot-buckle-message" - : "buckle-component-other-cannot-buckle-message", ("owner", Identity.Entity(buckleUid, EntityManager))); - if (_netManager.IsServer) - _popup.PopupEntity(message, userUid, userUid); - return false; - } - - if (TryComp(buckleUid, out var appearance)) - Appearance.SetData(buckleUid, BuckleVisuals.Buckled, true, appearance); - - _rotationVisuals.SetHorizontalAngle(buckleUid, strapComp.Rotation); - - ReAttach(buckleUid, strapUid, buckleComp, strapComp); - SetBuckledTo(buckleUid, strapUid, strapComp, buckleComp); - // TODO user is currently set to null because if it isn't the sound fails to play in some situations, fix that - _audio.PlayPredicted(strapComp.BuckleSound, strapUid, userUid); - - var ev = new BuckleChangeEvent(strapUid, buckleUid, true); - RaiseLocalEvent(ev.BuckledEntity, ref ev); - RaiseLocalEvent(ev.StrapEntity, ref ev); - - if (TryComp(buckleUid, out var ownerPullable)) - { - if (ownerPullable.Puller != null) - { - _pulling.TryStopPull(ownerPullable); - } - } - - if (TryComp(buckleUid, out var physics)) - { - _physics.ResetDynamics(buckleUid, physics); - } - - if (!buckleComp.PullStrap && TryComp(strapUid, out var toPullable)) - { - if (toPullable.Puller == buckleUid) - { - // can't pull it and buckle to it at the same time - _pulling.TryStopPull(toPullable); - } - } - - // Logging - if (userUid != buckleUid) - _adminLogger.Add(LogType.Action, LogImpact.Low, $"{ToPrettyString(userUid):player} buckled {ToPrettyString(buckleUid)} to {ToPrettyString(strapUid)}"); - else - _adminLogger.Add(LogType.Action, LogImpact.Low, $"{ToPrettyString(userUid):player} buckled themselves to {ToPrettyString(strapUid)}"); - - return true; - } - - /// - /// Tries to unbuckle the Owner of this component from its current strap. - /// - /// The entity to unbuckle. - /// The entity doing the unbuckling. - /// - /// Whether to force the unbuckling or not. Does not guarantee true to - /// be returned, but guarantees the owner to be unbuckled afterwards. - /// - /// The buckle component of the entity to unbuckle. - /// - /// true if the owner was unbuckled, otherwise false even if the owner - /// was previously already unbuckled. - /// - public bool TryUnbuckle(EntityUid buckleUid, EntityUid userUid, bool force = false, BuckleComponent? buckleComp = null) - { - if (!Resolve(buckleUid, ref buckleComp, false) || - buckleComp.BuckledTo is not { } strapUid) - return false; - - if (!force) - { - var attemptEvent = new BuckleAttemptEvent(strapUid, buckleUid, userUid, false); - RaiseLocalEvent(attemptEvent.BuckledEntity, ref attemptEvent); - RaiseLocalEvent(attemptEvent.StrapEntity, ref attemptEvent); - if (attemptEvent.Cancelled) - return false; - - if (_gameTiming.CurTime < buckleComp.BuckleTime + buckleComp.Delay) - return false; - - if (!_interaction.InRangeUnobstructed(userUid, strapUid, buckleComp.Range, popup: true)) - return false; - - if (HasComp(buckleUid) && buckleUid == userUid) - return false; - - // If the person is crit or dead in any kind of strap, return. This prevents people from unbuckling themselves while incapacitated. - if (_mobState.IsIncapacitated(buckleUid) && userUid == buckleUid) - return false; - } - - // Logging - if (userUid != buckleUid) - _adminLogger.Add(LogType.Action, LogImpact.Low, $"{ToPrettyString(userUid):player} unbuckled {ToPrettyString(buckleUid)} from {ToPrettyString(strapUid)}"); - else - _adminLogger.Add(LogType.Action, LogImpact.Low, $"{ToPrettyString(userUid):player} unbuckled themselves from {ToPrettyString(strapUid)}"); - - SetBuckledTo(buckleUid, null, null, buckleComp); - - if (!TryComp(strapUid, out var strapComp)) - return false; - - var buckleXform = Transform(buckleUid); - var oldBuckledXform = Transform(strapUid); - - if (buckleXform.ParentUid == strapUid && !Terminating(buckleXform.ParentUid)) - { - _container.AttachParentToContainerOrGrid((buckleUid, buckleXform)); - - var oldBuckledToWorldRot = _transform.GetWorldRotation(strapUid); - _transform.SetWorldRotation(buckleXform, oldBuckledToWorldRot); - - if (strapComp.UnbuckleOffset != Vector2.Zero) - buckleXform.Coordinates = oldBuckledXform.Coordinates.Offset(strapComp.UnbuckleOffset); - } - - if (TryComp(buckleUid, out AppearanceComponent? appearance)) - Appearance.SetData(buckleUid, BuckleVisuals.Buckled, false, appearance); - _rotationVisuals.ResetHorizontalAngle(buckleUid); - - if (TryComp(buckleUid, out var mobState) - && _mobState.IsIncapacitated(buckleUid, mobState) - || HasComp(buckleUid)) - { - _standing.Down(buckleUid); - } - else - { - _standing.Stand(buckleUid); - } - - if (_mobState.IsIncapacitated(buckleUid, mobState)) - { - _standing.Down(buckleUid); - } - if (strapComp.BuckledEntities.Remove(buckleUid)) - { - strapComp.OccupiedSize -= buckleComp.Size; - //Dirty(strapUid); - Dirty(strapComp); - } - - _joints.RefreshRelay(buckleUid); - Appearance.SetData(strapUid, StrapVisuals.State, strapComp.BuckledEntities.Count != 0); - - // TODO: Buckle listening to moveevents is sussy anyway. - if (!TerminatingOrDeleted(strapUid)) - _audio.PlayPredicted(strapComp.UnbuckleSound, strapUid, userUid); - - var ev = new BuckleChangeEvent(strapUid, buckleUid, false); - RaiseLocalEvent(buckleUid, ref ev); - RaiseLocalEvent(strapUid, ref ev); - - return true; - } - - /// - /// Makes an entity toggle the buckling status of the owner to a - /// specific entity. - /// - /// The entity to buckle/unbuckle from . - /// The entity doing the buckling/unbuckling. - /// - /// The entity to toggle the buckle status of the owner to. - /// - /// - /// Whether to force the unbuckling or not, if it happens. Does not - /// guarantee true to be returned, but guarantees the owner to be - /// unbuckled afterwards. - /// - /// The buckle component of the entity to buckle/unbuckle from . - /// true if the buckling status was changed, false otherwise. - public bool ToggleBuckle( - EntityUid buckleUid, - EntityUid userUid, - EntityUid strapUid, - bool force = false, - BuckleComponent? buckle = null) - { - if (!Resolve(buckleUid, ref buckle, false)) - return false; - - if (!buckle.Buckled) - { - return TryBuckle(buckleUid, userUid, strapUid, buckle); - } - else - { - return TryUnbuckle(buckleUid, userUid, force, buckle); - } - - } -} diff --git a/Content.Shared/Buckle/SharedBuckleSystem.Strap.cs b/Content.Shared/Buckle/SharedBuckleSystem.Strap.cs deleted file mode 100644 index 7be54360741..00000000000 --- a/Content.Shared/Buckle/SharedBuckleSystem.Strap.cs +++ /dev/null @@ -1,318 +0,0 @@ -using System.Linq; -using Content.Shared.Buckle.Components; -using Content.Shared.Construction; -using Content.Shared.Destructible; -using Content.Shared.DragDrop; -using Content.Shared.Foldable; -using Content.Shared.Interaction; -using Content.Shared.Rotation; -using Content.Shared.Storage; -using Content.Shared.Verbs; -using Robust.Shared.Containers; - -namespace Content.Shared.Buckle; - -public abstract partial class SharedBuckleSystem -{ - [Dependency] private readonly SharedRotationVisualsSystem _rotationVisuals = default!; - - private void InitializeStrap() - { - SubscribeLocalEvent(OnStrapStartup); - SubscribeLocalEvent(OnStrapShutdown); - SubscribeLocalEvent((_, c, _) => StrapRemoveAll(c)); - - SubscribeLocalEvent(OnStrapEntModifiedFromContainer); - SubscribeLocalEvent(OnStrapEntModifiedFromContainer); - SubscribeLocalEvent>(AddStrapVerbs); - SubscribeLocalEvent(OnStrapContainerGettingInsertedAttempt); - SubscribeLocalEvent(OnStrapInteractHand); - SubscribeLocalEvent((_,c,_) => StrapRemoveAll(c)); - SubscribeLocalEvent((_, c, _) => StrapRemoveAll(c)); - - SubscribeLocalEvent(OnStrapDragDropTarget); - SubscribeLocalEvent(OnCanDropTarget); - SubscribeLocalEvent(OnAttemptFold); - - SubscribeLocalEvent(OnStrapMoveEvent); - SubscribeLocalEvent((_, c, _) => StrapRemoveAll(c)); - } - - private void OnStrapStartup(EntityUid uid, StrapComponent component, ComponentStartup args) - { - Appearance.SetData(uid, StrapVisuals.State, component.BuckledEntities.Count != 0); - } - - private void OnStrapShutdown(EntityUid uid, StrapComponent component, ComponentShutdown args) - { - if (LifeStage(uid) > EntityLifeStage.MapInitialized) - return; - - StrapRemoveAll(component); - } - - private void OnStrapEntModifiedFromContainer(EntityUid uid, StrapComponent component, ContainerModifiedMessage message) - { - if (_gameTiming.ApplyingState) - return; - - foreach (var buckledEntity in component.BuckledEntities) - { - if (!TryComp(buckledEntity, out var buckleComp)) - { - continue; - } - - ContainerModifiedReAttach(buckledEntity, uid, buckleComp, component); - } - } - - private void ContainerModifiedReAttach(EntityUid buckleUid, EntityUid strapUid, BuckleComponent? buckleComp = null, StrapComponent? strapComp = null) - { - if (!Resolve(buckleUid, ref buckleComp, false) || - !Resolve(strapUid, ref strapComp, false)) - return; - - var contained = _container.TryGetContainingContainer(buckleUid, out var ownContainer); - var strapContained = _container.TryGetContainingContainer(strapUid, out var strapContainer); - - if (contained != strapContained || ownContainer != strapContainer) - { - TryUnbuckle(buckleUid, buckleUid, true, buckleComp); - return; - } - - if (!contained) - { - ReAttach(buckleUid, strapUid, buckleComp, strapComp); - } - } - - private void OnStrapContainerGettingInsertedAttempt(EntityUid uid, StrapComponent component, ContainerGettingInsertedAttemptEvent args) - { - // If someone is attempting to put this item inside of a backpack, ensure that it has no entities strapped to it. - if (HasComp(args.Container.Owner) && component.BuckledEntities.Count != 0) - args.Cancel(); - } - - private void OnStrapInteractHand(EntityUid uid, StrapComponent component, InteractHandEvent args) - { - if (args.Handled) - return; - - args.Handled = ToggleBuckle(args.User, args.User, uid); - } - - private void AddStrapVerbs(EntityUid uid, StrapComponent component, GetVerbsEvent args) - { - if (args.Hands == null || !args.CanAccess || !args.CanInteract || !component.Enabled) - return; - - // Note that for whatever bloody reason, buckle component has its own interaction range. Additionally, this - // range can be set per-component, so we have to check a modified InRangeUnobstructed for every verb. - - // Add unstrap verbs for every strapped entity. - foreach (var entity in component.BuckledEntities) - { - var buckledComp = Comp(entity); - - if (!_interaction.InRangeUnobstructed(args.User, args.Target, range: buckledComp.Range)) - continue; - - var verb = new InteractionVerb() - { - Act = () => TryUnbuckle(entity, args.User, buckleComp: buckledComp), - Category = VerbCategory.Unbuckle, - Text = entity == args.User - ? Loc.GetString("verb-self-target-pronoun") - : Comp(entity).EntityName - }; - - // In the event that you have more than once entity with the same name strapped to the same object, - // these two verbs will be identical according to Verb.CompareTo, and only one with actually be added to - // the verb list. However this should rarely ever be a problem. If it ever is, it could be fixed by - // appending an integer to verb.Text to distinguish the verbs. - - args.Verbs.Add(verb); - } - - // Add a verb to buckle the user. - if (TryComp(args.User, out var buckle) && - buckle.BuckledTo != uid && - args.User != uid && - StrapHasSpace(uid, buckle, component) && - _interaction.InRangeUnobstructed(args.User, args.Target, range: buckle.Range)) - { - InteractionVerb verb = new() - { - Act = () => TryBuckle(args.User, args.User, args.Target, buckle), - Category = VerbCategory.Buckle, - Text = Loc.GetString("verb-self-target-pronoun") - }; - args.Verbs.Add(verb); - } - - // If the user is currently holding/pulling an entity that can be buckled, add a verb for that. - if (args.Using is {Valid: true} @using && - TryComp(@using, out var usingBuckle) && - StrapHasSpace(uid, usingBuckle, component) && - _interaction.InRangeUnobstructed(@using, args.Target, range: usingBuckle.Range)) - { - // Check that the entity is unobstructed from the target (ignoring the user). - bool Ignored(EntityUid entity) => entity == args.User || entity == args.Target || entity == @using; - if (!_interaction.InRangeUnobstructed(@using, args.Target, usingBuckle.Range, predicate: Ignored)) - return; - - var isPlayer = _playerManager.TryGetSessionByEntity(@using, out var _); - InteractionVerb verb = new() - { - Act = () => TryBuckle(@using, args.User, args.Target, usingBuckle), - Category = VerbCategory.Buckle, - Text = Comp(@using).EntityName, - // just a held object, the user is probably just trying to sit down. - // If the used entity is a person being pulled, prioritize this verb. Conversely, if it is - Priority = isPlayer ? 1 : -1 - }; - - args.Verbs.Add(verb); - } - } - - private void OnCanDropTarget(EntityUid uid, StrapComponent component, ref CanDropTargetEvent args) - { - args.CanDrop = StrapCanDragDropOn(uid, args.User, uid, args.Dragged, component); - args.Handled = true; - } - - private void OnAttemptFold(EntityUid uid, StrapComponent component, ref FoldAttemptEvent args) - { - if (args.Cancelled) - return; - - args.Cancelled = component.BuckledEntities.Count != 0; - } - - private void OnStrapDragDropTarget(EntityUid uid, StrapComponent component, ref DragDropTargetEvent args) - { - if (!StrapCanDragDropOn(uid, args.User, uid, args.Dragged, component)) - return; - - args.Handled = TryBuckle(args.Dragged, args.User, uid); - } - - private void OnStrapMoveEvent(EntityUid uid, StrapComponent component, ref MoveEvent args) - { - // TODO: This looks dirty af. - // On rotation of a strap, reattach all buckled entities. - // This fixes buckle offsets and draw depths. - // This is mega cursed. Please somebody save me from Mr Buckle's wild ride. - // Oh god I'm back here again. Send help. - - // Consider a chair that has a player strapped to it. Then the client receives a new server state, showing - // that the player entity has moved elsewhere, and the chair has rotated. If the client applies the player - // state, then the chairs transform comp state, and then the buckle state. The transform state will - // forcefully teleport the player back to the chair (client-side only). This causes even more issues if the - // chair was teleporting in from nullspace after having left PVS. - // - // One option is to just never trigger re-buckles during state application. - // another is to.. just not do this? Like wtf is this code. But I CBF with buckle atm. - - if (_gameTiming.ApplyingState || args.NewRotation == args.OldRotation) - return; - - foreach (var buckledEntity in component.BuckledEntities) - { - if (!TryComp(buckledEntity, out var buckled)) - continue; - - if (!buckled.Buckled || buckled.LastEntityBuckledTo != uid) - { - Log.Error($"A moving strap entity {ToPrettyString(uid)} attempted to re-parent an entity that does not 'belong' to it {ToPrettyString(buckledEntity)}"); - continue; - } - - ReAttach(buckledEntity, uid, buckled, component); - Dirty(buckled); - } - } - - private bool StrapCanDragDropOn( - EntityUid strapUid, - EntityUid userUid, - EntityUid targetUid, - EntityUid buckleUid, - StrapComponent? strapComp = null, - BuckleComponent? buckleComp = null) - { - if (!Resolve(strapUid, ref strapComp, false) || - !Resolve(buckleUid, ref buckleComp, false)) - { - return false; - } - - bool Ignored(EntityUid entity) => entity == userUid || entity == buckleUid || entity == targetUid; - - return _interaction.InRangeUnobstructed(targetUid, buckleUid, buckleComp.Range, predicate: Ignored); - } - - /// - /// Remove everything attached to the strap - /// - private void StrapRemoveAll(StrapComponent strapComp) - { - foreach (var entity in strapComp.BuckledEntities.ToArray()) - { - TryUnbuckle(entity, entity, true); - } - - strapComp.BuckledEntities.Clear(); - strapComp.OccupiedSize = 0; - Dirty(strapComp); - } - - private bool StrapHasSpace(EntityUid strapUid, BuckleComponent buckleComp, StrapComponent? strapComp = null) - { - if (!Resolve(strapUid, ref strapComp, false)) - return false; - - return strapComp.OccupiedSize + buckleComp.Size <= strapComp.Size; - } - - /// - /// Try to add an entity to the strap - /// - private bool StrapTryAdd(EntityUid strapUid, EntityUid buckleUid, BuckleComponent buckleComp, bool force = false, StrapComponent? strapComp = null) - { - if (!Resolve(strapUid, ref strapComp, false) || - !strapComp.Enabled) - return false; - - if (!force && !StrapHasSpace(strapUid, buckleComp, strapComp)) - return false; - - if (!strapComp.BuckledEntities.Add(buckleUid)) - return false; - - strapComp.OccupiedSize += buckleComp.Size; - - Appearance.SetData(strapUid, StrapVisuals.State, true); - - Dirty(strapUid, strapComp); - return true; - } - - /// - /// Sets the enabled field in the strap component to a value - /// - public void StrapSetEnabled(EntityUid strapUid, bool enabled, StrapComponent? strapComp = null) - { - if (!Resolve(strapUid, ref strapComp, false) || - strapComp.Enabled == enabled) - return; - - strapComp.Enabled = enabled; - - if (!enabled) - StrapRemoveAll(strapComp); - } -} diff --git a/Content.Shared/Buckle/SharedBuckleSystem.cs b/Content.Shared/Buckle/SharedBuckleSystem.cs index 8f683356637..a7ab4a4b10f 100644 --- a/Content.Shared/Buckle/SharedBuckleSystem.cs +++ b/Content.Shared/Buckle/SharedBuckleSystem.cs @@ -40,7 +40,6 @@ public abstract partial class SharedBuckleSystem : EntitySystem [Dependency] private readonly StandingStateSystem _standing = default!; [Dependency] private readonly SharedPhysicsSystem _physics = default!; - /// public override void Initialize() { base.Initialize(); @@ -52,27 +51,239 @@ public override void Initialize() InitializeStrap(); } - /// - /// Reattaches this entity to the strap, modifying its position and rotation. - /// - /// The entity to reattach. - /// The entity to reattach the buckleUid entity to. - private void ReAttach( - EntityUid buckleUid, - EntityUid strapUid, - BuckleComponent? buckleComp = null, - StrapComponent? strapComp = null) + private void InitializeBuckle() { - if (!Resolve(strapUid, ref strapComp, false) - || !Resolve(buckleUid, ref buckleComp, false)) + SubscribeLocalEvent(OnBuckleStartup); + SubscribeLocalEvent(OnBuckleShutdown); + SubscribeLocalEvent(OnBuckleMove); + SubscribeLocalEvent(OnBuckleInteractHand); + SubscribeLocalEvent>(AddUnbuckleVerb); + SubscribeLocalEvent(OnBucklePreventCollide); + SubscribeLocalEvent(OnBuckleDownAttempt); + SubscribeLocalEvent(OnBuckleStandAttempt); + SubscribeLocalEvent(OnBuckleThrowPushbackAttempt); + SubscribeLocalEvent(OnBuckleUpdateCanMove); + } + + private void OnBuckleStartup(EntityUid uid, BuckleComponent component, ComponentStartup args) + { + UpdateBuckleStatus(uid, component); + } + + private void OnBuckleShutdown(EntityUid uid, BuckleComponent component, ComponentShutdown args) + { + TryUnbuckle(uid, uid, true, component); + } + + private void OnBuckleMove(EntityUid uid, BuckleComponent component, ref MoveEvent args) + { + if (component.BuckledTo == null || component.BuckledTo == uid) + return; + + if (!_transform.GetWorldPosition(uid).InRange(_transform.GetWorldPosition(component.BuckledTo.Value), component.Range)) + TryUnbuckle(uid, uid, true, component); + } + + private void OnBuckleInteractHand(EntityUid uid, BuckleComponent component, InteractHandEvent args) + { + if (args.Handled) + return; + + if (component.Buckled) + TryUnbuckle(uid, args.User, false, component); + else + TryBuckle(uid, args.User, args.Target, component); + + args.Handled = true; + } + + private void AddUnbuckleVerb(EntityUid uid, BuckleComponent component, GetVerbsEvent args) + { + if (!component.Buckled) + return; + + InteractionVerb verb = new() + { + Text = "Unbuckle", + Act = () => TryUnbuckle(uid, args.User, false, component), + Category = VerbCategory.Unbuckle + }; + + args.Verbs.Add(verb); + } + + private void OnBucklePreventCollide(EntityUid uid, BuckleComponent component, PreventCollideEvent args) + { + if (component.BuckledTo == null) + return; + + if (args.OtherEntity == component.BuckledTo) + args.Cancel(); + } + + private void OnBuckleDownAttempt(EntityUid uid, BuckleComponent component, DownAttemptEvent args) + { + if (component.Buckled) + args.Cancel(); + } + + private void OnBuckleStandAttempt(EntityUid uid, BuckleComponent component, StandAttemptEvent args) + { + if (component.Buckled) + args.Cancel(); + } + + private void OnBuckleThrowPushbackAttempt(EntityUid uid, BuckleComponent component, ThrowPushbackAttemptEvent args) + { + if (component.Buckled) + args.Cancel(); + } + + private void OnBuckleUpdateCanMove(EntityUid uid, BuckleComponent component, UpdateCanMoveEvent args) + { + if (component.Buckled) + args.Cancel(); + } + + private void UpdateBuckleStatus(EntityUid uid, BuckleComponent component) + { + if (component.BuckledTo == null) + return; + + var strap = Comp(component.BuckledTo.Value); + if (strap == null) + return; + + if (strap.BuckledEntities.Contains(uid)) + return; + + strap.BuckledEntities.Add(uid); + strap.OccupiedSize += component.Size; + Dirty(strap); + } + + private bool TryBuckle(EntityUid buckleUid, EntityUid userUid, EntityUid strapUid, BuckleComponent? buckleComp = null, StrapComponent? strapComp = null) + { + if (!Resolve(buckleUid, ref buckleComp, false) || !Resolve(strapUid, ref strapComp, false)) + return false; + + if (buckleComp.Buckled || !CanBuckle(buckleUid, strapUid, buckleComp, strapComp)) + return false; + + buckleComp.Buckled = true; + buckleComp.BuckledTo = strapUid; + buckleComp.BuckleTime = _gameTiming.CurTime; + + strapComp.BuckledEntities.Add(buckleUid); + strapComp.OccupiedSize += buckleComp.Size; + + ReAttach(buckleUid, strapUid, buckleComp, strapComp); + + _audio.PlayPredicted(strapComp.BuckleSound, strapUid, userUid); + _alerts.ShowAlert(buckleUid, strapComp.BuckledAlertType); + + var ev = new BuckleChangeEvent(strapUid, buckleUid, true); + RaiseLocalEvent(buckleUid, ref ev); + RaiseLocalEvent(strapUid, ref ev); + + return true; + } + + private bool TryUnbuckle(EntityUid buckleUid, EntityUid userUid, bool force, BuckleComponent? buckleComp = null, StrapComponent? strapComp = null) + { + if (!Resolve(buckleUid, ref buckleComp, false) || !buckleComp.Buckled || !Resolve(buckleComp.BuckledTo, ref strapComp, false)) + return false; + + if (!force && _gameTiming.CurTime < buckleComp.BuckleTime + buckleComp.Delay) + return false; + + buckleComp.Buckled = false; + buckleComp.BuckledTo = null; + + if (_mobState.IsIncapacitated(buckleUid)) + _standing.Down(buckleUid); + + if (strapComp.BuckledEntities.Remove(buckleUid)) + { + strapComp.OccupiedSize -= buckleComp.Size; + Dirty(strapComp); + } + + _joints.RefreshRelay(buckleUid); + Appearance.SetData(strapUid, StrapVisuals.State, strapComp.BuckledEntities.Count != 0); + + if (!TerminatingOrDeleted(strapUid)) + _audio.PlayPredicted(strapComp.UnbuckleSound, strapUid, userUid); + + var ev = new BuckleChangeEvent(strapUid, buckleUid, false); + RaiseLocalEvent(buckleUid, ref ev); + RaiseLocalEvent(strapUid, ref ev); + + return true; + } + + private bool CanBuckle(EntityUid buckleUid, EntityUid userUid, EntityUid strapUid, [NotNullWhen(true)] out StrapComponent? strapComp, BuckleComponent? buckleComp = null) + { + strapComp = null; + + // Guard clauses + if (userUid == strapUid || !Resolve(buckleUid, ref buckleComp, false) || !Resolve(strapUid, ref strapComp, false)) + return false; + + if (!IsAllowedBuckleType(buckleComp, userUid)) + return false; + + if (!IsStrapEnabled(strapComp)) + return false; + + if (!IsStrapSizeValid(buckleComp, strapComp)) + return false; + + if (!IsInRange(buckleUid, strapUid, buckleComp)) + return false; + + if (!IsEntityAllowed(buckleUid, strapComp)) + return false; + + return true; + } + + private bool IsAllowedBuckleType(BuckleComponent? buckleComp, EntityUid userUid) + { + if (buckleComp?.AllowedBuckleTypes != null && !buckleComp.AllowedBuckleTypes.IsValid(userUid, EntityManager)) + { + if (_netManager.IsServer) + _popup.PopupEntity(Loc.GetString("buckle-component-cannot-fit-message"), userUid, buckleUid, PopupType.Medium); + return false; + } + + return true; + } + + private bool IsStrapEnabled(StrapComponent? strapComp) + => strapComp?.Enabled == true; + + private bool IsStrapSizeValid(BuckleComponent? buckleComp, StrapComponent? strapComp) + => buckleComp != null && strapComp != null && strapComp.OccupiedSize + buckleComp.Size <= strapComp.Size; + + private bool IsInRange(EntityUid buckleUid, EntityUid strapUid, BuckleComponent? buckleComp) + => buckleComp != null && _interaction.InRangeUnobstructed(buckleUid, strapUid, buckleComp.Range); + + private bool IsEntityAllowed(EntityUid buckleUid, StrapComponent? strapComp) + => strapComp?.AllowedEntities == null || strapComp.AllowedEntities.IsValid(buckleUid); + + private void ReAttach(EntityUid buckleUid, EntityUid strapUid, BuckleComponent? buckleComp = null, StrapComponent? strapComp = null) + { + if (!Resolve(strapUid, ref strapComp, false) || !Resolve(buckleUid, ref buckleComp, false)) return; _transform.SetCoordinates(buckleUid, new EntityCoordinates(strapUid, strapComp.BuckleOffsetClamped)); var buckleTransform = Transform(buckleUid); - // Buckle subscribes to move for so this might fail. + // Buckle subscribes to move for < reasons > so this might fail. // TODO: Make buckle not do that. + if (buckleTransform.ParentUid != strapUid) return; diff --git a/Content.Shared/Vehicles/Components/VehicleKeyComponent.cs b/Content.Shared/Vehicles/Components/VehicleKeyComponent.cs new file mode 100644 index 00000000000..0f487b77138 --- /dev/null +++ b/Content.Shared/Vehicles/Components/VehicleKeyComponent.cs @@ -0,0 +1,16 @@ +// /Content.Shared/Vehicles/Components/VehicleKeyComponent.cs +using Robust.Shared.GameObjects; +using Robust.Shared.Serialization.Manager.Attributes; + +namespace Content.Shared.Vehicles.Components +{ + [RegisterComponent] + public sealed class VehicleKeyComponent : Component + { + [DataField("keyId")] + public string KeyId { get; set; } = string.Empty; + + [DataField("isLocked")] + public bool IsLocked { get; set; } = true; + } +} diff --git a/Resources/Prototypes/Entities/Vehicles/vehicles.yml b/Resources/Prototypes/Entities/Vehicles/vehicles.yml new file mode 100644 index 00000000000..1201f2a3ad0 --- /dev/null +++ b/Resources/Prototypes/Entities/Vehicles/vehicles.yml @@ -0,0 +1,26 @@ +- type: entity + id: VehicleCar + name: Car + description: A simple car for transportation. + components: + - type: Sprite + sprite: Vehicles/car.rsi + - type: Physics + - type: MovementSpeedModifier + baseWalkSpeed: 3.0 + baseSprintSpeed: 6.0 + - type: Vehicle + maxOccupants: 4 + maxDrivers: 1 + - type: Damageable + damageContainer: Vehicle + - type: Destructible + thresholds: + - trigger: !type:DamageTrigger + damage: 100 + behaviors: + - !type:DoActsBehavior + acts: ["Destruction"] + - type: ContainerContainer + containers: + vehicle_storage: !type:Container From eb94920e5ace811226a07db7a96b8bf3199f89f7 Mon Sep 17 00:00:00 2001 From: Acensti Date: Sat, 6 Jul 2024 21:43:32 +0200 Subject: [PATCH 2/8] Create VehicleComponent.cs --- .../Vehicles/Components/VehicleComponent.cs | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 Content.Server/Vehicles/Components/VehicleComponent.cs diff --git a/Content.Server/Vehicles/Components/VehicleComponent.cs b/Content.Server/Vehicles/Components/VehicleComponent.cs new file mode 100644 index 00000000000..fc1602225f0 --- /dev/null +++ b/Content.Server/Vehicles/Components/VehicleComponent.cs @@ -0,0 +1,19 @@ +// /Content.Server/Vehicles/Components/VehicleComponent.cs +using Robust.Shared.GameObjects; +using Robust.Shared.Serialization.Manager.Attributes; + +namespace Content.Server.Vehicles.Components +{ + [RegisterComponent] + public sealed class VehicleComponent : Component + { + [DataField("maxOccupants")] + public int MaxOccupants { get; set; } = 4; + + [DataField("maxDrivers")] + public int MaxDrivers { get; set; } = 1; + + public List Occupants { get; set; } = new(); + public EntityUid? Driver { get; set; } + } +} From 597ac3284da333fe47f9f2c76433856d69bab798 Mon Sep 17 00:00:00 2001 From: Acensti Date: Sun, 7 Jul 2024 12:48:02 +0200 Subject: [PATCH 3/8] hey --- Content.Client/Vehicle/ClientVehicleSystem.cs | 27 ++++++++ .../Vehicles/Components/VehicleComponent.cs | 19 ++++-- .../Vehicles/Systems/VehicleSystem.cs | 65 +++++++++++++++++-- .../Buckle/Components/StrapComponent.cs | 6 ++ Content.Shared/Buckle/SharedBuckleSystem.cs | 34 +++++++--- Content.Shared/Key/KeyComponent.cs | 14 ++++ Content.Shared/Key/KeyRequiredComponent.cs | 14 ++++ Content.Shared/Key/KeySystem.cs | 28 ++++++++ .../Vehicles/Components/KeyRequiredComponent | 18 +++++ .../Components/RiddenVehicleComponent.cs | 18 +++++ .../Vehicles/Components/VehicleComponent.cs | 24 +++++++ Content.Shared/Vehicles/KeySystem.cs | 50 ++++++++++++++ .../Vehicles/RiddenVehicleComponentState.cs | 16 +++++ .../Vehicles/RiddenVehicleSystem.cs | 53 +++++++++++++++ .../Prototypes/Entities/Vehicles/vehicles.yml | 24 +++++++ .../Entities/Markers/Spawners/Vehicles.yml | 13 ++++ 16 files changed, 401 insertions(+), 22 deletions(-) create mode 100644 Content.Client/Vehicle/ClientVehicleSystem.cs create mode 100644 Content.Shared/Key/KeyComponent.cs create mode 100644 Content.Shared/Key/KeyRequiredComponent.cs create mode 100644 Content.Shared/Key/KeySystem.cs create mode 100644 Content.Shared/Vehicles/Components/KeyRequiredComponent create mode 100644 Content.Shared/Vehicles/Components/RiddenVehicleComponent.cs create mode 100644 Content.Shared/Vehicles/Components/VehicleComponent.cs create mode 100644 Content.Shared/Vehicles/KeySystem.cs create mode 100644 Content.Shared/Vehicles/RiddenVehicleComponentState.cs create mode 100644 Content.Shared/Vehicles/RiddenVehicleSystem.cs create mode 100644 Resources/Prototypes/Nyanotrasen/Entities/Markers/Spawners/Vehicles.yml diff --git a/Content.Client/Vehicle/ClientVehicleSystem.cs b/Content.Client/Vehicle/ClientVehicleSystem.cs new file mode 100644 index 00000000000..0716f7294bb --- /dev/null +++ b/Content.Client/Vehicle/ClientVehicleSystem.cs @@ -0,0 +1,27 @@ +using Content.Shared.Vehicle; +using Robust.Client.GameObjects; +using Robust.Shared.GameObjects; +using Robust.Shared.IoC; + +namespace Content.Client.Vehicle +{ + public sealed class ClientVehicleSystem : EntitySystem + { + [Dependency] private readonly IEntityManager _entityManager = default!; + + public override void Initialize() + { + base.Initialize(); + SubscribeLocalEvent(OnHandleState); + } + + private void OnHandleState(EntityUid uid, RiddenVehicleComponent component, ref ComponentHandleState args) + { + if (args.Current is not RiddenVehicleComponentState state) + return; + + component.Riders.Clear(); + component.Riders.AddRange(state.Riders); + } + } +} diff --git a/Content.Server/Vehicles/Components/VehicleComponent.cs b/Content.Server/Vehicles/Components/VehicleComponent.cs index fc1602225f0..dd670434a4a 100644 --- a/Content.Server/Vehicles/Components/VehicleComponent.cs +++ b/Content.Server/Vehicles/Components/VehicleComponent.cs @@ -1,19 +1,26 @@ -// /Content.Server/Vehicles/Components/VehicleComponent.cs using Robust.Shared.GameObjects; using Robust.Shared.Serialization.Manager.Attributes; -namespace Content.Server.Vehicles.Components +namespace Content.Shared.Vehicle { [RegisterComponent] public sealed class VehicleComponent : Component { + public override string Name => "Vehicle"; + [DataField("maxOccupants")] - public int MaxOccupants { get; set; } = 4; + public int MaxOccupants = 1; [DataField("maxDrivers")] - public int MaxDrivers { get; set; } = 1; + public int MaxDrivers = 1; + + [DataField("canMove")] + public bool CanMove = true; + + [DataField("keyType")] + public string? KeyType; - public List Occupants { get; set; } = new(); - public EntityUid? Driver { get; set; } + [ViewVariables] + public List Occupants = new(); } } diff --git a/Content.Server/Vehicles/Systems/VehicleSystem.cs b/Content.Server/Vehicles/Systems/VehicleSystem.cs index fe54fac0b81..baab4cafd1c 100644 --- a/Content.Server/Vehicles/Systems/VehicleSystem.cs +++ b/Content.Server/Vehicles/Systems/VehicleSystem.cs @@ -1,6 +1,11 @@ -// /Content.Server/Vehicles/Systems/VehicleSystem.cs using Content.Server.Vehicles.Components; +using Content.Shared.Buckle; +using Content.Shared.Buckle.Components; +using Content.Shared.Interaction; +using Content.Shared.Popups; +using Content.Shared.Vehicle; using Robust.Shared.GameObjects; +using Robust.Shared.IoC; using Robust.Shared.Map; using Robust.Shared.Physics; using Robust.Shared.Player; @@ -13,12 +18,16 @@ public sealed class VehicleSystem : EntitySystem [Dependency] private readonly IGameTiming _gameTiming = default!; [Dependency] private readonly IMapManager _mapManager = default!; [Dependency] private readonly IEntityManager _entityManager = default!; + [Dependency] private readonly SharedBuckleSystem _buckleSystem = default!; + [Dependency] private readonly SharedPopupSystem _popupSystem = default!; public override void Initialize() { base.Initialize(); SubscribeLocalEvent>(AddEnterVehicleVerb); SubscribeLocalEvent(OnMoveInput); + SubscribeLocalEvent(OnInteractHand); + SubscribeLocalEvent(OnBuckleChange); } private void AddEnterVehicleVerb(EntityUid uid, VehicleComponent component, GetVerbsEvent args) @@ -40,12 +49,20 @@ private void AddEnterVehicleVerb(EntityUid uid, VehicleComponent component, GetV private void EnterVehicle(EntityUid user, EntityUid vehicle, VehicleComponent component) { - component.Occupants.Add(user); - if (component.Driver == null) + if (component.Occupants.Count >= component.MaxOccupants) + { + _popupSystem.PopupEntity("The vehicle is full.", vehicle, Filter.Entities(user)); + return; + } + + if (_buckleSystem.TryBuckle(user, user, vehicle)) { - component.Driver = user; + component.Occupants.Add(user); + if (component.Driver == null) + { + component.Driver = user; + } } - //TODO Additional logic to attach user to vehicle, update UI, etc maybe. } private void OnMoveInput(EntityUid uid, VehicleComponent component, ref MoveInputEvent args) @@ -53,7 +70,43 @@ private void OnMoveInput(EntityUid uid, VehicleComponent component, ref MoveInpu if (component.Driver == null || component.Driver != args.User) return; - // Handle vehicle movement logic here. Surely theres a component for that im just tossing ideas + // Handle vehicle movement logic here. + var transform = EntityManager.GetComponent(uid); + var direction = args.Direction.ToVec(); + transform.Coordinates += direction * component.Speed * _gameTiming.FrameTime; + } + + private void OnInteractHand(EntityUid uid, VehicleComponent component, InteractHandEvent args) + { + if (args.Handled) + return; + + if (component.Occupants.Contains(args.User)) + { + _buckleSystem.TryUnbuckle(args.User, args.User, false); + } + else + { + EnterVehicle(args.User, uid, component); + } + + args.Handled = true; + } + + private void OnBuckleChange(EntityUid uid, VehicleComponent component, BuckleChangeEvent args) + { + if (args.Buckled) + { + component.Occupants.Add(args.BuckleEntity); + } + else + { + component.Occupants.Remove(args.BuckleEntity); + if (component.Driver == args.BuckleEntity) + { + component.Driver = component.Occupants.Count > 0 ? component.Occupants[0] : null; + } + } } } } diff --git a/Content.Shared/Buckle/Components/StrapComponent.cs b/Content.Shared/Buckle/Components/StrapComponent.cs index 7585ba0fe88..e393cfd588b 100644 --- a/Content.Shared/Buckle/Components/StrapComponent.cs +++ b/Content.Shared/Buckle/Components/StrapComponent.cs @@ -21,6 +21,7 @@ public sealed partial class StrapComponent : Component /// [DataField] [ViewVariables(VVAccess.ReadWrite)] + [AutoNetworkedField] public float MaxBuckleDistance = 1.0f; /// @@ -42,6 +43,7 @@ public sealed partial class StrapComponent : Component /// [DataField] [ViewVariables(VVAccess.ReadWrite)] + [AutoNetworkedField] public int Size = 100; /// @@ -55,6 +57,7 @@ public sealed partial class StrapComponent : Component /// [DataField] [ViewVariables(VVAccess.ReadWrite)] + [AutoNetworkedField] public bool Enabled = true; /// @@ -62,6 +65,7 @@ public sealed partial class StrapComponent : Component /// [DataField] [ViewVariables(VVAccess.ReadWrite)] + [AutoNetworkedField] public AlertType BuckledAlertType = AlertType.Buckled; /// @@ -69,6 +73,7 @@ public sealed partial class StrapComponent : Component /// [DataField] [ViewVariables(VVAccess.ReadWrite)] + [AutoNetworkedField] public SoundSpecifier BuckleSound = new SoundPathSpecifier("/Audio/Effects/buckle.ogg"); /// @@ -76,6 +81,7 @@ public sealed partial class StrapComponent : Component /// [DataField] [ViewVariables(VVAccess.ReadWrite)] + [AutoNetworkedField] public SoundSpecifier UnbuckleSound = new SoundPathSpecifier("/Audio/Effects/unbuckle.ogg"); } diff --git a/Content.Shared/Buckle/SharedBuckleSystem.cs b/Content.Shared/Buckle/SharedBuckleSystem.cs index a7ab4a4b10f..77b24115dff 100644 --- a/Content.Shared/Buckle/SharedBuckleSystem.cs +++ b/Content.Shared/Buckle/SharedBuckleSystem.cs @@ -1,3 +1,11 @@ +using System.Diagnostics.CodeAnalysis; +using Content.Shared.Verbs; +using Content.Shared.Physics; +using Content.Shared.Throwing; +using Content.Shared.Movement; +using Content.Shared.Movement.Events; +using Robust.Shared.GameStates; +using Robust.Shared.Serialization; using Content.Shared.ActionBlocker; using Content.Shared.Administration.Logs; using Content.Shared.Alert; @@ -15,6 +23,7 @@ using Robust.Shared.Physics.Systems; using Robust.Shared.Player; using Robust.Shared.Timing; +using Robust.Shared.Utility; namespace Content.Shared.Buckle; @@ -51,6 +60,11 @@ public override void Initialize() InitializeStrap(); } + private void InitializeStrap() + { + // Initialization logic for straps... + } + private void InitializeBuckle() { SubscribeLocalEvent(OnBuckleStartup); @@ -159,15 +173,15 @@ private void UpdateBuckleStatus(EntityUid uid, BuckleComponent component) strap.BuckledEntities.Add(uid); strap.OccupiedSize += component.Size; - Dirty(strap); + Dirty(component.BuckledTo.Value, strap); } - private bool TryBuckle(EntityUid buckleUid, EntityUid userUid, EntityUid strapUid, BuckleComponent? buckleComp = null, StrapComponent? strapComp = null) + public bool TryBuckle(EntityUid buckleUid, EntityUid userUid, EntityUid strapUid, BuckleComponent? buckleComp = null, StrapComponent? strapComp = null) { if (!Resolve(buckleUid, ref buckleComp, false) || !Resolve(strapUid, ref strapComp, false)) return false; - if (buckleComp.Buckled || !CanBuckle(buckleUid, strapUid, buckleComp, strapComp)) + if (buckleComp.Buckled || !CanBuckle(buckleUid, userUid, strapUid, out strapComp, buckleComp)) return false; buckleComp.Buckled = true; @@ -189,7 +203,7 @@ private bool TryBuckle(EntityUid buckleUid, EntityUid userUid, EntityUid strapUi return true; } - private bool TryUnbuckle(EntityUid buckleUid, EntityUid userUid, bool force, BuckleComponent? buckleComp = null, StrapComponent? strapComp = null) + public bool TryUnbuckle(EntityUid buckleUid, EntityUid userUid, bool force, BuckleComponent? buckleComp = null, StrapComponent? strapComp = null) { if (!Resolve(buckleUid, ref buckleComp, false) || !buckleComp.Buckled || !Resolve(buckleComp.BuckledTo, ref strapComp, false)) return false; @@ -206,18 +220,18 @@ private bool TryUnbuckle(EntityUid buckleUid, EntityUid userUid, bool force, Buc if (strapComp.BuckledEntities.Remove(buckleUid)) { strapComp.OccupiedSize -= buckleComp.Size; - Dirty(strapComp); + Dirty(strapComp.Owner, strapComp); } _joints.RefreshRelay(buckleUid); - Appearance.SetData(strapUid, StrapVisuals.State, strapComp.BuckledEntities.Count != 0); + Appearance.SetData(strapComp.Owner, StrapVisuals.State, strapComp.BuckledEntities.Count != 0); - if (!TerminatingOrDeleted(strapUid)) - _audio.PlayPredicted(strapComp.UnbuckleSound, strapUid, userUid); + if (!TerminatingOrDeleted(strapComp.Owner)) + _audio.PlayPredicted(strapComp.UnbuckleSound, strapComp.Owner, userUid); - var ev = new BuckleChangeEvent(strapUid, buckleUid, false); + var ev = new BuckleChangeEvent(strapComp.Owner, buckleUid, false); RaiseLocalEvent(buckleUid, ref ev); - RaiseLocalEvent(strapUid, ref ev); + RaiseLocalEvent(strapComp.Owner, ref ev); return true; } diff --git a/Content.Shared/Key/KeyComponent.cs b/Content.Shared/Key/KeyComponent.cs new file mode 100644 index 00000000000..1caed5bf69f --- /dev/null +++ b/Content.Shared/Key/KeyComponent.cs @@ -0,0 +1,14 @@ +using Robust.Shared.GameObjects; +using Robust.Shared.Serialization.Manager.Attributes; + +namespace Content.Shared.Key +{ + [RegisterComponent] + public partial class KeyComponent : Component + { + public override string Name => "Key"; + + [DataField("keyId")] + public string KeyId = string.Empty; + } +} diff --git a/Content.Shared/Key/KeyRequiredComponent.cs b/Content.Shared/Key/KeyRequiredComponent.cs new file mode 100644 index 00000000000..2b8500c7ad6 --- /dev/null +++ b/Content.Shared/Key/KeyRequiredComponent.cs @@ -0,0 +1,14 @@ +using Robust.Shared.GameObjects; +using Robust.Shared.Serialization.Manager.Attributes; + +namespace Content.Shared.Key +{ + [RegisterComponent] + public partial class KeyRequiredComponent : Component + { + public override string Name => "KeyRequired"; + + [DataField("requiredKeyId")] + public string RequiredKeyId = string.Empty; + } +} diff --git a/Content.Shared/Key/KeySystem.cs b/Content.Shared/Key/KeySystem.cs new file mode 100644 index 00000000000..b91a63533c6 --- /dev/null +++ b/Content.Shared/Key/KeySystem.cs @@ -0,0 +1,28 @@ +using Robust.Shared.GameObjects; +using Robust.Shared.IoC; + +namespace Content.Shared.Key +{ + public sealed class KeySystem : EntitySystem + { + public override void Initialize() + { + base.Initialize(); + SubscribeLocalEvent(OnKeyRequiredStartup); + } + + private void OnKeyRequiredStartup(EntityUid uid, KeyRequiredComponent component, ComponentStartup args) + { + // Logic to handle key requirements + } + + public bool HasValidKey(EntityUid uid, string requiredKeyId) + { + if (EntityManager.TryGetComponent(uid, out KeyComponent? keyComp)) + { + return keyComp.KeyId == requiredKeyId; + } + return false; + } + } +} diff --git a/Content.Shared/Vehicles/Components/KeyRequiredComponent b/Content.Shared/Vehicles/Components/KeyRequiredComponent new file mode 100644 index 00000000000..e06101ac6f9 --- /dev/null +++ b/Content.Shared/Vehicles/Components/KeyRequiredComponent @@ -0,0 +1,18 @@ +using Robust.Shared.GameObjects; +using Robust.Shared.Serialization.Manager.Attributes; +using Robust.Shared.ViewVariables; + +namespace Content.Shared.Vehicle +{ + [RegisterComponent] + public sealed class KeyRequiredComponent : Component + { + public override string Name => "KeyRequired"; + + [DataField("keyType")] + public string KeyType = string.Empty; + + [ViewVariables] + public EntityUid? InsertedKey; + } +} diff --git a/Content.Shared/Vehicles/Components/RiddenVehicleComponent.cs b/Content.Shared/Vehicles/Components/RiddenVehicleComponent.cs new file mode 100644 index 00000000000..23a60c5166e --- /dev/null +++ b/Content.Shared/Vehicles/Components/RiddenVehicleComponent.cs @@ -0,0 +1,18 @@ +using Robust.Shared.GameObjects; +using Robust.Shared.Serialization.Manager.Attributes; +using Robust.Shared.ViewVariables; + +namespace Content.Shared.Vehicle +{ + [RegisterComponent] + public partial class RiddenVehicleComponent : Component + { + public override string Name => "RiddenVehicle"; + + [DataField("maxRiders")] + public int MaxRiders = 1; + + [ViewVariables] + public List Riders = new(); + } +} diff --git a/Content.Shared/Vehicles/Components/VehicleComponent.cs b/Content.Shared/Vehicles/Components/VehicleComponent.cs new file mode 100644 index 00000000000..e6a323da79b --- /dev/null +++ b/Content.Shared/Vehicles/Components/VehicleComponent.cs @@ -0,0 +1,24 @@ +using Robust.Shared.GameObjects; +using Robust.Shared.Serialization.Manager.Attributes; +using Robust.Shared.ViewVariables; + +namespace Content.Server.Vehicles.Components +{ + [RegisterComponent] + public sealed class VehicleComponent : Component + { + public override string Name => "Vehicle"; + + [DataField("maxOccupants")] + public int MaxOccupants = 1; + + [DataField("speed")] + public float Speed = 1.0f; + + [ViewVariables] + public List Occupants = new(); + + [ViewVariables] + public EntityUid? Driver; + } +} diff --git a/Content.Shared/Vehicles/KeySystem.cs b/Content.Shared/Vehicles/KeySystem.cs new file mode 100644 index 00000000000..fa7e09f64e3 --- /dev/null +++ b/Content.Shared/Vehicles/KeySystem.cs @@ -0,0 +1,50 @@ +using Content.Shared.Interaction; +using Content.Shared.Popups; +using Content.Shared.Vehicle; +using Robust.Shared.GameObjects; +using Robust.Shared.IoC; +using Robust.Shared.Player; +using Content.Shared.Vehicles.Components; +using Content.Shared.Interaction.Events; + + +namespace Content.Shared.Vehicle +{ + public sealed class KeySystem : EntitySystem + { + [Dependency] private readonly SharedPopupSystem _popupSystem = default!; + + public override void Initialize() + { + base.Initialize(); + SubscribeLocalEvent(OnInteractUsing); + SubscribeLocalEvent(OnAltInteract); + } + + private void OnInteractUsing(EntityUid uid, KeyRequiredComponent component, InteractUsingEvent args) + { + if (args.Handled) + return; + + if (component.InsertedKey == null && args.Used.HasComponent()) + { + component.InsertedKey = args.Used; + _popupSystem.PopupEntity("You insert the key.", uid, Filter.Entities(args.User)); + args.Handled = true; + } + } + + private void OnAltInteract(EntityUid uid, KeyRequiredComponent component, AltInteractEvent args) + { + if (args.Handled) + return; + + if (component.InsertedKey != null) + { + _popupSystem.PopupEntity("You remove the key.", uid, Filter.Entities(args.User)); + component.InsertedKey = null; + args.Handled = true; + } + } + } +} diff --git a/Content.Shared/Vehicles/RiddenVehicleComponentState.cs b/Content.Shared/Vehicles/RiddenVehicleComponentState.cs new file mode 100644 index 00000000000..e28e9a8fc80 --- /dev/null +++ b/Content.Shared/Vehicles/RiddenVehicleComponentState.cs @@ -0,0 +1,16 @@ +using Robust.Shared.GameObjects; +using Robust.Shared.Serialization; + +namespace Content.Shared.Vehicle +{ + [Serializable, NetSerializable] + public sealed class RiddenVehicleComponentState : ComponentState + { + public List Riders; + + public RiddenVehicleComponentState(List riders) + { + Riders = riders; + } + } +} diff --git a/Content.Shared/Vehicles/RiddenVehicleSystem.cs b/Content.Shared/Vehicles/RiddenVehicleSystem.cs new file mode 100644 index 00000000000..a3e623fc2c6 --- /dev/null +++ b/Content.Shared/Vehicles/RiddenVehicleSystem.cs @@ -0,0 +1,53 @@ +using Content.Shared.Buckle; +using Content.Shared.Buckle.Components; +using Content.Shared.Interaction; +using Content.Shared.Popups; +using Content.Shared.Vehicle; +using Robust.Shared.GameObjects; +using Robust.Shared.IoC; +using Robust.Shared.Player; + +namespace Content.Shared.Vehicle +{ + public sealed class RiddenVehicleSystem : EntitySystem + { + [Dependency] private readonly SharedBuckleSystem _buckleSystem = default!; + [Dependency] private readonly SharedPopupSystem _popupSystem = default!; + + public override void Initialize() + { + base.Initialize(); + SubscribeLocalEvent(OnInteractHand); + SubscribeLocalEvent(OnBuckleChange); + } + + private void OnInteractHand(EntityUid uid, RiddenVehicleComponent component, InteractHandEvent args) + { + if (args.Handled) + return; + + if (component.Riders.Contains(args.User)) + { + _buckleSystem.TryUnbuckle(args.User, args.User, false); + } + else + { + _buckleSystem.TryBuckle(args.User, args.User, uid); + } + + args.Handled = true; + } + + private void OnBuckleChange(EntityUid uid, RiddenVehicleComponent component, BuckleChangeEvent args) + { + if (args.Buckling) + { + component.Riders.Add(args.BuckledEntity); + } + else + { + component.Riders.Remove(args.BuckledEntity); + } + } + } +} diff --git a/Resources/Prototypes/Entities/Vehicles/vehicles.yml b/Resources/Prototypes/Entities/Vehicles/vehicles.yml index 1201f2a3ad0..075b7229016 100644 --- a/Resources/Prototypes/Entities/Vehicles/vehicles.yml +++ b/Resources/Prototypes/Entities/Vehicles/vehicles.yml @@ -24,3 +24,27 @@ - type: ContainerContainer containers: vehicle_storage: !type:Container + +- type: entity + id: VehicleSecway + name: Secway + description: A simple personal transportation device. + components: + - type: Sprite + sprite: Objects/Vehicles/secway.rsi + state: secway + - type: Physics + bodyType: Dynamic + - type: Vehicle + maxOccupants: 1 + maxDrivers: 1 + speed: 2.0 + - type: Buckle + range: 1.0 + delay: 0.5 + - type: Pullable + - type: Interactable + - type: UseDelay + delay: 0.5 + - type: Item + size: Large diff --git a/Resources/Prototypes/Nyanotrasen/Entities/Markers/Spawners/Vehicles.yml b/Resources/Prototypes/Nyanotrasen/Entities/Markers/Spawners/Vehicles.yml new file mode 100644 index 00000000000..f5c8d41e9ca --- /dev/null +++ b/Resources/Prototypes/Nyanotrasen/Entities/Markers/Spawners/Vehicles.yml @@ -0,0 +1,13 @@ +- type: entity + name: Secway Spawner + id: SpawnVehicleSecway + parent: MarkerBase + components: + - type: Sprite + layers: + - state: green + - sprite: Objects/Vehicles/secway.rsi + state: keys + - type: ConditionalSpawner + prototypes: + - VehicleSecway From 847461ec9356945841d7505160dd632b1dc7bd54 Mon Sep 17 00:00:00 2001 From: Acensti Date: Sun, 7 Jul 2024 14:10:24 +0200 Subject: [PATCH 4/8] throw what you see and see what sticks --- .../Buckle/Components/BuckleComponent.cs | 78 +++--- .../Buckle/Components/StrapComponent.cs | 18 ++ Content.Shared/Buckle/SharedBuckleSystem.cs | 248 ++++++++++++++---- 3 files changed, 248 insertions(+), 96 deletions(-) diff --git a/Content.Shared/Buckle/Components/BuckleComponent.cs b/Content.Shared/Buckle/Components/BuckleComponent.cs index ff304d46f24..1e05d348889 100644 --- a/Content.Shared/Buckle/Components/BuckleComponent.cs +++ b/Content.Shared/Buckle/Components/BuckleComponent.cs @@ -1,87 +1,81 @@ using Content.Shared.Interaction; using Robust.Shared.GameStates; using Robust.Shared.Serialization; - +using Content.Shared.Whitelist; namespace Content.Shared.Buckle.Components; [RegisterComponent, NetworkedComponent, AutoGenerateComponentState(true)] + [Access(typeof(SharedBuckleSystem))] + public sealed partial class BuckleComponent : Component + { - /// - /// The range from which this entity can buckle to a . - /// Separated from normal interaction range to fix the "someone buckled to a strap - /// across a table two tiles away" problem. - /// - [DataField] - [ViewVariables(VVAccess.ReadWrite)] + + [DataField, ViewVariables(VVAccess.ReadWrite)] + public float Range = SharedInteractionSystem.InteractionRange / 1.4f; - /// - /// True if the entity is buckled, false otherwise. - /// + [ViewVariables(VVAccess.ReadWrite)] + [AutoNetworkedField] + public bool Buckled; - /// - /// The last entity this component was buckled to. - /// + [ViewVariables] + [AutoNetworkedField] + public EntityUid? LastEntityBuckledTo; - /// - /// Whether or not collisions should be possible with the entity we are strapped to. - /// + [ViewVariables(VVAccess.ReadWrite)] + [DataField, AutoNetworkedField] + public bool DontCollide; - /// - /// Whether or not we should be allowed to pull the entity we are strapped to. - /// + [ViewVariables(VVAccess.ReadWrite)] + [DataField] + public bool PullStrap; - /// - /// The delay before the buckle/unbuckle action is completed. - /// - [DataField] - [ViewVariables(VVAccess.ReadWrite)] + + [DataField, ViewVariables(VVAccess.ReadWrite)] + public TimeSpan Delay = TimeSpan.FromSeconds(0.25f); - /// - /// The time when the buckle/unbuckle action was initiated. - /// + [ViewVariables] + public TimeSpan BuckleTime; - /// - /// The entity this component is currently buckled to. - /// + [ViewVariables] + [AutoNetworkedField] + public EntityUid? BuckledTo; - /// - /// The maximum size of entities that can be buckled to this component. - /// - [DataField] - [ViewVariables(VVAccess.ReadWrite)] + + [DataField, ViewVariables(VVAccess.ReadWrite)] + public int Size = 100; - /// - /// The original draw depth of the entity before it was buckled. - /// - [ViewVariables] public int? OriginalDrawDepth; - [DataField] + [ViewVariables] + + public int? OriginalDrawDepth; - [ViewVariables(VVAccess.ReadWrite)] + + [DataField, ViewVariables(VVAccess.ReadWrite)] public EntityWhitelist? AllowedBuckleTypes; + } [ByRefEvent] diff --git a/Content.Shared/Buckle/Components/StrapComponent.cs b/Content.Shared/Buckle/Components/StrapComponent.cs index e393cfd588b..dcb5cc0097c 100644 --- a/Content.Shared/Buckle/Components/StrapComponent.cs +++ b/Content.Shared/Buckle/Components/StrapComponent.cs @@ -1,5 +1,10 @@ using Robust.Shared.GameStates; using Robust.Shared.Serialization; +using Content.Shared.AlertLevel; +using Robust.Shared.Audio; +using System.Numerics; +using Content.Shared.Alert; +using Content.Shared.Whitelist; namespace Content.Shared.Buckle.Components; @@ -83,6 +88,19 @@ public sealed partial class StrapComponent : Component [ViewVariables(VVAccess.ReadWrite)] [AutoNetworkedField] public SoundSpecifier UnbuckleSound = new SoundPathSpecifier("/Audio/Effects/unbuckle.ogg"); + + /// + /// The allowed entities that can be buckled to this strap. + /// + [DataField] + [ViewVariables(VVAccess.ReadWrite)] + public EntityWhitelist? AllowedEntities; + + /// + /// The clamped buckle offset for this strap. + /// + [ViewVariables(VVAccess.ReadWrite)] + public Vector2 BuckleOffsetClamped => Vector2.Clamp(BuckleOffset, Vector2.One * -0.5f, Vector2.One * 0.5f); } public enum StrapPosition diff --git a/Content.Shared/Buckle/SharedBuckleSystem.cs b/Content.Shared/Buckle/SharedBuckleSystem.cs index 77b24115dff..6328415c085 100644 --- a/Content.Shared/Buckle/SharedBuckleSystem.cs +++ b/Content.Shared/Buckle/SharedBuckleSystem.cs @@ -1,10 +1,11 @@ using System.Diagnostics.CodeAnalysis; using Content.Shared.Verbs; -using Content.Shared.Physics; using Content.Shared.Throwing; using Content.Shared.Movement; using Content.Shared.Movement.Events; +using Robust.Shared.GameObjects; using Robust.Shared.GameStates; +using System.Linq; using Robust.Shared.Serialization; using Content.Shared.ActionBlocker; using Content.Shared.Administration.Logs; @@ -62,7 +63,8 @@ public override void Initialize() private void InitializeStrap() { - // Initialization logic for straps... + SubscribeLocalEvent(OnStrapStartup); + SubscribeLocalEvent(OnStrapShutdown); } private void InitializeBuckle() @@ -72,13 +74,107 @@ private void InitializeBuckle() SubscribeLocalEvent(OnBuckleMove); SubscribeLocalEvent(OnBuckleInteractHand); SubscribeLocalEvent>(AddUnbuckleVerb); - SubscribeLocalEvent(OnBucklePreventCollide); SubscribeLocalEvent(OnBuckleDownAttempt); SubscribeLocalEvent(OnBuckleStandAttempt); SubscribeLocalEvent(OnBuckleThrowPushbackAttempt); SubscribeLocalEvent(OnBuckleUpdateCanMove); } + private void OnStrapStartup(EntityUid uid, StrapComponent component, ComponentStartup args) + + { + + UpdateStrapVisuals(uid, component); + + + var buckleQuery = GetEntityQuery(); + + var xform = Transform(uid); + + var buckleEntities = GetEntitiesInRange(uid, component.MaxBuckleDistance); + + + foreach (var entity in buckleEntities) + + { + + if (buckleQuery.TryGetComponent(entity, out var buckle) && !buckle.Buckled) + + { + + TryBuckle(entity, entity, uid, buckle, component); + + } + + } + + } + public IEnumerable GetEntitiesInRange(EntityUid uid, float range, TransformComponent? xform = null) + { + if (!Resolve(uid, ref xform)) + yield break; + + var xformQuery = GetEntityQuery(); + var worldPos = _transform.GetWorldPosition(xform); + var rangeSquared = range * range; + + var query = EntityQueryEnumerator(); + while (query.MoveNext(out var otherUid, out var otherXform)) + { + if (otherUid == uid) + continue; + + var otherWorldPos = _transform.GetWorldPosition(otherXform, xformQuery); + var displacement = otherWorldPos - worldPos; + + if (displacement.LengthSquared() <= rangeSquared) + { + yield return otherUid; + } + } + } + private void OnStrapShutdown(EntityUid uid, StrapComponent component, ComponentShutdown args) + + { + + // Unbuckle all entities from this strap + + foreach (var buckledEntity in component.BuckledEntities.ToList()) + + { + + TryUnbuckle(buckledEntity, buckledEntity, true); + + } + + + // Clear the buckled entities list + + component.BuckledEntities.Clear(); + + component.OccupiedSize = 0; + + + // Update the strap's visual state + + UpdateStrapVisuals(uid, component); + + } + + + private void UpdateStrapVisuals(EntityUid uid, StrapComponent? strap = null) + + { + + if (!Resolve(uid, ref strap)) + + return; + + + Appearance.SetData(uid, StrapVisuals.State, strap.BuckledEntities.Count > 0); + + } + private void OnBuckleStartup(EntityUid uid, BuckleComponent component, ComponentStartup args) { UpdateBuckleStatus(uid, component); @@ -94,7 +190,10 @@ private void OnBuckleMove(EntityUid uid, BuckleComponent component, ref MoveEven if (component.BuckledTo == null || component.BuckledTo == uid) return; - if (!_transform.GetWorldPosition(uid).InRange(_transform.GetWorldPosition(component.BuckledTo.Value), component.Range)) + var bucklePos = _transform.GetWorldPosition(uid); + var strapPos = _transform.GetWorldPosition(component.BuckledTo.Value); + + if ((bucklePos - strapPos).LengthSquared() > component.Range * component.Range) TryUnbuckle(uid, uid, true, component); } @@ -126,15 +225,6 @@ private void AddUnbuckleVerb(EntityUid uid, BuckleComponent component, GetVerbsE args.Verbs.Add(verb); } - private void OnBucklePreventCollide(EntityUid uid, BuckleComponent component, PreventCollideEvent args) - { - if (component.BuckledTo == null) - return; - - if (args.OtherEntity == component.BuckledTo) - args.Cancel(); - } - private void OnBuckleDownAttempt(EntityUid uid, BuckleComponent component, DownAttemptEvent args) { if (component.Buckled) @@ -164,8 +254,7 @@ private void UpdateBuckleStatus(EntityUid uid, BuckleComponent component) if (component.BuckledTo == null) return; - var strap = Comp(component.BuckledTo.Value); - if (strap == null) + if (!TryComp(component.BuckledTo.Value, out var strap)) return; if (strap.BuckledEntities.Contains(uid)) @@ -177,127 +266,171 @@ private void UpdateBuckleStatus(EntityUid uid, BuckleComponent component) } public bool TryBuckle(EntityUid buckleUid, EntityUid userUid, EntityUid strapUid, BuckleComponent? buckleComp = null, StrapComponent? strapComp = null) + { + if (!Resolve(buckleUid, ref buckleComp, false) || !Resolve(strapUid, ref strapComp, false)) + return false; + if (buckleComp.Buckled || !CanBuckle(buckleUid, userUid, strapUid, out strapComp, buckleComp)) + return false; + buckleComp.Buckled = true; + buckleComp.BuckledTo = strapUid; + buckleComp.BuckleTime = _gameTiming.CurTime; + strapComp.BuckledEntities.Add(buckleUid); + strapComp.OccupiedSize += buckleComp.Size; + ReAttach(buckleUid, strapUid, buckleComp, strapComp); + _audio.PlayPredicted(strapComp.BuckleSound, strapUid, userUid); + _alerts.ShowAlert(buckleUid, strapComp.BuckledAlertType); + var ev = new BuckleChangeEvent(strapUid, buckleUid, true); + RaiseLocalEvent(buckleUid, ref ev); + RaiseLocalEvent(strapUid, ref ev); + return true; - } + } public bool TryUnbuckle(EntityUid buckleUid, EntityUid userUid, bool force, BuckleComponent? buckleComp = null, StrapComponent? strapComp = null) + { - if (!Resolve(buckleUid, ref buckleComp, false) || !buckleComp.Buckled || !Resolve(buckleComp.BuckledTo, ref strapComp, false)) + + if (!Resolve(buckleUid, ref buckleComp, false) || !buckleComp.Buckled || buckleComp.BuckledTo == null || !Resolve(buckleComp.BuckledTo.Value, ref strapComp, false)) + return false; + if (!force && _gameTiming.CurTime < buckleComp.BuckleTime + buckleComp.Delay) + return false; + buckleComp.Buckled = false; - buckleComp.BuckledTo = null; + + buckleComp.BuckledTo = null!; + if (_mobState.IsIncapacitated(buckleUid)) + _standing.Down(buckleUid); + if (strapComp.BuckledEntities.Remove(buckleUid)) + { + strapComp.OccupiedSize -= buckleComp.Size; - Dirty(strapComp.Owner, strapComp); + + Dirty(buckleComp.BuckledTo.Value, strapComp); + } + _joints.RefreshRelay(buckleUid); - Appearance.SetData(strapComp.Owner, StrapVisuals.State, strapComp.BuckledEntities.Count != 0); - if (!TerminatingOrDeleted(strapComp.Owner)) - _audio.PlayPredicted(strapComp.UnbuckleSound, strapComp.Owner, userUid); + Appearance.SetData(buckleComp.BuckledTo.Value, StrapVisuals.State, strapComp.BuckledEntities.Count != 0); + + + if (!TerminatingOrDeleted(buckleComp.BuckledTo.Value)) + + _audio.PlayPredicted(strapComp.UnbuckleSound, buckleComp.BuckledTo.Value, userUid); + + + var ev = new BuckleChangeEvent(buckleComp.BuckledTo.Value, buckleUid, false); - var ev = new BuckleChangeEvent(strapComp.Owner, buckleUid, false); RaiseLocalEvent(buckleUid, ref ev); - RaiseLocalEvent(strapComp.Owner, ref ev); + + RaiseLocalEvent(buckleComp.BuckledTo.Value, ref ev); + return true; + } + private bool CanBuckle(EntityUid buckleUid, EntityUid userUid, EntityUid strapUid, [NotNullWhen(true)] out StrapComponent? strapComp, BuckleComponent? buckleComp = null) + { + strapComp = null; - // Guard clauses - if (userUid == strapUid || !Resolve(buckleUid, ref buckleComp, false) || !Resolve(strapUid, ref strapComp, false)) + + if (!Resolve(buckleUid, ref buckleComp, false) || !Resolve(strapUid, ref strapComp, false)) + return false; - if (!IsAllowedBuckleType(buckleComp, userUid)) + + if (userUid == strapUid) + return false; - if (!IsStrapEnabled(strapComp)) + + if (!ActionBlocker.CanInteract(userUid, strapUid)) + return false; - if (!IsStrapSizeValid(buckleComp, strapComp)) + + if (!IsEntityAllowed(buckleUid, strapComp)) + return false; - if (!IsInRange(buckleUid, strapUid, buckleComp)) + + if (!_interaction.InRangeUnobstructed(buckleUid, strapUid, buckleComp.Range)) + return false; - if (!IsEntityAllowed(buckleUid, strapComp)) + + if (strapComp.OccupiedSize + buckleComp.Size > strapComp.Size) + return false; - return true; - } - private bool IsAllowedBuckleType(BuckleComponent? buckleComp, EntityUid userUid) - { - if (buckleComp?.AllowedBuckleTypes != null && !buckleComp.AllowedBuckleTypes.IsValid(userUid, EntityManager)) - { - if (_netManager.IsServer) - _popup.PopupEntity(Loc.GetString("buckle-component-cannot-fit-message"), userUid, buckleUid, PopupType.Medium); + if (!strapComp.Enabled) + return false; - } - return true; - } - private bool IsStrapEnabled(StrapComponent? strapComp) - => strapComp?.Enabled == true; + return true; - private bool IsStrapSizeValid(BuckleComponent? buckleComp, StrapComponent? strapComp) - => buckleComp != null && strapComp != null && strapComp.OccupiedSize + buckleComp.Size <= strapComp.Size; + } - private bool IsInRange(EntityUid buckleUid, EntityUid strapUid, BuckleComponent? buckleComp) - => buckleComp != null && _interaction.InRangeUnobstructed(buckleUid, strapUid, buckleComp.Range); + private bool IsEntityAllowed(EntityUid buckleUid, StrapComponent strapComp) + { + return strapComp.AllowedEntities == null || strapComp.AllowedEntities.IsValid(buckleUid, EntityManager); + } - private bool IsEntityAllowed(EntityUid buckleUid, StrapComponent? strapComp) - => strapComp?.AllowedEntities == null || strapComp.AllowedEntities.IsValid(buckleUid); + private bool IsInRange(EntityUid buckleUid, EntityUid strapUid, float range) + { + return _interaction.InRangeUnobstructed(buckleUid, strapUid, range); + } private void ReAttach(EntityUid buckleUid, EntityUid strapUid, BuckleComponent? buckleComp = null, StrapComponent? strapComp = null) { if (!Resolve(strapUid, ref strapComp, false) || !Resolve(buckleUid, ref buckleComp, false)) return; - _transform.SetCoordinates(buckleUid, new EntityCoordinates(strapUid, strapComp.BuckleOffsetClamped)); + _transform.SetCoordinates(buckleUid, new EntityCoordinates(strapUid, strapComp.BuckleOffset)); var buckleTransform = Transform(buckleUid); - // Buckle subscribes to move for < reasons > so this might fail. - // TODO: Make buckle not do that. - if (buckleTransform.ParentUid != strapUid) return; @@ -316,4 +449,11 @@ private void ReAttach(EntityUid buckleUid, EntityUid strapUid, BuckleComponent? break; } } + public enum StrapVisuals + + { + + State + + } } From 0040e5af78608108437b4804586dad082b7d4ea8 Mon Sep 17 00:00:00 2001 From: Acensti Date: Sun, 7 Jul 2024 14:45:19 +0200 Subject: [PATCH 5/8] more junk --- .../Systems/VehicleDestructionSystem.cs | 21 ---- .../Vehicles/Systems/VehicleSystem.cs | 71 ++--------- .../Vehicles/Components/KeyComponent.cs | 14 +++ .../Vehicles/Components/KeyRequiredComponent | 18 --- .../Components/RiddenVehicleComponent.cs | 4 +- .../Vehicles/Components/VehicleComponent.cs | 4 +- .../Components/VehicleKeyComponent.cs | 16 --- Content.Shared/Vehicles/KeySystem.cs | 43 +++---- Content.Shared/Vehicles/VehicleSystem.cs | 113 ++++++++++++++++++ 9 files changed, 161 insertions(+), 143 deletions(-) delete mode 100644 Content.Server/Vehicles/Systems/VehicleDestructionSystem.cs create mode 100644 Content.Shared/Vehicles/Components/KeyComponent.cs delete mode 100644 Content.Shared/Vehicles/Components/KeyRequiredComponent delete mode 100644 Content.Shared/Vehicles/Components/VehicleKeyComponent.cs create mode 100644 Content.Shared/Vehicles/VehicleSystem.cs diff --git a/Content.Server/Vehicles/Systems/VehicleDestructionSystem.cs b/Content.Server/Vehicles/Systems/VehicleDestructionSystem.cs deleted file mode 100644 index 667348dec05..00000000000 --- a/Content.Server/Vehicles/Systems/VehicleDestructionSystem.cs +++ /dev/null @@ -1,21 +0,0 @@ -// /Content.Server/Vehicles/Systems/VehicleDestructionSystem.cs -using Content.Server.Vehicles.Components; -using Robust.Shared.GameObjects; -using Robust.Shared.Physics; - -namespace Content.Server.Vehicles.Systems -{ - public sealed class VehicleDestructionSystem : EntitySystem - { - public override void Initialize() - { - base.Initialize(); - SubscribeLocalEvent(OnVehicleDestroyed); - } - - private void OnVehicleDestroyed(EntityUid uid, VehicleComponent component, DestructionEventArgs args) - { - // Logic for vehicle destruction, e.g., explosion, dropping items, etc. - } - } -} diff --git a/Content.Server/Vehicles/Systems/VehicleSystem.cs b/Content.Server/Vehicles/Systems/VehicleSystem.cs index baab4cafd1c..8c90c0fb702 100644 --- a/Content.Server/Vehicles/Systems/VehicleSystem.cs +++ b/Content.Server/Vehicles/Systems/VehicleSystem.cs @@ -1,4 +1,3 @@ -using Content.Server.Vehicles.Components; using Content.Shared.Buckle; using Content.Shared.Buckle.Components; using Content.Shared.Interaction; @@ -24,88 +23,36 @@ public sealed class VehicleSystem : EntitySystem public override void Initialize() { base.Initialize(); - SubscribeLocalEvent>(AddEnterVehicleVerb); - SubscribeLocalEvent(OnMoveInput); - SubscribeLocalEvent(OnInteractHand); - SubscribeLocalEvent(OnBuckleChange); + SubscribeLocalEvent(OnInteractHand); + SubscribeLocalEvent(OnBuckleChange); } - private void AddEnterVehicleVerb(EntityUid uid, VehicleComponent component, GetVerbsEvent args) - { - if (!args.CanInteract || !args.CanAccess) - return; - - if (component.Occupants.Count >= component.MaxOccupants) - return; - - AlternativeVerb verb = new() - { - Act = () => EnterVehicle(args.User, uid, component), - Text = Loc.GetString("enter-vehicle-verb"), - Priority = 2 - }; - args.Verbs.Add(verb); - } - - private void EnterVehicle(EntityUid user, EntityUid vehicle, VehicleComponent component) - { - if (component.Occupants.Count >= component.MaxOccupants) - { - _popupSystem.PopupEntity("The vehicle is full.", vehicle, Filter.Entities(user)); - return; - } - - if (_buckleSystem.TryBuckle(user, user, vehicle)) - { - component.Occupants.Add(user); - if (component.Driver == null) - { - component.Driver = user; - } - } - } - - private void OnMoveInput(EntityUid uid, VehicleComponent component, ref MoveInputEvent args) - { - if (component.Driver == null || component.Driver != args.User) - return; - - // Handle vehicle movement logic here. - var transform = EntityManager.GetComponent(uid); - var direction = args.Direction.ToVec(); - transform.Coordinates += direction * component.Speed * _gameTiming.FrameTime; - } - - private void OnInteractHand(EntityUid uid, VehicleComponent component, InteractHandEvent args) + private void OnInteractHand(EntityUid uid, RiddenVehicleComponent component, InteractHandEvent args) { if (args.Handled) return; - if (component.Occupants.Contains(args.User)) + if (component.Riders.Contains(args.User)) { _buckleSystem.TryUnbuckle(args.User, args.User, false); } else { - EnterVehicle(args.User, uid, component); + _buckleSystem.TryBuckle(args.User, args.User, uid); } args.Handled = true; } - private void OnBuckleChange(EntityUid uid, VehicleComponent component, BuckleChangeEvent args) + private void OnBuckleChange(EntityUid uid, RiddenVehicleComponent component, BuckleChangeEvent args) { - if (args.Buckled) + if (args.Buckling) { - component.Occupants.Add(args.BuckleEntity); + component.Riders.Add(args.BuckledEntity); } else { - component.Occupants.Remove(args.BuckleEntity); - if (component.Driver == args.BuckleEntity) - { - component.Driver = component.Occupants.Count > 0 ? component.Occupants[0] : null; - } + component.Riders.Remove(args.BuckledEntity); } } } diff --git a/Content.Shared/Vehicles/Components/KeyComponent.cs b/Content.Shared/Vehicles/Components/KeyComponent.cs new file mode 100644 index 00000000000..5a80a6fc0e8 --- /dev/null +++ b/Content.Shared/Vehicles/Components/KeyComponent.cs @@ -0,0 +1,14 @@ +using Robust.Shared.GameObjects; + +namespace Content.Shared.Vehicle +{ + [RegisterComponent] + public partial class KeyComponent : Component + { + [DataField("keyType")] + public string KeyType = string.Empty; + + [ViewVariables] + public bool IsInserted = false; + } +} diff --git a/Content.Shared/Vehicles/Components/KeyRequiredComponent b/Content.Shared/Vehicles/Components/KeyRequiredComponent deleted file mode 100644 index e06101ac6f9..00000000000 --- a/Content.Shared/Vehicles/Components/KeyRequiredComponent +++ /dev/null @@ -1,18 +0,0 @@ -using Robust.Shared.GameObjects; -using Robust.Shared.Serialization.Manager.Attributes; -using Robust.Shared.ViewVariables; - -namespace Content.Shared.Vehicle -{ - [RegisterComponent] - public sealed class KeyRequiredComponent : Component - { - public override string Name => "KeyRequired"; - - [DataField("keyType")] - public string KeyType = string.Empty; - - [ViewVariables] - public EntityUid? InsertedKey; - } -} diff --git a/Content.Shared/Vehicles/Components/RiddenVehicleComponent.cs b/Content.Shared/Vehicles/Components/RiddenVehicleComponent.cs index 23a60c5166e..d77da291131 100644 --- a/Content.Shared/Vehicles/Components/RiddenVehicleComponent.cs +++ b/Content.Shared/Vehicles/Components/RiddenVehicleComponent.cs @@ -5,10 +5,8 @@ namespace Content.Shared.Vehicle { [RegisterComponent] - public partial class RiddenVehicleComponent : Component + public sealed partial class RiddenVehicleComponent : Component { - public override string Name => "RiddenVehicle"; - [DataField("maxRiders")] public int MaxRiders = 1; diff --git a/Content.Shared/Vehicles/Components/VehicleComponent.cs b/Content.Shared/Vehicles/Components/VehicleComponent.cs index e6a323da79b..37d8fa6470c 100644 --- a/Content.Shared/Vehicles/Components/VehicleComponent.cs +++ b/Content.Shared/Vehicles/Components/VehicleComponent.cs @@ -5,10 +5,8 @@ namespace Content.Server.Vehicles.Components { [RegisterComponent] - public sealed class VehicleComponent : Component + public sealed partial class VehicleComponent : Component { - public override string Name => "Vehicle"; - [DataField("maxOccupants")] public int MaxOccupants = 1; diff --git a/Content.Shared/Vehicles/Components/VehicleKeyComponent.cs b/Content.Shared/Vehicles/Components/VehicleKeyComponent.cs deleted file mode 100644 index 0f487b77138..00000000000 --- a/Content.Shared/Vehicles/Components/VehicleKeyComponent.cs +++ /dev/null @@ -1,16 +0,0 @@ -// /Content.Shared/Vehicles/Components/VehicleKeyComponent.cs -using Robust.Shared.GameObjects; -using Robust.Shared.Serialization.Manager.Attributes; - -namespace Content.Shared.Vehicles.Components -{ - [RegisterComponent] - public sealed class VehicleKeyComponent : Component - { - [DataField("keyId")] - public string KeyId { get; set; } = string.Empty; - - [DataField("isLocked")] - public bool IsLocked { get; set; } = true; - } -} diff --git a/Content.Shared/Vehicles/KeySystem.cs b/Content.Shared/Vehicles/KeySystem.cs index fa7e09f64e3..b11fe554465 100644 --- a/Content.Shared/Vehicles/KeySystem.cs +++ b/Content.Shared/Vehicles/KeySystem.cs @@ -1,12 +1,8 @@ using Content.Shared.Interaction; using Content.Shared.Popups; -using Content.Shared.Vehicle; using Robust.Shared.GameObjects; using Robust.Shared.IoC; using Robust.Shared.Player; -using Content.Shared.Vehicles.Components; -using Content.Shared.Interaction.Events; - namespace Content.Shared.Vehicle { @@ -17,34 +13,41 @@ public sealed class KeySystem : EntitySystem public override void Initialize() { base.Initialize(); - SubscribeLocalEvent(OnInteractUsing); - SubscribeLocalEvent(OnAltInteract); + SubscribeLocalEvent(OnInteractHand); } - private void OnInteractUsing(EntityUid uid, KeyRequiredComponent component, InteractUsingEvent args) + private void OnInteractHand(EntityUid uid, KeyComponent component, InteractHandEvent args) + { + if (args.Handled) + return; - if (component.InsertedKey == null && args.Used.HasComponent()) + + if (component.IsInserted) + { - component.InsertedKey = args.Used; - _popupSystem.PopupEntity("You insert the key.", uid, Filter.Entities(args.User)); - args.Handled = true; + + component.IsInserted = false; + + _popupSystem.PopupEntity("Key removed.", uid, args.User, PopupType.Medium); + } - } - private void OnAltInteract(EntityUid uid, KeyRequiredComponent component, AltInteractEvent args) - { - if (args.Handled) - return; + else - if (component.InsertedKey != null) { - _popupSystem.PopupEntity("You remove the key.", uid, Filter.Entities(args.User)); - component.InsertedKey = null; - args.Handled = true; + + component.IsInserted = true; + + _popupSystem.PopupEntity("Key inserted.", uid, args.User, PopupType.Medium); + } + + + args.Handled = true; + } } } diff --git a/Content.Shared/Vehicles/VehicleSystem.cs b/Content.Shared/Vehicles/VehicleSystem.cs new file mode 100644 index 00000000000..fbf011f1ca1 --- /dev/null +++ b/Content.Shared/Vehicles/VehicleSystem.cs @@ -0,0 +1,113 @@ +using Content.Server.Vehicles.Components; +using Content.Shared.Buckle; +using Content.Shared.Buckle.Components; +using Content.Shared.Interaction; +using Content.Shared.Popups; +using Content.Shared.Vehicle; +using Content.Shared.Verbs; +using Content.Shared.Movement.Events; +using Robust.Shared.GameObjects; +using Robust.Shared.IoC; +using Robust.Shared.Map; +using Robust.Shared.Physics; +using Robust.Shared.Player; +using Robust.Shared.Timing; + +namespace Content.Server.Vehicles.Systems +{ + public sealed class VehicleSystem : EntitySystem + { + [Dependency] private readonly IGameTiming _gameTiming = default!; + [Dependency] private readonly IMapManager _mapManager = default!; + [Dependency] private readonly IEntityManager _entityManager = default!; + [Dependency] private readonly SharedBuckleSystem _buckleSystem = default!; + [Dependency] private readonly SharedPopupSystem _popupSystem = default!; + + public override void Initialize() + { + base.Initialize(); + SubscribeLocalEvent>(AddEnterVehicleVerb); + SubscribeLocalEvent(OnMoveInput); + SubscribeLocalEvent(OnInteractHand); + SubscribeLocalEvent(OnBuckleChange); + } + + private void AddEnterVehicleVerb(EntityUid uid, VehicleComponent component, GetVerbsEvent args) + { + if (!args.CanInteract || !args.CanAccess) + return; + + if (component.Occupants.Count >= component.MaxOccupants) + return; + + AlternativeVerb verb = new() + { + Act = () => EnterVehicle(args.User, uid, component), + Text = Loc.GetString("enter-vehicle-verb"), + Priority = 2 + }; + args.Verbs.Add(verb); + } + + private void EnterVehicle(EntityUid user, EntityUid vehicle, VehicleComponent component) + { + if (component.Occupants.Count >= component.MaxOccupants) + { + _popupSystem.PopupEntity("The vehicle is full.", vehicle, Filter.Entities(user)); + return; + } + + if (_buckleSystem.TryBuckle(user, user, vehicle)) + { + component.Occupants.Add(user); + if (component.Driver == null) + { + component.Driver = user; + } + } + } + + private void OnMoveInput(EntityUid uid, VehicleComponent component, ref MoveInputEvent args) + { + if (component.Driver == null || component.Driver != args.User) + return; + + var transform = EntityManager.GetComponent(uid); + var direction = args.Component.HeldMoveButtons.ToVec(); + transform.Coordinates += direction * component.Speed * (float) _gameTiming.FrameTime.TotalSeconds; + } + + private void OnInteractHand(EntityUid uid, VehicleComponent component, InteractHandEvent args) + { + if (args.Handled) + return; + + if (component.Occupants.Contains(args.User)) + { + _buckleSystem.TryUnbuckle(args.User, args.User, false); + } + else + { + EnterVehicle(args.User, uid, component); + } + + args.Handled = true; + } + + private void OnBuckleChange(EntityUid uid, VehicleComponent component, BuckleChangeEvent args) + { + if (args.Buckling) + { + component.Occupants.Add(args.BuckledEntity); + } + else + { + component.Occupants.Remove(args.BuckledEntity); + if (component.Driver == args.BuckledEntity) + { + component.Driver = component.Occupants.Count > 0 ? component.Occupants[0] : null; + } + } + } + } +} From 86529f9c9da52e63f29b8f19e3eb41939f2c99c0 Mon Sep 17 00:00:00 2001 From: Acensti Date: Sun, 7 Jul 2024 20:41:30 +0200 Subject: [PATCH 6/8] ridden --- Content.Client/Vehicle/ClientVehicleSystem.cs | 3 +- .../Tests/Buckle/BuckleTest.cs | 40 +++---- Content.Server/Alert/Click/Unbuckle.cs | 10 +- .../HTN/Preconditions/BuckledPrecondition.cs | 3 +- .../Vehicles/Components/VehicleComponent.cs | 4 +- .../Vehicles/Systems/VehicleKeySystem.cs | 48 -------- .../Vehicles/Systems/VehicleSystem.cs | 59 --------- .../Vehicles/UI/VehicleControlUI.cs | 31 ----- Content.Shared/Buckle/SharedBuckleSystem.cs | 38 ++++++ Content.Shared/Key/KeyComponent.cs | 1 - Content.Shared/Key/KeyRequiredComponent.cs | 3 +- .../Components/RiddenVehicleComponent.cs | 11 +- Content.Shared/Vehicles/KeySystem.cs | 53 -------- .../Vehicles/RiddenVehicleSystem.cs | 38 ++++++ Content.Shared/Vehicles/VehicleSystem.cs | 113 ------------------ .../Prototypes/Entities/Vehicles/vehicles.yml | 2 + .../Objects/Vehicles/secway.rsi/meta.json | 87 +++++++------- 17 files changed, 166 insertions(+), 378 deletions(-) delete mode 100644 Content.Server/Vehicles/Systems/VehicleKeySystem.cs delete mode 100644 Content.Server/Vehicles/Systems/VehicleSystem.cs delete mode 100644 Content.Server/Vehicles/UI/VehicleControlUI.cs delete mode 100644 Content.Shared/Vehicles/KeySystem.cs delete mode 100644 Content.Shared/Vehicles/VehicleSystem.cs diff --git a/Content.Client/Vehicle/ClientVehicleSystem.cs b/Content.Client/Vehicle/ClientVehicleSystem.cs index 0716f7294bb..6e3abd889be 100644 --- a/Content.Client/Vehicle/ClientVehicleSystem.cs +++ b/Content.Client/Vehicle/ClientVehicleSystem.cs @@ -2,6 +2,7 @@ using Robust.Client.GameObjects; using Robust.Shared.GameObjects; using Robust.Shared.IoC; +using Robust.Shared.GameStates; namespace Content.Client.Vehicle { @@ -21,7 +22,7 @@ private void OnHandleState(EntityUid uid, RiddenVehicleComponent component, ref return; component.Riders.Clear(); - component.Riders.AddRange(state.Riders); + component.Riders.UnionWith(state.Riders); } } } diff --git a/Content.IntegrationTests/Tests/Buckle/BuckleTest.cs b/Content.IntegrationTests/Tests/Buckle/BuckleTest.cs index 6e2a080370d..bcb1315f59c 100644 --- a/Content.IntegrationTests/Tests/Buckle/BuckleTest.cs +++ b/Content.IntegrationTests/Tests/Buckle/BuckleTest.cs @@ -119,9 +119,9 @@ await server.WaitAssertion(() => Assert.That(buckleSystem.TryBuckle(human, human, chair, buckle), Is.False); // Trying to unbuckle too quickly fails - Assert.That(buckleSystem.TryUnbuckle(human, human, buckleComp: buckle), Is.False); + Assert.That(buckleSystem.TryUnbuckle(human, human, false, buckle), Is.False); Assert.That(buckle.Buckled); - Assert.That(buckleSystem.ToggleBuckle(human, human, chair, buckle: buckle), Is.False); + Assert.That(buckleSystem.ToggleBuckle(human, human, chair, buckle), Is.False); Assert.That(buckle.Buckled); #pragma warning restore NUnit2045 }); @@ -137,7 +137,7 @@ await server.WaitAssertion(() => #pragma warning restore NUnit2045 // Unbuckle - Assert.That(buckleSystem.TryUnbuckle(human, human, buckleComp: buckle)); + Assert.That(buckleSystem.TryUnbuckle(human, human, false, buckle)); Assert.Multiple(() => { Assert.That(buckle.BuckledTo, Is.Null); @@ -153,15 +153,15 @@ await server.WaitAssertion(() => #pragma warning disable NUnit2045 // Interdependent asserts. // Re-buckling has no cooldown - Assert.That(buckleSystem.TryBuckle(human, human, chair, buckleComp: buckle)); + Assert.That(buckleSystem.TryBuckle(human, human, chair, buckle)); Assert.That(buckle.Buckled); // On cooldown - Assert.That(buckleSystem.TryUnbuckle(human, human, buckleComp: buckle), Is.False); + Assert.That(buckleSystem.TryUnbuckle(human, human, false, buckle), Is.False); Assert.That(buckle.Buckled); - Assert.That(buckleSystem.ToggleBuckle(human, human, chair, buckle: buckle), Is.False); + Assert.That(buckleSystem.ToggleBuckle(human, human, chair, buckle), Is.False); Assert.That(buckle.Buckled); - Assert.That(buckleSystem.ToggleBuckle(human, human, chair, buckle: buckle), Is.False); + Assert.That(buckleSystem.ToggleBuckle(human, human, chair, buckle), Is.False); Assert.That(buckle.Buckled); #pragma warning restore NUnit2045 }); @@ -176,7 +176,7 @@ await server.WaitAssertion(() => Assert.That(buckle.Buckled); // Unbuckle - Assert.That(buckleSystem.TryUnbuckle(human, human, buckleComp: buckle)); + Assert.That(buckleSystem.TryUnbuckle(human, human, false, buckle)); Assert.That(buckle.Buckled, Is.False); #pragma warning restore NUnit2045 @@ -187,9 +187,9 @@ await server.WaitAssertion(() => // Out of range #pragma warning disable NUnit2045 // Interdependent asserts. - Assert.That(buckleSystem.TryBuckle(human, human, chair, buckleComp: buckle), Is.False); - Assert.That(buckleSystem.TryUnbuckle(human, human, buckleComp: buckle), Is.False); - Assert.That(buckleSystem.ToggleBuckle(human, human, chair, buckle: buckle), Is.False); + Assert.That(buckleSystem.TryBuckle(human, human, chair, buckle), Is.False); + Assert.That(buckleSystem.TryUnbuckle(human, human, false, buckle), Is.False); + Assert.That(buckleSystem.ToggleBuckle(human, human, chair, buckle), Is.False); #pragma warning restore NUnit2045 // Move near the chair @@ -198,16 +198,16 @@ await server.WaitAssertion(() => // In range #pragma warning disable NUnit2045 // Interdependent asserts. - Assert.That(buckleSystem.TryBuckle(human, human, chair, buckleComp: buckle)); + Assert.That(buckleSystem.TryBuckle(human, human, chair, buckle)); Assert.That(buckle.Buckled); - Assert.That(buckleSystem.TryUnbuckle(human, human, buckleComp: buckle), Is.False); + Assert.That(buckleSystem.TryUnbuckle(human, human, false, buckle), Is.False); Assert.That(buckle.Buckled); - Assert.That(buckleSystem.ToggleBuckle(human, human, chair, buckle: buckle), Is.False); + Assert.That(buckleSystem.ToggleBuckle(human, human, chair, buckle), Is.False); Assert.That(buckle.Buckled); #pragma warning restore NUnit2045 // Force unbuckle - Assert.That(buckleSystem.TryUnbuckle(human, human, true, buckleComp: buckle)); + Assert.That(buckleSystem.TryUnbuckle(human, human, true, buckle)); Assert.Multiple(() => { Assert.That(buckle.Buckled, Is.False); @@ -217,7 +217,7 @@ await server.WaitAssertion(() => }); // Re-buckle - Assert.That(buckleSystem.TryBuckle(human, human, chair, buckleComp: buckle)); + Assert.That(buckleSystem.TryBuckle(human, human, chair, buckle)); // Move away from the chair oldWorldPosition = xformSystem.GetWorldPosition(chair, xformQuery); @@ -276,7 +276,7 @@ await server.WaitAssertion(() => }); // Buckle - Assert.That(buckleSystem.TryBuckle(human, human, chair, buckleComp: buckle)); + Assert.That(buckleSystem.TryBuckle(human, human, chair, buckle)); Assert.Multiple(() => { Assert.That(buckle.BuckledTo, Is.Not.Null); @@ -328,7 +328,7 @@ await server.WaitAssertion(() => Assert.That(hand.HeldEntity, Is.Null); } - buckleSystem.TryUnbuckle(human, human, true, buckleComp: buckle); + buckleSystem.TryUnbuckle(human, human, true, buckle); }); await pair.CleanReturnAsync(); @@ -363,7 +363,7 @@ await server.WaitAssertion(() => }); // Buckle - Assert.That(buckleSystem.TryBuckle(human, human, chair, buckleComp: buckle)); + Assert.That(buckleSystem.TryBuckle(human, human, chair, buckle)); Assert.Multiple(() => { Assert.That(buckle.BuckledTo, Is.Not.Null); @@ -388,7 +388,7 @@ await server.WaitAssertion(() => xformSystem.SetWorldPosition(human, oldWorldPosition, xformQuery); // Buckle - Assert.That(buckleSystem.TryBuckle(human, human, chair, buckleComp: buckle)); + Assert.That(buckleSystem.TryBuckle(human, human, chair, buckle)); Assert.Multiple(() => { Assert.That(buckle.BuckledTo, Is.Not.Null); diff --git a/Content.Server/Alert/Click/Unbuckle.cs b/Content.Server/Alert/Click/Unbuckle.cs index 3e53955d8c5..4e73354ac40 100644 --- a/Content.Server/Alert/Click/Unbuckle.cs +++ b/Content.Server/Alert/Click/Unbuckle.cs @@ -1,19 +1,25 @@ using Content.Shared.Alert; using Content.Shared.Buckle; +using Content.Shared.Buckle.Components; using JetBrains.Annotations; +using Robust.Shared.IoC; namespace Content.Server.Alert.Click { /// /// Unbuckles if player is currently buckled. /// - [UsedImplicitly] + [UsedImplicitly] [DataDefinition] public sealed partial class Unbuckle : IAlertClick { public void AlertClicked(EntityUid player) { - IoCManager.Resolve().System().TryUnbuckle(player, player); + var entityManager = IoCManager.Resolve(); + var buckleSystem = entityManager.System(); + var buckleComp = entityManager.GetComponent(player); + var strapComp = buckleComp.BuckledTo != null ? entityManager.GetComponent(buckleComp.BuckledTo.Value) : null; + buckleSystem.TryUnbuckle(player, player, false, buckleComp, strapComp); } } } diff --git a/Content.Server/NPC/HTN/Preconditions/BuckledPrecondition.cs b/Content.Server/NPC/HTN/Preconditions/BuckledPrecondition.cs index d4bbfde15ad..4b377f716b5 100644 --- a/Content.Server/NPC/HTN/Preconditions/BuckledPrecondition.cs +++ b/Content.Server/NPC/HTN/Preconditions/BuckledPrecondition.cs @@ -1,4 +1,5 @@ using Content.Shared.Buckle; +using Content.Shared.Buckle.Components; namespace Content.Server.NPC.HTN.Preconditions; @@ -9,7 +10,7 @@ public sealed partial class BuckledPrecondition : HTNPrecondition { private SharedBuckleSystem _buckle = default!; - [ViewVariables(VVAccess.ReadWrite)] [DataField("isBuckled")] public bool IsBuckled = true; + [ViewVariables(VVAccess.ReadWrite)][DataField("isBuckled")] public bool IsBuckled = true; public override void Initialize(IEntitySystemManager sysManager) { diff --git a/Content.Server/Vehicles/Components/VehicleComponent.cs b/Content.Server/Vehicles/Components/VehicleComponent.cs index dd670434a4a..8d43857136c 100644 --- a/Content.Server/Vehicles/Components/VehicleComponent.cs +++ b/Content.Server/Vehicles/Components/VehicleComponent.cs @@ -4,9 +4,9 @@ namespace Content.Shared.Vehicle { [RegisterComponent] - public sealed class VehicleComponent : Component + public sealed partial class VehicleComponent : Component { - public override string Name => "Vehicle"; + [DataField("maxOccupants")] public int MaxOccupants = 1; diff --git a/Content.Server/Vehicles/Systems/VehicleKeySystem.cs b/Content.Server/Vehicles/Systems/VehicleKeySystem.cs deleted file mode 100644 index cfdca5751e5..00000000000 --- a/Content.Server/Vehicles/Systems/VehicleKeySystem.cs +++ /dev/null @@ -1,48 +0,0 @@ -// /Content.Server/Vehicles/Systems/VehicleKeySystem.cs -using Content.Shared.Vehicles.Components; -using Robust.Shared.GameObjects; -using Robust.Shared.IoC; - -namespace Content.Server.Vehicles.Systems -{ - public sealed class VehicleKeySystem : EntitySystem - { - public override void Initialize() - { - base.Initialize(); - SubscribeLocalEvent(OnComponentStartup); - SubscribeLocalEvent(OnComponentShutdown); - } - - private void OnComponentStartup(EntityUid uid, VehicleKeyComponent component, ComponentStartup args) - { - // logic for vehicle keys - } - - private void OnComponentShutdown(EntityUid uid, VehicleKeyComponent component, ComponentShutdown args) - { - // Cleanup logic for vehicle keys (e.g., removing the key from the vehicle ? I dont fucking know man clown car needs car keys) - } - - public bool IsVehicleLocked(EntityUid uid) - { - return TryComp(uid, out var keyComp) && keyComp.IsLocked; - } - - public void LockVehicle(EntityUid uid) - { - if (TryComp(uid, out var keyComp)) - { - keyComp.IsLocked = true; - } - } - - public void UnlockVehicle(EntityUid uid) - { - if (TryComp(uid, out var keyComp)) - { - keyComp.IsLocked = false; - } - } - } -} diff --git a/Content.Server/Vehicles/Systems/VehicleSystem.cs b/Content.Server/Vehicles/Systems/VehicleSystem.cs deleted file mode 100644 index 8c90c0fb702..00000000000 --- a/Content.Server/Vehicles/Systems/VehicleSystem.cs +++ /dev/null @@ -1,59 +0,0 @@ -using Content.Shared.Buckle; -using Content.Shared.Buckle.Components; -using Content.Shared.Interaction; -using Content.Shared.Popups; -using Content.Shared.Vehicle; -using Robust.Shared.GameObjects; -using Robust.Shared.IoC; -using Robust.Shared.Map; -using Robust.Shared.Physics; -using Robust.Shared.Player; -using Robust.Shared.Timing; - -namespace Content.Server.Vehicles.Systems -{ - public sealed class VehicleSystem : EntitySystem - { - [Dependency] private readonly IGameTiming _gameTiming = default!; - [Dependency] private readonly IMapManager _mapManager = default!; - [Dependency] private readonly IEntityManager _entityManager = default!; - [Dependency] private readonly SharedBuckleSystem _buckleSystem = default!; - [Dependency] private readonly SharedPopupSystem _popupSystem = default!; - - public override void Initialize() - { - base.Initialize(); - SubscribeLocalEvent(OnInteractHand); - SubscribeLocalEvent(OnBuckleChange); - } - - private void OnInteractHand(EntityUid uid, RiddenVehicleComponent component, InteractHandEvent args) - { - if (args.Handled) - return; - - if (component.Riders.Contains(args.User)) - { - _buckleSystem.TryUnbuckle(args.User, args.User, false); - } - else - { - _buckleSystem.TryBuckle(args.User, args.User, uid); - } - - args.Handled = true; - } - - private void OnBuckleChange(EntityUid uid, RiddenVehicleComponent component, BuckleChangeEvent args) - { - if (args.Buckling) - { - component.Riders.Add(args.BuckledEntity); - } - else - { - component.Riders.Remove(args.BuckledEntity); - } - } - } -} diff --git a/Content.Server/Vehicles/UI/VehicleControlUI.cs b/Content.Server/Vehicles/UI/VehicleControlUI.cs deleted file mode 100644 index 0a42af2ed2b..00000000000 --- a/Content.Server/Vehicles/UI/VehicleControlUI.cs +++ /dev/null @@ -1,31 +0,0 @@ -// /Content.Client/Vehicles/UI/VehicleControlUI.cs -using Robust.Client.UserInterface; -using Robust.Client.UserInterface.Controls; - -namespace Content.Client.Vehicles.UI -{ - public sealed class VehicleControlUI : Control - { - - //TODO insert sad face - public VehicleControlUI() - { - var enterButton = new Button { Text = "Enter Vehicle" }; - enterButton.OnPressed += _ => EnterVehicle(); - AddChild(enterButton); - - var exitButton = new Button { Text = "Exit Vehicle" }; - exitButton.OnPressed += _ => ExitVehicle(); - AddChild(exitButton); - } - - private void EnterVehicle() - { - - - private void ExitVehicle() - { - - } - } - } diff --git a/Content.Shared/Buckle/SharedBuckleSystem.cs b/Content.Shared/Buckle/SharedBuckleSystem.cs index 6328415c085..a05621f9d93 100644 --- a/Content.Shared/Buckle/SharedBuckleSystem.cs +++ b/Content.Shared/Buckle/SharedBuckleSystem.cs @@ -79,6 +79,44 @@ private void InitializeBuckle() SubscribeLocalEvent(OnBuckleThrowPushbackAttempt); SubscribeLocalEvent(OnBuckleUpdateCanMove); } + public bool ToggleBuckle(EntityUid buckleUid, EntityUid userUid, EntityUid strapUid, BuckleComponent? buckleComp = null, StrapComponent? strapComp = null) + { + if (!Resolve(buckleUid, ref buckleComp, false) || !Resolve(strapUid, ref strapComp, false)) + return false; + + if (buckleComp.Buckled) + return TryUnbuckle(buckleUid, userUid, false, buckleComp, strapComp); + else + return TryBuckle(buckleUid, userUid, strapUid, buckleComp, strapComp); + } + public bool IsBuckled(EntityUid uid, BuckleComponent? buckleComp = null) + + { + + if (!Resolve(uid, ref buckleComp, false)) + + return false; + + + return buckleComp.Buckled; + + } + public void StrapSetEnabled(EntityUid uid, bool enabled) + + { + + if (TryComp(uid, out var strap)) + + { + + strap.Enabled = enabled; + + Dirty(uid, strap); + + } + + } + private void OnStrapStartup(EntityUid uid, StrapComponent component, ComponentStartup args) diff --git a/Content.Shared/Key/KeyComponent.cs b/Content.Shared/Key/KeyComponent.cs index 1caed5bf69f..d2e0f82ba5e 100644 --- a/Content.Shared/Key/KeyComponent.cs +++ b/Content.Shared/Key/KeyComponent.cs @@ -6,7 +6,6 @@ namespace Content.Shared.Key [RegisterComponent] public partial class KeyComponent : Component { - public override string Name => "Key"; [DataField("keyId")] public string KeyId = string.Empty; diff --git a/Content.Shared/Key/KeyRequiredComponent.cs b/Content.Shared/Key/KeyRequiredComponent.cs index 2b8500c7ad6..2c231a7a7e1 100644 --- a/Content.Shared/Key/KeyRequiredComponent.cs +++ b/Content.Shared/Key/KeyRequiredComponent.cs @@ -4,9 +4,8 @@ namespace Content.Shared.Key { [RegisterComponent] - public partial class KeyRequiredComponent : Component + public sealed partial class KeyRequiredComponent : Component { - public override string Name => "KeyRequired"; [DataField("requiredKeyId")] public string RequiredKeyId = string.Empty; diff --git a/Content.Shared/Vehicles/Components/RiddenVehicleComponent.cs b/Content.Shared/Vehicles/Components/RiddenVehicleComponent.cs index d77da291131..08b5a630b74 100644 --- a/Content.Shared/Vehicles/Components/RiddenVehicleComponent.cs +++ b/Content.Shared/Vehicles/Components/RiddenVehicleComponent.cs @@ -1,3 +1,4 @@ +using System.Collections.Generic; using Robust.Shared.GameObjects; using Robust.Shared.Serialization.Manager.Attributes; using Robust.Shared.ViewVariables; @@ -7,10 +8,12 @@ namespace Content.Shared.Vehicle [RegisterComponent] public sealed partial class RiddenVehicleComponent : Component { - [DataField("maxRiders")] - public int MaxRiders = 1; + [ViewVariables(VVAccess.ReadWrite)] + [DataField("riders")] + public HashSet Riders = new(); - [ViewVariables] - public List Riders = new(); + [ViewVariables(VVAccess.ReadWrite)] + [DataField("speed")] + public float Speed = 5f; } } diff --git a/Content.Shared/Vehicles/KeySystem.cs b/Content.Shared/Vehicles/KeySystem.cs deleted file mode 100644 index b11fe554465..00000000000 --- a/Content.Shared/Vehicles/KeySystem.cs +++ /dev/null @@ -1,53 +0,0 @@ -using Content.Shared.Interaction; -using Content.Shared.Popups; -using Robust.Shared.GameObjects; -using Robust.Shared.IoC; -using Robust.Shared.Player; - -namespace Content.Shared.Vehicle -{ - public sealed class KeySystem : EntitySystem - { - [Dependency] private readonly SharedPopupSystem _popupSystem = default!; - - public override void Initialize() - { - base.Initialize(); - SubscribeLocalEvent(OnInteractHand); - } - - private void OnInteractHand(EntityUid uid, KeyComponent component, InteractHandEvent args) - - { - - if (args.Handled) - - return; - - - if (component.IsInserted) - - { - - component.IsInserted = false; - - _popupSystem.PopupEntity("Key removed.", uid, args.User, PopupType.Medium); - - } - - else - - { - - component.IsInserted = true; - - _popupSystem.PopupEntity("Key inserted.", uid, args.User, PopupType.Medium); - - } - - - args.Handled = true; - - } - } -} diff --git a/Content.Shared/Vehicles/RiddenVehicleSystem.cs b/Content.Shared/Vehicles/RiddenVehicleSystem.cs index a3e623fc2c6..0c85adc2ab2 100644 --- a/Content.Shared/Vehicles/RiddenVehicleSystem.cs +++ b/Content.Shared/Vehicles/RiddenVehicleSystem.cs @@ -1,11 +1,16 @@ +using System.Numerics; using Content.Shared.Buckle; using Content.Shared.Buckle.Components; using Content.Shared.Interaction; +using Content.Shared.Movement.Components; +using Content.Shared.Movement.Events; +using Content.Shared.Movement.Systems; // Added this line using Content.Shared.Popups; using Content.Shared.Vehicle; using Robust.Shared.GameObjects; using Robust.Shared.IoC; using Robust.Shared.Player; +using Robust.Shared.Timing; namespace Content.Shared.Vehicle { @@ -13,12 +18,16 @@ public sealed class RiddenVehicleSystem : EntitySystem { [Dependency] private readonly SharedBuckleSystem _buckleSystem = default!; [Dependency] private readonly SharedPopupSystem _popupSystem = default!; + [Dependency] private readonly IGameTiming _gameTiming = default!; + [Dependency] private readonly IEntityManager _entityManager = default!; + [Dependency] private readonly SharedTransformSystem _transformSystem = default!; public override void Initialize() { base.Initialize(); SubscribeLocalEvent(OnInteractHand); SubscribeLocalEvent(OnBuckleChange); + SubscribeLocalEvent(OnMoveInput); } private void OnInteractHand(EntityUid uid, RiddenVehicleComponent component, InteractHandEvent args) @@ -49,5 +58,34 @@ private void OnBuckleChange(EntityUid uid, RiddenVehicleComponent component, Buc component.Riders.Remove(args.BuckledEntity); } } + + private void OnMoveInput(EntityUid uid, RiddenVehicleComponent component, MoveInputEvent args) + { + if (!component.Riders.Contains(args.Entity)) + return; + + var transform = _entityManager.GetComponent(uid); + var worldPos = _transformSystem.GetWorldPosition(transform); + var moveDir = ConvertMoveButtonsToVector(args.Component.HeldMoveButtons); + var newPos = worldPos + (moveDir * component.Speed * (float) _gameTiming.FrameTime.TotalSeconds); + + _transformSystem.SetWorldPosition(transform, newPos); + } + + private Vector2 ConvertMoveButtonsToVector(MoveButtons buttons) + { + var direction = Vector2.Zero; + + if (buttons.HasFlag(MoveButtons.Up)) + direction += Vector2.UnitY; + if (buttons.HasFlag(MoveButtons.Down)) + direction -= Vector2.UnitY; + if (buttons.HasFlag(MoveButtons.Left)) + direction -= Vector2.UnitX; + if (buttons.HasFlag(MoveButtons.Right)) + direction += Vector2.UnitX; + + return direction.Normalized(); + } } } diff --git a/Content.Shared/Vehicles/VehicleSystem.cs b/Content.Shared/Vehicles/VehicleSystem.cs deleted file mode 100644 index fbf011f1ca1..00000000000 --- a/Content.Shared/Vehicles/VehicleSystem.cs +++ /dev/null @@ -1,113 +0,0 @@ -using Content.Server.Vehicles.Components; -using Content.Shared.Buckle; -using Content.Shared.Buckle.Components; -using Content.Shared.Interaction; -using Content.Shared.Popups; -using Content.Shared.Vehicle; -using Content.Shared.Verbs; -using Content.Shared.Movement.Events; -using Robust.Shared.GameObjects; -using Robust.Shared.IoC; -using Robust.Shared.Map; -using Robust.Shared.Physics; -using Robust.Shared.Player; -using Robust.Shared.Timing; - -namespace Content.Server.Vehicles.Systems -{ - public sealed class VehicleSystem : EntitySystem - { - [Dependency] private readonly IGameTiming _gameTiming = default!; - [Dependency] private readonly IMapManager _mapManager = default!; - [Dependency] private readonly IEntityManager _entityManager = default!; - [Dependency] private readonly SharedBuckleSystem _buckleSystem = default!; - [Dependency] private readonly SharedPopupSystem _popupSystem = default!; - - public override void Initialize() - { - base.Initialize(); - SubscribeLocalEvent>(AddEnterVehicleVerb); - SubscribeLocalEvent(OnMoveInput); - SubscribeLocalEvent(OnInteractHand); - SubscribeLocalEvent(OnBuckleChange); - } - - private void AddEnterVehicleVerb(EntityUid uid, VehicleComponent component, GetVerbsEvent args) - { - if (!args.CanInteract || !args.CanAccess) - return; - - if (component.Occupants.Count >= component.MaxOccupants) - return; - - AlternativeVerb verb = new() - { - Act = () => EnterVehicle(args.User, uid, component), - Text = Loc.GetString("enter-vehicle-verb"), - Priority = 2 - }; - args.Verbs.Add(verb); - } - - private void EnterVehicle(EntityUid user, EntityUid vehicle, VehicleComponent component) - { - if (component.Occupants.Count >= component.MaxOccupants) - { - _popupSystem.PopupEntity("The vehicle is full.", vehicle, Filter.Entities(user)); - return; - } - - if (_buckleSystem.TryBuckle(user, user, vehicle)) - { - component.Occupants.Add(user); - if (component.Driver == null) - { - component.Driver = user; - } - } - } - - private void OnMoveInput(EntityUid uid, VehicleComponent component, ref MoveInputEvent args) - { - if (component.Driver == null || component.Driver != args.User) - return; - - var transform = EntityManager.GetComponent(uid); - var direction = args.Component.HeldMoveButtons.ToVec(); - transform.Coordinates += direction * component.Speed * (float) _gameTiming.FrameTime.TotalSeconds; - } - - private void OnInteractHand(EntityUid uid, VehicleComponent component, InteractHandEvent args) - { - if (args.Handled) - return; - - if (component.Occupants.Contains(args.User)) - { - _buckleSystem.TryUnbuckle(args.User, args.User, false); - } - else - { - EnterVehicle(args.User, uid, component); - } - - args.Handled = true; - } - - private void OnBuckleChange(EntityUid uid, VehicleComponent component, BuckleChangeEvent args) - { - if (args.Buckling) - { - component.Occupants.Add(args.BuckledEntity); - } - else - { - component.Occupants.Remove(args.BuckledEntity); - if (component.Driver == args.BuckledEntity) - { - component.Driver = component.Occupants.Count > 0 ? component.Occupants[0] : null; - } - } - } - } -} diff --git a/Resources/Prototypes/Entities/Vehicles/vehicles.yml b/Resources/Prototypes/Entities/Vehicles/vehicles.yml index 075b7229016..0bdade90fd5 100644 --- a/Resources/Prototypes/Entities/Vehicles/vehicles.yml +++ b/Resources/Prototypes/Entities/Vehicles/vehicles.yml @@ -48,3 +48,5 @@ delay: 0.5 - type: Item size: Large + - type: RiddenVehicle + maxRiders: 1 diff --git a/Resources/Textures/Objects/Vehicles/secway.rsi/meta.json b/Resources/Textures/Objects/Vehicles/secway.rsi/meta.json index 27d17beb56e..90b34f92578 100644 --- a/Resources/Textures/Objects/Vehicles/secway.rsi/meta.json +++ b/Resources/Textures/Objects/Vehicles/secway.rsi/meta.json @@ -1,43 +1,48 @@ { - "version": 1, - "size": { - "x": 32, - "y": 32 - }, - "license": "CC-BY-SA-3.0", - "copyright": "Taken from tgstation at https://github.com/tgstation/tgstation/commit/40d89d11ea4a5cb81d61dc1018b46f4e7d32c62a", - "states": [ - { - "name": "vehicle", - "directions": 4, - "delays": [ - [ - 0.2, - 0.2, - 0.2 - ], - [ - 0.2, - 0.2, - 0.2 - ], - [ - 0.2, - 0.2, - 0.2 - ], - [ - 0.2, - 0.2, - 0.2 - ] - ] - }, - { - "name": "keys" + "version": 1, + "size": { + "x": 32, + "y": 32 }, - { - "name": "icon" - } - ] -} + "license": "CC-BY-SA-3.0", + "copyright": "Taken from tgstation at https://github.com/tgstation/tgstation/commit/40d89d11ea4a5cb81d61dc1018b46f4e7d32c62a", + "states": [ + { + "name": "vehicle", + "directions": 4, + "delays": [ + [ + 0.2, + 0.2, + 0.2 + ], + [ + 0.2, + 0.2, + 0.2 + ], + [ + 0.2, + 0.2, + 0.2 + ], + [ + 0.2, + 0.2, + 0.2 + ] + ] + }, + { + "name": "keys" + }, + { + "name": "icon" + }, + { + "name": "secway", + "directions": 1, + "delay": [100] + } + ] + } From f96c8c97c69278fa97a06d3af925096327165304 Mon Sep 17 00:00:00 2001 From: Acensti Date: Sun, 7 Jul 2024 23:09:16 +0200 Subject: [PATCH 7/8] more stuff --- Content.Shared/Buckle/SharedBuckleSystem.cs | 114 ++---------------- .../Components/RiddenVehicleComponent.cs | 3 + .../Vehicles/Components/VehicleComponent.cs | 22 ---- .../Vehicles/RiddenVehicleSystem.cs | 2 +- .../Prototypes/Entities/Vehicles/vehicles.yml | 40 +----- .../Entities/Markers/Spawners/Vehicles.yml | 32 +++-- .../Objects/Vehicles/secway.rsi/meta.json | 8 -- 7 files changed, 39 insertions(+), 182 deletions(-) delete mode 100644 Content.Shared/Vehicles/Components/VehicleComponent.cs diff --git a/Content.Shared/Buckle/SharedBuckleSystem.cs b/Content.Shared/Buckle/SharedBuckleSystem.cs index a05621f9d93..5974c18dd49 100644 --- a/Content.Shared/Buckle/SharedBuckleSystem.cs +++ b/Content.Shared/Buckle/SharedBuckleSystem.cs @@ -79,6 +79,7 @@ private void InitializeBuckle() SubscribeLocalEvent(OnBuckleThrowPushbackAttempt); SubscribeLocalEvent(OnBuckleUpdateCanMove); } + public bool ToggleBuckle(EntityUid buckleUid, EntityUid userUid, EntityUid strapUid, BuckleComponent? buckleComp = null, StrapComponent? strapComp = null) { if (!Resolve(buckleUid, ref buckleComp, false) || !Resolve(strapUid, ref strapComp, false)) @@ -89,64 +90,41 @@ public bool ToggleBuckle(EntityUid buckleUid, EntityUid userUid, EntityUid strap else return TryBuckle(buckleUid, userUid, strapUid, buckleComp, strapComp); } - public bool IsBuckled(EntityUid uid, BuckleComponent? buckleComp = null) + public bool IsBuckled(EntityUid uid, BuckleComponent? buckleComp = null) { - if (!Resolve(uid, ref buckleComp, false)) - return false; - return buckleComp.Buckled; - } - public void StrapSetEnabled(EntityUid uid, bool enabled) + public void StrapSetEnabled(EntityUid uid, bool enabled) { - if (TryComp(uid, out var strap)) - { - strap.Enabled = enabled; - Dirty(uid, strap); - } - } - private void OnStrapStartup(EntityUid uid, StrapComponent component, ComponentStartup args) - { - UpdateStrapVisuals(uid, component); - var buckleQuery = GetEntityQuery(); - var xform = Transform(uid); - var buckleEntities = GetEntitiesInRange(uid, component.MaxBuckleDistance); - foreach (var entity in buckleEntities) - { - if (buckleQuery.TryGetComponent(entity, out var buckle) && !buckle.Buckled) - { - TryBuckle(entity, entity, uid, buckle, component); - } - } - } + public IEnumerable GetEntitiesInRange(EntityUid uid, float range, TransformComponent? xform = null) { if (!Resolve(uid, ref xform)) @@ -171,46 +149,29 @@ public IEnumerable GetEntitiesInRange(EntityUid uid, float range, Tra } } } - private void OnStrapShutdown(EntityUid uid, StrapComponent component, ComponentShutdown args) + private void OnStrapShutdown(EntityUid uid, StrapComponent component, ComponentShutdown args) { - // Unbuckle all entities from this strap - foreach (var buckledEntity in component.BuckledEntities.ToList()) - { - TryUnbuckle(buckledEntity, buckledEntity, true); - } - // Clear the buckled entities list - component.BuckledEntities.Clear(); - component.OccupiedSize = 0; - // Update the strap's visual state - UpdateStrapVisuals(uid, component); - } - private void UpdateStrapVisuals(EntityUid uid, StrapComponent? strap = null) - { - if (!Resolve(uid, ref strap)) - return; - Appearance.SetData(uid, StrapVisuals.State, strap.BuckledEntities.Count > 0); - } private void OnBuckleStartup(EntityUid uid, BuckleComponent component, ComponentStartup args) @@ -304,150 +265,91 @@ private void UpdateBuckleStatus(EntityUid uid, BuckleComponent component) } public bool TryBuckle(EntityUid buckleUid, EntityUid userUid, EntityUid strapUid, BuckleComponent? buckleComp = null, StrapComponent? strapComp = null) - { - if (!Resolve(buckleUid, ref buckleComp, false) || !Resolve(strapUid, ref strapComp, false)) - return false; - if (buckleComp.Buckled || !CanBuckle(buckleUid, userUid, strapUid, out strapComp, buckleComp)) - return false; - buckleComp.Buckled = true; - buckleComp.BuckledTo = strapUid; - buckleComp.BuckleTime = _gameTiming.CurTime; - strapComp.BuckledEntities.Add(buckleUid); - strapComp.OccupiedSize += buckleComp.Size; - ReAttach(buckleUid, strapUid, buckleComp, strapComp); - _audio.PlayPredicted(strapComp.BuckleSound, strapUid, userUid); - _alerts.ShowAlert(buckleUid, strapComp.BuckledAlertType); - var ev = new BuckleChangeEvent(strapUid, buckleUid, true); - RaiseLocalEvent(buckleUid, ref ev); - RaiseLocalEvent(strapUid, ref ev); - return true; - } - public bool TryUnbuckle(EntityUid buckleUid, EntityUid userUid, bool force, BuckleComponent? buckleComp = null, StrapComponent? strapComp = null) + public bool TryUnbuckle(EntityUid buckleUid, EntityUid userUid, bool force, BuckleComponent? buckleComp = null, StrapComponent? strapComp = null) { - if (!Resolve(buckleUid, ref buckleComp, false) || !buckleComp.Buckled || buckleComp.BuckledTo == null || !Resolve(buckleComp.BuckledTo.Value, ref strapComp, false)) - return false; - if (!force && _gameTiming.CurTime < buckleComp.BuckleTime + buckleComp.Delay) - return false; - buckleComp.Buckled = false; - buckleComp.BuckledTo = null!; - if (_mobState.IsIncapacitated(buckleUid)) - _standing.Down(buckleUid); - if (strapComp.BuckledEntities.Remove(buckleUid)) - { - strapComp.OccupiedSize -= buckleComp.Size; - Dirty(buckleComp.BuckledTo.Value, strapComp); - } - _joints.RefreshRelay(buckleUid); - Appearance.SetData(buckleComp.BuckledTo.Value, StrapVisuals.State, strapComp.BuckledEntities.Count != 0); - if (!TerminatingOrDeleted(buckleComp.BuckledTo.Value)) - _audio.PlayPredicted(strapComp.UnbuckleSound, buckleComp.BuckledTo.Value, userUid); - var ev = new BuckleChangeEvent(buckleComp.BuckledTo.Value, buckleUid, false); - RaiseLocalEvent(buckleUid, ref ev); - RaiseLocalEvent(buckleComp.BuckledTo.Value, ref ev); - return true; - } - private bool CanBuckle(EntityUid buckleUid, EntityUid userUid, EntityUid strapUid, [NotNullWhen(true)] out StrapComponent? strapComp, BuckleComponent? buckleComp = null) - { - strapComp = null; - if (!Resolve(buckleUid, ref buckleComp, false) || !Resolve(strapUid, ref strapComp, false)) - return false; - if (userUid == strapUid) - return false; - if (!ActionBlocker.CanInteract(userUid, strapUid)) - return false; - if (!IsEntityAllowed(buckleUid, strapComp)) - return false; - if (!_interaction.InRangeUnobstructed(buckleUid, strapUid, buckleComp.Range)) - return false; - if (strapComp.OccupiedSize + buckleComp.Size > strapComp.Size) - return false; - if (!strapComp.Enabled) - return false; - return true; - } private bool IsEntityAllowed(EntityUid buckleUid, StrapComponent strapComp) @@ -487,11 +389,9 @@ private void ReAttach(EntityUid buckleUid, EntityUid strapUid, BuckleComponent? break; } } - public enum StrapVisuals + public enum StrapVisuals { - State - } } diff --git a/Content.Shared/Vehicles/Components/RiddenVehicleComponent.cs b/Content.Shared/Vehicles/Components/RiddenVehicleComponent.cs index 08b5a630b74..962bb9e27ec 100644 --- a/Content.Shared/Vehicles/Components/RiddenVehicleComponent.cs +++ b/Content.Shared/Vehicles/Components/RiddenVehicleComponent.cs @@ -15,5 +15,8 @@ public sealed partial class RiddenVehicleComponent : Component [ViewVariables(VVAccess.ReadWrite)] [DataField("speed")] public float Speed = 5f; + [DataField("canMove")] + + public bool CanMove = true; } } diff --git a/Content.Shared/Vehicles/Components/VehicleComponent.cs b/Content.Shared/Vehicles/Components/VehicleComponent.cs deleted file mode 100644 index 37d8fa6470c..00000000000 --- a/Content.Shared/Vehicles/Components/VehicleComponent.cs +++ /dev/null @@ -1,22 +0,0 @@ -using Robust.Shared.GameObjects; -using Robust.Shared.Serialization.Manager.Attributes; -using Robust.Shared.ViewVariables; - -namespace Content.Server.Vehicles.Components -{ - [RegisterComponent] - public sealed partial class VehicleComponent : Component - { - [DataField("maxOccupants")] - public int MaxOccupants = 1; - - [DataField("speed")] - public float Speed = 1.0f; - - [ViewVariables] - public List Occupants = new(); - - [ViewVariables] - public EntityUid? Driver; - } -} diff --git a/Content.Shared/Vehicles/RiddenVehicleSystem.cs b/Content.Shared/Vehicles/RiddenVehicleSystem.cs index 0c85adc2ab2..36a1a622646 100644 --- a/Content.Shared/Vehicles/RiddenVehicleSystem.cs +++ b/Content.Shared/Vehicles/RiddenVehicleSystem.cs @@ -4,7 +4,7 @@ using Content.Shared.Interaction; using Content.Shared.Movement.Components; using Content.Shared.Movement.Events; -using Content.Shared.Movement.Systems; // Added this line +using Content.Shared.Movement.Systems; using Content.Shared.Popups; using Content.Shared.Vehicle; using Robust.Shared.GameObjects; diff --git a/Resources/Prototypes/Entities/Vehicles/vehicles.yml b/Resources/Prototypes/Entities/Vehicles/vehicles.yml index 0bdade90fd5..c559510eb07 100644 --- a/Resources/Prototypes/Entities/Vehicles/vehicles.yml +++ b/Resources/Prototypes/Entities/Vehicles/vehicles.yml @@ -1,30 +1,3 @@ -- type: entity - id: VehicleCar - name: Car - description: A simple car for transportation. - components: - - type: Sprite - sprite: Vehicles/car.rsi - - type: Physics - - type: MovementSpeedModifier - baseWalkSpeed: 3.0 - baseSprintSpeed: 6.0 - - type: Vehicle - maxOccupants: 4 - maxDrivers: 1 - - type: Damageable - damageContainer: Vehicle - - type: Destructible - thresholds: - - trigger: !type:DamageTrigger - damage: 100 - behaviors: - - !type:DoActsBehavior - acts: ["Destruction"] - - type: ContainerContainer - containers: - vehicle_storage: !type:Container - - type: entity id: VehicleSecway name: Secway @@ -32,21 +5,20 @@ components: - type: Sprite sprite: Objects/Vehicles/secway.rsi - state: secway + state: vehicle - type: Physics bodyType: Dynamic - - type: Vehicle - maxOccupants: 1 - maxDrivers: 1 + - type: RiddenVehicle speed: 2.0 - type: Buckle range: 1.0 delay: 0.5 + - type: Strap + position: Stand + buckleOffset: "0,0" + size: 100 - type: Pullable - - type: Interactable - type: UseDelay delay: 0.5 - type: Item size: Large - - type: RiddenVehicle - maxRiders: 1 diff --git a/Resources/Prototypes/Nyanotrasen/Entities/Markers/Spawners/Vehicles.yml b/Resources/Prototypes/Nyanotrasen/Entities/Markers/Spawners/Vehicles.yml index f5c8d41e9ca..47f97722374 100644 --- a/Resources/Prototypes/Nyanotrasen/Entities/Markers/Spawners/Vehicles.yml +++ b/Resources/Prototypes/Nyanotrasen/Entities/Markers/Spawners/Vehicles.yml @@ -1,13 +1,25 @@ - type: entity - name: Secway Spawner - id: SpawnVehicleSecway - parent: MarkerBase + id: VehicleSecway + name: Secway + description: A simple personal transportation device. components: - type: Sprite - layers: - - state: green - - sprite: Objects/Vehicles/secway.rsi - state: keys - - type: ConditionalSpawner - prototypes: - - VehicleSecway + sprite: Objects/Vehicles/secway.rsi + state: vehicle + - type: Physics + bodyType: Dynamic + - type: Vehicle + maxOccupants: 1 + maxDrivers: 1 + speed: 2.0 + - type: Buckle + range: 1.0 + delay: 0.5 + - type: Pullable + - type: Interactable + - type: UseDelay + delay: 0.5 + - type: Item + size: Large + - type: RiddenVehicle + maxRiders: 1 diff --git a/Resources/Textures/Objects/Vehicles/secway.rsi/meta.json b/Resources/Textures/Objects/Vehicles/secway.rsi/meta.json index 90b34f92578..ff058baacf3 100644 --- a/Resources/Textures/Objects/Vehicles/secway.rsi/meta.json +++ b/Resources/Textures/Objects/Vehicles/secway.rsi/meta.json @@ -35,14 +35,6 @@ }, { "name": "keys" - }, - { - "name": "icon" - }, - { - "name": "secway", - "directions": 1, - "delay": [100] } ] } From e757fde938b25eee1875522502acbb01ff0f8721 Mon Sep 17 00:00:00 2001 From: Acensti Date: Mon, 8 Jul 2024 13:47:54 +0200 Subject: [PATCH 8/8] c --- Content.Shared/Key/KeyComponent.cs | 13 --------- Content.Shared/Key/KeyRequiredComponent.cs | 13 --------- Content.Shared/Key/KeySystem.cs | 28 ------------------- .../Vehicles/Components/KeyComponent.cs | 14 ---------- .../Vehicles/RiddenVehicleSystem.cs | 4 +-- 5 files changed, 2 insertions(+), 70 deletions(-) delete mode 100644 Content.Shared/Key/KeyComponent.cs delete mode 100644 Content.Shared/Key/KeyRequiredComponent.cs delete mode 100644 Content.Shared/Key/KeySystem.cs delete mode 100644 Content.Shared/Vehicles/Components/KeyComponent.cs diff --git a/Content.Shared/Key/KeyComponent.cs b/Content.Shared/Key/KeyComponent.cs deleted file mode 100644 index d2e0f82ba5e..00000000000 --- a/Content.Shared/Key/KeyComponent.cs +++ /dev/null @@ -1,13 +0,0 @@ -using Robust.Shared.GameObjects; -using Robust.Shared.Serialization.Manager.Attributes; - -namespace Content.Shared.Key -{ - [RegisterComponent] - public partial class KeyComponent : Component - { - - [DataField("keyId")] - public string KeyId = string.Empty; - } -} diff --git a/Content.Shared/Key/KeyRequiredComponent.cs b/Content.Shared/Key/KeyRequiredComponent.cs deleted file mode 100644 index 2c231a7a7e1..00000000000 --- a/Content.Shared/Key/KeyRequiredComponent.cs +++ /dev/null @@ -1,13 +0,0 @@ -using Robust.Shared.GameObjects; -using Robust.Shared.Serialization.Manager.Attributes; - -namespace Content.Shared.Key -{ - [RegisterComponent] - public sealed partial class KeyRequiredComponent : Component - { - - [DataField("requiredKeyId")] - public string RequiredKeyId = string.Empty; - } -} diff --git a/Content.Shared/Key/KeySystem.cs b/Content.Shared/Key/KeySystem.cs deleted file mode 100644 index b91a63533c6..00000000000 --- a/Content.Shared/Key/KeySystem.cs +++ /dev/null @@ -1,28 +0,0 @@ -using Robust.Shared.GameObjects; -using Robust.Shared.IoC; - -namespace Content.Shared.Key -{ - public sealed class KeySystem : EntitySystem - { - public override void Initialize() - { - base.Initialize(); - SubscribeLocalEvent(OnKeyRequiredStartup); - } - - private void OnKeyRequiredStartup(EntityUid uid, KeyRequiredComponent component, ComponentStartup args) - { - // Logic to handle key requirements - } - - public bool HasValidKey(EntityUid uid, string requiredKeyId) - { - if (EntityManager.TryGetComponent(uid, out KeyComponent? keyComp)) - { - return keyComp.KeyId == requiredKeyId; - } - return false; - } - } -} diff --git a/Content.Shared/Vehicles/Components/KeyComponent.cs b/Content.Shared/Vehicles/Components/KeyComponent.cs deleted file mode 100644 index 5a80a6fc0e8..00000000000 --- a/Content.Shared/Vehicles/Components/KeyComponent.cs +++ /dev/null @@ -1,14 +0,0 @@ -using Robust.Shared.GameObjects; - -namespace Content.Shared.Vehicle -{ - [RegisterComponent] - public partial class KeyComponent : Component - { - [DataField("keyType")] - public string KeyType = string.Empty; - - [ViewVariables] - public bool IsInserted = false; - } -} diff --git a/Content.Shared/Vehicles/RiddenVehicleSystem.cs b/Content.Shared/Vehicles/RiddenVehicleSystem.cs index 36a1a622646..4ca53500b54 100644 --- a/Content.Shared/Vehicles/RiddenVehicleSystem.cs +++ b/Content.Shared/Vehicles/RiddenVehicleSystem.cs @@ -26,7 +26,7 @@ public override void Initialize() { base.Initialize(); SubscribeLocalEvent(OnInteractHand); - SubscribeLocalEvent(OnBuckleChange); + SubscribeLocalEvent(OnBuckleChange); SubscribeLocalEvent(OnMoveInput); } @@ -47,7 +47,7 @@ private void OnInteractHand(EntityUid uid, RiddenVehicleComponent component, Int args.Handled = true; } - private void OnBuckleChange(EntityUid uid, RiddenVehicleComponent component, BuckleChangeEvent args) + private void OnBuckleChange(EntityUid uid, RiddenVehicleComponent component, Content.Shared.Buckle.Components.BuckleChangeEvent args) { if (args.Buckling) {