using Content.Shared.Construction.Components; using Content.Shared.Stunnable; using Content.Shared.Throwing; using Content.Shared.Timing; using Content.Shared.Weapons.Melee.Components; using Content.Shared.Weapons.Melee.Events; using Robust.Shared.Physics; using Robust.Shared.Physics.Components; using Robust.Shared.Physics.Systems; using System.Numerics; namespace Content.Shared.Weapons.Melee; /// /// This handles /// public sealed class MeleeThrowOnHitSystem : EntitySystem { [Dependency] private readonly SharedTransformSystem _transform = default!; [Dependency] private readonly SharedPhysicsSystem _physics = default!; [Dependency] private readonly UseDelaySystem _delay = default!; [Dependency] private readonly SharedStunSystem _stun = default!; [Dependency] private readonly ThrowingSystem _throwing = default!; /// public override void Initialize() { SubscribeLocalEvent(OnMeleeHit); SubscribeLocalEvent(OnThrowHit); } private void OnMeleeHit(Entity weapon, ref MeleeHitEvent args) { // TODO: MeleeHitEvent is weird. Why is this even raised if we don't hit something? if (!args.IsHit) return; if (_delay.IsDelayed(weapon.Owner)) return; if (args.HitEntities.Count == 0) return; var userPos = _transform.GetWorldPosition(args.User); foreach (var target in args.HitEntities) { var targetPos = _transform.GetMapCoordinates(target).Position; var direction = args.Direction ?? targetPos - userPos; ThrowOnHitHelper(weapon, args.User, target, direction); } } private void OnThrowHit(Entity weapon, ref ThrowDoHitEvent args) { if (!weapon.Comp.ActivateOnThrown) return; if (!TryComp(args.Thrown, out var weaponPhysics)) return; ThrowOnHitHelper(weapon, args.Component.Thrower, args.Target, weaponPhysics.LinearVelocity); } private void ThrowOnHitHelper(Entity ent, EntityUid? user, EntityUid target, Vector2 direction) { var attemptEvent = new AttemptMeleeThrowOnHitEvent(target, user); RaiseLocalEvent(ent.Owner, ref attemptEvent); if (attemptEvent.Cancelled) return; var startEvent = new MeleeThrowOnHitStartEvent(ent.Owner, user); RaiseLocalEvent(target, ref startEvent); if (ent.Comp.StunTime != null) _stun.TryParalyze(target, ent.Comp.StunTime.Value, false); if (direction == Vector2.Zero) return; _throwing.TryThrow(target, direction.Normalized() * ent.Comp.Distance, ent.Comp.Speed, user, unanchor: ent.Comp.UnanchorOnHit); } }