From: metalgearsloth <31366439+metalgearsloth@users.noreply.github.com> Date: Fri, 19 May 2023 07:10:31 +0000 (+1000) Subject: Adds force-gun (#16561) X-Git-Url: https://git.smokeofanarchy.ru/gitweb.cgi?a=commitdiff_plain;h=4efb41aa587f57d501f6a2dd16bc1257020b421a;p=space-station-14.git Adds force-gun (#16561) --- diff --git a/Content.Client/Weapons/Misc/TetherGunOverlay.cs b/Content.Client/Weapons/Misc/TetherGunOverlay.cs index 215589c38d..142d9da823 100644 --- a/Content.Client/Weapons/Misc/TetherGunOverlay.cs +++ b/Content.Client/Weapons/Misc/TetherGunOverlay.cs @@ -19,6 +19,8 @@ public sealed class TetherGunOverlay : Overlay { var query = _entManager.EntityQueryEnumerator(); var xformQuery = _entManager.GetEntityQuery(); + var tetherQuery = _entManager.GetEntityQuery(); + var forceQuery = _entManager.GetEntityQuery(); var worldHandle = args.WorldHandle; var xformSystem = _entManager.System(); @@ -46,7 +48,18 @@ public sealed class TetherGunOverlay : Overlay var box = new Box2(-Width, -length, Width, length); var rotated = new Box2Rotated(box.Translated(midPoint), angle, midPoint); - worldHandle.DrawRect(rotated, Color.Orange.WithAlpha(0.3f)); + var color = Color.Red; + + if (forceQuery.TryGetComponent(tethered.Tetherer, out var force)) + { + color = force.LineColor; + } + else if (tetherQuery.TryGetComponent(tethered.Tetherer, out var tether)) + { + color = tether.LineColor; + } + + worldHandle.DrawRect(rotated, color.WithAlpha(0.3f)); } } } diff --git a/Content.Client/Weapons/Misc/TetherGunSystem.cs b/Content.Client/Weapons/Misc/TetherGunSystem.cs index 1219fe1357..9ceda9291d 100644 --- a/Content.Client/Weapons/Misc/TetherGunSystem.cs +++ b/Content.Client/Weapons/Misc/TetherGunSystem.cs @@ -22,16 +22,26 @@ public sealed class TetherGunSystem : SharedTetherGunSystem base.Initialize(); SubscribeLocalEvent(OnTetheredStartup); SubscribeLocalEvent(OnTetheredShutdown); + SubscribeLocalEvent(OnAfterState); + SubscribeLocalEvent(OnAfterState); _overlay.AddOverlay(new TetherGunOverlay(EntityManager)); } + private void OnAfterState(EntityUid uid, BaseForceGunComponent component, ref AfterAutoHandleStateEvent args) + { + if (!TryComp(component.Tethered, out var sprite)) + return; + + sprite.Color = component.LineColor; + } + public override void Shutdown() { base.Shutdown(); _overlay.RemoveOverlay(); } - protected override bool CanTether(EntityUid uid, TetherGunComponent component, EntityUid target, EntityUid? user) + protected override bool CanTether(EntityUid uid, BaseForceGunComponent component, EntityUid target, EntityUid? user) { // Need powercells predicted sadly :< return false; @@ -88,9 +98,18 @@ public sealed class TetherGunSystem : SharedTetherGunSystem private void OnTetheredStartup(EntityUid uid, TetheredComponent component, ComponentStartup args) { if (!TryComp(uid, out var sprite)) + { return; + } - sprite.Color = Color.Orange; + if (TryComp(component.Tetherer, out var force)) + { + sprite.Color = force.LineColor; + } + else if (TryComp(component.Tetherer, out var tether)) + { + sprite.Color = tether.LineColor; + } } private void OnTetheredShutdown(EntityUid uid, TetheredComponent component, ComponentShutdown args) diff --git a/Content.Server/Weapons/Misc/TetherGunSystem.cs b/Content.Server/Weapons/Misc/TetherGunSystem.cs index 3b62e3f8ca..44d0c49e3f 100644 --- a/Content.Server/Weapons/Misc/TetherGunSystem.cs +++ b/Content.Server/Weapons/Misc/TetherGunSystem.cs @@ -1,5 +1,4 @@ using Content.Server.PowerCell; -using Content.Shared.PowerCell.Components; using Content.Shared.Weapons.Misc; using Robust.Shared.Physics.Components; @@ -13,14 +12,15 @@ public sealed class TetherGunSystem : SharedTetherGunSystem { base.Initialize(); SubscribeLocalEvent(OnGunEmpty); + SubscribeLocalEvent(OnGunEmpty); } - private void OnGunEmpty(EntityUid uid, TetherGunComponent component, ref PowerCellSlotEmptyEvent args) + private void OnGunEmpty(EntityUid uid, BaseForceGunComponent component, ref PowerCellSlotEmptyEvent args) { StopTether(uid, component); } - protected override bool CanTether(EntityUid uid, TetherGunComponent component, EntityUid target, EntityUid? user) + protected override bool CanTether(EntityUid uid, BaseForceGunComponent component, EntityUid target, EntityUid? user) { if (!base.CanTether(uid, component, target, user)) return false; @@ -31,16 +31,16 @@ public sealed class TetherGunSystem : SharedTetherGunSystem return true; } - protected override void StartTether(EntityUid gunUid, TetherGunComponent component, EntityUid target, EntityUid? user, + protected override void StartTether(EntityUid gunUid, BaseForceGunComponent component, EntityUid target, EntityUid? user, PhysicsComponent? targetPhysics = null, TransformComponent? targetXform = null) { base.StartTether(gunUid, component, target, user, targetPhysics, targetXform); _cell.SetPowerCellDrawEnabled(gunUid, true); } - protected override void StopTether(EntityUid gunUid, TetherGunComponent component, bool transfer = false) + protected override void StopTether(EntityUid gunUid, BaseForceGunComponent component, bool land = true, bool transfer = false) { - base.StopTether(gunUid, component, transfer); + base.StopTether(gunUid, component, land, transfer); _cell.SetPowerCellDrawEnabled(gunUid, false); } } diff --git a/Content.Shared/Sound/SharedEmitSoundSystem.cs b/Content.Shared/Sound/SharedEmitSoundSystem.cs index 3dc1cb793f..a2fa038101 100644 --- a/Content.Shared/Sound/SharedEmitSoundSystem.cs +++ b/Content.Shared/Sound/SharedEmitSoundSystem.cs @@ -51,9 +51,12 @@ public abstract class SharedEmitSoundSystem : EntitySystem private void OnEmitSoundOnLand(EntityUid uid, BaseEmitSoundComponent component, ref LandEvent args) { - if (!TryComp(uid, out var xform) || + if (!args.PlaySound || + !TryComp(uid, out var xform) || !_mapManager.TryGetGrid(xform.GridUid, out var grid)) + { return; + } var tile = grid.GetTileRef(xform.Coordinates); diff --git a/Content.Shared/Throwing/LandEvent.cs b/Content.Shared/Throwing/LandEvent.cs index def0278816..1bf1f20371 100644 --- a/Content.Shared/Throwing/LandEvent.cs +++ b/Content.Shared/Throwing/LandEvent.cs @@ -6,7 +6,7 @@ namespace Content.Shared.Throwing /// Raised when an entity that was thrown lands. This occurs before they stop moving and is when their tile-friction is reapplied. /// [ByRefEvent] - public readonly record struct LandEvent(EntityUid? User); + public readonly record struct LandEvent(EntityUid? User, bool PlaySound); /// /// Raised when a thrown entity is no longer moving. diff --git a/Content.Shared/Throwing/ThrowingSystem.cs b/Content.Shared/Throwing/ThrowingSystem.cs index 44cfdc33fb..4368dac6b7 100644 --- a/Content.Shared/Throwing/ThrowingSystem.cs +++ b/Content.Shared/Throwing/ThrowingSystem.cs @@ -3,6 +3,7 @@ using Content.Shared.Interaction; using Content.Shared.Movement.Components; using Content.Shared.Projectiles; using Content.Shared.Tag; +using Robust.Shared.Map; using Robust.Shared.Physics; using Robust.Shared.Physics.Components; using Robust.Shared.Physics.Systems; @@ -25,9 +26,27 @@ public sealed class ThrowingSystem : EntitySystem [Dependency] private readonly SharedGravitySystem _gravity = default!; [Dependency] private readonly SharedInteractionSystem _interactionSystem = default!; [Dependency] private readonly SharedPhysicsSystem _physics = default!; + [Dependency] private readonly SharedTransformSystem _transform = default!; [Dependency] private readonly ThrownItemSystem _thrownSystem = default!; [Dependency] private readonly TagSystem _tagSystem = default!; + public void TryThrow( + EntityUid uid, + EntityCoordinates coordinates, + float strength = 1.0f, + EntityUid? user = null, + float pushbackRatio = PushbackDefault, + bool playSound = true) + { + var thrownPos = Transform(uid).MapPosition; + var mapPos = coordinates.ToMap(EntityManager, _transform); + + if (mapPos.MapId != thrownPos.MapId) + return; + + TryThrow(uid, mapPos.Position - thrownPos.Position, strength, user, pushbackRatio, playSound); + } + /// /// Tries to throw the entity if it has a physics component, otherwise does nothing. /// @@ -39,7 +58,8 @@ public sealed class ThrowingSystem : EntitySystem Vector2 direction, float strength = 1.0f, EntityUid? user = null, - float pushbackRatio = PushbackDefault) + float pushbackRatio = PushbackDefault, + bool playSound = true) { var physicsQuery = GetEntityQuery(); if (!physicsQuery.TryGetComponent(uid, out var physics)) @@ -57,7 +77,8 @@ public sealed class ThrowingSystem : EntitySystem tagQuery, strength, user, - pushbackRatio); + pushbackRatio, + playSound); } /// @@ -75,7 +96,8 @@ public sealed class ThrowingSystem : EntitySystem EntityQuery tagQuery, float strength = 1.0f, EntityUid? user = null, - float pushbackRatio = PushbackDefault) + float pushbackRatio = PushbackDefault, + bool playSound = true) { if (strength <= 0 || direction == Vector2.Infinity || direction == Vector2.NaN || direction == Vector2.Zero) return; @@ -105,11 +127,11 @@ public sealed class ThrowingSystem : EntitySystem _physics.ApplyLinearImpulse(uid, impulseVector, body: physics); // Estimate time to arrival so we can apply OnGround status and slow it much faster. - var time = (direction / strength).Length; + var time = direction.Length / strength; if (time < FlyTime) { - _thrownSystem.LandComponent(uid, comp, physics); + _thrownSystem.LandComponent(uid, comp, physics, playSound); } else { @@ -120,7 +142,7 @@ public sealed class ThrowingSystem : EntitySystem if (physics.Deleted) return; - _thrownSystem.LandComponent(uid, comp, physics); + _thrownSystem.LandComponent(uid, comp, physics, playSound); }); } diff --git a/Content.Shared/Throwing/ThrownItemSystem.cs b/Content.Shared/Throwing/ThrownItemSystem.cs index 6467ea2d77..39e357a32c 100644 --- a/Content.Shared/Throwing/ThrownItemSystem.cs +++ b/Content.Shared/Throwing/ThrownItemSystem.cs @@ -116,7 +116,7 @@ namespace Content.Shared.Throwing EntityManager.RemoveComponent(uid); } - public void LandComponent(EntityUid uid, ThrownItemComponent thrownItem, PhysicsComponent physics) + public void LandComponent(EntityUid uid, ThrownItemComponent thrownItem, PhysicsComponent physics, bool playSound) { _physics.SetBodyStatus(physics, BodyStatus.OnGround); @@ -138,7 +138,7 @@ namespace Content.Shared.Throwing _adminLogger.Add(LogType.Landed, LogImpact.Low, $"{ToPrettyString(landing):entity} thrown by {ToPrettyString(thrownItem.Thrower.Value):thrower} landed."); _broadphase.RegenerateContacts(physics); - var landEvent = new LandEvent(thrownItem.Thrower); + var landEvent = new LandEvent(thrownItem.Thrower, playSound); RaiseLocalEvent(landing, ref landEvent); } diff --git a/Content.Shared/Weapons/Misc/BaseForceGunComponent.cs b/Content.Shared/Weapons/Misc/BaseForceGunComponent.cs new file mode 100644 index 0000000000..45c81fa3f1 --- /dev/null +++ b/Content.Shared/Weapons/Misc/BaseForceGunComponent.cs @@ -0,0 +1,56 @@ +using Robust.Shared.Audio; + +namespace Content.Shared.Weapons.Misc; + +public abstract class BaseForceGunComponent : Component +{ + [ViewVariables(VVAccess.ReadWrite), DataField("lineColor"), AutoNetworkedField] + public Color LineColor = Color.Orange; + + /// + /// The entity the tethered target has a joint to. + /// + [DataField("tetherEntity"), AutoNetworkedField] + public EntityUid? TetherEntity; + + /// + /// The entity currently tethered. + /// + [ViewVariables(VVAccess.ReadWrite), DataField("tethered"), AutoNetworkedField] + public virtual EntityUid? Tethered { get; set; } + + /// + /// Can the tethergun unanchor entities. + /// + [ViewVariables(VVAccess.ReadWrite), DataField("canUnanchor"), AutoNetworkedField] + public bool CanUnanchor = false; + + [ViewVariables(VVAccess.ReadWrite), DataField("canTetherAlive"), AutoNetworkedField] + public bool CanTetherAlive = false; + + /// + /// Max force between the tether entity and the tethered target. + /// + [ViewVariables(VVAccess.ReadWrite), DataField("maxForce"), AutoNetworkedField] + public float MaxForce = 200f; + + [ViewVariables(VVAccess.ReadWrite), DataField("frequency"), AutoNetworkedField] + public float Frequency = 10f; + + [ViewVariables(VVAccess.ReadWrite), DataField("dampingRatio"), AutoNetworkedField] + public float DampingRatio = 2f; + + /// + /// Maximum amount of mass a tethered entity can have. + /// + [ViewVariables(VVAccess.ReadWrite), DataField("massLimit"), AutoNetworkedField] + public float MassLimit = 100f; + + [ViewVariables(VVAccess.ReadWrite), DataField("sound"), AutoNetworkedField] + public SoundSpecifier? Sound = new SoundPathSpecifier("/Audio/Weapons/weoweo.ogg") + { + Params = AudioParams.Default.WithLoop(true).WithVolume(-8f), + }; + + public IPlayingAudioStream? Stream; +} diff --git a/Content.Shared/Weapons/Misc/ForceGunComponent.cs b/Content.Shared/Weapons/Misc/ForceGunComponent.cs new file mode 100644 index 0000000000..f3aca0d4d0 --- /dev/null +++ b/Content.Shared/Weapons/Misc/ForceGunComponent.cs @@ -0,0 +1,29 @@ +using Robust.Shared.Audio; +using Robust.Shared.GameStates; + +namespace Content.Shared.Weapons.Misc; + +[RegisterComponent, NetworkedComponent, AutoGenerateComponentState(true)] +public sealed partial class ForceGunComponent : BaseForceGunComponent +{ + /// + /// Maximum distance to throw entities. + /// + [ViewVariables(VVAccess.ReadWrite), DataField("throwDistance"), AutoNetworkedField] + public float ThrowDistance = 15f; + + [ViewVariables(VVAccess.ReadWrite), DataField("throwForce"), AutoNetworkedField] + public float ThrowForce = 30f; + + /// + /// The entity currently tethered. + /// + [ViewVariables(VVAccess.ReadWrite), DataField("tethered"), AutoNetworkedField] + public override EntityUid? Tethered { get; set; } + + [ViewVariables(VVAccess.ReadWrite), DataField("soundLaunch")] + public SoundSpecifier? LaunchSound = new SoundPathSpecifier("/Audio/Weapons/soup.ogg") + { + Params = AudioParams.Default.WithVolume(5f), + }; +} diff --git a/Content.Shared/Weapons/Misc/SharedTetherGunSystem.Force.cs b/Content.Shared/Weapons/Misc/SharedTetherGunSystem.Force.cs new file mode 100644 index 0000000000..9b5665f1c4 --- /dev/null +++ b/Content.Shared/Weapons/Misc/SharedTetherGunSystem.Force.cs @@ -0,0 +1,54 @@ +using Content.Shared.Interaction; +using Robust.Shared.Map; + +namespace Content.Shared.Weapons.Misc; + +public abstract partial class SharedTetherGunSystem +{ + private void InitializeForce() + { + SubscribeLocalEvent(OnForceRanged); + SubscribeLocalEvent(OnForceActivate); + } + + private void OnForceActivate(EntityUid uid, ForceGunComponent component, ActivateInWorldEvent args) + { + StopTether(uid, component); + } + + private void OnForceRanged(EntityUid uid, ForceGunComponent component, AfterInteractEvent args) + { + if (IsTethered(component)) + { + if (!args.ClickLocation.TryDistance(EntityManager, TransformSystem, Transform(uid).Coordinates, + out var distance) || + distance > component.ThrowDistance) + { + return; + } + + // URGH, soon + // Need auto states to be nicer + powercelldraw to be nicer + if (!_netManager.IsServer) + return; + + // Launch + var tethered = component.Tethered; + StopTether(uid, component, land: false); + _throwing.TryThrow(tethered!.Value, args.ClickLocation, component.ThrowForce, playSound: false); + + _audio.PlayPredicted(component.LaunchSound, uid, null); + } + else if (args.Target != null) + { + // Pickup + if (TryTether(uid, args.Target.Value, args.User, component)) + TransformSystem.SetCoordinates(component.TetherEntity!.Value, new EntityCoordinates(uid, new Vector2(0.0f, -0.8f))); + } + } + + private bool IsTethered(ForceGunComponent component) + { + return component.Tethered != null; + } +} diff --git a/Content.Shared/Weapons/Misc/SharedTetherGunSystem.cs b/Content.Shared/Weapons/Misc/SharedTetherGunSystem.cs index f6d65c862d..1e4e890224 100644 --- a/Content.Shared/Weapons/Misc/SharedTetherGunSystem.cs +++ b/Content.Shared/Weapons/Misc/SharedTetherGunSystem.cs @@ -7,6 +7,7 @@ using Content.Shared.Mobs.Systems; using Content.Shared.Movement.Events; using Content.Shared.Throwing; using Content.Shared.Toggleable; +using Robust.Shared.Containers; using Robust.Shared.Map; using Robust.Shared.Network; using Robust.Shared.Physics; @@ -16,16 +17,18 @@ using Robust.Shared.Serialization; namespace Content.Shared.Weapons.Misc; -public abstract class SharedTetherGunSystem : EntitySystem +public abstract partial class SharedTetherGunSystem : EntitySystem { [Dependency] private readonly INetManager _netManager = default!; [Dependency] private readonly ActionBlockerSystem _blocker = default!; [Dependency] private readonly MobStateSystem _mob = default!; - [Dependency] private readonly SharedAppearanceSystem _appearance = default!; + [Dependency] private readonly SharedAppearanceSystem _appearance = default!; [Dependency] private readonly SharedAudioSystem _audio = default!; + [Dependency] private readonly SharedContainerSystem _container = default!; [Dependency] private readonly SharedJointSystem _joints = default!; [Dependency] private readonly SharedPhysicsSystem _physics = default!; [Dependency] protected readonly SharedTransformSystem TransformSystem = default!; + [Dependency] private readonly ThrowingSystem _throwing = default!; [Dependency] private readonly ThrownItemSystem _thrown = default!; private const string TetherJoint = "tether"; @@ -42,6 +45,8 @@ public abstract class SharedTetherGunSystem : EntitySystem SubscribeLocalEvent(OnTetheredBuckleAttempt); SubscribeLocalEvent(OnTetheredUpdateCanMove); + + InitializeForce(); } private void OnTetheredBuckleAttempt(EntityUid uid, TetheredComponent component, ref BuckleAttemptEvent args) @@ -115,7 +120,8 @@ public abstract class SharedTetherGunSystem : EntitySystem gun = null; if (!TryComp(user, out var hands) || - !TryComp(hands.ActiveHandEntity, out gun)) + !TryComp(hands.ActiveHandEntity, out gun) || + _container.IsEntityInContainer(user)) { return false; } @@ -129,18 +135,19 @@ public abstract class SharedTetherGunSystem : EntitySystem StopTether(uid, component); } - public void TryTether(EntityUid gun, EntityUid target, EntityUid? user, TetherGunComponent? component = null) + public bool TryTether(EntityUid gun, EntityUid target, EntityUid? user, BaseForceGunComponent? component = null) { if (!Resolve(gun, ref component)) - return; + return false; if (!CanTether(gun, component, target, user)) - return; + return false; StartTether(gun, component, target, user); + return true; } - protected virtual bool CanTether(EntityUid uid, TetherGunComponent component, EntityUid target, EntityUid? user) + protected virtual bool CanTether(EntityUid uid, BaseForceGunComponent component, EntityUid target, EntityUid? user) { if (HasComp(target) || !TryComp(target, out var physics)) return false; @@ -160,7 +167,7 @@ public abstract class SharedTetherGunSystem : EntitySystem return true; } - protected virtual void StartTether(EntityUid gunUid, TetherGunComponent component, EntityUid target, EntityUid? user, + protected virtual void StartTether(EntityUid gunUid, BaseForceGunComponent component, EntityUid target, EntityUid? user, PhysicsComponent? targetPhysics = null, TransformComponent? targetXform = null) { if (!Resolve(target, ref targetPhysics, ref targetXform)) @@ -212,7 +219,7 @@ public abstract class SharedTetherGunSystem : EntitySystem Dirty(component); } - protected virtual void StopTether(EntityUid gunUid, TetherGunComponent component, bool transfer = false) + protected virtual void StopTether(EntityUid gunUid, BaseForceGunComponent component, bool land = true, bool transfer = false) { if (component.Tethered == null) return; @@ -229,8 +236,11 @@ public abstract class SharedTetherGunSystem : EntitySystem if (TryComp(component.Tethered, out var targetPhysics)) { - var thrown = EnsureComp(component.Tethered.Value); - _thrown.LandComponent(component.Tethered.Value, thrown, targetPhysics); + if (land) + { + var thrown = EnsureComp(component.Tethered.Value); + _thrown.LandComponent(component.Tethered.Value, thrown, targetPhysics, true); + } _physics.SetBodyStatus(targetPhysics, BodyStatus.OnGround); _physics.SetSleepingAllowed(component.Tethered.Value, targetPhysics, true); diff --git a/Content.Shared/Weapons/Misc/TetherGunComponent.cs b/Content.Shared/Weapons/Misc/TetherGunComponent.cs index 7feaf7f518..06e7da6df4 100644 --- a/Content.Shared/Weapons/Misc/TetherGunComponent.cs +++ b/Content.Shared/Weapons/Misc/TetherGunComponent.cs @@ -1,58 +1,16 @@ -using Robust.Shared.Audio; using Robust.Shared.GameStates; namespace Content.Shared.Weapons.Misc; -[RegisterComponent, NetworkedComponent, AutoGenerateComponentState] -public sealed partial class TetherGunComponent : Component +[RegisterComponent, NetworkedComponent, AutoGenerateComponentState(true)] +public sealed partial class TetherGunComponent : BaseForceGunComponent { [ViewVariables(VVAccess.ReadWrite), DataField("maxDistance"), AutoNetworkedField] public float MaxDistance = 10f; - /// - /// The entity the tethered target has a joint to. - /// - [DataField("tetherEntity"), AutoNetworkedField] - public EntityUid? TetherEntity; - /// /// The entity currently tethered. /// [ViewVariables(VVAccess.ReadWrite), DataField("tethered"), AutoNetworkedField] - public EntityUid? Tethered; - - /// - /// Can the tethergun unanchor entities. - /// - [ViewVariables(VVAccess.ReadWrite), DataField("canUnanchor"), AutoNetworkedField] - public bool CanUnanchor = false; - - [ViewVariables(VVAccess.ReadWrite), DataField("canTetherAlive"), AutoNetworkedField] - public bool CanTetherAlive = false; - - /// - /// Max force between the tether entity and the tethered target. - /// - [ViewVariables(VVAccess.ReadWrite), DataField("maxForce"), AutoNetworkedField] - public float MaxForce = 200f; - - [ViewVariables(VVAccess.ReadWrite), DataField("frequency"), AutoNetworkedField] - public float Frequency = 10f; - - [ViewVariables(VVAccess.ReadWrite), DataField("dampingRatio"), AutoNetworkedField] - public float DampingRatio = 2f; - - /// - /// Maximum amount of mass a tethered entity can have. - /// - [ViewVariables(VVAccess.ReadWrite), DataField("massLimit"), AutoNetworkedField] - public float MassLimit = 100f; - - [ViewVariables(VVAccess.ReadWrite), DataField("sound"), AutoNetworkedField] - public SoundSpecifier? Sound = new SoundPathSpecifier("/Audio/Weapons/weoweo.ogg") - { - Params = AudioParams.Default.WithLoop(true).WithVolume(-8f), - }; - - public IPlayingAudioStream? Stream; + public override EntityUid? Tethered { get; set; } } diff --git a/Resources/Audio/Weapons/licenses.txt b/Resources/Audio/Weapons/licenses.txt index 7b077ffc71..4dbd19401a 100644 --- a/Resources/Audio/Weapons/licenses.txt +++ b/Resources/Audio/Weapons/licenses.txt @@ -16,4 +16,8 @@ pierce.ogg taken from: https://github.com/tgstation/tgstation/commit/106cd26fc00 - files: ["weoweo.ogg"] license: "SONNISS #GAMEAUDIOGDC BUNDLE LICENSING" - copyright: "Taken from Sonniss.com - GDC 2023 - Systematic Sound - TonalElements Obscurum - Dark Drones" \ No newline at end of file + copyright: "Taken from Sonniss.com - GDC 2023 - Systematic Sound - TonalElements Obscurum - Dark Drones" + +- files: ["soup.ogg"] + license: "SONNISS #GAMEAUDIOGDC BUNDLE LICENSING" + copyright: "Taken from Sonniss.com - GDC 2023 - 344 AUdio - Epic Impacts Vol. 1" \ No newline at end of file diff --git a/Resources/Audio/Weapons/soup.ogg b/Resources/Audio/Weapons/soup.ogg new file mode 100644 index 0000000000..b3dfe57f4a Binary files /dev/null and b/Resources/Audio/Weapons/soup.ogg differ diff --git a/Resources/Prototypes/Entities/Objects/Weapons/Guns/Launchers/launchers.yml b/Resources/Prototypes/Entities/Objects/Weapons/Guns/Launchers/launchers.yml index 4356efa474..0c0940b85e 100644 --- a/Resources/Prototypes/Entities/Objects/Weapons/Guns/Launchers/launchers.yml +++ b/Resources/Prototypes/Entities/Objects/Weapons/Guns/Launchers/launchers.yml @@ -186,6 +186,49 @@ True: { visible: true } False: { visible: false } +- type: entity + name: force gun + parent: + - BaseItem + - PowerCellSlotMediumItem + id: WeaponForceGun + description: Manipulates gravity around objects to fling them at high velocities. + components: + - type: ForceGun + frequency: 15 + dampingRatio: 4 + massLimit: 50 + lineColor: "#18a2d5" + soundLaunch: + path: /Audio/Weapons/soup.ogg + params: + volume: 2 + - type: PowerCellDraw + - type: Sprite + sprite: Objects/Weapons/Guns/Launchers/force_gun.rsi + layers: + - state: base + - state: base-unshaded + 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: Appearance + - type: GenericVisualizer + visuals: + enum.TetherVisualsStatus.Key: + unshaded: + True: { visible: true } + False: { visible: false } + # Admeme - type: entity name: tether gun @@ -226,6 +269,48 @@ True: { visible: true } False: { visible: false } +- type: entity + name: force gun + parent: BaseItem + id: WeaponForceGunAdmin + suffix: Admin + description: Manipulates gravity around objects to fling them at high velocities. + components: + - type: ForceGun + canTetherAlive: true + canUnanchor: true + maxForce: 10000 + massLimit: 10000 + frequency: 15 + dampingRatio: 4 + throwForce: 50 + throwDistance: 100 + lineColor: "#18a2d5" + - type: Sprite + sprite: Objects/Weapons/Guns/Launchers/force_gun.rsi + layers: + - state: base + - state: base-unshaded + 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: Appearance + - type: GenericVisualizer + visuals: + enum.TetherVisualsStatus.Key: + unshaded: + True: { visible: true } + False: { visible: false } + - type: entity name: meteor launcher parent: WeaponLauncherMultipleRocket diff --git a/Resources/Prototypes/Entities/Structures/Machines/lathe.yml b/Resources/Prototypes/Entities/Structures/Machines/lathe.yml index 888e37bd86..7c58249ef0 100644 --- a/Resources/Prototypes/Entities/Structures/Machines/lathe.yml +++ b/Resources/Prototypes/Entities/Structures/Machines/lathe.yml @@ -239,6 +239,7 @@ - ClothingShoesBootsMag - NodeScanner - HolofanProjector + - WeaponForceGun - WeaponTetherGun - ClothingBackpackHolding - ClothingBackpackSatchelHolding diff --git a/Resources/Prototypes/Recipes/Lathes/devices.yml b/Resources/Prototypes/Recipes/Lathes/devices.yml index b0cb852142..cf9954b48b 100644 --- a/Resources/Prototypes/Recipes/Lathes/devices.yml +++ b/Resources/Prototypes/Recipes/Lathes/devices.yml @@ -100,6 +100,15 @@ Plastic: 750 Plasma: 1000 +- type: latheRecipe + id: WeaponForceGun + result: WeaponForceGun + completetime: 5 + materials: + Steel: 500 + Glass: 400 + Silver: 200 + - type: latheRecipe id: WeaponTetherGun result: WeaponTetherGun diff --git a/Resources/Prototypes/Research/experimental.yml b/Resources/Prototypes/Research/experimental.yml index 5bc6c623c7..c2e96fd0a7 100644 --- a/Resources/Prototypes/Research/experimental.yml +++ b/Resources/Prototypes/Research/experimental.yml @@ -171,4 +171,5 @@ tier: 3 cost: 10000 recipeUnlocks: + - WeaponForceGun - WeaponTetherGun diff --git a/Resources/Textures/Objects/Weapons/Guns/Launchers/force_gun.rsi/base-unshaded.png b/Resources/Textures/Objects/Weapons/Guns/Launchers/force_gun.rsi/base-unshaded.png new file mode 100644 index 0000000000..99a23fa9b8 Binary files /dev/null and b/Resources/Textures/Objects/Weapons/Guns/Launchers/force_gun.rsi/base-unshaded.png differ diff --git a/Resources/Textures/Objects/Weapons/Guns/Launchers/force_gun.rsi/base.png b/Resources/Textures/Objects/Weapons/Guns/Launchers/force_gun.rsi/base.png new file mode 100644 index 0000000000..5ccd70e2bf Binary files /dev/null and b/Resources/Textures/Objects/Weapons/Guns/Launchers/force_gun.rsi/base.png differ diff --git a/Resources/Textures/Objects/Weapons/Guns/Launchers/force_gun.rsi/inhand-left-unshaded.png b/Resources/Textures/Objects/Weapons/Guns/Launchers/force_gun.rsi/inhand-left-unshaded.png new file mode 100644 index 0000000000..9396c9d630 Binary files /dev/null and b/Resources/Textures/Objects/Weapons/Guns/Launchers/force_gun.rsi/inhand-left-unshaded.png differ diff --git a/Resources/Textures/Objects/Weapons/Guns/Launchers/force_gun.rsi/inhand-left.png b/Resources/Textures/Objects/Weapons/Guns/Launchers/force_gun.rsi/inhand-left.png new file mode 100644 index 0000000000..5d314fb76d Binary files /dev/null and b/Resources/Textures/Objects/Weapons/Guns/Launchers/force_gun.rsi/inhand-left.png differ diff --git a/Resources/Textures/Objects/Weapons/Guns/Launchers/force_gun.rsi/inhand-right-unshaded.png b/Resources/Textures/Objects/Weapons/Guns/Launchers/force_gun.rsi/inhand-right-unshaded.png new file mode 100644 index 0000000000..e494ca3890 Binary files /dev/null and b/Resources/Textures/Objects/Weapons/Guns/Launchers/force_gun.rsi/inhand-right-unshaded.png differ diff --git a/Resources/Textures/Objects/Weapons/Guns/Launchers/force_gun.rsi/inhand-right.png b/Resources/Textures/Objects/Weapons/Guns/Launchers/force_gun.rsi/inhand-right.png new file mode 100644 index 0000000000..519a10b634 Binary files /dev/null and b/Resources/Textures/Objects/Weapons/Guns/Launchers/force_gun.rsi/inhand-right.png differ diff --git a/Resources/Textures/Objects/Weapons/Guns/Launchers/force_gun.rsi/meta.json b/Resources/Textures/Objects/Weapons/Guns/Launchers/force_gun.rsi/meta.json new file mode 100644 index 0000000000..66511d0404 --- /dev/null +++ b/Resources/Textures/Objects/Weapons/Guns/Launchers/force_gun.rsi/meta.json @@ -0,0 +1,33 @@ +{ + "version": 1, + "license": "CC-BY-SA-3.0", + "copyright": "Sprited by discord Kheprep#7153, modified by metalgearsloth", + "size": { + "x": 32, + "y": 32 + }, + "states": [ + { + "name": "base" + }, + { + "name": "base-unshaded" + }, + { + "name": "inhand-left", + "directions": 4 + }, + { + "name": "inhand-right", + "directions": 4 + }, + { + "name": "inhand-left-unshaded", + "directions": 4 + }, + { + "name": "inhand-right-unshaded", + "directions": 4 + } + ] +} \ No newline at end of file diff --git a/Resources/Textures/Objects/Weapons/Guns/Launchers/tether_gun.rsi/inhand-right.png b/Resources/Textures/Objects/Weapons/Guns/Launchers/tether_gun.rsi/inhand-right.png index 913d556380..519a10b634 100644 Binary files a/Resources/Textures/Objects/Weapons/Guns/Launchers/tether_gun.rsi/inhand-right.png and b/Resources/Textures/Objects/Weapons/Guns/Launchers/tether_gun.rsi/inhand-right.png differ