diff --git a/Content.Client/Pinpointer/UI/NavMapBeaconBoundUserInterface.cs b/Content.Client/Pinpointer/UI/NavMapBeaconBoundUserInterface.cs
new file mode 100644
index 0000000000..0573d1a2db
--- /dev/null
+++ b/Content.Client/Pinpointer/UI/NavMapBeaconBoundUserInterface.cs
@@ -0,0 +1,35 @@
+using Content.Shared.Pinpointer;
+using JetBrains.Annotations;
+
+namespace Content.Client.Pinpointer.UI;
+
+[UsedImplicitly]
+public sealed class NavMapBeaconBoundUserInterface : BoundUserInterface
+{
+ [ViewVariables]
+ private NavMapBeaconWindow? _window;
+
+ public NavMapBeaconBoundUserInterface(EntityUid owner, Enum uiKey) : base(owner, uiKey)
+ {
+ }
+
+ protected override void Open()
+ {
+ base.Open();
+
+ _window = new NavMapBeaconWindow(Owner);
+ _window.OpenCentered();
+ _window.OnClose += Close;
+
+ _window.OnApplyButtonPressed += (label, enabled, color) =>
+ {
+ SendMessage(new NavMapBeaconConfigureBuiMessage(label, enabled, color));
+ };
+ }
+
+ protected override void Dispose(bool disposing)
+ {
+ base.Dispose(disposing);
+ _window?.Dispose();
+ }
+}
diff --git a/Content.Client/Pinpointer/UI/NavMapBeaconWindow.xaml b/Content.Client/Pinpointer/UI/NavMapBeaconWindow.xaml
new file mode 100644
index 0000000000..88c3506263
--- /dev/null
+++ b/Content.Client/Pinpointer/UI/NavMapBeaconWindow.xaml
@@ -0,0 +1,17 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Content.Client/Pinpointer/UI/NavMapBeaconWindow.xaml.cs b/Content.Client/Pinpointer/UI/NavMapBeaconWindow.xaml.cs
new file mode 100644
index 0000000000..968fe188f7
--- /dev/null
+++ b/Content.Client/Pinpointer/UI/NavMapBeaconWindow.xaml.cs
@@ -0,0 +1,78 @@
+using Content.Client.UserInterface.Controls;
+using Content.Shared.Pinpointer;
+using Content.Shared.Preferences;
+using Robust.Client.AutoGenerated;
+using Robust.Client.UserInterface.Controls;
+using Robust.Client.UserInterface.XAML;
+
+namespace Content.Client.Pinpointer.UI;
+
+[GenerateTypedNameReferences]
+public sealed partial class NavMapBeaconWindow : FancyWindow
+{
+ [Dependency] private readonly IEntityManager _entityManager = default!;
+
+ private string? _defaultLabel;
+ private bool _defaultEnabled;
+ private Color _defaultColor;
+
+ public event Action? OnApplyButtonPressed;
+
+ public NavMapBeaconWindow(EntityUid beaconEntity)
+ {
+ RobustXamlLoader.Load(this);
+ IoCManager.InjectDependencies(this);
+
+ if (!_entityManager.TryGetComponent(beaconEntity, out var navMap))
+ return;
+ _defaultLabel = navMap.Text;
+ _defaultEnabled = navMap.Enabled;
+ _defaultColor = navMap.Color;
+
+ UpdateVisibleButton(navMap.Enabled);
+ VisibleButton.OnPressed += args => UpdateVisibleButton(args.Button.Pressed);
+
+ LabelLineEdit.Text = navMap.Text ?? string.Empty;
+ LabelLineEdit.OnTextChanged += OnTextChanged;
+
+ ColorSelector.Color = navMap.Color;
+ ColorSelector.OnColorChanged += _ => TryEnableApplyButton();
+
+ TryEnableApplyButton();
+ ApplyButton.OnPressed += OnApplyPressed;
+ }
+
+ private void UpdateVisibleButton(bool value)
+ {
+ VisibleButton.Pressed = value;
+ VisibleButton.Text = Loc.GetString(value
+ ? "nav-beacon-toggle-visible"
+ : "nav-beacon-toggle-invisible");
+
+ TryEnableApplyButton();
+ }
+
+ private void OnTextChanged(LineEdit.LineEditEventArgs obj)
+ {
+ if (obj.Text.Length > HumanoidCharacterProfile.MaxNameLength)
+ obj.Control.Text = obj.Text.Substring(0, HumanoidCharacterProfile.MaxNameLength);
+
+ TryEnableApplyButton();
+ }
+
+ private void TryEnableApplyButton()
+ {
+ ApplyButton.Disabled = LabelLineEdit.Text == (_defaultLabel ?? string.Empty) &&
+ VisibleButton.Pressed == _defaultEnabled &&
+ ColorSelector.Color == _defaultColor;
+ }
+
+ private void OnApplyPressed(BaseButton.ButtonEventArgs obj)
+ {
+ _defaultLabel = LabelLineEdit.Text == string.Empty ? null : LabelLineEdit.Text;
+ _defaultEnabled = VisibleButton.Pressed;
+ _defaultColor = ColorSelector.Color;
+ OnApplyButtonPressed?.Invoke(_defaultLabel, _defaultEnabled, _defaultColor);
+ TryEnableApplyButton();
+ }
+}
diff --git a/Content.Server/Pinpointer/NavMapSystem.cs b/Content.Server/Pinpointer/NavMapSystem.cs
index a97e664d02..bdf2b6409a 100644
--- a/Content.Server/Pinpointer/NavMapSystem.cs
+++ b/Content.Server/Pinpointer/NavMapSystem.cs
@@ -1,5 +1,8 @@
+using Content.Server.Administration.Logs;
using Content.Server.Station.Systems;
using Content.Server.Warps;
+using Content.Shared.Database;
+using Content.Shared.Examine;
using Content.Shared.Pinpointer;
using Content.Shared.Tag;
using Robust.Shared.GameStates;
@@ -14,6 +17,8 @@ namespace Content.Server.Pinpointer;
///
public sealed class NavMapSystem : SharedNavMapSystem
{
+ [Dependency] private readonly IAdminLogManager _adminLog = default!;
+ [Dependency] private readonly SharedAppearanceSystem _appearance = default!;
[Dependency] private readonly TagSystem _tags = default!;
private EntityQuery _physicsQuery;
@@ -35,6 +40,10 @@ public sealed class NavMapSystem : SharedNavMapSystem
SubscribeLocalEvent(OnNavMapBeaconStartup);
SubscribeLocalEvent(OnNavMapBeaconAnchor);
+
+ SubscribeLocalEvent(OnConfigureMessage);
+ SubscribeLocalEvent(OnConfigurableMapInit);
+ SubscribeLocalEvent(OnConfigurableExamined);
}
private void OnStationInit(StationGridAddedEvent ev)
@@ -50,9 +59,69 @@ public sealed class NavMapSystem : SharedNavMapSystem
private void OnNavMapBeaconAnchor(EntityUid uid, NavMapBeaconComponent component, ref AnchorStateChangedEvent args)
{
+ UpdateBeaconEnabledVisuals((uid, component));
RefreshNavGrid(uid);
}
+ private void OnConfigureMessage(Entity ent, ref NavMapBeaconConfigureBuiMessage args)
+ {
+ if (args.Session.AttachedEntity is not { } user)
+ return;
+
+ if (!TryComp(ent, out var navMap))
+ return;
+
+ if (navMap.Text == args.Text &&
+ navMap.Color == args.Color &&
+ navMap.Enabled == args.Enabled)
+ return;
+
+ _adminLog.Add(LogType.Action, LogImpact.Medium,
+ $"{ToPrettyString(user):player} configured NavMapBeacon \'{ToPrettyString(ent):entity}\' with text \'{args.Text}\', color {args.Color.ToHexNoAlpha()}, and {(args.Enabled ? "enabled" : "disabled")} it.");
+
+ if (TryComp(ent, out var warpPoint))
+ {
+ warpPoint.Location = args.Text;
+ }
+
+ navMap.Text = args.Text;
+ navMap.Color = args.Color;
+ navMap.Enabled = args.Enabled;
+ UpdateBeaconEnabledVisuals((ent, navMap));
+ Dirty(ent, navMap);
+ RefreshNavGrid(ent);
+ }
+
+ private void OnConfigurableMapInit(Entity ent, ref MapInitEvent args)
+ {
+ if (!TryComp(ent, out var navMap))
+ return;
+
+ // We set this on mapinit just in case the text was edited via VV or something.
+ if (TryComp(ent, out var warpPoint))
+ {
+ warpPoint.Location = navMap.Text;
+ }
+
+ UpdateBeaconEnabledVisuals((ent, navMap));
+ }
+
+ private void OnConfigurableExamined(Entity ent, ref ExaminedEvent args)
+ {
+ if (!args.IsInDetailsRange || !TryComp(ent, out var navMap))
+ return;
+
+ args.PushMarkup(Loc.GetString("nav-beacon-examine-text",
+ ("enabled", navMap.Enabled),
+ ("color", navMap.Color.ToHexNoAlpha()),
+ ("label", navMap.Text ?? string.Empty)));
+ }
+
+ private void UpdateBeaconEnabledVisuals(Entity ent)
+ {
+ _appearance.SetData(ent, NavMapBeaconVisuals.Enabled, ent.Comp.Enabled && Transform(ent).Anchored);
+ }
+
///
/// Refreshes the grid for the corresponding beacon.
///
@@ -61,7 +130,7 @@ public sealed class NavMapSystem : SharedNavMapSystem
{
var xform = Transform(uid);
- if (!CanBeacon(uid, xform) || !TryComp(xform.GridUid, out var navMap))
+ if (!TryComp(xform.GridUid, out var navMap))
return;
Dirty(xform.GridUid.Value, navMap);
@@ -244,6 +313,8 @@ public sealed class NavMapSystem : SharedNavMapSystem
return;
comp.Enabled = enabled;
+ UpdateBeaconEnabledVisuals((uid, comp));
+ Dirty(uid, comp);
RefreshNavGrid(uid);
}
diff --git a/Content.Shared/Pinpointer/ConfigurableNavMapBeaconComponent.cs b/Content.Shared/Pinpointer/ConfigurableNavMapBeaconComponent.cs
new file mode 100644
index 0000000000..cd6744c87d
--- /dev/null
+++ b/Content.Shared/Pinpointer/ConfigurableNavMapBeaconComponent.cs
@@ -0,0 +1,41 @@
+using Robust.Shared.GameStates;
+using Robust.Shared.Serialization;
+
+namespace Content.Shared.Pinpointer;
+
+///
+/// This is used for a that can be configured with a UI.
+///
+[RegisterComponent, NetworkedComponent]
+[Access(typeof(SharedNavMapSystem))]
+public sealed partial class ConfigurableNavMapBeaconComponent : Component
+{
+
+}
+
+[Serializable, NetSerializable]
+public sealed class NavMapBeaconConfigureBuiMessage : BoundUserInterfaceMessage
+{
+ public string? Text;
+ public bool Enabled;
+ public Color Color;
+
+ public NavMapBeaconConfigureBuiMessage(string? text, bool enabled, Color color)
+ {
+ Text = text;
+ Enabled = enabled;
+ Color = color;
+ }
+}
+
+[Serializable, NetSerializable]
+public enum NavMapBeaconUiKey : byte
+{
+ Key
+}
+
+[Serializable, NetSerializable]
+public enum NavMapBeaconVisuals : byte
+{
+ Enabled
+}
diff --git a/Content.Shared/Pinpointer/NavMapBeaconComponent.cs b/Content.Shared/Pinpointer/NavMapBeaconComponent.cs
index 2415f92f58..c3132ee37f 100644
--- a/Content.Shared/Pinpointer/NavMapBeaconComponent.cs
+++ b/Content.Shared/Pinpointer/NavMapBeaconComponent.cs
@@ -1,23 +1,29 @@
+using Robust.Shared.GameStates;
+
namespace Content.Shared.Pinpointer;
///
/// Will show a marker on a NavMap.
///
-[RegisterComponent, Access(typeof(SharedNavMapSystem))]
+[RegisterComponent, NetworkedComponent, Access(typeof(SharedNavMapSystem))]
+[AutoGenerateComponentState]
public sealed partial class NavMapBeaconComponent : Component
{
///
/// Defaults to entity name if nothing found.
///
[ViewVariables(VVAccess.ReadWrite), DataField]
+ [AutoNetworkedField]
public string? Text;
[ViewVariables(VVAccess.ReadWrite), DataField]
+ [AutoNetworkedField]
public Color Color = Color.Orange;
///
/// Only enabled beacons can be seen on a station map.
///
[ViewVariables(VVAccess.ReadWrite), DataField]
+ [AutoNetworkedField]
public bool Enabled = true;
}
diff --git a/Resources/Locale/en-US/pinpointer/station_map.ftl b/Resources/Locale/en-US/pinpointer/station_map.ftl
index d8172eb729..bd20a65fac 100644
--- a/Resources/Locale/en-US/pinpointer/station_map.ftl
+++ b/Resources/Locale/en-US/pinpointer/station_map.ftl
@@ -1 +1,11 @@
-station-map-window-title = Station map
\ No newline at end of file
+station-map-window-title = Station map
+
+nav-beacon-window-title = Station Beacon
+nav-beacon-toggle-visible = Visible
+nav-beacon-toggle-invisible = Invisible
+nav-beacon-text-label = Label:
+nav-beacon-button-apply = Apply
+nav-beacon-examine-text = It is [color={$enabled ->
+ [true] forestgreen]on
+ *[false] crimson]off
+}[/color] and the display reads [color={$color}]"{$label}"[/color]
diff --git a/Resources/Locale/en-US/prototypes/catalog/fills/crates/engineering-crates.ftl b/Resources/Locale/en-US/prototypes/catalog/fills/crates/engineering-crates.ftl
index 61bcd424a2..49bb0ecab4 100644
--- a/Resources/Locale/en-US/prototypes/catalog/fills/crates/engineering-crates.ftl
+++ b/Resources/Locale/en-US/prototypes/catalog/fills/crates/engineering-crates.ftl
@@ -22,6 +22,9 @@ ent-CrateEngineeringCableBulk = Bulk cable crate
ent-CrateEngineeringElectricalSupplies = Electrical Supplies Crate
.desc = NT is not responsible for any workplace infighting relating to the insulated gloves included within these crates.
+ent-CrateEngineeringStationBeaconBundle = Station Beacon Bundle
+ .desc = A crate containing 5 station beacon assemblies for modifying the station map.
+
ent-CrateEngineeringJetpack = Jetpack crate
.desc = Two jetpacks for those who don't know how to use fire extinguishers.
diff --git a/Resources/Prototypes/Catalog/Cargo/cargo_engineering.yml b/Resources/Prototypes/Catalog/Cargo/cargo_engineering.yml
index 5a801e50ab..9644dc261c 100644
--- a/Resources/Prototypes/Catalog/Cargo/cargo_engineering.yml
+++ b/Resources/Prototypes/Catalog/Cargo/cargo_engineering.yml
@@ -48,6 +48,16 @@
category: Engineering
group: market
+- type: cargoProduct
+ id: StationBeaconBundle
+ icon:
+ sprite: Objects/Devices/station_beacon.rsi
+ state: icon
+ product: CrateEngineeringStationBeaconBundle
+ cost: 500
+ category: Engineering
+ group: market
+
- type: cargoProduct
id: EngineeringJetpack
icon:
diff --git a/Resources/Prototypes/Catalog/Fills/Crates/engineering.yml b/Resources/Prototypes/Catalog/Fills/Crates/engineering.yml
index c0982e035b..e33e191300 100644
--- a/Resources/Prototypes/Catalog/Fills/Crates/engineering.yml
+++ b/Resources/Prototypes/Catalog/Fills/Crates/engineering.yml
@@ -88,6 +88,15 @@
- id: ClothingHandsGlovesColorYellow
amount: 2
+- type: entity
+ id: CrateEngineeringStationBeaconBundle
+ parent: CratePlastic
+ components:
+ - type: StorageFill
+ contents:
+ - id: StationBeaconPart
+ amount: 5
+
- type: entity
id: CrateEngineeringJetpack
parent: CrateGenericSteel
diff --git a/Resources/Prototypes/Entities/Markers/warp_point.yml b/Resources/Prototypes/Entities/Markers/warp_point.yml
index da109f6212..2536fde474 100644
--- a/Resources/Prototypes/Entities/Markers/warp_point.yml
+++ b/Resources/Prototypes/Entities/Markers/warp_point.yml
@@ -30,103 +30,3 @@
- state: pink
- sprite: Objects/Weapons/Bombs/spidercharge.rsi
state: icon
-
-# Departments
-- type: entity
- id: WarpPointBeaconBar
- parent: WarpPointBeacon
- name: warp point (bar)
- components:
- - type: NavMapBeacon
- text: bar
- color: "#791500"
- - type: WarpPoint
- location: bar
-
-- type: entity
- id: WarpPointBeaconCargo
- parent: WarpPointBeacon
- name: warp point (cargo)
- components:
- - type: NavMapBeacon
- text: cargo
- color: "#A46106"
- - type: WarpPoint
- location: cargo
-
-- type: entity
- id: WarpPointBeaconCommand
- parent: WarpPointBeacon
- name: warp point (command)
- components:
- - type: NavMapBeacon
- text: command
- color: "#334E6D"
- - type: WarpPoint
- location: command
-
-- type: entity
- id: WarpPointBeaconEngineering
- parent: WarpPointBeacon
- name: warp point (engineering)
- components:
- - type: NavMapBeacon
- text: engineering
- color: "#EFB341"
- - type: WarpPoint
- location: engineering
-
-- type: entity
- id: WarpPointBeaconMedical
- parent: WarpPointBeacon
- name: warp point (medical)
- components:
- - type: NavMapBeacon
- text: medical
- color: "#52B4E9"
- - type: WarpPoint
- location: medical
-
-- type: entity
- id: WarpPointBeaconNeutral
- parent: WarpPointBeacon
- name: warp point (neutral)
- components:
- - type: NavMapBeacon
- text: neutral
- color: "#D4D4D4"
- - type: WarpPoint
- location: neutral
-
-- type: entity
- id: WarpPointBeaconScience
- parent: WarpPointBeacon
- name: warp point (science)
- components:
- - type: NavMapBeacon
- text: science
- color: "#D381C9"
- - type: WarpPoint
- location: science
-
-- type: entity
- id: WarpPointBeaconSecurity
- parent: WarpPointBeacon
- name: warp point (security)
- components:
- - type: NavMapBeacon
- text: security
- color: "#DE3A3A"
- - type: WarpPoint
- location: security
-
-- type: entity
- id: WarpPointBeaconService
- parent: WarpPointBeacon
- name: warp point (service)
- components:
- - type: NavMapBeacon
- text: service
- color: "#9FED58"
- - type: WarpPoint
- location: service
diff --git a/Resources/Prototypes/Entities/Objects/Devices/station_beacon.yml b/Resources/Prototypes/Entities/Objects/Devices/station_beacon.yml
new file mode 100644
index 0000000000..1c2517bb41
--- /dev/null
+++ b/Resources/Prototypes/Entities/Objects/Devices/station_beacon.yml
@@ -0,0 +1,553 @@
+- type: entity
+ parent: BaseItem
+ id: DefaultStationBeacon
+ name: station beacon
+ description: A small device that transmits information to station maps. Can be configured.
+ placement:
+ mode: SnapgridCenter
+ suffix: General
+ components:
+ - type: Sprite
+ sprite: Objects/Devices/station_beacon.rsi
+ drawdepth: BelowFloor
+ layers:
+ - state: blink
+ map: ["base"]
+ - type: Appearance
+ - type: GenericVisualizer
+ visuals:
+ enum.NavMapBeaconVisuals.Enabled:
+ base:
+ True: {state: blink}
+ False: {state: icon}
+ - type: ConfigurableNavMapBeacon
+ - type: NavMapBeacon
+ text: general
+ color: "#D4D4D496"
+ - type: WarpPoint
+ - type: ActivatableUI
+ key: enum.NavMapBeaconUiKey.Key
+ singleUser: true
+ - type: UserInterface
+ interfaces:
+ - key: enum.NavMapBeaconUiKey.Key
+ type: NavMapBeaconBoundUserInterface
+ - type: Item
+ size: Small
+ - type: SubFloorHide
+ - type: Anchorable
+ - type: Construction
+ graph: StationBeaconPart
+ node: complete
+ - type: CollideOnAnchor
+ - type: Physics
+ canCollide: false
+ bodyType: static
+ - type: Transform
+ anchored: true
+ - type: Damageable
+ damageContainer: Inorganic
+ damageModifierSet: Metallic
+ - type: Destructible
+ thresholds:
+ - trigger: # for nukes
+ !type:DamageTrigger
+ damage: 200
+ behaviors:
+ - !type:DoActsBehavior
+ acts: ["Destruction"]
+ - trigger:
+ !type:DamageTrigger
+ damage: 100
+ behaviors:
+ - !type:PlaySoundBehavior
+ sound:
+ path: /Audio/Effects/metalbreak.ogg
+ params:
+ volume: -8
+ - !type:SpawnEntitiesBehavior
+ spawn:
+ SheetSteel1:
+ min: 1
+ max: 1
+ offset: 0
+ - !type:DoActsBehavior
+ acts: ["Breakage"]
+ - type: StaticPrice
+ price: 25
+
+- type: entity
+ parent: DefaultStationBeacon
+ id: DefaultStationBeaconUnanchored
+ suffix: General, Unanchored
+ placement:
+ mode: PlaceFree
+ components:
+ - type: Sprite
+ sprite: Objects/Devices/station_beacon.rsi
+ layers:
+ - state: icon
+ map: ["base"]
+ - type: Physics
+ canCollide: true
+ bodyType: dynamic
+ - type: Transform
+ anchored: false
+
+- type: entity
+ parent: BaseItem
+ id: StationBeaconPart
+ name: station beacon assembly
+ description: A flatpack used for constructing a station beacon.
+ components:
+ - type: Item
+ size: Small
+ sprite: Objects/Devices/station_beacon.rsi
+ - type: Sprite
+ sprite: Objects/Devices/station_beacon.rsi
+ state: assembly
+ - type: Construction
+ graph: StationBeaconPart
+ node: start
+ defaultTarget: complete
+
+# Prototypes for various default beacon configurations.
+- type: entity
+ parent: DefaultStationBeacon
+ id: DefaultStationBeaconCommand
+ suffix: Command
+ components:
+ - type: NavMapBeacon
+ text: command
+ color: "#334E6D"
+
+- type: entity
+ parent: DefaultStationBeaconCommand
+ id: DefaultStationBeaconBridge
+ suffix: Bridge
+ components:
+ - type: NavMapBeacon
+ text: bridge
+
+- type: entity
+ parent: DefaultStationBeaconCommand
+ id: DefaultStationBeaconVault
+ suffix: Vault
+ components:
+ - type: NavMapBeacon
+ text: vault
+
+- type: entity
+ parent: DefaultStationBeaconCommand
+ id: DefaultStationBeaconCaptainsQuarters
+ suffix: Captain's Quarters
+ components:
+ - type: NavMapBeacon
+ text: captain's quarters
+
+- type: entity
+ parent: DefaultStationBeaconCommand
+ id: DefaultStationBeaconHOPOffice
+ suffix: HOP's Office
+ components:
+ - type: NavMapBeacon
+ text: head of personnel’s office
+
+- type: entity
+ parent: DefaultStationBeacon
+ id: DefaultStationBeaconSecurity
+ suffix: Security
+ components:
+ - type: NavMapBeacon
+ text: security
+ color: "#DE3A3A"
+
+- type: entity
+ parent: DefaultStationBeaconSecurity
+ id: DefaultStationBeaconBrig
+ suffix: Brig
+ components:
+ - type: NavMapBeacon
+ text: brig
+
+- type: entity
+ parent: DefaultStationBeaconSecurity
+ id: DefaultStationBeaconWardensOffice
+ suffix: Warden's Office
+ components:
+ - type: NavMapBeacon
+ text: warden's office
+
+- type: entity
+ parent: DefaultStationBeaconSecurity
+ id: DefaultStationBeaconHOSRoom
+ suffix: HOS’s Room
+ components:
+ - type: NavMapBeacon
+ text: head of security’s room
+
+- type: entity
+ parent: DefaultStationBeaconSecurity
+ id: DefaultStationBeaconArmory
+ suffix: Armory
+ components:
+ - type: NavMapBeacon
+ text: armory
+
+- type: entity
+ parent: DefaultStationBeaconSecurity
+ id: DefaultStationBeaconPermaBrig
+ suffix: Perma Brig
+ components:
+ - type: NavMapBeacon
+ text: perma brig
+
+- type: entity
+ parent: DefaultStationBeaconSecurity
+ id: DefaultStationBeaconDetectiveRoom
+ suffix: Detective's Room
+ components:
+ - type: NavMapBeacon
+ text: detective's room
+
+- type: entity
+ parent: DefaultStationBeaconSecurity
+ id: DefaultStationBeaconCourtroom
+ suffix: Courtroom
+ components:
+ - type: NavMapBeacon
+ text: courtroom
+
+- type: entity
+ parent: DefaultStationBeaconSecurity
+ id: DefaultStationBeaconLawOffice
+ suffix: Law Office
+ components:
+ - type: NavMapBeacon
+ text: law office
+
+- type: entity
+ parent: DefaultStationBeacon
+ id: DefaultStationBeaconMedical
+ suffix: Medical
+ components:
+ - type: NavMapBeacon
+ text: medical
+ color: "#52B4E9"
+
+- type: entity
+ parent: DefaultStationBeaconMedical
+ id: DefaultStationBeaconMedbay
+ suffix: Medbay
+ components:
+ - type: NavMapBeacon
+ text: medbay
+
+- type: entity
+ parent: DefaultStationBeaconMedical
+ id: DefaultStationBeaconChemistry
+ suffix: Chemistry
+ components:
+ - type: NavMapBeacon
+ text: chemistry
+
+- type: entity
+ parent: DefaultStationBeaconMedical
+ id: DefaultStationBeaconCryonics
+ suffix: Cryonics
+ components:
+ - type: NavMapBeacon
+ text: cryonics
+
+- type: entity
+ parent: DefaultStationBeaconMedical
+ id: DefaultStationBeaconCMORoom
+ suffix: CMO's room
+ components:
+ - type: NavMapBeacon
+ text: chief medical officer’s room
+
+- type: entity
+ parent: DefaultStationBeaconMedical
+ id: DefaultStationBeaconMorgue
+ suffix: Morgue
+ components:
+ - type: NavMapBeacon
+ text: morgue
+
+- type: entity
+ parent: DefaultStationBeacon
+ id: DefaultStationBeaconScience
+ suffix: Science
+ components:
+ - type: NavMapBeacon
+ text: science
+ color: "#D381C9"
+
+- type: entity
+ parent: DefaultStationBeaconScience
+ id: DefaultStationBeaconRND
+ suffix: RND
+ components:
+ - type: NavMapBeacon
+ text: research & development
+
+- type: entity
+ parent: DefaultStationBeaconScience
+ id: DefaultStationBeaconServerRoom
+ suffix: Server Room
+ components:
+ - type: NavMapBeacon
+ text: server room
+
+- type: entity
+ parent: DefaultStationBeaconScience
+ id: DefaultStationBeaconRDRoom
+ suffix: RD's Room
+ components:
+ - type: NavMapBeacon
+ text: research director's room
+
+- type: entity
+ parent: DefaultStationBeaconScience
+ id: DefaultStationBeaconRobotics
+ suffix: Robotics
+ components:
+ - type: NavMapBeacon
+ text: robotics
+
+- type: entity
+ parent: DefaultStationBeaconScience
+ id: DefaultStationBeaconArtifactLab
+ suffix: Artifact Lab
+ components:
+ - type: NavMapBeacon
+ text: artifact lab
+
+- type: entity
+ parent: DefaultStationBeaconScience
+ id: DefaultStationBeaconAnomalyGenerator
+ suffix: Anomaly Generator
+ components:
+ - type: NavMapBeacon
+ text: anomaly generator
+
+- type: entity
+ parent: DefaultStationBeacon
+ id: DefaultStationBeaconSupply
+ suffix: Supply
+ components:
+ - type: NavMapBeacon
+ text: supply
+ color: "#A46106"
+
+- type: entity
+ parent: DefaultStationBeaconSupply
+ id: DefaultStationBeaconCargoReception
+ suffix: Cargo Reception
+ components:
+ - type: NavMapBeacon
+ text: cargo reception
+
+- type: entity
+ parent: DefaultStationBeaconSupply
+ id: DefaultStationBeaconCargoBay
+ suffix: Cargo Bay
+ components:
+ - type: NavMapBeacon
+ text: cargo bay
+
+- type: entity
+ parent: DefaultStationBeaconSupply
+ id: DefaultStationBeaconQMRoom
+ suffix: QM's Room
+ components:
+ - type: NavMapBeacon
+ text: quartermaster's room
+
+- type: entity
+ parent: DefaultStationBeaconSupply
+ id: DefaultStationBeaconSalvage
+ suffix: Salvage
+ components:
+ - type: NavMapBeacon
+ text: salvage
+
+- type: entity
+ parent: DefaultStationBeacon
+ id: DefaultStationBeaconEngineering
+ suffix: Engineering
+ components:
+ - type: NavMapBeacon
+ text: engineering
+ color: "#EFB341"
+
+- type: entity
+ parent: DefaultStationBeaconEngineering
+ id: DefaultStationBeaconCERoom
+ suffix: CE's Room
+ components:
+ - type: NavMapBeacon
+ text: chief engineer's room
+
+- type: entity
+ parent: DefaultStationBeaconEngineering
+ id: DefaultStationBeaconAME
+ suffix: AME
+ components:
+ - type: NavMapBeacon
+ text: AME
+
+- type: entity
+ parent: DefaultStationBeaconEngineering
+ id: DefaultStationBeaconSolars
+ suffix: Solars
+ components:
+ - type: NavMapBeacon
+ text: solars
+
+- type: entity
+ parent: DefaultStationBeaconEngineering
+ id: DefaultStationBeaconSingularity
+ suffix: Singularity
+ components:
+ - type: NavMapBeacon
+ text: singularity engine
+
+- type: entity
+ parent: DefaultStationBeaconEngineering
+ id: DefaultStationBeaconPowerBank
+ suffix: Power Bank
+ components:
+ - type: NavMapBeacon
+ text: SMES power bank
+
+- type: entity
+ parent: DefaultStationBeaconEngineering
+ id: DefaultStationBeaconTelecoms
+ suffix: Telecoms
+ components:
+ - type: NavMapBeacon
+ text: telecoms
+
+- type: entity
+ parent: DefaultStationBeaconEngineering
+ id: DefaultStationBeaconAtmospherics
+ suffix: Atmospherics
+ components:
+ - type: NavMapBeacon
+ text: atmospherics
+
+- type: entity
+ parent: DefaultStationBeaconEngineering
+ id: DefaultStationBeaconTEG
+ suffix: TEG
+ components:
+ - type: NavMapBeacon
+ text: TEG
+
+- type: entity
+ parent: DefaultStationBeaconEngineering
+ id: DefaultStationBeaconTeslaEngine
+ suffix: Tesla Engine
+ components:
+ - type: NavMapBeacon
+ text: tesla engine
+
+- type: entity
+ parent: DefaultStationBeaconEngineering
+ id: DefaultStationBeaconTechVault
+ suffix: Tech Vault
+ components:
+ - type: NavMapBeacon
+ text: tech vault
+
+- type: entity
+ parent: DefaultStationBeacon
+ id: DefaultStationBeaconService
+ suffix: Service
+ components:
+ - type: NavMapBeacon
+ text: service
+ color: "#9FED58"
+
+- type: entity
+ parent: DefaultStationBeaconService
+ id: DefaultStationBeaconKitchen
+ suffix: Kitchen
+ components:
+ - type: NavMapBeacon
+ text: kitchen
+
+- type: entity
+ parent: DefaultStationBeaconService
+ id: DefaultStationBeaconBar
+ suffix: Bar
+ components:
+ - type: NavMapBeacon
+ text: bar
+
+- type: entity
+ parent: DefaultStationBeaconService
+ id: DefaultStationBeaconBotany
+ suffix: Botany
+ components:
+ - type: NavMapBeacon
+ text: botany
+
+- type: entity
+ parent: DefaultStationBeaconService
+ id: DefaultStationBeaconJanitorsCloset
+ suffix: Janitor's Closet
+ components:
+ - type: NavMapBeacon
+ text: janitor's closet
+
+- type: entity
+ parent: DefaultStationBeacon
+ id: DefaultStationBeaconArrivals
+ suffix: Arrivals
+ components:
+ - type: NavMapBeacon
+ text: arrivals
+
+- type: entity
+ parent: DefaultStationBeacon
+ id: DefaultStationBeaconEVAStorage
+ suffix: EVA Storage
+ components:
+ - type: NavMapBeacon
+ text: EVA storage
+
+- type: entity
+ parent: DefaultStationBeacon
+ id: DefaultStationBeaconChapel
+ suffix: Chapel
+ components:
+ - type: NavMapBeacon
+ text: chapel
+
+- type: entity
+ parent: DefaultStationBeacon
+ id: DefaultStationBeaconLibrary
+ suffix: Library
+ components:
+ - type: NavMapBeacon
+ text: library
+
+- type: entity
+ parent: DefaultStationBeacon
+ id: DefaultStationBeaconToolRoom
+ suffix: Tool Room
+ components:
+ - type: NavMapBeacon
+ text: tool room
+
+- type: entity
+ parent: DefaultStationBeacon
+ id: DefaultStationBeaconDisposals
+ suffix: Disposals
+ components:
+ - type: NavMapBeacon
+ text: disposals
+
diff --git a/Resources/Prototypes/Recipes/Construction/Graphs/structures/station_beacon.yml b/Resources/Prototypes/Recipes/Construction/Graphs/structures/station_beacon.yml
new file mode 100644
index 0000000000..d9c2c2c6aa
--- /dev/null
+++ b/Resources/Prototypes/Recipes/Construction/Graphs/structures/station_beacon.yml
@@ -0,0 +1,26 @@
+- type: constructionGraph
+ id: StationBeaconPart
+ start: start
+ graph:
+ - node: start
+ edges:
+ - to: complete
+ steps:
+ - tool: Pulsing
+ completed:
+ - !type:PlaySound
+ sound: /Audio/Effects/unwrap.ogg
+
+ - node: complete
+ entity: DefaultStationBeaconUnanchored
+ edges:
+ - to: start
+ steps:
+ - tool: Welding
+ doAfter: 1
+ completed:
+ - !type:SpawnPrototype
+ prototype: SheetSteel1
+ amount: 1
+ - !type:DeleteEntity
+
diff --git a/Resources/Textures/Objects/Devices/station_beacon.rsi/assembly.png b/Resources/Textures/Objects/Devices/station_beacon.rsi/assembly.png
new file mode 100644
index 0000000000..b355d055f6
Binary files /dev/null and b/Resources/Textures/Objects/Devices/station_beacon.rsi/assembly.png differ
diff --git a/Resources/Textures/Objects/Devices/station_beacon.rsi/blink.png b/Resources/Textures/Objects/Devices/station_beacon.rsi/blink.png
new file mode 100644
index 0000000000..53fabd1714
Binary files /dev/null and b/Resources/Textures/Objects/Devices/station_beacon.rsi/blink.png differ
diff --git a/Resources/Textures/Objects/Devices/station_beacon.rsi/icon.png b/Resources/Textures/Objects/Devices/station_beacon.rsi/icon.png
new file mode 100644
index 0000000000..67f3f53eb5
Binary files /dev/null and b/Resources/Textures/Objects/Devices/station_beacon.rsi/icon.png differ
diff --git a/Resources/Textures/Objects/Devices/station_beacon.rsi/meta.json b/Resources/Textures/Objects/Devices/station_beacon.rsi/meta.json
new file mode 100644
index 0000000000..771ce4c261
--- /dev/null
+++ b/Resources/Textures/Objects/Devices/station_beacon.rsi/meta.json
@@ -0,0 +1,26 @@
+{
+ "version": 1,
+ "license": "CC0-1.0",
+ "copyright": "Created by EmoGarbage404 (github) for SS14, based on beacon design from /tg/",
+ "size": {
+ "x": 32,
+ "y": 32
+ },
+ "states": [
+ {
+ "name": "icon"
+ },
+ {
+ "name": "blink",
+ "delays": [
+ [
+ 2.0,
+ 0.1
+ ]
+ ]
+ },
+ {
+ "name": "assembly"
+ }
+ ]
+}
diff --git a/Resources/migration.yml b/Resources/migration.yml
index a56d3719b2..e32905c6e1 100644
--- a/Resources/migration.yml
+++ b/Resources/migration.yml
@@ -108,3 +108,14 @@ ReagentContainerMilkOat: DrinkOatMilkCarton
# 2023-12-20
MiasmaCanister: AmmoniaCanister
+
+# 2023-12-28
+WarpPointBeaconBar: null
+WarpPointBeaconCargo: null
+WarpPointBeaconCommand: null
+WarpPointBeaconEngineering: null
+WarpPointBeaconMedical: null
+WarpPointBeaconNeutral: null
+WarpPointBeaconScience: null
+WarpPointBeaconSecurity: null
+WarpPointBeaconService: null