* melee executions * fix damage bug * cleanup * address reviews hopefully * resistance bypass mechanic * component changes * self executions (not finished yet) * self execs part two * ok i fixed things (still not finished) * finish everything * review stuff * nuke if (kind = special) * more review stuffs * Make suicide system much less hardcoded and make much more use of events * Fix a dumb bug I introduced * self execution popups * Integration tests * Why did they even take 0.5 blunt damage? * More consistent integration tests * Destructive equals true * Allow it to dirty-dispose * IS THIS WHAT YOU WANT? * FRESH AND CLEAN * modifier to multiplier * don't jinx the integration tests * no file-scoped namespace * Move the rest of execution to shared, create SuicideGhostEvent * handled * Get rid of unused code and add a comment * ghost before suicide * stop cat suicides * popup fix + small suicide change * make it a bit better --------- Co-authored-by: Plykiya <58439124+Plykiya@users.noreply.github.com>
167 lines
5.9 KiB
C#
167 lines
5.9 KiB
C#
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;
|
|
|
|
/// <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;
|
|
}
|
|
|
|
/// <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;
|
|
}
|