using Content.Shared.Damage; using Content.Shared.Damage.Prototypes; using Robust.Shared.Audio; 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); } 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; 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); } }