Portals & hand teleporter (#13266)

* basic system with portals & linked ents

* hand tele sprites, no impl

* hand tele and teleportation works

* fancy it up

* oog

* special case projectiles

* predict portal-to-portal teleportation

* this stuff

* check nullspace

* sloth

* give to rd instead

* i guess this can probably happen

* docs
This commit is contained in:
Kara
2023-01-02 19:58:25 -06:00
committed by GitHub
parent a21a4711b6
commit c821ca71aa
23 changed files with 592 additions and 3 deletions

View File

@@ -0,0 +1,36 @@
using Content.Shared.Audio;
using Robust.Shared.Audio;
using Robust.Shared.GameStates;
using Robust.Shared.Prototypes;
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype;
namespace Content.Shared.Teleportation.Components;
/// <summary>
/// Creates portals. If two are created, both are linked together--otherwise the first teleports randomly.
/// Using it with both portals active deactivates both.
/// </summary>
[RegisterComponent, NetworkedComponent]
public sealed class HandTeleporterComponent : Component
{
[ViewVariables, DataField("firstPortal")]
public EntityUid? FirstPortal = null;
[ViewVariables, DataField("secondPortal")]
public EntityUid? SecondPortal = null;
[DataField("firstPortalPrototype", customTypeSerializer:typeof(PrototypeIdSerializer<EntityPrototype>))]
public string FirstPortalPrototype = "PortalRed";
[DataField("secondPortalPrototype", customTypeSerializer:typeof(PrototypeIdSerializer<EntityPrototype>))]
public string SecondPortalPrototype = "PortalBlue";
[DataField("newPortalSound")]
public SoundSpecifier NewPortalSound = new SoundPathSpecifier("/Audio/Machines/high_tech_confirm.ogg")
{
Params = AudioParams.Default.WithVolume(-2f)
};
[DataField("clearPortalsSound")]
public SoundSpecifier ClearPortalsSound = new SoundPathSpecifier("/Audio/Machines/button.ogg");
}

View File

@@ -0,0 +1,42 @@
using Content.Shared.Teleportation.Systems;
using Robust.Shared.GameStates;
using Robust.Shared.Serialization;
namespace Content.Shared.Teleportation.Components;
/// <summary>
/// Represents an entity which is linked to other entities (perhaps portals), and which can be walked through/
/// thrown into to teleport an entity.
/// </summary>
[RegisterComponent, Access(typeof(LinkedEntitySystem)), NetworkedComponent]
public sealed class LinkedEntityComponent : Component
{
/// <summary>
/// The entities that this entity is linked to.
/// </summary>
[DataField("linkedEntities")]
public HashSet<EntityUid> LinkedEntities = new();
/// <summary>
/// Should this entity be deleted if all of its links are removed?
/// </summary>
[DataField("deleteOnEmptyLinks")]
public bool DeleteOnEmptyLinks = false;
}
[Serializable, NetSerializable]
public sealed class LinkedEntityComponentState : ComponentState
{
public HashSet<EntityUid> LinkedEntities;
public LinkedEntityComponentState(HashSet<EntityUid> linkedEntities)
{
LinkedEntities = linkedEntities;
}
}
[Serializable, NetSerializable]
public enum LinkedEntityVisuals : byte
{
HasAnyLinks
}

View File

@@ -0,0 +1,31 @@
using Robust.Shared.Audio;
using Robust.Shared.GameStates;
namespace Content.Shared.Teleportation.Components;
/// <summary>
/// Marks an entity as being a 'portal' which teleports entities sent through it to linked entities.
/// Relies on <see cref="LinkedEntityComponent"/> being set up.
/// </summary>
[RegisterComponent, NetworkedComponent]
public sealed class PortalComponent : Component
{
/// <summary>
/// Sound played on arriving to this portal, centered on the destination.
/// The arrival sound of the entered portal will play if the destination is not a portal.
/// </summary>
[DataField("arrivalSound")]
public SoundSpecifier ArrivalSound = new SoundPathSpecifier("/Audio/Effects/teleport_arrival.ogg");
/// <summary>
/// Sound played on departing from this portal, centered on the original portal.
/// </summary>
[DataField("departureSound")]
public SoundSpecifier DepartureSound = new SoundPathSpecifier("/Audio/Effects/teleport_departure.ogg");
/// <summary>
/// If no portals are linked, the subject will be teleported a random distance at maximum this far away.
/// </summary>
[DataField("maxRandomRadius")]
public float MaxRandomRadius = 10.0f;
}

View File

@@ -0,0 +1,29 @@
using Robust.Shared.GameStates;
using Robust.Shared.Serialization;
namespace Content.Shared.Teleportation.Components;
/// <summary>
/// Attached to an entity after portal transit to mark that they should not immediately be portaled back
/// at the end destination.
/// </summary>
[RegisterComponent, NetworkedComponent]
public sealed class PortalTimeoutComponent : Component
{
/// <summary>
/// The portal that was entered. Null if coming from a hand teleporter, etc.
/// </summary>
[ViewVariables, DataField("enteredPortal")]
public EntityUid? EnteredPortal = null;
}
[Serializable, NetSerializable]
public sealed class PortalTimeoutComponentState : ComponentState
{
public EntityUid? EnteredPortal;
public PortalTimeoutComponentState(EntityUid? enteredPortal)
{
EnteredPortal = enteredPortal;
}
}