| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191 |
- 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;
- /// <summary>
- /// When given to a mob lets them do unarmed attacks, or when given to an item lets someone wield it to do attacks.
- /// </summary>
- [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.
- /// <summary>
- /// Does this entity do a disarm on alt attack.
- /// </summary>
- [DataField, ViewVariables(VVAccess.ReadWrite), AutoNetworkedField]
- public bool AltDisarm = true;
- /// <summary>
- /// Should the melee weapon's damage stats be examinable.
- /// </summary>
- [ViewVariables(VVAccess.ReadWrite)]
- [DataField]
- public bool Hidden;
- /// <summary>
- /// Next time this component is allowed to light attack. Heavy attacks are wound up and never have a cooldown.
- /// </summary>
- [DataField(customTypeSerializer: typeof(TimeOffsetSerializer)), AutoNetworkedField]
- [ViewVariables(VVAccess.ReadWrite)]
- [AutoPausedField]
- public TimeSpan NextAttack;
- /// <summary>
- /// Starts attack cooldown when equipped if true.
- /// </summary>
- [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.
- */
- /// <summary>
- /// How many times we can attack per second.
- /// </summary>
- [ViewVariables(VVAccess.ReadWrite), DataField, AutoNetworkedField]
- public float AttackRate = 1f;
- /// <summary>
- /// Are we currently holding down the mouse for an attack.
- /// Used so we can't just hold the mouse button and attack constantly.
- /// </summary>
- [ViewVariables(VVAccess.ReadWrite), AutoNetworkedField]
- public bool Attacking = false;
- /// <summary>
- /// If true, attacks will be repeated automatically without requiring the mouse button to be lifted.
- /// </summary>
- [DataField, ViewVariables(VVAccess.ReadWrite), AutoNetworkedField]
- public bool AutoAttack;
- /// <summary>
- /// If true, attacks will bypass armor resistances.
- /// </summary>
- [DataField, ViewVariables(VVAccess.ReadWrite), AutoNetworkedField]
- public bool ResistanceBypass = false;
- /// <summary>
- /// Base damage for this weapon. Can be modified via heavy damage or other means.
- /// </summary>
- [DataField(required: true)]
- [ViewVariables(VVAccess.ReadWrite), AutoNetworkedField]
- public DamageSpecifier Damage = default!;
- [DataField]
- [ViewVariables(VVAccess.ReadWrite)]
- public FixedPoint2 BluntStaminaDamageFactor = FixedPoint2.New(0.5f);
- /// <summary>
- /// Multiplies damage by this amount for single-target attacks.
- /// </summary>
- [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
- /// <summary>
- /// Nearest edge range to hit an entity.
- /// </summary>
- [ViewVariables(VVAccess.ReadWrite), DataField, AutoNetworkedField]
- public float Range = 1.5f;
- // goob edit - stunmeta
- /// <summary>
- /// Applies stamina damage on each successful wideswing hit to the attacker.
- /// </summary>
- [DataField, AutoNetworkedField]
- public float HeavyStaminaCost = 5f;
- /// <summary>
- /// Total width of the angle for wide attacks.
- /// </summary>
- [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";
- /// <summary>
- /// Rotation of the animation.
- /// 0 degrees means the top faces the attacker.
- /// </summary>
- [ViewVariables(VVAccess.ReadWrite), DataField]
- public Angle WideAnimationRotation = Angle.Zero;
- [ViewVariables(VVAccess.ReadWrite), DataField]
- public bool SwingLeft;
- // Sounds
- /// <summary>
- /// This gets played whenever a melee attack is done. This is predicted by the client.
- /// </summary>
- [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;
- /// <summary>
- /// Plays if no damage is done to the target entity.
- /// </summary>
- [ViewVariables(VVAccess.ReadWrite)]
- [DataField("soundNoDamage"), AutoNetworkedField]
- public SoundSpecifier NoDamageSound { get; set; } = new SoundCollectionSpecifier("WeakHit");
- /// <summary>
- /// 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.
- /// </summary>
- [DataField, AutoNetworkedField]
- public bool MustBeEquippedToUse = false;
- // Shitmed Change Start
- /// <summary>
- /// Shitmed Change: Part damage is multiplied by this amount for single-target attacks
- /// </summary>
- [DataField, AutoNetworkedField]
- public float ClickPartDamageMultiplier = 1.00f;
- /// <summary>
- /// Shitmed Change: Part damage is multiplied by this amount for heavy swings
- /// </summary>
- [DataField, AutoNetworkedField]
- public float HeavyPartDamageMultiplier = 0.5f;
- // Shitmed Change End
- // Goobstation
- [DataField, AutoNetworkedField]
- public bool CanWideSwing = true;
- }
- /// <summary>
- /// Event raised on entity in GetWeapon function to allow systems to manually
- /// specify what the weapon should be.
- /// </summary>
- public sealed class GetMeleeWeaponEvent : HandledEntityEventArgs
- {
- public EntityUid? Weapon;
- }
|