using Content.Shared.ActionBlocker; using Content.Shared.Movement.Events; using Content.Shared.StepTrigger.Systems; using Robust.Shared.Network; using Robust.Shared.Physics.Components; using Robust.Shared.Timing; namespace Content.Shared.Chasm; /// /// Handles making entities fall into chasms when stepped on. /// public sealed class ChasmSystem : EntitySystem { [Dependency] private readonly IGameTiming _timing = default!; [Dependency] private readonly ActionBlockerSystem _blocker = default!; [Dependency] private readonly INetManager _net = default!; [Dependency] private readonly SharedAudioSystem _audio = default!; public override void Initialize() { base.Initialize(); SubscribeLocalEvent(OnStepTriggered); SubscribeLocalEvent(OnStepTriggerAttempt); SubscribeLocalEvent(OnUnpaused); SubscribeLocalEvent(OnUpdateCanMove); } public override void Update(float frameTime) { base.Update(frameTime); // don't predict queuedels on client if (_net.IsClient) return; var query = EntityQueryEnumerator(); while (query.MoveNext(out var uid, out var chasm)) { if (_timing.CurTime < chasm.NextDeletionTime) continue; QueueDel(uid); } } private void OnStepTriggered(EntityUid uid, ChasmComponent component, ref StepTriggeredEvent args) { // already doomed if (HasComp(args.Tripper)) return; var falling = AddComp(args.Tripper); falling.NextDeletionTime = _timing.CurTime + falling.DeletionTime; _blocker.UpdateCanMove(args.Tripper); _audio.PlayPredicted(component.FallingSound, uid, args.Tripper); } private void OnStepTriggerAttempt(EntityUid uid, ChasmComponent component, ref StepTriggerAttemptEvent args) { if (TryComp(args.Tripper, out var physics) && physics.BodyStatus == BodyStatus.InAir) return; args.Continue = true; } private void OnUnpaused(EntityUid uid, ChasmFallingComponent component, ref EntityUnpausedEvent args) { component.NextDeletionTime += args.PausedTime; } private void OnUpdateCanMove(EntityUid uid, ChasmFallingComponent component, UpdateCanMoveEvent args) { args.Cancel(); } }