From 552fbb058549a5b43c1fb1e46f8d27310c6421e0 Mon Sep 17 00:00:00 2001 From: metalgearsloth <31366439+metalgearsloth@users.noreply.github.com> Date: Sat, 27 May 2023 14:15:15 +1000 Subject: [PATCH] Adds grappling gun (#16662) --- Content.Client/Physics/JointVisualsOverlay.cs | 74 ++++++ Content.Client/Physics/JointVisualsSystem.cs | 20 ++ .../Weapons/Misc/GrapplingGunSystem.cs | 58 +++++ .../Ranged/Systems/GunSystem.Ballistic.cs | 9 +- .../Weapons/Ranged/Systems/GunSystem.cs | 5 +- .../EntitySystems/EmitterSystem.cs | 2 +- .../Weapons/Misc/GrapplingGunSystem.cs | 8 + .../Ranged/Systems/GunSystem.Ballistic.cs | 6 +- .../Weapons/Ranged/Systems/GunSystem.cs | 6 +- .../Movement/Events/WeightlessMoveEvent.cs | 6 +- .../Movement/Systems/SharedMoverController.cs | 4 +- .../Physics/JointVisualsComponent.cs | 29 +++ .../EmbeddableProjectileComponent.cs | 12 + .../Projectiles/ProjectileEmbedEvent.cs | 7 + .../Projectiles/SharedProjectileSystem.cs | 22 +- .../Pulling/Systems/SharedPullingSystem.cs | 12 + .../Misc/GrapplingProjectileComponent.cs | 9 + .../Weapons/Misc/SharedGrapplingGunSystem.cs | 230 ++++++++++++++++++ .../Misc/SharedTetherGunSystem.Force.cs | 2 +- .../BallisticAmmoProviderComponent.cs | 2 + .../Components/GrapplingGunComponent.cs | 28 +++ .../Components/RechargeCycleAmmoComponent.cs | 12 + .../Weapons/Ranged/Events/GunCycledEvent.cs | 7 + .../Ranged/Systems/RechargeCycleAmmoSystem.cs | 31 +++ .../Systems/SharedGunSystem.Ballistic.cs | 4 +- .../Weapons/Ranged/Systems/SharedGunSystem.cs | 15 +- Content.Shared/Wieldable/WieldableSystem.cs | 1 - .../Weapons/Guns/Gunshots/attributions.yml | 5 + .../Audio/Weapons/Guns/Gunshots/harpoon.ogg | Bin 0 -> 7358 bytes Resources/Audio/Weapons/attributions.yml | 5 + Resources/Audio/Weapons/reel.ogg | Bin 0 -> 35499 bytes .../Locale/en-US/research/technologies.ftl | 1 + .../Weapons/Guns/Launchers/launchers.yml | 54 +++- .../Weapons/Guns/Projectiles/projectiles.yml | 35 +++ .../Entities/Structures/Machines/lathe.yml | 1 + .../Prototypes/Recipes/Lathes/devices.yml | 9 + .../Prototypes/Research/experimental.yml | 12 + .../grappling_gun.rsi/base-unshaded-off.png | Bin 0 -> 5413 bytes .../grappling_gun.rsi/base-unshaded.png | Bin 0 -> 5087 bytes .../Guns/Launchers/grappling_gun.rsi/base.png | Bin 0 -> 6807 bytes .../grappling_gun.rsi/hook-unshaded.png | Bin 0 -> 5191 bytes .../Guns/Launchers/grappling_gun.rsi/hook.png | Bin 0 -> 5891 bytes .../inhand-left-unshaded.png | Bin 0 -> 5415 bytes .../grappling_gun.rsi/inhand-left.png | Bin 0 -> 8248 bytes .../inhand-right-unshaded.png | Bin 0 -> 5675 bytes .../grappling_gun.rsi/inhand-right.png | Bin 0 -> 8878 bytes .../Launchers/grappling_gun.rsi/meta.json | 45 ++++ .../Guns/Launchers/grappling_gun.rsi/rope.png | Bin 0 -> 5403 bytes 48 files changed, 753 insertions(+), 35 deletions(-) create mode 100644 Content.Client/Physics/JointVisualsOverlay.cs create mode 100644 Content.Client/Physics/JointVisualsSystem.cs create mode 100644 Content.Client/Weapons/Misc/GrapplingGunSystem.cs create mode 100644 Content.Server/Weapons/Misc/GrapplingGunSystem.cs create mode 100644 Content.Shared/Physics/JointVisualsComponent.cs create mode 100644 Content.Shared/Projectiles/EmbeddableProjectileComponent.cs create mode 100644 Content.Shared/Projectiles/ProjectileEmbedEvent.cs create mode 100644 Content.Shared/Weapons/Misc/GrapplingProjectileComponent.cs create mode 100644 Content.Shared/Weapons/Misc/SharedGrapplingGunSystem.cs create mode 100644 Content.Shared/Weapons/Ranged/Components/GrapplingGunComponent.cs create mode 100644 Content.Shared/Weapons/Ranged/Components/RechargeCycleAmmoComponent.cs create mode 100644 Content.Shared/Weapons/Ranged/Events/GunCycledEvent.cs create mode 100644 Content.Shared/Weapons/Ranged/Systems/RechargeCycleAmmoSystem.cs create mode 100644 Resources/Audio/Weapons/Guns/Gunshots/harpoon.ogg create mode 100644 Resources/Audio/Weapons/reel.ogg create mode 100644 Resources/Textures/Objects/Weapons/Guns/Launchers/grappling_gun.rsi/base-unshaded-off.png create mode 100644 Resources/Textures/Objects/Weapons/Guns/Launchers/grappling_gun.rsi/base-unshaded.png create mode 100644 Resources/Textures/Objects/Weapons/Guns/Launchers/grappling_gun.rsi/base.png create mode 100644 Resources/Textures/Objects/Weapons/Guns/Launchers/grappling_gun.rsi/hook-unshaded.png create mode 100644 Resources/Textures/Objects/Weapons/Guns/Launchers/grappling_gun.rsi/hook.png create mode 100644 Resources/Textures/Objects/Weapons/Guns/Launchers/grappling_gun.rsi/inhand-left-unshaded.png create mode 100644 Resources/Textures/Objects/Weapons/Guns/Launchers/grappling_gun.rsi/inhand-left.png create mode 100644 Resources/Textures/Objects/Weapons/Guns/Launchers/grappling_gun.rsi/inhand-right-unshaded.png create mode 100644 Resources/Textures/Objects/Weapons/Guns/Launchers/grappling_gun.rsi/inhand-right.png create mode 100644 Resources/Textures/Objects/Weapons/Guns/Launchers/grappling_gun.rsi/meta.json create mode 100644 Resources/Textures/Objects/Weapons/Guns/Launchers/grappling_gun.rsi/rope.png diff --git a/Content.Client/Physics/JointVisualsOverlay.cs b/Content.Client/Physics/JointVisualsOverlay.cs new file mode 100644 index 0000000000..5362a848d5 --- /dev/null +++ b/Content.Client/Physics/JointVisualsOverlay.cs @@ -0,0 +1,74 @@ +using Content.Shared.Physics; +using Robust.Client.GameObjects; +using Robust.Client.Graphics; +using Robust.Shared.Enums; +using Robust.Shared.Physics; +using Robust.Shared.Physics.Dynamics.Joints; + +namespace Content.Client.Physics; + +/// +/// Draws a texture on top of a joint. +/// +public sealed class JointVisualsOverlay : Overlay +{ + public override OverlaySpace Space => OverlaySpace.WorldSpaceBelowFOV; + + private IEntityManager _entManager; + + private HashSet _drawn = new(); + + public JointVisualsOverlay(IEntityManager entManager) + { + _entManager = entManager; + } + + protected override void Draw(in OverlayDrawArgs args) + { + _drawn.Clear(); + var worldHandle = args.WorldHandle; + + var spriteSystem = _entManager.System(); + var xformSystem = _entManager.System(); + var joints = _entManager.EntityQueryEnumerator(); + var xformQuery = _entManager.GetEntityQuery(); + + while (joints.MoveNext(out var visuals, out var xform)) + { + if (xform.MapID != args.MapId) + continue; + + var other = visuals.Target; + + if (!xformQuery.TryGetComponent(other, out var otherXform)) + continue; + + if (xform.MapID != otherXform.MapID) + continue; + + var texture = spriteSystem.Frame0(visuals.Sprite); + var width = texture.Width / (float) EyeManager.PixelsPerMeter; + + var coordsA = xform.Coordinates; + var coordsB = otherXform.Coordinates; + + var rotA = xform.LocalRotation; + var rotB = otherXform.LocalRotation; + + coordsA = coordsA.Offset(rotA.RotateVec(visuals.OffsetA)); + coordsB = coordsB.Offset(rotB.RotateVec(visuals.OffsetB)); + + var posA = coordsA.ToMapPos(_entManager, xformSystem); + var posB = coordsB.ToMapPos(_entManager, xformSystem); + var diff = (posB - posA); + var length = diff.Length; + + var midPoint = diff / 2f + posA; + var angle = (posB - posA).ToWorldAngle(); + var box = new Box2(-width / 2f, -length / 2f, width / 2f, length / 2f); + var rotate = new Box2Rotated(box.Translated(midPoint), angle, midPoint); + + worldHandle.DrawTextureRect(texture, rotate); + } + } +} diff --git a/Content.Client/Physics/JointVisualsSystem.cs b/Content.Client/Physics/JointVisualsSystem.cs new file mode 100644 index 0000000000..2e4e2e4c61 --- /dev/null +++ b/Content.Client/Physics/JointVisualsSystem.cs @@ -0,0 +1,20 @@ +using Robust.Client.Graphics; + +namespace Content.Client.Physics; + +public sealed class JointVisualsSystem : EntitySystem +{ + [Dependency] private readonly IOverlayManager _overlay = default!; + + public override void Initialize() + { + base.Initialize(); + _overlay.AddOverlay(new JointVisualsOverlay(EntityManager)); + } + + public override void Shutdown() + { + base.Shutdown(); + _overlay.RemoveOverlay(); + } +} diff --git a/Content.Client/Weapons/Misc/GrapplingGunSystem.cs b/Content.Client/Weapons/Misc/GrapplingGunSystem.cs new file mode 100644 index 0000000000..b54b11ee09 --- /dev/null +++ b/Content.Client/Weapons/Misc/GrapplingGunSystem.cs @@ -0,0 +1,58 @@ +using System.Net; +using Content.Client.Hands.Systems; +using Content.Shared.CombatMode; +using Content.Shared.Weapons.Misc; +using Content.Shared.Weapons.Ranged.Components; +using Robust.Client.GameObjects; +using Robust.Client.Player; +using Robust.Shared.Input; +using Robust.Shared.Physics; +using Robust.Shared.Physics.Dynamics.Joints; + +namespace Content.Client.Weapons.Misc; + +public sealed class GrapplingGunSystem : SharedGrapplingGunSystem +{ + [Dependency] private readonly HandsSystem _hands = default!; + [Dependency] private readonly InputSystem _input = default!; + [Dependency] private readonly IPlayerManager _player = default!; + + public override void Update(float frameTime) + { + base.Update(frameTime); + + // Oh boy another input handler. + // If someone thinks of a better way to unify this please tell me. + if (!Timing.IsFirstTimePredicted) + return; + + var local = _player.LocalPlayer?.ControlledEntity; + var handUid = _hands.GetActiveHandEntity(); + + if (!TryComp(handUid, out var grappling)) + return; + + if (!TryComp(handUid, out var jointComp) || + !jointComp.GetJoints.TryGetValue(GrapplingJoint, out var joint) || + joint is not DistanceJoint distance) + { + return; + } + + if (distance.MaxLength <= distance.MinLength) + return; + + var reelKey = _input.CmdStates.GetState(EngineKeyFunctions.UseSecondary) == BoundKeyState.Down; + + if (!TryComp(local, out var combatMode) || + !combatMode.IsInCombatMode) + { + reelKey = false; + } + + if (grappling.Reeling == reelKey) + return; + + RaisePredictiveEvent(new RequestGrapplingReelMessage(reelKey)); + } +} diff --git a/Content.Client/Weapons/Ranged/Systems/GunSystem.Ballistic.cs b/Content.Client/Weapons/Ranged/Systems/GunSystem.Ballistic.cs index 3c4f3a9ffd..bb1754f06c 100644 --- a/Content.Client/Weapons/Ranged/Systems/GunSystem.Ballistic.cs +++ b/Content.Client/Weapons/Ranged/Systems/GunSystem.Ballistic.cs @@ -1,4 +1,5 @@ using Content.Shared.Weapons.Ranged.Components; +using Content.Shared.Weapons.Ranged.Events; using Robust.Shared.Map; namespace Content.Client.Weapons.Ranged.Systems; @@ -19,9 +20,10 @@ public sealed partial class GunSystem } } - protected override void Cycle(BallisticAmmoProviderComponent component, MapCoordinates coordinates) + protected override void Cycle(EntityUid uid, BallisticAmmoProviderComponent component, MapCoordinates coordinates) { - if (!Timing.IsFirstTimePredicted) return; + if (!Timing.IsFirstTimePredicted) + return; EntityUid? ent = null; @@ -43,5 +45,8 @@ public sealed partial class GunSystem if (ent != null && ent.Value.IsClientSide()) Del(ent.Value); + + var cycledEvent = new GunCycledEvent(); + RaiseLocalEvent(uid, ref cycledEvent); } } diff --git a/Content.Client/Weapons/Ranged/Systems/GunSystem.cs b/Content.Client/Weapons/Ranged/Systems/GunSystem.cs index 191c2b1089..6132fdae67 100644 --- a/Content.Client/Weapons/Ranged/Systems/GunSystem.cs +++ b/Content.Client/Weapons/Ranged/Systems/GunSystem.cs @@ -173,8 +173,10 @@ public sealed partial class GunSystem : SharedGunSystem } public override void Shoot(EntityUid gunUid, GunComponent gun, List<(EntityUid? Entity, IShootable Shootable)> ammo, - EntityCoordinates fromCoordinates, EntityCoordinates toCoordinates, EntityUid? user = null, bool throwItems = false) + EntityCoordinates fromCoordinates, EntityCoordinates toCoordinates, out bool userImpulse, EntityUid? user = null, bool throwItems = false) { + userImpulse = true; + // Rather than splitting client / server for every ammo provider it's easier // to just delete the spawned entities. This is for programmer sanity despite the wasted perf. // This also means any ammo specific stuff can be grabbed as necessary. @@ -207,6 +209,7 @@ public sealed partial class GunSystem : SharedGunSystem } else { + userImpulse = false; Audio.PlayPredicted(gun.SoundEmpty, gunUid, user); } diff --git a/Content.Server/Singularity/EntitySystems/EmitterSystem.cs b/Content.Server/Singularity/EntitySystems/EmitterSystem.cs index fb69f6b6b6..72c6be85df 100644 --- a/Content.Server/Singularity/EntitySystems/EmitterSystem.cs +++ b/Content.Server/Singularity/EntitySystems/EmitterSystem.cs @@ -293,7 +293,7 @@ namespace Content.Server.Singularity.EntitySystems _projectile.SetShooter(proj, uid); var targetPos = new EntityCoordinates(uid, (0, -1)); - _gun.Shoot(uid, guncomp, ent, xform.Coordinates, targetPos); + _gun.Shoot(uid, guncomp, ent, xform.Coordinates, targetPos, out _); } private void UpdateAppearance(EmitterComponent component) diff --git a/Content.Server/Weapons/Misc/GrapplingGunSystem.cs b/Content.Server/Weapons/Misc/GrapplingGunSystem.cs new file mode 100644 index 0000000000..3ece50af59 --- /dev/null +++ b/Content.Server/Weapons/Misc/GrapplingGunSystem.cs @@ -0,0 +1,8 @@ +using Content.Shared.Weapons.Misc; + +namespace Content.Server.Weapons.Misc; + +public sealed class GrapplingGunSystem : SharedGrapplingGunSystem +{ + +} diff --git a/Content.Server/Weapons/Ranged/Systems/GunSystem.Ballistic.cs b/Content.Server/Weapons/Ranged/Systems/GunSystem.Ballistic.cs index f6eaacd476..3a28c7cdb1 100644 --- a/Content.Server/Weapons/Ranged/Systems/GunSystem.Ballistic.cs +++ b/Content.Server/Weapons/Ranged/Systems/GunSystem.Ballistic.cs @@ -1,11 +1,12 @@ using Content.Shared.Weapons.Ranged.Components; +using Content.Shared.Weapons.Ranged.Events; using Robust.Shared.Map; namespace Content.Server.Weapons.Ranged.Systems; public sealed partial class GunSystem { - protected override void Cycle(BallisticAmmoProviderComponent component, MapCoordinates coordinates) + protected override void Cycle(EntityUid uid, BallisticAmmoProviderComponent component, MapCoordinates coordinates) { EntityUid? ent = null; @@ -27,5 +28,8 @@ public sealed partial class GunSystem if (ent != null) EjectCartridge(ent.Value); + + var cycledEvent = new GunCycledEvent(); + RaiseLocalEvent(uid, ref cycledEvent); } } diff --git a/Content.Server/Weapons/Ranged/Systems/GunSystem.cs b/Content.Server/Weapons/Ranged/Systems/GunSystem.cs index 9831b0643e..5c90d5ec32 100644 --- a/Content.Server/Weapons/Ranged/Systems/GunSystem.cs +++ b/Content.Server/Weapons/Ranged/Systems/GunSystem.cs @@ -67,8 +67,10 @@ public sealed partial class GunSystem : SharedGunSystem } public override void Shoot(EntityUid gunUid, GunComponent gun, List<(EntityUid? Entity, IShootable Shootable)> ammo, - EntityCoordinates fromCoordinates, EntityCoordinates toCoordinates, EntityUid? user = null, bool throwItems = false) + EntityCoordinates fromCoordinates, EntityCoordinates toCoordinates, out bool userImpulse, EntityUid? user = null, bool throwItems = false) { + userImpulse = true; + // Try a clumsy roll // TODO: Who put this here if (TryComp(user, out var clumsy)) @@ -88,6 +90,7 @@ public sealed partial class GunSystem : SharedGunSystem PopupSystem.PopupEntity(Loc.GetString("gun-clumsy"), user.Value); _adminLogger.Add(LogType.EntityDelete, LogImpact.Medium, $"Clumsy fire by {ToPrettyString(user.Value)} deleted {ToPrettyString(gunUid)}"); Del(gunUid); + userImpulse = false; return; } } @@ -161,6 +164,7 @@ public sealed partial class GunSystem : SharedGunSystem } else { + userImpulse = false; Audio.PlayPredicted(gun.SoundEmpty, gunUid, user); } diff --git a/Content.Shared/Movement/Events/WeightlessMoveEvent.cs b/Content.Shared/Movement/Events/WeightlessMoveEvent.cs index 73eac0d306..97e851d331 100644 --- a/Content.Shared/Movement/Events/WeightlessMoveEvent.cs +++ b/Content.Shared/Movement/Events/WeightlessMoveEvent.cs @@ -4,11 +4,7 @@ namespace Content.Shared.Movement.Events; /// Raised on an entity to check if it can move while weightless. /// [ByRefEvent] -public struct CanWeightlessMoveEvent +public record struct CanWeightlessMoveEvent(EntityUid Uid) { public bool CanMove = false; - - public CanWeightlessMoveEvent() - { - } } diff --git a/Content.Shared/Movement/Systems/SharedMoverController.cs b/Content.Shared/Movement/Systems/SharedMoverController.cs index ba52975105..b9e4bafb1a 100644 --- a/Content.Shared/Movement/Systems/SharedMoverController.cs +++ b/Content.Shared/Movement/Systems/SharedMoverController.cs @@ -185,8 +185,8 @@ namespace Content.Shared.Movement.Systems if (!touching) { - var ev = new CanWeightlessMoveEvent(); - RaiseLocalEvent(uid, ref ev); + var ev = new CanWeightlessMoveEvent(uid); + RaiseLocalEvent(uid, ref ev, true); // No gravity: is our entity touching anything? touching = ev.CanMove; diff --git a/Content.Shared/Physics/JointVisualsComponent.cs b/Content.Shared/Physics/JointVisualsComponent.cs new file mode 100644 index 0000000000..2394f2f6ff --- /dev/null +++ b/Content.Shared/Physics/JointVisualsComponent.cs @@ -0,0 +1,29 @@ +using Robust.Shared.GameStates; +using Robust.Shared.Utility; + +namespace Content.Shared.Physics; + +/// +/// Just draws a generic line between this entity and the target. +/// +[RegisterComponent, NetworkedComponent, AutoGenerateComponentState] +public sealed partial class JointVisualsComponent : Component +{ + [ViewVariables(VVAccess.ReadWrite), DataField("sprite", required: true), AutoNetworkedField] + public SpriteSpecifier Sprite = default!; + + [ViewVariables(VVAccess.ReadWrite), DataField("target"), AutoNetworkedField] + public EntityUid? Target; + + /// + /// Offset from Body A. + /// + [ViewVariables(VVAccess.ReadWrite), DataField("offsetA"), AutoNetworkedField] + public Vector2 OffsetA; + + /// + /// Offset from Body B. + /// + [ViewVariables(VVAccess.ReadWrite), DataField("offsetB"), AutoNetworkedField] + public Vector2 OffsetB; +} diff --git a/Content.Shared/Projectiles/EmbeddableProjectileComponent.cs b/Content.Shared/Projectiles/EmbeddableProjectileComponent.cs new file mode 100644 index 0000000000..d5cd1ef76f --- /dev/null +++ b/Content.Shared/Projectiles/EmbeddableProjectileComponent.cs @@ -0,0 +1,12 @@ +using Robust.Shared.GameStates; + +namespace Content.Shared.Weapons.Ranged.Components; + +/// +/// Embeds this entity inside of the hit target. +/// +[RegisterComponent, NetworkedComponent] +public sealed class EmbeddableProjectileComponent : Component +{ + +} diff --git a/Content.Shared/Projectiles/ProjectileEmbedEvent.cs b/Content.Shared/Projectiles/ProjectileEmbedEvent.cs new file mode 100644 index 0000000000..4dc9b9841c --- /dev/null +++ b/Content.Shared/Projectiles/ProjectileEmbedEvent.cs @@ -0,0 +1,7 @@ +namespace Content.Shared.Projectiles; + +/// +/// Raised directed on an entity when it embeds into something. +/// +[ByRefEvent] +public readonly record struct ProjectileEmbedEvent(EntityUid Shooter, EntityUid Weapon, EntityUid Embedded); diff --git a/Content.Shared/Projectiles/SharedProjectileSystem.cs b/Content.Shared/Projectiles/SharedProjectileSystem.cs index 08b974cfda..cd01b71cc0 100644 --- a/Content.Shared/Projectiles/SharedProjectileSystem.cs +++ b/Content.Shared/Projectiles/SharedProjectileSystem.cs @@ -1,6 +1,9 @@ using Content.Shared.Projectiles; +using Content.Shared.Weapons.Ranged.Components; using Robust.Shared.Map; +using Robust.Shared.Physics; using Robust.Shared.Physics.Events; +using Robust.Shared.Physics.Systems; using Robust.Shared.Serialization; namespace Content.Shared.Projectiles @@ -9,10 +12,26 @@ namespace Content.Shared.Projectiles { public const string ProjectileFixture = "projectile"; + [Dependency] private readonly SharedPhysicsSystem _physics = default!; + [Dependency] private readonly SharedTransformSystem _transform = default!; + public override void Initialize() { base.Initialize(); SubscribeLocalEvent(PreventCollision); + SubscribeLocalEvent(OnEmbedCollide); + } + + private void OnEmbedCollide(EntityUid uid, EmbeddableProjectileComponent component, ref StartCollideEvent args) + { + if (!TryComp(uid, out var projectile)) + return; + + _physics.SetLinearVelocity(uid, Vector2.Zero, body: args.OurBody); + _physics.SetBodyType(uid, BodyType.Static, body: args.OurBody); + _transform.SetParent(uid, args.OtherEntity); + var ev = new ProjectileEmbedEvent(projectile.Shooter, projectile.Weapon, args.OtherEntity); + RaiseLocalEvent(uid, ref ev); } private void PreventCollision(EntityUid uid, ProjectileComponent component, ref PreventCollideEvent args) @@ -25,7 +44,8 @@ namespace Content.Shared.Projectiles public void SetShooter(ProjectileComponent component, EntityUid uid) { - if (component.Shooter == uid) return; + if (component.Shooter == uid) + return; component.Shooter = uid; Dirty(component); diff --git a/Content.Shared/Pulling/Systems/SharedPullingSystem.cs b/Content.Shared/Pulling/Systems/SharedPullingSystem.cs index c655687a7c..6bacc338ec 100644 --- a/Content.Shared/Pulling/Systems/SharedPullingSystem.cs +++ b/Content.Shared/Pulling/Systems/SharedPullingSystem.cs @@ -12,6 +12,8 @@ using Robust.Shared.Containers; using Robust.Shared.Input.Binding; using Robust.Shared.Map; using Robust.Shared.Physics; +using Robust.Shared.Physics.Events; +using Robust.Shared.Physics.Systems; using Robust.Shared.Players; namespace Content.Shared.Pulling @@ -22,6 +24,7 @@ namespace Content.Shared.Pulling [Dependency] private readonly SharedPullingStateManagementSystem _pullSm = default!; [Dependency] private readonly SharedGravitySystem _gravity = default!; [Dependency] private readonly AlertsSystem _alertsSystem = default!; + [Dependency] private readonly SharedJointSystem _joints = default!; /// /// A mapping of pullers to the entity that they are pulling. @@ -45,6 +48,7 @@ namespace Content.Shared.Pulling SubscribeLocalEvent(OnPullStopped); SubscribeLocalEvent(HandleContainerInsert); SubscribeLocalEvent(OnJointRemoved); + SubscribeLocalEvent(OnPullableCollisionChange); SubscribeLocalEvent(PullableHandlePullStarted); SubscribeLocalEvent(PullableHandlePullStopped); @@ -56,6 +60,14 @@ namespace Content.Shared.Pulling .Register(); } + private void OnPullableCollisionChange(EntityUid uid, SharedPullableComponent component, ref CollisionChangeEvent args) + { + if (component.PullJointId != null && !args.CanCollide) + { + _joints.RemoveJoint(uid, component.PullJointId); + } + } + private void OnJointRemoved(EntityUid uid, SharedPullableComponent component, JointRemovedEvent args) { if (component.Puller != args.OtherBody.Owner) diff --git a/Content.Shared/Weapons/Misc/GrapplingProjectileComponent.cs b/Content.Shared/Weapons/Misc/GrapplingProjectileComponent.cs new file mode 100644 index 0000000000..5dcc7702ee --- /dev/null +++ b/Content.Shared/Weapons/Misc/GrapplingProjectileComponent.cs @@ -0,0 +1,9 @@ +using Robust.Shared.GameStates; + +namespace Content.Shared.Weapons.Misc; + +[RegisterComponent, NetworkedComponent] +public sealed class GrapplingProjectileComponent : Component +{ + +} diff --git a/Content.Shared/Weapons/Misc/SharedGrapplingGunSystem.cs b/Content.Shared/Weapons/Misc/SharedGrapplingGunSystem.cs new file mode 100644 index 0000000000..0787c4a28d --- /dev/null +++ b/Content.Shared/Weapons/Misc/SharedGrapplingGunSystem.cs @@ -0,0 +1,230 @@ +using Content.Shared.CombatMode; +using Content.Shared.Hands; +using Content.Shared.Hands.Components; +using Content.Shared.Interaction; +using Content.Shared.Movement.Events; +using Content.Shared.Physics; +using Content.Shared.Projectiles; +using Content.Shared.Timing; +using Content.Shared.Weapons.Ranged.Components; +using Content.Shared.Weapons.Ranged.Systems; +using Robust.Shared.Network; +using Robust.Shared.Physics; +using Robust.Shared.Physics.Components; +using Robust.Shared.Physics.Dynamics.Joints; +using Robust.Shared.Physics.Systems; +using Robust.Shared.Serialization; +using Robust.Shared.Timing; +using Robust.Shared.Utility; + +namespace Content.Shared.Weapons.Misc; + +public abstract class SharedGrapplingGunSystem : EntitySystem +{ + [Dependency] protected readonly IGameTiming Timing = default!; + [Dependency] private readonly INetManager _netManager = default!; + [Dependency] private readonly SharedAppearanceSystem _appearance = default!; + [Dependency] private readonly SharedAudioSystem _audio = default!; + [Dependency] private readonly SharedJointSystem _joints = default!; + [Dependency] private readonly SharedPhysicsSystem _physics = default!; + [Dependency] private readonly UseDelaySystem _delay = default!; + + public const string GrapplingJoint = "grappling"; + + public const float ReelRate = 2.5f; + + public override void Initialize() + { + base.Initialize(); + SubscribeLocalEvent(OnGrappleCollide); + SubscribeLocalEvent(OnWeightlessMove); + SubscribeAllEvent(OnGrapplingReel); + + SubscribeLocalEvent(OnGrapplingShot); + SubscribeLocalEvent(OnGunActivate); + SubscribeLocalEvent(OnGrapplingDeselected); + } + + private void OnGrapplingShot(EntityUid uid, GrapplingGunComponent component, ref GunShotEvent args) + { + foreach (var (shotUid, _) in args.Ammo) + { + if (!HasComp(shotUid)) + continue; + + // At least show the visuals. + component.Projectile = shotUid.Value; + Dirty(component); + var visuals = EnsureComp(shotUid.Value); + visuals.Sprite = + new SpriteSpecifier.Rsi(new ResPath("Objects/Weapons/Guns/Launchers/grappling_gun.rsi"), "rope"); + visuals.OffsetA = new Vector2(0f, 0.5f); + visuals.Target = uid; + Dirty(visuals); + } + + TryComp(uid, out var appearance); + _appearance.SetData(uid, SharedTetherGunSystem.TetherVisualsStatus.Key, false, appearance); + } + + private void OnGrapplingDeselected(EntityUid uid, GrapplingGunComponent component, HandDeselectedEvent args) + { + SetReeling(uid, component, false, args.User); + } + + private void OnGrapplingReel(RequestGrapplingReelMessage msg, EntitySessionEventArgs args) + { + var player = args.SenderSession.AttachedEntity; + if (!TryComp(player, out var hands) || + !TryComp(hands.ActiveHandEntity, out var grappling)) + { + return; + } + + if (msg.Reeling && + (!TryComp(player, out var combatMode) || + !combatMode.IsInCombatMode)) + { + return; + } + + SetReeling(hands.ActiveHandEntity.Value, grappling, msg.Reeling, player.Value); + } + + private void OnWeightlessMove(ref CanWeightlessMoveEvent ev) + { + if (ev.CanMove || !TryComp(ev.Uid, out var relayComp)) + return; + + foreach (var relay in relayComp.Relayed) + { + if (TryComp(relay, out var jointRelay) && jointRelay.GetJoints.ContainsKey(GrapplingJoint)) + { + ev.CanMove = true; + return; + } + } + } + + private void OnGunActivate(EntityUid uid, GrapplingGunComponent component, ActivateInWorldEvent args) + { + if (!Timing.IsFirstTimePredicted || _delay.ActiveDelay(uid)) + return; + + _delay.BeginDelay(uid); + _audio.PlayPredicted(component.CycleSound, uid, args.User); + + TryComp(uid, out var appearance); + _appearance.SetData(uid, SharedTetherGunSystem.TetherVisualsStatus.Key, true, appearance); + SetReeling(uid, component, false, args.User); + + if (!Deleted(component.Projectile)) + { + if (_netManager.IsServer) + { + QueueDel(component.Projectile.Value); + } + + component.Projectile = null; + Dirty(component); + } + } + + private void SetReeling(EntityUid uid, GrapplingGunComponent component, bool value, EntityUid? user) + { + if (component.Reeling == value) + return; + + if (value) + { + if (Timing.IsFirstTimePredicted) + component.Stream = _audio.PlayPredicted(component.ReelSound, uid, user); + } + else + { + if (Timing.IsFirstTimePredicted) + { + component.Stream?.Stop(); + component.Stream = null; + } + } + + component.Reeling = value; + Dirty(component); + } + + public override void Update(float frameTime) + { + base.Update(frameTime); + + var query = EntityQueryEnumerator(); + + while (query.MoveNext(out var uid, out var grappling)) + { + if (!grappling.Reeling) + { + if (Timing.IsFirstTimePredicted) + { + // Just in case. + grappling.Stream?.Stop(); + grappling.Stream = null; + } + + continue; + } + + if (!TryComp(uid, out var jointComp) || + !jointComp.GetJoints.TryGetValue(GrapplingJoint, out var joint) || + joint is not DistanceJoint distance) + { + SetReeling(uid, grappling, false, null); + continue; + } + + // TODO: This should be on engine. + distance.MaxLength = MathF.Max(distance.MinLength, distance.MaxLength - ReelRate * frameTime); + distance.Length = MathF.Min(distance.MaxLength, distance.Length); + + _physics.WakeBody(joint.BodyAUid); + _physics.WakeBody(joint.BodyBUid); + + if (jointComp.Relay != null) + { + _physics.WakeBody(jointComp.Relay.Value); + } + + Dirty(jointComp); + + if (distance.MaxLength.Equals(distance.MinLength)) + { + SetReeling(uid, grappling, false, null); + } + } + } + + private void OnGrappleCollide(EntityUid uid, GrapplingProjectileComponent component, ref ProjectileEmbedEvent args) + { + if (!Timing.IsFirstTimePredicted) + return; + + var jointComp = EnsureComp(uid); + var joint = _joints.CreateDistanceJoint(uid, args.Weapon, anchorA: new Vector2(0f, 0.5f), id: GrapplingJoint); + joint.MaxLength = joint.Length + 0.2f; + joint.Stiffness = 1f; + joint.MinLength = 0.35f; + // Setting velocity directly for mob movement fucks this so need to make them aware of it. + // joint.Breakpoint = 4000f; + Dirty(jointComp); + } + + [Serializable, NetSerializable] + protected sealed class RequestGrapplingReelMessage : EntityEventArgs + { + public bool Reeling; + + public RequestGrapplingReelMessage(bool reeling) + { + Reeling = reeling; + } + } +} diff --git a/Content.Shared/Weapons/Misc/SharedTetherGunSystem.Force.cs b/Content.Shared/Weapons/Misc/SharedTetherGunSystem.Force.cs index 9b5665f1c4..c76d60888c 100644 --- a/Content.Shared/Weapons/Misc/SharedTetherGunSystem.Force.cs +++ b/Content.Shared/Weapons/Misc/SharedTetherGunSystem.Force.cs @@ -43,7 +43,7 @@ public abstract partial class SharedTetherGunSystem { // Pickup if (TryTether(uid, args.Target.Value, args.User, component)) - TransformSystem.SetCoordinates(component.TetherEntity!.Value, new EntityCoordinates(uid, new Vector2(0.0f, -0.8f))); + TransformSystem.SetCoordinates(component.TetherEntity!.Value, new EntityCoordinates(uid, new Vector2(0f, 0f))); } } diff --git a/Content.Shared/Weapons/Ranged/Components/BallisticAmmoProviderComponent.cs b/Content.Shared/Weapons/Ranged/Components/BallisticAmmoProviderComponent.cs index 9c4b9045cc..672d3da5f8 100644 --- a/Content.Shared/Weapons/Ranged/Components/BallisticAmmoProviderComponent.cs +++ b/Content.Shared/Weapons/Ranged/Components/BallisticAmmoProviderComponent.cs @@ -22,6 +22,8 @@ public sealed partial class BallisticAmmoProviderComponent : Component [ViewVariables(VVAccess.ReadWrite), DataField("capacity")] public int Capacity = 30; + public int Count => UnspawnedCount + Container.ContainedEntities.Count; + [ViewVariables(VVAccess.ReadWrite), DataField("unspawnedCount")] [AutoNetworkedField] public int UnspawnedCount; diff --git a/Content.Shared/Weapons/Ranged/Components/GrapplingGunComponent.cs b/Content.Shared/Weapons/Ranged/Components/GrapplingGunComponent.cs new file mode 100644 index 0000000000..51f3e835b7 --- /dev/null +++ b/Content.Shared/Weapons/Ranged/Components/GrapplingGunComponent.cs @@ -0,0 +1,28 @@ +using Robust.Shared.Audio; +using Robust.Shared.GameStates; + +namespace Content.Shared.Weapons.Ranged.Components; + +// I have tried to make this as generic as possible but "delete joint on cycle / right-click reels in" is very specific behavior. +[RegisterComponent, NetworkedComponent, AutoGenerateComponentState] +public sealed partial class GrapplingGunComponent : Component +{ + [DataField("jointId"), AutoNetworkedField] + public string Joint = string.Empty; + + [DataField("projectile")] public EntityUid? Projectile; + + [ViewVariables(VVAccess.ReadWrite), DataField("reeling"), AutoNetworkedField] + public bool Reeling; + + [ViewVariables(VVAccess.ReadWrite), DataField("reelSound"), AutoNetworkedField] + public SoundSpecifier? ReelSound = new SoundPathSpecifier("/Audio/Weapons/reel.ogg") + { + Params = AudioParams.Default.WithLoop(true) + }; + + [ViewVariables(VVAccess.ReadWrite), DataField("cycleSound"), AutoNetworkedField] + public SoundSpecifier? CycleSound = new SoundPathSpecifier("/Audio/Weapons/Guns/MagIn/kinetic_reload.ogg"); + + public IPlayingAudioStream? Stream; +} diff --git a/Content.Shared/Weapons/Ranged/Components/RechargeCycleAmmoComponent.cs b/Content.Shared/Weapons/Ranged/Components/RechargeCycleAmmoComponent.cs new file mode 100644 index 0000000000..70a053e292 --- /dev/null +++ b/Content.Shared/Weapons/Ranged/Components/RechargeCycleAmmoComponent.cs @@ -0,0 +1,12 @@ +using Robust.Shared.GameStates; + +namespace Content.Shared.Weapons.Ranged.Components; + +/// +/// Recharges ammo upon the gun being cycled. +/// +[RegisterComponent, NetworkedComponent] +public sealed class RechargeCycleAmmoComponent : Component +{ + +} diff --git a/Content.Shared/Weapons/Ranged/Events/GunCycledEvent.cs b/Content.Shared/Weapons/Ranged/Events/GunCycledEvent.cs new file mode 100644 index 0000000000..537db0d6e2 --- /dev/null +++ b/Content.Shared/Weapons/Ranged/Events/GunCycledEvent.cs @@ -0,0 +1,7 @@ +namespace Content.Shared.Weapons.Ranged.Events; + +/// +/// Raised directed on a gun when it cycles. +/// +[ByRefEvent] +public readonly record struct GunCycledEvent; diff --git a/Content.Shared/Weapons/Ranged/Systems/RechargeCycleAmmoSystem.cs b/Content.Shared/Weapons/Ranged/Systems/RechargeCycleAmmoSystem.cs new file mode 100644 index 0000000000..136e9b59b2 --- /dev/null +++ b/Content.Shared/Weapons/Ranged/Systems/RechargeCycleAmmoSystem.cs @@ -0,0 +1,31 @@ +using Content.Shared.Interaction; +using Content.Shared.Weapons.Ranged.Components; + +namespace Content.Shared.Weapons.Ranged.Systems; + +/// +/// Recharges ammo whenever the gun is cycled. +/// +public sealed class RechargeCycleAmmoSystem : EntitySystem +{ + [Dependency] private readonly SharedGunSystem _gun = default!; + + public override void Initialize() + { + base.Initialize(); + SubscribeLocalEvent(OnRechargeCycled); + } + + private void OnRechargeCycled(EntityUid uid, RechargeCycleAmmoComponent component, ActivateInWorldEvent args) + { + if (!TryComp(uid, out var basic) || args.Handled) + return; + + if (basic.Count >= basic.Capacity || basic.Count == null) + return; + + _gun.UpdateBasicEntityAmmoCount(uid, basic.Count.Value + 1, basic); + Dirty(basic); + args.Handled = true; + } +} diff --git a/Content.Shared/Weapons/Ranged/Systems/SharedGunSystem.Ballistic.cs b/Content.Shared/Weapons/Ranged/Systems/SharedGunSystem.Ballistic.cs index b529a978fa..abafb4c95f 100644 --- a/Content.Shared/Weapons/Ranged/Systems/SharedGunSystem.Ballistic.cs +++ b/Content.Shared/Weapons/Ranged/Systems/SharedGunSystem.Ballistic.cs @@ -162,7 +162,7 @@ public abstract partial class SharedGunSystem var shots = GetBallisticShots(component); component.Cycled = true; - Cycle(component, coordinates); + Cycle(uid, component, coordinates); var text = Loc.GetString(shots == 0 ? "gun-ballistic-cycled-empty" : "gun-ballistic-cycled"); @@ -171,7 +171,7 @@ public abstract partial class SharedGunSystem UpdateAmmoCount(uid); } - protected abstract void Cycle(BallisticAmmoProviderComponent component, MapCoordinates coordinates); + protected abstract void Cycle(EntityUid uid, BallisticAmmoProviderComponent component, MapCoordinates coordinates); private void OnBallisticInit(EntityUid uid, BallisticAmmoProviderComponent component, ComponentInit args) { diff --git a/Content.Shared/Weapons/Ranged/Systems/SharedGunSystem.cs b/Content.Shared/Weapons/Ranged/Systems/SharedGunSystem.cs index 89068db8ae..22243015f1 100644 --- a/Content.Shared/Weapons/Ranged/Systems/SharedGunSystem.cs +++ b/Content.Shared/Weapons/Ranged/Systems/SharedGunSystem.cs @@ -313,15 +313,16 @@ public abstract partial class SharedGunSystem : EntitySystem } // Shoot confirmed - sounds also played here in case it's invalid (e.g. cartridge already spent). - Shoot(gunUid, gun, ev.Ammo, fromCoordinates, toCoordinates.Value, user, throwItems: attemptEv.ThrowItems); - var shotEv = new GunShotEvent(user); + Shoot(gunUid, gun, ev.Ammo, fromCoordinates, toCoordinates.Value, out var userImpulse, user, throwItems: attemptEv.ThrowItems); + var shotEv = new GunShotEvent(user, ev.Ammo); RaiseLocalEvent(gunUid, ref shotEv); - // Projectiles cause impulses especially important in non gravity environments - if (TryComp(user, out var userPhysics)) + + if (userImpulse && TryComp(user, out var userPhysics)) { if (_gravity.IsWeightless(user, userPhysics)) CauseImpulse(fromCoordinates, toCoordinates.Value, user, userPhysics); } + Dirty(gun); } @@ -331,11 +332,12 @@ public abstract partial class SharedGunSystem : EntitySystem EntityUid ammo, EntityCoordinates fromCoordinates, EntityCoordinates toCoordinates, + out bool userImpulse, EntityUid? user = null, bool throwItems = false) { var shootable = EnsureComp(ammo); - Shoot(gunUid, gun, new List<(EntityUid? Entity, IShootable Shootable)>(1) { (ammo, shootable) }, fromCoordinates, toCoordinates, user, throwItems); + Shoot(gunUid, gun, new List<(EntityUid? Entity, IShootable Shootable)>(1) { (ammo, shootable) }, fromCoordinates, toCoordinates, out userImpulse, user, throwItems); } public abstract void Shoot( @@ -344,6 +346,7 @@ public abstract partial class SharedGunSystem : EntitySystem List<(EntityUid? Entity, IShootable Shootable)> ammo, EntityCoordinates fromCoordinates, EntityCoordinates toCoordinates, + out bool userImpulse, EntityUid? user = null, bool throwItems = false); @@ -436,7 +439,7 @@ public record struct AttemptShootEvent(EntityUid User, string? Message, bool Can /// /// The user that fired this gun. [ByRefEvent] -public record struct GunShotEvent(EntityUid User); +public record struct GunShotEvent(EntityUid User, List<(EntityUid? Uid, IShootable Shootable)> Ammo); public enum EffectLayers : byte { diff --git a/Content.Shared/Wieldable/WieldableSystem.cs b/Content.Shared/Wieldable/WieldableSystem.cs index ea1ac7e42a..61c167fda7 100644 --- a/Content.Shared/Wieldable/WieldableSystem.cs +++ b/Content.Shared/Wieldable/WieldableSystem.cs @@ -9,7 +9,6 @@ using Content.Shared.Popups; using Content.Shared.Verbs; using Content.Shared.Weapons.Melee.Events; using Content.Shared.Weapons.Melee.Components; -using Content.Shared.Weapons.Melee.Events; using Content.Shared.Weapons.Ranged.Components; using Content.Shared.Weapons.Ranged.Systems; using Content.Shared.Wieldable.Components; diff --git a/Resources/Audio/Weapons/Guns/Gunshots/attributions.yml b/Resources/Audio/Weapons/Guns/Gunshots/attributions.yml index 4bbd672461..8bc504ec81 100644 --- a/Resources/Audio/Weapons/Guns/Gunshots/attributions.yml +++ b/Resources/Audio/Weapons/Guns/Gunshots/attributions.yml @@ -2,3 +2,8 @@ license: "CC0-1.0" copyright: "Watering by elittle13. Converted to .OGG and MONO by EmoGarbage404 (github)" source: "https://freesound.org/people/elittle13/sounds/568558" + +- files: ["harpoon.ogg"] + license: "CC0-1.0" + copyright: "grappling hook by 16bitstudios. Converted to .OGG and MONO by metalgearsloth" + source: "https://freesound.org/people/16bitstudios/sounds/541975/" diff --git a/Resources/Audio/Weapons/Guns/Gunshots/harpoon.ogg b/Resources/Audio/Weapons/Guns/Gunshots/harpoon.ogg new file mode 100644 index 0000000000000000000000000000000000000000..11187bac1973a5b29feea2b6e7e27a71a4ed7a38 GIT binary patch literal 7358 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%0ARErVIJfl)9`(j0rwG&?7+!3OCfb=8dOJtqsTB|# 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

;ewve4d|_8fHlY~Z}TiJvR2uU{y`@3yIp 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 literal 0 HcmV?d00001 diff --git a/Resources/Locale/en-US/research/technologies.ftl b/Resources/Locale/en-US/research/technologies.ftl index f64a1c2774..6d56273f60 100644 --- a/Resources/Locale/en-US/research/technologies.ftl +++ b/Resources/Locale/en-US/research/technologies.ftl @@ -34,6 +34,7 @@ research-technology-basic-xenoarcheology = Basic XenoArcheology research-technology-alternative-research = Alternative Research research-technology-magnets-tech = Localized Magnetism research-technology-advanced-parts = Advanced Parts +research-technology-grappling = Grappling research-technology-abnormal-artifact-manipulation = Abnormal Artifact Manipulation research-technology-gravity-manipulation = Gravity Manipulation research-technology-mobile-anomaly-tech = Mobile Anomaly Tech diff --git a/Resources/Prototypes/Entities/Objects/Weapons/Guns/Launchers/launchers.yml b/Resources/Prototypes/Entities/Objects/Weapons/Guns/Launchers/launchers.yml index 3c7f670650..cbf7176bd8 100644 --- a/Resources/Prototypes/Entities/Objects/Weapons/Guns/Launchers/launchers.yml +++ b/Resources/Prototypes/Entities/Objects/Weapons/Guns/Launchers/launchers.yml @@ -214,22 +214,54 @@ map: [ "unshaded" ] shader: unshaded visible: false - - type: ToggleableLightVisuals - spriteLayer: unshaded - inhandVisuals: - left: - - state: inhand-left-unshaded - shader: unshaded - right: - - state: inhand-right-unshaded - shader: unshaded + - type: ToggleableLightVisuals + spriteLayer: unshaded + inhandVisuals: + left: + - state: inhand-left-unshaded + shader: unshaded + right: + - state: inhand-right-unshaded + shader: unshaded + - type: Appearance + - type: GenericVisualizer + visuals: + enum.TetherVisualsStatus.Key: + unshaded: + True: { visible: true } + False: { visible: false } + +- type: entity + name: grappling gun + parent: BaseItem + id: WeaponGrapplingGun + components: + - type: AmmoCounter + - type: GrapplingGun + - type: Gun + soundGunshot: /Audio/Weapons/Guns/Gunshots/harpoon.ogg + fireRate: 0.5 + - type: RechargeCycleAmmo + - type: BasicEntityAmmoProvider + proto: GrapplingHook + capacity: 1 + - type: Sprite + sprite: Objects/Weapons/Guns/Launchers/grappling_gun.rsi + layers: + - state: base + - state: base-unshaded + map: [ "unshaded" ] + shader: unshaded + visible: true + - type: UseDelay + delay: 1.5 - type: Appearance - type: GenericVisualizer visuals: enum.TetherVisualsStatus.Key: unshaded: - True: { visible: true } - False: { visible: false } + True: { state: base-unshaded } + False: { state: base-unshaded-off } # Admeme - type: entity diff --git a/Resources/Prototypes/Entities/Objects/Weapons/Guns/Projectiles/projectiles.yml b/Resources/Prototypes/Entities/Objects/Weapons/Guns/Projectiles/projectiles.yml index f59153f320..705da6a081 100644 --- a/Resources/Prototypes/Entities/Objects/Weapons/Guns/Projectiles/projectiles.yml +++ b/Resources/Prototypes/Entities/Objects/Weapons/Guns/Projectiles/projectiles.yml @@ -670,3 +670,38 @@ radius: 1 color: orange energy: 0.5 + +- type: entity + id: GrapplingHook + name: grappling hook + noSpawn: true + components: + - type: EmbeddableProjectile + - type: Clickable + - type: Sprite + noRot: false + sprite: Objects/Weapons/Guns/Launchers/grappling_gun.rsi + layers: + - state: hook + - state: hook-unshaded + shader: unshaded + - type: Physics + bodyType: Dynamic + linearDamping: 0 + angularDamping: 0 + - type: Projectile + deleteOnCollide: false + damage: + types: + Blunt: 0 + - type: Fixtures + fixtures: + projectile: + shape: + !type:PhysShapeAabb + bounds: "-0.1,-0.1,0.1,0.1" + hard: false + mask: + - Impassable + - HighImpassable + - type: GrapplingProjectile diff --git a/Resources/Prototypes/Entities/Structures/Machines/lathe.yml b/Resources/Prototypes/Entities/Structures/Machines/lathe.yml index 5641613d26..8b6e150e4c 100644 --- a/Resources/Prototypes/Entities/Structures/Machines/lathe.yml +++ b/Resources/Prototypes/Entities/Structures/Machines/lathe.yml @@ -243,6 +243,7 @@ - HolofanProjector - WeaponForceGun - WeaponTetherGun + - WeaponGrapplingGun - ClothingBackpackHolding - ClothingBackpackSatchelHolding - ClothingBackpackDuffelHolding diff --git a/Resources/Prototypes/Recipes/Lathes/devices.yml b/Resources/Prototypes/Recipes/Lathes/devices.yml index baa9e8e001..95d0e3086a 100644 --- a/Resources/Prototypes/Recipes/Lathes/devices.yml +++ b/Resources/Prototypes/Recipes/Lathes/devices.yml @@ -120,3 +120,12 @@ Steel: 500 Glass: 400 Silver: 100 + +- type: latheRecipe + id: WeaponGrapplingGun + result: WeaponGrapplingGun + completetime: 5 + materials: + Steel: 500 + Glass: 400 + Gold: 100 diff --git a/Resources/Prototypes/Research/experimental.yml b/Resources/Prototypes/Research/experimental.yml index c2e96fd0a7..2043bc2648 100644 --- a/Resources/Prototypes/Research/experimental.yml +++ b/Resources/Prototypes/Research/experimental.yml @@ -145,6 +145,18 @@ recipeUnlocks: - RPED +- type: technology + id: Grappling + name: research-technology-grappling + icon: + sprite: Objects/Weapons/Guns/Launchers/grappling_gun.rsi + state: base + discipline: Experimental + tier: 2 + cost: 5000 + recipeUnlocks: + - WeaponGrapplingGun + # Tier 3 - type: technology diff --git a/Resources/Textures/Objects/Weapons/Guns/Launchers/grappling_gun.rsi/base-unshaded-off.png b/Resources/Textures/Objects/Weapons/Guns/Launchers/grappling_gun.rsi/base-unshaded-off.png new file mode 100644 index 0000000000000000000000000000000000000000..ed7f70c53d4d77bdc2213ce8451c3c4a9b9d0447 GIT binary patch literal 5413 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 literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Weapons/Guns/Launchers/grappling_gun.rsi/base-unshaded.png b/Resources/Textures/Objects/Weapons/Guns/Launchers/grappling_gun.rsi/base-unshaded.png new file mode 100644 index 0000000000000000000000000000000000000000..70be300e8fa0cc299fd9deb5e4be52bdcd506fee GIT binary patch literal 5087 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 HJtpHHzb?D| literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Weapons/Guns/Launchers/grappling_gun.rsi/base.png b/Resources/Textures/Objects/Weapons/Guns/Launchers/grappling_gun.rsi/base.png new file mode 100644 index 0000000000000000000000000000000000000000..f3019b187b73408d7ee76a522b7871f7506efada GIT binary patch literal 6807 zcmeHKc{r5q_aCxlCrhM^5!uFUmYK1yku2GT7_%A6%$OOBEkfC~B3rT*g+f%8R0^fY zS`jUX6pEBKeIM%W?Y(~Af8Oi*egA7_o|$>hea`2c^Ev0fuk)lh*zFYJm*oe6Ktk45 z=8nKGcNR%KVm=!@Mf{APj2?Sz~%;k78Ze0wfLrw>iU!R@FC~ zT6}JBcRx;IsEWRq-|g?kN0v_2ob-R<)}v77xmozr9s3JD7NynaI^?BeOr}Do_Mg&S z@VAJCZKT=RU3k|SF)=x3!k(KjT9E6GnQH5~Tzsg~k~aSE`*{5uJj(UbNqT5gM&xdc zTh;5JVo&LWfIFns_~hu!yL*ynO;mR41x;_R!HRf|TIhN+N2^i7x(!wZVzra>RBSH-@1(bG62%nVb1qrcUr)$F96$=mMsuOAM!YD*T> zPfe-6U))!iA)8uo%7X_&eQK9A@obv?UA2aT%c8YP)iETf&72h?zgtxJ!GVJ}*;A*x zm!#s-9_@AL;1&gGOW#r=*MEGBk@Emm6gP?Vg^SW5`%B6WPYOOdVjXl}{c&OWKK+41 z5nY1Yx0fBcaY$oB)#igMcWOn=Y~#(vtdEsjWo4VDT08E-sH!%~F|<4wcQH9$O!eYh z5Tz`yU6ti7J{!tZwTHZHsvERF1X)pA#@rw5{b=z1(e3wxOjzp&9lj#5q;#!CmC{U| zZ-SdvPf}ibkP3sZTBuZCA(Usid4x9DR?PW^J*gY$X@1i*D$uZHnAQn%VCn{}g3AS# z1hh%a{pRTMO?&Qv?&Z%I>#K8dU2?k@6oQDfutU^KeinGK$5EpGl>|aGy*uLZ{EeO! zfjt)U^3O?(ukrcco4aHV&gXQ+bk6M~i1NzJ#Zl z-_znv zWHa@CkfjGh)nRXi(!Iv>U)U(#{N^Bg2c4&$JI`mm5vdcrX-KH8xt(=<$7*CIPS7;G z^RYwKPJf+)d!orry+@K~kt0^(ZV3v+*hn0&y$0{o*MgtX_qJAl?zoIRED%M5_LvUk zsTe4YZZr56x2KKId0ewFz*yd$o#KMeRXpnd^e!VbU9ob{LT7TGyhdN8WD^Rn81Yy} z>Av=Zyg|xJWzAMPhekb4jLqGED9N%7D+!c;7`6G9iwfxrr2nRDVB=>6m#~j&&tU@E zMdkaYu^V|pWX@jAs&lST>6U^~njbWeq2^~1w0s?eWPB~Q&#gDZoThh>N2n&NvmzeP zl-jD|nX?dB%ik)hf-M*kIq_j7i+cs0s6$uPdgbW~>pZ;i#jP6NNw3@tH>=x0d?z=_ z3P+?pP~j#{_)F@V6bw-FYjPf`@|M(w-l@0Vc{+;AZzN^1@%w?6ZdWtBltNEtiUmUe z)&ALWn7Unx5TNh?P3}`f0nsy}BT<+%0aiTBVr z&kl*sa<}6818Vd9da5O?hDqgv7L2fv%uB~scxuT|W0@8aF$W31AovX_Zj*NJ!lz~d z?iixRfc+zsP2`0W60cFkTOy$v$Cigs6Y57BUmrwVt&SFJ52X!e&q4>-1zcuJuH+1F z@9e^KP_AfAb=$m4_-G0CRpv!Y&(hkYVVi1)hgPZbawmHZkL&I(6l%R`6B=>fv)@rmaUiaHdQwK9Hr%#UUrs&5DB%!=o+nf9dRb)z-%cfG zMr#a)6qM+;Sjj0gQLmp$tkO=V7vU=!n_Q z=AkBvlS66M%el9OJh_&9pHm3_+w}^iw)Gc@R9;W2JWv~rzSQsUWxAt>a{Y`ekIBbo z0VxQ$_+SfNthb`z#mq2a03Ueym zs>R%DjPHi}X0-Mv?6^eQ$S_fhDDjQYGsIUok3^&QL}BDKgbZvRoo(t+l!ZwO#e9x( z_s=LhS=Lb1p>*cN;Hwcq#m@v;7r7FySbXUQZoJm{t@28ydYpCVuX;ocEmjK${< zO~-DWQVUZ%Hm&ITbU0t-;Gu8)=%iJXQ-ao{fZVeS*TQA;^gj@EcWrkL>5OPUTW9s6 zePBeSD%xl%`pB{>Pk?=R6sXzuO@+Fc%LhMAZ4GJvnCqCpY3u61t(mb{aYI3D5roh2 za+hr0oSwM!9!1npuDXK#@iOluez%)5?6POJDii&mT$El}4st~z{k^8Q4O{0mIKU#e z_Vi)UPp6Agvegz1--X2HZb5MIt(@eQ;+qu~GG@y~e9F(9yKM!_Y*Vk#7RY)XIMH6Q zZP#E}?{i$=OE5aPwCgf1A17M(0YZ4Poon-#o|#uyd@r2SEQ3^KhDgba@jrlNf$B8$ z&%IZsdK|Y$I`w>Yl8n{c=Q3DPBSt+tI@mLdTg8vtIo}OzeE@4&?%T_>R)iW2%52cL zi%{+s!i1tLnR(^Uiu`%zkd<4$X=;lb^}RyneN1W7TlINRl!4oF&F}mt*b(Dwe9nWG zZy*pyBE`(i!P?C1ugL_MM+#z&8d$X(%iZ>IvawK$4-*aHb1c+IPDSsMO!F* zN30~t#UArQUcKu(>255kw!KqimA9=~Tfpf!)lr3qYhTb8yaeAo=l!POSozVgC9bzd z8{GDe`UHdOi^?93?w#bD8RgNe8O>|q^_mAI*f$ZZGAGZfO7LI*A`{~zy!i@udeqnk-MCXyJy7I(|`$bGXX@zh2}O0m_jgsxM|zMZRuu2e~MKkgXk1# z=ZudG#A65$BSU_DHWmN~CbDo~c5o1tiDer=)^V}G|1~iT0$x{P1sXuyZ5_a7GzJl@ zrKzO}hgz^HVMvG}KUkkZAYmQNEq_7)cLorD7K@IB!NSACHN#PwGzJ-lz+f;iI1+|L zLIDjZGlI&(v7uC^;u^#c409qA&!Es*6dD!0hKci|g|ZAF5MUkrSA4;ATiajoROU|> z06t)B936(xgu{Y^VZU22Sr%ac$j^ZOs|C{;7`S1ML?$hifhSso5veT2-ysP2U-tA+ zM$mdX1U!rwL<|O0nSfWsKV0s#wsrVru|@%z5=>vW0?7V{CW}J)o2-AtwzjgK&hLQ$ z=D%?Nq5W6x>&k$Ztu5A^h7Vl}&)VDovgRL4py4S5?D}6kS_g^HMfpK>FeF{576wUx zqT$*^C<%o`V@TR49LA6E8;Vdu zKnrL7z2r;@COWZjYkVSf&{|puEnQtS91VvfwEtFeB{G;mFRq~?;F?JE`pQ~ius}Kh zwYarT1pwCNKsH!21`)@iF`Q|%AOpx+P~bJo^#%v)|0s(Ug$Zaxto8iQu6H7a{J8tE z34$o=OJMMN<6?36A5NIKFyfDz0Cqo?@cuX|nF#FgpDp#5obq4Fh1Wvr0#!voF?byW zR0~f;LHz*Mp$I>1BuWRaLxOAnAnq4BlSX2N;}}E}GLR{d4bVdC*??7klBv3$_AmW# zf8rWba3l%}*M=g{&PXIy8-qomA+Vpx!q)cmU)k!z{tqAe>k7Xe0)X8Q8F07&XBF(% zVfB+Q!1w?1^|KEDOBZ19A1D8c-#>Kyq3d5U@UN8rbk`rc{uKlNO8HNB{lC%0|M%k# zkqS&e;lRVpr^STrz=IHvpUqBl(D$|X>DIHy0m(+Xl?M|964ezi3T*R_Wjz>2J<&ASsd^DIghH*?Q@vnyL86jH8-(rFZ49ZH2%7`+l3;ePJDA zZ_3^+I4}C%A$-7(=hLozyw54={I>1+?3{9B-inPh^t9bkdrAAA(ra?B_D0`s+^@n) z;xtBnO6hH`nhZ@%w;YO9$bB^2h*mIz)F!U3a(EWln2!(ATT00vPl_uT#&y&mJ&PpmsYD^#ERy=FG$@9La|E(#{ohZU_gH6~0} zG{0Xc?{{d%7MJ(;$aWD~oN=kCfu5t{skJ>h@!7jJfCg)N7Ip3sS&rY9qv1QaxW9Ou>>6e5a~g zNjm$})Ii1OJq=AMuO9|*fPC5(CVH#4JURENilfLg{v$)1^M>p0`}d9&TfwT2>Yq%5 ziF@+QO2`x+y%?PHIrD~mU_k>6ZVD1!^s?OX=Bo#(VOdB*`0$EYb84%%u!d%lHv8-o z5-eQgU?Ao7mKlNY4WP!bj}i8{r;;5R*|YDT0&;muGN;auo4M+A5d&RE#nw tDEzut^w9#(>lEMRwg?GHX9tc|&fWDM-LH0Kk%6WMSzFkd*O>ao{|C-!`ab{w literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Weapons/Guns/Launchers/grappling_gun.rsi/hook-unshaded.png b/Resources/Textures/Objects/Weapons/Guns/Launchers/grappling_gun.rsi/hook-unshaded.png new file mode 100644 index 0000000000000000000000000000000000000000..91cdd1d075803603eb02d6bd015d27233b662d46 GIT binary patch literal 5191 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 OM3ICo6(0&s$^S1B29PKK literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Weapons/Guns/Launchers/grappling_gun.rsi/hook.png b/Resources/Textures/Objects/Weapons/Guns/Launchers/grappling_gun.rsi/hook.png new file mode 100644 index 0000000000000000000000000000000000000000..d58cf6559c0763031f42240ba332267c9b07e2f1 GIT binary patch literal 5891 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 CC690b literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Weapons/Guns/Launchers/grappling_gun.rsi/inhand-right-unshaded.png b/Resources/Textures/Objects/Weapons/Guns/Launchers/grappling_gun.rsi/inhand-right-unshaded.png new file mode 100644 index 0000000000000000000000000000000000000000..fd20f4db5a29f71316d43587f8de523d95d80572 GIT binary patch literal 5675 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 literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Weapons/Guns/Launchers/grappling_gun.rsi/inhand-right.png b/Resources/Textures/Objects/Weapons/Guns/Launchers/grappling_gun.rsi/inhand-right.png new file mode 100644 index 0000000000000000000000000000000000000000..af27ad1ecb49082259736eec61acd541edf33d4f GIT binary patch literal 8878 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 literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Weapons/Guns/Launchers/grappling_gun.rsi/meta.json b/Resources/Textures/Objects/Weapons/Guns/Launchers/grappling_gun.rsi/meta.json new file mode 100644 index 0000000000..a6d927a54e --- /dev/null +++ b/Resources/Textures/Objects/Weapons/Guns/Launchers/grappling_gun.rsi/meta.json @@ -0,0 +1,45 @@ +{ + "version": 1, + "license": "CC-BY-SA-3.0", + "copyright": "Sprited by discord Kheprep#7153", + "size": { + "x": 32, + "y": 32 + }, + "states": [ + { + "name": "base" + }, + { + "name": "base-unshaded" + }, + { + "name": "base-unshaded-off" + }, + { + "name": "inhand-left", + "directions": 4 + }, + { + "name": "inhand-right", + "directions": 4 + }, + { + "name": "inhand-left-unshaded", + "directions": 4 + }, + { + "name": "inhand-right-unshaded", + "directions": 4 + }, + { + "name": "rope" + }, + { + "name": "hook" + }, + { + "name": "hook-unshaded" + } + ] +} \ No newline at end of file diff --git a/Resources/Textures/Objects/Weapons/Guns/Launchers/grappling_gun.rsi/rope.png b/Resources/Textures/Objects/Weapons/Guns/Launchers/grappling_gun.rsi/rope.png new file mode 100644 index 0000000000000000000000000000000000000000..dd1893fcd14f24da1cc0ad7bbbe645774805c15d GIT binary patch literal 5403 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