using Content.Shared.Damage; using Content.Shared.FixedPoint; using Robust.Shared.Audio; using Robust.Shared.GameStates; using Robust.Shared.Prototypes; using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom; namespace Content.Shared.Weapons.Melee; /// /// When given to a mob lets them do unarmed attacks, or when given to an item lets someone wield it to do attacks. /// [RegisterComponent, NetworkedComponent, AutoGenerateComponentState, AutoGenerateComponentPause] public sealed partial class MeleeWeaponComponent : Component { // TODO: This is becoming bloated as shit. // This should just be its own component for alt attacks. /// /// Does this entity do a disarm on alt attack. /// [DataField, ViewVariables(VVAccess.ReadWrite), AutoNetworkedField] public bool AltDisarm = true; /// /// Should the melee weapon's damage stats be examinable. /// [ViewVariables(VVAccess.ReadWrite)] [DataField] public bool Hidden; /// /// Next time this component is allowed to light attack. Heavy attacks are wound up and never have a cooldown. /// [DataField(customTypeSerializer: typeof(TimeOffsetSerializer)), AutoNetworkedField] [ViewVariables(VVAccess.ReadWrite)] [AutoPausedField] public TimeSpan NextAttack; /// /// Starts attack cooldown when equipped if true. /// [ViewVariables(VVAccess.ReadWrite), DataField] public bool ResetOnHandSelected = true; /* * Melee combat works based around 2 types of attacks: * 1. Click attacks with left-click. This attacks whatever is under your mnouse * 2. Wide attacks with right-click + left-click. This attacks whatever is in the direction of your mouse. */ /// /// How many times we can attack per second. /// [ViewVariables(VVAccess.ReadWrite), DataField, AutoNetworkedField] public float AttackRate = 1f; /// /// Are we currently holding down the mouse for an attack. /// Used so we can't just hold the mouse button and attack constantly. /// [ViewVariables(VVAccess.ReadWrite), AutoNetworkedField] public bool Attacking = false; /// /// If true, attacks will be repeated automatically without requiring the mouse button to be lifted. /// [DataField, ViewVariables(VVAccess.ReadWrite), AutoNetworkedField] public bool AutoAttack; /// /// If true, attacks will bypass armor resistances. /// [DataField, ViewVariables(VVAccess.ReadWrite), AutoNetworkedField] public bool ResistanceBypass = false; /// /// Base damage for this weapon. Can be modified via heavy damage or other means. /// [DataField(required: true)] [ViewVariables(VVAccess.ReadWrite), AutoNetworkedField] public DamageSpecifier Damage = default!; [DataField] [ViewVariables(VVAccess.ReadWrite)] public FixedPoint2 BluntStaminaDamageFactor = FixedPoint2.New(0.5f); /// /// Multiplies damage by this amount for single-target attacks. /// [ViewVariables(VVAccess.ReadWrite), DataField] public FixedPoint2 ClickDamageModifier = FixedPoint2.New(1); // TODO: Temporarily 1.5 until interactionoutline is adjusted to use melee, then probably drop to 1.2 /// /// Nearest edge range to hit an entity. /// [ViewVariables(VVAccess.ReadWrite), DataField, AutoNetworkedField] public float Range = 1.5f; // goob edit - stunmeta /// /// Applies stamina damage on each successful wideswing hit to the attacker. /// [DataField, AutoNetworkedField] public float HeavyStaminaCost = 5f; /// /// Total width of the angle for wide attacks. /// [ViewVariables(VVAccess.ReadWrite), DataField] public Angle Angle = Angle.FromDegrees(60); [ViewVariables(VVAccess.ReadWrite), DataField, AutoNetworkedField] public EntProtoId Animation = "WeaponArcPunch"; [ViewVariables(VVAccess.ReadWrite), DataField, AutoNetworkedField] public EntProtoId WideAnimation = "WeaponArcSlash"; /// /// Rotation of the animation. /// 0 degrees means the top faces the attacker. /// [ViewVariables(VVAccess.ReadWrite), DataField] public Angle WideAnimationRotation = Angle.Zero; [ViewVariables(VVAccess.ReadWrite), DataField] public bool SwingLeft; // Sounds /// /// This gets played whenever a melee attack is done. This is predicted by the client. /// [ViewVariables(VVAccess.ReadWrite)] [DataField("soundSwing"), AutoNetworkedField] public SoundSpecifier SwingSound { get; set; } = new SoundPathSpecifier("/Audio/Weapons/punchmiss.ogg") { Params = AudioParams.Default.WithVolume(-3f).WithVariation(0.025f), }; // We do not predict the below sounds in case the client thinks but the server disagrees. If this were the case // then a player may doubt if the target actually took damage or not. // If overwatch and apex do this then we probably should too. [ViewVariables(VVAccess.ReadWrite)] [DataField("soundHit"), AutoNetworkedField] public SoundSpecifier? HitSound; /// /// Plays if no damage is done to the target entity. /// [ViewVariables(VVAccess.ReadWrite)] [DataField("soundNoDamage"), AutoNetworkedField] public SoundSpecifier NoDamageSound { get; set; } = new SoundCollectionSpecifier("WeakHit"); /// /// If true, the weapon must be equipped for it to be used. /// E.g boxing gloves must be equipped to your gloves, /// not just held in your hand to be used. /// [DataField, AutoNetworkedField] public bool MustBeEquippedToUse = false; // Shitmed Change Start /// /// Shitmed Change: Part damage is multiplied by this amount for single-target attacks /// [DataField, AutoNetworkedField] public float ClickPartDamageMultiplier = 1.00f; /// /// Shitmed Change: Part damage is multiplied by this amount for heavy swings /// [DataField, AutoNetworkedField] public float HeavyPartDamageMultiplier = 0.5f; // Shitmed Change End // Goobstation [DataField, AutoNetworkedField] public bool CanWideSwing = true; } /// /// Event raised on entity in GetWeapon function to allow systems to manually /// specify what the weapon should be. /// public sealed class GetMeleeWeaponEvent : HandledEntityEventArgs { public EntityUid? Weapon; }