Refactor stations to properly use entity prototypes. (stationsv3) (#16570)
* Update StationSpawningSystem.cs Web-edit to allow feeding in an existing entity. * Update StationSpawningSystem.cs value type moment * Update StationSpawningSystem.cs * Oh goddamnit this is a refactor now. * awawawa * aaaaaaaaaaa * ee * forgot records. * no records? no records. * What's in a name? * Sloth forcing me to do the refactor properly smh. * e * optional evac in test. * tests pls work * awa --------- Co-authored-by: moonheart08 <moonheart08@users.noreply.github.com>
This commit is contained in:
@@ -227,14 +227,20 @@ namespace Content.IntegrationTests.Tests
|
|||||||
// Test shuttle can dock.
|
// Test shuttle can dock.
|
||||||
// This is done inside gamemap test because loading the map takes ages and we already have it.
|
// This is done inside gamemap test because loading the map takes ages and we already have it.
|
||||||
var station = entManager.GetComponent<StationMemberComponent>(targetGrid!.Value).Station;
|
var station = entManager.GetComponent<StationMemberComponent>(targetGrid!.Value).Station;
|
||||||
var stationConfig = entManager.GetComponent<StationDataComponent>(station).StationConfig;
|
if (entManager.TryGetComponent<StationEmergencyShuttleComponent>(station, out var stationEvac))
|
||||||
Assert.IsNotNull(stationConfig, $"{entManager.ToPrettyString(station)} had null StationConfig.");
|
{
|
||||||
var shuttlePath = stationConfig.EmergencyShuttlePath.ToString();
|
var shuttlePath = stationEvac.EmergencyShuttlePath;
|
||||||
var shuttle = mapLoader.LoadGrid(shuttleMap, shuttlePath);
|
var shuttle = mapLoader.LoadGrid(shuttleMap, shuttlePath.ToString());
|
||||||
Assert.That(shuttle != null && shuttleSystem.TryFTLDock(shuttle.Value, entManager.GetComponent<ShuttleComponent>(shuttle.Value), targetGrid.Value), $"Unable to dock {shuttlePath} to {mapProto}");
|
Assert.That(
|
||||||
|
shuttle != null && shuttleSystem.TryFTLDock(shuttle.Value,
|
||||||
|
entManager.GetComponent<ShuttleComponent>(shuttle.Value), targetGrid.Value),
|
||||||
|
$"Unable to dock {shuttlePath} to {mapProto}");
|
||||||
|
}
|
||||||
|
|
||||||
mapManager.DeleteMap(shuttleMap);
|
mapManager.DeleteMap(shuttleMap);
|
||||||
|
|
||||||
|
if (entManager.HasComponent<StationJobsComponent>(station))
|
||||||
|
{
|
||||||
// Test that the map has valid latejoin spawn points
|
// Test that the map has valid latejoin spawn points
|
||||||
if (!NoSpawnMaps.Contains(mapProto))
|
if (!NoSpawnMaps.Contains(mapProto))
|
||||||
{
|
{
|
||||||
@@ -256,6 +262,7 @@ namespace Content.IntegrationTests.Tests
|
|||||||
|
|
||||||
Assert.That(lateSpawns, Is.GreaterThan(0), $"Found no latejoin spawn points on {mapProto}");
|
Assert.That(lateSpawns, Is.GreaterThan(0), $"Found no latejoin spawn points on {mapProto}");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Test all availableJobs have spawnPoints
|
// Test all availableJobs have spawnPoints
|
||||||
// This is done inside gamemap test because loading the map takes ages and we already have it.
|
// This is done inside gamemap test because loading the map takes ages and we already have it.
|
||||||
var jobList = entManager.GetComponent<StationJobsComponent>(station).RoundStartJobList
|
var jobList = entManager.GetComponent<StationJobsComponent>(station).RoundStartJobList
|
||||||
@@ -271,7 +278,10 @@ namespace Content.IntegrationTests.Tests
|
|||||||
if (protoManager.Index<JobPrototype>(spawnpoint).SetPreference)
|
if (protoManager.Index<JobPrototype>(spawnpoint).SetPreference)
|
||||||
missingSpawnPoints.Add(spawnpoint);
|
missingSpawnPoints.Add(spawnpoint);
|
||||||
}
|
}
|
||||||
Assert.That(missingSpawnPoints.Count() == 0, $"There is no spawnpoint for {String.Join(", ", missingSpawnPoints)} on {mapProto}.");
|
|
||||||
|
Assert.That(missingSpawnPoints.Count() == 0,
|
||||||
|
$"There is no spawnpoint for {String.Join(", ", missingSpawnPoints)} on {mapProto}.");
|
||||||
|
}
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ using System.Collections.Generic;
|
|||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Content.Server.Maps;
|
using Content.Server.Maps;
|
||||||
|
using Content.Server.Station.Components;
|
||||||
using Content.Server.Station.Systems;
|
using Content.Server.Station.Systems;
|
||||||
using Content.Shared.Preferences;
|
using Content.Shared.Preferences;
|
||||||
using Content.Shared.Roles;
|
using Content.Shared.Roles;
|
||||||
@@ -32,6 +33,9 @@ public sealed class StationJobsTest
|
|||||||
stations:
|
stations:
|
||||||
Station:
|
Station:
|
||||||
mapNameTemplate: FooStation
|
mapNameTemplate: FooStation
|
||||||
|
stationProto: StandardNanotrasenStation
|
||||||
|
components:
|
||||||
|
- type: StationJobs
|
||||||
overflowJobs:
|
overflowJobs:
|
||||||
- Assistant
|
- Assistant
|
||||||
availableJobs:
|
availableJobs:
|
||||||
@@ -213,7 +217,10 @@ public sealed class StationJobsTest
|
|||||||
{
|
{
|
||||||
foreach (var (stationId, station) in gameMap.Stations)
|
foreach (var (stationId, station) in gameMap.Stations)
|
||||||
{
|
{
|
||||||
foreach (var job in station.AvailableJobs.Keys)
|
if (!station.StationComponentOverrides.TryGetComponent("StationJobs", out var comp))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
foreach (var (job, _) in ((StationJobsComponent)comp).SetupAvailableJobs)
|
||||||
{
|
{
|
||||||
Assert.That(invalidJobs.Contains(job), Is.False, $"Station {stationId} contains job prototype {job} which cannot be present roundstart.");
|
Assert.That(invalidJobs.Contains(job), Is.False, $"Station {stationId} contains job prototype {job} which cannot be present roundstart.");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
using Content.Server.Station.Components;
|
||||||
using Content.Server.Station.Systems;
|
using Content.Server.Station.Systems;
|
||||||
using Content.Shared.Administration;
|
using Content.Shared.Administration;
|
||||||
using Content.Shared.Roles;
|
using Content.Shared.Roles;
|
||||||
@@ -9,6 +10,10 @@ namespace Content.Server.Administration.Commands.Station;
|
|||||||
[AdminCommand(AdminFlags.Round)]
|
[AdminCommand(AdminFlags.Round)]
|
||||||
public sealed class AdjustStationJobCommand : IConsoleCommand
|
public sealed class AdjustStationJobCommand : IConsoleCommand
|
||||||
{
|
{
|
||||||
|
[Dependency] private readonly IEntityManager _entityManager = default!;
|
||||||
|
[Dependency] private readonly IEntitySystemManager _entSysManager = default!;
|
||||||
|
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
|
||||||
|
|
||||||
public string Command => "adjstationjob";
|
public string Command => "adjstationjob";
|
||||||
|
|
||||||
public string Description => "Adjust the job manifest on a station.";
|
public string Description => "Adjust the job manifest on a station.";
|
||||||
@@ -23,19 +28,15 @@ public sealed class AdjustStationJobCommand : IConsoleCommand
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var prototypeManager = IoCManager.Resolve<IPrototypeManager>();
|
var stationJobs = _entSysManager.GetEntitySystem<StationJobsSystem>();
|
||||||
var stationSystem = EntitySystem.Get<StationSystem>();
|
|
||||||
var stationJobs = EntitySystem.Get<StationJobsSystem>();
|
|
||||||
|
|
||||||
if (!int.TryParse(args[0], out var stationInt) || !stationSystem.Stations.Contains(new EntityUid(stationInt)))
|
if (!EntityUid.TryParse(args[0], out var station) || _entityManager.HasComponent<StationDataComponent>(station))
|
||||||
{
|
{
|
||||||
shell.WriteError(Loc.GetString("shell-argument-station-id-invalid", ("index", 1)));
|
shell.WriteError(Loc.GetString("shell-argument-station-id-invalid", ("index", 1)));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var station = new EntityUid(stationInt);
|
if (!_prototypeManager.TryIndex<JobPrototype>(args[1], out var job))
|
||||||
|
|
||||||
if (!prototypeManager.TryIndex<JobPrototype>(args[1], out var job))
|
|
||||||
{
|
{
|
||||||
shell.WriteError(Loc.GetString("shell-argument-must-be-prototype",
|
shell.WriteError(Loc.GetString("shell-argument-must-be-prototype",
|
||||||
("index", 2), ("prototypeName", nameof(JobPrototype))));
|
("index", 2), ("prototypeName", nameof(JobPrototype))));
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
using Content.Server.Station.Components;
|
||||||
using Content.Server.Station.Systems;
|
using Content.Server.Station.Systems;
|
||||||
using Content.Shared.Administration;
|
using Content.Shared.Administration;
|
||||||
using Robust.Shared.Console;
|
using Robust.Shared.Console;
|
||||||
@@ -7,6 +8,9 @@ namespace Content.Server.Administration.Commands.Station;
|
|||||||
[AdminCommand(AdminFlags.Admin)]
|
[AdminCommand(AdminFlags.Admin)]
|
||||||
public sealed class ListStationJobsCommand : IConsoleCommand
|
public sealed class ListStationJobsCommand : IConsoleCommand
|
||||||
{
|
{
|
||||||
|
[Dependency] private readonly IEntityManager _entityManager = default!;
|
||||||
|
[Dependency] private readonly IEntitySystemManager _entSysManager = default!;
|
||||||
|
|
||||||
public string Command => "lsstationjobs";
|
public string Command => "lsstationjobs";
|
||||||
|
|
||||||
public string Description => "Lists all jobs on the given station.";
|
public string Description => "Lists all jobs on the given station.";
|
||||||
@@ -21,16 +25,16 @@ public sealed class ListStationJobsCommand : IConsoleCommand
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var stationSystem = EntitySystem.Get<StationSystem>();
|
var stationSystem = _entSysManager.GetEntitySystem<StationSystem>();
|
||||||
var stationJobs = EntitySystem.Get<StationJobsSystem>();
|
var stationJobs = _entSysManager.GetEntitySystem<StationJobsSystem>();
|
||||||
|
|
||||||
if (!int.TryParse(args[0], out var station) || !stationSystem.Stations.Contains(new EntityUid(station)))
|
if (!EntityUid.TryParse(args[0], out var station) || !_entityManager.HasComponent<StationJobsComponent>(station))
|
||||||
{
|
{
|
||||||
shell.WriteError(Loc.GetString("shell-argument-station-id-invalid", ("index", 1)));
|
shell.WriteError(Loc.GetString("shell-argument-station-id-invalid", ("index", 1)));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (var (job, amount) in stationJobs.GetJobs(new EntityUid(station)))
|
foreach (var (job, amount) in stationJobs.GetJobs(station))
|
||||||
{
|
{
|
||||||
var amountText = amount is null ? "Infinite" : amount.ToString();
|
var amountText = amount is null ? "Infinite" : amount.ToString();
|
||||||
shell.WriteLine($"{job}: {amountText}");
|
shell.WriteLine($"{job}: {amountText}");
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
using Content.Server.Station.Components;
|
||||||
using Content.Server.Station.Systems;
|
using Content.Server.Station.Systems;
|
||||||
using Content.Shared.Administration;
|
using Content.Shared.Administration;
|
||||||
using Robust.Shared.Console;
|
using Robust.Shared.Console;
|
||||||
@@ -17,7 +18,9 @@ public sealed class ListStationsCommand : IConsoleCommand
|
|||||||
|
|
||||||
public void Execute(IConsoleShell shell, string argStr, string[] args)
|
public void Execute(IConsoleShell shell, string argStr, string[] args)
|
||||||
{
|
{
|
||||||
foreach (var station in EntitySystem.Get<StationSystem>().Stations)
|
var query = _entityManager.EntityQueryEnumerator<StationDataComponent>();
|
||||||
|
|
||||||
|
while (query.MoveNext(out var station, out _))
|
||||||
{
|
{
|
||||||
var name = _entityManager.GetComponent<MetaDataComponent>(station).EntityName;
|
var name = _entityManager.GetComponent<MetaDataComponent>(station).EntityName;
|
||||||
shell.WriteLine($"{station, -10} | {name}");
|
shell.WriteLine($"{station, -10} | {name}");
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
using Content.Server.Station.Components;
|
||||||
using Content.Server.Station.Systems;
|
using Content.Server.Station.Systems;
|
||||||
using Content.Shared.Administration;
|
using Content.Shared.Administration;
|
||||||
using Robust.Shared.Console;
|
using Robust.Shared.Console;
|
||||||
@@ -7,6 +8,9 @@ namespace Content.Server.Administration.Commands.Station;
|
|||||||
[AdminCommand(AdminFlags.Admin)]
|
[AdminCommand(AdminFlags.Admin)]
|
||||||
public sealed class RenameStationCommand : IConsoleCommand
|
public sealed class RenameStationCommand : IConsoleCommand
|
||||||
{
|
{
|
||||||
|
[Dependency] private readonly IEntityManager _entityManager = default!;
|
||||||
|
[Dependency] private readonly IEntitySystemManager _entSysManager = default!;
|
||||||
|
|
||||||
public string Command => "renamestation";
|
public string Command => "renamestation";
|
||||||
|
|
||||||
public string Description => "Renames the given station";
|
public string Description => "Renames the given station";
|
||||||
@@ -21,14 +25,14 @@ public sealed class RenameStationCommand : IConsoleCommand
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var stationSystem = EntitySystem.Get<StationSystem>();
|
var stationSystem = _entSysManager.GetEntitySystem<StationSystem>();
|
||||||
|
|
||||||
if (!int.TryParse(args[0], out var station) || !stationSystem.Stations.Contains(new EntityUid(station)))
|
if (!EntityUid.TryParse(args[0], out var station) || _entityManager.HasComponent<StationDataComponent>(station))
|
||||||
{
|
{
|
||||||
shell.WriteError(Loc.GetString("shell-argument-station-id-invalid", ("index", 1)));
|
shell.WriteError(Loc.GetString("shell-argument-station-id-invalid", ("index", 1)));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
stationSystem.RenameStation(new EntityUid(station), args[1]);
|
stationSystem.RenameStation(station, args[1]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype;
|
||||||
|
|
||||||
namespace Content.Server.AlertLevel;
|
namespace Content.Server.AlertLevel;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -14,7 +16,7 @@ public sealed class AlertLevelComponent : Component
|
|||||||
public AlertLevelPrototype? AlertLevels;
|
public AlertLevelPrototype? AlertLevels;
|
||||||
|
|
||||||
// Once stations are a prototype, this should be used.
|
// Once stations are a prototype, this should be used.
|
||||||
[DataField("alertLevelPrototype")]
|
[DataField("alertLevelPrototype", required: true, customTypeSerializer: typeof(PrototypeIdSerializer<AlertLevelPrototype>))]
|
||||||
public string AlertLevelPrototype = default!;
|
public string AlertLevelPrototype = default!;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
@@ -32,13 +32,10 @@ public sealed class AlertLevelSystem : EntitySystem
|
|||||||
|
|
||||||
public override void Update(float time)
|
public override void Update(float time)
|
||||||
{
|
{
|
||||||
foreach (var station in _stationSystem.Stations)
|
var query = EntityQueryEnumerator<AlertLevelComponent>();
|
||||||
{
|
|
||||||
if (!TryComp(station, out AlertLevelComponent? alert))
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
while (query.MoveNext(out var station, out var alert))
|
||||||
|
{
|
||||||
if (alert.CurrentDelay <= 0)
|
if (alert.CurrentDelay <= 0)
|
||||||
{
|
{
|
||||||
if (alert.ActiveDelay)
|
if (alert.ActiveDelay)
|
||||||
@@ -55,9 +52,10 @@ public sealed class AlertLevelSystem : EntitySystem
|
|||||||
|
|
||||||
private void OnStationInitialize(StationInitializedEvent args)
|
private void OnStationInitialize(StationInitializedEvent args)
|
||||||
{
|
{
|
||||||
var alertLevelComponent = AddComp<AlertLevelComponent>(args.Station);
|
if (!TryComp<AlertLevelComponent>(args.Station, out var alertLevelComponent))
|
||||||
|
return;
|
||||||
|
|
||||||
if (!_prototypeManager.TryIndex(DefaultAlertLevelSet, out AlertLevelPrototype? alerts))
|
if (!_prototypeManager.TryIndex(alertLevelComponent.AlertLevelPrototype, out AlertLevelPrototype? alerts))
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,7 +22,6 @@ public sealed partial class CargoSystem : SharedCargoSystem
|
|||||||
InitializeConsole();
|
InitializeConsole();
|
||||||
InitializeShuttle();
|
InitializeShuttle();
|
||||||
InitializeTelepad();
|
InitializeTelepad();
|
||||||
SubscribeLocalEvent<StationInitializedEvent>(OnStationInit);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void Shutdown()
|
public override void Shutdown()
|
||||||
@@ -32,12 +31,6 @@ public sealed partial class CargoSystem : SharedCargoSystem
|
|||||||
CleanupShuttle();
|
CleanupShuttle();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnStationInit(StationInitializedEvent ev)
|
|
||||||
{
|
|
||||||
EnsureComp<StationBankAccountComponent>(ev.Station);
|
|
||||||
EnsureComp<StationCargoOrderDatabaseComponent>(ev.Station);
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void Update(float frameTime)
|
public override void Update(float frameTime)
|
||||||
{
|
{
|
||||||
base.Update(frameTime);
|
base.Update(frameTime);
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
using System.Linq;
|
using System.Linq;
|
||||||
using Content.Server.Administration;
|
using Content.Server.Administration;
|
||||||
using Content.Server.EUI;
|
using Content.Server.EUI;
|
||||||
|
using Content.Server.Station.Components;
|
||||||
using Content.Server.Station.Systems;
|
using Content.Server.Station.Systems;
|
||||||
using Content.Server.StationRecords;
|
using Content.Server.StationRecords;
|
||||||
using Content.Server.StationRecords.Systems;
|
using Content.Server.StationRecords.Systems;
|
||||||
@@ -270,13 +271,12 @@ public sealed class CrewManifestCommand : IConsoleCommand
|
|||||||
}
|
}
|
||||||
|
|
||||||
var stations = _entityManager
|
var stations = _entityManager
|
||||||
.System<StationSystem>()
|
.EntityQuery<StationDataComponent>()
|
||||||
.Stations
|
.Select(stationData =>
|
||||||
.Select(station =>
|
|
||||||
{
|
{
|
||||||
var meta = _entityManager.GetComponent<MetaDataComponent>(station);
|
var meta = _entityManager.GetComponent<MetaDataComponent>(stationData.Owner);
|
||||||
|
|
||||||
return new CompletionOption(station.ToString(), meta.EntityName);
|
return new CompletionOption(stationData.Owner.ToString(), meta.EntityName);
|
||||||
});
|
});
|
||||||
|
|
||||||
return CompletionResult.FromHintOptions(stations, null);
|
return CompletionResult.FromHintOptions(stations, null);
|
||||||
|
|||||||
@@ -31,10 +31,13 @@ public sealed partial class DragonSystem
|
|||||||
{
|
{
|
||||||
base.Started(uid, component, gameRule, args);
|
base.Started(uid, component, gameRule, args);
|
||||||
|
|
||||||
if (!_station.Stations.Any())
|
var eligible = EntityQuery<StationEventEligibleComponent>().Select(x => x.Owner).ToList();
|
||||||
|
|
||||||
|
if (!eligible.Any())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var station = _random.Pick(_station.Stations);
|
var station = _random.Pick(eligible);
|
||||||
|
|
||||||
if (_station.GetLargestGrid(EntityManager.GetComponent<StationDataComponent>(station)) is not { } grid)
|
if (_station.GetLargestGrid(EntityManager.GetComponent<StationDataComponent>(station)) is not { } grid)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
|||||||
@@ -174,7 +174,6 @@ namespace Content.Server.Entry
|
|||||||
protected override void Dispose(bool disposing)
|
protected override void Dispose(bool disposing)
|
||||||
{
|
{
|
||||||
_playTimeTracking?.Shutdown();
|
_playTimeTracking?.Shutdown();
|
||||||
_sysMan?.GetEntitySystemOrNull<StationSystem>()?.OnServerDispose();
|
|
||||||
_dbManager?.Shutdown();
|
_dbManager?.Shutdown();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -52,23 +52,22 @@ namespace Content.Server.GameTicking
|
|||||||
var playerCount = $"{_playerManager.PlayerCount}";
|
var playerCount = $"{_playerManager.PlayerCount}";
|
||||||
var readyCount = _playerGameStatuses.Values.Count(x => x == PlayerGameStatus.ReadyToPlay);
|
var readyCount = _playerGameStatuses.Values.Count(x => x == PlayerGameStatus.ReadyToPlay);
|
||||||
|
|
||||||
StringBuilder stationNames = new StringBuilder();
|
var stationNames = new StringBuilder();
|
||||||
if (_stationSystem.Stations.Count != 0)
|
var query =
|
||||||
{
|
EntityQueryEnumerator<StationJobsComponent, StationSpawningComponent, MetaDataComponent>();
|
||||||
foreach (EntityUid entUID in _stationSystem.Stations)
|
|
||||||
{
|
var foundOne = false;
|
||||||
StationDataComponent? stationData = null;
|
|
||||||
MetaDataComponent? metaData = null;
|
while (query.MoveNext(out _, out _, out var meta))
|
||||||
if (Resolve(entUID, ref stationData, ref metaData, logMissing: true))
|
|
||||||
{
|
{
|
||||||
|
foundOne = true;
|
||||||
if (stationNames.Length > 0)
|
if (stationNames.Length > 0)
|
||||||
stationNames.Append('\n');
|
stationNames.Append('\n');
|
||||||
|
|
||||||
stationNames.Append(metaData.EntityName);
|
stationNames.Append(meta.EntityName);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
if (!foundOne)
|
||||||
else
|
|
||||||
{
|
{
|
||||||
stationNames.Append(Loc.GetString("game-ticker-no-map-selected"));
|
stationNames.Append(Loc.GetString("game-ticker-no-map-selected"));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -50,7 +50,9 @@ namespace Content.Server.GameTicking
|
|||||||
|
|
||||||
foreach (var (player, _) in profiles)
|
foreach (var (player, _) in profiles)
|
||||||
{
|
{
|
||||||
if (playerNetIds.Contains(player)) continue;
|
if (playerNetIds.Contains(player))
|
||||||
|
continue;
|
||||||
|
|
||||||
toRemove.Add(player);
|
toRemove.Add(player);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -60,12 +62,14 @@ namespace Content.Server.GameTicking
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var assignedJobs = _stationJobs.AssignJobs(profiles, _stationSystem.Stations.ToList());
|
var spawnableStations = EntityQuery<StationJobsComponent, StationSpawningComponent>().Select(x => x.Item1.Owner).ToList();
|
||||||
|
|
||||||
_stationJobs.AssignOverflowJobs(ref assignedJobs, playerNetIds, profiles, _stationSystem.Stations.ToList());
|
var assignedJobs = _stationJobs.AssignJobs(profiles, spawnableStations);
|
||||||
|
|
||||||
|
_stationJobs.AssignOverflowJobs(ref assignedJobs, playerNetIds, profiles, spawnableStations);
|
||||||
|
|
||||||
// Calculate extended access for stations.
|
// Calculate extended access for stations.
|
||||||
var stationJobCounts = _stationSystem.Stations.ToDictionary(e => e, _ => 0);
|
var stationJobCounts = spawnableStations.ToDictionary(e => e, _ => 0);
|
||||||
foreach (var (netUser, (job, station)) in assignedJobs)
|
foreach (var (netUser, (job, station)) in assignedJobs)
|
||||||
{
|
{
|
||||||
if (job == null)
|
if (job == null)
|
||||||
@@ -117,7 +121,7 @@ namespace Content.Server.GameTicking
|
|||||||
|
|
||||||
if (station == EntityUid.Invalid)
|
if (station == EntityUid.Invalid)
|
||||||
{
|
{
|
||||||
var stations = _stationSystem.Stations.ToList();
|
var stations = EntityQuery<StationJobsComponent, StationSpawningComponent>().Select(x => x.Item1.Owner).ToList();
|
||||||
_robustRandom.Shuffle(stations);
|
_robustRandom.Shuffle(stations);
|
||||||
if (stations.Count == 0)
|
if (stations.Count == 0)
|
||||||
station = EntityUid.Invalid;
|
station = EntityUid.Invalid;
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
using Content.Server.NPC.Components;
|
||||||
using Content.Server.StationEvents.Events;
|
using Content.Server.StationEvents.Events;
|
||||||
using Content.Shared.Dataset;
|
using Content.Shared.Dataset;
|
||||||
using Content.Shared.Humanoid.Prototypes;
|
using Content.Shared.Humanoid.Prototypes;
|
||||||
@@ -7,6 +8,7 @@ using Robust.Shared.Audio;
|
|||||||
using Robust.Shared.Map;
|
using Robust.Shared.Map;
|
||||||
using Robust.Shared.Serialization.TypeSerializers.Implementations;
|
using Robust.Shared.Serialization.TypeSerializers.Implementations;
|
||||||
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype;
|
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype;
|
||||||
|
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype.Set;
|
||||||
using Robust.Shared.Utility;
|
using Robust.Shared.Utility;
|
||||||
|
|
||||||
namespace Content.Server.GameTicking.Rules.Components;
|
namespace Content.Server.GameTicking.Rules.Components;
|
||||||
@@ -119,6 +121,9 @@ public sealed class NukeopsRuleComponent : Component
|
|||||||
/// todo: don't store sessions, dingus
|
/// todo: don't store sessions, dingus
|
||||||
[DataField("operativePlayers")]
|
[DataField("operativePlayers")]
|
||||||
public readonly Dictionary<string, IPlayerSession> OperativePlayers = new();
|
public readonly Dictionary<string, IPlayerSession> OperativePlayers = new();
|
||||||
|
|
||||||
|
[DataField("faction", customTypeSerializer: typeof(PrototypeIdSerializer<FactionPrototype>), required: true)]
|
||||||
|
public string Faction = default!;
|
||||||
}
|
}
|
||||||
|
|
||||||
public enum WinType : byte
|
public enum WinType : byte
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ using Content.Server.Ghost.Roles.Components;
|
|||||||
using Content.Server.Ghost.Roles.Events;
|
using Content.Server.Ghost.Roles.Events;
|
||||||
using Content.Server.Humanoid;
|
using Content.Server.Humanoid;
|
||||||
using Content.Server.Mind.Components;
|
using Content.Server.Mind.Components;
|
||||||
|
using Content.Server.NPC.Components;
|
||||||
using Content.Server.NPC.Systems;
|
using Content.Server.NPC.Systems;
|
||||||
using Content.Server.Nuke;
|
using Content.Server.Nuke;
|
||||||
using Content.Server.Preferences.Managers;
|
using Content.Server.Preferences.Managers;
|
||||||
@@ -175,12 +176,16 @@ public sealed class NukeopsRuleSystem : GameRuleSystem<NukeopsRuleComponent>
|
|||||||
// we can only currently guarantee that NT stations are the only station to
|
// we can only currently guarantee that NT stations are the only station to
|
||||||
// exist in the base game.
|
// exist in the base game.
|
||||||
|
|
||||||
component.TargetStation = _stationSystem.Stations.FirstOrNull();
|
var eligible = EntityQuery<StationEventEligibleComponent, FactionComponent>()
|
||||||
|
.Where(x =>
|
||||||
|
_faction.IsFactionHostile(component.Faction, x.Item2.Owner, x.Item2))
|
||||||
|
.Select(x => x.Item1.Owner)
|
||||||
|
.ToList();
|
||||||
|
|
||||||
if (component.TargetStation == null)
|
if (!eligible.Any())
|
||||||
{
|
|
||||||
return;
|
return;
|
||||||
}
|
|
||||||
|
component.TargetStation = _random.Pick(eligible);
|
||||||
|
|
||||||
var filter = Filter.Empty();
|
var filter = Filter.Empty();
|
||||||
var query = EntityQueryEnumerator<NukeOperativeComponent, ActorComponent>();
|
var query = EntityQueryEnumerator<NukeOperativeComponent, ActorComponent>();
|
||||||
|
|||||||
@@ -144,8 +144,8 @@ public sealed class PiratesRuleSystem : GameRuleSystem<PiratesRuleComponent>
|
|||||||
var map = "/Maps/Shuttles/pirate.yml";
|
var map = "/Maps/Shuttles/pirate.yml";
|
||||||
var xformQuery = GetEntityQuery<TransformComponent>();
|
var xformQuery = GetEntityQuery<TransformComponent>();
|
||||||
|
|
||||||
var aabbs = _stationSystem.Stations.SelectMany(x =>
|
var aabbs = EntityQuery<StationDataComponent>().SelectMany(x =>
|
||||||
Comp<StationDataComponent>(x).Grids.Select(x =>
|
x.Grids.Select(x =>
|
||||||
xformQuery.GetComponent(x).WorldMatrix.TransformBox(_mapManager.GetGridComp(x).LocalAABB)))
|
xformQuery.GetComponent(x).WorldMatrix.TransformBox(_mapManager.GetGridComp(x).LocalAABB)))
|
||||||
.ToArray();
|
.ToArray();
|
||||||
|
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ namespace Content.Server.Jobs
|
|||||||
|
|
||||||
[DataField("components")]
|
[DataField("components")]
|
||||||
[AlwaysPushInheritance]
|
[AlwaysPushInheritance]
|
||||||
public EntityPrototype.ComponentRegistry Components { get; } = new();
|
public ComponentRegistry Components { get; } = new();
|
||||||
|
|
||||||
public override void AfterEquip(EntityUid mob)
|
public override void AfterEquip(EntityUid mob)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ public sealed class ChangeComponentsSpellEvent : EntityTargetActionEvent, ISpeak
|
|||||||
|
|
||||||
[DataField("toAdd")]
|
[DataField("toAdd")]
|
||||||
[AlwaysPushInheritance]
|
[AlwaysPushInheritance]
|
||||||
public EntityPrototype.ComponentRegistry ToAdd = new();
|
public ComponentRegistry ToAdd = new();
|
||||||
|
|
||||||
[DataField("toRemove")]
|
[DataField("toRemove")]
|
||||||
[AlwaysPushInheritance]
|
[AlwaysPushInheritance]
|
||||||
|
|||||||
@@ -8,5 +8,5 @@ namespace Content.Server.NPC.Queries.Queries;
|
|||||||
public sealed class ComponentQuery : UtilityQuery
|
public sealed class ComponentQuery : UtilityQuery
|
||||||
{
|
{
|
||||||
[DataField("components", required: true)]
|
[DataField("components", required: true)]
|
||||||
public EntityPrototype.ComponentRegistry Components = default!;
|
public ComponentRegistry Components = default!;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,5 +5,5 @@ namespace Content.Server.NPC.Queries.Queries;
|
|||||||
public sealed class NearbyComponentsQuery : UtilityQuery
|
public sealed class NearbyComponentsQuery : UtilityQuery
|
||||||
{
|
{
|
||||||
[DataField("components")]
|
[DataField("components")]
|
||||||
public EntityPrototype.ComponentRegistry Component = default!;
|
public ComponentRegistry Component = default!;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -153,7 +153,7 @@ public sealed class FactionSystem : EntitySystem
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool IsFriendly(EntityUid uidA, EntityUid uidB, FactionComponent? factionA = null, FactionComponent? factionB = null)
|
public bool IsEntityFriendly(EntityUid uidA, EntityUid uidB, FactionComponent? factionA = null, FactionComponent? factionB = null)
|
||||||
{
|
{
|
||||||
if (!Resolve(uidA, ref factionA, false) || !Resolve(uidB, ref factionB, false))
|
if (!Resolve(uidA, ref factionA, false) || !Resolve(uidB, ref factionB, false))
|
||||||
return false;
|
return false;
|
||||||
@@ -161,6 +161,39 @@ public sealed class FactionSystem : EntitySystem
|
|||||||
return factionA.Factions.Overlaps(factionB.Factions) || factionA.FriendlyFactions.Overlaps(factionB.Factions);
|
return factionA.Factions.Overlaps(factionB.Factions) || factionA.FriendlyFactions.Overlaps(factionB.Factions);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public bool IsFactionFriendly(string target, string with)
|
||||||
|
{
|
||||||
|
return _factions[target].Friendly.Contains(with) && _factions[with].Friendly.Contains(target);
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool IsFactionFriendly(string target, EntityUid with, FactionComponent? factionWith = null)
|
||||||
|
{
|
||||||
|
if (!Resolve(with, ref factionWith, false))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return factionWith.Factions.All(x => IsFactionFriendly(target, x)) ||
|
||||||
|
factionWith.FriendlyFactions.Contains(target);
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool IsFactionHostile(string target, string with)
|
||||||
|
{
|
||||||
|
return _factions[target].Hostile.Contains(with) && _factions[with].Hostile.Contains(target);
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool IsFactionHostile(string target, EntityUid with, FactionComponent? factionWith = null)
|
||||||
|
{
|
||||||
|
if (!Resolve(with, ref factionWith, false))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return factionWith.Factions.All(x => IsFactionHostile(target, x)) ||
|
||||||
|
factionWith.HostileFactions.Contains(target);
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool IsFactionNeutral(string target, string with)
|
||||||
|
{
|
||||||
|
return !IsFactionFriendly(target, with) && !IsFactionHostile(target, with);
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Makes the source faction friendly to the target faction, 1-way.
|
/// Makes the source faction friendly to the target faction, 1-way.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@@ -470,7 +470,7 @@ public sealed partial class NPCSteeringSystem
|
|||||||
(mask & otherBody.CollisionLayer) == 0x0 &&
|
(mask & otherBody.CollisionLayer) == 0x0 &&
|
||||||
(layer & otherBody.CollisionMask) == 0x0 ||
|
(layer & otherBody.CollisionMask) == 0x0 ||
|
||||||
!factionQuery.TryGetComponent(ent, out var otherFaction) ||
|
!factionQuery.TryGetComponent(ent, out var otherFaction) ||
|
||||||
!_faction.IsFriendly(uid, ent, ourFaction, otherFaction) ||
|
!_faction.IsEntityFriendly(uid, ent, ourFaction, otherFaction) ||
|
||||||
// Use <= 0 so we ignore stationary friends in case.
|
// Use <= 0 so we ignore stationary friends in case.
|
||||||
Vector2.Dot(otherBody.LinearVelocity, ourVelocity) <= 0f)
|
Vector2.Dot(otherBody.LinearVelocity, ourVelocity) <= 0f)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
using System.Linq;
|
using System.Linq;
|
||||||
using Content.Server.Administration;
|
using Content.Server.Administration;
|
||||||
|
using Content.Server.Station.Components;
|
||||||
using Content.Server.Station.Systems;
|
using Content.Server.Station.Systems;
|
||||||
using Content.Shared.Administration;
|
using Content.Shared.Administration;
|
||||||
using JetBrains.Annotations;
|
using JetBrains.Annotations;
|
||||||
@@ -47,13 +48,12 @@ namespace Content.Server.Nuke.Commands
|
|||||||
}
|
}
|
||||||
|
|
||||||
var stations = _entityManager
|
var stations = _entityManager
|
||||||
.System<StationSystem>()
|
.EntityQuery<StationDataComponent>()
|
||||||
.Stations
|
.Select(stationData =>
|
||||||
.Select(station =>
|
|
||||||
{
|
{
|
||||||
var meta = _entityManager.GetComponent<MetaDataComponent>(station);
|
var meta = _entityManager.GetComponent<MetaDataComponent>(stationData.Owner);
|
||||||
|
|
||||||
return new CompletionOption(station.ToString(), meta.EntityName);
|
return new CompletionOption(stationData.Owner.ToString(), meta.EntityName);
|
||||||
});
|
});
|
||||||
|
|
||||||
return CompletionResult.FromHintOptions(stations, null);
|
return CompletionResult.FromHintOptions(stations, null);
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
using Content.Server.Objectives.Interfaces;
|
using Content.Server.Objectives.Interfaces;
|
||||||
|
using Content.Server.Shuttles.Components;
|
||||||
using Content.Server.Station.Components;
|
using Content.Server.Station.Components;
|
||||||
using Content.Shared.Cuffs.Components;
|
using Content.Shared.Cuffs.Components;
|
||||||
using JetBrains.Annotations;
|
using JetBrains.Annotations;
|
||||||
@@ -61,7 +62,7 @@ namespace Content.Server.Objectives.Conditions
|
|||||||
agentIsEscaping = false;
|
agentIsEscaping = false;
|
||||||
|
|
||||||
// Any emergency shuttle counts for this objective.
|
// Any emergency shuttle counts for this objective.
|
||||||
foreach (var stationData in entMan.EntityQuery<StationDataComponent>())
|
foreach (var stationData in entMan.EntityQuery<StationEmergencyShuttleComponent>())
|
||||||
{
|
{
|
||||||
if (IsAgentOnShuttle(xform, stationData.EmergencyShuttle)) {
|
if (IsAgentOnShuttle(xform, stationData.EmergencyShuttle)) {
|
||||||
shuttleContainsAgent = true;
|
shuttleContainsAgent = true;
|
||||||
|
|||||||
@@ -28,8 +28,6 @@ public sealed partial class SalvageSystem
|
|||||||
|
|
||||||
private void InitializeExpeditions()
|
private void InitializeExpeditions()
|
||||||
{
|
{
|
||||||
SubscribeLocalEvent<StationInitializedEvent>(OnSalvageExpStationInit);
|
|
||||||
|
|
||||||
SubscribeLocalEvent<SalvageExpeditionConsoleComponent, ComponentInit>(OnSalvageConsoleInit);
|
SubscribeLocalEvent<SalvageExpeditionConsoleComponent, ComponentInit>(OnSalvageConsoleInit);
|
||||||
SubscribeLocalEvent<SalvageExpeditionConsoleComponent, EntParentChangedMessage>(OnSalvageConsoleParent);
|
SubscribeLocalEvent<SalvageExpeditionConsoleComponent, EntParentChangedMessage>(OnSalvageConsoleParent);
|
||||||
SubscribeLocalEvent<SalvageExpeditionConsoleComponent, ClaimSalvageMessage>(OnSalvageClaimMessage);
|
SubscribeLocalEvent<SalvageExpeditionConsoleComponent, ClaimSalvageMessage>(OnSalvageClaimMessage);
|
||||||
@@ -115,11 +113,6 @@ public sealed partial class SalvageSystem
|
|||||||
component.EndTime += args.PausedTime;
|
component.EndTime += args.PausedTime;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnSalvageExpStationInit(StationInitializedEvent ev)
|
|
||||||
{
|
|
||||||
EnsureComp<SalvageExpeditionDataComponent>(ev.Station);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void UpdateExpeditions()
|
private void UpdateExpeditions()
|
||||||
{
|
{
|
||||||
var currentTime = _timing.CurTime;
|
var currentTime = _timing.CurTime;
|
||||||
|
|||||||
@@ -0,0 +1,24 @@
|
|||||||
|
using Content.Server.Shuttles.Systems;
|
||||||
|
using Robust.Shared.Serialization.TypeSerializers.Implementations;
|
||||||
|
using Robust.Shared.Utility;
|
||||||
|
|
||||||
|
namespace Content.Server.Shuttles.Components;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// This is used for controlling evacuation for a station.
|
||||||
|
/// </summary>
|
||||||
|
[RegisterComponent]
|
||||||
|
public sealed class StationEmergencyShuttleComponent : Component
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The emergency shuttle assigned to this station.
|
||||||
|
/// </summary>
|
||||||
|
[ViewVariables, Access(typeof(ShuttleSystem), typeof(EmergencyShuttleSystem), Friend = AccessPermissions.ReadWrite)]
|
||||||
|
public EntityUid? EmergencyShuttle;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Emergency shuttle map path for this station.
|
||||||
|
/// </summary>
|
||||||
|
[DataField("emergencyShuttlePath", customTypeSerializer: typeof(ResPathSerializer))]
|
||||||
|
public ResPath EmergencyShuttlePath { get; set; } = new("/Maps/Shuttles/emergency.yml");
|
||||||
|
}
|
||||||
@@ -57,7 +57,6 @@ public sealed class ArrivalsSystem : EntitySystem
|
|||||||
SubscribeLocalEvent<ArrivalsShuttleComponent, EntityUnpausedEvent>(OnShuttleUnpaused);
|
SubscribeLocalEvent<ArrivalsShuttleComponent, EntityUnpausedEvent>(OnShuttleUnpaused);
|
||||||
SubscribeLocalEvent<ArrivalsShuttleComponent, FTLTagEvent>(OnShuttleTag);
|
SubscribeLocalEvent<ArrivalsShuttleComponent, FTLTagEvent>(OnShuttleTag);
|
||||||
|
|
||||||
SubscribeLocalEvent<StationInitializedEvent>(OnStationInit);
|
|
||||||
SubscribeLocalEvent<RoundStartingEvent>(OnRoundStarting);
|
SubscribeLocalEvent<RoundStartingEvent>(OnRoundStarting);
|
||||||
SubscribeLocalEvent<ArrivalsShuttleComponent, FTLStartedEvent>(OnArrivalsFTL);
|
SubscribeLocalEvent<ArrivalsShuttleComponent, FTLStartedEvent>(OnArrivalsFTL);
|
||||||
|
|
||||||
@@ -207,17 +206,15 @@ public sealed class ArrivalsSystem : EntitySystem
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnStationInit(StationInitializedEvent ev)
|
|
||||||
{
|
|
||||||
EnsureComp<StationArrivalsComponent>(ev.Station);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnPlayerSpawn(PlayerSpawningEvent ev)
|
private void OnPlayerSpawn(PlayerSpawningEvent ev)
|
||||||
{
|
{
|
||||||
// Only works on latejoin even if enabled.
|
// Only works on latejoin even if enabled.
|
||||||
if (!Enabled || _ticker.RunLevel != GameRunLevel.InRound)
|
if (!Enabled || _ticker.RunLevel != GameRunLevel.InRound)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
if (!HasComp<StationArrivalsComponent>(ev.Station))
|
||||||
|
return;
|
||||||
|
|
||||||
var points = EntityQuery<SpawnPointComponent, TransformComponent>().ToList();
|
var points = EntityQuery<SpawnPointComponent, TransformComponent>().ToList();
|
||||||
_random.Shuffle(points);
|
_random.Shuffle(points);
|
||||||
TryGetArrivals(out var arrivals);
|
TryGetArrivals(out var arrivals);
|
||||||
|
|||||||
@@ -156,7 +156,7 @@ public sealed partial class EmergencyShuttleSystem
|
|||||||
|
|
||||||
if (CentComMap != null)
|
if (CentComMap != null)
|
||||||
{
|
{
|
||||||
var dataQuery = AllEntityQuery<StationDataComponent>();
|
var dataQuery = AllEntityQuery<StationEmergencyShuttleComponent>();
|
||||||
|
|
||||||
while (dataQuery.MoveNext(out var comp))
|
while (dataQuery.MoveNext(out var comp))
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -73,7 +73,7 @@ public sealed partial class EmergencyShuttleSystem : EntitySystem
|
|||||||
// Don't immediately invoke as roundstart will just handle it.
|
// Don't immediately invoke as roundstart will just handle it.
|
||||||
_configManager.OnValueChanged(CCVars.EmergencyShuttleEnabled, SetEmergencyShuttleEnabled);
|
_configManager.OnValueChanged(CCVars.EmergencyShuttleEnabled, SetEmergencyShuttleEnabled);
|
||||||
SubscribeLocalEvent<RoundStartingEvent>(OnRoundStart);
|
SubscribeLocalEvent<RoundStartingEvent>(OnRoundStart);
|
||||||
SubscribeLocalEvent<StationDataComponent, ComponentStartup>(OnStationStartup);
|
SubscribeLocalEvent<StationEmergencyShuttleComponent, ComponentStartup>(OnStationStartup);
|
||||||
SubscribeNetworkEvent<EmergencyShuttleRequestPositionMessage>(OnShuttleRequestPosition);
|
SubscribeNetworkEvent<EmergencyShuttleRequestPositionMessage>(OnShuttleRequestPosition);
|
||||||
InitializeEmergencyConsole();
|
InitializeEmergencyConsole();
|
||||||
}
|
}
|
||||||
@@ -115,19 +115,22 @@ public sealed partial class EmergencyShuttleSystem : EntitySystem
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
var player = args.SenderSession.AttachedEntity;
|
var player = args.SenderSession.AttachedEntity;
|
||||||
|
if (player is null)
|
||||||
|
return;
|
||||||
|
|
||||||
if (player == null ||
|
var station = _station.GetOwningStation(player.Value);
|
||||||
!TryComp<StationDataComponent>(_station.GetOwningStation(player.Value), out var stationData) ||
|
|
||||||
!HasComp<ShuttleComponent>(stationData.EmergencyShuttle))
|
if (!TryComp<StationEmergencyShuttleComponent>(station, out var stationShuttle) ||
|
||||||
|
!HasComp<ShuttleComponent>(stationShuttle.EmergencyShuttle))
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var targetGrid = _station.GetLargestGrid(stationData);
|
var targetGrid = _station.GetLargestGrid(Comp<StationDataComponent>(station.Value));
|
||||||
if (targetGrid == null)
|
if (targetGrid == null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var config = _dock.GetDockingConfig(stationData.EmergencyShuttle.Value, targetGrid.Value, DockTag);
|
var config = _dock.GetDockingConfig(stationShuttle.EmergencyShuttle.Value, targetGrid.Value, DockTag);
|
||||||
if (config == null)
|
if (config == null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@@ -143,14 +146,14 @@ public sealed partial class EmergencyShuttleSystem : EntitySystem
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public void CallEmergencyShuttle(EntityUid? stationUid)
|
public void CallEmergencyShuttle(EntityUid? stationUid)
|
||||||
{
|
{
|
||||||
if (!TryComp<StationDataComponent>(stationUid, out var stationData) ||
|
if (!TryComp<StationEmergencyShuttleComponent>(stationUid, out var stationShuttle) ||
|
||||||
!TryComp<TransformComponent>(stationData.EmergencyShuttle, out var xform) ||
|
!TryComp<TransformComponent>(stationShuttle.EmergencyShuttle, out var xform) ||
|
||||||
!TryComp<ShuttleComponent>(stationData.EmergencyShuttle, out var shuttle))
|
!TryComp<ShuttleComponent>(stationShuttle.EmergencyShuttle, out var shuttle))
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var targetGrid = _station.GetLargestGrid(stationData);
|
var targetGrid = _station.GetLargestGrid(Comp<StationDataComponent>(stationUid.Value));
|
||||||
|
|
||||||
// UHH GOOD LUCK
|
// UHH GOOD LUCK
|
||||||
if (targetGrid == null)
|
if (targetGrid == null)
|
||||||
@@ -164,11 +167,11 @@ public sealed partial class EmergencyShuttleSystem : EntitySystem
|
|||||||
|
|
||||||
var xformQuery = GetEntityQuery<TransformComponent>();
|
var xformQuery = GetEntityQuery<TransformComponent>();
|
||||||
|
|
||||||
if (_shuttle.TryFTLDock(stationData.EmergencyShuttle.Value, shuttle, targetGrid.Value, DockTag))
|
if (_shuttle.TryFTLDock(stationShuttle.EmergencyShuttle.Value, shuttle, targetGrid.Value, DockTag))
|
||||||
{
|
{
|
||||||
if (TryComp<TransformComponent>(targetGrid.Value, out var targetXform))
|
if (TryComp<TransformComponent>(targetGrid.Value, out var targetXform))
|
||||||
{
|
{
|
||||||
var angle = _dock.GetAngle(stationData.EmergencyShuttle.Value, xform, targetGrid.Value, targetXform, xformQuery);
|
var angle = _dock.GetAngle(stationShuttle.EmergencyShuttle.Value, xform, targetGrid.Value, targetXform, xformQuery);
|
||||||
_chatSystem.DispatchStationAnnouncement(stationUid.Value, Loc.GetString("emergency-shuttle-docked", ("time", $"{_consoleAccumulator:0}"), ("direction", angle.GetDir())), playDefaultSound: false);
|
_chatSystem.DispatchStationAnnouncement(stationUid.Value, Loc.GetString("emergency-shuttle-docked", ("time", $"{_consoleAccumulator:0}"), ("direction", angle.GetDir())), playDefaultSound: false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -180,7 +183,7 @@ public sealed partial class EmergencyShuttleSystem : EntitySystem
|
|||||||
{
|
{
|
||||||
if (TryComp<TransformComponent>(targetGrid.Value, out var targetXform))
|
if (TryComp<TransformComponent>(targetGrid.Value, out var targetXform))
|
||||||
{
|
{
|
||||||
var angle = _dock.GetAngle(stationData.EmergencyShuttle.Value, xform, targetGrid.Value, targetXform, xformQuery);
|
var angle = _dock.GetAngle(stationShuttle.EmergencyShuttle.Value, xform, targetGrid.Value, targetXform, xformQuery);
|
||||||
_chatSystem.DispatchStationAnnouncement(stationUid.Value, Loc.GetString("emergency-shuttle-nearby", ("direction", angle.GetDir())), playDefaultSound: false);
|
_chatSystem.DispatchStationAnnouncement(stationUid.Value, Loc.GetString("emergency-shuttle-nearby", ("direction", angle.GetDir())), playDefaultSound: false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -190,7 +193,7 @@ public sealed partial class EmergencyShuttleSystem : EntitySystem
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnStationStartup(EntityUid uid, StationDataComponent component, ComponentStartup args)
|
private void OnStationStartup(EntityUid uid, StationEmergencyShuttleComponent component, ComponentStartup args)
|
||||||
{
|
{
|
||||||
AddEmergencyShuttle(component);
|
AddEmergencyShuttle(component);
|
||||||
}
|
}
|
||||||
@@ -254,24 +257,23 @@ public sealed partial class EmergencyShuttleSystem : EntitySystem
|
|||||||
_sawmill.Info("No CentCom map found, skipping setup.");
|
_sawmill.Info("No CentCom map found, skipping setup.");
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (var comp in EntityQuery<StationDataComponent>(true))
|
foreach (var comp in EntityQuery<StationEmergencyShuttleComponent>(true))
|
||||||
{
|
{
|
||||||
AddEmergencyShuttle(comp);
|
AddEmergencyShuttle(comp);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void AddEmergencyShuttle(StationDataComponent component)
|
private void AddEmergencyShuttle(StationEmergencyShuttleComponent component)
|
||||||
{
|
{
|
||||||
if (!_emergencyShuttleEnabled
|
if (!_emergencyShuttleEnabled
|
||||||
|| CentComMap == null
|
|| CentComMap == null
|
||||||
|| component.EmergencyShuttle != null
|
|| component.EmergencyShuttle != null)
|
||||||
|| component.StationConfig == null)
|
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Load escape shuttle
|
// Load escape shuttle
|
||||||
var shuttlePath = component.StationConfig.EmergencyShuttlePath;
|
var shuttlePath = component.EmergencyShuttlePath;
|
||||||
var shuttle = _map.LoadGrid(CentComMap.Value, shuttlePath.ToString(), new MapLoadOptions()
|
var shuttle = _map.LoadGrid(CentComMap.Value, shuttlePath.ToString(), new MapLoadOptions()
|
||||||
{
|
{
|
||||||
// Should be far enough... right? I'm too lazy to bounds check CentCom rn.
|
// Should be far enough... right? I'm too lazy to bounds check CentCom rn.
|
||||||
|
|||||||
@@ -1,15 +0,0 @@
|
|||||||
using Content.Server.GameTicking;
|
|
||||||
|
|
||||||
namespace Content.Server.Station.Components;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Added to grids saved in maps to designate them as 'part of a station' and not main grids. I.e. ancillary
|
|
||||||
/// shuttles for multi-grid stations.
|
|
||||||
/// </summary>
|
|
||||||
[RegisterComponent, Access(typeof(GameTicker)), Obsolete("Performs the exact same function as BecomesStationComponent.")]
|
|
||||||
public sealed class PartOfStationComponent : Component
|
|
||||||
{
|
|
||||||
[DataField("id", required: true)]
|
|
||||||
[ViewVariables(VVAccess.ReadWrite)]
|
|
||||||
public string Id = default!;
|
|
||||||
}
|
|
||||||
@@ -1,5 +1,7 @@
|
|||||||
using Content.Server.Shuttles.Systems;
|
using Content.Server.Shuttles.Systems;
|
||||||
using Content.Server.Station.Systems;
|
using Content.Server.Station.Systems;
|
||||||
|
using Robust.Shared.Serialization.TypeSerializers.Implementations;
|
||||||
|
using Robust.Shared.Utility;
|
||||||
|
|
||||||
namespace Content.Server.Station.Components;
|
namespace Content.Server.Station.Components;
|
||||||
|
|
||||||
@@ -19,15 +21,6 @@ public sealed class StationDataComponent : Component
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// List of all grids this station is part of.
|
/// List of all grids this station is part of.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <remarks>
|
|
||||||
/// You should not mutate this yourself, go through StationSystem so the appropriate events get fired.
|
|
||||||
/// </remarks>
|
|
||||||
[DataField("grids")]
|
[DataField("grids")]
|
||||||
public readonly HashSet<EntityUid> Grids = new();
|
public readonly HashSet<EntityUid> Grids = new();
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The emergency shuttle assigned to this station.
|
|
||||||
/// </summary>
|
|
||||||
[ViewVariables, Access(typeof(ShuttleSystem), typeof(EmergencyShuttleSystem), Friend = AccessPermissions.ReadWrite)]
|
|
||||||
public EntityUid? EmergencyShuttle;
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,10 @@
|
|||||||
|
namespace Content.Server.Station.Components;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// This is used for event eligibility.
|
||||||
|
/// </summary>
|
||||||
|
[RegisterComponent]
|
||||||
|
public sealed class StationEventEligibleComponent : Component
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
@@ -32,6 +32,16 @@ public sealed class StationJobsComponent : Component
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
[DataField("extendedAccess")] public bool ExtendedAccess;
|
[DataField("extendedAccess")] public bool ExtendedAccess;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// If there are less than or equal this amount of players in the game at round start,
|
||||||
|
/// people get extended access levels from job prototypes.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// Set to -1 to disable extended access.
|
||||||
|
/// </remarks>
|
||||||
|
[DataField("extendedAccessThreshold")]
|
||||||
|
public int ExtendedAccessThreshold { get; set; } = 15;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The percentage of jobs remaining.
|
/// The percentage of jobs remaining.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -62,5 +72,10 @@ public sealed class StationJobsComponent : Component
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Overflow jobs that round-start can spawn infinitely many of.
|
/// Overflow jobs that round-start can spawn infinitely many of.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[DataField("overflowJobs", customTypeSerializer: typeof(PrototypeIdHashSetSerializer<JobPrototype>))] public HashSet<string> OverflowJobs = new();
|
[DataField("overflowJobs", customTypeSerializer: typeof(PrototypeIdHashSetSerializer<JobPrototype>))]
|
||||||
|
public HashSet<string> OverflowJobs = new();
|
||||||
|
|
||||||
|
[DataField("availableJobs", required: true,
|
||||||
|
customTypeSerializer: typeof(PrototypeIdDictionarySerializer<List<int?>, JobPrototype>))]
|
||||||
|
public readonly Dictionary<string, List<int?>> SetupAvailableJobs = default!;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,23 @@
|
|||||||
|
using Content.Server.Maps.NameGenerators;
|
||||||
|
|
||||||
|
namespace Content.Server.Station.Components;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// This is used for setting up a station's name.
|
||||||
|
/// </summary>
|
||||||
|
[RegisterComponent]
|
||||||
|
public sealed class StationNameSetupComponent : Component
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The name template to use for the station.
|
||||||
|
/// If there's a name generator this should follow it's required format.
|
||||||
|
/// </summary>
|
||||||
|
[DataField("mapNameTemplate", required: true)]
|
||||||
|
public string StationNameTemplate { get; } = default!;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Name generator to use for the station, if any.
|
||||||
|
/// </summary>
|
||||||
|
[DataField("nameGenerator")]
|
||||||
|
public StationNameGenerator? NameGenerator { get; }
|
||||||
|
}
|
||||||
@@ -1,38 +0,0 @@
|
|||||||
using Content.Shared.Roles;
|
|
||||||
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype.Dictionary;
|
|
||||||
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype.List;
|
|
||||||
|
|
||||||
namespace Content.Server.Station;
|
|
||||||
|
|
||||||
public sealed partial class StationConfig
|
|
||||||
{
|
|
||||||
[DataField("overflowJobs", required: true, customTypeSerializer: typeof(PrototypeIdListSerializer<JobPrototype>))]
|
|
||||||
private readonly List<string> _overflowJobs = default!;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Jobs used at round start should the station run out of job slots.
|
|
||||||
/// Doesn't necessarily mean the station has infinite slots for the given jobs mid-round!
|
|
||||||
/// </summary>
|
|
||||||
public IReadOnlyList<string> OverflowJobs => _overflowJobs;
|
|
||||||
|
|
||||||
|
|
||||||
[DataField("availableJobs", required: true,
|
|
||||||
customTypeSerializer: typeof(PrototypeIdDictionarySerializer<List<int?>, JobPrototype>))]
|
|
||||||
private readonly Dictionary<string, List<int?>> _availableJobs = default!;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Index of all jobs available on the station, of form
|
|
||||||
/// job name: [round-start, mid-round]
|
|
||||||
/// </summary>
|
|
||||||
public IReadOnlyDictionary<string, List<int?>> AvailableJobs => _availableJobs;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// If there are less than or equal this amount of players in the game at round start,
|
|
||||||
/// people get extended access levels from job prototypes.
|
|
||||||
/// </summary>
|
|
||||||
/// <remarks>
|
|
||||||
/// Set to -1 to disable extended access.
|
|
||||||
/// </remarks>
|
|
||||||
[DataField("extendedAccessThreshold")]
|
|
||||||
public int ExtendedAccessThreshold { get; set; } = 15;
|
|
||||||
}
|
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
using Robust.Shared.Utility;
|
|
||||||
using Robust.Shared.Serialization.TypeSerializers.Implementations;
|
|
||||||
|
|
||||||
namespace Content.Server.Station;
|
|
||||||
|
|
||||||
public sealed partial class StationConfig
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Emergency shuttle map path for this station.
|
|
||||||
/// </summary>
|
|
||||||
[DataField("emergencyShuttlePath", customTypeSerializer: typeof(ResPathSerializer))]
|
|
||||||
public ResPath EmergencyShuttlePath { get; set; } = new("/Maps/Shuttles/emergency.yml");
|
|
||||||
}
|
|
||||||
@@ -1,30 +1,19 @@
|
|||||||
using Content.Server.Maps.NameGenerators;
|
using Content.Server.Maps.NameGenerators;
|
||||||
using JetBrains.Annotations;
|
using JetBrains.Annotations;
|
||||||
|
using Robust.Shared.Prototypes;
|
||||||
|
|
||||||
namespace Content.Server.Station;
|
namespace Content.Server.Station;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// A config for a station. Specifies name and job slots.
|
/// A config for a station. Specifies name and component modifications.
|
||||||
/// This is the only part of stations a downstream should ideally need to modify directly.
|
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <remarks>
|
|
||||||
/// Forks should not directly edit existing parts of this class.
|
|
||||||
/// Make a new partial for your fancy new feature, it'll save you time later.
|
|
||||||
/// </remarks>
|
|
||||||
[DataDefinition, PublicAPI]
|
[DataDefinition, PublicAPI]
|
||||||
public sealed partial class StationConfig
|
public sealed class StationConfig
|
||||||
{
|
{
|
||||||
/// <summary>
|
[DataField("stationProto", required: true)]
|
||||||
/// The name template to use for the station.
|
public string StationPrototype = default!;
|
||||||
/// If there's a name generator this should follow it's required format.
|
|
||||||
/// </summary>
|
|
||||||
[DataField("mapNameTemplate", required: true)]
|
|
||||||
public string StationNameTemplate { get; } = default!;
|
|
||||||
|
|
||||||
/// <summary>
|
[DataField("components", required: true)]
|
||||||
/// Name generator to use for the station, if any.
|
public ComponentRegistry StationComponentOverrides = default!;
|
||||||
/// </summary>
|
|
||||||
[DataField("nameGenerator")]
|
|
||||||
public StationNameGenerator? NameGenerator { get; }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -318,9 +318,8 @@ public sealed partial class StationJobsSystem
|
|||||||
foreach (var (station, count) in jobsCount)
|
foreach (var (station, count) in jobsCount)
|
||||||
{
|
{
|
||||||
var jobs = Comp<StationJobsComponent>(station);
|
var jobs = Comp<StationJobsComponent>(station);
|
||||||
var data = Comp<StationDataComponent>(station);
|
|
||||||
|
|
||||||
var thresh = data.StationConfig?.ExtendedAccessThreshold ?? -1;
|
var thresh = jobs.ExtendedAccessThreshold;
|
||||||
|
|
||||||
jobs.ExtendedAccess = count <= thresh;
|
jobs.ExtendedAccess = count <= thresh;
|
||||||
|
|
||||||
|
|||||||
@@ -53,30 +53,32 @@ public sealed partial class StationJobsSystem : EntitySystem
|
|||||||
|
|
||||||
private void OnStationInitialized(StationInitializedEvent msg)
|
private void OnStationInitialized(StationInitializedEvent msg)
|
||||||
{
|
{
|
||||||
var stationJobs = AddComp<StationJobsComponent>(msg.Station);
|
if (!TryComp<StationJobsComponent>(msg.Station, out var stationJobs))
|
||||||
var stationData = Comp<StationDataComponent>(msg.Station);
|
|
||||||
|
|
||||||
if (stationData.StationConfig == null)
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var mapJobList = stationData.StationConfig.AvailableJobs;
|
var mapJobList = stationJobs.SetupAvailableJobs;
|
||||||
|
|
||||||
stationJobs.RoundStartTotalJobs = mapJobList.Values.Where(x => x[0] is not null && x[0] > 0).Sum(x => x[0]!.Value);
|
stationJobs.RoundStartTotalJobs = mapJobList.Values.Where(x => x[0] is not null && x[0] > 0).Sum(x => x[0]!.Value);
|
||||||
stationJobs.MidRoundTotalJobs = mapJobList.Values.Where(x => x[1] is not null && x[1] > 0).Sum(x => x[1]!.Value);
|
stationJobs.MidRoundTotalJobs = mapJobList.Values.Where(x => x[1] is not null && x[1] > 0).Sum(x => x[1]!.Value);
|
||||||
|
|
||||||
stationJobs.TotalJobs = stationJobs.MidRoundTotalJobs;
|
stationJobs.TotalJobs = stationJobs.MidRoundTotalJobs;
|
||||||
|
|
||||||
stationJobs.JobList = mapJobList.ToDictionary(x => x.Key, x =>
|
stationJobs.JobList = mapJobList.ToDictionary(x => x.Key, x =>
|
||||||
{
|
{
|
||||||
if (x.Value[1] <= -1)
|
if (x.Value[1] <= -1)
|
||||||
return null;
|
return null;
|
||||||
return (uint?) x.Value[1];
|
return (uint?) x.Value[1];
|
||||||
});
|
});
|
||||||
|
|
||||||
stationJobs.RoundStartJobList = mapJobList.ToDictionary(x => x.Key, x =>
|
stationJobs.RoundStartJobList = mapJobList.ToDictionary(x => x.Key, x =>
|
||||||
{
|
{
|
||||||
if (x.Value[0] <= -1)
|
if (x.Value[0] <= -1)
|
||||||
return null;
|
return null;
|
||||||
return (uint?) x.Value[0];
|
return (uint?) x.Value[0];
|
||||||
});
|
});
|
||||||
stationJobs.OverflowJobs = stationData.StationConfig.OverflowJobs.ToHashSet();
|
|
||||||
|
stationJobs.OverflowJobs = stationJobs.OverflowJobs.ToHashSet();
|
||||||
|
|
||||||
UpdateJobsAvailable();
|
UpdateJobsAvailable();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -464,9 +466,11 @@ public sealed partial class StationJobsSystem : EntitySystem
|
|||||||
var jobs = new Dictionary<EntityUid, Dictionary<string, uint?>>();
|
var jobs = new Dictionary<EntityUid, Dictionary<string, uint?>>();
|
||||||
var stationNames = new Dictionary<EntityUid, string>();
|
var stationNames = new Dictionary<EntityUid, string>();
|
||||||
|
|
||||||
foreach (var station in _stationSystem.Stations)
|
var query = EntityQueryEnumerator<StationJobsComponent>();
|
||||||
|
|
||||||
|
while (query.MoveNext(out var station, out var comp))
|
||||||
{
|
{
|
||||||
var list = Comp<StationJobsComponent>(station).JobList.ToDictionary(x => x.Key, x => x.Value);
|
var list = comp.JobList.ToDictionary(x => x.Key, x => x.Value);
|
||||||
jobs.Add(station, list);
|
jobs.Add(station, list);
|
||||||
stationNames.Add(station, Name(station));
|
stationNames.Add(station, Name(station));
|
||||||
}
|
}
|
||||||
|
|||||||
35
Content.Server/Station/Systems/StationNameSystem.cs
Normal file
35
Content.Server/Station/Systems/StationNameSystem.cs
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
using Content.Server.Station.Components;
|
||||||
|
|
||||||
|
namespace Content.Server.Station.Systems;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// This handles naming stations.
|
||||||
|
/// </summary>
|
||||||
|
public sealed class StationNameSystem : EntitySystem
|
||||||
|
{
|
||||||
|
[Dependency] private readonly StationSystem _station = default!;
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public override void Initialize()
|
||||||
|
{
|
||||||
|
SubscribeLocalEvent<StationNameSetupComponent, ComponentInit>(OnStationNameSetupInit);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnStationNameSetupInit(EntityUid uid, StationNameSetupComponent component, ComponentInit args)
|
||||||
|
{
|
||||||
|
if (!HasComp<StationDataComponent>(uid))
|
||||||
|
return;
|
||||||
|
|
||||||
|
_station.RenameStation(uid, GenerateStationName(component), false);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Generates a station name from the given config.
|
||||||
|
/// </summary>
|
||||||
|
private static string GenerateStationName(StationNameSetupComponent config)
|
||||||
|
{
|
||||||
|
return config.NameGenerator is not null
|
||||||
|
? config.NameGenerator.FormatName(config.StationNameTemplate)
|
||||||
|
: config.StationNameTemplate;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -50,15 +50,9 @@ public sealed class StationSpawningSystem : EntitySystem
|
|||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public override void Initialize()
|
public override void Initialize()
|
||||||
{
|
{
|
||||||
SubscribeLocalEvent<StationInitializedEvent>(OnStationInitialized);
|
|
||||||
_configurationManager.OnValueChanged(CCVars.ICRandomCharacters, e => _randomizeCharacters = e, true);
|
_configurationManager.OnValueChanged(CCVars.ICRandomCharacters, e => _randomizeCharacters = e, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnStationInitialized(StationInitializedEvent ev)
|
|
||||||
{
|
|
||||||
AddComp<StationSpawningComponent>(ev.Station);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Attempts to spawn a player character onto the given station.
|
/// Attempts to spawn a player character onto the given station.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -95,16 +89,19 @@ public sealed class StationSpawningSystem : EntitySystem
|
|||||||
/// <param name="job">Job to assign to the character, if any.</param>
|
/// <param name="job">Job to assign to the character, if any.</param>
|
||||||
/// <param name="profile">Appearance profile to use for the character.</param>
|
/// <param name="profile">Appearance profile to use for the character.</param>
|
||||||
/// <param name="station">The station this player is being spawned on.</param>
|
/// <param name="station">The station this player is being spawned on.</param>
|
||||||
|
/// <param name="entity">The entity to use, if one already exists.</param>
|
||||||
/// <returns>The spawned entity</returns>
|
/// <returns>The spawned entity</returns>
|
||||||
public EntityUid SpawnPlayerMob(
|
public EntityUid SpawnPlayerMob(
|
||||||
EntityCoordinates coordinates,
|
EntityCoordinates coordinates,
|
||||||
Job? job,
|
Job? job,
|
||||||
HumanoidCharacterProfile? profile,
|
HumanoidCharacterProfile? profile,
|
||||||
EntityUid? station)
|
EntityUid? station,
|
||||||
|
EntityUid? entity = null)
|
||||||
{
|
{
|
||||||
// If we're not spawning a humanoid, we're gonna exit early without doing all the humanoid stuff.
|
// If we're not spawning a humanoid, we're gonna exit early without doing all the humanoid stuff.
|
||||||
if (job?.JobEntity != null)
|
if (job?.JobEntity != null)
|
||||||
{
|
{
|
||||||
|
DebugTools.Assert(entity is null);
|
||||||
var jobEntity = EntityManager.SpawnEntity(job.JobEntity, coordinates);
|
var jobEntity = EntityManager.SpawnEntity(job.JobEntity, coordinates);
|
||||||
MakeSentientCommand.MakeSentient(jobEntity, EntityManager);
|
MakeSentientCommand.MakeSentient(jobEntity, EntityManager);
|
||||||
DoJobSpecials(job, jobEntity);
|
DoJobSpecials(job, jobEntity);
|
||||||
@@ -131,7 +128,7 @@ public sealed class StationSpawningSystem : EntitySystem
|
|||||||
if (!_prototypeManager.TryIndex<SpeciesPrototype>(speciesId, out var species))
|
if (!_prototypeManager.TryIndex<SpeciesPrototype>(speciesId, out var species))
|
||||||
throw new ArgumentException($"Invalid species prototype was used: {speciesId}");
|
throw new ArgumentException($"Invalid species prototype was used: {speciesId}");
|
||||||
|
|
||||||
var entity = Spawn(species.Prototype, coordinates);
|
entity ??= Spawn(species.Prototype, coordinates);
|
||||||
|
|
||||||
if (_randomizeCharacters)
|
if (_randomizeCharacters)
|
||||||
{
|
{
|
||||||
@@ -141,24 +138,24 @@ public sealed class StationSpawningSystem : EntitySystem
|
|||||||
if (job?.StartingGear != null)
|
if (job?.StartingGear != null)
|
||||||
{
|
{
|
||||||
var startingGear = _prototypeManager.Index<StartingGearPrototype>(job.StartingGear);
|
var startingGear = _prototypeManager.Index<StartingGearPrototype>(job.StartingGear);
|
||||||
EquipStartingGear(entity, startingGear, profile);
|
EquipStartingGear(entity.Value, startingGear, profile);
|
||||||
if (profile != null)
|
if (profile != null)
|
||||||
EquipIdCard(entity, profile.Name, job.Prototype, station);
|
EquipIdCard(entity.Value, profile.Name, job.Prototype, station);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (profile != null)
|
if (profile != null)
|
||||||
{
|
{
|
||||||
_humanoidSystem.LoadProfile(entity, profile);
|
_humanoidSystem.LoadProfile(entity.Value, profile);
|
||||||
MetaData(entity).EntityName = profile.Name;
|
MetaData(entity.Value).EntityName = profile.Name;
|
||||||
if (profile.FlavorText != "" && _configurationManager.GetCVar(CCVars.FlavorText))
|
if (profile.FlavorText != "" && _configurationManager.GetCVar(CCVars.FlavorText))
|
||||||
{
|
{
|
||||||
AddComp<DetailExaminableComponent>(entity).Content = profile.FlavorText;
|
AddComp<DetailExaminableComponent>(entity.Value).Content = profile.FlavorText;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
DoJobSpecials(job, entity);
|
DoJobSpecials(job, entity.Value);
|
||||||
_identity.QueueIdentityUpdate(entity);
|
_identity.QueueIdentityUpdate(entity.Value);
|
||||||
return entity;
|
return entity.Value;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void DoJobSpecials(Job? job, EntityUid entity)
|
private void DoJobSpecials(Job? job, EntityUid entity)
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ using Robust.Shared.Map;
|
|||||||
using Robust.Shared.Map.Components;
|
using Robust.Shared.Map.Components;
|
||||||
using Robust.Shared.Player;
|
using Robust.Shared.Player;
|
||||||
using Robust.Shared.Random;
|
using Robust.Shared.Random;
|
||||||
|
using Robust.Shared.Utility;
|
||||||
|
|
||||||
namespace Content.Server.Station.Systems;
|
namespace Content.Server.Station.Systems;
|
||||||
|
|
||||||
@@ -35,16 +36,6 @@ public sealed class StationSystem : EntitySystem
|
|||||||
|
|
||||||
private ISawmill _sawmill = default!;
|
private ISawmill _sawmill = default!;
|
||||||
|
|
||||||
private readonly HashSet<EntityUid> _stations = new();
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// All stations that currently exist.
|
|
||||||
/// </summary>
|
|
||||||
/// <remarks>
|
|
||||||
/// I'd have this just invoke an entity query, but I want this to be a hashset for convenience and it allocating on use would be lame.
|
|
||||||
/// </remarks>
|
|
||||||
public IReadOnlySet<EntityUid> Stations => _stations;
|
|
||||||
|
|
||||||
private bool _randomStationOffset;
|
private bool _randomStationOffset;
|
||||||
private bool _randomStationRotation;
|
private bool _randomStationRotation;
|
||||||
private float _maxRandomStationOffset;
|
private float _maxRandomStationOffset;
|
||||||
@@ -57,9 +48,8 @@ public sealed class StationSystem : EntitySystem
|
|||||||
SubscribeLocalEvent<GameRunLevelChangedEvent>(OnRoundEnd);
|
SubscribeLocalEvent<GameRunLevelChangedEvent>(OnRoundEnd);
|
||||||
SubscribeLocalEvent<PreGameMapLoad>(OnPreGameMapLoad);
|
SubscribeLocalEvent<PreGameMapLoad>(OnPreGameMapLoad);
|
||||||
SubscribeLocalEvent<PostGameMapLoad>(OnPostGameMapLoad);
|
SubscribeLocalEvent<PostGameMapLoad>(OnPostGameMapLoad);
|
||||||
SubscribeLocalEvent<StationDataComponent, ComponentAdd>(OnStationAdd);
|
SubscribeLocalEvent<StationDataComponent, ComponentStartup>(OnStationAdd);
|
||||||
SubscribeLocalEvent<StationDataComponent, ComponentShutdown>(OnStationDeleted);
|
SubscribeLocalEvent<StationDataComponent, ComponentShutdown>(OnStationDeleted);
|
||||||
SubscribeLocalEvent<StationDataComponent, EntParentChangedMessage>(OnParentChanged);
|
|
||||||
SubscribeLocalEvent<StationMemberComponent, ComponentShutdown>(OnStationGridDeleted);
|
SubscribeLocalEvent<StationMemberComponent, ComponentShutdown>(OnStationGridDeleted);
|
||||||
SubscribeLocalEvent<StationMemberComponent, PostGridSplitEvent>(OnStationSplitEvent);
|
SubscribeLocalEvent<StationMemberComponent, PostGridSplitEvent>(OnStationSplitEvent);
|
||||||
|
|
||||||
@@ -89,68 +79,34 @@ public sealed class StationSystem : EntitySystem
|
|||||||
_player.PlayerStatusChanged -= OnPlayerStatusChanged;
|
_player.PlayerStatusChanged -= OnPlayerStatusChanged;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Called when the server shuts down or restarts to avoid uneccesarily logging mid-round station deletion errors.
|
|
||||||
/// </summary>
|
|
||||||
public void OnServerDispose()
|
|
||||||
{
|
|
||||||
_stations.Clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnPlayerStatusChanged(object? sender, SessionStatusEventArgs e)
|
private void OnPlayerStatusChanged(object? sender, SessionStatusEventArgs e)
|
||||||
{
|
{
|
||||||
if (e.NewStatus == SessionStatus.Connected)
|
if (e.NewStatus == SessionStatus.Connected)
|
||||||
{
|
{
|
||||||
RaiseNetworkEvent(new StationsUpdatedEvent(_stations), e.Session);
|
RaiseNetworkEvent(new StationsUpdatedEvent(GetStationsSet()), e.Session);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#region Event handlers
|
#region Event handlers
|
||||||
|
|
||||||
private void OnStationAdd(EntityUid uid, StationDataComponent component, ComponentAdd args)
|
private void OnStationAdd(EntityUid uid, StationDataComponent component, ComponentStartup args)
|
||||||
{
|
{
|
||||||
_stations.Add(uid);
|
RaiseNetworkEvent(new StationsUpdatedEvent(GetStationsSet()), Filter.Broadcast());
|
||||||
|
|
||||||
|
var metaData = MetaData(uid);
|
||||||
|
RaiseLocalEvent(new StationInitializedEvent(uid));
|
||||||
|
_sawmill.Info($"Set up station {metaData.EntityName} ({uid}).");
|
||||||
|
|
||||||
RaiseNetworkEvent(new StationsUpdatedEvent(_stations), Filter.Broadcast());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnStationDeleted(EntityUid uid, StationDataComponent component, ComponentShutdown args)
|
private void OnStationDeleted(EntityUid uid, StationDataComponent component, ComponentShutdown args)
|
||||||
{
|
{
|
||||||
if (_stations.Contains(uid) && // Was not deleted via DeleteStation()
|
|
||||||
_gameTicker.RunLevel == GameRunLevel.InRound && // And not due to a round restart
|
|
||||||
_gameTicker.LobbyEnabled) // If there isn't a lobby, this is probably sandbox, single player, or a test
|
|
||||||
{
|
|
||||||
// printing a stack trace, rather than throwing an exception so that entity deletion continues as normal.
|
|
||||||
Logger.Error($"Station entity {ToPrettyString(uid)} is getting deleted mid-round. Trace: {Environment.StackTrace}");
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach (var grid in component.Grids)
|
foreach (var grid in component.Grids)
|
||||||
{
|
{
|
||||||
RemComp<StationMemberComponent>(grid);
|
RemComp<StationMemberComponent>(grid);
|
||||||
}
|
}
|
||||||
|
|
||||||
_stations.Remove(uid);
|
RaiseNetworkEvent(new StationsUpdatedEvent(GetStationsSet()), Filter.Broadcast());
|
||||||
RaiseNetworkEvent(new StationsUpdatedEvent(_stations), Filter.Broadcast());
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// If a station data entity is getting re-parented mid-round, this will log an error.
|
|
||||||
/// </summary>
|
|
||||||
/// <remarks>
|
|
||||||
/// This doesn't really achieve anything, it just for debugging any future station data bugs.
|
|
||||||
/// </remarks>
|
|
||||||
private void OnParentChanged(EntityUid uid, StationDataComponent component, ref EntParentChangedMessage args)
|
|
||||||
{
|
|
||||||
if (_gameTicker.RunLevel != GameRunLevel.InRound ||
|
|
||||||
MetaData(uid).EntityLifeStage >= EntityLifeStage.MapInitialized ||
|
|
||||||
component.LifeStage <= ComponentLifeStage.Initializing)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Yeah this doesn't actually stop the parent change..... it just ineffectually yells about it.
|
|
||||||
// STOP RIGHT THERE CRIMINAL SCUM
|
|
||||||
_sawmill.Error($"Station entity {ToPrettyString(uid)} is getting reparented from {ToPrettyString(args.OldParent ?? EntityUid.Invalid)} to {ToPrettyString(args.Transform.ParentUid)}");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnPreGameMapLoad(PreGameMapLoad ev)
|
private void OnPreGameMapLoad(PreGameMapLoad ev)
|
||||||
@@ -199,23 +155,18 @@ public sealed class StationSystem : EntitySystem
|
|||||||
_sawmill.Error($"There were no station grids for {ev.GameMap.ID}!");
|
_sawmill.Error($"There were no station grids for {ev.GameMap.ID}!");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Iterate over all PartOfStation
|
|
||||||
// TODO: Remove this whenever pillar finally gets replaced. It's the sole user.
|
|
||||||
foreach (var grid in ev.Grids)
|
|
||||||
{
|
|
||||||
if (!TryComp<PartOfStationComponent>(grid, out var partOfStation))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
AddGrid(partOfStation.Id, grid);
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach (var (id, gridIds) in dict)
|
foreach (var (id, gridIds) in dict)
|
||||||
{
|
{
|
||||||
StationConfig? stationConfig = null;
|
StationConfig stationConfig;
|
||||||
|
|
||||||
if (ev.GameMap.Stations.ContainsKey(id))
|
if (ev.GameMap.Stations.ContainsKey(id))
|
||||||
stationConfig = ev.GameMap.Stations[id];
|
stationConfig = ev.GameMap.Stations[id];
|
||||||
else
|
else
|
||||||
|
{
|
||||||
_sawmill.Error($"The station {id} in map {ev.GameMap.ID} does not have an associated station config!");
|
_sawmill.Error($"The station {id} in map {ev.GameMap.ID} does not have an associated station config!");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
InitializeNewStation(stationConfig, gridIds, ev.StationName);
|
InitializeNewStation(stationConfig, gridIds, ev.StationName);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -225,9 +176,10 @@ public sealed class StationSystem : EntitySystem
|
|||||||
if (eventArgs.New != GameRunLevel.PreRoundLobby)
|
if (eventArgs.New != GameRunLevel.PreRoundLobby)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
foreach (var entity in _stations)
|
var query = EntityQueryEnumerator<StationDataComponent>();
|
||||||
|
while (query.MoveNext(out var station, out _))
|
||||||
{
|
{
|
||||||
DeleteStation(entity);
|
QueueDel(station);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -326,47 +278,26 @@ public sealed class StationSystem : EntitySystem
|
|||||||
return filter;
|
return filter;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Generates a station name from the given config.
|
|
||||||
/// </summary>
|
|
||||||
public static string GenerateStationName(StationConfig config)
|
|
||||||
{
|
|
||||||
return config.NameGenerator is not null
|
|
||||||
? config.NameGenerator.FormatName(config.StationNameTemplate)
|
|
||||||
: config.StationNameTemplate;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes a new station with the given information.
|
/// Initializes a new station with the given information.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="stationConfig">The game map prototype used, if any.</param>
|
/// <param name="stationConfig">The game map prototype used, if any.</param>
|
||||||
/// <param name="gridIds">All grids that should be added to the station.</param>
|
/// <param name="gridIds">All grids that should be added to the station.</param>
|
||||||
/// <param name="name">Optional override for the station name.</param>
|
/// <param name="name">Optional override for the station name.</param>
|
||||||
|
/// <remarks>This is for ease of use, manually spawning the entity works just fine.</remarks>
|
||||||
/// <returns>The initialized station.</returns>
|
/// <returns>The initialized station.</returns>
|
||||||
public EntityUid InitializeNewStation(StationConfig? stationConfig, IEnumerable<EntityUid>? gridIds, string? name = null)
|
public EntityUid InitializeNewStation(StationConfig stationConfig, IEnumerable<EntityUid>? gridIds, string? name = null)
|
||||||
{
|
{
|
||||||
var station = Spawn(null, MapCoordinates.Nullspace);
|
// Use overrides for setup.
|
||||||
|
var station = EntityManager.SpawnEntity(stationConfig.StationPrototype, MapCoordinates.Nullspace, stationConfig.StationComponentOverrides);
|
||||||
|
|
||||||
// TODO SERIALIZATION The station data needs to be saveable somehow, but when a map gets saved, this entity
|
if (name is not null)
|
||||||
// won't be included because its in null-space. Also, what happens to shuttles on other maps?
|
RenameStation(station, name, false);
|
||||||
|
|
||||||
var data = AddComp<StationDataComponent>(station);
|
DebugTools.Assert(HasComp<StationDataComponent>(station), "Stations should have StationData in their prototype.");
|
||||||
var metaData = MetaData(station);
|
|
||||||
data.StationConfig = stationConfig;
|
|
||||||
|
|
||||||
if (stationConfig is not null && name is null)
|
var data = Comp<StationDataComponent>(station);
|
||||||
{
|
name ??= MetaData(station).EntityName;
|
||||||
name = GenerateStationName(stationConfig);
|
|
||||||
}
|
|
||||||
else if (name is null)
|
|
||||||
{
|
|
||||||
_sawmill.Error($"When setting up station {station}, was unable to find a valid name in the config and no name was provided.");
|
|
||||||
name = "unnamed station";
|
|
||||||
}
|
|
||||||
|
|
||||||
metaData.EntityName = name;
|
|
||||||
RaiseLocalEvent(new StationInitializedEvent(station));
|
|
||||||
_sawmill.Info($"Set up station {metaData.EntityName} ({station}).");
|
|
||||||
|
|
||||||
foreach (var grid in gridIds ?? Array.Empty<EntityUid>())
|
foreach (var grid in gridIds ?? Array.Empty<EntityUid>())
|
||||||
{
|
{
|
||||||
@@ -397,11 +328,11 @@ public sealed class StationSystem : EntitySystem
|
|||||||
|
|
||||||
var stationMember = AddComp<StationMemberComponent>(mapGrid);
|
var stationMember = AddComp<StationMemberComponent>(mapGrid);
|
||||||
stationMember.Station = station;
|
stationMember.Station = station;
|
||||||
stationData.Grids.Add(gridComponent.Owner);
|
stationData.Grids.Add(mapGrid);
|
||||||
|
|
||||||
RaiseLocalEvent(station, new StationGridAddedEvent(gridComponent.Owner, false), true);
|
RaiseLocalEvent(station, new StationGridAddedEvent(mapGrid, false), true);
|
||||||
|
|
||||||
_sawmill.Info($"Adding grid {mapGrid}:{gridComponent.Owner} to station {Name(station)} ({station})");
|
_sawmill.Info($"Adding grid {mapGrid} to station {Name(station)} ({station})");
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -420,10 +351,10 @@ public sealed class StationSystem : EntitySystem
|
|||||||
throw new ArgumentException("Tried to use a non-station entity as a station!", nameof(station));
|
throw new ArgumentException("Tried to use a non-station entity as a station!", nameof(station));
|
||||||
|
|
||||||
RemComp<StationMemberComponent>(mapGrid);
|
RemComp<StationMemberComponent>(mapGrid);
|
||||||
stationData.Grids.Remove(gridComponent.Owner);
|
stationData.Grids.Remove(mapGrid);
|
||||||
|
|
||||||
RaiseLocalEvent(station, new StationGridRemovedEvent(gridComponent.Owner), true);
|
RaiseLocalEvent(station, new StationGridRemovedEvent(mapGrid), true);
|
||||||
_sawmill.Info($"Removing grid {mapGrid}:{gridComponent.Owner} from station {Name(station)} ({station})");
|
_sawmill.Info($"Removing grid {mapGrid} from station {Name(station)} ({station})");
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -462,9 +393,7 @@ public sealed class StationSystem : EntitySystem
|
|||||||
if (!Resolve(station, ref stationData))
|
if (!Resolve(station, ref stationData))
|
||||||
throw new ArgumentException("Tried to use a non-station entity as a station!", nameof(station));
|
throw new ArgumentException("Tried to use a non-station entity as a station!", nameof(station));
|
||||||
|
|
||||||
// component shutdown will error if the station was not removed from _stations prior to deletion.
|
QueueDel(station);
|
||||||
_stations.Remove(station);
|
|
||||||
Del(station);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -501,6 +430,16 @@ public sealed class StationSystem : EntitySystem
|
|||||||
|
|
||||||
return CompOrNull<StationMemberComponent>(xform.GridUid)?.Station;
|
return CompOrNull<StationMemberComponent>(xform.GridUid)?.Station;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public List<EntityUid> GetStations()
|
||||||
|
{
|
||||||
|
return EntityQuery<StationDataComponent>().Select(x => x.Owner).ToList();
|
||||||
|
}
|
||||||
|
|
||||||
|
public HashSet<EntityUid> GetStationsSet()
|
||||||
|
{
|
||||||
|
return EntityQuery<StationDataComponent>().Select(x => x.Owner).ToHashSet();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
@@ -24,9 +24,9 @@ public sealed class AnomalySpawnRule : StationEventSystem<AnomalySpawnRuleCompon
|
|||||||
{
|
{
|
||||||
base.Started(uid, component, gameRule, args);
|
base.Started(uid, component, gameRule, args);
|
||||||
|
|
||||||
if (StationSystem.Stations.Count == 0)
|
if (!TryGetRandomStation(out var chosenStation))
|
||||||
return; // No stations
|
return;
|
||||||
var chosenStation = RobustRandom.Pick(StationSystem.Stations.ToList());
|
|
||||||
if (!TryComp<StationDataComponent>(chosenStation, out var stationData))
|
if (!TryComp<StationDataComponent>(chosenStation, out var stationData))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
|||||||
@@ -26,9 +26,8 @@ public sealed class BreakerFlipRule : StationEventSystem<BreakerFlipRuleComponen
|
|||||||
{
|
{
|
||||||
base.Started(uid, component, gameRule, args);
|
base.Started(uid, component, gameRule, args);
|
||||||
|
|
||||||
if (StationSystem.Stations.Count == 0)
|
if (!TryGetRandomStation(out var chosenStation))
|
||||||
return;
|
return;
|
||||||
var chosenStation = RobustRandom.Pick(StationSystem.Stations.ToList());
|
|
||||||
|
|
||||||
var stationApcs = new List<ApcComponent>();
|
var stationApcs = new List<ApcComponent>();
|
||||||
foreach (var (apc, transform) in EntityQuery<ApcComponent, TransformComponent>())
|
foreach (var (apc, transform) in EntityQuery<ApcComponent, TransformComponent>())
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
using System.Linq;
|
using System.Linq;
|
||||||
using Content.Server.GameTicking.Rules.Components;
|
using Content.Server.GameTicking.Rules.Components;
|
||||||
|
using Content.Server.Station.Components;
|
||||||
using Content.Server.Station.Systems;
|
using Content.Server.Station.Systems;
|
||||||
using Content.Server.StationEvents.Components;
|
using Content.Server.StationEvents.Components;
|
||||||
using JetBrains.Annotations;
|
using JetBrains.Annotations;
|
||||||
@@ -16,10 +17,13 @@ public sealed class BureaucraticErrorRule : StationEventSystem<BureaucraticError
|
|||||||
{
|
{
|
||||||
base.Started(uid, component, gameRule, args);
|
base.Started(uid, component, gameRule, args);
|
||||||
|
|
||||||
if (StationSystem.Stations.Count == 0)
|
if (!TryGetRandomStation(out var chosenStation, HasComp<StationJobsComponent>))
|
||||||
return; // No stations
|
return;
|
||||||
var chosenStation = RobustRandom.Pick(StationSystem.Stations.ToList());
|
|
||||||
var jobList = _stationJobs.GetJobs(chosenStation).Keys.ToList();
|
var jobList = _stationJobs.GetJobs(chosenStation.Value).Keys.ToList();
|
||||||
|
|
||||||
|
if (jobList.Count == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
var mod = GetSeverityModifier();
|
var mod = GetSeverityModifier();
|
||||||
|
|
||||||
@@ -28,12 +32,12 @@ public sealed class BureaucraticErrorRule : StationEventSystem<BureaucraticError
|
|||||||
if (RobustRandom.Prob(Math.Min(0.25f * MathF.Sqrt(mod), 1.0f)))
|
if (RobustRandom.Prob(Math.Min(0.25f * MathF.Sqrt(mod), 1.0f)))
|
||||||
{
|
{
|
||||||
var chosenJob = RobustRandom.PickAndTake(jobList);
|
var chosenJob = RobustRandom.PickAndTake(jobList);
|
||||||
_stationJobs.MakeJobUnlimited(chosenStation, chosenJob); // INFINITE chaos.
|
_stationJobs.MakeJobUnlimited(chosenStation.Value, chosenJob); // INFINITE chaos.
|
||||||
foreach (var job in jobList)
|
foreach (var job in jobList)
|
||||||
{
|
{
|
||||||
if (_stationJobs.IsJobUnlimited(chosenStation, job))
|
if (_stationJobs.IsJobUnlimited(chosenStation.Value, job))
|
||||||
continue;
|
continue;
|
||||||
_stationJobs.TrySetJobSlot(chosenStation, job, 0);
|
_stationJobs.TrySetJobSlot(chosenStation.Value, job, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -45,10 +49,10 @@ public sealed class BureaucraticErrorRule : StationEventSystem<BureaucraticError
|
|||||||
for (var i = 0; i < num; i++)
|
for (var i = 0; i < num; i++)
|
||||||
{
|
{
|
||||||
var chosenJob = RobustRandom.PickAndTake(jobList);
|
var chosenJob = RobustRandom.PickAndTake(jobList);
|
||||||
if (_stationJobs.IsJobUnlimited(chosenStation, chosenJob))
|
if (_stationJobs.IsJobUnlimited(chosenStation.Value, chosenJob))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
_stationJobs.TryAdjustJobSlot(chosenStation, chosenJob, RobustRandom.Next(-3, 6), clamp: true);
|
_stationJobs.TryAdjustJobSlot(chosenStation.Value, chosenJob, RobustRandom.Next(-3, 6), clamp: true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,8 +22,9 @@ namespace Content.Server.StationEvents.Events
|
|||||||
var mod = MathF.Sqrt(GetSeverityModifier());
|
var mod = MathF.Sqrt(GetSeverityModifier());
|
||||||
|
|
||||||
// Essentially we'll pick out a target amount of gas to leak, then a rate to leak it at, then work out the duration from there.
|
// Essentially we'll pick out a target amount of gas to leak, then a rate to leak it at, then work out the duration from there.
|
||||||
if (TryFindRandomTile(out component.TargetTile, out component.TargetStation, out component.TargetGrid, out component.TargetCoords))
|
if (TryFindRandomTile(out component.TargetTile, out var target, out component.TargetGrid, out component.TargetCoords))
|
||||||
{
|
{
|
||||||
|
component.TargetStation = target.Value;
|
||||||
component.FoundTile = true;
|
component.FoundTile = true;
|
||||||
|
|
||||||
component.LeakGas = RobustRandom.Pick(component.LeakableGases);
|
component.LeakGas = RobustRandom.Pick(component.LeakableGases);
|
||||||
|
|||||||
@@ -23,9 +23,8 @@ namespace Content.Server.StationEvents.Events
|
|||||||
{
|
{
|
||||||
base.Started(uid, component, gameRule, args);
|
base.Started(uid, component, gameRule, args);
|
||||||
|
|
||||||
if (StationSystem.Stations.Count == 0)
|
if (!TryGetRandomStation(out var chosenStation))
|
||||||
return;
|
return;
|
||||||
var chosenStation = RobustRandom.Pick(StationSystem.Stations.ToList());
|
|
||||||
|
|
||||||
foreach (var (apc, transform) in EntityQuery<ApcComponent, TransformComponent>(true))
|
foreach (var (apc, transform) in EntityQuery<ApcComponent, TransformComponent>(true))
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
using System.Diagnostics.CodeAnalysis;
|
||||||
|
using System.Linq;
|
||||||
using Content.Server.Administration.Logs;
|
using Content.Server.Administration.Logs;
|
||||||
using Content.Server.Atmos.EntitySystems;
|
using Content.Server.Atmos.EntitySystems;
|
||||||
using Content.Server.Chat.Systems;
|
using Content.Server.Chat.Systems;
|
||||||
@@ -131,19 +133,37 @@ public abstract class StationEventSystem<T> : GameRuleSystem<T> where T : Compon
|
|||||||
GameTicker.EndGameRule(uid, component);
|
GameTicker.EndGameRule(uid, component);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected bool TryFindRandomTile(out Vector2i tile, out EntityUid targetStation, out EntityUid targetGrid, out EntityCoordinates targetCoords)
|
protected bool TryGetRandomStation([NotNullWhen(true)] out EntityUid? station, Func<EntityUid, bool>? filter = null)
|
||||||
|
{
|
||||||
|
filter ??= _ => true;
|
||||||
|
|
||||||
|
// augh. sorry sloth there's no better API and my goal today isn't adding 50 entitymanager methods :waa:
|
||||||
|
var stations = EntityManager.GetAllComponents(typeof(StationEventEligibleComponent)).Select(x => x.Owner).Where(filter).ToArray();
|
||||||
|
|
||||||
|
if (stations.Length == 0)
|
||||||
|
{
|
||||||
|
station = null;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
station = RobustRandom.Pick(stations);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected bool TryFindRandomTile(out Vector2i tile, [NotNullWhen(true)] out EntityUid? targetStation, out EntityUid targetGrid, out EntityCoordinates targetCoords)
|
||||||
{
|
{
|
||||||
tile = default;
|
tile = default;
|
||||||
|
|
||||||
targetCoords = EntityCoordinates.Invalid;
|
targetCoords = EntityCoordinates.Invalid;
|
||||||
if (StationSystem.Stations.Count == 0)
|
if (!TryGetRandomStation(out targetStation))
|
||||||
{
|
{
|
||||||
targetStation = EntityUid.Invalid;
|
targetStation = EntityUid.Invalid;
|
||||||
targetGrid = EntityUid.Invalid;
|
targetGrid = EntityUid.Invalid;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
targetStation = RobustRandom.Pick(StationSystem.Stations);
|
var possibleTargets = Comp<StationDataComponent>(targetStation.Value).Grids;
|
||||||
var possibleTargets = Comp<StationDataComponent>(targetStation).Grids;
|
|
||||||
if (possibleTargets.Count == 0)
|
if (possibleTargets.Count == 0)
|
||||||
{
|
{
|
||||||
targetGrid = EntityUid.Invalid;
|
targetGrid = EntityUid.Invalid;
|
||||||
|
|||||||
@@ -22,9 +22,8 @@ public sealed class VentClogRule : StationEventSystem<VentClogRuleComponent>
|
|||||||
{
|
{
|
||||||
base.Started(uid, component, gameRule, args);
|
base.Started(uid, component, gameRule, args);
|
||||||
|
|
||||||
if (StationSystem.Stations.Count == 0)
|
if (!TryGetRandomStation(out var chosenStation))
|
||||||
return;
|
return;
|
||||||
var chosenStation = RobustRandom.Pick(StationSystem.Stations.ToList());
|
|
||||||
|
|
||||||
// TODO: "safe random" for chems. Right now this includes admin chemicals.
|
// TODO: "safe random" for chems. Right now this includes admin chemicals.
|
||||||
var allReagents = PrototypeManager.EnumeratePrototypes<ReagentPrototype>()
|
var allReagents = PrototypeManager.EnumeratePrototypes<ReagentPrototype>()
|
||||||
|
|||||||
@@ -44,17 +44,14 @@ public sealed class StationRecordsSystem : EntitySystem
|
|||||||
{
|
{
|
||||||
base.Initialize();
|
base.Initialize();
|
||||||
|
|
||||||
SubscribeLocalEvent<StationInitializedEvent>(OnStationInitialize);
|
|
||||||
SubscribeLocalEvent<PlayerSpawnCompleteEvent>(OnPlayerSpawn);
|
SubscribeLocalEvent<PlayerSpawnCompleteEvent>(OnPlayerSpawn);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnStationInitialize(StationInitializedEvent args)
|
|
||||||
{
|
|
||||||
AddComp<StationRecordsComponent>(args.Station);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnPlayerSpawn(PlayerSpawnCompleteEvent args)
|
private void OnPlayerSpawn(PlayerSpawnCompleteEvent args)
|
||||||
{
|
{
|
||||||
|
if (!HasComp<StationRecordsComponent>(args.Station))
|
||||||
|
return;
|
||||||
|
|
||||||
CreateGeneralRecord(args.Station, args.Mob, args.Profile, args.JobId);
|
CreateGeneralRecord(args.Station, args.Mob, args.Profile, args.JobId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -41,7 +41,7 @@ public sealed class BiomePrototype : IPrototype, IInheritingPrototype
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
[DataField("chunkComponents")]
|
[DataField("chunkComponents")]
|
||||||
[AlwaysPushInheritance]
|
[AlwaysPushInheritance]
|
||||||
public EntityPrototype.ComponentRegistry ChunkComponents { get; } = new();
|
public ComponentRegistry ChunkComponents { get; } = new();
|
||||||
|
|
||||||
//TODO: Get someone to make this a method on componentregistry that does it Correctly.
|
//TODO: Get someone to make this a method on componentregistry that does it Correctly.
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ public sealed class WorldgenConfigPrototype : IPrototype
|
|||||||
/// The components that get added to the target map.
|
/// The components that get added to the target map.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[DataField("components", required: true)]
|
[DataField("components", required: true)]
|
||||||
public EntityPrototype.ComponentRegistry Components { get; } = default!;
|
public ComponentRegistry Components { get; } = default!;
|
||||||
|
|
||||||
//TODO: Get someone to make this a method on componentregistry that does it Correctly.
|
//TODO: Get someone to make this a method on componentregistry that does it Correctly.
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
@@ -33,5 +33,5 @@ public sealed class RandomHumanoidSettingsPrototype : IPrototype, IInheritingPro
|
|||||||
/// Extra components to add to this entity.
|
/// Extra components to add to this entity.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[DataField("components")]
|
[DataField("components")]
|
||||||
public EntityPrototype.ComponentRegistry? Components { get; }
|
public ComponentRegistry? Components { get; }
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ public sealed class PayloadTriggerComponent : Component
|
|||||||
/// List of components to add or remove from an entity when this trigger is (un)installed.
|
/// List of components to add or remove from an entity when this trigger is (un)installed.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[DataField("components", serverOnly:true, readOnly: true)]
|
[DataField("components", serverOnly:true, readOnly: true)]
|
||||||
public readonly EntityPrototype.ComponentRegistry? Components = null;
|
public readonly ComponentRegistry? Components = null;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Keeps track of what components this trigger has granted to the payload case.
|
/// Keeps track of what components this trigger has granted to the payload case.
|
||||||
|
|||||||
@@ -21,13 +21,13 @@ public sealed class ArtifactEffectPrototype : IPrototype
|
|||||||
/// These are removed after the node is exited and the effect is changed.
|
/// These are removed after the node is exited and the effect is changed.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[DataField("components", serverOnly: true)]
|
[DataField("components", serverOnly: true)]
|
||||||
public EntityPrototype.ComponentRegistry Components = new();
|
public ComponentRegistry Components = new();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Components that are permanently added to an entity when the effect's node is entered.
|
/// Components that are permanently added to an entity when the effect's node is entered.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[DataField("permanentComponents")]
|
[DataField("permanentComponents")]
|
||||||
public EntityPrototype.ComponentRegistry PermanentComponents = new();
|
public ComponentRegistry PermanentComponents = new();
|
||||||
|
|
||||||
//TODO: make this a list so we can have multiple target depths
|
//TODO: make this a list so we can have multiple target depths
|
||||||
[DataField("targetDepth")]
|
[DataField("targetDepth")]
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ public sealed class ArtifactTriggerPrototype : IPrototype
|
|||||||
public string ID { get; } = default!;
|
public string ID { get; } = default!;
|
||||||
|
|
||||||
[DataField("components", serverOnly: true)]
|
[DataField("components", serverOnly: true)]
|
||||||
public EntityPrototype.ComponentRegistry Components = new();
|
public ComponentRegistry Components = new();
|
||||||
|
|
||||||
[DataField("targetDepth")]
|
[DataField("targetDepth")]
|
||||||
public int TargetDepth = 0;
|
public int TargetDepth = 0;
|
||||||
|
|||||||
57
Resources/Prototypes/Entities/Stations/base.yml
Normal file
57
Resources/Prototypes/Entities/Stations/base.yml
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
- type: entity
|
||||||
|
id: BaseStation
|
||||||
|
abstract: true
|
||||||
|
components:
|
||||||
|
- type: StationData
|
||||||
|
|
||||||
|
- type: entity
|
||||||
|
id: BaseStationCargo
|
||||||
|
abstract: true
|
||||||
|
components:
|
||||||
|
- type: StationBankAccount
|
||||||
|
- type: StationCargoOrderDatabase
|
||||||
|
|
||||||
|
- type: entity
|
||||||
|
id: BaseStationJobsSpawning
|
||||||
|
abstract: true
|
||||||
|
components:
|
||||||
|
- type: StationJobs
|
||||||
|
availableJobs: {}
|
||||||
|
- type: StationSpawning
|
||||||
|
|
||||||
|
- type: entity
|
||||||
|
id: BaseStationRecords
|
||||||
|
abstract: true
|
||||||
|
components:
|
||||||
|
- type: StationRecords
|
||||||
|
|
||||||
|
- type: entity
|
||||||
|
id: BaseStationArrivals
|
||||||
|
abstract: true
|
||||||
|
components:
|
||||||
|
- type: StationArrivals
|
||||||
|
|
||||||
|
- type: entity
|
||||||
|
id: BaseStationEvacuation
|
||||||
|
abstract: true
|
||||||
|
components:
|
||||||
|
- type: StationEmergencyShuttle
|
||||||
|
|
||||||
|
- type: entity
|
||||||
|
id: BaseStationAlertLevels
|
||||||
|
abstract: true
|
||||||
|
components:
|
||||||
|
- type: AlertLevel
|
||||||
|
alertLevelPrototype: stationAlerts
|
||||||
|
|
||||||
|
- type: entity
|
||||||
|
id: BaseStationExpeditions
|
||||||
|
abstract: true
|
||||||
|
components:
|
||||||
|
- type: SalvageExpeditionData
|
||||||
|
|
||||||
|
- type: entity
|
||||||
|
id: BaseStationAllEventsEligible
|
||||||
|
abstract: true
|
||||||
|
components:
|
||||||
|
- type: StationEventEligible # For when someone makes this more granular in the future.
|
||||||
33
Resources/Prototypes/Entities/Stations/nanotrasen.yml
Normal file
33
Resources/Prototypes/Entities/Stations/nanotrasen.yml
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
- type: entity
|
||||||
|
id: BaseStationNanotrasen
|
||||||
|
components:
|
||||||
|
- type: Faction
|
||||||
|
factions:
|
||||||
|
- NanoTrasen
|
||||||
|
|
||||||
|
- type: entity
|
||||||
|
id: StandardNanotrasenStation
|
||||||
|
parent:
|
||||||
|
- BaseStation
|
||||||
|
- BaseStationCargo
|
||||||
|
- BaseStationJobsSpawning
|
||||||
|
- BaseStationRecords
|
||||||
|
- BaseStationArrivals
|
||||||
|
- BaseStationEvacuation
|
||||||
|
- BaseStationAlertLevels
|
||||||
|
- BaseStationExpeditions
|
||||||
|
- BaseStationAllEventsEligible
|
||||||
|
- BaseStationNanotrasen
|
||||||
|
noSpawn: true
|
||||||
|
components:
|
||||||
|
- type: Transform
|
||||||
|
|
||||||
|
- type: entity
|
||||||
|
id: NanotrasenCentralCommand
|
||||||
|
parent:
|
||||||
|
- BaseStation
|
||||||
|
- BaseStationAlertLevels
|
||||||
|
- BaseStationNanotrasen
|
||||||
|
noSpawn: true
|
||||||
|
components:
|
||||||
|
- type: Transform
|
||||||
@@ -36,6 +36,7 @@
|
|||||||
noSpawn: true
|
noSpawn: true
|
||||||
components:
|
components:
|
||||||
- type: NukeopsRule
|
- type: NukeopsRule
|
||||||
|
faction: Syndicate
|
||||||
|
|
||||||
- type: entity
|
- type: entity
|
||||||
id: Pirates
|
id: Pirates
|
||||||
|
|||||||
@@ -6,11 +6,16 @@
|
|||||||
maxPlayers: 70
|
maxPlayers: 70
|
||||||
stations:
|
stations:
|
||||||
Aspid:
|
Aspid:
|
||||||
|
stationProto: StandardNanotrasenStation
|
||||||
|
components:
|
||||||
|
- type: StationNameSetup
|
||||||
mapNameTemplate: '{0} NCS Aspid {1}'
|
mapNameTemplate: '{0} NCS Aspid {1}'
|
||||||
emergencyShuttlePath: /Maps/Shuttles/emergency_courser.yml
|
|
||||||
nameGenerator:
|
nameGenerator:
|
||||||
!type:NanotrasenNameGenerator
|
!type:NanotrasenNameGenerator
|
||||||
prefixCreator: '14'
|
prefixCreator: '14'
|
||||||
|
- type: StationEmergencyShuttle
|
||||||
|
emergencyShuttlePath: /Maps/Shuttles/emergency_courser.yml
|
||||||
|
- type: StationJobs
|
||||||
overflowJobs:
|
overflowJobs:
|
||||||
- Passenger
|
- Passenger
|
||||||
availableJobs:
|
availableJobs:
|
||||||
|
|||||||
@@ -6,11 +6,16 @@
|
|||||||
maxPlayers: 75
|
maxPlayers: 75
|
||||||
stations:
|
stations:
|
||||||
Bagel:
|
Bagel:
|
||||||
|
stationProto: StandardNanotrasenStation
|
||||||
|
components:
|
||||||
|
- type: StationNameSetup
|
||||||
mapNameTemplate: '{0} Bagel Station {1}'
|
mapNameTemplate: '{0} Bagel Station {1}'
|
||||||
emergencyShuttlePath: /Maps/Shuttles/emergency_lox.yml
|
|
||||||
nameGenerator:
|
nameGenerator:
|
||||||
!type:NanotrasenNameGenerator
|
!type:NanotrasenNameGenerator
|
||||||
prefixCreator: '14'
|
prefixCreator: '14'
|
||||||
|
- type: StationEmergencyShuttle
|
||||||
|
emergencyShuttlePath: /Maps/Shuttles/emergency_lox.yml
|
||||||
|
- type: StationJobs
|
||||||
overflowJobs:
|
overflowJobs:
|
||||||
- Passenger
|
- Passenger
|
||||||
availableJobs:
|
availableJobs:
|
||||||
|
|||||||
@@ -6,11 +6,16 @@
|
|||||||
maxPlayers: 70
|
maxPlayers: 70
|
||||||
stations:
|
stations:
|
||||||
Barratry:
|
Barratry:
|
||||||
|
stationProto: StandardNanotrasenStation
|
||||||
|
components:
|
||||||
|
- type: StationNameSetup
|
||||||
mapNameTemplate: '{0} Barratry {1}'
|
mapNameTemplate: '{0} Barratry {1}'
|
||||||
emergencyShuttlePath: /Maps/Shuttles/emergency_raven.yml
|
|
||||||
nameGenerator:
|
nameGenerator:
|
||||||
!type:NanotrasenNameGenerator
|
!type:NanotrasenNameGenerator
|
||||||
prefixCreator: '14'
|
prefixCreator: '14'
|
||||||
|
- type: StationEmergencyShuttle
|
||||||
|
emergencyShuttlePath: /Maps/Shuttles/emergency_raven.yml
|
||||||
|
- type: StationJobs
|
||||||
overflowJobs:
|
overflowJobs:
|
||||||
- Passenger
|
- Passenger
|
||||||
availableJobs:
|
availableJobs:
|
||||||
|
|||||||
@@ -5,11 +5,16 @@
|
|||||||
minPlayers: 50
|
minPlayers: 50
|
||||||
stations:
|
stations:
|
||||||
Boxstation:
|
Boxstation:
|
||||||
|
stationProto: StandardNanotrasenStation
|
||||||
|
components:
|
||||||
|
- type: StationNameSetup
|
||||||
mapNameTemplate: '{0} Box Station {1}'
|
mapNameTemplate: '{0} Box Station {1}'
|
||||||
emergencyShuttlePath: /Maps/Shuttles/emergency_box.yml
|
|
||||||
nameGenerator:
|
nameGenerator:
|
||||||
!type:NanotrasenNameGenerator
|
!type:NanotrasenNameGenerator
|
||||||
prefixCreator: 'TG'
|
prefixCreator: 'TG'
|
||||||
|
- type: StationEmergencyShuttle
|
||||||
|
emergencyShuttlePath: /Maps/Shuttles/emergency_box.yml
|
||||||
|
- type: StationJobs
|
||||||
overflowJobs:
|
overflowJobs:
|
||||||
- Passenger
|
- Passenger
|
||||||
availableJobs:
|
availableJobs:
|
||||||
|
|||||||
@@ -5,11 +5,10 @@
|
|||||||
minPlayers: 10
|
minPlayers: 10
|
||||||
stations:
|
stations:
|
||||||
centcomm:
|
centcomm:
|
||||||
|
stationProto: NanotrasenCentralCommand
|
||||||
|
components:
|
||||||
|
- type: StationNameSetup
|
||||||
mapNameTemplate: '{0} Central Command {1}'
|
mapNameTemplate: '{0} Central Command {1}'
|
||||||
nameGenerator:
|
nameGenerator:
|
||||||
!type:NanotrasenNameGenerator
|
!type:NanotrasenNameGenerator
|
||||||
prefixCreator: 'TG'
|
prefixCreator: 'TG'
|
||||||
overflowJobs:
|
|
||||||
- Passenger
|
|
||||||
availableJobs:
|
|
||||||
Passenger: [ 0, 1 ]
|
|
||||||
|
|||||||
@@ -6,10 +6,14 @@
|
|||||||
maxPlayers: 35
|
maxPlayers: 35
|
||||||
stations:
|
stations:
|
||||||
Cluster:
|
Cluster:
|
||||||
|
stationProto: StandardNanotrasenStation
|
||||||
|
components:
|
||||||
|
- type: StationNameSetup
|
||||||
mapNameTemplate: '{0} Cluster Station {1}'
|
mapNameTemplate: '{0} Cluster Station {1}'
|
||||||
nameGenerator:
|
nameGenerator:
|
||||||
!type:NanotrasenNameGenerator
|
!type:NanotrasenNameGenerator
|
||||||
prefixCreator: '14'
|
prefixCreator: '14'
|
||||||
|
- type: StationJobs
|
||||||
overflowJobs:
|
overflowJobs:
|
||||||
- Passenger
|
- Passenger
|
||||||
availableJobs:
|
availableJobs:
|
||||||
|
|||||||
@@ -5,7 +5,11 @@
|
|||||||
minPlayers: 0
|
minPlayers: 0
|
||||||
stations:
|
stations:
|
||||||
Empty:
|
Empty:
|
||||||
|
stationProto: StandardNanotrasenStation
|
||||||
|
components:
|
||||||
|
- type: StationNameSetup
|
||||||
mapNameTemplate: "Empty"
|
mapNameTemplate: "Empty"
|
||||||
|
- type: StationJobs
|
||||||
overflowJobs:
|
overflowJobs:
|
||||||
- Passenger
|
- Passenger
|
||||||
availableJobs:
|
availableJobs:
|
||||||
@@ -18,7 +22,11 @@
|
|||||||
minPlayers: 0
|
minPlayers: 0
|
||||||
stations:
|
stations:
|
||||||
Dev:
|
Dev:
|
||||||
|
stationProto: StandardNanotrasenStation
|
||||||
|
components:
|
||||||
|
- type: StationNameSetup
|
||||||
mapNameTemplate: "Dev"
|
mapNameTemplate: "Dev"
|
||||||
|
- type: StationJobs
|
||||||
overflowJobs:
|
overflowJobs:
|
||||||
- Captain
|
- Captain
|
||||||
availableJobs:
|
availableJobs:
|
||||||
|
|||||||
@@ -5,11 +5,16 @@
|
|||||||
minPlayers: 70
|
minPlayers: 70
|
||||||
stations:
|
stations:
|
||||||
Fland:
|
Fland:
|
||||||
|
stationProto: StandardNanotrasenStation
|
||||||
|
components:
|
||||||
|
- type: StationNameSetup
|
||||||
mapNameTemplate: '{0} Fland Installation {1}'
|
mapNameTemplate: '{0} Fland Installation {1}'
|
||||||
emergencyShuttlePath: /Maps/Shuttles/emergency_courser.yml
|
|
||||||
nameGenerator:
|
nameGenerator:
|
||||||
!type:NanotrasenNameGenerator
|
!type:NanotrasenNameGenerator
|
||||||
prefixCreator: 'B'
|
prefixCreator: 'B'
|
||||||
|
- type: StationEmergencyShuttle
|
||||||
|
emergencyShuttlePath: /Maps/Shuttles/emergency_courser.yml
|
||||||
|
- type: StationJobs
|
||||||
overflowJobs:
|
overflowJobs:
|
||||||
- Passenger
|
- Passenger
|
||||||
availableJobs:
|
availableJobs:
|
||||||
|
|||||||
@@ -1,14 +0,0 @@
|
|||||||
- type: gameMap
|
|
||||||
id: Infiltrator
|
|
||||||
mapName: 'Syndicate Infiltrator'
|
|
||||||
mapPath: /Maps/infiltrator.yml
|
|
||||||
minPlayers: 0
|
|
||||||
stations:
|
|
||||||
Station: #TODO: Mapper, add a BecomesStation component to the primary grid of the map.
|
|
||||||
mapNameTemplate: '{0} Infiltrator {1}'
|
|
||||||
nameGenerator:
|
|
||||||
!type:NanotrasenNameGenerator
|
|
||||||
prefixCreator: '14'
|
|
||||||
overflowJobs: []
|
|
||||||
availableJobs:
|
|
||||||
Captain: [ 1, 1 ]
|
|
||||||
@@ -5,11 +5,16 @@
|
|||||||
minPlayers: 35
|
minPlayers: 35
|
||||||
stations:
|
stations:
|
||||||
Kettle:
|
Kettle:
|
||||||
|
stationProto: StandardNanotrasenStation
|
||||||
|
components:
|
||||||
|
- type: StationNameSetup
|
||||||
mapNameTemplate: '{0} Kettle {1}'
|
mapNameTemplate: '{0} Kettle {1}'
|
||||||
emergencyShuttlePath: /Maps/Shuttles/emergency_courser.yml
|
|
||||||
nameGenerator:
|
nameGenerator:
|
||||||
!type:NanotrasenNameGenerator
|
!type:NanotrasenNameGenerator
|
||||||
prefixCreator: '14'
|
prefixCreator: '14'
|
||||||
|
- type: StationEmergencyShuttle
|
||||||
|
emergencyShuttlePath: /Maps/Shuttles/emergency_courser.yml
|
||||||
|
- type: StationJobs
|
||||||
overflowJobs:
|
overflowJobs:
|
||||||
- Passenger
|
- Passenger
|
||||||
availableJobs:
|
availableJobs:
|
||||||
|
|||||||
@@ -6,11 +6,16 @@
|
|||||||
maxPlayers: 70
|
maxPlayers: 70
|
||||||
stations:
|
stations:
|
||||||
Marathon:
|
Marathon:
|
||||||
|
stationProto: StandardNanotrasenStation
|
||||||
|
components:
|
||||||
|
- type: StationNameSetup
|
||||||
mapNameTemplate: '{0} Marathon Station {1}'
|
mapNameTemplate: '{0} Marathon Station {1}'
|
||||||
emergencyShuttlePath: /Maps/Shuttles/emergency_courser.yml
|
|
||||||
nameGenerator:
|
nameGenerator:
|
||||||
!type:NanotrasenNameGenerator
|
!type:NanotrasenNameGenerator
|
||||||
prefixCreator: '14'
|
prefixCreator: '14'
|
||||||
|
- type: StationEmergencyShuttle
|
||||||
|
emergencyShuttlePath: /Maps/Shuttles/emergency_courser.yml
|
||||||
|
- type: StationJobs
|
||||||
overflowJobs:
|
overflowJobs:
|
||||||
- Passenger
|
- Passenger
|
||||||
availableJobs:
|
availableJobs:
|
||||||
|
|||||||
@@ -5,11 +5,16 @@
|
|||||||
minPlayers: 50
|
minPlayers: 50
|
||||||
stations:
|
stations:
|
||||||
Meta:
|
Meta:
|
||||||
|
stationProto: StandardNanotrasenStation
|
||||||
|
components:
|
||||||
|
- type: StationNameSetup
|
||||||
mapNameTemplate: '{0} Meta Station {1}'
|
mapNameTemplate: '{0} Meta Station {1}'
|
||||||
emergencyShuttlePath: /Maps/Shuttles/emergency_courser.yml
|
|
||||||
nameGenerator:
|
nameGenerator:
|
||||||
!type:NanotrasenNameGenerator
|
!type:NanotrasenNameGenerator
|
||||||
prefixCreator: 'TG'
|
prefixCreator: 'TG'
|
||||||
|
- type: StationEmergencyShuttle
|
||||||
|
emergencyShuttlePath: /Maps/Shuttles/emergency_courser.yml
|
||||||
|
- type: StationJobs
|
||||||
overflowJobs:
|
overflowJobs:
|
||||||
- Passenger
|
- Passenger
|
||||||
availableJobs:
|
availableJobs:
|
||||||
|
|||||||
@@ -7,10 +7,14 @@
|
|||||||
fallback: true
|
fallback: true
|
||||||
stations:
|
stations:
|
||||||
Moose:
|
Moose:
|
||||||
|
stationProto: StandardNanotrasenStation
|
||||||
|
components:
|
||||||
|
- type: StationNameSetup
|
||||||
mapNameTemplate: '{0} Moose {1}'
|
mapNameTemplate: '{0} Moose {1}'
|
||||||
nameGenerator:
|
nameGenerator:
|
||||||
!type:NanotrasenNameGenerator
|
!type:NanotrasenNameGenerator
|
||||||
prefixCreator: '14'
|
prefixCreator: '14'
|
||||||
|
- type: StationJobs
|
||||||
overflowJobs:
|
overflowJobs:
|
||||||
- Passenger
|
- Passenger
|
||||||
availableJobs:
|
availableJobs:
|
||||||
|
|||||||
@@ -6,10 +6,14 @@
|
|||||||
maxPlayers: 35
|
maxPlayers: 35
|
||||||
stations:
|
stations:
|
||||||
Omega:
|
Omega:
|
||||||
|
stationProto: StandardNanotrasenStation
|
||||||
|
components:
|
||||||
|
- type: StationNameSetup
|
||||||
mapNameTemplate: '{0} Omega Station {1}'
|
mapNameTemplate: '{0} Omega Station {1}'
|
||||||
nameGenerator:
|
nameGenerator:
|
||||||
!type:NanotrasenNameGenerator
|
!type:NanotrasenNameGenerator
|
||||||
prefixCreator: 'TG'
|
prefixCreator: 'TG'
|
||||||
|
- type: StationJobs
|
||||||
overflowJobs:
|
overflowJobs:
|
||||||
- Passenger
|
- Passenger
|
||||||
availableJobs:
|
availableJobs:
|
||||||
|
|||||||
@@ -5,11 +5,16 @@
|
|||||||
minPlayers: 50
|
minPlayers: 50
|
||||||
stations:
|
stations:
|
||||||
Origin:
|
Origin:
|
||||||
|
stationProto: StandardNanotrasenStation
|
||||||
|
components:
|
||||||
|
- type: StationNameSetup
|
||||||
mapNameTemplate: '{0} Origin {1}'
|
mapNameTemplate: '{0} Origin {1}'
|
||||||
emergencyShuttlePath: /Maps/Shuttles/emergency_courser.yml
|
|
||||||
nameGenerator:
|
nameGenerator:
|
||||||
!type:NanotrasenNameGenerator
|
!type:NanotrasenNameGenerator
|
||||||
prefixCreator: '14'
|
prefixCreator: '14'
|
||||||
|
- type: StationEmergencyShuttle
|
||||||
|
emergencyShuttlePath: /Maps/Shuttles/emergency_courser.yml
|
||||||
|
- type: StationJobs
|
||||||
overflowJobs:
|
overflowJobs:
|
||||||
- Passenger
|
- Passenger
|
||||||
availableJobs:
|
availableJobs:
|
||||||
|
|||||||
@@ -7,10 +7,14 @@
|
|||||||
fallback: true
|
fallback: true
|
||||||
stations:
|
stations:
|
||||||
Saltern:
|
Saltern:
|
||||||
|
stationProto: StandardNanotrasenStation
|
||||||
|
components:
|
||||||
|
- type: StationNameSetup
|
||||||
mapNameTemplate: '{0} Saltern {1}'
|
mapNameTemplate: '{0} Saltern {1}'
|
||||||
nameGenerator:
|
nameGenerator:
|
||||||
!type:NanotrasenNameGenerator
|
!type:NanotrasenNameGenerator
|
||||||
prefixCreator: '14'
|
prefixCreator: '14'
|
||||||
|
- type: StationJobs
|
||||||
overflowJobs:
|
overflowJobs:
|
||||||
- Passenger
|
- Passenger
|
||||||
availableJobs:
|
availableJobs:
|
||||||
|
|||||||
Submodule RobustToolbox updated: 57ddf81fc4...7836130bef
Reference in New Issue
Block a user