using System.Linq;
using Content.Shared._Stalker.Teleport;
using Content.Shared.Access.Systems;
using Content.Shared.Movement.Pulling.Systems;
using Content.Shared.Teleportation.Components;
using Content.Shared.Teleportation.Systems;
using Robust.Shared.Physics.Events;
using Robust.Shared.Random;
using Content.Shared.Movement.Pulling.Components;
namespace Content.Server._Stalker.Teleports.LocalTeleport;
///
/// Use to teleport entities between maps/grids/tiles. Just spawn two portals with the same name.
///
public sealed class LocalTeleportSystem : SharedTeleportSystem
{
[Dependency] private readonly PullingSystem _pulling = default!;
[Dependency] private readonly IRobustRandom _random = default!;
[Dependency] private readonly SharedTransformSystem _xformSystem = default!;
[Dependency] private readonly LinkedEntitySystem _linkedEntitySystem = default!;
[Dependency] private readonly IEntityManager _entMan = default!;
[Dependency] private readonly AccessReaderSystem _accessReaderSystem = default!;
public override void Initialize()
{
SubscribeLocalEvent(OnStartCollide);
SubscribeLocalEvent(OnEndCollide);
}
private void OnStartCollide(EntityUid uid, LocalTeleportComponent component, ref StartCollideEvent args)
{
var subject = args.OtherEntity;
// Check for access
if (!component.AllowAll)
{
if (!_accessReaderSystem.IsAllowed(args.OtherEntity, args.OurEntity))
return;
}
// Asked to remove, testing now - Reenabled for civ14 because dragging items through is buggy
if (TryComp(subject, out var pullable) && pullable.BeingPulled)
_pulling.TryStopPull(subject, pullable);
if (TryComp(subject, out var pulling)
&& pulling.Pulling != null && TryComp(pulling.Pulling.Value, out var subjectPulling))
_pulling.TryStopPull(subject, subjectPulling);
// Remove Timeout from other portal
if (HasComp(subject))
return;
// If there are no linked entity - link one
if (!TryComp(uid, out var link))
{
var ents = _entMan.GetEntities();
foreach (var ent in ents)
{
if (!TryComp(ent, out var local))
continue;
if (local.PortalName != component.PortalName || uid == ent)
continue;
_linkedEntitySystem.TryLink(uid, ent, true);
}
}
if (link == null)
return;
if (!link.LinkedEntities.Any())
return;
var target = _random.Pick(link.LinkedEntities);
// Setup Timeout for an entity to not teleport it after teleport...
var timeout = EnsureComp(subject);
timeout.EnteredPortal = uid;
Dirty(subject, timeout);
var xform = Transform(target);
TeleportEntity(subject, xform.Coordinates);
}
private void OnEndCollide(EntityUid uid, LocalTeleportComponent component, ref EndCollideEvent args)
{
var subject = args.OtherEntity;
// Remove Timeout set by other portal.
if (TryComp(subject, out var timeout) && timeout.EnteredPortal != uid)
{
RemCompDeferred(subject);
}
}
}