using Content.Server.Flash; using Content.Server.Procedural; using Content.Shared._CP14.Demiplane; using Content.Shared._CP14.Demiplane.Components; using Content.Shared.Popups; using Robust.Server.Audio; using Robust.Shared.Map; using Robust.Shared.Prototypes; using Robust.Shared.Random; using Robust.Shared.Timing; namespace Content.Server._CP14.Demiplane; public sealed partial class CP14DemiplaneSystem : CP14SharedDemiplaneSystem { [Dependency] private readonly IPrototypeManager _proto = default!; [Dependency] private readonly IRobustRandom _random = default!; [Dependency] private readonly ILogManager _logManager = default!; [Dependency] private readonly IMapManager _mapManager = default!; [Dependency] private readonly DungeonSystem _dungeon = default!; [Dependency] private readonly MetaDataSystem _metaData = default!; [Dependency] private readonly SharedMapSystem _mapSystem = default!; [Dependency] private readonly SharedTransformSystem _transform = default!; [Dependency] private readonly AudioSystem _audio = default!; [Dependency] private readonly FlashSystem _flash = default!; [Dependency] private readonly IGameTiming _timing = default!; [Dependency] private readonly SharedPopupSystem _popup = default!; public override void Initialize() { base.Initialize(); InitGeneration(); InitConnections(); InitStabilization(); SubscribeLocalEvent(OnDemiplanShutdown); } public override void Update(float frameTime) { base.Update(frameTime); UpdateGeneration(frameTime); UpdateStabilization(frameTime); } /// /// Teleports the entity inside the demiplane, to one of the random entry points. /// /// The demiplane the entity will be teleported to /// The entity to be teleported /// public bool TryTeleportIntoDemiplane(Entity demiplane, EntityUid? entity) { if (entity is null) return false; if (!TryGetDemiplanEntryPoint(demiplane, out var entryPoint) || entryPoint is null) { Log.Error($"{entity} cant get in demiplane {demiplane}: no active entry points!"); return false; } var targetCoord = Transform(entryPoint.Value).Coordinates; _flash.Flash(entity.Value, null, null, 3000f, 0.5f); _transform.SetCoordinates(entity.Value, targetCoord); _audio.PlayGlobal(demiplane.Comp.ArrivalSound, entity.Value); return true; } /// /// Teleports an entity from the demiplane to the real world, to one of the random exit points in the real world. /// /// The demiplane from which the entity will be teleported /// An entity that will be teleported into the real world. This entity must be in the demiplane, otherwise the function will not work. /// public bool TryTeleportOutDemiplane(Entity demiplane, EntityUid? entity) { if (entity is null) return false; if (Transform(entity.Value).MapUid != demiplane.Owner) return false; if (!TryGetDemiplanExitPoint(demiplane, out var connection) || connection is null) { Log.Error($"{entity} cant get out of demiplane {demiplane}: no active connections!"); return false; } var targetCoord = Transform(connection.Value).Coordinates; _flash.Flash(entity.Value, null, null, 3000f, 0.5f); _transform.SetCoordinates(entity.Value, targetCoord); _audio.PlayGlobal(demiplane.Comp.DepartureSound, entity.Value); return true; } private void OnDemiplanShutdown(Entity demiplane, ref ComponentShutdown args) { //We stop asynchronous generation of a demiplane early if for some reason this demiplane is deleted before generation is complete foreach (var (job, cancelToken) in _expeditionJobs.ToArray()) { if (job.DemiplaneMapUid == demiplane.Owner) { cancelToken.Cancel(); _expeditionJobs.Remove((job, cancelToken)); } } foreach (var exit in demiplane.Comp.ExitPoints) { RemoveDemiplanRandomExitPoint(demiplane, exit); } foreach (var entry in demiplane.Comp.EntryPoints) { RemoveDemiplanRandomEntryPoint(demiplane, entry); } } }