From 83d95e0b210927a5ca354ee5dfd0aed9e824df8f Mon Sep 17 00:00:00 2001
From: keronshb <54602815+keronshb@users.noreply.github.com>
Date: Mon, 28 Apr 2025 20:42:24 +0300
Subject: [PATCH] Wizard Teleport Scroll (Teleport Location ECS) (#36424)
(cherry picked from commit 0a394d4af5b3b5320a011ae2bbe0542f41fe22dc)
---
Content.Benchmarks/PvsBenchmark.cs | 1 +
.../Teleportation/TeleportLocationsSystem.cs | 11 +++
.../Ui/TeleportLocationsBoundUserInterface.cs | 36 +++++++++
.../Teleportation/Ui/TeleportMenu.xaml | 10 +++
.../Teleportation/Ui/TeleportMenu.xaml.cs | 74 +++++++++++++++++++
.../Administration/Commands/WarpCommand.cs | 1 +
Content.Server/Ghost/GhostSystem.cs | 1 +
.../Systems/NinjaConditionsSystem.cs | 1 +
Content.Server/Pinpointer/NavMapSystem.cs | 1 +
.../Teleportation/TeleportLocationsSystem.cs | 71 ++++++++++++++++++
Content.Server/Warps/WarpPointComponent.cs | 18 -----
Content.Server/Warps/WarpPointSystem.cs | 1 +
.../Components/TeleportLocationsComponent.cs | 66 +++++++++++++++++
.../Systems/SharedTeleportLocationsSystem.cs | 59 +++++++++++++++
.../Teleportation/TeleportLocationsUi.cs | 19 +++++
Content.Shared/Warps/WarpPointComponent.cs | 27 +++++++
.../teleportation/teleportation-menu-gui.ftl | 6 ++
.../Entities/Markers/warp_point.yml | 22 ++++++
.../Entities/Mobs/Player/narsie.yml | 6 ++
.../Entities/Mobs/Player/ratvar.yml | 6 ++
.../Entities/Mobs/Player/silicon.yml | 18 +++++
.../Objects/Devices/station_beacon.yml | 47 ++++++++++++
.../Entities/Objects/Fun/immovable_rod.yml | 3 +
.../Entities/Objects/Misc/dat_fukken_disk.yml | 4 +
.../Entities/Objects/Power/powersink.yml | 6 ++
.../Entities/Structures/Machines/nuke.yml | 6 ++
.../Generation/Singularity/singularity.yml | 6 ++
.../Power/Generation/Tesla/energyball.yml | 6 ++
.../Prototypes/Magic/teleport_scroll.yml | 26 +++++++
.../Roles/Jobs/Fun/wizard_startinggear.yml | 8 +-
Resources/Prototypes/tags.yml | 4 +
31 files changed, 546 insertions(+), 25 deletions(-)
create mode 100644 Content.Client/Teleportation/TeleportLocationsSystem.cs
create mode 100644 Content.Client/Teleportation/Ui/TeleportLocationsBoundUserInterface.cs
create mode 100644 Content.Client/Teleportation/Ui/TeleportMenu.xaml
create mode 100644 Content.Client/Teleportation/Ui/TeleportMenu.xaml.cs
create mode 100644 Content.Server/Teleportation/TeleportLocationsSystem.cs
delete mode 100644 Content.Server/Warps/WarpPointComponent.cs
create mode 100644 Content.Shared/Teleportation/Components/TeleportLocationsComponent.cs
create mode 100644 Content.Shared/Teleportation/Systems/SharedTeleportLocationsSystem.cs
create mode 100644 Content.Shared/Teleportation/TeleportLocationsUi.cs
create mode 100644 Content.Shared/Warps/WarpPointComponent.cs
create mode 100644 Resources/Locale/en-US/teleportation/teleportation-menu-gui.ftl
create mode 100644 Resources/Prototypes/Magic/teleport_scroll.yml
diff --git a/Content.Benchmarks/PvsBenchmark.cs b/Content.Benchmarks/PvsBenchmark.cs
index 2f87545426..1edbcb6448 100644
--- a/Content.Benchmarks/PvsBenchmark.cs
+++ b/Content.Benchmarks/PvsBenchmark.cs
@@ -7,6 +7,7 @@ using Content.IntegrationTests;
using Content.IntegrationTests.Pair;
using Content.Server.Mind;
using Content.Server.Warps;
+using Content.Shared.Warps;
using Robust.Shared;
using Robust.Shared.Analyzers;
using Robust.Shared.EntitySerialization;
diff --git a/Content.Client/Teleportation/TeleportLocationsSystem.cs b/Content.Client/Teleportation/TeleportLocationsSystem.cs
new file mode 100644
index 0000000000..d191b8d385
--- /dev/null
+++ b/Content.Client/Teleportation/TeleportLocationsSystem.cs
@@ -0,0 +1,11 @@
+using Content.Shared.Teleportation.Systems;
+
+namespace Content.Client.Teleportation;
+
+///
+///
+///
+public sealed partial class TeleportLocationsSystem : SharedTeleportLocationsSystem
+{
+
+}
diff --git a/Content.Client/Teleportation/Ui/TeleportLocationsBoundUserInterface.cs b/Content.Client/Teleportation/Ui/TeleportLocationsBoundUserInterface.cs
new file mode 100644
index 0000000000..80b4f30094
--- /dev/null
+++ b/Content.Client/Teleportation/Ui/TeleportLocationsBoundUserInterface.cs
@@ -0,0 +1,36 @@
+using Content.Shared.Teleportation;
+using Content.Shared.Teleportation.Components;
+using JetBrains.Annotations;
+using Robust.Client.UserInterface;
+
+namespace Content.Client.Teleportation.Ui;
+
+[UsedImplicitly]
+public sealed class TeleportLocationsBoundUserInterface : BoundUserInterface
+{
+ [ViewVariables]
+ private TeleportMenu? _menu;
+
+ public TeleportLocationsBoundUserInterface(EntityUid owner, Enum uiKey) : base(owner, uiKey)
+ {
+ }
+
+ protected override void Open()
+ {
+ base.Open();
+
+ _menu = this.CreateWindow();
+
+ if (!EntMan.TryGetComponent(Owner, out var teleComp))
+ return;
+
+ _menu.Title = Loc.GetString(teleComp.Name);
+ _menu.Warps = teleComp.AvailableWarps;
+ _menu.AddTeleportButtons();
+
+ _menu.TeleportClicked += (netEnt, pointName) =>
+ {
+ SendPredictedMessage(new TeleportLocationDestinationMessage(netEnt, pointName));
+ };
+ }
+}
diff --git a/Content.Client/Teleportation/Ui/TeleportMenu.xaml b/Content.Client/Teleportation/Ui/TeleportMenu.xaml
new file mode 100644
index 0000000000..50a77bbbcc
--- /dev/null
+++ b/Content.Client/Teleportation/Ui/TeleportMenu.xaml
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/Content.Client/Teleportation/Ui/TeleportMenu.xaml.cs b/Content.Client/Teleportation/Ui/TeleportMenu.xaml.cs
new file mode 100644
index 0000000000..1a730bf747
--- /dev/null
+++ b/Content.Client/Teleportation/Ui/TeleportMenu.xaml.cs
@@ -0,0 +1,74 @@
+using System.Numerics;
+using Content.Shared.Teleportation.Components;
+using Robust.Client.AutoGenerated;
+using Robust.Client.UserInterface.CustomControls;
+using Robust.Client.UserInterface.XAML;
+using Robust.Client.UserInterface.Controls;
+
+namespace Content.Client.Teleportation.Ui;
+
+[GenerateTypedNameReferences]
+public sealed partial class TeleportMenu : DefaultWindow
+{
+ public string SearchText = "";
+
+ public HashSet Warps = new();
+
+ public event Action? TeleportClicked;
+
+ public TeleportMenu()
+ {
+ RobustXamlLoader.Load(this);
+ IoCManager.InjectDependencies(this);
+
+ SearchBar.OnTextChanged += OnSearchTextChanged;
+ }
+
+ public void AddTeleportButtons()
+ {
+ foreach (var points in Warps)
+ {
+ var name = points.Location;
+ var teleportPoint = points.TelePoint;
+
+ var currentButtonRef = new Button
+ {
+ Text = name,
+ TextAlign = Label.AlignMode.Right,
+ HorizontalAlignment = HAlignment.Center,
+ VerticalAlignment = VAlignment.Center,
+ SizeFlagsStretchRatio = 1,
+ MinSize = new Vector2(340, 20),
+ ClipText = true,
+ };
+
+ currentButtonRef.OnPressed += _ => TeleportClicked?.Invoke(teleportPoint, name);
+ currentButtonRef.Visible = ButtonIsVisible(currentButtonRef);
+
+ TeleportButtonContainer.AddChild(currentButtonRef);
+ }
+ }
+
+ private bool ButtonIsVisible(Button button)
+ {
+ return string.IsNullOrEmpty(SearchText) || button.Text == null ||
+ button.Text.Contains(SearchText, StringComparison.OrdinalIgnoreCase);
+ }
+
+ private void UpdateVisibleButtons()
+ {
+ foreach (var child in TeleportButtonContainer.Children)
+ {
+ if (child is Button button)
+ button.Visible = ButtonIsVisible(button);
+ }
+ }
+
+ public void OnSearchTextChanged(LineEdit.LineEditEventArgs args)
+ {
+ SearchText = args.Text;
+ UpdateVisibleButtons();
+ // Very funny it's called TeleportScroll
+ TeleportScroll.SetScrollValue(Vector2.Zero);
+ }
+}
diff --git a/Content.Server/Administration/Commands/WarpCommand.cs b/Content.Server/Administration/Commands/WarpCommand.cs
index 0d6da0d993..8a2c133e44 100644
--- a/Content.Server/Administration/Commands/WarpCommand.cs
+++ b/Content.Server/Administration/Commands/WarpCommand.cs
@@ -4,6 +4,7 @@ using Content.Server.Warps;
using Content.Shared.Administration;
using Content.Shared.Follower;
using Content.Shared.Ghost;
+using Content.Shared.Warps;
using Robust.Shared.Console;
using Robust.Shared.Enums;
using Robust.Shared.Map;
diff --git a/Content.Server/Ghost/GhostSystem.cs b/Content.Server/Ghost/GhostSystem.cs
index accc0a9c86..a843d9e4cb 100644
--- a/Content.Server/Ghost/GhostSystem.cs
+++ b/Content.Server/Ghost/GhostSystem.cs
@@ -30,6 +30,7 @@ using Content.Shared.Movement.Systems;
using Content.Shared.Popups;
using Content.Shared.Storage.Components;
using Content.Shared.Tag;
+using Content.Shared.Warps;
using Robust.Server.GameObjects;
using Robust.Server.Player;
using Robust.Shared.Configuration;
diff --git a/Content.Server/Objectives/Systems/NinjaConditionsSystem.cs b/Content.Server/Objectives/Systems/NinjaConditionsSystem.cs
index ee99658f66..808829f6d9 100644
--- a/Content.Server/Objectives/Systems/NinjaConditionsSystem.cs
+++ b/Content.Server/Objectives/Systems/NinjaConditionsSystem.cs
@@ -4,6 +4,7 @@ using Content.Server.Warps;
using Content.Shared.Objectives.Components;
using Content.Shared.Ninja.Components;
using Content.Shared.Roles;
+using Content.Shared.Warps;
using Robust.Shared.Random;
namespace Content.Server.Objectives.Systems;
diff --git a/Content.Server/Pinpointer/NavMapSystem.cs b/Content.Server/Pinpointer/NavMapSystem.cs
index 547ac47f23..dcedeb15cc 100644
--- a/Content.Server/Pinpointer/NavMapSystem.cs
+++ b/Content.Server/Pinpointer/NavMapSystem.cs
@@ -13,6 +13,7 @@ using Robust.Shared.Map;
using Robust.Shared.Map.Components;
using Robust.Shared.Timing;
using System.Diagnostics.CodeAnalysis;
+using Content.Shared.Warps;
namespace Content.Server.Pinpointer;
diff --git a/Content.Server/Teleportation/TeleportLocationsSystem.cs b/Content.Server/Teleportation/TeleportLocationsSystem.cs
new file mode 100644
index 0000000000..14211d9672
--- /dev/null
+++ b/Content.Server/Teleportation/TeleportLocationsSystem.cs
@@ -0,0 +1,71 @@
+using Content.Server.Chat.Systems;
+using Content.Shared.Teleportation;
+using Content.Shared.Teleportation.Components;
+using Content.Shared.Teleportation.Systems;
+using Content.Shared.UserInterface;
+using Content.Shared.Warps;
+using Content.Shared.Whitelist;
+
+namespace Content.Server.Teleportation;
+
+///
+///
+///
+public sealed partial class TeleportLocationsSystem : SharedTeleportLocationsSystem
+{
+ [Dependency] private readonly ChatSystem _chat = default!;
+ [Dependency] private readonly EntityWhitelistSystem _whitelist = default!;
+
+ public override void Initialize()
+ {
+ base.Initialize();
+
+ SubscribeLocalEvent(OnMapInit);
+ SubscribeLocalEvent(OnBeforeUiOpen);
+ }
+
+ private void OnMapInit(Entity ent, ref MapInitEvent args)
+ {
+ UpdateTeleportPoints(ent);
+ }
+
+ private void OnBeforeUiOpen(Entity ent, ref BeforeActivatableUIOpenEvent args)
+ {
+ UpdateTeleportPoints(ent);
+ }
+
+ protected override void OnTeleportToLocationRequest(Entity ent, ref TeleportLocationDestinationMessage args)
+ {
+ if (Delay.IsDelayed(ent.Owner, TeleportDelay))
+ return;
+
+ if (!string.IsNullOrWhiteSpace(ent.Comp.Speech))
+ {
+ var msg = Loc.GetString(ent.Comp.Speech, ("location", args.PointName));
+ _chat.TrySendInGameICMessage(args.Actor, msg, InGameICChatType.Speak, ChatTransmitRange.Normal);
+ }
+
+ base.OnTeleportToLocationRequest(ent, ref args);
+ }
+
+ // If it's in shared this doesn't populate the points on the UI
+ ///
+ /// Gets the teleport points to send to the BUI
+ ///
+ private void UpdateTeleportPoints(Entity ent)
+ {
+ ent.Comp.AvailableWarps.Clear();
+
+ var allEnts = AllEntityQuery();
+
+ while (allEnts.MoveNext(out var warpEnt, out var warpPointComp))
+ {
+ if (_whitelist.IsBlacklistPass(warpPointComp.Blacklist, warpEnt) || string.IsNullOrWhiteSpace(warpPointComp.Location))
+ continue;
+
+ ent.Comp.AvailableWarps.Add(new TeleportPoint(warpPointComp.Location, GetNetEntity(warpEnt)));
+ }
+
+ Dirty(ent);
+ }
+}
diff --git a/Content.Server/Warps/WarpPointComponent.cs b/Content.Server/Warps/WarpPointComponent.cs
deleted file mode 100644
index ce169f2e19..0000000000
--- a/Content.Server/Warps/WarpPointComponent.cs
+++ /dev/null
@@ -1,18 +0,0 @@
-namespace Content.Server.Warps
-{
- ///
- /// Allows ghosts etc to warp to this entity by name.
- ///
- [RegisterComponent]
- public sealed partial class WarpPointComponent : Component
- {
- [ViewVariables(VVAccess.ReadWrite), DataField]
- public string? Location;
-
- ///
- /// If true, ghosts warping to this entity will begin following it.
- ///
- [DataField]
- public bool Follow;
- }
-}
diff --git a/Content.Server/Warps/WarpPointSystem.cs b/Content.Server/Warps/WarpPointSystem.cs
index d3b978a147..2e2264a81a 100644
--- a/Content.Server/Warps/WarpPointSystem.cs
+++ b/Content.Server/Warps/WarpPointSystem.cs
@@ -1,5 +1,6 @@
using Content.Shared.Examine;
using Content.Shared.Ghost;
+using Content.Shared.Warps;
namespace Content.Server.Warps;
diff --git a/Content.Shared/Teleportation/Components/TeleportLocationsComponent.cs b/Content.Shared/Teleportation/Components/TeleportLocationsComponent.cs
new file mode 100644
index 0000000000..ef5d6c5b2c
--- /dev/null
+++ b/Content.Shared/Teleportation/Components/TeleportLocationsComponent.cs
@@ -0,0 +1,66 @@
+using Content.Shared.Teleportation.Systems;
+using Robust.Shared.GameStates;
+using Robust.Shared.Prototypes;
+using Robust.Shared.Serialization;
+
+namespace Content.Shared.Teleportation.Components;
+
+// TODO: In the future assimilate ghost UI to use this.
+///
+/// Used where you want an entity to display a list of player-safe teleport locations
+/// They teleport to the location clicked
+/// Looks for non Ghost-Only WarpPointComponents
+///
+[RegisterComponent, NetworkedComponent, Access(typeof(SharedTeleportLocationsSystem)), AutoGenerateComponentState]
+public sealed partial class TeleportLocationsComponent : Component
+{
+ ///
+ /// List of available warp points
+ ///
+ [DataField, AutoNetworkedField]
+ public HashSet AvailableWarps = new();
+
+ ///
+ /// What should spawn as an effect when the user teleports?
+ ///
+ [DataField]
+ public EntProtoId? TeleportEffect;
+
+ ///
+ /// Should this close the BUI after teleport?
+ ///
+ [DataField]
+ public bool CloseAfterTeleport;
+
+ ///
+ /// Name of the Teleport Location menu
+ ///
+ [DataField]
+ public LocId Name;
+
+ ///
+ /// Should the user have some speech if they teleport?
+ /// If enabled it will be prepended to the location name.
+ /// So something like "I am going to" would become "I am going to (Bridge)"
+ ///
+ [DataField]
+ public LocId? Speech;
+}
+
+///
+/// A teleport point, which has a location (the destination) and the entity that it represents.
+///
+[Serializable, NetSerializable, DataDefinition]
+public partial record struct TeleportPoint
+{
+ [DataField]
+ public string Location;
+ [DataField]
+ public NetEntity TelePoint;
+
+ public TeleportPoint(string Location, NetEntity TelePoint)
+ {
+ this.Location = Location;
+ this.TelePoint = TelePoint;
+ }
+}
diff --git a/Content.Shared/Teleportation/Systems/SharedTeleportLocationsSystem.cs b/Content.Shared/Teleportation/Systems/SharedTeleportLocationsSystem.cs
new file mode 100644
index 0000000000..eb4be36ced
--- /dev/null
+++ b/Content.Shared/Teleportation/Systems/SharedTeleportLocationsSystem.cs
@@ -0,0 +1,59 @@
+using Content.Shared.Teleportation.Components;
+using Content.Shared.Timing;
+using Content.Shared.UserInterface;
+using Content.Shared.Warps;
+
+namespace Content.Shared.Teleportation.Systems;
+
+///
+///
+///
+public abstract partial class SharedTeleportLocationsSystem : EntitySystem
+{
+ [Dependency] protected readonly UseDelaySystem Delay = default!;
+
+ [Dependency] private readonly SharedUserInterfaceSystem _ui = default!;
+ [Dependency] private readonly SharedTransformSystem _xform = default!;
+
+ protected const string TeleportDelay = "TeleportDelay";
+
+ public override void Initialize()
+ {
+ base.Initialize();
+
+ SubscribeLocalEvent(OnUiOpenAttempt);
+ SubscribeLocalEvent(OnTeleportToLocationRequest);
+ }
+
+ private void OnUiOpenAttempt(Entity ent, ref ActivatableUIOpenAttemptEvent args)
+ {
+ if (!Delay.IsDelayed(ent.Owner, TeleportDelay))
+ return;
+
+ args.Cancel();
+ }
+
+ protected virtual void OnTeleportToLocationRequest(Entity ent, ref TeleportLocationDestinationMessage args)
+ {
+ if (!TryGetEntity(args.NetEnt, out var telePointEnt) || TerminatingOrDeleted(telePointEnt) || !HasComp(telePointEnt) || Delay.IsDelayed(ent.Owner, TeleportDelay))
+ return;
+
+ var comp = ent.Comp;
+ var originEnt = args.Actor;
+ var telePointXForm = Transform(telePointEnt.Value);
+
+ SpawnAtPosition(comp.TeleportEffect, Transform(originEnt).Coordinates);
+
+ _xform.SetMapCoordinates(originEnt, _xform.GetMapCoordinates(telePointEnt.Value, telePointXForm));
+
+ SpawnAtPosition(comp.TeleportEffect, telePointXForm.Coordinates);
+
+ Delay.TryResetDelay(ent.Owner, true, id: TeleportDelay);
+
+ if (!ent.Comp.CloseAfterTeleport)
+ return;
+
+ // Teleport's done, now tell the BUI to close if needed.
+ _ui.CloseUi(ent.Owner, TeleportLocationUiKey.Key);
+ }
+}
diff --git a/Content.Shared/Teleportation/TeleportLocationsUi.cs b/Content.Shared/Teleportation/TeleportLocationsUi.cs
new file mode 100644
index 0000000000..f4ca97584a
--- /dev/null
+++ b/Content.Shared/Teleportation/TeleportLocationsUi.cs
@@ -0,0 +1,19 @@
+using Robust.Shared.Serialization;
+
+namespace Content.Shared.Teleportation;
+
+[Serializable, NetSerializable]
+public enum TeleportLocationUiKey : byte
+{
+ Key
+}
+
+///
+/// Sends message to request that the clicker teleports to the requested location
+///
+[Serializable, NetSerializable]
+public sealed class TeleportLocationDestinationMessage(NetEntity netEnt, string pointName) : BoundUserInterfaceMessage
+{
+ public NetEntity NetEnt = netEnt;
+ public string PointName = pointName;
+}
diff --git a/Content.Shared/Warps/WarpPointComponent.cs b/Content.Shared/Warps/WarpPointComponent.cs
new file mode 100644
index 0000000000..61e84a660c
--- /dev/null
+++ b/Content.Shared/Warps/WarpPointComponent.cs
@@ -0,0 +1,27 @@
+using Content.Shared.Whitelist;
+using Robust.Shared.GameStates;
+
+namespace Content.Shared.Warps;
+
+///
+/// Allows ghosts etc to warp to this entity by name.
+///
+[RegisterComponent, NetworkedComponent]
+public sealed partial class WarpPointComponent : Component
+{
+ [ViewVariables(VVAccess.ReadWrite), DataField]
+ public string? Location;
+
+ ///
+ /// If true, ghosts warping to this entity will begin following it.
+ ///
+ [DataField]
+ public bool Follow;
+
+ ///
+ /// What points should be excluded?
+ /// Useful where you want things like a ghost to reach only like CentComm
+ ///
+ [DataField]
+ public EntityWhitelist? Blacklist;
+}
diff --git a/Resources/Locale/en-US/teleportation/teleportation-menu-gui.ftl b/Resources/Locale/en-US/teleportation/teleportation-menu-gui.ftl
new file mode 100644
index 0000000000..847f2cbc54
--- /dev/null
+++ b/Resources/Locale/en-US/teleportation/teleportation-menu-gui.ftl
@@ -0,0 +1,6 @@
+## Default
+teleportation-menu-default-window-title = Teleportation Menu
+
+## Wizard
+teleportation-scroll-window-title = Teleportation Scroll
+teleportation-scroll-speech-wizard = EY TCHEL TORT TU {$location}
diff --git a/Resources/Prototypes/Entities/Markers/warp_point.yml b/Resources/Prototypes/Entities/Markers/warp_point.yml
index 2536fde474..675938c09b 100644
--- a/Resources/Prototypes/Entities/Markers/warp_point.yml
+++ b/Resources/Prototypes/Entities/Markers/warp_point.yml
@@ -16,6 +16,22 @@
- type: WarpPoint
location: beacon
+# Use for areas like CC
+- type: entity
+ id: GhostWarpPoint
+ parent: MarkerBase
+ name: ghost only warp point
+ components:
+ - type: Tag
+ tags:
+ - GhostOnlyWarp
+ - type: WarpPoint
+ blacklist:
+ tags:
+ - GhostOnlyWarp
+ - type: Sprite
+ state: pink
+
- type: entity
parent: WarpPoint
id: WarpPointBombing
@@ -23,8 +39,14 @@
suffix: ninja bombing target
components:
- type: BombingTarget
+ - type: Tag
+ tags:
+ - GhostOnlyWarp
- type: WarpPoint
location: bombing target
+ blacklist:
+ tags:
+ - GhostOnlyWarp
- type: Sprite
layers:
- state: pink
diff --git a/Resources/Prototypes/Entities/Mobs/Player/narsie.yml b/Resources/Prototypes/Entities/Mobs/Player/narsie.yml
index 84fd15959b..4f4976106d 100644
--- a/Resources/Prototypes/Entities/Mobs/Player/narsie.yml
+++ b/Resources/Prototypes/Entities/Mobs/Player/narsie.yml
@@ -87,6 +87,12 @@
bodyType: Dynamic
bodyStatus: InAir
- type: CanMoveInAir
+ - type: Tag
+ tags:
+ - GhostOnlyWarp
- type: WarpPoint
follow: true
location: Nar'Sie
+ blacklist:
+ tags:
+ - GhostOnlyWarp
diff --git a/Resources/Prototypes/Entities/Mobs/Player/ratvar.yml b/Resources/Prototypes/Entities/Mobs/Player/ratvar.yml
index 530f5e1037..658f14a6d4 100644
--- a/Resources/Prototypes/Entities/Mobs/Player/ratvar.yml
+++ b/Resources/Prototypes/Entities/Mobs/Player/ratvar.yml
@@ -89,6 +89,12 @@
- type: GravityWell
baseRadialAcceleration: 6
maxRange: 8
+ - type: Tag
+ tags:
+ - GhostOnlyWarp
- type: WarpPoint
follow: true
location: Ratvar
+ blacklist:
+ tags:
+ - GhostOnlyWarp
diff --git a/Resources/Prototypes/Entities/Mobs/Player/silicon.yml b/Resources/Prototypes/Entities/Mobs/Player/silicon.yml
index 35c11dd208..cfca68d5eb 100644
--- a/Resources/Prototypes/Entities/Mobs/Player/silicon.yml
+++ b/Resources/Prototypes/Entities/Mobs/Player/silicon.yml
@@ -169,6 +169,9 @@
description: Handles AI interactions across holocards + AI cores
components:
- type: ItemSlots
+ - type: Tag
+ tags:
+ - GhostOnlyWarp
- type: StationAiHolder
slot:
name: station-ai-mind-slot
@@ -735,6 +738,9 @@
components:
- type: IonStormTarget
- type: WarpPoint
+ blacklist:
+ tags:
+ - GhostOnlyWarp
- type: ContainerComp
proto: AiHeld
container: station_ai_mind_slot
@@ -848,8 +854,14 @@
categories: [ HideSpawnMenu, DoNotMap ]
components:
- type: NoFTL
+ - type: Tag
+ tags:
+ - GhostOnlyWarp
- type: WarpPoint
follow: true
+ blacklist:
+ tags:
+ - GhostOnlyWarp
- type: Eye
pvsScale: 1.5
- type: Visibility
@@ -888,8 +900,14 @@
components:
- type: Transform
anchored: true
+ - type: Tag
+ tags:
+ - GhostOnlyWarp
- type: WarpPoint
follow: true
+ blacklist:
+ tags:
+ - GhostOnlyWarp
- type: Eye
- type: ContentEye
- type: Examiner
diff --git a/Resources/Prototypes/Entities/Objects/Devices/station_beacon.yml b/Resources/Prototypes/Entities/Objects/Devices/station_beacon.yml
index 1f56a0e1c2..a4c2e30481 100644
--- a/Resources/Prototypes/Entities/Objects/Devices/station_beacon.yml
+++ b/Resources/Prototypes/Entities/Objects/Devices/station_beacon.yml
@@ -661,3 +661,50 @@
components:
- type: NavMapBeacon
defaultText: station-beacon-vox
+
+# Ghost Only Beacons
+- type: entity
+ parent: DefaultStationBeacon
+ id: DefaultStationBeaconGhost
+ suffix: Boo
+ components:
+ - type: Tag
+ tags:
+ - GhostOnlyWarp
+ - type: WarpPoint
+ blacklist:
+ tags:
+ - GhostOnlyWarp
+
+# CentComm Beacons
+- type: entity
+ parent: DefaultStationBeaconGhost
+ id: DefaultStationBeaconCentComm
+ suffix: CentComm
+ components:
+ - type: NavMapBeacon
+ text: CentComm
+
+- type: entity
+ parent: DefaultStationBeaconGhost
+ id: DefaultStationBeaconCentCommAfterhours
+ suffix: CentComm Afterhours
+ components:
+ - type: NavMapBeacon
+ text: Afterhours
+
+- type: entity
+ parent: DefaultStationBeaconGhost
+ id: DefaultStationBeaconCentCommThunderdome
+ suffix: CentComm Thunder Dome
+ components:
+ - type: NavMapBeacon
+ text: Thunderdome
+
+- type: entity
+ parent: DefaultStationBeaconGhost
+ id: DefaultStationBeaconCentCommERT
+ suffix: CentComm ERT
+ components:
+ - type: NavMapBeacon
+ text: ERT
diff --git a/Resources/Prototypes/Entities/Objects/Fun/immovable_rod.yml b/Resources/Prototypes/Entities/Objects/Fun/immovable_rod.yml
index 318ca667fe..420cc759a7 100644
--- a/Resources/Prototypes/Entities/Objects/Fun/immovable_rod.yml
+++ b/Resources/Prototypes/Entities/Objects/Fun/immovable_rod.yml
@@ -32,6 +32,9 @@
- type: WarpPoint
follow: true
location: immovable rod
+ blacklist:
+ tags:
+ - GhostOnlyWarp
- type: entity
id: ImmovableRodDespawn
diff --git a/Resources/Prototypes/Entities/Objects/Misc/dat_fukken_disk.yml b/Resources/Prototypes/Entities/Objects/Misc/dat_fukken_disk.yml
index ca575b3e89..1d57742a81 100644
--- a/Resources/Prototypes/Entities/Objects/Misc/dat_fukken_disk.yml
+++ b/Resources/Prototypes/Entities/Objects/Misc/dat_fukken_disk.yml
@@ -17,9 +17,13 @@
- type: WarpPoint
follow: true
location: nuke disk
+ blacklist:
+ tags:
+ - GhostOnlyWarp
- type: Tag
tags:
- HighRiskItem
+ - GhostOnlyWarp
- type: StealTarget
stealGroup: NukeDisk
- type: EmitSoundOnPickup
diff --git a/Resources/Prototypes/Entities/Objects/Power/powersink.yml b/Resources/Prototypes/Entities/Objects/Power/powersink.yml
index 40406209a7..5d1043f08c 100644
--- a/Resources/Prototypes/Entities/Objects/Power/powersink.yml
+++ b/Resources/Prototypes/Entities/Objects/Power/powersink.yml
@@ -45,5 +45,11 @@
- type: Sprite
sprite: Objects/Power/powersink.rsi
state: powersink
+ - type: Tag
+ tags:
+ - GhostOnlyWarp
- type: WarpPoint
location: powersink
+ blacklist:
+ tags:
+ - GhostOnlyWarp
diff --git a/Resources/Prototypes/Entities/Structures/Machines/nuke.yml b/Resources/Prototypes/Entities/Structures/Machines/nuke.yml
index 6c351c0074..425a7ea5de 100644
--- a/Resources/Prototypes/Entities/Structures/Machines/nuke.yml
+++ b/Resources/Prototypes/Entities/Structures/Machines/nuke.yml
@@ -100,9 +100,15 @@
Nuke: !type:ContainerSlot
- type: StealTarget
stealGroup: NuclearBomb
+ - type: Tag
+ tags:
+ - GhostOnlyWarp
- type: WarpPoint
follow: true
location: nuclear bomb
+ blacklist:
+ tags:
+ - GhostOnlyWarp
- type: FTLSmashImmune
- type: entity
diff --git a/Resources/Prototypes/Entities/Structures/Power/Generation/Singularity/singularity.yml b/Resources/Prototypes/Entities/Structures/Power/Generation/Singularity/singularity.yml
index e9faaa813d..1b0d43790d 100644
--- a/Resources/Prototypes/Entities/Structures/Power/Generation/Singularity/singularity.yml
+++ b/Resources/Prototypes/Entities/Structures/Power/Generation/Singularity/singularity.yml
@@ -67,9 +67,15 @@
- SingularityEngine
- SingularityTeslaEngine
- Power
+ - type: Tag
+ tags:
+ - GhostOnlyWarp
- type: WarpPoint
follow: true
location: singularity
+ blacklist:
+ tags:
+ - GhostOnlyWarp
- type: Sprite
sprite: Structures/Power/Generation/Singularity/singularity_1.rsi
shader: unshaded
diff --git a/Resources/Prototypes/Entities/Structures/Power/Generation/Tesla/energyball.yml b/Resources/Prototypes/Entities/Structures/Power/Generation/Tesla/energyball.yml
index e4dd0d42fe..1b7e641c7d 100644
--- a/Resources/Prototypes/Entities/Structures/Power/Generation/Tesla/energyball.yml
+++ b/Resources/Prototypes/Entities/Structures/Power/Generation/Tesla/energyball.yml
@@ -90,9 +90,15 @@
- type: ChaoticJump
jumpMinInterval: 8
jumpMaxInterval: 15
+ - type: Tag
+ tags:
+ - GhostOnlyWarp
- type: WarpPoint
follow: true
location: tesla ball
+ blacklist:
+ tags:
+ - GhostOnlyWarp
- type: Sprite
drawdepth: Effects
sprite: Structures/Power/Generation/Tesla/energy_ball.rsi
diff --git a/Resources/Prototypes/Magic/teleport_scroll.yml b/Resources/Prototypes/Magic/teleport_scroll.yml
new file mode 100644
index 0000000000..89c9ae5163
--- /dev/null
+++ b/Resources/Prototypes/Magic/teleport_scroll.yml
@@ -0,0 +1,26 @@
+- type: entity
+ id: WizardTeleportScroll
+ name: teleport scroll
+ suffix: Wizard
+ parent: [ BaseItem, BaseMagicalContraband ]
+ components:
+ - type: UserInterface
+ interfaces:
+ enum.TeleportLocationUiKey.Key:
+ type: TeleportLocationsBoundUserInterface
+ - type: ActivatableUI
+ key: enum.TeleportLocationUiKey.Key
+ - type: Sprite
+ sprite: Objects/Magic/magicactions.rsi
+ layers:
+ - state: spell_default
+ - type: TeleportLocations
+ name: teleportation-scroll-window-title
+ teleportEffect: WizardSmoke
+ closeAfterTeleport: true
+ speech: teleportation-scroll-speech-wizard
+ - type: UseDelay
+ delay: 1
+ delays:
+ TeleportDelay: !type:UseDelayInfo
+ length: 300
diff --git a/Resources/Prototypes/Roles/Jobs/Fun/wizard_startinggear.yml b/Resources/Prototypes/Roles/Jobs/Fun/wizard_startinggear.yml
index 50c65d4bc7..fd3142255a 100644
--- a/Resources/Prototypes/Roles/Jobs/Fun/wizard_startinggear.yml
+++ b/Resources/Prototypes/Roles/Jobs/Fun/wizard_startinggear.yml
@@ -12,7 +12,7 @@
id: WizardPDA
ears: ClothingHeadsetAltCommand
belt: ClothingBeltWand
- # pocket1: TODO: Include wizard teleport scroll
+ pocket1: WizardTeleportScroll
pocket2: WizardsGrimoire
- type: startingGear
@@ -30,9 +30,3 @@
jumpsuit: ClothingUniformJumpsuitColorPurple
head: ClothingHeadHatVioletwizard
outerClothing: ClothingOuterWizardViolet
-
-- type: startingGear
- id: WizardHardsuitGear
- parent: WizardVioletGear
- equipment:
- outerClothing: ClothingOuterHardsuitWizard
diff --git a/Resources/Prototypes/tags.yml b/Resources/Prototypes/tags.yml
index 2426b3ab4b..a96e2d24ed 100644
--- a/Resources/Prototypes/tags.yml
+++ b/Resources/Prototypes/tags.yml
@@ -638,6 +638,10 @@
- type: Tag
id: GeigerCounter
+# Used for warps
+- type: Tag
+ id: GhostOnlyWarp
+
- type: Tag
id: GlassAirlock