Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Melee Pt2 #693

Merged
merged 14 commits into from
Aug 10, 2024
5 changes: 2 additions & 3 deletions Content.Client/Weapons/Melee/MeleeWeaponSystem.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using System.Linq;
using Content.Client.Gameplay;
using Content.Shared.CCVar;
using Content.Shared.CombatMode;
using Content.Shared.Effects;
using Content.Shared.Hands.Components;
Expand All @@ -16,8 +17,6 @@
using Robust.Shared.Input;
using Robust.Shared.Map;
using Robust.Shared.Player;
using Robust.Shared.Prototypes;
using Robust.Shared.Timing;

namespace Content.Client.Weapons.Melee;

Expand Down Expand Up @@ -228,7 +227,7 @@ private void ClientHeavyAttack(EntityUid user, EntityCoordinates coordinates, En
// This should really be improved. GetEntitiesInArc uses pos instead of bounding boxes.
// Server will validate it with InRangeUnobstructed.
var entities = GetNetEntityList(ArcRayCast(userPos, direction.ToWorldAngle(), component.Angle, distance, userXform.MapID, user).ToList());
RaisePredictiveEvent(new HeavyAttackEvent(GetNetEntity(meleeUid), entities.GetRange(0, Math.Min(MaxTargets, entities.Count)), GetNetCoordinates(coordinates)));
RaisePredictiveEvent(new HeavyAttackEvent(GetNetEntity(meleeUid), entities.GetRange(0, Math.Min(component.MaxTargets, entities.Count)), GetNetCoordinates(coordinates)));
}

private void OnMeleeLunge(MeleeLungeEvent ev)
Expand Down
2 changes: 1 addition & 1 deletion Content.Server/Execution/ExecutionSystem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -251,7 +251,7 @@ private void OnDoafterMelee(EntityUid uid, SharpComponent component, DoAfterEven
return;

_damageableSystem.TryChangeDamage(victim, melee.Damage * DamageModifier, true);
_audioSystem.PlayEntity(melee.HitSound, Filter.Pvs(weapon), weapon, true, AudioParams.Default);
_audioSystem.PlayEntity(melee.SoundHit, Filter.Pvs(weapon), weapon, true, AudioParams.Default);

if (attacker == victim)
{
Expand Down
11 changes: 9 additions & 2 deletions Content.Server/Weapons/Melee/MeleeWeaponSystem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,9 @@ private void OnMeleeExamineDamage(EntityUid uid, MeleeWeaponComponent component,
return;

_damageExamine.AddDamageExamine(args.Message, damageSpec, Loc.GetString("damage-melee"));

if (damageSpec * component.HeavyDamageBaseModifier != damageSpec)
_damageExamine.AddDamageExamine(args.Message, damageSpec * component.HeavyDamageBaseModifier, Loc.GetString("damage-melee-heavy"));
}

protected override bool ArcRaySuccessful(EntityUid targetUid, Vector2 position, Angle angle, Angle arcWidth, float range, MapId mapId,
Expand Down Expand Up @@ -132,7 +135,7 @@ protected override bool DoDisarm(EntityUid user, DisarmAttackEvent ev, EntityUid
if (attemptEvent.Cancelled)
return false;

var chance = CalculateDisarmChance(user, target, inTargetHand, combatMode) * _contests.MassContest(user, target);
var chance = CalculateDisarmChance(user, target, inTargetHand, combatMode);

if (_random.Prob(chance))
{
Expand Down Expand Up @@ -212,7 +215,11 @@ private float CalculateDisarmChance(EntityUid disarmer, EntityUid disarmed, Enti
chance += malus.Malus;
}

return Math.Clamp(chance, 0f, 1f);
return Math.Clamp(chance
* _contests.MassContest(disarmer, disarmed, false, 0.5f)
* _contests.StaminaContest(disarmer, disarmed, false, 0.5f)
* _contests.HealthContest(disarmer, disarmed, false, 0.5f),
0f, 1f);
}

public override void DoLunge(EntityUid user, EntityUid weapon, Angle angle, Vector2 localPos, string? animation, bool predicted = true)
Expand Down
2 changes: 1 addition & 1 deletion Content.Server/Zombies/ZombieSystem.Transform.cs
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,7 @@ public void ZombifyEntity(EntityUid target, MobStateComponent? mobState = null)
melee.AltDisarm = false;
melee.Range = 1.2f;
melee.Angle = 0.0f;
melee.HitSound = zombiecomp.BiteSound;
melee.SoundHit = zombiecomp.BiteSound;

if (mobState.CurrentState == MobState.Alive)
{
Expand Down
3 changes: 2 additions & 1 deletion Content.Shared/Damage/Systems/StaminaSystem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -245,7 +245,8 @@ public bool TryTakeStamina(EntityUid uid, float value, StaminaComponent? compone
public void TakeStaminaDamage(EntityUid uid, float value, StaminaComponent? component = null,
EntityUid? source = null, EntityUid? with = null, bool visual = true, SoundSpecifier? sound = null)
{
if (!Resolve(uid, ref component, false))
if (!Resolve(uid, ref component, false)
|| value == 0)
return;

var ev = new BeforeStaminaDamageEvent(value);
Expand Down
6 changes: 3 additions & 3 deletions Content.Shared/Weapons/Melee/MeleeSoundSystem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ public sealed class MeleeSoundSystem : EntitySystem
/// </summary>
public void PlaySwingSound(EntityUid userUid, EntityUid weaponUid, MeleeWeaponComponent weaponComponent)
{
_audio.PlayPredicted(weaponComponent.SwingSound, weaponUid, userUid);
_audio.PlayPredicted(weaponComponent.SoundSwing, weaponUid, userUid);
}

/// <summary>
Expand All @@ -32,8 +32,8 @@ public void PlaySwingSound(EntityUid userUid, EntityUid weaponUid, MeleeWeaponCo
/// <param name="hitSoundOverride"> A sound can be supplied by the <see cref="MeleeHitEvent"/> itself to override everything else </param>
public void PlayHitSound(EntityUid targetUid, EntityUid? userUid, string? damageType, SoundSpecifier? hitSoundOverride, MeleeWeaponComponent weaponComponent)
{
var hitSound = weaponComponent.HitSound;
var noDamageSound = weaponComponent.NoDamageSound;
var hitSound = weaponComponent.SoundHit;
var noDamageSound = weaponComponent.SoundNoDamage;

var playedSound = false;

Expand Down
71 changes: 44 additions & 27 deletions Content.Shared/Weapons/Melee/MeleeWeaponComponent.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,28 +18,26 @@ public sealed partial class MeleeWeaponComponent : Component
/// <summary>
/// Does this entity do a disarm on alt attack.
/// </summary>
[DataField, ViewVariables(VVAccess.ReadWrite), AutoNetworkedField]
[DataField, 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]
[DataField]
public bool ResetOnHandSelected = true;

/*
Expand All @@ -51,77 +49,98 @@ public sealed partial class MeleeWeaponComponent : Component
/// <summary>
/// How many times we can attack per second.
/// </summary>
[ViewVariables(VVAccess.ReadWrite), DataField, AutoNetworkedField]
[DataField, AutoNetworkedField]
public float AttackRate = 1f;

/// <summary>
/// When power attacking, the swing speed (in attacks per second) is multiplied by this amount
/// </summary>
[DataField, AutoNetworkedField]
public float HeavyRateModifier = 0.8f;
/// <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]
[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]
[DataField, AutoNetworkedField]
public bool AutoAttack;

/// <summary>
/// Base damage for this weapon. Can be modified via heavy damage or other means.
/// </summary>
[DataField(required: true)]
[ViewVariables(VVAccess.ReadWrite), AutoNetworkedField]
[AutoNetworkedField]
public DamageSpecifier Damage = default!;

[DataField]
[ViewVariables(VVAccess.ReadWrite)]
public FixedPoint2 BluntStaminaDamageFactor = FixedPoint2.New(0.5f);
[DataField, AutoNetworkedField]
public FixedPoint2 BluntStaminaDamageFactor = FixedPoint2.New(1f);

/// <summary>
/// Multiplies damage by this amount for single-target attacks.
/// </summary>
[ViewVariables(VVAccess.ReadWrite), DataField]
[DataField, AutoNetworkedField]
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]
[DataField, AutoNetworkedField]
public float Range = 1.5f;

/// <summary>
/// Attack range for heavy swings
/// </summary>
[DataField, AutoNetworkedField]
public float HeavyRangeModifier = 1f;

/// <summary>
/// Weapon damage is multiplied by this amount for heavy swings
/// </summary>
[DataField, AutoNetworkedField]
public float HeavyDamageBaseModifier = 1.2f;

/// <summary>
/// Total width of the angle for wide attacks.
/// </summary>
[ViewVariables(VVAccess.ReadWrite), DataField]
[DataField, AutoNetworkedField]
public Angle Angle = Angle.FromDegrees(60);

[ViewVariables(VVAccess.ReadWrite), DataField, AutoNetworkedField]
[DataField, AutoNetworkedField]
public EntProtoId Animation = "WeaponArcPunch";

[ViewVariables(VVAccess.ReadWrite), DataField, AutoNetworkedField]
[DataField, AutoNetworkedField]
public EntProtoId WideAnimation = "WeaponArcSlash";

/// <summary>
/// Rotation of the animation.
/// 0 degrees means the top faces the attacker.
/// </summary>
[ViewVariables(VVAccess.ReadWrite), DataField]
[DataField, AutoNetworkedField]
public Angle WideAnimationRotation = Angle.Zero;

[ViewVariables(VVAccess.ReadWrite), DataField]
[DataField]
public bool SwingLeft;

[DataField, AutoNetworkedField]
public float HeavyStaminaCost = 20f;

[DataField, AutoNetworkedField]
public int MaxTargets = 5;


// 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")
[DataField, AutoNetworkedField]
public SoundSpecifier SoundSwing { get; set; } = new SoundPathSpecifier("/Audio/Weapons/punchmiss.ogg")
{
Params = AudioParams.Default.WithVolume(-3f).WithVariation(0.025f),
};
Expand All @@ -130,16 +149,14 @@ public sealed partial class MeleeWeaponComponent : Component
// 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;
[DataField, AutoNetworkedField]
public SoundSpecifier? SoundHit;

/// <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");
[DataField, AutoNetworkedField]
public SoundSpecifier SoundNoDamage { get; set; } = new SoundCollectionSpecifier("WeakHit");
}

/// <summary>
Expand Down
Loading
Loading