1
0

MeleeWeaponComponent.cs 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191
  1. using Content.Shared.Damage;
  2. using Content.Shared.FixedPoint;
  3. using Robust.Shared.Audio;
  4. using Robust.Shared.GameStates;
  5. using Robust.Shared.Prototypes;
  6. using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom;
  7. namespace Content.Shared.Weapons.Melee;
  8. /// <summary>
  9. /// When given to a mob lets them do unarmed attacks, or when given to an item lets someone wield it to do attacks.
  10. /// </summary>
  11. [RegisterComponent, NetworkedComponent, AutoGenerateComponentState, AutoGenerateComponentPause]
  12. public sealed partial class MeleeWeaponComponent : Component
  13. {
  14. // TODO: This is becoming bloated as shit.
  15. // This should just be its own component for alt attacks.
  16. /// <summary>
  17. /// Does this entity do a disarm on alt attack.
  18. /// </summary>
  19. [DataField, ViewVariables(VVAccess.ReadWrite), AutoNetworkedField]
  20. public bool AltDisarm = true;
  21. /// <summary>
  22. /// Should the melee weapon's damage stats be examinable.
  23. /// </summary>
  24. [ViewVariables(VVAccess.ReadWrite)]
  25. [DataField]
  26. public bool Hidden;
  27. /// <summary>
  28. /// Next time this component is allowed to light attack. Heavy attacks are wound up and never have a cooldown.
  29. /// </summary>
  30. [DataField(customTypeSerializer: typeof(TimeOffsetSerializer)), AutoNetworkedField]
  31. [ViewVariables(VVAccess.ReadWrite)]
  32. [AutoPausedField]
  33. public TimeSpan NextAttack;
  34. /// <summary>
  35. /// Starts attack cooldown when equipped if true.
  36. /// </summary>
  37. [ViewVariables(VVAccess.ReadWrite), DataField]
  38. public bool ResetOnHandSelected = true;
  39. /*
  40. * Melee combat works based around 2 types of attacks:
  41. * 1. Click attacks with left-click. This attacks whatever is under your mnouse
  42. * 2. Wide attacks with right-click + left-click. This attacks whatever is in the direction of your mouse.
  43. */
  44. /// <summary>
  45. /// How many times we can attack per second.
  46. /// </summary>
  47. [ViewVariables(VVAccess.ReadWrite), DataField, AutoNetworkedField]
  48. public float AttackRate = 1f;
  49. /// <summary>
  50. /// Are we currently holding down the mouse for an attack.
  51. /// Used so we can't just hold the mouse button and attack constantly.
  52. /// </summary>
  53. [ViewVariables(VVAccess.ReadWrite), AutoNetworkedField]
  54. public bool Attacking = false;
  55. /// <summary>
  56. /// If true, attacks will be repeated automatically without requiring the mouse button to be lifted.
  57. /// </summary>
  58. [DataField, ViewVariables(VVAccess.ReadWrite), AutoNetworkedField]
  59. public bool AutoAttack;
  60. /// <summary>
  61. /// If true, attacks will bypass armor resistances.
  62. /// </summary>
  63. [DataField, ViewVariables(VVAccess.ReadWrite), AutoNetworkedField]
  64. public bool ResistanceBypass = false;
  65. /// <summary>
  66. /// Base damage for this weapon. Can be modified via heavy damage or other means.
  67. /// </summary>
  68. [DataField(required: true)]
  69. [ViewVariables(VVAccess.ReadWrite), AutoNetworkedField]
  70. public DamageSpecifier Damage = default!;
  71. [DataField]
  72. [ViewVariables(VVAccess.ReadWrite)]
  73. public FixedPoint2 BluntStaminaDamageFactor = FixedPoint2.New(0.5f);
  74. /// <summary>
  75. /// Multiplies damage by this amount for single-target attacks.
  76. /// </summary>
  77. [ViewVariables(VVAccess.ReadWrite), DataField]
  78. public FixedPoint2 ClickDamageModifier = FixedPoint2.New(1);
  79. // TODO: Temporarily 1.5 until interactionoutline is adjusted to use melee, then probably drop to 1.2
  80. /// <summary>
  81. /// Nearest edge range to hit an entity.
  82. /// </summary>
  83. [ViewVariables(VVAccess.ReadWrite), DataField, AutoNetworkedField]
  84. public float Range = 1.5f;
  85. // goob edit - stunmeta
  86. /// <summary>
  87. /// Applies stamina damage on each successful wideswing hit to the attacker.
  88. /// </summary>
  89. [DataField, AutoNetworkedField]
  90. public float HeavyStaminaCost = 5f;
  91. /// <summary>
  92. /// Total width of the angle for wide attacks.
  93. /// </summary>
  94. [ViewVariables(VVAccess.ReadWrite), DataField]
  95. public Angle Angle = Angle.FromDegrees(60);
  96. [ViewVariables(VVAccess.ReadWrite), DataField, AutoNetworkedField]
  97. public EntProtoId Animation = "WeaponArcPunch";
  98. [ViewVariables(VVAccess.ReadWrite), DataField, AutoNetworkedField]
  99. public EntProtoId WideAnimation = "WeaponArcSlash";
  100. /// <summary>
  101. /// Rotation of the animation.
  102. /// 0 degrees means the top faces the attacker.
  103. /// </summary>
  104. [ViewVariables(VVAccess.ReadWrite), DataField]
  105. public Angle WideAnimationRotation = Angle.Zero;
  106. [ViewVariables(VVAccess.ReadWrite), DataField]
  107. public bool SwingLeft;
  108. // Sounds
  109. /// <summary>
  110. /// This gets played whenever a melee attack is done. This is predicted by the client.
  111. /// </summary>
  112. [ViewVariables(VVAccess.ReadWrite)]
  113. [DataField("soundSwing"), AutoNetworkedField]
  114. public SoundSpecifier SwingSound { get; set; } = new SoundPathSpecifier("/Audio/Weapons/punchmiss.ogg")
  115. {
  116. Params = AudioParams.Default.WithVolume(-3f).WithVariation(0.025f),
  117. };
  118. // We do not predict the below sounds in case the client thinks but the server disagrees. If this were the case
  119. // then a player may doubt if the target actually took damage or not.
  120. // If overwatch and apex do this then we probably should too.
  121. [ViewVariables(VVAccess.ReadWrite)]
  122. [DataField("soundHit"), AutoNetworkedField]
  123. public SoundSpecifier? HitSound;
  124. /// <summary>
  125. /// Plays if no damage is done to the target entity.
  126. /// </summary>
  127. [ViewVariables(VVAccess.ReadWrite)]
  128. [DataField("soundNoDamage"), AutoNetworkedField]
  129. public SoundSpecifier NoDamageSound { get; set; } = new SoundCollectionSpecifier("WeakHit");
  130. /// <summary>
  131. /// If true, the weapon must be equipped for it to be used.
  132. /// E.g boxing gloves must be equipped to your gloves,
  133. /// not just held in your hand to be used.
  134. /// </summary>
  135. [DataField, AutoNetworkedField]
  136. public bool MustBeEquippedToUse = false;
  137. // Shitmed Change Start
  138. /// <summary>
  139. /// Shitmed Change: Part damage is multiplied by this amount for single-target attacks
  140. /// </summary>
  141. [DataField, AutoNetworkedField]
  142. public float ClickPartDamageMultiplier = 1.00f;
  143. /// <summary>
  144. /// Shitmed Change: Part damage is multiplied by this amount for heavy swings
  145. /// </summary>
  146. [DataField, AutoNetworkedField]
  147. public float HeavyPartDamageMultiplier = 0.5f;
  148. // Shitmed Change End
  149. // Goobstation
  150. [DataField, AutoNetworkedField]
  151. public bool CanWideSwing = true;
  152. }
  153. /// <summary>
  154. /// Event raised on entity in GetWeapon function to allow systems to manually
  155. /// specify what the weapon should be.
  156. /// </summary>
  157. public sealed class GetMeleeWeaponEvent : HandledEntityEventArgs
  158. {
  159. public EntityUid? Weapon;
  160. }