forked from space-wizards/space-station-14
-
-
Notifications
You must be signed in to change notification settings - Fork 90
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #1482 from Saeko-44/master
Fishing part 1 : The Fishing Rod
- Loading branch information
Showing
33 changed files
with
589 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,58 @@ | ||
using System.Net; | ||
using Content.Client.Hands.Systems; | ||
using Content.Shared._Impstation.Fishing; | ||
using Content.Shared.CombatMode; | ||
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._Impstation.Fishing; | ||
|
||
//Imp : Basically a copy of GrapplingGunSystem | ||
public sealed class FishingRodSystem : SharedFishingRodSystem | ||
{ | ||
[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.LocalEntity; | ||
var handUid = _hands.GetActiveHandEntity(); | ||
|
||
if (!TryComp<FishingRodComponent>(handUid, out var grappling)) | ||
return; | ||
|
||
if (!TryComp<JointComponent>(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<CombatModeComponent>(local, out var combatMode) || | ||
!combatMode.IsInCombatMode) | ||
{ | ||
reelKey = false; | ||
} | ||
|
||
if (grappling.Reeling == reelKey) | ||
return; | ||
|
||
RaisePredictiveEvent(new RequestGrapplingReelMessage(reelKey)); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
using Content.Shared._Impstation.Fishing; | ||
|
||
namespace Content.Server._Impstation.Fishing; | ||
|
||
//Imp : Basically a copy of GrapplingGunSystem | ||
public sealed class FishingRodSystem : SharedFishingRodSystem | ||
{ | ||
|
||
} |
10 changes: 10 additions & 0 deletions
10
Content.Shared/_Impstation/Fishing/FishingProjectileComponent.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
using Robust.Shared.GameStates; | ||
|
||
namespace Content.Shared._Impstation.Fishing; | ||
|
||
[RegisterComponent, NetworkedComponent] | ||
//Imp : Basically a copy of GrapplingProjectileComponent | ||
public sealed partial class FishingProjectileComponent : Component | ||
{ | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
using Robust.Shared.Audio; | ||
using Robust.Shared.GameStates; | ||
using Robust.Shared.Utility; | ||
|
||
namespace Content.Shared._Impstation.Fishing; | ||
|
||
// 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] | ||
//Imp : Basically a copy of GrapplingGunComponent | ||
public sealed partial class FishingRodComponent : Component | ||
{ | ||
/// <summary> | ||
/// Hook's reeling force and speed - the higher the number, the faster the hook rewinds. | ||
/// </summary> | ||
[DataField, AutoNetworkedField] | ||
public float ReelRate = 2.5f; | ||
|
||
[DataField("jointId"), AutoNetworkedField] | ||
public string Joint = string.Empty; | ||
|
||
[DataField, AutoNetworkedField] | ||
public EntityUid? Projectile; | ||
|
||
[DataField, AutoNetworkedField] | ||
public bool Reeling; | ||
|
||
[DataField, AutoNetworkedField] | ||
public SoundSpecifier? ReelSound = new SoundPathSpecifier("/Audio/Weapons/reel.ogg") | ||
{ | ||
Params = AudioParams.Default.WithLoop(true) | ||
}; | ||
|
||
[DataField, AutoNetworkedField] | ||
public SoundSpecifier? CycleSound = new SoundPathSpecifier("/Audio/Weapons/Guns/MagIn/kinetic_reload.ogg"); | ||
|
||
[DataField] | ||
public SpriteSpecifier RopeSprite = | ||
new SpriteSpecifier.Rsi(new ResPath("Objects/Weapons/Guns/Launchers/grappling_gun.rsi"), "rope"); | ||
|
||
public EntityUid? Stream; | ||
} |
246 changes: 246 additions & 0 deletions
246
Content.Shared/_Impstation/Fishing/SharedFishingSystem.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,246 @@ | ||
using System.Numerics; | ||
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.Weapons.Misc; | ||
using Content.Shared.Weapons.Ranged.Systems; | ||
using Robust.Shared.Audio.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; | ||
|
||
namespace Content.Shared._Impstation.Fishing; | ||
|
||
//Imp : Basically a copy of GrapplingGunSystem | ||
public abstract class SharedFishingRodSystem : 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 SharedGunSystem _gun = default!; | ||
[Dependency] private readonly SharedPhysicsSystem _physics = default!; | ||
|
||
public const string GrapplingJoint = "grappling"; | ||
|
||
public override void Initialize() | ||
{ | ||
base.Initialize(); | ||
|
||
SubscribeLocalEvent<CanWeightlessMoveEvent>(OnWeightlessMove); | ||
SubscribeAllEvent<RequestGrapplingReelMessage>(OnGrapplingReel); | ||
|
||
SubscribeLocalEvent<FishingRodComponent, GunShotEvent>(OnGrapplingShot); | ||
SubscribeLocalEvent<FishingRodComponent, ActivateInWorldEvent>(OnGunActivate); | ||
SubscribeLocalEvent<FishingRodComponent, HandDeselectedEvent>(OnGrapplingDeselected); | ||
|
||
SubscribeLocalEvent<FishingProjectileComponent, ProjectileEmbedEvent>(OnGrappleCollide); | ||
SubscribeLocalEvent<FishingProjectileComponent, JointRemovedEvent>(OnGrappleJointRemoved); | ||
SubscribeLocalEvent<FishingProjectileComponent, RemoveEmbedEvent>(OnRemoveEmbed); | ||
} | ||
|
||
private void OnGrappleJointRemoved(EntityUid uid, FishingProjectileComponent component, JointRemovedEvent args) | ||
{ | ||
if (_netManager.IsServer) | ||
QueueDel(uid); | ||
} | ||
|
||
private void OnGrapplingShot(EntityUid uid, FishingRodComponent component, ref GunShotEvent args) | ||
{ | ||
foreach (var (shotUid, _) in args.Ammo) | ||
{ | ||
if (!HasComp<FishingProjectileComponent>(shotUid)) | ||
continue; | ||
|
||
//todo: this doesn't actually support multigrapple | ||
// At least show the visuals. | ||
component.Projectile = shotUid.Value; | ||
Dirty(uid, component); | ||
var visuals = EnsureComp<JointVisualsComponent>(shotUid.Value); | ||
visuals.Sprite = component.RopeSprite; | ||
visuals.OffsetA = new Vector2(0f, 0.5f); | ||
visuals.Target = GetNetEntity(uid); | ||
Dirty(shotUid.Value, visuals); | ||
} | ||
|
||
TryComp<AppearanceComponent>(uid, out var appearance); | ||
_appearance.SetData(uid, SharedTetherGunSystem.TetherVisualsStatus.Key, false, appearance); | ||
Dirty(uid, component); | ||
} | ||
|
||
private void OnGrapplingDeselected(EntityUid uid, FishingRodComponent component, HandDeselectedEvent args) | ||
{ | ||
SetReeling(uid, component, false, args.User); | ||
} | ||
|
||
private void OnGrapplingReel(RequestGrapplingReelMessage msg, EntitySessionEventArgs args) | ||
{ | ||
var player = args.SenderSession.AttachedEntity; | ||
if (!TryComp<HandsComponent>(player, out var hands) || | ||
!TryComp<FishingRodComponent>(hands.ActiveHandEntity, out var grappling)) | ||
{ | ||
return; | ||
} | ||
|
||
if (msg.Reeling && | ||
(!TryComp<CombatModeComponent>(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<JointRelayTargetComponent>(ev.Uid, out var relayComp)) | ||
return; | ||
|
||
foreach (var relay in relayComp.Relayed) | ||
{ | ||
if (TryComp<JointComponent>(relay, out var jointRelay) && jointRelay.GetJoints.ContainsKey(GrapplingJoint)) | ||
{ | ||
ev.CanMove = true; | ||
return; | ||
} | ||
} | ||
} | ||
|
||
private void OnGunActivate(EntityUid uid, FishingRodComponent component, ActivateInWorldEvent args) | ||
{ | ||
if (!Timing.IsFirstTimePredicted || args.Handled || !args.Complex || component.Projectile is not {} projectile) | ||
return; | ||
|
||
_audio.PlayPredicted(component.CycleSound, uid, args.User); | ||
_appearance.SetData(uid, SharedTetherGunSystem.TetherVisualsStatus.Key, true); | ||
|
||
if (_netManager.IsServer) | ||
QueueDel(projectile); | ||
|
||
component.Projectile = null; | ||
SetReeling(uid, component, false, args.User); | ||
_gun.ChangeBasicEntityAmmoCount(uid, 1); | ||
|
||
_joints.RemoveJoint(uid, GrapplingJoint); | ||
|
||
args.Handled = true; | ||
} | ||
|
||
private void SetReeling(EntityUid uid, FishingRodComponent component, bool value, EntityUid? user) | ||
{ | ||
if (component.Reeling == value) | ||
return; | ||
|
||
if (value) | ||
{ | ||
if (Timing.IsFirstTimePredicted) | ||
component.Stream = _audio.PlayPredicted(component.ReelSound, uid, user)?.Entity; | ||
} | ||
else | ||
{ | ||
if (Timing.IsFirstTimePredicted) | ||
{ | ||
component.Stream = _audio.Stop(component.Stream); | ||
} | ||
} | ||
|
||
component.Reeling = value; | ||
Dirty(uid, component); | ||
} | ||
|
||
public override void Update(float frameTime) | ||
{ | ||
base.Update(frameTime); | ||
|
||
var query = EntityQueryEnumerator<FishingRodComponent>(); | ||
|
||
while (query.MoveNext(out var uid, out var grappling)) | ||
{ | ||
if (!grappling.Reeling) | ||
{ | ||
if (Timing.IsFirstTimePredicted) | ||
{ | ||
// Just in case. | ||
grappling.Stream = _audio.Stop(grappling.Stream); | ||
} | ||
|
||
continue; | ||
} | ||
|
||
if (!TryComp<JointComponent>(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 - grappling.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(uid, jointComp); | ||
|
||
if (distance.MaxLength.Equals(distance.MinLength)) | ||
{ | ||
SetReeling(uid, grappling, false, null); | ||
} | ||
} | ||
} | ||
|
||
private void OnGrappleCollide(EntityUid uid, FishingProjectileComponent component, ref ProjectileEmbedEvent args) | ||
{ | ||
if (!Timing.IsFirstTimePredicted) | ||
return; | ||
|
||
//joint between the embedded and the weapon | ||
var jointComp = EnsureComp<JointComponent>(args.Weapon); | ||
var joint = _joints.CreateDistanceJoint(args.Weapon, args.Embedded, 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(args.Weapon, jointComp); | ||
} | ||
|
||
private void OnRemoveEmbed(EntityUid uid, FishingProjectileComponent component, RemoveEmbedEvent args) | ||
{ | ||
if (TryComp<EmbeddableProjectileComponent>(uid, out var projectile)) | ||
{ | ||
if (projectile.EmbeddedIntoUid != null) | ||
{ | ||
_joints.ClearJoints(projectile.EmbeddedIntoUid.Value); | ||
} | ||
} | ||
} | ||
|
||
[Serializable, NetSerializable] | ||
protected sealed class RequestGrapplingReelMessage : EntityEventArgs | ||
{ | ||
public bool Reeling; | ||
|
||
public RequestGrapplingReelMessage(bool reeling) | ||
{ | ||
Reeling = reeling; | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1,2 @@ | ||
research-technology-advanced-sidearms = Advanced Sidearms | ||
research-technology-basic-fishing = Fishing |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Empty file.
Oops, something went wrong.