using Content.Shared.Damage; using Content.Shared.Item.ItemToggle.Components; using Content.Shared.Weapons.Melee.Events; using Robust.Shared.Audio.Systems; using Robust.Shared.Containers; namespace Content.Shared.Blocking; public sealed partial class BlockingSystem { [Dependency] private readonly DamageableSystem _damageable = default!; [Dependency] private readonly SharedAudioSystem _audio = default!; private void InitializeUser() { SubscribeLocalEvent(OnUserDamageModified); SubscribeLocalEvent(OnDamageModified); SubscribeLocalEvent(OnParentChanged); SubscribeLocalEvent(OnInsertAttempt); SubscribeLocalEvent(OnAnchorChanged); SubscribeLocalEvent(OnEntityTerminating); SubscribeLocalEvent(OnMeleeBlockAttempt); // WD } // WD START private void OnMeleeBlockAttempt(Entity 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) { UserStopBlocking(uid, component); } private void OnInsertAttempt(EntityUid uid, BlockingUserComponent component, ContainerGettingInsertedAttemptEvent args) { UserStopBlocking(uid, component); } private void OnAnchorChanged(EntityUid uid, BlockingUserComponent component, ref AnchorStateChangedEvent args) { if (args.Anchored) return; UserStopBlocking(uid, component); } private void OnUserDamageModified(EntityUid uid, BlockingUserComponent component, DamageModifyEvent args) { if (TryComp(component.BlockingItem, out var blocking)) { if (args.Damage.GetTotal() <= 0) return; // A shield should only block damage it can itself absorb. To determine that we need the Damageable component on it. if (!TryComp(component.BlockingItem, out var dmgComp)) return; var blockFraction = blocking.IsBlocking ? blocking.ActiveBlockFraction : blocking.PassiveBlockFraction; if (TryComp(component.BlockingItem, out ItemToggleComponent? toggle) && !toggle.Activated) // WD blockFraction = 0f; blockFraction = Math.Clamp(blockFraction, 0, 1); _damageable.TryChangeDamage(component.BlockingItem, blockFraction * args.OriginalDamage); var modify = new DamageModifierSet(); foreach (var key in dmgComp.Damage.DamageDict.Keys) { modify.Coefficients.TryAdd(key, 1 - blockFraction); } args.Damage = DamageSpecifier.ApplyModifierSet(args.Damage, modify); if (blocking.IsBlocking && !args.Damage.Equals(args.OriginalDamage)) { _audio.PlayPvs(blocking.BlockSound, uid); } } } private void OnDamageModified(EntityUid uid, BlockingComponent component, DamageModifyEvent args) { var modifier = component.IsBlocking ? component.ActiveBlockDamageModifier : component.PassiveBlockDamageModifer; if (modifier == null) { return; } args.Damage = DamageSpecifier.ApplyModifierSet(args.Damage, modifier); } private void OnEntityTerminating(EntityUid uid, BlockingUserComponent component, ref EntityTerminatingEvent args) { if (!TryComp(component.BlockingItem, out var blockingComponent)) return; StopBlockingHelper(component.BlockingItem.Value, blockingComponent, uid); } /// /// Check for the shield and has the user stop blocking /// Used where you'd like the user to stop blocking, but also don't want to remove the /// /// The user blocking /// The private void UserStopBlocking(EntityUid uid, BlockingUserComponent component) { if (TryComp(component.BlockingItem, out var blockComp) && blockComp.IsBlocking) StopBlocking(component.BlockingItem.Value, blockComp, uid); } }