Portal sprite & behavior tweaks (#19179)

* Portal repalette

* Portal traversal verb + anchoring

* map restriction

* optional max distance checks if we decide to have them later

* lower pointlight energy slightly hopefully makes it less garish
This commit is contained in:
Kara
2023-08-15 13:56:14 -07:00
committed by GitHub
parent 452f2112e8
commit 2e86f4c556
11 changed files with 106 additions and 18 deletions

View File

@@ -22,7 +22,6 @@ public sealed class HandTeleporterSystem : EntitySystem
public override void Initialize() public override void Initialize()
{ {
SubscribeLocalEvent<HandTeleporterComponent, UseInHandEvent>(OnUseInHand); SubscribeLocalEvent<HandTeleporterComponent, UseInHandEvent>(OnUseInHand);
SubscribeLocalEvent<HandTeleporterComponent, TeleporterDoAfterEvent>(OnDoAfter); SubscribeLocalEvent<HandTeleporterComponent, TeleporterDoAfterEvent>(OnDoAfter);
} }

View File

@@ -1,4 +1,5 @@
using Content.Server.Mind.Components; using Content.Server.Ghost.Components;
using Content.Server.Mind.Components;
using Content.Shared.Administration.Logs; using Content.Shared.Administration.Logs;
using Content.Shared.Database; using Content.Shared.Database;
using Content.Shared.Teleportation.Systems; using Content.Shared.Teleportation.Systems;
@@ -14,7 +15,7 @@ public sealed class PortalSystem : SharedPortalSystem
protected override void LogTeleport(EntityUid portal, EntityUid subject, EntityCoordinates source, protected override void LogTeleport(EntityUid portal, EntityUid subject, EntityCoordinates source,
EntityCoordinates target) EntityCoordinates target)
{ {
if (HasComp<MindContainerComponent>(subject)) if (HasComp<MindContainerComponent>(subject) && !HasComp<GhostComponent>(subject))
_adminLogger.Add(LogType.Teleport, LogImpact.Low, $"{ToPrettyString(subject):player} teleported via {ToPrettyString(portal)} from {source} to {target}"); _adminLogger.Add(LogType.Teleport, LogImpact.Low, $"{ToPrettyString(subject):player} teleported via {ToPrettyString(portal)} from {source} to {target}");
} }
} }

View File

@@ -38,7 +38,8 @@ public sealed class HandTeleporterComponent : Component
/// <summary> /// <summary>
/// Delay for creating the portals in seconds. /// Delay for creating the portals in seconds.
/// </summary> /// </summary>
[DataField("portalCreationDelay")] public float PortalCreationDelay = 2.5f; [DataField("portalCreationDelay")]
public float PortalCreationDelay = 1.0f;
} }
[Serializable, NetSerializable] [Serializable, NetSerializable]

View File

@@ -28,4 +28,23 @@ public sealed class PortalComponent : Component
/// </summary> /// </summary>
[DataField("maxRandomRadius")] [DataField("maxRandomRadius")]
public float MaxRandomRadius = 7.0f; public float MaxRandomRadius = 7.0f;
/// <summary>
/// If false, this portal will fail to teleport and fizzle out if attempting to send an entity to a different map
/// </summary>
/// <remarks>
/// Shouldn't be able to teleport people to centcomm or the eshuttle from the station
/// </remarks>
[DataField("canTeleportToOtherMaps")]
public bool CanTeleportToOtherMaps = false;
/// <summary>
/// Maximum distance that portals can teleport to, in all cases. Mostly this matters for linked portals.
/// Null means no restriction on distance.
/// </summary>
/// <remarks>
/// Obviously this should strictly be larger than <see cref="MaxRandomRadius"/> (or null)
/// </remarks>
[DataField("maxTeleportRadius")]
public float? MaxTeleportRadius;
} }

View File

@@ -1,15 +1,20 @@
using System.Linq; using System.Linq;
using Content.Shared.Directions; using Content.Shared.Ghost;
using Content.Shared.Pinpointer;
using Content.Shared.Popups;
using Content.Shared.Projectiles; using Content.Shared.Projectiles;
using Content.Shared.Pulling; using Content.Shared.Pulling;
using Content.Shared.Pulling.Components; using Content.Shared.Pulling.Components;
using Content.Shared.Teleportation.Components; using Content.Shared.Teleportation.Components;
using Content.Shared.Verbs;
using Robust.Shared.GameStates; using Robust.Shared.GameStates;
using Robust.Shared.Map; using Robust.Shared.Map;
using Robust.Shared.Network; using Robust.Shared.Network;
using Robust.Shared.Physics.Dynamics; using Robust.Shared.Physics.Dynamics;
using Robust.Shared.Physics.Events; using Robust.Shared.Physics.Events;
using Robust.Shared.Player;
using Robust.Shared.Random; using Robust.Shared.Random;
using Robust.Shared.Utility;
namespace Content.Shared.Teleportation.Systems; namespace Content.Shared.Teleportation.Systems;
@@ -24,6 +29,7 @@ public abstract class SharedPortalSystem : EntitySystem
[Dependency] private readonly SharedAudioSystem _audio = default!; [Dependency] private readonly SharedAudioSystem _audio = default!;
[Dependency] private readonly SharedTransformSystem _transform = default!; [Dependency] private readonly SharedTransformSystem _transform = default!;
[Dependency] private readonly SharedPullingSystem _pulling = default!; [Dependency] private readonly SharedPullingSystem _pulling = default!;
[Dependency] private readonly SharedPopupSystem _popup = default!;
private const string PortalFixture = "portalFixture"; private const string PortalFixture = "portalFixture";
private const string ProjectileFixture = "projectile"; private const string ProjectileFixture = "projectile";
@@ -35,11 +41,42 @@ public abstract class SharedPortalSystem : EntitySystem
{ {
SubscribeLocalEvent<PortalComponent, StartCollideEvent>(OnCollide); SubscribeLocalEvent<PortalComponent, StartCollideEvent>(OnCollide);
SubscribeLocalEvent<PortalComponent, EndCollideEvent>(OnEndCollide); SubscribeLocalEvent<PortalComponent, EndCollideEvent>(OnEndCollide);
SubscribeLocalEvent<PortalComponent, GetVerbsEvent<AlternativeVerb>>(OnGetVerbs);
SubscribeLocalEvent<PortalTimeoutComponent, ComponentGetState>(OnGetState); SubscribeLocalEvent<PortalTimeoutComponent, ComponentGetState>(OnGetState);
SubscribeLocalEvent<PortalTimeoutComponent, ComponentHandleState>(OnHandleState); SubscribeLocalEvent<PortalTimeoutComponent, ComponentHandleState>(OnHandleState);
} }
private void OnGetVerbs(EntityUid uid, PortalComponent component, GetVerbsEvent<AlternativeVerb> args)
{
// Traversal altverb for ghosts to use that bypasses normal functionality
if (!args.CanAccess || !HasComp<SharedGhostComponent>(args.User))
return;
// Don't use the verb with unlinked or with multi-output portals
// (this is only intended to be useful for ghosts to see where a linked portal leads)
var disabled = !TryComp<LinkedEntityComponent>(uid, out var link) || link.LinkedEntities.Count != 1;
args.Verbs.Add(new AlternativeVerb
{
Priority = 11,
Act = () =>
{
if (link == null || disabled)
return;
var ent = link.LinkedEntities.First();
TeleportEntity(uid, args.User, Transform(ent).Coordinates, ent, false);
},
Disabled = disabled,
Text = Loc.GetString("portal-component-ghost-traverse"),
Message = disabled
? Loc.GetString("portal-component-no-linked-entities")
: Loc.GetString("portal-component-can-ghost-traverse"),
Icon = new SpriteSpecifier.Texture(new("/Textures/Interface/VerbIcons/open.svg.192dpi.png"))
});
}
private void OnGetState(EntityUid uid, PortalTimeoutComponent component, ref ComponentGetState args) private void OnGetState(EntityUid uid, PortalTimeoutComponent component, ref ComponentGetState args)
{ {
args.State = new PortalTimeoutComponentState(component.EnteredPortal); args.State = new PortalTimeoutComponentState(component.EnteredPortal);
@@ -138,12 +175,38 @@ public abstract class SharedPortalSystem : EntitySystem
} }
} }
private void TeleportEntity(EntityUid portal, EntityUid subject, EntityCoordinates target, EntityUid? targetEntity=null, private void TeleportEntity(EntityUid portal, EntityUid subject, EntityCoordinates target, EntityUid? targetEntity=null, bool playSound=true,
PortalComponent? portalComponent = null) PortalComponent? portalComponent = null)
{ {
if (!Resolve(portal, ref portalComponent)) if (!Resolve(portal, ref portalComponent))
return; return;
var ourCoords = Transform(portal).Coordinates;
var onSameMap = ourCoords.GetMapId(EntityManager) == target.GetMapId(EntityManager);
var distanceInvalid = portalComponent.MaxTeleportRadius != null
&& ourCoords.TryDistance(EntityManager, target, out var distance)
&& distance > portalComponent.MaxTeleportRadius;
if (!onSameMap && !portalComponent.CanTeleportToOtherMaps || distanceInvalid)
{
if (!_netMan.IsServer)
return;
// Early out if this is an invalid configuration
_popup.PopupCoordinates(Loc.GetString("portal-component-invalid-configuration-fizzle"),
ourCoords, Filter.Pvs(ourCoords, entityMan: EntityManager), true);
_popup.PopupCoordinates(Loc.GetString("portal-component-invalid-configuration-fizzle"),
target, Filter.Pvs(target, entityMan: EntityManager), true);
QueueDel(portal);
if (targetEntity != null)
QueueDel(targetEntity.Value);
return;
}
var arrivalSound = CompOrNull<PortalComponent>(targetEntity)?.ArrivalSound ?? portalComponent.ArrivalSound; var arrivalSound = CompOrNull<PortalComponent>(targetEntity)?.ArrivalSound ?? portalComponent.ArrivalSound;
var departureSound = portalComponent.DepartureSound; var departureSound = portalComponent.DepartureSound;
@@ -159,6 +222,9 @@ public abstract class SharedPortalSystem : EntitySystem
_transform.SetCoordinates(subject, target); _transform.SetCoordinates(subject, target);
if (!playSound)
return;
_audio.PlayPredicted(departureSound, portal, subject); _audio.PlayPredicted(departureSound, portal, subject);
_audio.PlayPredicted(arrivalSound, subject, subject); _audio.PlayPredicted(arrivalSound, subject, subject);
} }

View File

@@ -0,0 +1,8 @@
### Portal verb text
portal-component-ghost-traverse = Traverse
portal-component-no-linked-entities = Can't ghost traverse a portal that doesn't have exactly 1 linked portal
portal-component-can-ghost-traverse = Teleport to the linked portal
portal-component-invalid-configuration-fizzle = The portal fizzles out!

View File

@@ -4,6 +4,8 @@
name: bluespace portal name: bluespace portal
description: Transports you to a linked destination! description: Transports you to a linked destination!
components: components:
- type: Transform
anchored: True
- type: InteractionOutline - type: InteractionOutline
- type: Clickable - type: Clickable
- type: Physics - type: Physics
@@ -34,8 +36,9 @@
- type: PointLight - type: PointLight
color: OrangeRed color: OrangeRed
radius: 3 radius: 3
energy: 3 energy: 1
netsync: false netsync: false
- type: entity - type: entity
id: PortalBlue id: PortalBlue
parent: BasePortal parent: BasePortal
@@ -46,5 +49,5 @@
- type: PointLight - type: PointLight
color: SkyBlue color: SkyBlue
radius: 3 radius: 3
energy: 3 energy: 1
netsync: false netsync: false

View File

@@ -5,7 +5,7 @@
"y": 32 "y": 32
}, },
"license": "CC-BY-SA-3.0", "license": "CC-BY-SA-3.0",
"copyright": "Taken from tgStation at commit https://github.com/tgstation/tgstation/blob/4a367160a204db4c5b51c1f811a3b899f0bde3ea/icons/obj/stationobjs.dmi", "copyright": "Taken from tgStation at commit https://github.com/tgstation/tgstation/blob/4a367160a204db4c5b51c1f811a3b899f0bde3ea/icons/obj/stationobjs.dmi and repaletted using old tg sprites by mirrorcult",
"states": [ "states": [
{ {
"name": "portal-blue", "name": "portal-blue",
@@ -24,15 +24,6 @@
0.1, 0.1 0.1, 0.1
] ]
] ]
},
{
"name": "portal",
"delays": [
[
0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1,
0.1, 0.1
]
]
} }
] ]
} }

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.9 KiB

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 KiB

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.8 KiB