2025-02-05 14:21:12 +03:00
using Content.Server._CP14.Demiplane.Components ;
2025-02-09 17:18:24 +03:00
using Content.Server.Chat.Managers ;
using Content.Server.Chat.Systems ;
2024-10-31 19:13:44 +03:00
using Content.Server.Flash ;
using Content.Server.Procedural ;
using Content.Shared._CP14.Demiplane ;
using Content.Shared._CP14.Demiplane.Components ;
2025-02-09 17:18:24 +03:00
using Content.Shared.Chat ;
2024-11-01 09:23:22 +03:00
using Content.Shared.Popups ;
2024-10-31 19:13:44 +03:00
using Robust.Server.Audio ;
2025-02-05 22:52:50 +03:00
using Robust.Shared.Audio ;
2024-10-31 19:13:44 +03:00
using Robust.Shared.Map ;
2025-02-09 17:18:24 +03:00
using Robust.Shared.Map.Components ;
using Robust.Shared.Player ;
2024-10-31 19:13:44 +03:00
using Robust.Shared.Prototypes ;
using Robust.Shared.Random ;
2024-11-01 09:23:22 +03:00
using Robust.Shared.Timing ;
2024-10-31 19:13:44 +03:00
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 ! ;
2024-11-01 09:23:22 +03:00
[Dependency] private readonly IGameTiming _timing = default ! ;
[Dependency] private readonly SharedPopupSystem _popup = default ! ;
2025-02-09 17:18:24 +03:00
[Dependency] private readonly ChatSystem _chat = default ! ;
[Dependency] private readonly IChatManager _chatManager = default ! ;
2024-10-31 19:13:44 +03:00
2025-02-05 14:21:12 +03:00
private EntityQuery < CP14DemiplaneComponent > _demiplaneQuery ;
2024-10-31 19:13:44 +03:00
public override void Initialize ( )
{
base . Initialize ( ) ;
2025-02-05 14:21:12 +03:00
_demiplaneQuery = GetEntityQuery < CP14DemiplaneComponent > ( ) ;
2024-10-31 19:13:44 +03:00
InitGeneration ( ) ;
InitConnections ( ) ;
2024-11-01 09:23:22 +03:00
InitStabilization ( ) ;
2025-02-05 14:21:12 +03:00
InitEchoes ( ) ;
2025-02-09 17:18:24 +03:00
InitDestruction ( ) ;
2024-10-31 19:13:44 +03:00
SubscribeLocalEvent < CP14DemiplaneComponent , ComponentShutdown > ( OnDemiplanShutdown ) ;
2025-02-05 14:21:12 +03:00
SubscribeLocalEvent < CP14SpawnOutOfDemiplaneComponent , MapInitEvent > ( OnSpawnOutOfDemiplane ) ;
}
private void OnSpawnOutOfDemiplane ( Entity < CP14SpawnOutOfDemiplaneComponent > ent , ref MapInitEvent args )
{
//Check if entity is in demiplane
var map = Transform ( ent ) . MapUid ;
if ( ! _demiplaneQuery . TryComp ( map , out var demiplane ) )
return ;
//Get random exit demiplane point and spawn entity there
if ( demiplane . ExitPoints . Count = = 0 )
return ;
var exit = _random . Pick ( demiplane . ExitPoints ) ;
var coordinates = Transform ( exit ) . Coordinates ;
var proto = ent . Comp . Proto ;
if ( proto is null )
proto = MetaData ( ent ) . EntityPrototype ? . ID ;
Spawn ( proto , coordinates ) ;
2024-10-31 19:13:44 +03:00
}
public override void Update ( float frameTime )
{
base . Update ( frameTime ) ;
UpdateGeneration ( frameTime ) ;
2024-11-01 09:23:22 +03:00
UpdateStabilization ( frameTime ) ;
2025-02-09 17:18:24 +03:00
UpdateDestruction ( frameTime ) ;
2024-10-31 19:13:44 +03:00
}
2024-12-06 17:16:38 +03:00
2024-10-31 19:13:44 +03:00
/// <summary>
/// Teleports the entity inside the demiplane, to one of the random entry points.
/// </summary>
/// <param name="demiplane">The demiplane the entity will be teleported to</param>
/// <param name="entity">The entity to be teleported</param>
/// <returns></returns>
2025-02-05 22:52:50 +03:00
public override bool TryTeleportIntoDemiplane ( Entity < CP14DemiplaneComponent > demiplane , EntityUid ? entity )
2024-10-31 19:13:44 +03:00
{
if ( entity is null )
return false ;
2025-02-03 17:09:09 +03:00
if ( ! TryGetDemiplaneEntryPoint ( demiplane , out var entryPoint ) | | entryPoint is null )
2024-10-31 19:13:44 +03:00
{
Log . Error ( $"{entity} cant get in demiplane {demiplane}: no active entry points!" ) ;
return false ;
}
2025-02-05 22:52:50 +03:00
TeleportEntityToCoordinate ( entity . Value , Transform ( entryPoint . Value ) . Coordinates , demiplane . Comp . ArrivalSound ) ;
2024-10-31 19:13:44 +03:00
return true ;
}
2025-02-05 22:52:50 +03:00
/// <summary>
/// Simple teleportation, with common special effects for all the game's teleportation mechanics
/// </summary>
/// <param name="entity"></param>
/// <param name="coordinates"></param>
/// <param name="sound"></param>
public void TeleportEntityToCoordinate ( EntityUid ? entity , EntityCoordinates coordinates , SoundSpecifier ? sound = null )
{
if ( entity is null )
return ;
_flash . Flash ( entity . Value , null , null , 3000f , 0.5f ) ;
_transform . SetCoordinates ( entity . Value , coordinates ) ;
_audio . PlayGlobal ( sound , entity . Value ) ;
}
2024-10-31 19:13:44 +03:00
/// <summary>
/// Teleports an entity from the demiplane to the real world, to one of the random exit points in the real world.
/// </summary>
/// <param name="demiplane">The demiplane from which the entity will be teleported</param>
/// <param name="entity">An entity that will be teleported into the real world. This entity must be in the demiplane, otherwise the function will not work.</param>
/// <returns></returns>
2025-02-05 22:52:50 +03:00
public override bool TryTeleportOutDemiplane ( Entity < CP14DemiplaneComponent > demiplane , EntityUid ? entity )
2024-10-31 19:13:44 +03:00
{
if ( entity is null )
return false ;
if ( Transform ( entity . Value ) . MapUid ! = demiplane . Owner )
return false ;
2025-02-03 17:09:09 +03:00
if ( ! TryGetDemiplaneExitPoint ( demiplane , out var connection ) | | connection is null )
2024-10-31 19:13:44 +03:00
{
Log . Error ( $"{entity} cant get out of demiplane {demiplane}: no active connections!" ) ;
return false ;
}
2025-02-05 22:52:50 +03:00
TeleportEntityToCoordinate ( entity . Value , Transform ( connection . Value ) . Coordinates , demiplane . Comp . DepartureSound ) ;
2024-10-31 19:13:44 +03:00
return true ;
}
private void OnDemiplanShutdown ( Entity < CP14DemiplaneComponent > 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 )
{
2025-05-05 15:19:44 +03:00
RemoveDemiplaneRandomExitPoint ( demiplane , exit ) ;
2024-10-31 19:13:44 +03:00
}
foreach ( var entry in demiplane . Comp . EntryPoints )
{
2025-02-03 17:09:09 +03:00
RemoveDemiplaneRandomEntryPoint ( demiplane , entry ) ;
2024-10-31 19:13:44 +03:00
}
}
2025-02-09 17:18:24 +03:00
private void DemiplaneAnnounce ( EntityUid mapUid , string text )
{
var mapId = Comp < MapComponent > ( mapUid ) . MapId ;
_chatManager . ChatMessageToManyFiltered (
Filter . BroadcastMap ( mapId ) ,
ChatChannel . Radio ,
text ,
text ,
_mapManager . GetMapEntityId ( mapId ) ,
false ,
true ,
null ) ;
}
2024-10-31 19:13:44 +03:00
}