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

Martial Artist Rework + Fix MeleeWeapon Wizmerge Bugs #1560

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions Content.Client/Weapons/Melee/MeleeWeaponSystem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,9 @@ public override void Update(float frameTime)
if (mousePos.MapId != attackerPos.MapId ||
(attackerPos.Position - mousePos.Position).Length() > weapon.Range)
{
if (weapon.HeavyOnLightMiss)
ClientHeavyAttack(entity, coordinates, weaponUid, weapon);

return;
}

Expand All @@ -165,6 +168,12 @@ public override void Update(float frameTime)
if (Interaction.CombatModeCanHandInteract(entity, target))
return;

if (weapon.HeavyOnLightMiss && !CanDoLightAttack(entity, target, weapon, out _))
{
ClientHeavyAttack(entity, coordinates, weaponUid, weapon);
return;
}

RaisePredictiveEvent(new LightAttackEvent(GetNetEntity(target), GetNetEntity(weaponUid), GetNetCoordinates(coordinates)));
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ public sealed partial class BoxerComponent : Component
public DamageModifierSet UnarmedModifiers = default!;

[DataField("rangeBonus")]
public float RangeBonus = 1.5f;
public float RangeBonus = 1.0f;

/// <summary>
/// Damage modifier with boxing glove stam damage.
Expand Down
90 changes: 90 additions & 0 deletions Content.Server/Traits/TraitSystem.Functions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@
using Content.Shared.Mobs;
using Content.Shared.Damage.Components;
using Content.Shared.NPC.Systems;
using Content.Shared.Weapons.Melee;
using Robust.Shared.Audio;

namespace Content.Server.Traits;

Expand Down Expand Up @@ -585,3 +587,91 @@ public override void OnPlayerSpawn(EntityUid uid,
slowOnDamage.SpeedModifierThresholds = newSpeedModifierThresholds;
}
}

/// <summary>
/// Used for traits that modify unarmed damage on MeleeWeaponComponent.
/// </summary>
[UsedImplicitly]
public sealed partial class TraitModifyUnarmed : TraitFunction
{
// <summary>
// The sound played on hitting targets.
// </summary>
[DataField, AlwaysPushInheritance]
public SoundSpecifier? SoundHit;

// <summary>
// The animation to play on hit, for both light and power attacks.
// </summary>
[DataField, AlwaysPushInheritance]
public EntProtoId? Animation;

// <summary>
// Whether to set the power attack animation to be the same as the light attack.
// </summary>
[DataField, AlwaysPushInheritance]
public bool HeavyAnimationFromLight = true;

// <summary>
// The damage values of unarmed damage.
// </summary>
[DataField, AlwaysPushInheritance]
public DamageSpecifier? Damage;

// <summary>
// Additional damage added to the existing damage.
// </summary>
[DataField, AlwaysPushInheritance]
public DamageSpecifier? FlatDamageIncrease;

/// <summary>
/// Turns the left click into a power attack when the light attack misses.
/// </summary>
[DataField]
public bool? HeavyOnLightMiss;

// <summary>
// What to multiply the melee weapon range by.
// </summary>
[DataField, AlwaysPushInheritance]
public float? RangeModifier;

// <summary>
// What to multiply the attack rate by.
// </summary>
[DataField, AlwaysPushInheritance]
public float? AttackRateModifier;

public override void OnPlayerSpawn(EntityUid uid,
IComponentFactory factory,
IEntityManager entityManager,
ISerializationManager serializationManager)
{
if (!entityManager.TryGetComponent<MeleeWeaponComponent>(uid, out var melee))
return;

if (SoundHit != null)
melee.SoundHit = SoundHit;

if (Animation != null)
melee.Animation = Animation.Value;

if (HeavyAnimationFromLight)
melee.WideAnimation = melee.Animation;

if (Damage != null)
melee.Damage = Damage;

if (FlatDamageIncrease != null)
melee.Damage += FlatDamageIncrease;

if (HeavyOnLightMiss != null)
melee.HeavyOnLightMiss = HeavyOnLightMiss.Value;

if (RangeModifier != null)
melee.Range *= RangeModifier.Value;

if (AttackRateModifier != null)
melee.AttackRate *= AttackRateModifier.Value;
}
}
6 changes: 6 additions & 0 deletions Content.Shared/Weapons/Melee/MeleeWeaponComponent.cs
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,12 @@ public sealed partial class MeleeWeaponComponent : Component
[DataField]
public bool DisableClick = false;

/// <summary>
/// If true, when a light attack misses, the weapon will perform a power attack instead.
/// </summary>
[DataField, AutoNetworkedField]
public bool HeavyOnLightMiss = false;

/*
* Melee combat works based around 2 types of attacks:
* 1. Click attacks with left-click. This attacks whatever is under your mnouse
Expand Down
43 changes: 17 additions & 26 deletions Content.Shared/Weapons/Melee/SharedMeleeWeaponSystem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -68,8 +68,6 @@ public override void Initialize()
base.Initialize();

SubscribeLocalEvent<MeleeWeaponComponent, HandSelectedEvent>(OnMeleeSelected);
SubscribeLocalEvent<MeleeWeaponComponent, ShotAttemptedEvent>(OnMeleeShotAttempted);
SubscribeLocalEvent<MeleeWeaponComponent, GunShotEvent>(OnMeleeShot);
SubscribeLocalEvent<BonusMeleeDamageComponent, GetMeleeDamageEvent>(OnGetBonusMeleeDamage);
SubscribeLocalEvent<BonusMeleeDamageComponent, GetHeavyDamageModifierEvent>(OnGetBonusHeavyDamageModifier);
SubscribeLocalEvent<BonusMeleeAttackRateComponent, GetMeleeAttackRateEvent>(OnGetBonusMeleeAttackRate);
Expand All @@ -93,24 +91,6 @@ private void OnMapInit(EntityUid uid, MeleeWeaponComponent component, MapInitEve
#endif
}

private void OnMeleeShotAttempted(EntityUid uid, MeleeWeaponComponent comp, ref ShotAttemptedEvent args)
{
if (comp.NextAttack > Timing.CurTime)
args.Cancel();
}

private void OnMeleeShot(EntityUid uid, MeleeWeaponComponent component, ref GunShotEvent args)
{
if (!TryComp<GunComponent>(uid, out var gun))
return;

if (gun.NextFire > component.NextAttack)
{
component.NextAttack = gun.NextFire;
DirtyField(uid, component, nameof(MeleeWeaponComponent.NextAttack));
}
}

private void OnMeleeSelected(EntityUid uid, MeleeWeaponComponent component, HandSelectedEvent args)
{
var attackRate = GetAttackRate(uid, args.User, component);
Expand Down Expand Up @@ -351,6 +331,8 @@ private bool AttemptAttack(EntityUid user, EntityUid weaponUid, MeleeWeaponCompo
if (!CombatMode.IsInCombatMode(user))
return false;

var fireRateSwingModifier = 1f;

EntityUid? target = null;
switch (attack)
{
Expand All @@ -368,6 +350,9 @@ private bool AttemptAttack(EntityUid user, EntityUid weaponUid, MeleeWeaponCompo
if (weaponUid == target)
return false;

break;
case HeavyAttackEvent:
fireRateSwingModifier = weapon.HeavyRateModifier;
break;
case DisarmAttackEvent disarm:
if (disarm.Target != null && !TryGetEntity(disarm.Target, out target))
Expand All @@ -386,7 +371,7 @@ private bool AttemptAttack(EntityUid user, EntityUid weaponUid, MeleeWeaponCompo
}

// Windup time checked elsewhere.
var fireRate = TimeSpan.FromSeconds(1f / GetAttackRate(weaponUid, user, weapon));
var fireRate = TimeSpan.FromSeconds(GetAttackRate(weaponUid, user, weapon) * fireRateSwingModifier);
var swings = 0;

// TODO: If we get autoattacks then probably need a shotcounter like guns so we can do timing properly.
Expand Down Expand Up @@ -457,6 +442,16 @@ private bool AttemptAttack(EntityUid user, EntityUid weaponUid, MeleeWeaponCompo

protected abstract bool InRange(EntityUid user, EntityUid target, float range, ICommonSession? session);

protected bool CanDoLightAttack(EntityUid user, [NotNullWhen(true)] EntityUid? target, MeleeWeaponComponent component, [NotNullWhen(true)] out TransformComponent? targetXform, ICommonSession? session = null)
{
targetXform = null;
return !Deleted(target) &&
HasComp<DamageableComponent>(target) &&
TryComp<TransformComponent>(target, out targetXform) &&
// Not in LOS.
InRange(user, target.Value, component.Range, session);
}

protected virtual void DoLightAttack(EntityUid user, LightAttackEvent ev, EntityUid meleeUid, MeleeWeaponComponent component, ICommonSession? session)
{
// If I do not come back later to fix Light Attacks being Heavy Attacks you can throw me in the spider pit -Errant
Expand All @@ -465,11 +460,7 @@ protected virtual void DoLightAttack(EntityUid user, LightAttackEvent ev, Entity
var resistanceBypass = GetResistanceBypass(meleeUid, user, component);

// For consistency with wide attacks stuff needs damageable.
if (Deleted(target) ||
!HasComp<DamageableComponent>(target) ||
!TryComp(target, out TransformComponent? targetXform) ||
// Not in LOS.
!InRange(user, target.Value, component.Range, session))
if (!CanDoLightAttack(user, target, component, out var targetXform, session))
{
// Leave IsHit set to true, because the only time it's set to false
// is when a melee weapon is examined. Misses are inferred from an
Expand Down
8 changes: 5 additions & 3 deletions Resources/Locale/en-US/traits/traits.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -179,9 +179,11 @@ trait-description-Feeble =

trait-name-MartialArtist = Martial Artist
trait-description-MartialArtist =
You have received formal training in unarmed combat, whether with Fists, Feet, or Claws.
Your unarmed melee attacks have a small range increase, and deal 50% more damage.
This does not apply to any form of armed melee, only the weapons you were naturally born with.
You have received formal training in unarmed combat, whether with fists, claws, feet, or teeth.
Your unarmed melee attack is now considered a single-target [color=orange]Power Attack[/color], requiring less precision.
Additionally, your unarmed melee attacks deal [color=yellow]20%[/color] more damage, attack [color=yellow]25%[/color] faster, and have [color=yellow]10%[/color] increased range.
This has no effect on damage dealt with any form of armed melee.
The [color=#9FED58]Boxer[/color], [color=#9FED58]Martial Artist[/color], and [color=#9FED58]Gladiator[/color] jobs start with this trait by default.

trait-name-Vigor = Vigor
trait-description-Vigor =
Expand Down
5 changes: 5 additions & 0 deletions Resources/Prototypes/Entities/Mobs/Player/silicon_base.yml
Original file line number Diff line number Diff line change
Expand Up @@ -256,6 +256,11 @@
damage:
types:
Blunt: 6 # It's tough.
heavyRateModifier: 1
heavyDamageBaseModifier: 1
heavyPartDamageMultiplier: 1
heavyStaminaCost: 0
maxTargets: 1
- type: MobPrice
price: 1500 # Kidnapping a living person and selling them for cred is a good move.
deathPenalty: 0.01 # However they really ought to be living and intact, otherwise they're worth 100x less.
Expand Down
5 changes: 5 additions & 0 deletions Resources/Prototypes/Entities/Mobs/Species/base.yml
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,11 @@
damage:
types:
Blunt: 5
heavyRateModifier: 1
heavyDamageBaseModifier: 1
heavyPartDamageMultiplier: 1
heavyStaminaCost: 0
maxTargets: 1
- type: SleepEmitSound
- type: SSDIndicator
- type: StandingState
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,9 @@
department: Security
min: 21600
special:
- !type:AddComponentSpecial
components:
- type: Boxer
modifiers:
coefficients: # These only apply to unarmed
Blunt: 1.5
Slash: 1.5
Piercing: 1.5
- !type:AddTraitSpecial
traits:
- MartialArtist

- type: startingGear
id: NyanoGladiatorGear
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,9 @@
- Theatre # DeltaV - Add Theatre access
- Boxer # DeltaV - Add Boxer access
special:
- !type:AddComponentSpecial
components:
- type: Boxer
modifiers:
coefficients: # These only apply to unarmed
Blunt: 1.5
Slash: 1.5
Piercing: 1.5
- !type:AddTraitSpecial
traits:
- MartialArtist

- type: startingGear
id: MartialArtistGear
Expand Down
11 changes: 3 additions & 8 deletions Resources/Prototypes/Roles/Jobs/Wildcards/boxer.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,9 @@
- Theatre # DeltaV - Add Theatre access
- Boxer # DeltaV - Add Boxer access
special: # Nyanotrasen - BoxerComponent, see Content.Server/Nyanotrasen/Abilities/Boxer/Boxer/BoxerComponent.cs
- !type:AddComponentSpecial
components:
- type: Boxer
modifiers:
coefficients: # These only apply to unarmed
Blunt: 1.5
Slash: 1.5
Piercing: 1.5
- !type:AddTraitSpecial
traits:
- MartialArtist

- type: startingGear
id: BoxerGear
Expand Down
Loading
Loading