Escape pods (#14809)
* Namespace adjustments for days * pod * thanks rider * Fix the oop launch * Fixes * Fix stuff * eeeeeeeee * Fix * access * map * forgor * thing * Genericise escape pod fill
This commit is contained in:
@@ -225,7 +225,7 @@ namespace Content.IntegrationTests.Tests
|
||||
Assert.IsNotNull(stationConfig, $"{entManager.ToPrettyString(station)} had null StationConfig.");
|
||||
var shuttlePath = stationConfig.EmergencyShuttlePath.ToString();
|
||||
var shuttle = mapLoader.LoadGrid(shuttleMap, shuttlePath);
|
||||
Assert.That(shuttle != null && shuttleSystem.TryFTLDock(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);
|
||||
|
||||
|
||||
@@ -30,10 +30,10 @@ namespace Content.Server.Communications
|
||||
[Dependency] private readonly InteractionSystem _interaction = default!;
|
||||
[Dependency] private readonly AlertLevelSystem _alertLevelSystem = default!;
|
||||
[Dependency] private readonly ChatSystem _chatSystem = default!;
|
||||
[Dependency] private readonly EmergencyShuttleSystem _emergency = default!;
|
||||
[Dependency] private readonly IdCardSystem _idCardSystem = default!;
|
||||
[Dependency] private readonly PopupSystem _popupSystem = default!;
|
||||
[Dependency] private readonly RoundEndSystem _roundEndSystem = default!;
|
||||
[Dependency] private readonly ShuttleSystem _shuttle = default!;
|
||||
[Dependency] private readonly StationSystem _stationSystem = default!;
|
||||
[Dependency] private readonly IConfigurationManager _cfg = default!;
|
||||
[Dependency] private readonly IAdminLogManager _adminLogger = default!;
|
||||
@@ -186,7 +186,7 @@ namespace Content.Server.Communications
|
||||
private bool CanCallOrRecall(CommunicationsConsoleComponent comp)
|
||||
{
|
||||
// Defer to what the round end system thinks we should be able to do.
|
||||
if (_shuttle.EmergencyShuttleArrived || !_roundEndSystem.CanCallOrRecall())
|
||||
if (_emergency.EmergencyShuttleArrived || !_roundEndSystem.CanCallOrRecall())
|
||||
return false;
|
||||
|
||||
// Calling shuttle checks
|
||||
|
||||
@@ -43,15 +43,16 @@ public sealed class NukeopsRuleSystem : GameRuleSystem
|
||||
[Dependency] private readonly IChatManager _chatManager = default!;
|
||||
[Dependency] private readonly IMapManager _mapManager = default!;
|
||||
[Dependency] private readonly IPlayerManager _playerSystem = default!;
|
||||
[Dependency] private readonly EmergencyShuttleSystem _emergency = default!;
|
||||
[Dependency] private readonly FactionSystem _faction = default!;
|
||||
[Dependency] private readonly HumanoidAppearanceSystem _humanoidSystem = default!;
|
||||
[Dependency] private readonly StationSpawningSystem _stationSpawningSystem = default!;
|
||||
[Dependency] private readonly StationSystem _stationSystem = default!;
|
||||
[Dependency] private readonly ShuttleSystem _shuttleSystem = default!;
|
||||
[Dependency] private readonly RoundEndSystem _roundEndSystem = default!;
|
||||
[Dependency] private readonly SharedAudioSystem _audioSystem = default!;
|
||||
[Dependency] private readonly GameTicker _ticker = default!;
|
||||
[Dependency] private readonly MapLoaderSystem _map = default!;
|
||||
[Dependency] private readonly ShuttleSystem _shuttle = default!;
|
||||
|
||||
|
||||
private enum WinType
|
||||
@@ -277,7 +278,7 @@ public sealed class NukeopsRuleSystem : GameRuleSystem
|
||||
}
|
||||
|
||||
// UH OH
|
||||
if (nukeTransform.MapID == _shuttleSystem.CentComMap)
|
||||
if (nukeTransform.MapID == _emergency.CentComMap)
|
||||
{
|
||||
_winConditions.Add(WinCondition.NukeActiveAtCentCom);
|
||||
RuleWinType = WinType.OpsMajor;
|
||||
@@ -334,7 +335,7 @@ public sealed class NukeopsRuleSystem : GameRuleSystem
|
||||
foreach (var (_, transform) in EntityManager.EntityQuery<NukeDiskComponent, TransformComponent>())
|
||||
{
|
||||
var diskMapId = transform.MapID;
|
||||
diskAtCentCom = _shuttleSystem.CentComMap == diskMapId;
|
||||
diskAtCentCom = _emergency.CentComMap == diskMapId;
|
||||
|
||||
// TODO: The target station should be stored, and the nuke disk should store its original station.
|
||||
// This is fine for now, because we can assume a single station in base SS14.
|
||||
@@ -655,7 +656,7 @@ public sealed class NukeopsRuleSystem : GameRuleSystem
|
||||
|
||||
if (TryComp<ShuttleComponent>(shuttleId, out var shuttle))
|
||||
{
|
||||
_shuttleSystem.TryFTLDock(shuttle, _nukieOutpost.Value);
|
||||
_shuttle.TryFTLDock(shuttleId, shuttle, _nukieOutpost.Value);
|
||||
}
|
||||
|
||||
_nukiePlanet = mapId;
|
||||
|
||||
@@ -32,7 +32,7 @@ namespace Content.Server.RoundEnd
|
||||
[Dependency] private readonly IPrototypeManager _protoManager = default!;
|
||||
[Dependency] private readonly ChatSystem _chatSystem = default!;
|
||||
[Dependency] private readonly GameTicker _gameTicker = default!;
|
||||
[Dependency] private readonly ShuttleSystem _shuttle = default!;
|
||||
[Dependency] private readonly EmergencyShuttleSystem _shuttle = default!;
|
||||
[Dependency] private readonly StationSystem _stationSystem = default!;
|
||||
|
||||
public TimeSpan DefaultCooldownDuration { get; set; } = TimeSpan.FromSeconds(30);
|
||||
|
||||
@@ -11,12 +11,15 @@ namespace Content.Server.Shuttles.Commands;
|
||||
[AdminCommand(AdminFlags.Fun)]
|
||||
public sealed class DelayRoundEndCommand : IConsoleCommand
|
||||
{
|
||||
[Dependency] private readonly IEntitySystemManager _sysManager = default!;
|
||||
|
||||
public string Command => "delayroundend";
|
||||
public string Description => Loc.GetString("emergency-shuttle-command-round-desc");
|
||||
public string Help => $"{Command}";
|
||||
public void Execute(IConsoleShell shell, string argStr, string[] args)
|
||||
{
|
||||
var system = IoCManager.Resolve<IEntitySystemManager>().GetEntitySystem<ShuttleSystem>();
|
||||
var system = _sysManager.GetEntitySystem<EmergencyShuttleSystem>();
|
||||
|
||||
if (system.DelayEmergencyRoundEnd())
|
||||
{
|
||||
shell.WriteLine(Loc.GetString("emergency-shuttle-command-round-yes"));
|
||||
|
||||
@@ -4,7 +4,7 @@ using Content.Server.Shuttles.Systems;
|
||||
using Content.Shared.Administration;
|
||||
using Robust.Shared.Console;
|
||||
|
||||
namespace Content.Server.Shuttles;
|
||||
namespace Content.Server.Shuttles.Commands;
|
||||
|
||||
[AdminCommand(AdminFlags.Mapping)]
|
||||
public sealed class DockCommand : IConsoleCommand
|
||||
@@ -11,12 +11,14 @@ namespace Content.Server.Shuttles.Commands;
|
||||
[AdminCommand(AdminFlags.Fun)]
|
||||
public sealed class DockEmergencyShuttleCommand : IConsoleCommand
|
||||
{
|
||||
[Dependency] private readonly IEntitySystemManager _sysManager = default!;
|
||||
|
||||
public string Command => "dockemergencyshuttle";
|
||||
public string Description => Loc.GetString("emergency-shuttle-command-dock-desc");
|
||||
public string Help => $"{Command}";
|
||||
public void Execute(IConsoleShell shell, string argStr, string[] args)
|
||||
{
|
||||
var system = IoCManager.Resolve<IEntitySystemManager>().GetEntitySystem<ShuttleSystem>();
|
||||
var system = _sysManager.GetEntitySystem<EmergencyShuttleSystem>();
|
||||
system.CallEmergencyShuttle();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,12 +11,14 @@ namespace Content.Server.Shuttles.Commands;
|
||||
[AdminCommand(AdminFlags.Fun)]
|
||||
public sealed class LaunchEmergencyShuttleCommand : IConsoleCommand
|
||||
{
|
||||
[Dependency] private readonly IEntitySystemManager _sysManager = default!;
|
||||
|
||||
public string Command => "launchemergencyshuttle";
|
||||
public string Description => Loc.GetString("emergency-shuttle-command-launch-desc");
|
||||
public string Help => $"{Command}";
|
||||
public void Execute(IConsoleShell shell, string argStr, string[] args)
|
||||
{
|
||||
var system = IoCManager.Resolve<IEntitySystemManager>().GetEntitySystem<ShuttleSystem>();
|
||||
var system = _sysManager.GetEntitySystem<EmergencyShuttleSystem>();
|
||||
system.EarlyLaunch();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
using Content.Server.Shuttles.Systems;
|
||||
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom;
|
||||
|
||||
namespace Content.Server.Shuttles.Components;
|
||||
|
||||
[RegisterComponent]
|
||||
[RegisterComponent, Access(typeof(ArrivalsSystem))]
|
||||
public sealed class ArrivalsShuttleComponent : Component
|
||||
{
|
||||
[DataField("station")]
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
using Content.Server.Shuttles.Systems;
|
||||
|
||||
namespace Content.Server.Shuttles.Components;
|
||||
|
||||
/// <summary>
|
||||
/// Added to a designated arrivals station for players to spawn at, if enabled.
|
||||
/// </summary>
|
||||
[RegisterComponent]
|
||||
[RegisterComponent, Access(typeof(ArrivalsSystem))]
|
||||
public sealed class ArrivalsSourceComponent : Component
|
||||
{
|
||||
|
||||
|
||||
14
Content.Server/Shuttles/Components/EscapePodComponent.cs
Normal file
14
Content.Server/Shuttles/Components/EscapePodComponent.cs
Normal file
@@ -0,0 +1,14 @@
|
||||
using Content.Server.Shuttles.Systems;
|
||||
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom;
|
||||
|
||||
namespace Content.Server.Shuttles.Components;
|
||||
|
||||
/// <summary>
|
||||
/// If added to a grid gets launched when the emergency shuttle launches.
|
||||
/// </summary>
|
||||
[RegisterComponent, Access(typeof(EmergencyShuttleSystem))]
|
||||
public sealed class EscapePodComponent : Component
|
||||
{
|
||||
[DataField("launchTime", customTypeSerializer:typeof(TimeOffsetSerializer))]
|
||||
public TimeSpan? LaunchTime;
|
||||
}
|
||||
13
Content.Server/Shuttles/Components/GridFillComponent.cs
Normal file
13
Content.Server/Shuttles/Components/GridFillComponent.cs
Normal file
@@ -0,0 +1,13 @@
|
||||
using Content.Server.Shuttles.Systems;
|
||||
using Robust.Shared.Utility;
|
||||
|
||||
namespace Content.Server.Shuttles.Components;
|
||||
|
||||
/// <summary>
|
||||
/// If added to an airlock will try to autofill a grid onto it on MapInit
|
||||
/// </summary>
|
||||
[RegisterComponent, Access(typeof(ShuttleSystem))]
|
||||
public sealed class GridFillComponent : Component
|
||||
{
|
||||
[DataField("path")] public ResourcePath Path = new("/Maps/Shuttles/escape_pod_small.yml");
|
||||
}
|
||||
@@ -1,3 +1,4 @@
|
||||
using Content.Server.Shuttles.Systems;
|
||||
using Robust.Shared.Utility;
|
||||
|
||||
namespace Content.Server.Shuttles.Components;
|
||||
@@ -5,7 +6,7 @@ namespace Content.Server.Shuttles.Components;
|
||||
/// <summary>
|
||||
/// Added to a station that is available for arrivals shuttles.
|
||||
/// </summary>
|
||||
[RegisterComponent]
|
||||
[RegisterComponent, Access(typeof(ArrivalsSystem))]
|
||||
public sealed class StationArrivalsComponent : Component
|
||||
{
|
||||
[DataField("shuttle")]
|
||||
|
||||
28
Content.Server/Shuttles/DockingConfig.cs
Normal file
28
Content.Server/Shuttles/DockingConfig.cs
Normal file
@@ -0,0 +1,28 @@
|
||||
using Content.Server.Shuttles.Components;
|
||||
using Robust.Shared.Map;
|
||||
|
||||
namespace Content.Server.Shuttles;
|
||||
|
||||
/// <summary>
|
||||
/// Stores the data for a valid docking configuration for the emergency shuttle
|
||||
/// </summary>
|
||||
public sealed class DockingConfig
|
||||
{
|
||||
/// <summary>
|
||||
/// The pairs of docks that can connect.
|
||||
/// </summary>
|
||||
public List<(EntityUid DockAUid, EntityUid DockBUid, DockingComponent DockA, DockingComponent DockB)> Docks = new();
|
||||
|
||||
/// <summary>
|
||||
/// Area relative to the target grid the emergency shuttle will spawn in on.
|
||||
/// </summary>
|
||||
public Box2 Area;
|
||||
|
||||
/// <summary>
|
||||
/// Target grid for docking.
|
||||
/// </summary>
|
||||
public EntityUid TargetGrid;
|
||||
|
||||
public EntityCoordinates Coordinates;
|
||||
public Angle Angle;
|
||||
}
|
||||
@@ -280,7 +280,7 @@ public sealed class ArrivalsSystem : EntitySystem
|
||||
// TODO: Need some kind of comp to shunt people off if they try to get on?
|
||||
if (TryComp<TransformComponent>(arrivals, out var arrivalsXform))
|
||||
{
|
||||
while (query.MoveNext(out var comp, out var shuttle, out var xform))
|
||||
while (query.MoveNext(out var uid, out var comp, out var shuttle, out var xform))
|
||||
{
|
||||
if (comp.NextTransfer > curTime || !TryComp<StationDataComponent>(comp.Station, out var data))
|
||||
continue;
|
||||
@@ -289,7 +289,7 @@ public sealed class ArrivalsSystem : EntitySystem
|
||||
if (xform.MapUid != arrivalsXform.MapUid)
|
||||
{
|
||||
if (arrivals.IsValid())
|
||||
_shuttles.FTLTravel(shuttle, arrivals, dock: true);
|
||||
_shuttles.FTLTravel(uid, shuttle, arrivals, dock: true);
|
||||
}
|
||||
// Go to station
|
||||
else
|
||||
@@ -297,7 +297,7 @@ public sealed class ArrivalsSystem : EntitySystem
|
||||
var targetGrid = _station.GetLargestGrid(data);
|
||||
|
||||
if (targetGrid != null)
|
||||
_shuttles.FTLTravel(shuttle, targetGrid.Value, dock: true);
|
||||
_shuttles.FTLTravel(uid, shuttle, targetGrid.Value, dock: true);
|
||||
}
|
||||
|
||||
comp.NextTransfer += TimeSpan.FromSeconds(_cfgManager.GetCVar(CCVars.ArrivalsCooldown));
|
||||
@@ -395,7 +395,7 @@ public sealed class ArrivalsSystem : EntitySystem
|
||||
var arrivalsComp = EnsureComp<ArrivalsShuttleComponent>(component.Shuttle);
|
||||
arrivalsComp.Station = uid;
|
||||
EnsureComp<ProtectedGridComponent>(uid);
|
||||
_shuttles.FTLTravel(shuttleComp, arrivals, hyperspaceTime: 10f, dock: true);
|
||||
_shuttles.FTLTravel(component.Shuttle, shuttleComp, arrivals, hyperspaceTime: 10f, dock: true);
|
||||
arrivalsComp.NextTransfer = _timing.CurTime + TimeSpan.FromSeconds(_cfgManager.GetCVar(CCVars.ArrivalsCooldown));
|
||||
}
|
||||
|
||||
|
||||
@@ -56,8 +56,8 @@ public sealed partial class DockingSystem
|
||||
continue;
|
||||
}
|
||||
|
||||
var worldPos = _transformSystem.GetWorldPosition(xform, xformQuery);
|
||||
var otherWorldPos = _transformSystem.GetWorldPosition(otherXform, xformQuery);
|
||||
var worldPos = _transform.GetWorldPosition(xform, xformQuery);
|
||||
var otherWorldPos = _transform.GetWorldPosition(otherXform, xformQuery);
|
||||
|
||||
if ((worldPos - otherWorldPos).Length < comp.Radius) continue;
|
||||
|
||||
|
||||
267
Content.Server/Shuttles/Systems/DockingSystem.Shuttle.cs
Normal file
267
Content.Server/Shuttles/Systems/DockingSystem.Shuttle.cs
Normal file
@@ -0,0 +1,267 @@
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Linq;
|
||||
using Content.Server.Shuttles.Components;
|
||||
using Robust.Shared.Map;
|
||||
using Robust.Shared.Map.Components;
|
||||
using Robust.Shared.Physics;
|
||||
using Robust.Shared.Physics.Components;
|
||||
|
||||
namespace Content.Server.Shuttles.Systems;
|
||||
|
||||
public sealed partial class DockingSystem
|
||||
{
|
||||
/*
|
||||
* Handles the shuttle side of FTL docking.
|
||||
*/
|
||||
|
||||
public Angle GetAngle(EntityUid uid, TransformComponent xform, EntityUid targetUid, TransformComponent targetXform, EntityQuery<TransformComponent> xformQuery)
|
||||
{
|
||||
var (shuttlePos, shuttleRot) = _transform.GetWorldPositionRotation(xform, xformQuery);
|
||||
var (targetPos, targetRot) = _transform.GetWorldPositionRotation(targetXform, xformQuery);
|
||||
|
||||
var shuttleCOM = Robust.Shared.Physics.Transform.Mul(new Transform(shuttlePos, shuttleRot),
|
||||
Comp<PhysicsComponent>(uid).LocalCenter);
|
||||
var targetCOM = Robust.Shared.Physics.Transform.Mul(new Transform(targetPos, targetRot),
|
||||
Comp<PhysicsComponent>(targetUid).LocalCenter);
|
||||
|
||||
var mapDiff = shuttleCOM - targetCOM;
|
||||
var angle = mapDiff.ToWorldAngle();
|
||||
angle -= targetRot;
|
||||
return angle;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks if 2 docks can be connected by moving the shuttle directly onto docks.
|
||||
/// </summary>
|
||||
public bool CanDock(
|
||||
DockingComponent shuttleDock,
|
||||
TransformComponent shuttleDockXform,
|
||||
DockingComponent gridDock,
|
||||
TransformComponent gridDockXform,
|
||||
Angle targetGridRotation,
|
||||
Box2 shuttleAABB,
|
||||
MapGridComponent grid,
|
||||
[NotNullWhen(true)] out Box2? shuttleDockedAABB,
|
||||
out Matrix3 matty,
|
||||
out Angle gridRotation)
|
||||
{
|
||||
gridRotation = Angle.Zero;
|
||||
matty = Matrix3.Identity;
|
||||
shuttleDockedAABB = null;
|
||||
|
||||
if (shuttleDock.Docked ||
|
||||
gridDock.Docked ||
|
||||
!shuttleDockXform.Anchored ||
|
||||
!gridDockXform.Anchored)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// First, get the station dock's position relative to the shuttle, this is where we rotate it around
|
||||
var stationDockPos = shuttleDockXform.LocalPosition +
|
||||
shuttleDockXform.LocalRotation.RotateVec(new Vector2(0f, -1f));
|
||||
|
||||
// Need to invert the grid's angle.
|
||||
var shuttleDockAngle = shuttleDockXform.LocalRotation;
|
||||
var gridDockAngle = gridDockXform.LocalRotation.Opposite();
|
||||
|
||||
var stationDockMatrix = Matrix3.CreateInverseTransform(stationDockPos, shuttleDockAngle);
|
||||
var gridXformMatrix = Matrix3.CreateTransform(gridDockXform.LocalPosition, gridDockAngle);
|
||||
Matrix3.Multiply(in stationDockMatrix, in gridXformMatrix, out matty);
|
||||
shuttleDockedAABB = matty.TransformBox(shuttleAABB);
|
||||
// Rounding moment
|
||||
shuttleDockedAABB = shuttleDockedAABB.Value.Enlarged(-0.01f);
|
||||
|
||||
if (!ValidSpawn(grid, shuttleDockedAABB.Value))
|
||||
return false;
|
||||
|
||||
gridRotation = targetGridRotation + gridDockAngle - shuttleDockAngle;
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets docking config between 2 specific docks.
|
||||
/// </summary>
|
||||
public DockingConfig? GetDockingConfig(
|
||||
EntityUid shuttleUid,
|
||||
EntityUid targetGrid,
|
||||
EntityUid shuttleDockUid,
|
||||
DockingComponent shuttleDock,
|
||||
EntityUid gridDockUid,
|
||||
DockingComponent gridDock)
|
||||
{
|
||||
var shuttleDocks = new List<(EntityUid, DockingComponent)>(1)
|
||||
{
|
||||
(shuttleDockUid, shuttleDock)
|
||||
};
|
||||
|
||||
var gridDocks = new List<(EntityUid, DockingComponent)>(1)
|
||||
{
|
||||
(gridDockUid, gridDock)
|
||||
};
|
||||
|
||||
return GetDockingConfigPrivate(shuttleUid, targetGrid, shuttleDocks, gridDocks);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tries to get a valid docking configuration for the shuttle to the target grid.
|
||||
/// </summary>
|
||||
/// <param name="priorityTag">Priority docking tag to prefer, e.g. for emergency shuttle</param>
|
||||
public DockingConfig? GetDockingConfig(EntityUid shuttleUid, EntityUid targetGrid, string? priorityTag = null)
|
||||
{
|
||||
var gridDocks = GetDocks(targetGrid);
|
||||
var shuttleDocks = GetDocks(shuttleUid);
|
||||
|
||||
return GetDockingConfigPrivate(shuttleUid, targetGrid, shuttleDocks, gridDocks, priorityTag);
|
||||
}
|
||||
|
||||
private DockingConfig? GetDockingConfigPrivate(
|
||||
EntityUid shuttleUid,
|
||||
EntityUid targetGrid,
|
||||
List<(EntityUid, DockingComponent)> shuttleDocks,
|
||||
List<(EntityUid, DockingComponent)> gridDocks,
|
||||
string? priorityTag = null)
|
||||
{
|
||||
if (gridDocks.Count <= 0)
|
||||
return null;
|
||||
|
||||
var xformQuery = GetEntityQuery<TransformComponent>();
|
||||
var targetGridGrid = Comp<MapGridComponent>(targetGrid);
|
||||
var targetGridXform = xformQuery.GetComponent(targetGrid);
|
||||
var targetGridAngle = _transform.GetWorldRotation(targetGridXform).Reduced();
|
||||
|
||||
var shuttleAABB = Comp<MapGridComponent>(shuttleUid).LocalAABB;
|
||||
|
||||
var validDockConfigs = new List<DockingConfig>();
|
||||
|
||||
if (shuttleDocks.Count > 0)
|
||||
{
|
||||
// We'll try all combinations of shuttle docks and see which one is most suitable
|
||||
foreach (var (dockUid, shuttleDock) in shuttleDocks)
|
||||
{
|
||||
var shuttleDockXform = xformQuery.GetComponent(dockUid);
|
||||
|
||||
foreach (var (gridDockUid, gridDock) in gridDocks)
|
||||
{
|
||||
var gridXform = xformQuery.GetComponent(gridDockUid);
|
||||
|
||||
if (!CanDock(
|
||||
shuttleDock, shuttleDockXform,
|
||||
gridDock, gridXform,
|
||||
targetGridAngle,
|
||||
shuttleAABB,
|
||||
targetGridGrid,
|
||||
out var dockedAABB,
|
||||
out var matty,
|
||||
out var targetAngle))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// Can't just use the AABB as we want to get bounds as tight as possible.
|
||||
var spawnPosition = new EntityCoordinates(targetGrid, matty.Transform(Vector2.Zero));
|
||||
spawnPosition = new EntityCoordinates(targetGridXform.MapUid!.Value, spawnPosition.ToMapPos(EntityManager, _transform));
|
||||
|
||||
var dockedBounds = new Box2Rotated(shuttleAABB.Translated(spawnPosition.Position), targetGridAngle, spawnPosition.Position);
|
||||
|
||||
// Check if there's no intersecting grids (AKA oh god it's docking at cargo).
|
||||
if (_mapManager.FindGridsIntersecting(targetGridXform.MapID,
|
||||
dockedBounds).Any(o => o.Owner != targetGrid))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// Alright well the spawn is valid now to check how many we can connect
|
||||
// Get the matrix for each shuttle dock and test it against the grid docks to see
|
||||
// if the connected position / direction matches.
|
||||
|
||||
var dockedPorts = new List<(EntityUid DockAUid, EntityUid DockBUid, DockingComponent DockA, DockingComponent DockB)>()
|
||||
{
|
||||
(dockUid, gridDockUid, shuttleDock, gridDock),
|
||||
};
|
||||
|
||||
// TODO: Check shuttle orientation as the tiebreaker.
|
||||
|
||||
foreach (var (otherUid, other) in shuttleDocks)
|
||||
{
|
||||
if (other == shuttleDock)
|
||||
continue;
|
||||
|
||||
foreach (var (otherGridUid, otherGrid) in gridDocks)
|
||||
{
|
||||
if (otherGrid == gridDock)
|
||||
continue;
|
||||
|
||||
if (!CanDock(
|
||||
other,
|
||||
xformQuery.GetComponent(otherUid),
|
||||
otherGrid,
|
||||
xformQuery.GetComponent(otherGridUid),
|
||||
targetGridAngle,
|
||||
shuttleAABB, targetGridGrid,
|
||||
out var otherDockedAABB,
|
||||
out _,
|
||||
out var otherTargetAngle) ||
|
||||
!otherDockedAABB.Equals(dockedAABB) ||
|
||||
!targetAngle.Equals(otherTargetAngle))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
dockedPorts.Add((otherUid, otherGridUid, other, otherGrid));
|
||||
}
|
||||
}
|
||||
|
||||
validDockConfigs.Add(new DockingConfig()
|
||||
{
|
||||
Docks = dockedPorts,
|
||||
Area = dockedAABB.Value,
|
||||
Coordinates = spawnPosition,
|
||||
Angle = targetAngle,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (validDockConfigs.Count <= 0)
|
||||
return null;
|
||||
|
||||
// Prioritise by priority docks, then by maximum connected ports, then by most similar angle.
|
||||
validDockConfigs = validDockConfigs
|
||||
.OrderByDescending(x => x.Docks.Any(docks =>
|
||||
TryComp<PriorityDockComponent>(docks.DockB.Owner, out var priority) &&
|
||||
priority.Tag?.Equals(priorityTag) == true))
|
||||
.ThenByDescending(x => x.Docks.Count)
|
||||
.ThenBy(x => Math.Abs(Angle.ShortestDistance(x.Angle.Reduced(), targetGridAngle).Theta)).ToList();
|
||||
|
||||
var location = validDockConfigs.First();
|
||||
location.TargetGrid = targetGrid;
|
||||
// TODO: Ideally do a hyperspace warpin, just have it run on like a 10 second timer.
|
||||
|
||||
return location;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks whether the emergency shuttle can warp to the specified position.
|
||||
/// </summary>
|
||||
private bool ValidSpawn(MapGridComponent grid, Box2 area)
|
||||
{
|
||||
return !grid.GetLocalTilesIntersecting(area).Any();
|
||||
}
|
||||
|
||||
public List<(EntityUid Uid, DockingComponent Component)> GetDocks(EntityUid uid)
|
||||
{
|
||||
var result = new List<(EntityUid Uid, DockingComponent Component)>();
|
||||
var query = AllEntityQuery<DockingComponent, TransformComponent>();
|
||||
|
||||
while (query.MoveNext(out var dockUid, out var dock, out var xform))
|
||||
{
|
||||
if (xform.ParentUid != uid || !dock.Enabled)
|
||||
continue;
|
||||
|
||||
result.Add((dockUid, dock));
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
@@ -25,7 +25,7 @@ namespace Content.Server.Shuttles.Systems
|
||||
[Dependency] private readonly ShuttleConsoleSystem _console = default!;
|
||||
[Dependency] private readonly SharedJointSystem _jointSystem = default!;
|
||||
[Dependency] private readonly SharedPhysicsSystem _physics = default!;
|
||||
[Dependency] private readonly SharedTransformSystem _transformSystem = default!;
|
||||
[Dependency] private readonly SharedTransformSystem _transform = default!;
|
||||
|
||||
private ISawmill _sawmill = default!;
|
||||
private const string DockingFixture = "docking";
|
||||
|
||||
@@ -1,14 +1,11 @@
|
||||
using System.Threading;
|
||||
using Content.Server.Access.Systems;
|
||||
using Content.Server.Popups;
|
||||
using Content.Server.RoundEnd;
|
||||
using Content.Server.Shuttles.Components;
|
||||
using Content.Server.Shuttles.Events;
|
||||
using Content.Server.Station.Components;
|
||||
using Content.Server.UserInterface;
|
||||
using Content.Shared.Access.Systems;
|
||||
using Content.Shared.CCVar;
|
||||
using Content.Shared.Database;
|
||||
using Content.Shared.GameTicking;
|
||||
using Content.Shared.Popups;
|
||||
using Content.Shared.Shuttles.BUIStates;
|
||||
using Content.Shared.Shuttles.Events;
|
||||
@@ -16,23 +13,16 @@ using Content.Shared.Shuttles.Systems;
|
||||
using Robust.Shared.Audio;
|
||||
using Robust.Shared.Map;
|
||||
using Robust.Shared.Player;
|
||||
using Robust.Shared.Timing;
|
||||
using Timer = Robust.Shared.Timing.Timer;
|
||||
|
||||
namespace Content.Server.Shuttles.Systems;
|
||||
|
||||
public sealed partial class ShuttleSystem
|
||||
public sealed partial class EmergencyShuttleSystem
|
||||
{
|
||||
/*
|
||||
* Handles the emergency shuttle's console and early launching.
|
||||
*/
|
||||
|
||||
[Dependency] private readonly IGameTiming _timing = default!;
|
||||
[Dependency] private readonly IdCardSystem _idSystem = default!;
|
||||
[Dependency] private readonly AccessReaderSystem _reader = default!;
|
||||
[Dependency] private readonly PopupSystem _popup = default!;
|
||||
[Dependency] private readonly RoundEndSystem _roundEnd = default!;
|
||||
|
||||
/// <summary>
|
||||
/// Has the emergency shuttle arrived?
|
||||
/// </summary>
|
||||
@@ -43,7 +33,7 @@ public sealed partial class ShuttleSystem
|
||||
/// <summary>
|
||||
/// How much time remaining until the shuttle consoles for emergency shuttles are unlocked?
|
||||
/// </summary>
|
||||
private float _consoleAccumulator;
|
||||
private float _consoleAccumulator = float.MinValue;
|
||||
|
||||
/// <summary>
|
||||
/// How long after the transit is over to end the round.
|
||||
@@ -70,6 +60,8 @@ public sealed partial class ShuttleSystem
|
||||
/// </summary>
|
||||
private bool _launchedShuttles;
|
||||
|
||||
private bool _leftShuttles;
|
||||
|
||||
/// <summary>
|
||||
/// Have we announced the launch?
|
||||
/// </summary>
|
||||
@@ -84,6 +76,8 @@ public sealed partial class ShuttleSystem
|
||||
SubscribeLocalEvent<EmergencyShuttleConsoleComponent, EmergencyShuttleRepealMessage>(OnEmergencyRepeal);
|
||||
SubscribeLocalEvent<EmergencyShuttleConsoleComponent, EmergencyShuttleRepealAllMessage>(OnEmergencyRepealAll);
|
||||
SubscribeLocalEvent<EmergencyShuttleConsoleComponent, ActivatableUIOpenAttemptEvent>(OnEmergencyOpenAttempt);
|
||||
|
||||
SubscribeLocalEvent<EscapePodComponent, EntityUnpausedEvent>(OnEscapeUnpaused);
|
||||
}
|
||||
|
||||
private void OnEmergencyOpenAttempt(EntityUid uid, EmergencyShuttleConsoleComponent component, ActivatableUIOpenAttemptEvent args)
|
||||
@@ -119,7 +113,14 @@ public sealed partial class ShuttleSystem
|
||||
|
||||
private void UpdateEmergencyConsole(float frameTime)
|
||||
{
|
||||
if (_consoleAccumulator <= 0f) return;
|
||||
// Add some buffer time so eshuttle always first.
|
||||
var minTime = -(TransitTime - (ShuttleSystem.DefaultStartupTime + ShuttleSystem.DefaultTravelTime + 1f));
|
||||
|
||||
// TODO: I know this is shit but I already just cleaned up a billion things.
|
||||
if (_consoleAccumulator < minTime)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_consoleAccumulator -= frameTime;
|
||||
|
||||
@@ -131,46 +132,76 @@ public sealed partial class ShuttleSystem
|
||||
}
|
||||
|
||||
// Imminent departure
|
||||
if (!_launchedShuttles && _consoleAccumulator <= DefaultStartupTime)
|
||||
if (!_launchedShuttles && _consoleAccumulator <= ShuttleSystem.DefaultStartupTime)
|
||||
{
|
||||
_launchedShuttles = true;
|
||||
|
||||
if (CentComMap != null)
|
||||
{
|
||||
foreach (var comp in EntityQuery<StationDataComponent>(true))
|
||||
var dataQuery = AllEntityQuery<StationDataComponent>();
|
||||
|
||||
while (dataQuery.MoveNext(out var comp))
|
||||
{
|
||||
if (!TryComp<ShuttleComponent>(comp.EmergencyShuttle, out var shuttle)) continue;
|
||||
if (!TryComp<ShuttleComponent>(comp.EmergencyShuttle, out var shuttle))
|
||||
continue;
|
||||
|
||||
if (Deleted(CentCom))
|
||||
{
|
||||
// TODO: Need to get non-overlapping positions.
|
||||
FTLTravel(shuttle,
|
||||
_shuttle.FTLTravel(comp.EmergencyShuttle.Value, shuttle,
|
||||
new EntityCoordinates(
|
||||
_mapManager.GetMapEntityId(CentComMap.Value),
|
||||
Vector2.One * 1000f), _consoleAccumulator, TransitTime);
|
||||
_random.NextVector2(1000f)), _consoleAccumulator, TransitTime);
|
||||
}
|
||||
else
|
||||
{
|
||||
FTLTravel(shuttle,
|
||||
_shuttle.FTLTravel(comp.EmergencyShuttle.Value, shuttle,
|
||||
CentCom.Value, _consoleAccumulator, TransitTime, true);
|
||||
}
|
||||
}
|
||||
|
||||
var podQuery = AllEntityQuery<EscapePodComponent>();
|
||||
var podLaunchOffset = 0.5f;
|
||||
|
||||
// Stagger launches coz funny
|
||||
while (podQuery.MoveNext(out _, out var pod))
|
||||
{
|
||||
pod.LaunchTime = _timing.CurTime + TimeSpan.FromSeconds(podLaunchOffset);
|
||||
podLaunchOffset += _random.NextFloat(0.5f, 2.5f);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Departed
|
||||
if (_consoleAccumulator <= 0f)
|
||||
var podLaunchQuery = EntityQueryEnumerator<EscapePodComponent, ShuttleComponent>();
|
||||
|
||||
while (podLaunchQuery.MoveNext(out var uid, out var pod, out var shuttle))
|
||||
{
|
||||
_launchedShuttles = true;
|
||||
if (CentCom == null || pod.LaunchTime == null || pod.LaunchTime < _timing.CurTime)
|
||||
continue;
|
||||
|
||||
// Don't dock them. If you do end up doing this then stagger launch.
|
||||
_shuttle.FTLTravel(uid, shuttle,
|
||||
CentCom.Value, hyperspaceTime: TransitTime);
|
||||
|
||||
RemCompDeferred<EscapePodComponent>(uid);
|
||||
}
|
||||
|
||||
// Departed
|
||||
if (!_leftShuttles && _consoleAccumulator <= 0f)
|
||||
{
|
||||
_leftShuttles = true;
|
||||
_chatSystem.DispatchGlobalAnnouncement(Loc.GetString("emergency-shuttle-left", ("transitTime", $"{TransitTime:0}")));
|
||||
|
||||
_roundEndCancelToken = new CancellationTokenSource();
|
||||
Timer.Spawn((int) (TransitTime * 1000) + _bufferTime.Milliseconds, () => _roundEnd.EndRound(), _roundEndCancelToken.Token);
|
||||
}
|
||||
|
||||
// All the others.
|
||||
if (_consoleAccumulator < minTime)
|
||||
{
|
||||
// Guarantees that emergency shuttle arrives first before anyone else can FTL.
|
||||
if (CentCom != null)
|
||||
AddFTLDestination(CentCom.Value, true);
|
||||
|
||||
_shuttle.AddFTLDestination(CentCom.Value, true);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -185,7 +216,8 @@ public sealed partial class ShuttleSystem
|
||||
return;
|
||||
}
|
||||
|
||||
if (component.AuthorizedEntities.Count == 0) return;
|
||||
if (component.AuthorizedEntities.Count == 0)
|
||||
return;
|
||||
|
||||
_logger.Add(LogType.EmergencyShuttle, LogImpact.High, $"Emergency shuttle early launch REPEAL ALL by {args.Session:user}");
|
||||
_chatSystem.DispatchGlobalAnnouncement(Loc.GetString("emergency-shuttle-console-auth-revoked", ("remaining", component.AuthorizationsRequired)));
|
||||
@@ -246,8 +278,9 @@ public sealed partial class ShuttleSystem
|
||||
{
|
||||
_announced = false;
|
||||
_roundEndCancelToken = null;
|
||||
_leftShuttles = false;
|
||||
_launchedShuttles = false;
|
||||
_consoleAccumulator = 0f;
|
||||
_consoleAccumulator = float.MinValue;
|
||||
EarlyLaunchAuthorized = false;
|
||||
EmergencyShuttleArrived = false;
|
||||
}
|
||||
@@ -294,7 +327,7 @@ public sealed partial class ShuttleSystem
|
||||
if (EarlyLaunchAuthorized || !EmergencyShuttleArrived || _consoleAccumulator <= _authorizeTime) return false;
|
||||
|
||||
_logger.Add(LogType.EmergencyShuttle, LogImpact.Extreme, $"Emergency shuttle launch authorized");
|
||||
_consoleAccumulator =_authorizeTime;
|
||||
_consoleAccumulator = _authorizeTime;
|
||||
EarlyLaunchAuthorized = true;
|
||||
RaiseLocalEvent(new EmergencyShuttleAuthorizedEvent());
|
||||
AnnounceLaunch();
|
||||
@@ -1,33 +1,30 @@
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Linq;
|
||||
using Content.Server.Access.Systems;
|
||||
using Content.Server.Administration.Logs;
|
||||
using Content.Server.Administration.Managers;
|
||||
using Content.Server.Chat.Systems;
|
||||
using Content.Server.Communications;
|
||||
using Content.Server.GameTicking.Events;
|
||||
using Content.Server.Popups;
|
||||
using Content.Server.RoundEnd;
|
||||
using Content.Server.Shuttles.Components;
|
||||
using Content.Server.Station.Components;
|
||||
using Content.Server.Station.Systems;
|
||||
using Content.Shared.Access.Systems;
|
||||
using Content.Shared.CCVar;
|
||||
using Content.Shared.Database;
|
||||
using Content.Shared.Shuttles.Events;
|
||||
using Content.Shared.Tiles;
|
||||
using Content.Shared.Tag;
|
||||
using Robust.Server.GameObjects;
|
||||
using Robust.Server.Maps;
|
||||
using Robust.Server.Player;
|
||||
using Robust.Shared.Audio;
|
||||
using Robust.Shared.Configuration;
|
||||
using Robust.Shared.Map;
|
||||
using Robust.Shared.Map.Components;
|
||||
using Robust.Shared.Physics;
|
||||
using Robust.Shared.Physics.Components;
|
||||
using Robust.Shared.Player;
|
||||
using Robust.Shared.Random;
|
||||
using Robust.Shared.Timing;
|
||||
|
||||
namespace Content.Server.Shuttles.Systems;
|
||||
|
||||
public sealed partial class ShuttleSystem
|
||||
public sealed partial class EmergencyShuttleSystem : EntitySystem
|
||||
{
|
||||
/*
|
||||
* Handles the escape shuttle + CentCom.
|
||||
@@ -36,12 +33,23 @@ public sealed partial class ShuttleSystem
|
||||
[Dependency] private readonly IAdminLogManager _logger = default!;
|
||||
[Dependency] private readonly IAdminManager _admin = default!;
|
||||
[Dependency] private readonly IConfigurationManager _configManager = default!;
|
||||
[Dependency] private readonly IGameTiming _timing = default!;
|
||||
[Dependency] private readonly IMapManager _mapManager = default!;
|
||||
[Dependency] private readonly IRobustRandom _random = default!;
|
||||
[Dependency] private readonly AccessReaderSystem _reader = default!;
|
||||
[Dependency] private readonly ChatSystem _chatSystem = default!;
|
||||
[Dependency] private readonly CommunicationsConsoleSystem _commsConsole = default!;
|
||||
[Dependency] private readonly DockingSystem _dockSystem = default!;
|
||||
[Dependency] private readonly DockingSystem _dock = default!;
|
||||
[Dependency] private readonly IdCardSystem _idSystem = default!;
|
||||
[Dependency] private readonly MapLoaderSystem _map = default!;
|
||||
[Dependency] private readonly PopupSystem _popup = default!;
|
||||
[Dependency] private readonly RoundEndSystem _roundEnd = default!;
|
||||
[Dependency] private readonly SharedAudioSystem _audio = default!;
|
||||
[Dependency] private readonly ShuttleSystem _shuttle = default!;
|
||||
[Dependency] private readonly StationSystem _station = default!;
|
||||
[Dependency] private readonly UserInterfaceSystem _uiSystem = default!;
|
||||
|
||||
private ISawmill _sawmill = default!;
|
||||
|
||||
public MapId? CentComMap { get; private set; }
|
||||
public EntityUid? CentCom { get; private set; }
|
||||
@@ -55,19 +63,22 @@ public sealed partial class ShuttleSystem
|
||||
|
||||
private bool _emergencyShuttleEnabled;
|
||||
|
||||
private void InitializeEscape()
|
||||
public override void Initialize()
|
||||
{
|
||||
_sawmill = Logger.GetSawmill("shuttle.emergency");
|
||||
_emergencyShuttleEnabled = _configManager.GetCVar(CCVars.EmergencyShuttleEnabled);
|
||||
// Don't immediately invoke as roundstart will just handle it.
|
||||
_configManager.OnValueChanged(CCVars.EmergencyShuttleEnabled, SetEmergencyShuttleEnabled);
|
||||
SubscribeLocalEvent<RoundStartingEvent>(OnRoundStart);
|
||||
SubscribeLocalEvent<StationDataComponent, ComponentStartup>(OnStationStartup);
|
||||
SubscribeNetworkEvent<EmergencyShuttleRequestPositionMessage>(OnShuttleRequestPosition);
|
||||
InitializeEmergencyConsole();
|
||||
}
|
||||
|
||||
private void SetEmergencyShuttleEnabled(bool value)
|
||||
{
|
||||
if (_emergencyShuttleEnabled == value) return;
|
||||
if (_emergencyShuttleEnabled == value)
|
||||
return;
|
||||
_emergencyShuttleEnabled = value;
|
||||
|
||||
if (value)
|
||||
@@ -80,9 +91,16 @@ public sealed partial class ShuttleSystem
|
||||
}
|
||||
}
|
||||
|
||||
private void ShutdownEscape()
|
||||
public override void Update(float frameTime)
|
||||
{
|
||||
base.Update(frameTime);
|
||||
UpdateEmergencyConsole(frameTime);
|
||||
}
|
||||
|
||||
public override void Shutdown()
|
||||
{
|
||||
_configManager.UnsubValueChanged(CCVars.EmergencyShuttleEnabled, SetEmergencyShuttleEnabled);
|
||||
ShutdownEmergencyConsole();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -90,18 +108,25 @@ public sealed partial class ShuttleSystem
|
||||
/// </summary>
|
||||
private void OnShuttleRequestPosition(EmergencyShuttleRequestPositionMessage msg, EntitySessionEventArgs args)
|
||||
{
|
||||
if (!_admin.IsAdmin((IPlayerSession) args.SenderSession)) return;
|
||||
if (!_admin.IsAdmin((IPlayerSession) args.SenderSession))
|
||||
return;
|
||||
|
||||
var player = args.SenderSession.AttachedEntity;
|
||||
|
||||
if (player == null ||
|
||||
!TryComp<StationDataComponent>(_station.GetOwningStation(player.Value), out var stationData) ||
|
||||
!TryComp<ShuttleComponent>(stationData.EmergencyShuttle, out var shuttle)) return;
|
||||
!HasComp<ShuttleComponent>(stationData.EmergencyShuttle))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var targetGrid = _station.GetLargestGrid(stationData);
|
||||
if (targetGrid == null) return;
|
||||
var config = GetDockingConfig(shuttle, targetGrid.Value);
|
||||
if (config == null) return;
|
||||
if (targetGrid == null)
|
||||
return;
|
||||
|
||||
var config = _dock.GetDockingConfig(stationData.EmergencyShuttle.Value, targetGrid.Value);
|
||||
if (config == null)
|
||||
return;
|
||||
|
||||
RaiseNetworkEvent(new EmergencyShuttlePositionMessage()
|
||||
{
|
||||
@@ -117,7 +142,10 @@ public sealed partial class ShuttleSystem
|
||||
{
|
||||
if (!TryComp<StationDataComponent>(stationUid, out var stationData) ||
|
||||
!TryComp<TransformComponent>(stationData.EmergencyShuttle, out var xform) ||
|
||||
!TryComp<ShuttleComponent>(stationData.EmergencyShuttle, out var shuttle)) return;
|
||||
!TryComp<ShuttleComponent>(stationData.EmergencyShuttle, out var shuttle))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var targetGrid = _station.GetLargestGrid(stationData);
|
||||
|
||||
@@ -127,105 +155,38 @@ public sealed partial class ShuttleSystem
|
||||
_logger.Add(LogType.EmergencyShuttle, LogImpact.High, $"Emergency shuttle {ToPrettyString(stationUid.Value)} unable to dock with station {ToPrettyString(stationUid.Value)}");
|
||||
_chatSystem.DispatchStationAnnouncement(stationUid.Value, Loc.GetString("emergency-shuttle-good-luck"), playDefaultSound: false);
|
||||
// TODO: Need filter extensions or something don't blame me.
|
||||
SoundSystem.Play("/Audio/Misc/notice1.ogg", Filter.Broadcast());
|
||||
_audio.PlayGlobal("/Audio/Misc/notice1.ogg", Filter.Broadcast(), true);
|
||||
return;
|
||||
}
|
||||
|
||||
var xformQuery = GetEntityQuery<TransformComponent>();
|
||||
|
||||
if (TryFTLDock(shuttle, targetGrid.Value))
|
||||
if (_shuttle.TryFTLDock(stationData.EmergencyShuttle.Value, shuttle, targetGrid.Value))
|
||||
{
|
||||
if (TryComp<TransformComponent>(targetGrid.Value, out var targetXform))
|
||||
{
|
||||
var angle = GetAngle(xform, targetXform, xformQuery);
|
||||
var angle = _dock.GetAngle(stationData.EmergencyShuttle.Value, xform, targetGrid.Value, targetXform, xformQuery);
|
||||
_chatSystem.DispatchStationAnnouncement(stationUid.Value, Loc.GetString("emergency-shuttle-docked", ("time", $"{_consoleAccumulator:0}"), ("direction", angle.GetDir())), playDefaultSound: false);
|
||||
}
|
||||
|
||||
_logger.Add(LogType.EmergencyShuttle, LogImpact.High, $"Emergency shuttle {ToPrettyString(stationUid.Value)} docked with stations");
|
||||
// TODO: Need filter extensions or something don't blame me.
|
||||
SoundSystem.Play("/Audio/Announcements/shuttle_dock.ogg", Filter.Broadcast());
|
||||
_audio.PlayGlobal("/Audio/Announcements/shuttle_dock.ogg", Filter.Broadcast(), true);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (TryComp<TransformComponent>(targetGrid.Value, out var targetXform))
|
||||
{
|
||||
var angle = GetAngle(xform, targetXform, xformQuery);
|
||||
var angle = _dock.GetAngle(stationData.EmergencyShuttle.Value, xform, targetGrid.Value, targetXform, xformQuery);
|
||||
_chatSystem.DispatchStationAnnouncement(stationUid.Value, Loc.GetString("emergency-shuttle-nearby", ("direction", angle.GetDir())), playDefaultSound: false);
|
||||
}
|
||||
|
||||
_logger.Add(LogType.EmergencyShuttle, LogImpact.High, $"Emergency shuttle {ToPrettyString(stationUid.Value)} unable to find a valid docking port for {ToPrettyString(stationUid.Value)}");
|
||||
// TODO: Need filter extensions or something don't blame me.
|
||||
SoundSystem.Play("/Audio/Misc/notice1.ogg", Filter.Broadcast());
|
||||
_audio.PlayGlobal("/Audio/Misc/notice1.ogg", Filter.Broadcast(), true);
|
||||
}
|
||||
}
|
||||
|
||||
private Angle GetAngle(TransformComponent xform, TransformComponent targetXform, EntityQuery<TransformComponent> xformQuery)
|
||||
{
|
||||
var (shuttlePos, shuttleRot) = xform.GetWorldPositionRotation(xformQuery);
|
||||
var (targetPos, targetRot) = targetXform.GetWorldPositionRotation(xformQuery);
|
||||
|
||||
var shuttleCOM = Robust.Shared.Physics.Transform.Mul(new Transform(shuttlePos, shuttleRot),
|
||||
Comp<PhysicsComponent>(xform.Owner).LocalCenter);
|
||||
var targetCOM = Robust.Shared.Physics.Transform.Mul(new Transform(targetPos, targetRot),
|
||||
Comp<PhysicsComponent>(targetXform.Owner).LocalCenter);
|
||||
|
||||
var mapDiff = shuttleCOM - targetCOM;
|
||||
var targetRotation = targetRot;
|
||||
var angle = mapDiff.ToWorldAngle();
|
||||
angle -= targetRotation;
|
||||
return angle;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks if 2 docks can be connected by moving the shuttle directly onto docks.
|
||||
/// </summary>
|
||||
private bool CanDock(
|
||||
DockingComponent shuttleDock,
|
||||
TransformComponent shuttleDockXform,
|
||||
DockingComponent gridDock,
|
||||
TransformComponent gridDockXform,
|
||||
Angle targetGridRotation,
|
||||
Box2 shuttleAABB,
|
||||
EntityUid gridUid,
|
||||
MapGridComponent grid,
|
||||
[NotNullWhen(true)] out Box2? shuttleDockedAABB,
|
||||
out Matrix3 matty,
|
||||
out Angle gridRotation)
|
||||
{
|
||||
gridRotation = Angle.Zero;
|
||||
matty = Matrix3.Identity;
|
||||
shuttleDockedAABB = null;
|
||||
|
||||
if (shuttleDock.Docked ||
|
||||
gridDock.Docked ||
|
||||
!shuttleDockXform.Anchored ||
|
||||
!gridDockXform.Anchored)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// First, get the station dock's position relative to the shuttle, this is where we rotate it around
|
||||
var stationDockPos = shuttleDockXform.LocalPosition +
|
||||
shuttleDockXform.LocalRotation.RotateVec(new Vector2(0f, -1f));
|
||||
|
||||
// Need to invert the grid's angle.
|
||||
var shuttleDockAngle = shuttleDockXform.LocalRotation;
|
||||
var gridDockAngle = gridDockXform.LocalRotation.Opposite();
|
||||
|
||||
var stationDockMatrix = Matrix3.CreateInverseTransform(stationDockPos, shuttleDockAngle);
|
||||
var gridXformMatrix = Matrix3.CreateTransform(gridDockXform.LocalPosition, gridDockAngle);
|
||||
Matrix3.Multiply(in stationDockMatrix, in gridXformMatrix, out matty);
|
||||
shuttleDockedAABB = matty.TransformBox(shuttleAABB);
|
||||
// Rounding moment
|
||||
shuttleDockedAABB = shuttleDockedAABB.Value.Enlarged(-0.01f);
|
||||
|
||||
if (!ValidSpawn(gridUid, grid, shuttleDockedAABB.Value))
|
||||
return false;
|
||||
|
||||
gridRotation = targetGridRotation + gridDockAngle - shuttleDockAngle;
|
||||
return true;
|
||||
}
|
||||
|
||||
private void OnStationStartup(EntityUid uid, StationDataComponent component, ComponentStartup args)
|
||||
{
|
||||
AddEmergencyShuttle(component);
|
||||
@@ -233,6 +194,7 @@ public sealed partial class ShuttleSystem
|
||||
|
||||
private void OnRoundStart(RoundStartingEvent ev)
|
||||
{
|
||||
CleanupEmergencyConsole();
|
||||
SetupEmergencyShuttle();
|
||||
}
|
||||
|
||||
@@ -241,7 +203,8 @@ public sealed partial class ShuttleSystem
|
||||
/// </summary>
|
||||
public void CallEmergencyShuttle()
|
||||
{
|
||||
if (EmergencyShuttleArrived) return;
|
||||
if (EmergencyShuttleArrived)
|
||||
return;
|
||||
|
||||
if (!_emergencyShuttleEnabled)
|
||||
{
|
||||
@@ -255,28 +218,16 @@ public sealed partial class ShuttleSystem
|
||||
if (CentComMap != null)
|
||||
_mapManager.SetMapPaused(CentComMap.Value, false);
|
||||
|
||||
foreach (var comp in EntityQuery<StationDataComponent>(true))
|
||||
var query = AllEntityQuery<StationDataComponent>();
|
||||
|
||||
while (query.MoveNext(out var uid, out var comp))
|
||||
{
|
||||
CallEmergencyShuttle(comp.Owner);
|
||||
CallEmergencyShuttle(uid);
|
||||
}
|
||||
|
||||
_commsConsole.UpdateCommsConsoleInterface();
|
||||
}
|
||||
|
||||
public List<DockingComponent> GetDocks(EntityUid uid)
|
||||
{
|
||||
var result = new List<DockingComponent>();
|
||||
|
||||
foreach (var (dock, xform) in EntityQuery<DockingComponent, TransformComponent>(true))
|
||||
{
|
||||
if (xform.ParentUid != uid || !dock.Enabled) continue;
|
||||
|
||||
result.Add(dock);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private void SetupEmergencyShuttle()
|
||||
{
|
||||
if (!_emergencyShuttleEnabled || CentComMap != null && _mapManager.MapExists(CentComMap.Value)) return;
|
||||
@@ -293,7 +244,7 @@ public sealed partial class ShuttleSystem
|
||||
CentCom = centcomm;
|
||||
|
||||
if (CentCom != null)
|
||||
AddFTLDestination(CentCom.Value, false);
|
||||
_shuttle.AddFTLDestination(CentCom.Value, false);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -332,7 +283,6 @@ public sealed partial class ShuttleSystem
|
||||
|
||||
_shuttleIndex += _mapManager.GetGrid(shuttle.Value).LocalAABB.Width + ShuttleSpawnBuffer;
|
||||
component.EmergencyShuttle = shuttle;
|
||||
EnsureComp<ProtectedGridComponent>(shuttle.Value);
|
||||
}
|
||||
|
||||
private void CleanupEmergencyShuttle()
|
||||
@@ -354,27 +304,11 @@ public sealed partial class ShuttleSystem
|
||||
_mapManager.DeleteMap(CentComMap.Value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Stores the data for a valid docking configuration for the emergency shuttle
|
||||
/// </summary>
|
||||
private sealed class DockingConfig
|
||||
private void OnEscapeUnpaused(EntityUid uid, EscapePodComponent component, ref EntityUnpausedEvent args)
|
||||
{
|
||||
/// <summary>
|
||||
/// The pairs of docks that can connect.
|
||||
/// </summary>
|
||||
public List<(DockingComponent DockA, DockingComponent DockB)> Docks = new();
|
||||
if (component.LaunchTime == null)
|
||||
return;
|
||||
|
||||
/// <summary>
|
||||
/// Area relative to the target grid the emergency shuttle will spawn in on.
|
||||
/// </summary>
|
||||
public Box2 Area;
|
||||
|
||||
/// <summary>
|
||||
/// Target grid for docking.
|
||||
/// </summary>
|
||||
public EntityUid TargetGrid;
|
||||
|
||||
public EntityCoordinates Coordinates;
|
||||
public Angle Angle;
|
||||
component.LaunchTime = component.LaunchTime.Value + args.PausedTime;
|
||||
}
|
||||
}
|
||||
@@ -12,16 +12,17 @@ using Content.Shared.Shuttles.Events;
|
||||
using Content.Shared.Shuttles.Systems;
|
||||
using Content.Shared.Tag;
|
||||
using Robust.Server.GameObjects;
|
||||
using Robust.Shared.Collections;
|
||||
using Robust.Shared.GameStates;
|
||||
using Robust.Shared.Map.Components;
|
||||
using Robust.Shared.Physics.Components;
|
||||
using Robust.Shared.Timing;
|
||||
using Robust.Shared.Utility;
|
||||
|
||||
namespace Content.Server.Shuttles.Systems
|
||||
namespace Content.Server.Shuttles.Systems;
|
||||
|
||||
public sealed class ShuttleConsoleSystem : SharedShuttleConsoleSystem
|
||||
{
|
||||
public sealed class ShuttleConsoleSystem : SharedShuttleConsoleSystem
|
||||
{
|
||||
[Dependency] private readonly IGameTiming _timing = default!;
|
||||
[Dependency] private readonly ActionBlockerSystem _blocker = default!;
|
||||
[Dependency] private readonly AlertsSystem _alertsSystem = default!;
|
||||
@@ -93,7 +94,9 @@ namespace Content.Server.Shuttles.Systems
|
||||
return;
|
||||
}
|
||||
|
||||
if (HasComp<FTLComponent>(xform.GridUid))
|
||||
var shuttleUid = xform.GridUid.Value;
|
||||
|
||||
if (HasComp<FTLComponent>(shuttleUid))
|
||||
{
|
||||
_popup.PopupCursor(Loc.GetString("shuttle-console-in-ftl"), args.Session);
|
||||
return;
|
||||
@@ -109,7 +112,7 @@ namespace Content.Server.Shuttles.Systems
|
||||
var tagEv = new FTLTagEvent();
|
||||
RaiseLocalEvent(xform.GridUid.Value, ref tagEv);
|
||||
|
||||
_shuttle.FTLTravel(shuttle, args.Destination, dock: dock, priorityTag: tagEv.Tag);
|
||||
_shuttle.FTLTravel(xform.GridUid.Value, shuttle, args.Destination, dock: dock, priorityTag: tagEv.Tag);
|
||||
}
|
||||
|
||||
private void OnDock(DockEvent ev)
|
||||
@@ -138,7 +141,7 @@ namespace Content.Server.Shuttles.Systems
|
||||
|
||||
while (query.MoveNext(out var uid, out var comp))
|
||||
{
|
||||
UpdateState(uid, comp, docks);
|
||||
UpdateState(uid, docks);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -170,12 +173,12 @@ namespace Content.Server.Shuttles.Systems
|
||||
|
||||
private void OnConsoleAnchorChange(EntityUid uid, ShuttleConsoleComponent component, ref AnchorStateChangedEvent args)
|
||||
{
|
||||
UpdateState(uid, component);
|
||||
UpdateState(uid);
|
||||
}
|
||||
|
||||
private void OnConsolePowerChange(EntityUid uid, ShuttleConsoleComponent component, ref PowerChangedEvent args)
|
||||
{
|
||||
UpdateState(uid, component);
|
||||
UpdateState(uid);
|
||||
}
|
||||
|
||||
private bool TryPilot(EntityUid user, EntityUid uid)
|
||||
@@ -189,7 +192,7 @@ namespace Content.Server.Shuttles.Systems
|
||||
return false;
|
||||
}
|
||||
|
||||
var pilotComponent = EntityManager.EnsureComponent<PilotComponent>(user);
|
||||
var pilotComponent = EnsureComp<PilotComponent>(user);
|
||||
var console = pilotComponent.Console;
|
||||
|
||||
if (console != null)
|
||||
@@ -240,7 +243,7 @@ namespace Content.Server.Shuttles.Systems
|
||||
return result;
|
||||
}
|
||||
|
||||
private void UpdateState(EntityUid consoleUid, ShuttleConsoleComponent component, List<DockingInterfaceState>? docks = null)
|
||||
private void UpdateState(EntityUid consoleUid, List<DockingInterfaceState>? docks = null)
|
||||
{
|
||||
EntityUid? entity = consoleUid;
|
||||
|
||||
@@ -299,7 +302,7 @@ namespace Content.Server.Shuttles.Systems
|
||||
|
||||
var canTravel = !locked &&
|
||||
comp.Enabled &&
|
||||
(!TryComp<FTLComponent>(comp.Owner, out var ftl) || ftl.State == FTLState.Cooldown);
|
||||
(!TryComp<FTLComponent>(destUid, out var ftl) || ftl.State == FTLState.Cooldown);
|
||||
|
||||
// Can't travel to same map (yet)
|
||||
if (canTravel && consoleXform?.MapUid == Transform(destUid).MapUid)
|
||||
@@ -328,7 +331,7 @@ namespace Content.Server.Shuttles.Systems
|
||||
{
|
||||
base.Update(frameTime);
|
||||
|
||||
var toRemove = new RemQueue<PilotComponent>();
|
||||
var toRemove = new ValueList<(EntityUid, PilotComponent)>();
|
||||
var query = EntityQueryEnumerator<PilotComponent>();
|
||||
|
||||
while (query.MoveNext(out var uid, out var comp))
|
||||
@@ -338,13 +341,13 @@ namespace Content.Server.Shuttles.Systems
|
||||
|
||||
if (!_blocker.CanInteract(uid, comp.Console.Owner))
|
||||
{
|
||||
toRemove.Add(comp);
|
||||
toRemove.Add((uid, comp));
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var comp in toRemove)
|
||||
foreach (var (uid, comp) in toRemove)
|
||||
{
|
||||
RemovePilot(comp.Owner, comp);
|
||||
RemovePilot(uid, comp);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -418,11 +421,12 @@ namespace Content.Server.Shuttles.Systems
|
||||
eye.Zoom = new(1.0f, 1.0f);
|
||||
}
|
||||
|
||||
if (!helmsman.SubscribedPilots.Remove(pilotComponent)) return;
|
||||
if (!helmsman.SubscribedPilots.Remove(pilotComponent))
|
||||
return;
|
||||
|
||||
_alertsSystem.ClearAlert(pilotUid, AlertType.PilotingShuttle);
|
||||
|
||||
pilotComponent.Owner.PopupMessage(Loc.GetString("shuttle-pilot-end"));
|
||||
_popup.PopupEntity(Loc.GetString("shuttle-pilot-end"), pilotUid, pilotUid);
|
||||
|
||||
if (pilotComponent.LifeStage < ComponentLifeStage.Stopping)
|
||||
EntityManager.RemoveComponent<PilotComponent>(pilotUid);
|
||||
@@ -430,7 +434,8 @@ namespace Content.Server.Shuttles.Systems
|
||||
|
||||
public void RemovePilot(EntityUid entity)
|
||||
{
|
||||
if (!EntityManager.TryGetComponent(entity, out PilotComponent? pilotComponent)) return;
|
||||
if (!EntityManager.TryGetComponent(entity, out PilotComponent? pilotComponent))
|
||||
return;
|
||||
|
||||
RemovePilot(entity, pilotComponent);
|
||||
}
|
||||
@@ -442,5 +447,4 @@ namespace Content.Server.Shuttles.Systems
|
||||
RemovePilot(pilot.Owner, pilot);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
using Content.Server.Doors.Systems;
|
||||
using Content.Server.Shuttles.Components;
|
||||
using Content.Server.Station.Systems;
|
||||
using Content.Server.Stunnable;
|
||||
using Content.Shared.Parallax;
|
||||
using Content.Shared.Shuttles.Systems;
|
||||
using Content.Shared.StatusEffect;
|
||||
@@ -29,18 +28,11 @@ public sealed partial class ShuttleSystem
|
||||
* This is a way to move a shuttle from one location to another, via an intermediate map for fanciness.
|
||||
*/
|
||||
|
||||
[Dependency] private readonly AirlockSystem _airlock = default!;
|
||||
[Dependency] private readonly DoorSystem _doors = default!;
|
||||
[Dependency] private readonly ShuttleConsoleSystem _console = default!;
|
||||
[Dependency] private readonly SharedTransformSystem _transform = default!;
|
||||
[Dependency] private readonly StunSystem _stuns = default!;
|
||||
[Dependency] private readonly ThrusterSystem _thruster = default!;
|
||||
|
||||
private MapId? _hyperSpaceMap;
|
||||
|
||||
private const float DefaultStartupTime = 5.5f;
|
||||
private const float DefaultTravelTime = 30f;
|
||||
private const float DefaultArrivalTime = 5f;
|
||||
public const float DefaultStartupTime = 5.5f;
|
||||
public const float DefaultTravelTime = 30f;
|
||||
public const float DefaultArrivalTime = 5f;
|
||||
private const float FTLCooldown = 30f;
|
||||
private const float ShuttleFTLRange = 100f;
|
||||
|
||||
@@ -106,14 +98,17 @@ public sealed partial class ShuttleSystem
|
||||
return true;
|
||||
}
|
||||
|
||||
var bounds = xform.WorldMatrix.TransformBox(grid.LocalAABB).Enlarged(ShuttleFTLRange);
|
||||
var bounds = _transform.GetWorldMatrix(xform).TransformBox(grid.LocalAABB).Enlarged(ShuttleFTLRange);
|
||||
var bodyQuery = GetEntityQuery<PhysicsComponent>();
|
||||
|
||||
foreach (var other in _mapManager.FindGridsIntersecting(xform.MapID, bounds))
|
||||
{
|
||||
if (grid.Owner == other.Owner ||
|
||||
if (uid == other.Owner ||
|
||||
!bodyQuery.TryGetComponent(other.Owner, out var body) ||
|
||||
body.Mass < ShuttleFTLMassThreshold) continue;
|
||||
body.Mass < ShuttleFTLMassThreshold)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
reason = Loc.GetString("shuttle-console-proximity");
|
||||
return false;
|
||||
@@ -127,7 +122,8 @@ public sealed partial class ShuttleSystem
|
||||
/// </summary>
|
||||
public FTLDestinationComponent AddFTLDestination(EntityUid uid, bool enabled)
|
||||
{
|
||||
if (TryComp<FTLDestinationComponent>(uid, out var destination) && destination.Enabled == enabled) return destination;
|
||||
if (TryComp<FTLDestinationComponent>(uid, out var destination) && destination.Enabled == enabled)
|
||||
return destination;
|
||||
|
||||
destination = EnsureComp<FTLDestinationComponent>(uid);
|
||||
|
||||
@@ -146,19 +142,22 @@ public sealed partial class ShuttleSystem
|
||||
{
|
||||
if (!RemComp<FTLDestinationComponent>(uid))
|
||||
return;
|
||||
|
||||
_console.RefreshShuttleConsoles();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Moves a shuttle from its current position to the target one. Goes through the hyperspace map while the timer is running.
|
||||
/// </summary>
|
||||
public void FTLTravel(ShuttleComponent component,
|
||||
public void FTLTravel(
|
||||
EntityUid shuttleUid,
|
||||
ShuttleComponent component,
|
||||
EntityCoordinates coordinates,
|
||||
float startupTime = DefaultStartupTime,
|
||||
float hyperspaceTime = DefaultTravelTime,
|
||||
string? priorityTag = null)
|
||||
{
|
||||
if (!TrySetupFTL(component, out var hyperspace))
|
||||
if (!TrySetupFTL(shuttleUid, component, out var hyperspace))
|
||||
return;
|
||||
|
||||
hyperspace.StartupTime = startupTime;
|
||||
@@ -173,14 +172,16 @@ public sealed partial class ShuttleSystem
|
||||
/// <summary>
|
||||
/// Moves a shuttle from its current position to docked on the target one. Goes through the hyperspace map while the timer is running.
|
||||
/// </summary>
|
||||
public void FTLTravel(ShuttleComponent component,
|
||||
public void FTLTravel(
|
||||
EntityUid shuttleUid,
|
||||
ShuttleComponent component,
|
||||
EntityUid target,
|
||||
float startupTime = DefaultStartupTime,
|
||||
float hyperspaceTime = DefaultTravelTime,
|
||||
bool dock = false,
|
||||
string? priorityTag = null)
|
||||
{
|
||||
if (!TrySetupFTL(component, out var hyperspace))
|
||||
if (!TrySetupFTL(shuttleUid, component, out var hyperspace))
|
||||
return;
|
||||
|
||||
hyperspace.StartupTime = startupTime;
|
||||
@@ -192,9 +193,8 @@ public sealed partial class ShuttleSystem
|
||||
_console.RefreshShuttleConsoles();
|
||||
}
|
||||
|
||||
private bool TrySetupFTL(ShuttleComponent shuttle, [NotNullWhen(true)] out FTLComponent? component)
|
||||
private bool TrySetupFTL(EntityUid uid, ShuttleComponent shuttle, [NotNullWhen(true)] out FTLComponent? component)
|
||||
{
|
||||
var uid = shuttle.Owner;
|
||||
component = null;
|
||||
|
||||
if (HasComp<FTLComponent>(uid))
|
||||
@@ -310,9 +310,9 @@ public sealed partial class ShuttleSystem
|
||||
if (comp.TargetUid != null && shuttle != null)
|
||||
{
|
||||
if (comp.Dock)
|
||||
TryFTLDock(shuttle, comp.TargetUid.Value, comp.PriorityTag);
|
||||
TryFTLDock(uid, shuttle, comp.TargetUid.Value, comp.PriorityTag);
|
||||
else
|
||||
TryFTLProximity(shuttle, comp.TargetUid.Value);
|
||||
TryFTLProximity(uid, shuttle, comp.TargetUid.Value);
|
||||
|
||||
mapId = Transform(comp.TargetUid.Value).MapID;
|
||||
}
|
||||
@@ -350,7 +350,7 @@ public sealed partial class ShuttleSystem
|
||||
comp.TravelStream = null;
|
||||
}
|
||||
|
||||
SoundSystem.Play(_arrivalSound.GetSound(), Filter.Empty().AddInRange(Transform(uid).MapPosition, GetSoundRange(uid)), _arrivalSound.Params);
|
||||
_audio.PlayGlobal(_arrivalSound, Filter.Empty().AddInRange(Transform(uid).MapPosition, GetSoundRange(uid)), true);
|
||||
|
||||
if (TryComp<FTLDestinationComponent>(uid, out var dest))
|
||||
{
|
||||
@@ -380,7 +380,9 @@ public sealed partial class ShuttleSystem
|
||||
{
|
||||
foreach (var (dock, xform) in EntityQuery<DockingComponent, TransformComponent>(true))
|
||||
{
|
||||
if (xform.ParentUid != uid || dock.Enabled == enabled) continue;
|
||||
if (xform.ParentUid != uid || dock.Enabled == enabled)
|
||||
continue;
|
||||
|
||||
_dockSystem.Undock(dock);
|
||||
dock.Enabled = enabled;
|
||||
}
|
||||
@@ -388,25 +390,30 @@ public sealed partial class ShuttleSystem
|
||||
|
||||
private void SetDockBolts(EntityUid uid, bool enabled)
|
||||
{
|
||||
foreach (var (_, door, xform) in EntityQuery<DockingComponent, AirlockComponent, TransformComponent>(true))
|
||||
{
|
||||
if (xform.ParentUid != uid) continue;
|
||||
var query = AllEntityQuery<DockingComponent, AirlockComponent, TransformComponent>();
|
||||
|
||||
_doors.TryClose(door.Owner);
|
||||
_airlock.SetBoltsWithAudio(door.Owner, door, enabled);
|
||||
while (query.MoveNext(out var doorUid, out _, out var door, out var xform))
|
||||
{
|
||||
if (xform.ParentUid != uid)
|
||||
continue;
|
||||
|
||||
_doors.TryClose(doorUid);
|
||||
_airlock.SetBoltsWithAudio(doorUid, door, enabled);
|
||||
}
|
||||
}
|
||||
|
||||
private float GetSoundRange(EntityUid uid)
|
||||
{
|
||||
if (!_mapManager.TryGetGrid(uid, out var grid)) return 4f;
|
||||
if (!_mapManager.TryGetGrid(uid, out var grid))
|
||||
return 4f;
|
||||
|
||||
return MathF.Max(grid.LocalAABB.Width, grid.LocalAABB.Height) + 12.5f;
|
||||
}
|
||||
|
||||
private void SetupHyperspace()
|
||||
{
|
||||
if (_hyperSpaceMap != null) return;
|
||||
if (_hyperSpaceMap != null)
|
||||
return;
|
||||
|
||||
_hyperSpaceMap = _mapManager.CreateMap();
|
||||
_sawmill.Info($"Setup hyperspace map at {_hyperSpaceMap.Value}");
|
||||
@@ -453,7 +460,8 @@ public sealed partial class ShuttleSystem
|
||||
|
||||
while (childEnumerator.MoveNext(out var child))
|
||||
{
|
||||
if (!buckleQuery.TryGetComponent(child.Value, out var buckle) || buckle.Buckled) continue;
|
||||
if (!buckleQuery.TryGetComponent(child.Value, out var buckle) || buckle.Buckled)
|
||||
continue;
|
||||
|
||||
toKnock.Add(child.Value);
|
||||
}
|
||||
@@ -462,10 +470,9 @@ public sealed partial class ShuttleSystem
|
||||
/// <summary>
|
||||
/// Tries to dock with the target grid, otherwise falls back to proximity.
|
||||
/// </summary>
|
||||
/// <param name="priorityTag">Priority docking tag to prefer, e.g. for emergency shuttle</param>
|
||||
public bool TryFTLDock(ShuttleComponent component, EntityUid targetUid, string? priorityTag = null)
|
||||
public bool TryFTLDock(EntityUid shuttleUid, ShuttleComponent component, EntityUid targetUid, string? priorityTag = null)
|
||||
{
|
||||
if (!TryComp<TransformComponent>(component.Owner, out var xform) ||
|
||||
if (!TryComp<TransformComponent>(shuttleUid, out var shuttleXform) ||
|
||||
!TryComp<TransformComponent>(targetUid, out var targetXform) ||
|
||||
targetXform.MapUid == null ||
|
||||
!targetXform.MapUid.Value.IsValid())
|
||||
@@ -473,42 +480,49 @@ public sealed partial class ShuttleSystem
|
||||
return false;
|
||||
}
|
||||
|
||||
var config = GetDockingConfig(component, targetUid, priorityTag);
|
||||
var config = _dockSystem.GetDockingConfig(shuttleUid, targetUid, priorityTag);
|
||||
|
||||
if (config != null)
|
||||
{
|
||||
// Set position
|
||||
xform.Coordinates = config.Coordinates;
|
||||
xform.WorldRotation = config.Angle;
|
||||
|
||||
// Connect everything
|
||||
foreach (var (dockA, dockB) in config.Docks)
|
||||
{
|
||||
_dockSystem.Dock(dockA.Owner, dockA, dockB.Owner, dockB);
|
||||
}
|
||||
|
||||
FTLDock(config, shuttleXform);
|
||||
return true;
|
||||
}
|
||||
|
||||
TryFTLProximity(component, targetUid, xform, targetXform);
|
||||
TryFTLProximity(shuttleUid, component, targetUid, shuttleXform, targetXform);
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Forces an FTL dock.
|
||||
/// </summary>
|
||||
public void FTLDock(DockingConfig config, TransformComponent shuttleXform)
|
||||
{
|
||||
// Set position
|
||||
shuttleXform.Coordinates = config.Coordinates;
|
||||
_transform.SetWorldRotation(shuttleXform, config.Angle);
|
||||
|
||||
// Connect everything
|
||||
foreach (var (dockAUid, dockBUid, dockA, dockB) in config.Docks)
|
||||
{
|
||||
_dockSystem.Dock(dockAUid, dockA, dockBUid, dockB);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tries to arrive nearby without overlapping with other grids.
|
||||
/// </summary>
|
||||
public bool TryFTLProximity(ShuttleComponent component, EntityUid targetUid, TransformComponent? xform = null, TransformComponent? targetXform = null)
|
||||
public bool TryFTLProximity(EntityUid shuttleUid, ShuttleComponent component, EntityUid targetUid, TransformComponent? xform = null, TransformComponent? targetXform = null)
|
||||
{
|
||||
if (!Resolve(targetUid, ref targetXform) ||
|
||||
targetXform.MapUid == null ||
|
||||
!targetXform.MapUid.Value.IsValid() ||
|
||||
!Resolve(component.Owner, ref xform))
|
||||
!Resolve(shuttleUid, ref xform))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
var xformQuery = GetEntityQuery<TransformComponent>();
|
||||
var shuttleAABB = Comp<MapGridComponent>(component.Owner).LocalAABB;
|
||||
var shuttleAABB = Comp<MapGridComponent>(shuttleUid).LocalAABB;
|
||||
Box2 targetLocalAABB;
|
||||
|
||||
// Spawn nearby.
|
||||
@@ -534,7 +548,8 @@ public sealed partial class ShuttleSystem
|
||||
{
|
||||
foreach (var grid in _mapManager.FindGridsIntersecting(mapId, targetAABB))
|
||||
{
|
||||
if (!nearbyGrids.Add(grid.Owner)) continue;
|
||||
if (!nearbyGrids.Add(grid.Owner))
|
||||
continue;
|
||||
|
||||
targetAABB = targetAABB.Union(_transform.GetWorldMatrix(grid.Owner, xformQuery)
|
||||
.TransformBox(Comp<MapGridComponent>(grid.Owner).LocalAABB));
|
||||
@@ -557,7 +572,8 @@ public sealed partial class ShuttleSystem
|
||||
foreach (var grid in _mapManager.GetAllGrids())
|
||||
{
|
||||
// Don't add anymore as it is irrelevant, but that doesn't mean we need to re-do existing work.
|
||||
if (nearbyGrids.Contains(grid.Owner)) continue;
|
||||
if (nearbyGrids.Contains(grid.Owner))
|
||||
continue;
|
||||
|
||||
targetAABB = targetAABB.Union(_transform.GetWorldMatrix(grid.Owner, xformQuery)
|
||||
.TransformBox(Comp<MapGridComponent>(grid.Owner).LocalAABB));
|
||||
@@ -568,10 +584,10 @@ public sealed partial class ShuttleSystem
|
||||
|
||||
Vector2 spawnPos;
|
||||
|
||||
if (TryComp<PhysicsComponent>(component.Owner, out var shuttleBody))
|
||||
if (TryComp<PhysicsComponent>(shuttleUid, out var shuttleBody))
|
||||
{
|
||||
_physics.SetLinearVelocity(component.Owner, Vector2.Zero, body: shuttleBody);
|
||||
_physics.SetAngularVelocity(component.Owner, 0f, body: shuttleBody);
|
||||
_physics.SetLinearVelocity(shuttleUid, Vector2.Zero, body: shuttleBody);
|
||||
_physics.SetAngularVelocity(shuttleUid, 0f, body: shuttleBody);
|
||||
}
|
||||
|
||||
// TODO: This is pretty crude for multiple landings.
|
||||
@@ -604,138 +620,4 @@ public sealed partial class ShuttleSystem
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks whether the emergency shuttle can warp to the specified position.
|
||||
/// </summary>
|
||||
private bool ValidSpawn(EntityUid gridUid, MapGridComponent grid, Box2 area)
|
||||
{
|
||||
// If the target is a map then any tile is valid.
|
||||
// TODO: We already need the entities-under check
|
||||
if (HasComp<MapComponent>(gridUid))
|
||||
return true;
|
||||
|
||||
return !grid.GetLocalTilesIntersecting(area).Any();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tries to get a valid docking configuration for the shuttle to the target grid.
|
||||
/// </summary>
|
||||
/// <param name="priorityTag">Priority docking tag to prefer, e.g. for emergency shuttle</param>
|
||||
private DockingConfig? GetDockingConfig(ShuttleComponent component, EntityUid targetGrid, string? priorityTag = null)
|
||||
{
|
||||
var gridDocks = GetDocks(targetGrid);
|
||||
|
||||
if (gridDocks.Count <= 0)
|
||||
return null;
|
||||
|
||||
var xformQuery = GetEntityQuery<TransformComponent>();
|
||||
var targetGridGrid = Comp<MapGridComponent>(targetGrid);
|
||||
var targetGridXform = xformQuery.GetComponent(targetGrid);
|
||||
var targetGridAngle = targetGridXform.WorldRotation.Reduced();
|
||||
|
||||
var shuttleDocks = GetDocks(component.Owner);
|
||||
var shuttleAABB = Comp<MapGridComponent>(component.Owner).LocalAABB;
|
||||
|
||||
var validDockConfigs = new List<DockingConfig>();
|
||||
|
||||
if (shuttleDocks.Count > 0)
|
||||
{
|
||||
// We'll try all combinations of shuttle docks and see which one is most suitable
|
||||
foreach (var shuttleDock in shuttleDocks)
|
||||
{
|
||||
var shuttleDockXform = xformQuery.GetComponent(shuttleDock.Owner);
|
||||
|
||||
foreach (var gridDock in gridDocks)
|
||||
{
|
||||
var gridXform = xformQuery.GetComponent(gridDock.Owner);
|
||||
|
||||
if (!CanDock(
|
||||
shuttleDock, shuttleDockXform,
|
||||
gridDock, gridXform,
|
||||
targetGridAngle,
|
||||
shuttleAABB,
|
||||
targetGrid,
|
||||
targetGridGrid,
|
||||
out var dockedAABB,
|
||||
out var matty,
|
||||
out var targetAngle)) continue;
|
||||
|
||||
// Can't just use the AABB as we want to get bounds as tight as possible.
|
||||
var spawnPosition = new EntityCoordinates(targetGrid, matty.Transform(Vector2.Zero));
|
||||
spawnPosition = new EntityCoordinates(targetGridXform.MapUid!.Value, spawnPosition.ToMapPos(EntityManager));
|
||||
|
||||
var dockedBounds = new Box2Rotated(shuttleAABB.Translated(spawnPosition.Position), targetGridAngle, spawnPosition.Position);
|
||||
|
||||
// Check if there's no intersecting grids (AKA oh god it's docking at cargo).
|
||||
if (_mapManager.FindGridsIntersecting(targetGridXform.MapID,
|
||||
dockedBounds).Any(o => o.Owner != targetGrid))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// Alright well the spawn is valid now to check how many we can connect
|
||||
// Get the matrix for each shuttle dock and test it against the grid docks to see
|
||||
// if the connected position / direction matches.
|
||||
|
||||
var dockedPorts = new List<(DockingComponent DockA, DockingComponent DockB)>()
|
||||
{
|
||||
(shuttleDock, gridDock),
|
||||
};
|
||||
|
||||
foreach (var other in shuttleDocks)
|
||||
{
|
||||
if (other == shuttleDock) continue;
|
||||
|
||||
foreach (var otherGrid in gridDocks)
|
||||
{
|
||||
if (otherGrid == gridDock) continue;
|
||||
|
||||
if (!CanDock(
|
||||
other,
|
||||
xformQuery.GetComponent(other.Owner),
|
||||
otherGrid,
|
||||
xformQuery.GetComponent(otherGrid.Owner),
|
||||
targetGridAngle,
|
||||
shuttleAABB,
|
||||
targetGrid,
|
||||
targetGridGrid,
|
||||
out var otherDockedAABB,
|
||||
out _,
|
||||
out var otherTargetAngle) ||
|
||||
!otherDockedAABB.Equals(dockedAABB) ||
|
||||
!targetAngle.Equals(otherTargetAngle)) continue;
|
||||
|
||||
dockedPorts.Add((other, otherGrid));
|
||||
}
|
||||
}
|
||||
|
||||
validDockConfigs.Add(new DockingConfig()
|
||||
{
|
||||
Docks = dockedPorts,
|
||||
Area = dockedAABB.Value,
|
||||
Coordinates = spawnPosition,
|
||||
Angle = targetAngle,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (validDockConfigs.Count <= 0)
|
||||
return null;
|
||||
|
||||
// Prioritise by priority docks, then by maximum connected ports, then by most similar angle.
|
||||
validDockConfigs = validDockConfigs
|
||||
.OrderByDescending(x => x.Docks.Any(docks =>
|
||||
TryComp<PriorityDockComponent>(docks.DockB.Owner, out var priority) &&
|
||||
priority.Tag?.Equals(priorityTag) == true))
|
||||
.ThenByDescending(x => x.Docks.Count)
|
||||
.ThenBy(x => Math.Abs(Angle.ShortestDistance(x.Angle.Reduced(), targetGridAngle).Theta)).ToList();
|
||||
|
||||
var location = validDockConfigs.First();
|
||||
location.TargetGrid = targetGrid;
|
||||
// TODO: Ideally do a hyperspace warpin, just have it run on like a 10 second timer.
|
||||
|
||||
return location;
|
||||
}
|
||||
}
|
||||
|
||||
69
Content.Server/Shuttles/Systems/ShuttleSystem.GridFill.cs
Normal file
69
Content.Server/Shuttles/Systems/ShuttleSystem.GridFill.cs
Normal file
@@ -0,0 +1,69 @@
|
||||
using Content.Server.Shuttles.Components;
|
||||
|
||||
namespace Content.Server.Shuttles.Systems;
|
||||
|
||||
public sealed partial class ShuttleSystem
|
||||
{
|
||||
private void InitializeGridFills()
|
||||
{
|
||||
SubscribeLocalEvent<GridFillComponent, MapInitEvent>(OnGridFillMapInit);
|
||||
}
|
||||
|
||||
private void OnGridFillMapInit(EntityUid uid, GridFillComponent component, MapInitEvent args)
|
||||
{
|
||||
if (!TryComp<DockingComponent>(uid, out var dock) ||
|
||||
!TryComp<TransformComponent>(uid, out var xform) ||
|
||||
xform.GridUid == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Spawn on a dummy map and try to dock if possible, otherwise dump it.
|
||||
var mapId = _mapManager.CreateMap();
|
||||
var valid = false;
|
||||
|
||||
if (_loader.TryLoad(mapId, component.Path.ToString(), out var ent) &&
|
||||
ent.Count == 1 &&
|
||||
TryComp<TransformComponent>(ent[0], out var shuttleXform))
|
||||
{
|
||||
var escape = GetSingleDock(ent[0]);
|
||||
|
||||
if (escape != null)
|
||||
{
|
||||
var config = _dockSystem.GetDockingConfig(ent[0], xform.GridUid.Value, escape.Value.Entity, escape.Value.Component, uid, dock);
|
||||
|
||||
if (config != null)
|
||||
{
|
||||
FTLDock(config, shuttleXform);
|
||||
valid = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!valid)
|
||||
{
|
||||
_sawmill.Error($"Error loading gridfill dock for {ToPrettyString(uid)} / {component.Path}");
|
||||
}
|
||||
|
||||
_mapManager.DeleteMap(mapId);
|
||||
}
|
||||
|
||||
private (EntityUid Entity, DockingComponent Component)? GetSingleDock(EntityUid uid)
|
||||
{
|
||||
var dockQuery = GetEntityQuery<DockingComponent>();
|
||||
var xformQuery = GetEntityQuery<TransformComponent>();
|
||||
var xform = xformQuery.GetComponent(uid);
|
||||
|
||||
var rator = xform.ChildEnumerator;
|
||||
|
||||
while (rator.MoveNext(out var child))
|
||||
{
|
||||
if (!dockQuery.TryGetComponent(child, out var dock))
|
||||
continue;
|
||||
|
||||
return (child.Value, dock);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -1,15 +1,16 @@
|
||||
using Content.Server.Doors.Systems;
|
||||
using Content.Server.Shuttles.Components;
|
||||
using Content.Shared.CCVar;
|
||||
using Content.Server.Stunnable;
|
||||
using Content.Shared.GameTicking;
|
||||
using Content.Shared.Shuttles.Systems;
|
||||
using JetBrains.Annotations;
|
||||
using Robust.Server.GameObjects;
|
||||
using Robust.Shared.Configuration;
|
||||
using Robust.Shared.Map;
|
||||
using Robust.Shared.Map.Components;
|
||||
using Robust.Shared.Physics;
|
||||
using Robust.Shared.Physics.Components;
|
||||
using Robust.Shared.Physics.Systems;
|
||||
using Robust.Shared.Random;
|
||||
|
||||
namespace Content.Server.Shuttles.Systems
|
||||
{
|
||||
@@ -17,9 +18,18 @@ namespace Content.Server.Shuttles.Systems
|
||||
public sealed partial class ShuttleSystem : SharedShuttleSystem
|
||||
{
|
||||
[Dependency] private readonly IMapManager _mapManager = default!;
|
||||
[Dependency] private readonly IRobustRandom _random = default!;
|
||||
[Dependency] private readonly AirlockSystem _airlock = default!;
|
||||
[Dependency] private readonly DockingSystem _dockSystem = default!;
|
||||
[Dependency] private readonly DoorSystem _doors = default!;
|
||||
[Dependency] private readonly FixtureSystem _fixtures = default!;
|
||||
[Dependency] private readonly MapLoaderSystem _loader = default!;
|
||||
[Dependency] private readonly SharedAudioSystem _audio = default!;
|
||||
[Dependency] private readonly SharedPhysicsSystem _physics = default!;
|
||||
[Dependency] private readonly SharedTransformSystem _transform = default!;
|
||||
[Dependency] private readonly ShuttleConsoleSystem _console = default!;
|
||||
[Dependency] private readonly StunSystem _stuns = default!;
|
||||
[Dependency] private readonly ThrusterSystem _thruster = default!;
|
||||
[Dependency] private readonly UserInterfaceSystem _uiSystem = default!;
|
||||
|
||||
private ISawmill _sawmill = default!;
|
||||
@@ -34,9 +44,8 @@ namespace Content.Server.Shuttles.Systems
|
||||
base.Initialize();
|
||||
_sawmill = Logger.GetSawmill("shuttles");
|
||||
|
||||
InitializeEmergencyConsole();
|
||||
InitializeEscape();
|
||||
InitializeFTL();
|
||||
InitializeGridFills();
|
||||
InitializeIFF();
|
||||
InitializeImpact();
|
||||
|
||||
@@ -53,24 +62,14 @@ namespace Content.Server.Shuttles.Systems
|
||||
public override void Update(float frameTime)
|
||||
{
|
||||
base.Update(frameTime);
|
||||
UpdateEmergencyConsole(frameTime);
|
||||
UpdateHyperspace(frameTime);
|
||||
}
|
||||
|
||||
private void OnRoundRestart(RoundRestartCleanupEvent ev)
|
||||
{
|
||||
CleanupEmergencyConsole();
|
||||
CleanupEmergencyShuttle();
|
||||
CleanupHyperspace();
|
||||
}
|
||||
|
||||
public override void Shutdown()
|
||||
{
|
||||
base.Shutdown();
|
||||
ShutdownEscape();
|
||||
ShutdownEmergencyConsole();
|
||||
}
|
||||
|
||||
private void OnShuttleAdd(EntityUid uid, ShuttleComponent component, ComponentAdd args)
|
||||
{
|
||||
// Easier than doing it in the comp and they don't have constructors.
|
||||
@@ -83,7 +82,8 @@ namespace Content.Server.Shuttles.Systems
|
||||
private void OnGridFixtureChange(GridFixtureChangeEvent args)
|
||||
{
|
||||
// Look this is jank but it's a placeholder until we design it.
|
||||
if (args.NewFixtures.Count == 0) return;
|
||||
if (args.NewFixtures.Count == 0)
|
||||
return;
|
||||
|
||||
var uid = args.NewFixtures[0].Body.Owner;
|
||||
var manager = Comp<FixturesComponent>(uid);
|
||||
@@ -107,12 +107,12 @@ namespace Content.Server.Shuttles.Systems
|
||||
|
||||
private void OnShuttleStartup(EntityUid uid, ShuttleComponent component, ComponentStartup args)
|
||||
{
|
||||
if (!EntityManager.HasComponent<MapGridComponent>(component.Owner))
|
||||
if (!EntityManager.HasComponent<MapGridComponent>(uid))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!EntityManager.TryGetComponent(component.Owner, out PhysicsComponent? physicsComponent))
|
||||
if (!EntityManager.TryGetComponent(uid, out PhysicsComponent? physicsComponent))
|
||||
{
|
||||
return;
|
||||
}
|
||||
@@ -125,7 +125,8 @@ namespace Content.Server.Shuttles.Systems
|
||||
|
||||
public void Toggle(EntityUid uid, ShuttleComponent component)
|
||||
{
|
||||
if (!EntityManager.TryGetComponent(component.Owner, out PhysicsComponent? physicsComponent)) return;
|
||||
if (!EntityManager.TryGetComponent(uid, out PhysicsComponent? physicsComponent))
|
||||
return;
|
||||
|
||||
component.Enabled = !component.Enabled;
|
||||
|
||||
@@ -164,7 +165,7 @@ namespace Content.Server.Shuttles.Systems
|
||||
// None of the below is necessary for any cleanup if we're just deleting.
|
||||
if (EntityManager.GetComponent<MetaDataComponent>(uid).EntityLifeStage >= EntityLifeStage.Terminating) return;
|
||||
|
||||
if (!EntityManager.TryGetComponent(component.Owner, out PhysicsComponent? physicsComponent))
|
||||
if (!EntityManager.TryGetComponent(uid, out PhysicsComponent? physicsComponent))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -28,6 +28,6 @@ public sealed class StationDataComponent : Component
|
||||
/// <summary>
|
||||
/// The emergency shuttle assigned to this station.
|
||||
/// </summary>
|
||||
[ViewVariables, Access(typeof(ShuttleSystem), Friend = AccessPermissions.ReadWrite)]
|
||||
[ViewVariables, Access(typeof(ShuttleSystem), typeof(EmergencyShuttleSystem), Friend = AccessPermissions.ReadWrite)]
|
||||
public EntityUid? EmergencyShuttle;
|
||||
}
|
||||
|
||||
@@ -68,12 +68,12 @@ namespace Content.Shared.Popups
|
||||
public abstract void PopupEntity(string message, EntityUid uid, PopupType type=PopupType.Small);
|
||||
|
||||
/// <summary>
|
||||
/// Variant of <see cref="PopupEntity(string, EntityUid, PopupType)"/> that shoes the popup only to some specific client.
|
||||
/// Variant of <see cref="PopupEntity(string, EntityUid, PopupType)"/> that shows the popup only to some specific client.
|
||||
/// </summary>
|
||||
public abstract void PopupEntity(string message, EntityUid uid, EntityUid recipient, PopupType type = PopupType.Small);
|
||||
|
||||
/// <summary>
|
||||
/// Variant of <see cref="PopupEntity(string, EntityUid, PopupType)"/> that shoes the popup only to some specific client.
|
||||
/// Variant of <see cref="PopupEntity(string, EntityUid, PopupType)"/> that shows the popup only to some specific client.
|
||||
/// </summary>
|
||||
public abstract void PopupEntity(string message, EntityUid uid, ICommonSession recipient, PopupType type = PopupType.Small);
|
||||
|
||||
|
||||
406
Resources/Maps/Shuttles/escape_pod_small.yml
Normal file
406
Resources/Maps/Shuttles/escape_pod_small.yml
Normal file
@@ -0,0 +1,406 @@
|
||||
meta:
|
||||
format: 3
|
||||
name: DemoStation
|
||||
author: Space-Wizards
|
||||
postmapinit: false
|
||||
tilemap:
|
||||
0: Space
|
||||
1: FloorArcadeBlue
|
||||
2: FloorArcadeBlue2
|
||||
3: FloorArcadeRed
|
||||
4: FloorAsteroidCoarseSand0
|
||||
5: FloorAsteroidCoarseSandDug
|
||||
6: FloorAsteroidIronsand1
|
||||
7: FloorAsteroidIronsand2
|
||||
8: FloorAsteroidIronsand3
|
||||
9: FloorAsteroidIronsand4
|
||||
10: FloorAsteroidSand
|
||||
11: FloorAsteroidTile
|
||||
12: FloorBar
|
||||
13: FloorBasalt
|
||||
14: FloorBlue
|
||||
15: FloorBlueCircuit
|
||||
16: FloorBoxing
|
||||
17: FloorCarpetClown
|
||||
18: FloorCarpetOffice
|
||||
19: FloorCave
|
||||
20: FloorCaveDrought
|
||||
21: FloorClown
|
||||
22: FloorDark
|
||||
23: FloorDarkDiagonal
|
||||
24: FloorDarkDiagonalMini
|
||||
25: FloorDarkHerringbone
|
||||
26: FloorDarkMini
|
||||
27: FloorDarkMono
|
||||
28: FloorDarkOffset
|
||||
29: FloorDarkPavement
|
||||
30: FloorDarkPavementVertical
|
||||
31: FloorDarkPlastic
|
||||
32: FloorDesert
|
||||
33: FloorDirt
|
||||
34: FloorEighties
|
||||
35: FloorElevatorShaft
|
||||
36: FloorFlesh
|
||||
37: FloorFreezer
|
||||
38: FloorGlass
|
||||
39: FloorGold
|
||||
40: FloorGrass
|
||||
41: FloorGrassDark
|
||||
42: FloorGrassJungle
|
||||
43: FloorGrassLight
|
||||
44: FloorGreenCircuit
|
||||
45: FloorGym
|
||||
46: FloorHydro
|
||||
47: FloorKitchen
|
||||
48: FloorLaundry
|
||||
49: FloorLino
|
||||
50: FloorLowDesert
|
||||
51: FloorMetalDiamond
|
||||
52: FloorMime
|
||||
53: FloorMono
|
||||
54: FloorPlanetDirt
|
||||
55: FloorPlanetGrass
|
||||
56: FloorPlastic
|
||||
57: FloorRGlass
|
||||
58: FloorReinforced
|
||||
59: FloorRockVault
|
||||
60: FloorShowroom
|
||||
61: FloorShuttleBlue
|
||||
62: FloorShuttleOrange
|
||||
63: FloorShuttlePurple
|
||||
64: FloorShuttleRed
|
||||
65: FloorShuttleWhite
|
||||
66: FloorSilver
|
||||
67: FloorSnow
|
||||
68: FloorSteel
|
||||
69: FloorSteelDiagonal
|
||||
70: FloorSteelDiagonalMini
|
||||
71: FloorSteelDirty
|
||||
72: FloorSteelHerringbone
|
||||
73: FloorSteelMini
|
||||
74: FloorSteelMono
|
||||
75: FloorSteelOffset
|
||||
76: FloorSteelPavement
|
||||
77: FloorSteelPavementVertical
|
||||
78: FloorTechMaint
|
||||
79: FloorTechMaint2
|
||||
80: FloorTechMaint3
|
||||
81: FloorWhite
|
||||
82: FloorWhiteDiagonal
|
||||
83: FloorWhiteDiagonalMini
|
||||
84: FloorWhiteHerringbone
|
||||
85: FloorWhiteMini
|
||||
86: FloorWhiteMono
|
||||
87: FloorWhiteOffset
|
||||
88: FloorWhitePavement
|
||||
89: FloorWhitePavementVertical
|
||||
90: FloorWhitePlastic
|
||||
91: FloorWood
|
||||
92: FloorWoodTile
|
||||
93: Lattice
|
||||
94: Plating
|
||||
entities:
|
||||
- uid: 0
|
||||
components:
|
||||
- type: MetaData
|
||||
- type: EscapePod
|
||||
- parent: invalid
|
||||
type: Transform
|
||||
- chunks:
|
||||
-1,-1:
|
||||
ind: -1,-1
|
||||
tiles: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAF4AAAA+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABeAAAAPQAAAA==
|
||||
0,0:
|
||||
ind: 0,0
|
||||
tiles: XgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAF0AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==
|
||||
-1,0:
|
||||
ind: -1,0
|
||||
tiles: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABeAAAAPQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAXQAAAF4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==
|
||||
0,-1:
|
||||
ind: 0,-1
|
||||
tiles: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABeAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAXgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==
|
||||
type: MapGrid
|
||||
- type: Broadphase
|
||||
- angularDamping: 0.05
|
||||
linearDamping: 0.05
|
||||
fixedRotation: False
|
||||
bodyType: Dynamic
|
||||
type: Physics
|
||||
- fixtures: []
|
||||
type: Fixtures
|
||||
- id: Empty
|
||||
type: BecomesStation
|
||||
- type: OccluderTree
|
||||
- type: Shuttle
|
||||
- nextUpdate: 88.8784752
|
||||
type: GridPathfinding
|
||||
- gravityShakeSound: !type:SoundPathSpecifier
|
||||
path: /Audio/Effects/alert.ogg
|
||||
type: Gravity
|
||||
- chunkCollection:
|
||||
version: 2
|
||||
nodes: []
|
||||
type: DecalGrid
|
||||
- version: 2
|
||||
data:
|
||||
tiles:
|
||||
-1,-1:
|
||||
0: 52224
|
||||
0,0:
|
||||
0: 1
|
||||
-1,0:
|
||||
0: 12
|
||||
0,-1:
|
||||
0: 4352
|
||||
uniqueMixes:
|
||||
- volume: 2500
|
||||
temperature: 293.15
|
||||
moles:
|
||||
- 21.824879
|
||||
- 82.10312
|
||||
- 0
|
||||
- 0
|
||||
- 0
|
||||
- 0
|
||||
- 0
|
||||
- 0
|
||||
- 0
|
||||
- 0
|
||||
- 0
|
||||
- 0
|
||||
chunkSize: 4
|
||||
type: GridAtmosphere
|
||||
- type: GasTileOverlay
|
||||
- type: RadiationGridResistance
|
||||
- uid: 1
|
||||
type: WallShuttle
|
||||
components:
|
||||
- pos: -1.5,-0.5
|
||||
parent: 0
|
||||
type: Transform
|
||||
- uid: 2
|
||||
type: WallShuttle
|
||||
components:
|
||||
- pos: -1.5,0.5
|
||||
parent: 0
|
||||
type: Transform
|
||||
- uid: 3
|
||||
type: WallShuttle
|
||||
components:
|
||||
- pos: 0.5,-0.5
|
||||
parent: 0
|
||||
type: Transform
|
||||
- uid: 4
|
||||
type: WallShuttle
|
||||
components:
|
||||
- pos: 0.5,0.5
|
||||
parent: 0
|
||||
type: Transform
|
||||
- uid: 5
|
||||
type: WallShuttleDiagonal
|
||||
components:
|
||||
- pos: -1.5,1.5
|
||||
parent: 0
|
||||
type: Transform
|
||||
- uid: 6
|
||||
type: WallShuttleDiagonal
|
||||
components:
|
||||
- rot: -1.5707963267948966 rad
|
||||
pos: 0.5,1.5
|
||||
parent: 0
|
||||
type: Transform
|
||||
- uid: 7
|
||||
type: ShuttleWindow
|
||||
components:
|
||||
- pos: -0.5,1.5
|
||||
parent: 0
|
||||
type: Transform
|
||||
- uid: 8
|
||||
type: Grille
|
||||
components:
|
||||
- pos: -0.5,1.5
|
||||
parent: 0
|
||||
type: Transform
|
||||
- uid: 9
|
||||
type: AtmosDeviceFanTiny
|
||||
components:
|
||||
- pos: -0.5,-1.5
|
||||
parent: 0
|
||||
type: Transform
|
||||
- uid: 10
|
||||
type: Thruster
|
||||
components:
|
||||
- rot: 3.141592653589793 rad
|
||||
pos: -1.5,-1.5
|
||||
parent: 0
|
||||
type: Transform
|
||||
- bodyType: Static
|
||||
type: Physics
|
||||
- uid: 11
|
||||
type: Thruster
|
||||
components:
|
||||
- rot: 3.141592653589793 rad
|
||||
pos: 0.5,-1.5
|
||||
parent: 0
|
||||
type: Transform
|
||||
- bodyType: Static
|
||||
type: Physics
|
||||
- uid: 12
|
||||
type: AirlockExternalShuttleLocked
|
||||
components:
|
||||
- pos: -0.5,-1.5
|
||||
parent: 0
|
||||
type: Transform
|
||||
- fixtures:
|
||||
- shape: !type:PolygonShape
|
||||
radius: 0.01
|
||||
vertices:
|
||||
- 0.49,-0.49
|
||||
- 0.49,0.49
|
||||
- -0.49,0.49
|
||||
- -0.49,-0.49
|
||||
mask:
|
||||
- Impassable
|
||||
- MidImpassable
|
||||
- HighImpassable
|
||||
- LowImpassable
|
||||
- InteractImpassable
|
||||
layer:
|
||||
- MidImpassable
|
||||
- HighImpassable
|
||||
- BulletImpassable
|
||||
- InteractImpassable
|
||||
- Opaque
|
||||
density: 100
|
||||
hard: True
|
||||
restitution: 0
|
||||
friction: 0.4
|
||||
id: null
|
||||
- shape: !type:PhysShapeCircle
|
||||
radius: 0.2
|
||||
position: 0,-0.5
|
||||
mask: []
|
||||
layer: []
|
||||
density: 1
|
||||
hard: False
|
||||
restitution: 0
|
||||
friction: 0.4
|
||||
id: docking
|
||||
type: Fixtures
|
||||
- uid: 13
|
||||
type: GeneratorWallmountAPU
|
||||
components:
|
||||
- pos: -1.5,-0.5
|
||||
parent: 0
|
||||
type: Transform
|
||||
- uid: 14
|
||||
type: SubstationWallBasic
|
||||
components:
|
||||
- pos: 0.5,-0.5
|
||||
parent: 0
|
||||
type: Transform
|
||||
- uid: 15
|
||||
type: APCBasic
|
||||
components:
|
||||
- rot: 1.5707963267948966 rad
|
||||
pos: -1.5,0.5
|
||||
parent: 0
|
||||
type: Transform
|
||||
- uid: 16
|
||||
type: CableHV
|
||||
components:
|
||||
- pos: -1.5,-0.5
|
||||
parent: 0
|
||||
type: Transform
|
||||
- enabled: True
|
||||
type: AmbientSound
|
||||
- uid: 17
|
||||
type: CableHV
|
||||
components:
|
||||
- pos: -0.5,-0.5
|
||||
parent: 0
|
||||
type: Transform
|
||||
- uid: 18
|
||||
type: CableHV
|
||||
components:
|
||||
- pos: 0.5,-0.5
|
||||
parent: 0
|
||||
type: Transform
|
||||
- enabled: True
|
||||
type: AmbientSound
|
||||
- uid: 19
|
||||
type: CableMV
|
||||
components:
|
||||
- pos: 0.5,-0.5
|
||||
parent: 0
|
||||
type: Transform
|
||||
- enabled: True
|
||||
type: AmbientSound
|
||||
- uid: 20
|
||||
type: CableMV
|
||||
components:
|
||||
- pos: -0.5,-0.5
|
||||
parent: 0
|
||||
type: Transform
|
||||
- uid: 21
|
||||
type: CableMV
|
||||
components:
|
||||
- pos: -0.5,0.5
|
||||
parent: 0
|
||||
type: Transform
|
||||
- uid: 22
|
||||
type: CableMV
|
||||
components:
|
||||
- pos: -1.5,0.5
|
||||
parent: 0
|
||||
type: Transform
|
||||
- enabled: True
|
||||
type: AmbientSound
|
||||
- uid: 23
|
||||
type: CableApcExtension
|
||||
components:
|
||||
- pos: -1.5,0.5
|
||||
parent: 0
|
||||
type: Transform
|
||||
- enabled: True
|
||||
type: AmbientSound
|
||||
- uid: 24
|
||||
type: CableApcExtension
|
||||
components:
|
||||
- pos: -0.5,0.5
|
||||
parent: 0
|
||||
type: Transform
|
||||
- uid: 25
|
||||
type: CableApcExtension
|
||||
components:
|
||||
- pos: -0.5,-0.5
|
||||
parent: 0
|
||||
type: Transform
|
||||
- uid: 26
|
||||
type: ChairPilotSeat
|
||||
components:
|
||||
- rot: 3.141592653589793 rad
|
||||
pos: -0.5,-0.5
|
||||
parent: 0
|
||||
type: Transform
|
||||
- bodyType: Static
|
||||
type: Physics
|
||||
- uid: 27
|
||||
type: ChairPilotSeat
|
||||
components:
|
||||
- rot: 3.141592653589793 rad
|
||||
pos: -0.5,0.5
|
||||
parent: 0
|
||||
type: Transform
|
||||
- bodyType: Static
|
||||
type: Physics
|
||||
- uid: 28
|
||||
type: PoweredSmallLight
|
||||
components:
|
||||
- rot: 1.5707963267948966 rad
|
||||
pos: -0.5,-0.5
|
||||
parent: 0
|
||||
type: Transform
|
||||
- powerLoad: 0
|
||||
type: ApcPowerReceiver
|
||||
...
|
||||
@@ -740,6 +740,13 @@
|
||||
- type: PriorityDock
|
||||
tag: DockArrivals
|
||||
|
||||
- type: entity
|
||||
parent: AirlockGlassShuttle
|
||||
id: AirlockExternalGlassShuttleEscape
|
||||
suffix: External, Escape 3x4, Glass, Docking
|
||||
components:
|
||||
- type: GridFill
|
||||
|
||||
#HighSecDoors
|
||||
- type: entity
|
||||
parent: HighSecDoor
|
||||
|
||||
Reference in New Issue
Block a user