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;
--- /dev/null
+using Content.Shared.Teleportation.Systems;
+
+namespace Content.Client.Teleportation;
+
+/// <summary>
+/// <inheritdoc cref="SharedTeleportLocationsSystem"/>
+/// </summary>
+public sealed partial class TeleportLocationsSystem : SharedTeleportLocationsSystem
+{
+
+}
--- /dev/null
+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<TeleportMenu>();
+
+ if (!EntMan.TryGetComponent<TeleportLocationsComponent>(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));
+ };
+ }
+}
--- /dev/null
+<DefaultWindow xmlns="https://spacestation14.io" Title = "{Loc 'teleportation-scroll-window-title'}" MinSize="450 450" SetSize="450 450">
+ <BoxContainer Orientation="Vertical" HorizontalExpand="True" SizeFlagsStretchRatio="0.4">
+ <LineEdit Name="SearchBar" PlaceHolder="Search" HorizontalExpand="True" Margin="0 4" />
+ <ScrollContainer Name="TeleportScroll" VerticalExpand="True" HorizontalExpand="True" HScrollEnabled="False">
+ <BoxContainer Name="TeleportButtonContainer" Orientation="Vertical" VerticalExpand="True" SeparationOverride="5">
+ <!-- Teleport buttons get added here by code -->
+ </BoxContainer>
+ </ScrollContainer>
+ </BoxContainer>
+</DefaultWindow>
--- /dev/null
+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<TeleportPoint> Warps = new();
+
+ public event Action<NetEntity, string>? 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);
+ }
+}
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;
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;
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;
using Robust.Shared.Map.Components;
using Robust.Shared.Timing;
using System.Diagnostics.CodeAnalysis;
+using Content.Shared.Warps;
namespace Content.Server.Pinpointer;
--- /dev/null
+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;
+
+/// <summary>
+/// <inheritdoc cref="SharedTeleportLocationsSystem"/>
+/// </summary>
+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<TeleportLocationsComponent, MapInitEvent>(OnMapInit);
+ SubscribeLocalEvent<TeleportLocationsComponent, BeforeActivatableUIOpenEvent>(OnBeforeUiOpen);
+ }
+
+ private void OnMapInit(Entity<TeleportLocationsComponent> ent, ref MapInitEvent args)
+ {
+ UpdateTeleportPoints(ent);
+ }
+
+ private void OnBeforeUiOpen(Entity<TeleportLocationsComponent> ent, ref BeforeActivatableUIOpenEvent args)
+ {
+ UpdateTeleportPoints(ent);
+ }
+
+ protected override void OnTeleportToLocationRequest(Entity<TeleportLocationsComponent> 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
+ /// <summary>
+ /// Gets the teleport points to send to the BUI
+ /// </summary>
+ private void UpdateTeleportPoints(Entity<TeleportLocationsComponent> ent)
+ {
+ ent.Comp.AvailableWarps.Clear();
+
+ var allEnts = AllEntityQuery<WarpPointComponent>();
+
+ 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);
+ }
+}
+++ /dev/null
-namespace Content.Server.Warps
-{
- /// <summary>
- /// Allows ghosts etc to warp to this entity by name.
- /// </summary>
- [RegisterComponent]
- public sealed partial class WarpPointComponent : Component
- {
- [ViewVariables(VVAccess.ReadWrite), DataField]
- public string? Location;
-
- /// <summary>
- /// If true, ghosts warping to this entity will begin following it.
- /// </summary>
- [DataField]
- public bool Follow;
- }
-}
using Content.Shared.Examine;
using Content.Shared.Ghost;
+using Content.Shared.Warps;
namespace Content.Server.Warps;
--- /dev/null
+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.
+/// <summary>
+/// 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
+/// </summary>
+[RegisterComponent, NetworkedComponent, Access(typeof(SharedTeleportLocationsSystem)), AutoGenerateComponentState]
+public sealed partial class TeleportLocationsComponent : Component
+{
+ /// <summary>
+ /// List of available warp points
+ /// </summary>
+ [DataField, AutoNetworkedField]
+ public HashSet<TeleportPoint> AvailableWarps = new();
+
+ /// <summary>
+ /// What should spawn as an effect when the user teleports?
+ /// </summary>
+ [DataField]
+ public EntProtoId? TeleportEffect;
+
+ /// <summary>
+ /// Should this close the BUI after teleport?
+ /// </summary>
+ [DataField]
+ public bool CloseAfterTeleport;
+
+ /// <summary>
+ /// Name of the Teleport Location menu
+ /// </summary>
+ [DataField]
+ public LocId Name;
+
+ /// <summary>
+ /// 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)"
+ /// </summary>
+ [DataField]
+ public LocId? Speech;
+}
+
+/// <summary>
+/// A teleport point, which has a location (the destination) and the entity that it represents.
+/// </summary>
+[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;
+ }
+}
--- /dev/null
+using Content.Shared.Teleportation.Components;
+using Content.Shared.Timing;
+using Content.Shared.UserInterface;
+using Content.Shared.Warps;
+
+namespace Content.Shared.Teleportation.Systems;
+
+/// <summary>
+/// <inheritdoc cref="TeleportLocationsComponent"/>
+/// </summary>
+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<TeleportLocationsComponent, ActivatableUIOpenAttemptEvent>(OnUiOpenAttempt);
+ SubscribeLocalEvent<TeleportLocationsComponent, TeleportLocationDestinationMessage>(OnTeleportToLocationRequest);
+ }
+
+ private void OnUiOpenAttempt(Entity<TeleportLocationsComponent> ent, ref ActivatableUIOpenAttemptEvent args)
+ {
+ if (!Delay.IsDelayed(ent.Owner, TeleportDelay))
+ return;
+
+ args.Cancel();
+ }
+
+ protected virtual void OnTeleportToLocationRequest(Entity<TeleportLocationsComponent> ent, ref TeleportLocationDestinationMessage args)
+ {
+ if (!TryGetEntity(args.NetEnt, out var telePointEnt) || TerminatingOrDeleted(telePointEnt) || !HasComp<WarpPointComponent>(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);
+ }
+}
--- /dev/null
+using Robust.Shared.Serialization;
+
+namespace Content.Shared.Teleportation;
+
+[Serializable, NetSerializable]
+public enum TeleportLocationUiKey : byte
+{
+ Key
+}
+
+/// <summary>
+/// Sends message to request that the clicker teleports to the requested location
+/// </summary>
+[Serializable, NetSerializable]
+public sealed class TeleportLocationDestinationMessage(NetEntity netEnt, string pointName) : BoundUserInterfaceMessage
+{
+ public NetEntity NetEnt = netEnt;
+ public string PointName = pointName;
+}
--- /dev/null
+using Content.Shared.Whitelist;
+using Robust.Shared.GameStates;
+
+namespace Content.Shared.Warps;
+
+/// <summary>
+/// Allows ghosts etc to warp to this entity by name.
+/// </summary>
+[RegisterComponent, NetworkedComponent]
+public sealed partial class WarpPointComponent : Component
+{
+ [ViewVariables(VVAccess.ReadWrite), DataField]
+ public string? Location;
+
+ /// <summary>
+ /// If true, ghosts warping to this entity will begin following it.
+ /// </summary>
+ [DataField]
+ public bool Follow;
+
+ /// <summary>
+ /// What points should be excluded?
+ /// Useful where you want things like a ghost to reach only like CentComm
+ /// </summary>
+ [DataField]
+ public EntityWhitelist? Blacklist;
+}
--- /dev/null
+## Default
+teleportation-menu-default-window-title = Teleportation Menu
+
+## Wizard
+teleportation-scroll-window-title = Teleportation Scroll
+teleportation-scroll-speech-wizard = EY TCHEL TORT TU {$location}
meta:
format: 7
category: Grid
- engineVersion: 247.2.0
+ engineVersion: 250.0.0
forkId: ""
forkVersion: ""
- time: 03/05/2025 09:01:26
+ time: 04/24/2025 00:06:42
entityCount: 9680
maps: []
grids:
- type: Transform
pos: 3.5,-12.5
parent: 1668
+- proto: ChemistryBottleEpinephrine
+ entities:
+ - uid: 6859
+ components:
+ - type: Transform
+ parent: 6846
+ - type: Physics
+ canCollide: False
+ - type: InsideEntityStorage
+ - uid: 6860
+ components:
+ - type: Transform
+ parent: 6846
+ - type: Physics
+ canCollide: False
+ - type: InsideEntityStorage
+ - uid: 6867
+ components:
+ - type: Transform
+ parent: 6865
+ - type: Physics
+ canCollide: False
+ - type: InsideEntityStorage
+ - uid: 6871
+ components:
+ - type: Transform
+ parent: 6865
+ - type: Physics
+ canCollide: False
+ - type: InsideEntityStorage
+- proto: ChemistryBottleOmnizine
+ entities:
+ - uid: 6862
+ components:
+ - type: Transform
+ parent: 6846
+ - type: Physics
+ canCollide: False
+ - type: InsideEntityStorage
+ - uid: 6863
+ components:
+ - type: Transform
+ parent: 6846
+ - type: Physics
+ canCollide: False
+ - type: InsideEntityStorage
+ - uid: 6866
+ components:
+ - type: Transform
+ parent: 6865
+ - type: Physics
+ canCollide: False
+ - type: InsideEntityStorage
+ - uid: 6876
+ components:
+ - type: Transform
+ parent: 6865
+ - type: Physics
+ canCollide: False
+ - type: InsideEntityStorage
+- proto: ChemistryBottleUnstableMutagen
+ entities:
+ - uid: 1035
+ components:
+ - type: Transform
+ pos: 7.383148,-17.230762
+ parent: 1668
+ - uid: 1036
+ components:
+ - type: Transform
+ pos: 7.6053705,-17.223818
+ parent: 1668
+ - uid: 1037
+ components:
+ - type: Transform
+ pos: 7.5012035,-17.411318
+ parent: 1668
+ - uid: 1038
+ components:
+ - type: Transform
+ pos: 7.7303705,-17.411318
+ parent: 1668
- proto: ChemistryHotplate
entities:
- uid: 671
- type: Transform
pos: -12.5,5.5
parent: 1668
-- proto: DefaultStationBeacon
+- proto: DefaultStationBeaconCentComm
entities:
- uid: 4656
components:
- type: Transform
pos: -0.5,3.5
parent: 1668
- - type: NavMapBeacon
- text: CentComm
+- proto: DefaultStationBeaconCentCommAfterhours
+ entities:
- uid: 9452
components:
- type: Transform
pos: 22.5,-21.5
parent: 1668
- - type: NavMapBeacon
- text: Afterhours
- - uid: 9479
+- proto: DefaultStationBeaconCentCommERT
+ entities:
+ - uid: 9480
components:
- type: Transform
- pos: -0.5,-41.5
+ pos: -41.5,-7.5
parent: 1668
- - type: NavMapBeacon
- text: Thunderdome
- - uid: 9480
+- proto: DefaultStationBeaconCentCommThunderdome
+ entities:
+ - uid: 9479
components:
- type: Transform
- pos: -41.5,-7.5
+ pos: -0.5,-41.5
parent: 1668
- - type: NavMapBeacon
- text: ERT
- proto: DefibrillatorCabinetFilled
entities:
- uid: 511
- type: Transform
pos: 13.91264,32.80469
parent: 1668
-- proto: EpinephrineChemistryBottle
- entities:
- - uid: 6859
- components:
- - type: Transform
- parent: 6846
- - type: Physics
- canCollide: False
- - type: InsideEntityStorage
- - uid: 6860
- components:
- - type: Transform
- parent: 6846
- - type: Physics
- canCollide: False
- - type: InsideEntityStorage
- - uid: 6867
- components:
- - type: Transform
- parent: 6865
- - type: Physics
- canCollide: False
- - type: InsideEntityStorage
- - uid: 6871
- components:
- - type: Transform
- parent: 6865
- - type: Physics
- canCollide: False
- - type: InsideEntityStorage
- proto: ERTEngineerPDA
entities:
- uid: 6784
- type: Transform
pos: -1.4979519,1.1034296
parent: 1668
-- proto: OmnizineChemistryBottle
- entities:
- - uid: 6862
- components:
- - type: Transform
- parent: 6846
- - type: Physics
- canCollide: False
- - type: InsideEntityStorage
- - uid: 6863
- components:
- - type: Transform
- parent: 6846
- - type: Physics
- canCollide: False
- - type: InsideEntityStorage
- - uid: 6866
- components:
- - type: Transform
- parent: 6865
- - type: Physics
- canCollide: False
- - type: InsideEntityStorage
- - uid: 6876
- components:
- - type: Transform
- parent: 6865
- - type: Physics
- canCollide: False
- - type: InsideEntityStorage
- proto: OreProcessor
entities:
- uid: 4080
- Left: Reverse
- Right: Forward
- Middle: Off
-- proto: UnstableMutagenChemistryBottle
- entities:
- - uid: 1035
- components:
- - type: Transform
- pos: 7.383148,-17.230762
- parent: 1668
- - uid: 1036
- components:
- - type: Transform
- pos: 7.6053705,-17.223818
- parent: 1668
- - uid: 1037
- components:
- - type: Transform
- pos: 7.5012035,-17.411318
- parent: 1668
- - uid: 1038
- components:
- - type: Transform
- pos: 7.7303705,-17.411318
- parent: 1668
- proto: UraniumReinforcedWindowDirectional
entities:
- uid: 9601
- type: StorageFill
contents:
- id: OxygenTankFilled
- - id: ClothingOuterHardsuitWizard
- id: ClothingMaskBreath
- - id: JetpackVoidFilled
+ # TODO: Gone until reworked to have no space protection
+ #- id: ClothingOuterHardsuitWizard
+ #- id: JetpackVoidFilled
- 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
suffix: ninja bombing target
components:
- type: BombingTarget
+ - type: Tag
+ tags:
+ - GhostOnlyWarp
- type: WarpPoint
location: bombing target
+ blacklist:
+ tags:
+ - GhostOnlyWarp
- type: Sprite
layers:
- state: pink
- type: GravityWell
baseRadialAcceleration: 6
maxRange: 8
+ - type: Tag
+ tags:
+ - GhostOnlyWarp
- type: WarpPoint
follow: true
location: Nar'Sie
+ blacklist:
+ tags:
+ - GhostOnlyWarp
- type: GravityWell
baseRadialAcceleration: 6
maxRange: 8
+ - type: Tag
+ tags:
+ - GhostOnlyWarp
- type: WarpPoint
follow: true
location: Ratvar
+ blacklist:
+ tags:
+ - GhostOnlyWarp
description: Handles AI interactions across holocards + AI cores
components:
- type: ItemSlots
+ - type: Tag
+ tags:
+ - GhostOnlyWarp
- type: StationAiHolder
slot:
name: station-ai-mind-slot
suffix: Empty
components:
- type: WarpPoint
+ blacklist:
+ tags:
+ - GhostOnlyWarp
- type: ContainerComp
proto: AiHeld
container: station_ai_mind_slot
categories: [ HideSpawnMenu, DoNotMap ]
components:
- type: NoFTL
+ - type: Tag
+ tags:
+ - GhostOnlyWarp
- type: WarpPoint
follow: true
+ blacklist:
+ tags:
+ - GhostOnlyWarp
- type: Eye
pvsScale: 1.5
- type: Visibility
components:
- type: Transform
anchored: true
+ - type: Tag
+ tags:
+ - GhostOnlyWarp
- type: WarpPoint
follow: true
+ blacklist:
+ tags:
+ - GhostOnlyWarp
- type: Eye
- type: ContentEye
- type: Examiner
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
- type: WarpPoint
follow: true
location: immovable rod
+ blacklist:
+ tags:
+ - GhostOnlyWarp
- type: entity
id: ImmovableRodDespawn
- type: WarpPoint
follow: true
location: nuke disk
+ blacklist:
+ tags:
+ - GhostOnlyWarp
- type: Tag
tags:
- HighRiskItem
+ - GhostOnlyWarp
- type: StealTarget
stealGroup: NukeDisk
- type: Sprite
sprite: Objects/Power/powersink.rsi
state: powersink
+ - type: Tag
+ tags:
+ - GhostOnlyWarp
- type: WarpPoint
location: powersink
+ blacklist:
+ tags:
+ - GhostOnlyWarp
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
- 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
- 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
--- /dev/null
+- 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
id: WizardPDA
ears: ClothingHeadsetAltWizard
belt: ClothingBeltWand
- # pocket1: TODO: Include wizard teleport scroll
+ pocket1: WizardTeleportScroll
pocket2: WizardsGrimoire
- type: startingGear
jumpsuit: ClothingUniformJumpsuitColorPurple
head: ClothingHeadHatVioletwizard
outerClothing: ClothingOuterWizardViolet
-
-- type: startingGear
- id: WizardHardsuitGear
- parent: WizardVioletGear
- equipment:
- outerClothing: ClothingOuterHardsuitWizard
- type: Tag
id: GeigerCounter
+# Used for warps
+- type: Tag
+ id: GhostOnlyWarp
+
- type: Tag
id: GlassAirlock