Files
tbd-station-14/Content.Shared/Doors/Systems/SharedTurnstileSystem.cs
Nemanja 712954f1c4 Turnstiles (#36313)
* construction rotation fix

* Turnstiles

* renaming

* review-slarticodefast-1

* mild attempts to fix (sorry sloth)

* move some more shit

* Remove engine dependency

* grid agnostic

* remove debug string

* fix json

* Update Content.Shared/Movement/Pulling/Systems/PullingSystem.cs

Co-authored-by: ArtisticRoomba <145879011+ArtisticRoomba@users.noreply.github.com>

* Update Content.Shared/Movement/Pulling/Systems/PullingSystem.cs

Co-authored-by: ArtisticRoomba <145879011+ArtisticRoomba@users.noreply.github.com>

* remove pass delay for mispredict reasons.

* most minor of changes

* Give directional indicator on examine

---------

Co-authored-by: ArtisticRoomba <145879011+ArtisticRoomba@users.noreply.github.com>
2025-04-24 13:39:40 +02:00

132 lines
4.5 KiB
C#

using Content.Shared.Access.Systems;
using Content.Shared.Doors.Components;
using Content.Shared.Movement.Pulling.Systems;
using Content.Shared.Popups;
using Content.Shared.Whitelist;
using Robust.Shared.Audio.Systems;
using Robust.Shared.Physics.Events;
using Robust.Shared.Timing;
namespace Content.Shared.Doors.Systems;
/// <summary>
/// This handles logic and interactions related to <see cref="TurnstileComponent"/>
/// </summary>
public abstract partial class SharedTurnstileSystem : EntitySystem
{
[Dependency] private readonly IGameTiming _timing = default!;
[Dependency] private readonly AccessReaderSystem _accessReader = default!;
[Dependency] private readonly SharedAudioSystem _audio = default!;
[Dependency] private readonly EntityWhitelistSystem _entityWhitelist = default!;
[Dependency] private readonly PullingSystem _pulling = default!;
[Dependency] private readonly SharedTransformSystem _transform = default!;
[Dependency] private readonly SharedPopupSystem _popup = default!;
/// <inheritdoc/>
public override void Initialize()
{
SubscribeLocalEvent<TurnstileComponent, PreventCollideEvent>(OnPreventCollide);
SubscribeLocalEvent<TurnstileComponent, StartCollideEvent>(OnStartCollide);
SubscribeLocalEvent<TurnstileComponent, EndCollideEvent>(OnEndCollide);
}
private void OnPreventCollide(Entity<TurnstileComponent> ent, ref PreventCollideEvent args)
{
if (args.Cancelled || !args.OurFixture.Hard || !args.OtherFixture.Hard)
return;
if (ent.Comp.CollideExceptions.Contains(args.OtherEntity))
{
args.Cancelled = true;
return;
}
// We need to add this in here too for chain pulls
if (_pulling.GetPuller(args.OtherEntity) is { } puller && ent.Comp.CollideExceptions.Contains(puller))
{
ent.Comp.CollideExceptions.Add(args.OtherEntity);
Dirty(ent);
args.Cancelled = true;
return;
}
// unblockables go through for free.
if (_entityWhitelist.IsWhitelistFail(ent.Comp.ProcessWhitelist, args.OtherEntity))
{
args.Cancelled = true;
return;
}
if (CanPassDirection(ent, args.OtherEntity))
{
if (!_accessReader.IsAllowed(args.OtherEntity, ent))
return;
ent.Comp.CollideExceptions.Add(args.OtherEntity);
if (_pulling.GetPulling(args.OtherEntity) is { } uid)
ent.Comp.CollideExceptions.Add(uid);
args.Cancelled = true;
Dirty(ent);
}
else
{
if (_timing.CurTime >= ent.Comp.NextResistTime)
{
_popup.PopupClient(Loc.GetString("turnstile-component-popup-resist", ("turnstile", ent.Owner)), ent, args.OtherEntity);
ent.Comp.NextResistTime = _timing.CurTime + TimeSpan.FromSeconds(0.1);
Dirty(ent);
}
}
}
private void OnStartCollide(Entity<TurnstileComponent> ent, ref StartCollideEvent args)
{
if (!ent.Comp.CollideExceptions.Contains(args.OtherEntity))
{
if (CanPassDirection(ent, args.OtherEntity))
{
if (!_accessReader.IsAllowed(args.OtherEntity, ent))
{
_audio.PlayPredicted(ent.Comp.DenySound, ent, args.OtherEntity);
PlayAnimation(ent, ent.Comp.DenyState);
}
}
return;
}
// if they passed through:
PlayAnimation(ent, ent.Comp.SpinState);
_audio.PlayPredicted(ent.Comp.TurnSound, ent, args.OtherEntity);
}
private void OnEndCollide(Entity<TurnstileComponent> ent, ref EndCollideEvent args)
{
if (!args.OurFixture.Hard)
{
ent.Comp.CollideExceptions.Remove(args.OtherEntity);
Dirty(ent);
}
}
protected bool CanPassDirection(Entity<TurnstileComponent> ent, EntityUid other)
{
var xform = Transform(ent);
var otherXform = Transform(other);
var (pos, rot) = _transform.GetWorldPositionRotation(xform);
var otherPos = _transform.GetWorldPosition(otherXform);
var approachAngle = (pos - otherPos).ToAngle();
var rotateAngle = rot.ToWorldVec().ToAngle();
var dif = Math.Min(Math.Abs(approachAngle.Theta - rotateAngle.Theta), Math.Abs(rotateAngle.Theta - approachAngle.Theta));
return dif < Math.PI / 4;
}
protected virtual void PlayAnimation(EntityUid uid, string stateId)
{
}
}