Add the ability for station maps to track grids they are not on (#41248)

* Initial commit

* Accidentally included the nukie map changes

* Fix the gridcheck

* Addressing review

* Review change

* Review comments
This commit is contained in:
SlamBamActionman
2026-01-12 03:47:47 +01:00
committed by GitHub
parent 4fafb55477
commit 435b7d5cf8
10 changed files with 158 additions and 7 deletions

View File

@@ -17,7 +17,11 @@ public sealed class StationMapBoundUserInterface : BoundUserInterface
base.Open();
EntityUid? gridUid = null;
if (EntMan.TryGetComponent<TransformComponent>(Owner, out var xform))
if (EntMan.TryGetComponent<StationMapComponent>(Owner, out var comp) && comp.TargetGrid != null)
{
gridUid = comp.TargetGrid;
}
else if (EntMan.TryGetComponent<TransformComponent>(Owner, out var xform))
{
gridUid = xform.GridUid;
}
@@ -30,8 +34,8 @@ public sealed class StationMapBoundUserInterface : BoundUserInterface
{
stationName = gridMetaData.EntityName;
}
if (EntMan.TryGetComponent<StationMapComponent>(Owner, out var comp) && comp.ShowLocation)
if (comp != null && comp.ShowLocation)
_window.Set(stationName, gridUid, Owner);
else
_window.Set(stationName, gridUid, null);

View File

@@ -86,6 +86,8 @@ public sealed class NukeopsRuleSystem : GameRuleSystem<NukeopsRuleComponent>
return;
component.TargetStation = RobustRandom.Pick(eligible);
var ev = new NukeopsTargetStationSelectedEvent(uid, component.TargetStation);
RaiseLocalEvent(ref ev);
}
#region Event Handlers
@@ -549,3 +551,20 @@ public sealed class NukeopsRuleSystem : GameRuleSystem<NukeopsRuleComponent>
return null;
}
}
/// <summary>
/// Raised when a station has been assigned as a target for the NukeOps rule.
/// </summary>
[ByRefEvent]
public readonly struct NukeopsTargetStationSelectedEvent(EntityUid ruleEntity, EntityUid? targetStation)
{
/// <summary>
/// The entity containing the NukeOps gamerule.
/// </summary>
public readonly EntityUid RuleEntity = ruleEntity;
/// <summary>
/// The target station, if it exists.
/// </summary>
public readonly EntityUid? TargetStation = targetStation;
}

View File

@@ -1,7 +1,10 @@
using Content.Server.GameTicking;
using Content.Server.GameTicking.Rules;
using Content.Server.GameTicking.Rules.Components;
using Content.Shared.PowerCell;
using Content.Shared.Pinpointer;
using Content.Shared.Station;
using Robust.Server.GameObjects;
using Robust.Shared.Player;
namespace Content.Server.Pinpointer;
@@ -9,12 +12,18 @@ public sealed class StationMapSystem : EntitySystem
{
[Dependency] private readonly UserInterfaceSystem _ui = default!;
[Dependency] private readonly PowerCellSystem _cell = default!;
[Dependency] private readonly SharedStationSystem _station = default!;
[Dependency] private readonly SharedTransformSystem _xform = default!;
[Dependency] private readonly GameTicker _gameTicker = default!;
public override void Initialize()
{
base.Initialize();
SubscribeLocalEvent<StationMapComponent, MapInitEvent>(OnMapInit);
SubscribeLocalEvent<StationMapUserComponent, EntParentChangedMessage>(OnUserParentChanged);
SubscribeLocalEvent<NukeopsStationMapComponent, NukeopsTargetStationSelectedEvent>(OnNukeopsStationSelected);
Subs.BuiEvents<StationMapComponent>(StationMapUiKey.Key, subs =>
{
subs.Event<BoundUIOpenedEvent>(OnStationMapOpened);
@@ -22,6 +31,33 @@ public sealed class StationMapSystem : EntitySystem
});
}
private void OnMapInit(Entity<StationMapComponent> ent, ref MapInitEvent args)
{
if (!ent.Comp.InitializeWithStation)
return;
// If we ever find a need to make more exceptions like this, just turn this into an event.
if (HasComp<NukeopsStationMapComponent>(ent))
{
foreach (var rule in _gameTicker.GetActiveGameRules())
{
if (TryComp<NukeopsRuleComponent>(rule, out var nukeopsRule) && nukeopsRule.TargetStation != null)
{
ent.Comp.TargetGrid = _station.GetLargestGrid((nukeopsRule.TargetStation.Value, null));
Dirty(ent);
return;
}
}
}
var station = _station.GetStationInMap(_xform.GetMapId(ent.Owner));
if (station != null)
{
ent.Comp.TargetGrid = _station.GetLargestGrid((station.Value, null));
Dirty(ent);
}
}
private void OnStationMapClosed(EntityUid uid, StationMapComponent component, BoundUIClosedEvent args)
{
if (!Equals(args.UiKey, StationMapUiKey.Key))
@@ -43,4 +79,19 @@ public sealed class StationMapSystem : EntitySystem
var comp = EnsureComp<StationMapUserComponent>(args.Actor);
comp.Map = uid;
}
private void OnNukeopsStationSelected(Entity<NukeopsStationMapComponent> ent, ref NukeopsTargetStationSelectedEvent args)
{
if (args.TargetStation == null)
return;
if (!TryComp<StationMapComponent>(ent, out var stationMap) || !TryComp<RuleGridsComponent>(args.RuleEntity, out var ruleGrids))
return;
if (Transform(ent).MapID != ruleGrids.Map)
return;
stationMap.TargetGrid = _station.GetLargestGrid((args.TargetStation.Value, null));
Dirty(ent);
}
}

View File

@@ -0,0 +1,10 @@
namespace Content.Shared.Pinpointer;
/// <summary>
/// Used to indicate that an entity with the StationMapComponent should be updated to target the TargetStation of NukeopsRuleComponent.
/// Uses the most recent active NukeopsRule when spawned, or the NukeopsRule which spawned the grid that the entity is on.
/// </summary>
[RegisterComponent]
public sealed partial class NukeopsStationMapComponent : Component
{
}

View File

@@ -1,11 +1,27 @@
using Robust.Shared.GameStates;
namespace Content.Shared.Pinpointer;
[RegisterComponent]
[RegisterComponent, NetworkedComponent, AutoGenerateComponentState]
public sealed partial class StationMapComponent : Component
{
/// <summary>
/// Whether or not to show the user's location on the map.
/// </summary>
[DataField]
[DataField, AutoNetworkedField]
public bool ShowLocation = true;
/// <summary>
/// If true, when this entity initializes it will target and remember the station grid of the map the entity is in.
/// If there is no station, the entity will target a random station in the current session.
/// </summary>
[DataField]
public bool InitializeWithStation = false;
/// <summary>
/// The target grid that the map will display.
/// If null, it will display the user's current grid.
/// </summary>
[DataField, AutoNetworkedField]
public EntityUid? TargetGrid;
}

View File

@@ -52,3 +52,37 @@
id: HandheldStationMapUnpowered
parent: BaseHandheldStationMap
suffix: Handheld, Always Powered
- type: entity
parent: HandheldStationMap
id: HandheldStationMapStatic
suffix: Handheld, Works Off-Station
components:
- type: StationMap
initializeWithStation: true
- type: entity
parent: HandheldStationMap
id: HandheldStationMapNukeops
name: target station map
suffix: Handheld, NukeOps
description: Displays a readout of the target station.
components:
- type: Sprite
sprite: Objects/Devices/tablets.rsi
layers:
- state: tablet
- state: syndie
shader: unshaded
- type: Item
sprite: Objects/Devices/tablets.rsi
inhandVisuals:
left:
- state: inhand-left-syndie
right:
- state: inhand-right-syndie
- type: StationMap
showLocation: false
initializeWithStation: true
- type: NukeopsStationMap

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

View File

@@ -1,7 +1,7 @@
{
"version": 1,
"license": "CC-BY-SA-3.0",
"copyright": "Taken from Baystation12 at https://github.com/Baystation12/Baystation12/tree/17e84546562b97d775cb26790a08e6d87e7f8077 and heavily modified by Flareguy for Space Station 14. Inhands by carousel",
"copyright": "Taken from Baystation12 at https://github.com/Baystation12/Baystation12/tree/17e84546562b97d775cb26790a08e6d87e7f8077 and heavily modified by Flareguy for Space Station 14. Inhands by carousel. Syndie versions modified from generic by SlamBamActionman",
"size": {
"x": 32,
"y": 32
@@ -29,6 +29,23 @@
{
"name": "inhand-right",
"directions": 4
},
{
"name": "syndie",
"delays": [
[
0.3,
0.3
]
]
},
{
"name": "inhand-left-syndie",
"directions": 4
},
{
"name": "inhand-right-syndie",
"directions": 4
}
]
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB