diff --git a/Content.Shared/Weapons/Ranged/Components/GunComponent.cs b/Content.Shared/Weapons/Ranged/Components/GunComponent.cs new file mode 100644 index 00000000000..bcc56c28ab1 --- /dev/null +++ b/Content.Shared/Weapons/Ranged/Components/GunComponent.cs @@ -0,0 +1,282 @@ +using System.Numerics; +using Content.Shared.Weapons.Ranged.Events; +using Content.Shared.Weapons.Ranged.Systems; +using Robust.Shared.Audio; +using Robust.Shared.GameStates; +using Robust.Shared.Map; +using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom; + +namespace Content.Shared.Weapons.Ranged.Components; + +[RegisterComponent, NetworkedComponent, AutoGenerateComponentState, AutoGenerateComponentPause] +[Access(typeof(SharedGunSystem))] +public sealed partial class GunComponent : Component +{ + #region Sound + + /// + /// The base sound to use when the gun is fired. + /// + [DataField] + public SoundSpecifier? SoundGunshot = new SoundPathSpecifier("/Audio/Weapons/Guns/Gunshots/smg.ogg"); + + /// + /// The sound to use when the gun is fired. + /// + /// + [AutoNetworkedField, ViewVariables(VVAccess.ReadWrite)] + public SoundSpecifier? SoundGunshotModified; + + [DataField] + public SoundSpecifier? SoundEmpty = new SoundPathSpecifier("/Audio/Weapons/Guns/Empty/empty.ogg"); + + /// + /// Sound played when toggling the for this gun. + /// + [DataField] + public SoundSpecifier? SoundMode = new SoundPathSpecifier("/Audio/Weapons/Guns/Misc/selector.ogg"); + + #endregion + + #region Recoil + + // These values are very small for now until we get a debug overlay and fine tune it + + /// + /// The base scalar value applied to the vector governing camera recoil. + /// + [DataField, AutoNetworkedField] + public float CameraRecoilScalar = 1f; + + /// + /// A scalar value applied to the vector governing camera recoil. + /// If 0, there will be no camera recoil. + /// + /// + [AutoNetworkedField, ViewVariables(VVAccess.ReadWrite)] + public float CameraRecoilScalarModified = 1f; + + /// + /// Last time the gun fired. + /// Used for recoil purposes. + /// + [DataField] + public TimeSpan LastFire = TimeSpan.Zero; + + /// + /// What the current spread is for shooting. This gets changed every time the gun fires. + /// + [DataField] + [AutoNetworkedField] + public Angle CurrentAngle; + + /// + /// The base value for how much the spread increases every time the gun fires. + /// + [DataField] + public Angle AngleIncrease = Angle.FromDegrees(0.5); + + /// + /// How much the spread increases every time the gun fires. + /// + /// + [AutoNetworkedField, ViewVariables(VVAccess.ReadWrite)] + public Angle AngleIncreaseModified; + + /// + /// The base value for how much the decreases per second. + /// + [DataField] + public Angle AngleDecay = Angle.FromDegrees(4); + + /// + /// How much the decreases per second. + /// + /// + [AutoNetworkedField, ViewVariables(VVAccess.ReadWrite)] + public Angle AngleDecayModified; + + /// + /// The base value for the maximum angle allowed for + /// + [DataField] + [AutoNetworkedField] + public Angle MaxAngle = Angle.FromDegrees(2); + + /// + /// The maximum angle allowed for + /// + /// + [AutoNetworkedField, ViewVariables(VVAccess.ReadWrite)] + public Angle MaxAngleModified; + + /// + /// The base value for the minimum angle allowed for + /// + [DataField] + [AutoNetworkedField] + public Angle MinAngle = Angle.FromDegrees(1); + + /// + /// The minimum angle allowed for . + /// + /// + [AutoNetworkedField, ViewVariables(VVAccess.ReadWrite)] + public Angle MinAngleModified; + + #endregion + + /// + /// Whether this gun is shot via the use key or the alt-use key. + /// + [DataField, AutoNetworkedField] + public bool UseKey = true; + + /// + /// Where the gun is being requested to shoot. + /// + [ViewVariables] + public EntityCoordinates? ShootCoordinates = null; + + /// + /// Who the gun is being requested to shoot at directly. + /// + [ViewVariables] + public EntityUid? Target = null; + + /// + /// The base value for how many shots to fire per burst. + /// + [DataField, AutoNetworkedField] + public int ShotsPerBurst = 3; + + /// + /// How many shots to fire per burst. + /// + /// + [AutoNetworkedField, ViewVariables(VVAccess.ReadWrite)] + public int ShotsPerBurstModified = 3; + + /// + /// How long time must pass between burstfire shots. + /// + [DataField, AutoNetworkedField] + public float BurstCooldown = 0.25f; + + /// + /// The fire rate of the weapon in burst fire mode. + /// + [DataField, AutoNetworkedField] + public float BurstFireRate = 8f; + + /// + /// Whether the burst fire mode has been activated. + /// + [AutoNetworkedField, ViewVariables(VVAccess.ReadWrite)] + public bool BurstActivated = false; + + /// + /// The burst fire bullet count. + /// + [AutoNetworkedField, ViewVariables(VVAccess.ReadWrite)] + public int BurstShotsCount = 0; + + /// + /// Used for tracking semi-auto / burst + /// + [ViewVariables] + [AutoNetworkedField] + public int ShotCounter = 0; + + /// + /// The base value for how many times it shoots per second. + /// + [DataField] + [AutoNetworkedField] + public float FireRate = 8f; + + /// + /// How many times it shoots per second. + /// + /// + [AutoNetworkedField, ViewVariables(VVAccess.ReadWrite)] + public float FireRateModified; + + /// + /// Starts fire cooldown when equipped if true. + /// + [DataField] + public bool ResetOnHandSelected = true; + + /// + /// The base value for how fast the projectile moves. + /// + [DataField] + public float ProjectileSpeed = 25f; + + /// + /// How fast the projectile moves. + /// + /// + [AutoNetworkedField, ViewVariables(VVAccess.ReadWrite)] + public float ProjectileSpeedModified; + + /// + /// When the gun is next available to be shot. + /// Can be set multiple times in a single tick due to guns firing faster than a single tick time. + /// + [DataField(customTypeSerializer:typeof(TimeOffsetSerializer))] + [AutoNetworkedField] + [AutoPausedField] + public TimeSpan NextFire = TimeSpan.Zero; + + /// + /// What firemodes can be selected. + /// + [DataField] + [AutoNetworkedField] + public SelectiveFire AvailableModes = SelectiveFire.SemiAuto; + + /// + /// What firemode is currently selected. + /// + [DataField] + [AutoNetworkedField] + public SelectiveFire SelectedMode = SelectiveFire.SemiAuto; + + /// + /// Whether or not information about + /// the gun will be shown on examine. + /// + [DataField] + public bool ShowExamineText = true; + + /// + /// Whether or not someone with the + /// clumsy trait can shoot this + /// + [DataField] + public bool ClumsyProof = false; + + /// + /// Firing direction for an item not being held (e.g. shuttle cannons, thrown guns still firing). + /// + [DataField] + public Vector2 DefaultDirection = new Vector2(0, -1); + + /// + /// Corvax-Next. The percentage chance of a given gun to accidentally discharge if violently thrown into a wall or person + /// + [DataField] + public float FireOnDropChance = 0.1f; +} + +[Flags] +public enum SelectiveFire : byte +{ + Invalid = 0, + // Combat mode already functions as the equivalent of Safety + SemiAuto = 1 << 0, + Burst = 1 << 1, + FullAuto = 1 << 2, // Not in the building! +}