using System.Collections.Generic; using Content.Server.GameObjects.Components.Mobs; using Content.Server.GameObjects.EntitySystems; using Content.Shared.GameObjects; using Content.Shared.GameObjects.Components.Strap; using Content.Shared.GameObjects.EntitySystems; using Robust.Server.GameObjects; using Robust.Shared.GameObjects; using Robust.Shared.GameObjects.Systems; using Robust.Shared.Interfaces.GameObjects; using Robust.Shared.Localization; using Robust.Shared.Serialization; using Robust.Shared.ViewVariables; namespace Content.Server.GameObjects.Components.Strap { [RegisterComponent] public class StrapComponent : SharedStrapComponent, IInteractHand { private StrapPosition _position; private string _buckleSound; private string _unbuckleSound; private int _rotation; private int _size; /// /// The entity that is currently buckled here, synced from /// private HashSet BuckledEntities { get; set; } /// /// The change in position to the strapped mob /// public override StrapPosition Position { get => _position; set { _position = value; Dirty(); } } /// /// The sound to be played when a mob is buckled /// [ViewVariables] public string BuckleSound => _buckleSound; /// /// The sound to be played when a mob is unbuckled /// [ViewVariables] public string UnbuckleSound => _unbuckleSound; /// /// The angle in degrees to rotate the player by when they get strapped /// [ViewVariables] public int Rotation => _rotation; /// /// The size of the strap which is compared against when buckling entities /// [ViewVariables] public int Size => _size; /// /// The sum of the sizes of all the buckled entities in this strap /// [ViewVariables] private int OccupiedSize { get; set; } public bool HasSpace(BuckleComponent buckle) { return OccupiedSize + buckle.Size <= _size; } /// /// Adds a buckled entity. Called from /// /// The component to add /// Whether or not to check if the strap has enough space /// True if added, false otherwise public bool TryAdd(BuckleComponent buckle, bool force = false) { if (!force && !HasSpace(buckle)) { return false; } if (!BuckledEntities.Add(buckle.Owner)) { return false; } OccupiedSize += buckle.Size; if (buckle.Owner.TryGetComponent(out AppearanceComponent appearance)) { appearance.SetData(StrapVisuals.RotationAngle, _rotation); } return true; } /// /// Removes a buckled entity. Called from /// /// The component to remove public void Remove(BuckleComponent buckle) { if (BuckledEntities.Remove(buckle.Owner)) { OccupiedSize -= buckle.Size; } } public override void ExposeData(ObjectSerializer serializer) { base.ExposeData(serializer); serializer.DataField(ref _position, "position", StrapPosition.None); serializer.DataField(ref _buckleSound, "buckleSound", "/Audio/effects/buckle.ogg"); serializer.DataField(ref _unbuckleSound, "unbuckleSound", "/Audio/effects/unbuckle.ogg"); serializer.DataField(ref _rotation, "rotation", 0); var defaultSize = 100; serializer.DataField(ref _size, "size", defaultSize); BuckledEntities = new HashSet(_size / defaultSize); OccupiedSize = 0; } public override void OnRemove() { base.OnRemove(); foreach (var entity in BuckledEntities) { if (entity.TryGetComponent(out BuckleComponent buckle)) { buckle.TryUnbuckle(entity, true); } } BuckledEntities.Clear(); OccupiedSize = 0; } [Verb] private sealed class StrapVerb : Verb { protected override void GetData(IEntity user, StrapComponent component, VerbData data) { data.Visibility = VerbVisibility.Invisible; if (!ActionBlockerSystem.CanInteract(component.Owner) || !user.TryGetComponent(out BuckleComponent buckle) || buckle.BuckledTo != null && buckle.BuckledTo != component || user == component.Owner) { return; } var parent = component.Owner.Transform.Parent; while (parent != null) { if (parent == user.Transform) { return; } parent = parent.Parent; } var userPosition = user.Transform.MapPosition; var strapPosition = component.Owner.Transform.MapPosition; var range = SharedInteractionSystem.InteractionRange / 2; var inRange = EntitySystem.Get() .InRangeUnobstructed(userPosition, strapPosition, range, predicate: entity => entity == user || entity == component.Owner); if (!inRange) { return; } data.Visibility = VerbVisibility.Visible; data.Text = buckle.BuckledTo == null ? Loc.GetString("Buckle") : Loc.GetString("Unbuckle"); } protected override void Activate(IEntity user, StrapComponent component) { if (!user.TryGetComponent(out BuckleComponent buckle)) { return; } buckle.ToggleBuckle(user, component.Owner); } } bool IInteractHand.InteractHand(InteractHandEventArgs eventArgs) { if (!eventArgs.User.TryGetComponent(out BuckleComponent buckle)) { return false; } return buckle.ToggleBuckle(eventArgs.User, Owner); } } }