2023-02-16 18:27:43 -06:00
using Content.Server.Administration.Logs ;
2024-06-20 16:24:36 +00:00
using Content.Server.Popups ;
2023-02-24 19:01:25 -05:00
using Content.Shared.DoAfter ;
2023-02-16 18:27:43 -06:00
using Content.Shared.Database ;
2023-01-03 01:53:16 -06:00
using Content.Shared.Interaction.Events ;
2024-06-20 16:24:36 +00:00
using Content.Shared.Popups ;
2023-01-02 19:58:25 -06:00
using Content.Shared.Teleportation.Components ;
using Content.Shared.Teleportation.Systems ;
2023-11-27 22:12:34 +11:00
using Robust.Server.Audio ;
2023-01-02 19:58:25 -06:00
using Robust.Server.GameObjects ;
namespace Content.Server.Teleportation ;
/// <summary>
/// This handles creating portals from a hand teleporter.
/// </summary>
public sealed class HandTeleporterSystem : EntitySystem
{
2023-02-16 18:27:43 -06:00
[Dependency] private readonly IAdminLogManager _adminLogger = default ! ;
2023-01-02 19:58:25 -06:00
[Dependency] private readonly LinkedEntitySystem _link = default ! ;
[Dependency] private readonly AudioSystem _audio = default ! ;
2023-04-03 13:13:48 +12:00
[Dependency] private readonly SharedDoAfterSystem _doafter = default ! ;
2024-06-20 16:24:36 +00:00
[Dependency] private readonly PopupSystem _popup = default ! ;
2023-01-02 19:58:25 -06:00
/// <inheritdoc/>
public override void Initialize ( )
{
SubscribeLocalEvent < HandTeleporterComponent , UseInHandEvent > ( OnUseInHand ) ;
2023-04-03 13:13:48 +12:00
SubscribeLocalEvent < HandTeleporterComponent , TeleporterDoAfterEvent > ( OnDoAfter ) ;
2023-01-03 01:53:16 -06:00
}
2023-02-24 19:01:25 -05:00
private void OnDoAfter ( EntityUid uid , HandTeleporterComponent component , DoAfterEvent args )
2023-01-03 01:53:16 -06:00
{
2023-02-24 19:01:25 -05:00
if ( args . Cancelled | | args . Handled )
return ;
2023-01-03 01:53:16 -06:00
2023-02-24 19:01:25 -05:00
HandlePortalUpdating ( uid , component , args . Args . User ) ;
args . Handled = true ;
2023-01-02 19:58:25 -06:00
}
private void OnUseInHand ( EntityUid uid , HandTeleporterComponent component , UseInHandEvent args )
{
if ( Deleted ( component . FirstPortal ) )
component . FirstPortal = null ;
if ( Deleted ( component . SecondPortal ) )
component . SecondPortal = null ;
2023-01-03 01:53:16 -06:00
if ( component . FirstPortal ! = null & & component . SecondPortal ! = null )
{
// handle removing portals immediately as opposed to a doafter
HandlePortalUpdating ( uid , component , args . User ) ;
}
else
{
var xform = Transform ( args . User ) ;
if ( xform . ParentUid ! = xform . GridUid )
return ;
2023-09-11 09:42:41 +10:00
var doafterArgs = new DoAfterArgs ( EntityManager , args . User , component . PortalCreationDelay , new TeleporterDoAfterEvent ( ) , uid , used : uid )
2023-01-03 01:53:16 -06:00
{
BreakOnDamage = true ,
2024-03-19 12:09:00 +02:00
BreakOnMove = true ,
2023-01-03 01:53:16 -06:00
MovementThreshold = 0.5f ,
} ;
2023-04-03 13:13:48 +12:00
_doafter . TryStartDoAfter ( doafterArgs ) ;
2023-01-03 01:53:16 -06:00
}
}
/// <summary>
/// Creates or removes a portal given the state of the hand teleporter.
/// </summary>
private void HandlePortalUpdating ( EntityUid uid , HandTeleporterComponent component , EntityUid user )
{
if ( Deleted ( user ) )
return ;
var xform = Transform ( user ) ;
2023-01-02 19:58:25 -06:00
// Create the first portal.
2023-07-24 16:21:44 -04:00
if ( Deleted ( component . FirstPortal ) & & Deleted ( component . SecondPortal ) )
2023-01-02 19:58:25 -06:00
{
2023-01-03 01:53:16 -06:00
// don't portal
if ( xform . ParentUid ! = xform . GridUid )
return ;
var timeout = EnsureComp < PortalTimeoutComponent > ( user ) ;
2023-01-02 19:58:25 -06:00
timeout . EnteredPortal = null ;
2023-01-03 01:53:16 -06:00
component . FirstPortal = Spawn ( component . FirstPortalPrototype , Transform ( user ) . Coordinates ) ;
2023-02-16 18:27:43 -06:00
_adminLogger . Add ( LogType . EntitySpawn , LogImpact . Low , $"{ToPrettyString(user):player} opened {ToPrettyString(component.FirstPortal.Value)} at {Transform(component.FirstPortal.Value).Coordinates} using {ToPrettyString(uid)}" ) ;
2023-01-02 19:58:25 -06:00
_audio . PlayPvs ( component . NewPortalSound , uid ) ;
}
2023-07-24 16:21:44 -04:00
else if ( Deleted ( component . SecondPortal ) )
2023-01-02 19:58:25 -06:00
{
2024-06-20 16:24:36 +00:00
if ( xform . ParentUid ! = xform . GridUid ) // Still, don't portal.
return ;
if ( ! component . AllowPortalsOnDifferentGrids & & xform . ParentUid ! = Transform ( component . FirstPortal ! . Value ) . ParentUid )
{
// Whoops. Fizzle time. Crime time too because yippee I'm not refactoring this logic right now (I started to, I'm not going to.)
FizzlePortals ( uid , component , user , true ) ;
return ;
}
2023-01-03 01:53:16 -06:00
var timeout = EnsureComp < PortalTimeoutComponent > ( user ) ;
2023-01-02 19:58:25 -06:00
timeout . EnteredPortal = null ;
2023-01-03 01:53:16 -06:00
component . SecondPortal = Spawn ( component . SecondPortalPrototype , Transform ( user ) . Coordinates ) ;
2023-02-16 18:27:43 -06:00
_adminLogger . Add ( LogType . EntitySpawn , LogImpact . Low , $"{ToPrettyString(user):player} opened {ToPrettyString(component.SecondPortal.Value)} at {Transform(component.SecondPortal.Value).Coordinates} linked to {ToPrettyString(component.FirstPortal!.Value)} using {ToPrettyString(uid)}" ) ;
2023-01-02 19:58:25 -06:00
_link . TryLink ( component . FirstPortal ! . Value , component . SecondPortal . Value , true ) ;
_audio . PlayPvs ( component . NewPortalSound , uid ) ;
}
else
{
2024-06-20 16:24:36 +00:00
FizzlePortals ( uid , component , user , false ) ;
2023-01-02 19:58:25 -06:00
}
}
2024-06-20 16:24:36 +00:00
private void FizzlePortals ( EntityUid uid , HandTeleporterComponent component , EntityUid user , bool instability )
{
// Logging
var portalStrings = "" ;
portalStrings + = ToPrettyString ( component . FirstPortal ) ;
if ( portalStrings ! = "" )
portalStrings + = " and " ;
portalStrings + = ToPrettyString ( component . SecondPortal ) ;
if ( portalStrings ! = "" )
_adminLogger . Add ( LogType . EntityDelete , LogImpact . Low , $"{ToPrettyString(user):player} closed {portalStrings} with {ToPrettyString(uid)}" ) ;
// Clear both portals
if ( ! Deleted ( component . FirstPortal ) )
QueueDel ( component . FirstPortal . Value ) ;
if ( ! Deleted ( component . SecondPortal ) )
QueueDel ( component . SecondPortal . Value ) ;
component . FirstPortal = null ;
component . SecondPortal = null ;
_audio . PlayPvs ( component . ClearPortalsSound , uid ) ;
if ( instability )
_popup . PopupEntity ( Loc . GetString ( "handheld-teleporter-instability-fizzle" ) , uid , user , PopupType . MediumCaution ) ;
}
2023-01-02 19:58:25 -06:00
}