diff --git a/Content.Client/LateJoin/LateJoinGui.cs b/Content.Client/LateJoin/LateJoinGui.cs
index 72fc9b198f..c43acad0b6 100644
--- a/Content.Client/LateJoin/LateJoinGui.cs
+++ b/Content.Client/LateJoin/LateJoinGui.cs
@@ -105,7 +105,7 @@ namespace Content.Client.LateJoin
new Label()
{
StyleClasses = { "LabelBig" },
- Text = $"NTSS {name}",
+ Text = name,
Align = Label.AlignMode.Center,
},
collapseButton
diff --git a/Content.Server/Maps/GameMapManager.cs b/Content.Server/Maps/GameMapManager.cs
index 01a599d46d..efabeeae3e 100644
--- a/Content.Server/Maps/GameMapManager.cs
+++ b/Content.Server/Maps/GameMapManager.cs
@@ -4,6 +4,7 @@ using System.Diagnostics.CodeAnalysis;
using System.Linq;
using Content.Server.Chat.Managers;
using Content.Shared.CCVar;
+using Robust.Server.Maps;
using Robust.Server.Player;
using Robust.Shared.Configuration;
using Robust.Shared.IoC;
@@ -20,6 +21,7 @@ public class GameMapManager : IGameMapManager
[Dependency] private readonly IPlayerManager _playerManager = default!;
[Dependency] private readonly IRobustRandom _random = default!;
[Dependency] private readonly IChatManager _chatManager = default!;
+ [Dependency] private readonly IMapLoader _mapLoader = default!;
private GameMapPrototype _currentMap = default!;
private bool _currentMapForced;
@@ -116,4 +118,12 @@ public class GameMapManager : IGameMapManager
{
return _prototypeManager.TryIndex(gameMap, out map);
}
-}
\ No newline at end of file
+
+ public string GenerateMapName(GameMapPrototype gameMap)
+ {
+ if (gameMap.NameGenerator is not null && gameMap.MapNameTemplate is not null)
+ return gameMap.NameGenerator.FormatName(gameMap.MapNameTemplate);
+ else
+ return gameMap.MapName;
+ }
+}
diff --git a/Content.Server/Maps/GameMapPrototype.cs b/Content.Server/Maps/GameMapPrototype.cs
index 2305a69d8e..d64fe04192 100644
--- a/Content.Server/Maps/GameMapPrototype.cs
+++ b/Content.Server/Maps/GameMapPrototype.cs
@@ -1,10 +1,10 @@
using System.Collections.Generic;
+using Content.Server.Maps.NameGenerators;
using Content.Shared.Roles;
using Robust.Shared.Prototypes;
using Robust.Shared.Serialization.Manager.Attributes;
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype.Dictionary;
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype.List;
-using Robust.Shared.ViewVariables;
namespace Content.Server.Maps;
@@ -31,11 +31,23 @@ public class GameMapPrototype : IPrototype
public uint MaxPlayers { get; } = uint.MaxValue;
///
- /// Name of the given map.
+ /// Name of the map to use in generic messages, like the map vote.
///
[DataField("mapName", required: true)]
public string MapName { get; } = default!;
+ ///
+ /// Name of the given map.
+ ///
+ [DataField("mapNameTemplate")]
+ public string? MapNameTemplate { get; } = default!;
+
+ ///
+ /// Name generator to use for the map, if any.
+ ///
+ [DataField("nameGenerator")]
+ public GameMapNameGenerator? NameGenerator { get; } = default!;
+
///
/// Relative directory path to the given map, i.e. `Maps/saltern.yml`
///
diff --git a/Content.Server/Maps/IGameMapManager.cs b/Content.Server/Maps/IGameMapManager.cs
index 2fe6eefde0..5177220761 100644
--- a/Content.Server/Maps/IGameMapManager.cs
+++ b/Content.Server/Maps/IGameMapManager.cs
@@ -64,4 +64,6 @@ public interface IGameMapManager
/// name of the map
/// existence
bool CheckMapExists(string gameMap);
-}
\ No newline at end of file
+
+ public string GenerateMapName(GameMapPrototype gameMap);
+}
diff --git a/Content.Server/Maps/NameGenerators/GameMapNameGenerator.cs b/Content.Server/Maps/NameGenerators/GameMapNameGenerator.cs
new file mode 100644
index 0000000000..d69f643736
--- /dev/null
+++ b/Content.Server/Maps/NameGenerators/GameMapNameGenerator.cs
@@ -0,0 +1,9 @@
+using Robust.Shared.Serialization.Manager.Attributes;
+
+namespace Content.Server.Maps.NameGenerators;
+
+[ImplicitDataDefinitionForInheritors]
+public abstract class GameMapNameGenerator
+{
+ public abstract string FormatName(string input);
+}
diff --git a/Content.Server/Maps/NameGenerators/NanotrasenNameGenerator.cs b/Content.Server/Maps/NameGenerators/NanotrasenNameGenerator.cs
new file mode 100644
index 0000000000..4486315a84
--- /dev/null
+++ b/Content.Server/Maps/NameGenerators/NanotrasenNameGenerator.cs
@@ -0,0 +1,26 @@
+using JetBrains.Annotations;
+using Robust.Shared.IoC;
+using Robust.Shared.Random;
+using Robust.Shared.Serialization.Manager.Attributes;
+
+namespace Content.Server.Maps.NameGenerators;
+
+[UsedImplicitly]
+public class NanotrasenNameGenerator : GameMapNameGenerator
+{
+ ///
+ /// Where the map comes from. Should be a two or three letter code, for example "VG" for Packedstation.
+ ///
+ [DataField("prefixCreator")] public string PrefixCreator = default!;
+
+ private string Prefix => "NT";
+ private string[] SuffixCodes => new []{ "LV", "NX", "EV", "QT", "PR" };
+
+ public override string FormatName(string input)
+ {
+ var random = IoCManager.Resolve();
+
+ // No way in hell am I writing custom format code just to add nice names. You can live with {0}
+ return string.Format(input, $"{Prefix}{PrefixCreator}", $"{random.Pick(SuffixCodes)}-{random.Next(0, 999):D3}");
+ }
+}
diff --git a/Content.Server/Station/StationSystem.cs b/Content.Server/Station/StationSystem.cs
index d514ca36f7..b6411a507d 100644
--- a/Content.Server/Station/StationSystem.cs
+++ b/Content.Server/Station/StationSystem.cs
@@ -16,6 +16,7 @@ namespace Content.Server.Station;
public class StationSystem : EntitySystem
{
[Dependency] private GameTicker _gameTicker = default!;
+ [Dependency] private IGameMapManager _gameMapManager = default!;
private uint _idCounter = 1;
private Dictionary _stationInfo = new();
@@ -101,14 +102,14 @@ public class StationSystem : EntitySystem
var jobListDict = mapPrototype.AvailableJobs.ToDictionary(x => x.Key, x => x.Value[1]);
var id = AllocateStationInfo();
- _stationInfo[id] = new StationInfoData(stationName ?? mapPrototype.MapName, mapPrototype, jobListDict);
+ _stationInfo[id] = new StationInfoData(stationName ?? _gameMapManager.GenerateMapName(mapPrototype), mapPrototype, jobListDict);
var station = EntityManager.AddComponent(mapGrid);
station.Station = id;
_gameTicker.UpdateJobsAvailable(); // new station means new jobs, tell any lobby-goers.
Logger.InfoS("stations",
- $"Setting up new {mapPrototype.ID} called {mapPrototype.MapName} on grid {mapGrid}:{gridComponent.GridIndex}");
+ $"Setting up new {mapPrototype.ID} called {_stationInfo[id].Name} on grid {mapGrid}:{gridComponent.GridIndex}");
return id;
}
diff --git a/Resources/Prototypes/Maps/game.yml b/Resources/Prototypes/Maps/game.yml
index b45aeab570..ac8bcc66bc 100644
--- a/Resources/Prototypes/Maps/game.yml
+++ b/Resources/Prototypes/Maps/game.yml
@@ -1,6 +1,10 @@
- type: gameMap
id: saltern
- mapName: Saltern
+ mapName: 'Saltern'
+ mapNameTemplate: '{0} Saltern {1}'
+ nameGenerator:
+ !type:NanotrasenNameGenerator
+ prefixCreator: '14'
mapPath: Maps/saltern.yml
minPlayers: 0
maxPlayers: 20
@@ -30,7 +34,11 @@
- type: gameMap
id: packedstation
- mapName: Packedstation
+ mapName: 'Packedstation'
+ mapNameTemplate: '{0} Packedstation {1}'
+ nameGenerator:
+ !type:NanotrasenNameGenerator
+ prefixCreator: 'VG'
mapPath: Maps/packedstation.yml
minPlayers: 15
overflowJobs:
@@ -59,7 +67,11 @@
- type: gameMap
id: knightship
- mapName: Knight Ship
+ mapName: 'Knightship'
+ mapNameTemplate: '{0} Knightship {1}'
+ nameGenerator:
+ !type:NanotrasenNameGenerator
+ prefixCreator: '14'
mapPath: Maps/knightship.yml
minPlayers: 0
maxPlayers: 8
diff --git a/SpaceStation14.sln.DotSettings b/SpaceStation14.sln.DotSettings
index 9a0273ca86..3287ea383e 100644
--- a/SpaceStation14.sln.DotSettings
+++ b/SpaceStation14.sln.DotSettings
@@ -240,6 +240,7 @@
True
True
True
+ True
True
True
True