Skip to content

Commit

Permalink
[Port] Melee Block / Блок В Ближнем Бою (#10)
Browse files Browse the repository at this point in the history
* add: melee block

* add: RU loc

* test

* fix

* test

* test
  • Loading branch information
Spatison authored Aug 31, 2024
1 parent 3ec79ec commit e5b1e86
Show file tree
Hide file tree
Showing 38 changed files with 252 additions and 6 deletions.
7 changes: 6 additions & 1 deletion Content.Server/Chemistry/EntitySystems/HypospraySystem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
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;
Expand All @@ -32,7 +33,8 @@ public override void Initialize()
base.Initialize();

SubscribeLocalEvent<HyposprayComponent, AfterInteractEvent>(OnAfterInteract);
SubscribeLocalEvent<HyposprayComponent, MeleeHitEvent>(OnAttack);
SubscribeLocalEvent<HyposprayComponent, MeleeHitEvent>(OnAttack,
after: new[] {typeof(MeleeBlockSystem)}); // WD EDIT
SubscribeLocalEvent<HyposprayComponent, UseInHandEvent>(OnUseInHand);
}

Expand Down Expand Up @@ -68,6 +70,9 @@ public void OnAfterInteract(Entity<HyposprayComponent> entity, ref AfterInteract

public void OnAttack(Entity<HyposprayComponent> entity, ref MeleeHitEvent args)
{
if (args.Handled) // WD EDIT
return;

if (!args.HitEntities.Any())
return;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
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;
Expand All @@ -28,7 +29,8 @@ public override void Initialize()
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)
Expand All @@ -43,6 +45,9 @@ private void HandleEmbed(Entity<SolutionInjectOnEmbedComponent> entity, ref Embe

private void HandleMeleeHit(Entity<MeleeChemicalInjectorComponent> entity, ref MeleeHitEvent args)
{
if (args.Handled) // WD EDIT
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)
Expand Down
Original file line number Diff line number Diff line change
@@ -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;
Expand Down Expand Up @@ -28,7 +29,8 @@ protected override void InitializeSpillable()

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);
Expand Down
7 changes: 6 additions & 1 deletion Content.Server/Forensics/Systems/ForensicsSystem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
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;
Expand Down Expand Up @@ -31,7 +32,8 @@ public override void Initialize()
SubscribeLocalEvent<ScentComponent, MapInitEvent>(OnScentInit);

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);
Expand Down Expand Up @@ -87,6 +89,9 @@ private void OnBeingGibbed(EntityUid uid, DnaComponent component, BeingGibbedEve

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))
Expand Down
7 changes: 6 additions & 1 deletion Content.Server/Zombies/ZombieSystem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
using Content.Server.Chat.Systems;
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;
Expand Down Expand Up @@ -56,7 +57,8 @@ public override void Initialize()
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);
Expand Down Expand Up @@ -209,6 +211,9 @@ private float GetZombieInfectionChance(EntityUid uid, ZombieComponent component)

private void OnMeleeHit(EntityUid uid, ZombieComponent component, MeleeHitEvent args)
{
if (args.Handled) // WD EDIT
return;

if (!TryComp<ZombieComponent>(args.User, out _))
return;

Expand Down
1 change: 1 addition & 0 deletions Content.Shared/Alert/AlertType.cs
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ public enum AlertType : byte
BorgCrit,
BorgDead,
Offer,
RecentlyBlocked, // WD EDIT
}

}
27 changes: 27 additions & 0 deletions Content.Shared/Blocking/BlockingSystem.User.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
using Content.Shared._White.Blocking;
using Content.Shared.Damage;
using Content.Shared.Damage.Prototypes;
using Content.Shared.Item.ItemToggle.Components;
using Robust.Shared.Audio;
using Robust.Shared.Audio.Systems;
using Robust.Shared.Containers;
Expand All @@ -20,7 +22,32 @@ private void InitializeUser()
SubscribeLocalEvent<BlockingUserComponent, ContainerGettingInsertedAttemptEvent>(OnInsertAttempt);
SubscribeLocalEvent<BlockingUserComponent, AnchorStateChangedEvent>(OnAnchorChanged);
SubscribeLocalEvent<BlockingUserComponent, EntityTerminatingEvent>(OnEntityTerminating);

SubscribeLocalEvent<BlockingUserComponent, MeleeBlockAttemptEvent>(OnMeleeBlockAttempt); // WD
}

// WD START
private void OnMeleeBlockAttempt(Entity<BlockingUserComponent> ent, ref MeleeBlockAttemptEvent args)
{
if (args.Handled)
return;

var uid = ent.Comp.BlockingItem;
if (!TryComp(uid, out BlockingComponent? blocking) || !blocking.IsBlocking)
return;

if (TryComp(uid.Value, out ItemToggleComponent? toggle) && !toggle.Activated)
return;

if (!TryComp(uid.Value, out DamageableComponent? damageable))
return;

_audio.PlayPredicted(blocking.BlockSound, ent, args.Attacker);
_popupSystem.PopupPredicted(Loc.GetString("melee-block-event-blocked"), ent, args.Attacker);
_damageable.TryChangeDamage(uid.Value, args.Damage, damageable: damageable);
args.Handled = true;
}
// WD END

private void OnParentChanged(EntityUid uid, BlockingUserComponent component, ref EntParentChangedMessage args)
{
Expand Down
3 changes: 3 additions & 0 deletions Content.Shared/Damage/Systems/StaminaSystem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,9 @@ private void OnDisarmed(EntityUid uid, StaminaComponent component, DisarmedEvent

private void OnMeleeHit(EntityUid uid, StaminaDamageOnHitComponent component, MeleeHitEvent args)
{
if (args.Handled) // WD EDIT
return;

if (!args.IsHit ||
!args.HitEntities.Any() ||
component.Damage <= 0f)
Expand Down
3 changes: 3 additions & 0 deletions Content.Shared/Weapons/Melee/MeleeThrowOnHitSystem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,9 @@ public override void Initialize()

private void OnMeleeHit(Entity<MeleeThrowOnHitComponent> ent, ref MeleeHitEvent args)
{
if (args.Handled) // WD EDIT
return;

var (_, comp) = ent;
if (!args.IsHit)
return;
Expand Down
5 changes: 5 additions & 0 deletions Content.Shared/Weapons/Melee/MeleeWeaponComponent.cs
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,11 @@ public sealed partial class MeleeWeaponComponent : Component
/// </summary>
[DataField, AutoNetworkedField]
public SoundSpecifier SoundNoDamage { get; set; } = new SoundCollectionSpecifier("WeakHit");

// WD EDIT START
[ViewVariables(VVAccess.ReadWrite), DataField, AutoNetworkedField]
public bool CanBeBlocked = true;
// WD EDIT END
}

/// <summary>
Expand Down
6 changes: 6 additions & 0 deletions Content.Shared/_White/Blocking/BlockBlockerComponent.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
using Robust.Shared.GameStates;

namespace Content.Shared._White.Blocking;

[RegisterComponent, NetworkedComponent]
public sealed partial class BlockBlockerComponent : Component;
24 changes: 24 additions & 0 deletions Content.Shared/_White/Blocking/MeleeBlockComponent.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
using Content.Shared.Damage;
using Robust.Shared.Audio;

namespace Content.Shared._White.Blocking;

[RegisterComponent]
public sealed partial class MeleeBlockComponent : Component
{
[DataField, ViewVariables(VVAccess.ReadWrite)]
public TimeSpan Delay = TimeSpan.FromSeconds(3.1);

[DataField]
public SoundSpecifier BlockSound = new SoundPathSpecifier("/Audio/Weapons/block_metal1.ogg")
{
Params = AudioParams.Default.WithVariation(0.25f)
};
}

public sealed class MeleeBlockAttemptEvent(EntityUid attacker, DamageSpecifier damage) : HandledEntityEventArgs
{
public EntityUid Attacker = attacker;

public DamageSpecifier Damage = damage;
}
95 changes: 95 additions & 0 deletions Content.Shared/_White/Blocking/MeleeBlockSystem.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
using Content.Shared.Blocking;
using Content.Shared.Damage;
using Content.Shared.Damage.Systems;
using Content.Shared.Examine;
using Content.Shared.Hands.Components;
using Content.Shared.Item.ItemToggle.Components;
using Content.Shared.Popups;
using Content.Shared.StatusEffect;
using Content.Shared.Weapons.Melee;
using Content.Shared.Weapons.Melee.Events;
using Robust.Shared.Audio.Systems;
using Robust.Shared.Timing;

namespace Content.Shared._White.Blocking;

public sealed class MeleeBlockSystem : EntitySystem
{
[Dependency] private readonly IGameTiming _timing = default!;
[Dependency] private readonly DamageableSystem _damageable = default!;
[Dependency] private readonly SharedAudioSystem _audio = default!;
[Dependency] private readonly SharedPopupSystem _popupSystem = default!;
[Dependency] private readonly StatusEffectsSystem _statusEffect = default!;

public override void Initialize()
{
base.Initialize();

SubscribeLocalEvent<HandsComponent, MeleeBlockAttemptEvent>(OnBlockAttempt,
after: new[] {typeof(BlockingSystem)});
SubscribeLocalEvent<MeleeWeaponComponent, MeleeHitEvent>(OnHit,
before: new[] {typeof(StaminaSystem), typeof(MeleeThrowOnHitSystem)});
SubscribeLocalEvent<MeleeBlockComponent, ExaminedEvent>(OnExamine);
}

private void OnExamine(Entity<MeleeBlockComponent> ent, ref ExaminedEvent args)
{
args.PushMarkup(Loc.GetString("melee-block-component-delay", ("delay", ent.Comp.Delay.TotalSeconds)));
}

private void OnHit(Entity<MeleeWeaponComponent> ent, ref MeleeHitEvent args)
{
if (!_timing.IsFirstTimePredicted)
return;

if (!ent.Comp.CanBeBlocked || !args.IsHit || args.Handled)
return;

if (args.Direction != null || args.HitEntities.Count != 1) // Heavy attacks are unblockable
return;

var hitEntity = args.HitEntities[0];

if (hitEntity == args.User)
return;

var ev = new MeleeBlockAttemptEvent(args.User, args.BaseDamage + args.BonusDamage);
RaiseLocalEvent(hitEntity, ev);

if (ev.Handled)
args.Handled = true;
}

private void OnBlockAttempt(Entity<HandsComponent> ent, ref MeleeBlockAttemptEvent args)
{
if (args.Handled || HasComp<BlockBlockerComponent>(ent))
return;

if (!TryComp(ent, out StatusEffectsComponent? statusEffects))
return;

var uid = ent.Comp.ActiveHandEntity;
if (!TryComp(uid, out MeleeBlockComponent? block))
return;

if (TryComp(uid.Value, out ItemToggleComponent? toggle) && !toggle.Activated)
return;

_audio.PlayPredicted(block.BlockSound, ent, args.Attacker);
_popupSystem.PopupPredicted(Loc.GetString("melee-block-event-blocked"), ent, args.Attacker);
_damageable.TryChangeDamage(uid.Value, args.Damage);
TryBlockBlocking(ent, block.Delay, true, statusEffects);
args.Handled = true;
}

public bool TryBlockBlocking(EntityUid uid, TimeSpan time, bool refresh, StatusEffectsComponent? status = null)
{
if (time <= TimeSpan.Zero)
return false;

if (!Resolve(uid, ref status, false))
return false;

return _statusEffect.TryAddStatusEffect<BlockBlockerComponent>(uid, "RecentlyBlocked", time, refresh);
}
}
2 changes: 2 additions & 0 deletions Resources/Locale/en-US/_white/alerts/alerts.ftl
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
alerts-blocked-name = Recently blocked
alerts-blocked-desc = I can't block for a while!
2 changes: 2 additions & 0 deletions Resources/Locale/en-US/_white/block/melee-block.ftl
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
melee-block-event-blocked = blocked!
melee-block-component-delay = Can block a melee attack every {$delay} seconds.
2 changes: 2 additions & 0 deletions Resources/Locale/ru-RU/_white/alerts/alerts.ftl
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
alerts-blocked-name = Атака заблокирована
alerts-blocked-desc = Невозможно блокировать некоторое время.
2 changes: 2 additions & 0 deletions Resources/Locale/ru-RU/_white/block/melee-block.ftl
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
melee-block-event-blocked = заблокировал!
melee-block-component-delay = Может блокировать атаку ближнего боя каждые {$delay} секунд.
8 changes: 8 additions & 0 deletions Resources/Prototypes/Alerts/alerts.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
- alertType: Magboots
- alertType: Pacified
- alertType: Offer
- alertType: RecentlyBlocked # WD EDIT

- type: entity
id: AlertSpriteView
Expand Down Expand Up @@ -449,6 +450,13 @@
minSeverity: 0
maxSeverity: 1

# WD EDIT
- type: alert
id: RecentlyBlocked
icons: [ /Textures/Objects/Weapons/Melee/shields.rsi/buckler-icon.png ]
name: alerts-blocked-name
description: alerts-blocked-desc

- type: alert
id: Debug1
icons:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
- type: Item
size: Small
- type: MeleeWeapon
canBeBlocked: false # WD EDIT
soundNoDamage:
path: "/Audio/Effects/Fluids/splat.ogg"
damage:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
- type: Sprite
state: icon
- type: MeleeWeapon
canBeBlocked: false # WD EDIT
soundNoDamage:
path: "/Audio/Effects/Fluids/splat.ogg"
damage:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@
- type: Spillable
solution: drink
- type: MeleeWeapon
canBeBlocked: false # WD EDIT
soundNoDamage:
path: "/Audio/Effects/Fluids/splat.ogg"
damage:
Expand Down
Loading

0 comments on commit e5b1e86

Please sign in to comment.