Better melee combat (#542)

* - add: NextMobAttack, EquipCooldown.

* - fix: Some combat fixes.

* - add: Telebaton.

* - add: Stun baton rework.

* - tweak: Reduce melee range.

* - add: Rework melee block system.

* - add: ExaminedEvent.
This commit is contained in:
Aviu00
2024-08-02 11:50:26 +00:00
committed by GitHub
parent 6ca036189e
commit 27268d4e28
83 changed files with 772 additions and 222 deletions

View File

@@ -6,6 +6,7 @@ using Content.Server.Stunnable;
using Content.Server.Temperature.Components;
using Content.Server.Temperature.Systems;
using Content.Server.Damage.Components;
using Content.Shared._White.Blocking;
using Content.Shared.ActionBlocker;
using Content.Shared.Alert;
using Content.Shared.Atmos;

View File

@@ -17,6 +17,7 @@ using Content.Server.Chemistry.Containers.EntitySystems;
using Robust.Shared.GameStates;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using Content.Shared._White.Blocking;
using Robust.Server.Audio;
namespace Content.Server.Chemistry.EntitySystems;
@@ -32,7 +33,8 @@ public sealed class HypospraySystem : SharedHypospraySystem
base.Initialize();
SubscribeLocalEvent<HyposprayComponent, AfterInteractEvent>(OnAfterInteract);
SubscribeLocalEvent<HyposprayComponent, MeleeHitEvent>(OnAttack);
SubscribeLocalEvent<HyposprayComponent, MeleeHitEvent>(OnAttack,
after: new[] {typeof(MeleeBlockSystem)}); // WD EDIT
SubscribeLocalEvent<HyposprayComponent, UseInHandEvent>(OnUseInHand);
}
@@ -68,6 +70,9 @@ public sealed class HypospraySystem : SharedHypospraySystem
public void OnAttack(Entity<HyposprayComponent> entity, ref MeleeHitEvent args)
{
if (args.Handled) // WD
return;
if (!args.HitEntities.Any())
return;

View File

@@ -2,6 +2,7 @@ using Content.Server.Body.Components;
using Content.Server.Body.Systems;
using Content.Server.Chemistry.Components;
using Content.Server.Chemistry.Containers.EntitySystems;
using Content.Shared._White.Blocking;
using Content.Shared.Inventory;
using Content.Shared.Popups;
using Content.Shared.Projectiles;
@@ -28,7 +29,8 @@ public sealed class SolutionInjectOnCollideSystem : EntitySystem
base.Initialize();
SubscribeLocalEvent<SolutionInjectOnProjectileHitComponent, ProjectileHitEvent>(HandleProjectileHit);
SubscribeLocalEvent<SolutionInjectOnEmbedComponent, EmbedEvent>(HandleEmbed);
SubscribeLocalEvent<MeleeChemicalInjectorComponent, MeleeHitEvent>(HandleMeleeHit);
SubscribeLocalEvent<MeleeChemicalInjectorComponent, MeleeHitEvent>(HandleMeleeHit,
after: new[] {typeof(MeleeBlockSystem)}); // WD EDIT
}
private void HandleProjectileHit(Entity<SolutionInjectOnProjectileHitComponent> entity, ref ProjectileHitEvent args)
@@ -43,6 +45,8 @@ public sealed class SolutionInjectOnCollideSystem : EntitySystem
private void HandleMeleeHit(Entity<MeleeChemicalInjectorComponent> entity, ref MeleeHitEvent args)
{
if (args.Handled) // WD
return;
// MeleeHitEvent is weird, so we have to filter to make sure we actually
// hit something and aren't just examining the weapon.
if (args.IsHit)

View File

@@ -1,5 +1,6 @@
using Content.Server.Chemistry.Containers.EntitySystems;
using Content.Server.Fluids.Components;
using Content.Shared._White.Blocking;
using Content.Shared.Chemistry.Components;
using Content.Shared.Chemistry.EntitySystems;
using Content.Shared.Chemistry.Reaction;
@@ -28,7 +29,8 @@ public sealed partial class PuddleSystem
SubscribeLocalEvent<SpillableComponent, LandEvent>(SpillOnLand);
// Openable handles the event if it's closed
SubscribeLocalEvent<SpillableComponent, MeleeHitEvent>(SplashOnMeleeHit, after: [typeof(OpenableSystem)]);
SubscribeLocalEvent<SpillableComponent, MeleeHitEvent>(
SplashOnMeleeHit, before: new[] {typeof(MeleeBlockSystem)}, after:[typeof(OpenableSystem)]); // WD EDIT
SubscribeLocalEvent<SpillableComponent, GotEquippedEvent>(OnGotEquipped);
SubscribeLocalEvent<SpillableComponent, GotUnequippedEvent>(OnGotUnequipped);
SubscribeLocalEvent<SpillableComponent, SolutionContainerOverflowEvent>(OnOverflow);

View File

@@ -3,6 +3,7 @@ using Content.Server.DoAfter;
using Content.Server.Fluids.EntitySystems;
using Content.Server.Forensics.Components;
using Content.Server.Popups;
using Content.Shared._White.Blocking;
using Content.Shared.Chemistry.Components;
using Content.Shared.DoAfter;
using Content.Shared.Forensics;
@@ -27,7 +28,8 @@ namespace Content.Server.Forensics
SubscribeLocalEvent<DnaComponent, MapInitEvent>(OnDNAInit);
SubscribeLocalEvent<DnaComponent, BeingGibbedEvent>(OnBeingGibbed);
SubscribeLocalEvent<ForensicsComponent, MeleeHitEvent>(OnMeleeHit);
SubscribeLocalEvent<ForensicsComponent, MeleeHitEvent>(OnMeleeHit,
after: new[] {typeof(MeleeBlockSystem)}); // WD EDIT
SubscribeLocalEvent<ForensicsComponent, GotRehydratedEvent>(OnRehydrated);
SubscribeLocalEvent<CleansForensicsComponent, AfterInteractEvent>(OnAfterInteract, after: new[] { typeof(AbsorbentSystem) });
SubscribeLocalEvent<ForensicsComponent, CleanForensicsDoAfterEvent>(OnCleanForensicsDoAfter);
@@ -61,6 +63,8 @@ namespace Content.Server.Forensics
private void OnMeleeHit(EntityUid uid, ForensicsComponent component, MeleeHitEvent args)
{
if (args.Handled) // WD EDIT
return;
if((args.BaseDamage.DamageDict.TryGetValue("Blunt", out var bluntDamage) && bluntDamage.Value > 0) ||
(args.BaseDamage.DamageDict.TryGetValue("Slash", out var slashDamage) && slashDamage.Value > 0) ||
(args.BaseDamage.DamageDict.TryGetValue("Piercing", out var pierceDamage) && pierceDamage.Value > 0))

View File

@@ -101,7 +101,7 @@ public sealed partial class NPCCombatSystem
return;
}
if (weapon.NextAttack > curTime || !Enabled)
if (weapon.NextAttack > curTime || weapon.NextMobAttack > curTime || !Enabled) // WD EDIT
return;
if (_random.Prob(component.MissChance) &&

View File

@@ -143,7 +143,7 @@ public sealed class NPCJukeSystem : EntitySystem
if (!_melee.TryGetWeapon(uid, out var weaponUid, out var weapon))
return;
var cdRemaining = weapon.NextAttack - _timing.CurTime;
var cdRemaining = weapon.NextMobAttack - _timing.CurTime; // WD EDIT
var attackCooldown = TimeSpan.FromSeconds(1f / _melee.GetAttackRate(weaponUid, uid, weapon));
// Might as well get in range.

View File

@@ -1,3 +1,4 @@
using Content.Shared._White.Blocking;
using Content.Shared.Weapons.Melee.Events;
using Robust.Shared.Random;
using Robust.Shared.Audio.Systems;

View File

@@ -6,6 +6,7 @@ using Content.Server.Cloning;
using Content.Server.Drone.Components;
using Content.Server.Emoting.Systems;
using Content.Server.Speech.EntitySystems;
using Content.Shared._White.Blocking;
using Content.Shared.Bed.Sleep;
using Content.Shared.Cloning;
using Content.Shared.Damage;
@@ -56,7 +57,8 @@ namespace Content.Server.Zombies
SubscribeLocalEvent<ZombieComponent, EmoteEvent>(OnEmote, before:
new[] { typeof(VocalSystem), typeof(BodyEmotesSystem) });
SubscribeLocalEvent<ZombieComponent, MeleeHitEvent>(OnMeleeHit);
SubscribeLocalEvent<ZombieComponent, MeleeHitEvent>(OnMeleeHit,
after: new[] {typeof(MeleeBlockSystem)}); // WD EDIT
SubscribeLocalEvent<ZombieComponent, MobStateChangedEvent>(OnMobState);
SubscribeLocalEvent<ZombieComponent, CloningEvent>(OnZombieCloning);
SubscribeLocalEvent<ZombieComponent, TryingToSleepEvent>(OnSleepAttempt);
@@ -207,6 +209,9 @@ namespace Content.Server.Zombies
private void OnMeleeHit(EntityUid uid, ZombieComponent component, MeleeHitEvent args)
{
if (args.Handled) // WD EDIT
return;
if (!TryComp<ZombieComponent>(args.User, out _))
return;

View File

@@ -31,7 +31,7 @@ public sealed class ReturnItemOnThrowSystem : EntitySystem
if (!HasComp<MobStateComponent>(args.Target))
return;
if (!_stun.IsParalyzed(args.Target) && !isCultist && !_holyWeapon.IsHoldingHolyWeapon(args.Target))
if (!isCultist && !_holyWeapon.IsHoldingHolyWeapon(args.Target))
{
_stun.TryParalyze(args.Target, TimeSpan.FromSeconds(component.StunTime), true);
}

View File

@@ -1,4 +1,5 @@
using System.Linq;
using Content.Shared._White.Blocking;
using Content.Shared._White.Cult.Components;
using Content.Shared.Containers.ItemSlots;
using Content.Shared.Mind.Components;
@@ -22,7 +23,7 @@ public partial class CultSystem
SubscribeLocalEvent<ConstructShellComponent, ComponentInit>(OnShellInit);
SubscribeLocalEvent<ConstructShellComponent, ComponentRemove>(OnShellRemove);
SubscribeLocalEvent<ConstructShellComponent, ConstructFormSelectedEvent>(OnShellSelected);
SubscribeLocalEvent<ConstructComponent, MeleeHitEvent>(OnMeleeHit);
SubscribeLocalEvent<ConstructComponent, MeleeHitEvent>(OnMeleeHit, before: new []{typeof(MeleeBlockSystem)});
}
private void OnMeleeHit(Entity<ConstructComponent> ent, ref MeleeHitEvent args)

View File

@@ -1,6 +1,7 @@
using Content.Server.Body.Components;
using Content.Server.Body.Systems;
using Content.Server.Popups;
using Content.Shared._White.Blocking;
using Content.Shared.Damage;
using Content.Shared.Damage.Prototypes;
using Content.Shared.Examine;
@@ -25,7 +26,7 @@ public sealed class CritSystem : EntitySystem
base.Initialize();
SubscribeLocalEvent<CritComponent, ExaminedEvent>(OnExamine);
SubscribeLocalEvent<CritComponent, MeleeHitEvent>(HandleHit);
SubscribeLocalEvent<CritComponent, MeleeHitEvent>(HandleHit, before: new [] {typeof(MeleeBlockSystem)});
SubscribeLocalEvent<CritComponent, GetMeleeAttackRateEvent>(GetMeleeAttackRate);
SubscribeLocalEvent<BloodLustComponent, RefreshMovementSpeedModifiersEvent>(OnRefreshMoveSpeed);
}

View File

@@ -1,8 +0,0 @@
namespace Content.Server._White.Other.MeleeBlockSystem;
[RegisterComponent]
public sealed partial class MeleeBlockComponent : Component
{
[DataField, ViewVariables(VVAccess.ReadWrite)]
public float BlockChance = 0.4f;
}

View File

@@ -1,37 +0,0 @@
using Content.Shared.Hands.Components;
using Content.Shared.Popups;
using Content.Shared.Weapons.Melee.Events;
using Robust.Shared.Audio;
using Robust.Shared.Audio.Systems;
using Robust.Shared.Random;
namespace Content.Server._White.Other.MeleeBlockSystem;
public sealed class MeleeBlockSystem : EntitySystem
{
[Dependency] private readonly IRobustRandom _random = default!;
[Dependency] private readonly SharedAudioSystem _audio = default!;
[Dependency] private readonly SharedPopupSystem _popupSystem = default!;
public override void Initialize()
{
base.Initialize();
SubscribeLocalEvent<HandsComponent, MeleeBlockAttemptEvent>(OnBlockAttempt);
}
private void OnBlockAttempt(Entity<HandsComponent> ent, ref MeleeBlockAttemptEvent args)
{
if (ent.Owner == args.Attacker ||
!TryComp(ent.Comp.ActiveHandEntity, out MeleeBlockComponent? blockComponent) ||
!_random.Prob(blockComponent.BlockChance))
return;
args.Blocked = true;
_popupSystem.PopupEntity("заблокировал!", ent);
_audio.PlayPvs(new SoundPathSpecifier("/Audio/Weapons/block_metal1.ogg"), ent,
AudioParams.Default.WithVariation(0.25f));
}
}

View File

@@ -1,3 +1,4 @@
using Content.Shared._White.Blocking;
using Content.Shared.Damage;
using Content.Shared.Damage.Prototypes;
using Content.Shared.Weapons.Melee.Events;
@@ -15,7 +16,7 @@ public sealed class RandomDamageSystem : EntitySystem
{
base.Initialize();
SubscribeLocalEvent<RandomDamageComponent, MeleeHitEvent>(HandleHit);
SubscribeLocalEvent<RandomDamageComponent, MeleeHitEvent>(HandleHit, before: new [] {typeof(MeleeBlockSystem)});
}
private void HandleHit(Entity<RandomDamageComponent> ent, ref MeleeHitEvent args)

View File

@@ -4,7 +4,7 @@ namespace Content.Server._White.Stunprod;
public sealed partial class StunprodComponent : Component
{
[DataField, ViewVariables(VVAccess.ReadWrite)]
public float EnergyPerUse { get; set; } = 72;
public float EnergyPerUse { get; set; } = 144;
[DataField]
public bool HasHeldPrefix = true;