Add FTL destinations (#9685)
This commit is contained in:
@@ -22,8 +22,6 @@ namespace Content.Client.Nutrition.Components
|
|||||||
}
|
}
|
||||||
|
|
||||||
_currentHungerThreshold = hunger.CurrentThreshold;
|
_currentHungerThreshold = hunger.CurrentThreshold;
|
||||||
|
|
||||||
EntitySystem.Get<MovementSpeedModifierSystem>().RefreshMovementSpeedModifiers(Owner);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,10 +22,19 @@ public sealed class ShuttleConsoleBoundUserInterface : BoundUserInterface
|
|||||||
_window.UndockPressed += OnUndockPressed;
|
_window.UndockPressed += OnUndockPressed;
|
||||||
_window.StartAutodockPressed += OnAutodockPressed;
|
_window.StartAutodockPressed += OnAutodockPressed;
|
||||||
_window.StopAutodockPressed += OnStopAutodockPressed;
|
_window.StopAutodockPressed += OnStopAutodockPressed;
|
||||||
|
_window.DestinationPressed += OnDestinationPressed;
|
||||||
_window.OpenCentered();
|
_window.OpenCentered();
|
||||||
_window.OnClose += OnClose;
|
_window.OnClose += OnClose;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void OnDestinationPressed(EntityUid obj)
|
||||||
|
{
|
||||||
|
SendMessage(new ShuttleConsoleDestinationMessage()
|
||||||
|
{
|
||||||
|
Destination = obj,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
private void OnClose()
|
private void OnClose()
|
||||||
{
|
{
|
||||||
Close();
|
Close();
|
||||||
|
|||||||
@@ -35,6 +35,11 @@ public sealed class RadarControl : Control
|
|||||||
private float _radarMaxRange = 256f;
|
private float _radarMaxRange = 256f;
|
||||||
public float RadarRange { get; private set; } = 256f;
|
public float RadarRange { get; private set; } = 256f;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Controls the maximum distance that IFF labels will display.
|
||||||
|
/// </summary>
|
||||||
|
public float MaxRadarRange { get; private set; } = 256f * 10f;
|
||||||
|
|
||||||
private int MidPoint => SizeFull / 2;
|
private int MidPoint => SizeFull / 2;
|
||||||
private int SizeFull => (int) ((MinimapRadius + MinimapMargin) * 2 * UIScale);
|
private int SizeFull => (int) ((MinimapRadius + MinimapMargin) * 2 * UIScale);
|
||||||
private int ScaledMinimapRadius => (int) (MinimapRadius * UIScale);
|
private int ScaledMinimapRadius => (int) (MinimapRadius * UIScale);
|
||||||
@@ -182,7 +187,7 @@ public sealed class RadarControl : Control
|
|||||||
|
|
||||||
// Draw other grids... differently
|
// Draw other grids... differently
|
||||||
foreach (var grid in _mapManager.FindGridsIntersecting(mapPosition.MapId,
|
foreach (var grid in _mapManager.FindGridsIntersecting(mapPosition.MapId,
|
||||||
new Box2(mapPosition.Position - RadarRange, mapPosition.Position + RadarRange)))
|
new Box2(mapPosition.Position - MaxRadarRange, mapPosition.Position + MaxRadarRange)))
|
||||||
{
|
{
|
||||||
if (grid.GridEntityId == ourGridId) continue;
|
if (grid.GridEntityId == ourGridId) continue;
|
||||||
|
|
||||||
@@ -206,19 +211,25 @@ public sealed class RadarControl : Control
|
|||||||
|
|
||||||
if (ShowIFF)
|
if (ShowIFF)
|
||||||
{
|
{
|
||||||
|
Label label;
|
||||||
|
|
||||||
if (!_iffControls.TryGetValue(grid.GridEntityId, out var control))
|
if (!_iffControls.TryGetValue(grid.GridEntityId, out var control))
|
||||||
{
|
{
|
||||||
var label = new Label()
|
label = new Label()
|
||||||
{
|
{
|
||||||
HorizontalAlignment = HAlignment.Left,
|
HorizontalAlignment = HAlignment.Left,
|
||||||
|
FontColorOverride = Color.Aquamarine,
|
||||||
};
|
};
|
||||||
|
|
||||||
control = new PanelContainer()
|
control = new PanelContainer()
|
||||||
{
|
{
|
||||||
HorizontalAlignment = HAlignment.Left,
|
HorizontalAlignment = HAlignment.Center,
|
||||||
VerticalAlignment = VAlignment.Top,
|
VerticalAlignment = VAlignment.Center,
|
||||||
Children = { label },
|
Children =
|
||||||
StyleClasses = { StyleNano.StyleClassTooltipPanel },
|
{
|
||||||
|
label
|
||||||
|
},
|
||||||
|
StyleClasses = { StyleNano.StyleClassBorderedWindowPanel },
|
||||||
};
|
};
|
||||||
|
|
||||||
_iffControls[grid.GridEntityId] = control;
|
_iffControls[grid.GridEntityId] = control;
|
||||||
@@ -227,20 +238,17 @@ public sealed class RadarControl : Control
|
|||||||
|
|
||||||
var gridCentre = matty.Transform(gridBody.LocalCenter);
|
var gridCentre = matty.Transform(gridBody.LocalCenter);
|
||||||
gridCentre.Y = -gridCentre.Y;
|
gridCentre.Y = -gridCentre.Y;
|
||||||
|
var distance = gridCentre.Length;
|
||||||
|
|
||||||
// TODO: When we get IFF or whatever we can show controls at a further distance; for now
|
if (gridCentre.Length > RadarRange)
|
||||||
// we don't do that because it would immediately reveal nukies.
|
|
||||||
if (gridCentre.Length < RadarRange)
|
|
||||||
{
|
{
|
||||||
control.Visible = true;
|
gridCentre = gridCentre.Normalized * RadarRange;
|
||||||
var label = (Label) control.GetChild(0);
|
|
||||||
label.Text = Loc.GetString("shuttle-console-iff-label", ("name", name), ("distance", $"{gridCentre.Length:0.0}"));
|
|
||||||
LayoutContainer.SetPosition(control, ScalePosition(gridCentre) / UIScale);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
control.Visible = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
control.Visible = true;
|
||||||
|
label = (Label) control.GetChild(0);
|
||||||
|
label.Text = Loc.GetString("shuttle-console-iff-label", ("name", name), ("distance", $"{distance:0.0}"));
|
||||||
|
LayoutContainer.SetPosition(control, ScalePosition(gridCentre) / UIScale);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -4,7 +4,8 @@
|
|||||||
xmlns:ui1="clr-namespace:Content.Client.HUD.UI"
|
xmlns:ui1="clr-namespace:Content.Client.HUD.UI"
|
||||||
Title="{Loc 'shuttle-console-window-title'}">
|
Title="{Loc 'shuttle-console-window-title'}">
|
||||||
<GridContainer Columns="3"
|
<GridContainer Columns="3"
|
||||||
HorizontalAlignment="Stretch">
|
HorizontalAlignment="Stretch"
|
||||||
|
Margin="5 5 5 5">
|
||||||
<BoxContainer Name="LeftDisplay"
|
<BoxContainer Name="LeftDisplay"
|
||||||
VerticalAlignment="Top"
|
VerticalAlignment="Top"
|
||||||
HorizontalAlignment="Left"
|
HorizontalAlignment="Left"
|
||||||
@@ -19,6 +20,14 @@
|
|||||||
Orientation="Vertical">
|
Orientation="Vertical">
|
||||||
</BoxContainer>
|
</BoxContainer>
|
||||||
</BoxContainer>
|
</BoxContainer>
|
||||||
|
<BoxContainer Orientation="Vertical">
|
||||||
|
<ui1:StripeBack>
|
||||||
|
<Label Name="HyperspaceLabel" Text="{Loc 'shuttle-console-hyperspace-label'}" HorizontalAlignment="Center"/>
|
||||||
|
</ui1:StripeBack>
|
||||||
|
<BoxContainer Name="HyperspaceDestinations"
|
||||||
|
Orientation="Vertical">
|
||||||
|
</BoxContainer>
|
||||||
|
</BoxContainer>
|
||||||
</BoxContainer>
|
</BoxContainer>
|
||||||
<PanelContainer>
|
<PanelContainer>
|
||||||
<ui:RadarControl Name="RadarScreen"
|
<ui:RadarControl Name="RadarScreen"
|
||||||
@@ -29,7 +38,7 @@
|
|||||||
</PanelContainer>
|
</PanelContainer>
|
||||||
<BoxContainer Name="RightDisplay"
|
<BoxContainer Name="RightDisplay"
|
||||||
VerticalAlignment="Top"
|
VerticalAlignment="Top"
|
||||||
HorizontalAlignment="Left"
|
HorizontalAlignment="Right"
|
||||||
MinWidth="256"
|
MinWidth="256"
|
||||||
Align="Center"
|
Align="Center"
|
||||||
Orientation="Vertical">
|
Orientation="Vertical">
|
||||||
@@ -40,6 +49,14 @@
|
|||||||
<GridContainer Columns="2"
|
<GridContainer Columns="2"
|
||||||
HorizontalAlignment="Stretch"
|
HorizontalAlignment="Stretch"
|
||||||
VerticalAlignment="Top">
|
VerticalAlignment="Top">
|
||||||
|
<Label Text="{Loc 'shuttle-console-ftl-state'}"/>
|
||||||
|
<Label Name="FTLState"
|
||||||
|
Text="{Loc 'ftl-shuttle-console-available'}"
|
||||||
|
HorizontalAlignment="Right"/>
|
||||||
|
<Label Text="{Loc 'shuttle-console-ftl-timer'}"/>
|
||||||
|
<Label Name="FTLTimer"
|
||||||
|
Text="0.0"
|
||||||
|
HorizontalAlignment="Right"/>
|
||||||
<Label Text="{Loc 'shuttle-console-max-radar'}"/>
|
<Label Text="{Loc 'shuttle-console-max-radar'}"/>
|
||||||
<Label Name="MaxRadarRange"
|
<Label Name="MaxRadarRange"
|
||||||
Text="0.0"
|
Text="0.0"
|
||||||
|
|||||||
@@ -2,12 +2,14 @@ using Content.Client.Computer;
|
|||||||
using Content.Client.UserInterface;
|
using Content.Client.UserInterface;
|
||||||
using Content.Shared.Shuttles.BUIStates;
|
using Content.Shared.Shuttles.BUIStates;
|
||||||
using Content.Shared.Shuttles.Components;
|
using Content.Shared.Shuttles.Components;
|
||||||
|
using Content.Shared.Shuttles.Systems;
|
||||||
using Robust.Client.AutoGenerated;
|
using Robust.Client.AutoGenerated;
|
||||||
using Robust.Client.Graphics;
|
using Robust.Client.Graphics;
|
||||||
using Robust.Client.UserInterface;
|
using Robust.Client.UserInterface;
|
||||||
using Robust.Client.UserInterface.Controls;
|
using Robust.Client.UserInterface.Controls;
|
||||||
using Robust.Client.UserInterface.XAML;
|
using Robust.Client.UserInterface.XAML;
|
||||||
using Robust.Shared.Map;
|
using Robust.Shared.Map;
|
||||||
|
using Robust.Shared.Timing;
|
||||||
using Robust.Shared.Utility;
|
using Robust.Shared.Utility;
|
||||||
|
|
||||||
namespace Content.Client.Shuttles.UI;
|
namespace Content.Client.Shuttles.UI;
|
||||||
@@ -17,6 +19,7 @@ public sealed partial class ShuttleConsoleWindow : FancyWindow,
|
|||||||
IComputerWindow<ShuttleConsoleBoundInterfaceState>
|
IComputerWindow<ShuttleConsoleBoundInterfaceState>
|
||||||
{
|
{
|
||||||
private readonly IEntityManager _entManager;
|
private readonly IEntityManager _entManager;
|
||||||
|
private readonly IGameTiming _timing;
|
||||||
|
|
||||||
private EntityUid? _shuttleUid;
|
private EntityUid? _shuttleUid;
|
||||||
|
|
||||||
@@ -28,17 +31,26 @@ public sealed partial class ShuttleConsoleWindow : FancyWindow,
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Stored by grid entityid then by states
|
/// Stored by grid entityid then by states
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private Dictionary<EntityUid, List<DockingInterfaceState>> _docks = new();
|
private readonly Dictionary<EntityUid, List<DockingInterfaceState>> _docks = new();
|
||||||
|
|
||||||
|
private readonly Dictionary<BaseButton, EntityUid> _destinations = new();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Next FTL state change.
|
||||||
|
/// </summary>
|
||||||
|
public TimeSpan FTLTime;
|
||||||
|
|
||||||
public Action<ShuttleMode>? ShuttleModePressed;
|
public Action<ShuttleMode>? ShuttleModePressed;
|
||||||
public Action<EntityUid>? UndockPressed;
|
public Action<EntityUid>? UndockPressed;
|
||||||
public Action<EntityUid>? StartAutodockPressed;
|
public Action<EntityUid>? StartAutodockPressed;
|
||||||
public Action<EntityUid>? StopAutodockPressed;
|
public Action<EntityUid>? StopAutodockPressed;
|
||||||
|
public Action<EntityUid>? DestinationPressed;
|
||||||
|
|
||||||
public ShuttleConsoleWindow()
|
public ShuttleConsoleWindow()
|
||||||
{
|
{
|
||||||
RobustXamlLoader.Load(this);
|
RobustXamlLoader.Load(this);
|
||||||
_entManager = IoCManager.Resolve<IEntityManager>();
|
_entManager = IoCManager.Resolve<IEntityManager>();
|
||||||
|
_timing = IoCManager.Resolve<IGameTiming>();
|
||||||
|
|
||||||
OnRadarRangeChange(RadarScreen.RadarRange);
|
OnRadarRangeChange(RadarScreen.RadarRange);
|
||||||
RadarScreen.OnRadarRangeChanged += OnRadarRangeChange;
|
RadarScreen.OnRadarRangeChanged += OnRadarRangeChange;
|
||||||
@@ -91,11 +103,84 @@ public sealed partial class ShuttleConsoleWindow : FancyWindow,
|
|||||||
public void UpdateState(ShuttleConsoleBoundInterfaceState scc)
|
public void UpdateState(ShuttleConsoleBoundInterfaceState scc)
|
||||||
{
|
{
|
||||||
UpdateDocks(scc.Docks);
|
UpdateDocks(scc.Docks);
|
||||||
|
UpdateFTL(scc.Destinations, scc.FTLState, scc.FTLTime);
|
||||||
RadarScreen.UpdateState(scc);
|
RadarScreen.UpdateState(scc);
|
||||||
MaxRadarRange.Text = $"{scc.MaxRange:0}";
|
MaxRadarRange.Text = $"{scc.MaxRange:0}";
|
||||||
ShuttleModeDisplay.Pressed = scc.Mode == ShuttleMode.Strafing;
|
ShuttleModeDisplay.Pressed = scc.Mode == ShuttleMode.Strafing;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void UpdateFTL(List<(EntityUid Entity, string Destination, bool Enabled)> destinations, FTLState state, TimeSpan time)
|
||||||
|
{
|
||||||
|
HyperspaceDestinations.DisposeAllChildren();
|
||||||
|
_destinations.Clear();
|
||||||
|
|
||||||
|
if (destinations.Count == 0)
|
||||||
|
{
|
||||||
|
HyperspaceDestinations.AddChild(new Label()
|
||||||
|
{
|
||||||
|
Text = Loc.GetString("shuttle-console-hyperspace-none"),
|
||||||
|
HorizontalAlignment = HAlignment.Center,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
destinations.Sort((x, y) => string.Compare(x.Destination, y.Destination, StringComparison.Ordinal));
|
||||||
|
|
||||||
|
foreach (var destination in destinations)
|
||||||
|
{
|
||||||
|
var button = new Button()
|
||||||
|
{
|
||||||
|
Disabled = !destination.Enabled,
|
||||||
|
Text = destination.Destination,
|
||||||
|
};
|
||||||
|
|
||||||
|
_destinations[button] = destination.Entity;
|
||||||
|
button.OnPressed += OnHyperspacePressed;
|
||||||
|
HyperspaceDestinations.AddChild(button);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
string stateText;
|
||||||
|
|
||||||
|
switch (state)
|
||||||
|
{
|
||||||
|
case Shared.Shuttles.Systems.FTLState.Available:
|
||||||
|
stateText = Loc.GetString("shuttle-console-ftl-available");
|
||||||
|
break;
|
||||||
|
case Shared.Shuttles.Systems.FTLState.Starting:
|
||||||
|
stateText = Loc.GetString("shuttle-console-ftl-starting");
|
||||||
|
break;
|
||||||
|
case Shared.Shuttles.Systems.FTLState.Travelling:
|
||||||
|
stateText = Loc.GetString("shuttle-console-ftl-travelling");
|
||||||
|
break;
|
||||||
|
case Shared.Shuttles.Systems.FTLState.Cooldown:
|
||||||
|
stateText = Loc.GetString("shuttle-console-ftl-cooldown");
|
||||||
|
break;
|
||||||
|
case Shared.Shuttles.Systems.FTLState.Arriving:
|
||||||
|
stateText = Loc.GetString("shuttle-console-ftl-arriving");
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new ArgumentOutOfRangeException(nameof(state), state, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
FTLState.Text = stateText;
|
||||||
|
// Add a buffer due to lag or whatever
|
||||||
|
time += TimeSpan.FromSeconds(0.3);
|
||||||
|
FTLTime = time;
|
||||||
|
FTLTimer.Text = GetFTLText();
|
||||||
|
}
|
||||||
|
|
||||||
|
private string GetFTLText()
|
||||||
|
{
|
||||||
|
return $"{Math.Max(0, (FTLTime - _timing.CurTime).TotalSeconds):0.0}";
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnHyperspacePressed(BaseButton.ButtonEventArgs obj)
|
||||||
|
{
|
||||||
|
var ent = _destinations[obj.Button];
|
||||||
|
DestinationPressed?.Invoke(ent);
|
||||||
|
}
|
||||||
|
|
||||||
#region Docking
|
#region Docking
|
||||||
|
|
||||||
private void UpdateDocks(List<DockingInterfaceState> docks)
|
private void UpdateDocks(List<DockingInterfaceState> docks)
|
||||||
@@ -113,8 +198,6 @@ public sealed partial class ShuttleConsoleWindow : FancyWindow,
|
|||||||
DockPorts.DisposeAllChildren();
|
DockPorts.DisposeAllChildren();
|
||||||
DockingScreen.Docks = _docks;
|
DockingScreen.Docks = _docks;
|
||||||
|
|
||||||
|
|
||||||
// TODO: Show Placeholder
|
|
||||||
if (_shuttleUid != null && _docks.TryGetValue(_shuttleUid.Value, out var gridDocks))
|
if (_shuttleUid != null && _docks.TryGetValue(_shuttleUid.Value, out var gridDocks))
|
||||||
{
|
{
|
||||||
var index = 1;
|
var index = 1;
|
||||||
@@ -241,6 +324,13 @@ public sealed partial class ShuttleConsoleWindow : FancyWindow,
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (_entManager.TryGetComponent<MetaDataComponent>(_shuttleUid, out var metadata) && metadata.EntityPaused)
|
||||||
|
{
|
||||||
|
FTLTime += _timing.FrameTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
FTLTimer.Text = GetFTLText();
|
||||||
|
|
||||||
var (_, worldRot, worldMatrix) = gridXform.GetWorldPositionRotationMatrix();
|
var (_, worldRot, worldMatrix) = gridXform.GetWorldPositionRotationMatrix();
|
||||||
var worldPos = worldMatrix.Transform(gridBody.LocalCenter);
|
var worldPos = worldMatrix.Transform(gridBody.LocalCenter);
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,6 @@
|
|||||||
using Content.Shared.Cargo;
|
using Content.Shared.Cargo;
|
||||||
|
using Content.Shared.Cargo.Prototypes;
|
||||||
|
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype;
|
||||||
|
|
||||||
namespace Content.Server.Cargo.Components;
|
namespace Content.Server.Cargo.Components;
|
||||||
|
|
||||||
@@ -22,7 +24,7 @@ public sealed class StationCargoOrderDatabaseComponent : Component
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public int Index;
|
public int Index;
|
||||||
|
|
||||||
[ViewVariables, DataField("cargoShuttleProto")]
|
[ViewVariables, DataField("cargoShuttleProto", customTypeSerializer:typeof(PrototypeIdSerializer<CargoShuttlePrototype>))]
|
||||||
public string? CargoShuttleProto = "CargoShuttle";
|
public string? CargoShuttleProto = "CargoShuttle";
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
using System.Diagnostics.CodeAnalysis;
|
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using Content.Server.Cargo.Components;
|
using Content.Server.Cargo.Components;
|
||||||
using Content.Server.Labels.Components;
|
using Content.Server.Labels.Components;
|
||||||
@@ -6,6 +5,7 @@ using Content.Server.Shuttles.Components;
|
|||||||
using Content.Server.Shuttles.Events;
|
using Content.Server.Shuttles.Events;
|
||||||
using Content.Server.UserInterface;
|
using Content.Server.UserInterface;
|
||||||
using Content.Server.Paper;
|
using Content.Server.Paper;
|
||||||
|
using Content.Server.Shuttles.Systems;
|
||||||
using Content.Shared.Cargo;
|
using Content.Shared.Cargo;
|
||||||
using Content.Shared.Cargo.BUI;
|
using Content.Shared.Cargo.BUI;
|
||||||
using Content.Shared.Cargo.Components;
|
using Content.Shared.Cargo.Components;
|
||||||
@@ -15,7 +15,6 @@ using Content.Shared.CCVar;
|
|||||||
using Content.Shared.Dataset;
|
using Content.Shared.Dataset;
|
||||||
using Content.Shared.GameTicking;
|
using Content.Shared.GameTicking;
|
||||||
using Content.Shared.MobState.Components;
|
using Content.Shared.MobState.Components;
|
||||||
|
|
||||||
using Robust.Server.Maps;
|
using Robust.Server.Maps;
|
||||||
using Robust.Shared.Audio;
|
using Robust.Shared.Audio;
|
||||||
using Robust.Shared.Configuration;
|
using Robust.Shared.Configuration;
|
||||||
@@ -40,16 +39,11 @@ public sealed partial class CargoSystem
|
|||||||
[Dependency] private readonly IRobustRandom _random = default!;
|
[Dependency] private readonly IRobustRandom _random = default!;
|
||||||
[Dependency] private readonly EntityLookupSystem _lookup = default!;
|
[Dependency] private readonly EntityLookupSystem _lookup = default!;
|
||||||
[Dependency] private readonly PricingSystem _pricing = default!;
|
[Dependency] private readonly PricingSystem _pricing = default!;
|
||||||
|
[Dependency] private readonly ShuttleConsoleSystem _console = default!;
|
||||||
|
[Dependency] private readonly ShuttleSystem _shuttle = default!;
|
||||||
|
|
||||||
public MapId? CargoMap { get; private set; }
|
public MapId? CargoMap { get; private set; }
|
||||||
|
|
||||||
private const float ShuttleRecallRange = 100f;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Minimum mass a grid needs to be to block a shuttle recall.
|
|
||||||
/// </summary>
|
|
||||||
private const float ShuttleCallMassThreshold = 300f;
|
|
||||||
|
|
||||||
private const float CallOffset = 50f;
|
private const float CallOffset = 50f;
|
||||||
|
|
||||||
private int _index;
|
private int _index;
|
||||||
@@ -162,12 +156,11 @@ public sealed partial class CargoSystem
|
|||||||
var orders = GetProjectedOrders(orderDatabase, shuttle);
|
var orders = GetProjectedOrders(orderDatabase, shuttle);
|
||||||
var shuttleName = orderDatabase?.Shuttle != null ? MetaData(orderDatabase.Shuttle.Value).EntityName : string.Empty;
|
var shuttleName = orderDatabase?.Shuttle != null ? MetaData(orderDatabase.Shuttle.Value).EntityName : string.Empty;
|
||||||
|
|
||||||
// TODO: Loc
|
|
||||||
_uiSystem.GetUiOrNull(component.Owner, CargoConsoleUiKey.Shuttle)?.SetState(
|
_uiSystem.GetUiOrNull(component.Owner, CargoConsoleUiKey.Shuttle)?.SetState(
|
||||||
new CargoShuttleConsoleBoundUserInterfaceState(
|
new CargoShuttleConsoleBoundUserInterfaceState(
|
||||||
station != null ? MetaData(station.Value).EntityName : Loc.GetString("cargo-shuttle-console-station-unknown"),
|
station != null ? MetaData(station.Value).EntityName : Loc.GetString("cargo-shuttle-console-station-unknown"),
|
||||||
string.IsNullOrEmpty(shuttleName) ? Loc.GetString("cargo-shuttle-console-shuttle-not-found") : shuttleName,
|
string.IsNullOrEmpty(shuttleName) ? Loc.GetString("cargo-shuttle-console-shuttle-not-found") : shuttleName,
|
||||||
CanRecallShuttle(shuttle?.Owner, out _),
|
_shuttle.CanFTL(shuttle?.Owner, out _),
|
||||||
shuttle?.NextCall,
|
shuttle?.NextCall,
|
||||||
orders));
|
orders));
|
||||||
}
|
}
|
||||||
@@ -194,7 +187,7 @@ public sealed partial class CargoSystem
|
|||||||
var oldCanRecall = component.CanRecall;
|
var oldCanRecall = component.CanRecall;
|
||||||
|
|
||||||
// Check if we can update the recall status.
|
// Check if we can update the recall status.
|
||||||
var canRecall = CanRecallShuttle(uid, out _, args.Component);
|
var canRecall = _shuttle.CanFTL(uid, out _, args.Component);
|
||||||
if (oldCanRecall == canRecall) return;
|
if (oldCanRecall == canRecall) return;
|
||||||
|
|
||||||
component.CanRecall = canRecall;
|
component.CanRecall = canRecall;
|
||||||
@@ -370,6 +363,7 @@ public sealed partial class CargoSystem
|
|||||||
shuttle.NextCall = null;
|
shuttle.NextCall = null;
|
||||||
|
|
||||||
// Find a valid free area nearby to spawn in on
|
// Find a valid free area nearby to spawn in on
|
||||||
|
// TODO: Make this use hyperspace now.
|
||||||
var center = new Vector2();
|
var center = new Vector2();
|
||||||
var minRadius = 0f;
|
var minRadius = 0f;
|
||||||
Box2? aabb = null;
|
Box2? aabb = null;
|
||||||
@@ -399,6 +393,7 @@ public sealed partial class CargoSystem
|
|||||||
AddCargoContents(shuttle, orderDatabase);
|
AddCargoContents(shuttle, orderDatabase);
|
||||||
UpdateOrders(orderDatabase);
|
UpdateOrders(orderDatabase);
|
||||||
UpdateShuttleCargoConsoles(shuttle);
|
UpdateShuttleCargoConsoles(shuttle);
|
||||||
|
_console.RefreshShuttleConsoles();
|
||||||
|
|
||||||
_sawmill.Info($"Retrieved cargo shuttle {ToPrettyString(shuttle.Owner)} from {ToPrettyString(orderDatabase.Owner)}");
|
_sawmill.Info($"Retrieved cargo shuttle {ToPrettyString(shuttle.Owner)} from {ToPrettyString(orderDatabase.Owner)}");
|
||||||
}
|
}
|
||||||
@@ -469,29 +464,6 @@ public sealed partial class CargoSystem
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool CanRecallShuttle(EntityUid? uid, [NotNullWhen(false)] out string? reason, TransformComponent? xform = null)
|
|
||||||
{
|
|
||||||
reason = null;
|
|
||||||
|
|
||||||
if (!TryComp<IMapGridComponent>(uid, out var grid) ||
|
|
||||||
!Resolve(uid.Value, ref xform)) return true;
|
|
||||||
|
|
||||||
var bounds = grid.Grid.WorldAABB.Enlarged(ShuttleRecallRange);
|
|
||||||
var bodyQuery = GetEntityQuery<PhysicsComponent>();
|
|
||||||
|
|
||||||
foreach (var other in _mapManager.FindGridsIntersecting(xform.MapID, bounds))
|
|
||||||
{
|
|
||||||
if (grid.GridIndex == other.Index ||
|
|
||||||
!bodyQuery.TryGetComponent(other.GridEntityId, out var body) ||
|
|
||||||
body.Mass < ShuttleCallMassThreshold) continue;
|
|
||||||
|
|
||||||
reason = Loc.GetString("cargo-shuttle-console-proximity");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void RecallCargoShuttle(EntityUid uid, CargoShuttleConsoleComponent component, CargoRecallShuttleMessage args)
|
private void RecallCargoShuttle(EntityUid uid, CargoShuttleConsoleComponent component, CargoRecallShuttleMessage args)
|
||||||
{
|
{
|
||||||
var player = args.Session.AttachedEntity;
|
var player = args.Session.AttachedEntity;
|
||||||
@@ -505,11 +477,11 @@ public sealed partial class CargoSystem
|
|||||||
|
|
||||||
if (!TryComp<CargoShuttleComponent>(orderDatabase.Shuttle, out var shuttle))
|
if (!TryComp<CargoShuttleComponent>(orderDatabase.Shuttle, out var shuttle))
|
||||||
{
|
{
|
||||||
_popup.PopupEntity($"No cargo shuttle found!", args.Entity, Filter.Entities(args.Entity));
|
_popup.PopupEntity(Loc.GetString("cargo-no-shuttle"), args.Entity, Filter.Entities(args.Entity));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!CanRecallShuttle(shuttle.Owner, out var reason))
|
if (!_shuttle.CanFTL(shuttle.Owner, out var reason))
|
||||||
{
|
{
|
||||||
_popup.PopupEntity(reason, args.Entity, Filter.Entities(args.Entity));
|
_popup.PopupEntity(reason, args.Entity, Filter.Entities(args.Entity));
|
||||||
return;
|
return;
|
||||||
@@ -523,7 +495,7 @@ public sealed partial class CargoSystem
|
|||||||
};
|
};
|
||||||
|
|
||||||
SellPallets(shuttle, bank);
|
SellPallets(shuttle, bank);
|
||||||
|
_console.RefreshShuttleConsoles();
|
||||||
SendToCargoMap(orderDatabase.Shuttle.Value);
|
SendToCargoMap(orderDatabase.Shuttle.Value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -43,9 +43,4 @@ public sealed partial class CargoSystem : SharedCargoSystem
|
|||||||
UpdateConsole(frameTime);
|
UpdateConsole(frameTime);
|
||||||
UpdateTelepad(frameTime);
|
UpdateTelepad(frameTime);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void UpdateBankAccount(StationBankAccountComponent component, int BalanceAdded)
|
|
||||||
{
|
|
||||||
component.Balance += BalanceAdded;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,6 +6,8 @@ using Content.Server.Nuke;
|
|||||||
using Content.Server.Players;
|
using Content.Server.Players;
|
||||||
using Content.Server.Roles;
|
using Content.Server.Roles;
|
||||||
using Content.Server.RoundEnd;
|
using Content.Server.RoundEnd;
|
||||||
|
using Content.Server.Shuttles.Components;
|
||||||
|
using Content.Server.Shuttles.Systems;
|
||||||
using Content.Server.Spawners.Components;
|
using Content.Server.Spawners.Components;
|
||||||
using Content.Server.Station.Components;
|
using Content.Server.Station.Components;
|
||||||
using Content.Server.Station.Systems;
|
using Content.Server.Station.Systems;
|
||||||
@@ -185,43 +187,28 @@ public sealed class NukeopsRuleSystem : GameRuleSystem
|
|||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Make this a prototype
|
// TODO: Make this a prototype
|
||||||
var map = "/Maps/infiltrator.yml";
|
// so true PAUL!
|
||||||
|
var path = "/Maps/nukieplanet.yml";
|
||||||
|
var shuttlePath = "/Maps/infiltrator.yml";
|
||||||
|
var mapId = _mapManager.CreateMap();
|
||||||
|
|
||||||
var center = new Vector2();
|
var (_, outpost) = _mapLoader.LoadBlueprint(mapId, "/Maps/nukieplanet.yml");
|
||||||
var minRadius = 0f;
|
|
||||||
Box2? aabb = null;
|
|
||||||
|
|
||||||
foreach (var uid in _stationSystem.Stations)
|
if (outpost == null)
|
||||||
{
|
{
|
||||||
if (TryComp<StationDataComponent>(uid, out var stationData))
|
Logger.ErrorS("nukies", $"Error loading map {path} for nukies!");
|
||||||
{
|
return;
|
||||||
foreach (var grid in stationData.Grids)
|
|
||||||
{
|
|
||||||
if (TryComp<IMapGridComponent>(grid, out var gridComp))
|
|
||||||
aabb = aabb?.Union(gridComp.Grid.WorldAABB) ?? gridComp.Grid.WorldAABB;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (aabb != null)
|
// Listen I just don't want it to overlap.
|
||||||
|
var (_, shuttleId) = _mapLoader.LoadBlueprint(mapId, shuttlePath, new MapLoadOptions()
|
||||||
{
|
{
|
||||||
center = aabb.Value.Center;
|
Offset = Vector2.One * 1000f,
|
||||||
minRadius = MathF.Max(aabb.Value.Width, aabb.Value.Height);
|
|
||||||
}
|
|
||||||
|
|
||||||
var (_, gridUid) = _mapLoader.LoadBlueprint(GameTicker.DefaultMap, map, new MapLoadOptions
|
|
||||||
{
|
|
||||||
Offset = center + MathF.Max(minRadius, minRadius) + 1000f,
|
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!gridUid.HasValue)
|
if (TryComp<ShuttleComponent>(shuttleId, out var shuttle))
|
||||||
{
|
{
|
||||||
Logger.ErrorS("NUKEOPS", $"Gridid was null when loading \"{map}\", aborting.");
|
IoCManager.Resolve<IEntitySystemManager>().GetEntitySystem<ShuttleSystem>().TryFTLDock(shuttle, outpost.Value);
|
||||||
foreach (var session in operatives)
|
|
||||||
{
|
|
||||||
ev.PlayerPool.Add(session);
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Loot table or something
|
// TODO: Loot table or something
|
||||||
@@ -236,14 +223,18 @@ public sealed class NukeopsRuleSystem : GameRuleSystem
|
|||||||
// Forgive me for hardcoding prototypes
|
// Forgive me for hardcoding prototypes
|
||||||
foreach (var (_, meta, xform) in EntityManager.EntityQuery<SpawnPointComponent, MetaDataComponent, TransformComponent>(true))
|
foreach (var (_, meta, xform) in EntityManager.EntityQuery<SpawnPointComponent, MetaDataComponent, TransformComponent>(true))
|
||||||
{
|
{
|
||||||
if (meta.EntityPrototype?.ID != "SpawnPointNukies" || xform.ParentUid != gridUid) continue;
|
if (meta.EntityPrototype?.ID != "SpawnPointNukies") continue;
|
||||||
|
|
||||||
spawns.Add(xform.Coordinates);
|
if (xform.ParentUid == outpost)
|
||||||
|
{
|
||||||
|
spawns.Add(xform.Coordinates);
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (spawns.Count == 0)
|
if (spawns.Count == 0)
|
||||||
{
|
{
|
||||||
spawns.Add(EntityManager.GetComponent<TransformComponent>(gridUid.Value).Coordinates);
|
spawns.Add(EntityManager.GetComponent<TransformComponent>(outpost.Value).Coordinates);
|
||||||
Logger.WarningS("nukies", $"Fell back to default spawn for nukies!");
|
Logger.WarningS("nukies", $"Fell back to default spawn for nukies!");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ using Content.Shared.Movement;
|
|||||||
using Content.Shared.Movement.Components;
|
using Content.Shared.Movement.Components;
|
||||||
using Content.Shared.Movement.Systems;
|
using Content.Shared.Movement.Systems;
|
||||||
using Content.Shared.Shuttles.Components;
|
using Content.Shared.Shuttles.Components;
|
||||||
|
using Content.Shared.Shuttles.Systems;
|
||||||
using Robust.Shared.Map;
|
using Robust.Shared.Map;
|
||||||
using Robust.Shared.Player;
|
using Robust.Shared.Player;
|
||||||
using Robust.Shared.Utility;
|
using Robust.Shared.Utility;
|
||||||
@@ -95,7 +96,7 @@ namespace Content.Server.Physics.Controllers
|
|||||||
// Reset inputs for non-piloted shuttles.
|
// Reset inputs for non-piloted shuttles.
|
||||||
foreach (var (shuttle, _) in _shuttlePilots)
|
foreach (var (shuttle, _) in _shuttlePilots)
|
||||||
{
|
{
|
||||||
if (newPilots.ContainsKey(shuttle)) continue;
|
if (newPilots.ContainsKey(shuttle) || FTLLocked(shuttle)) continue;
|
||||||
|
|
||||||
_thruster.DisableLinearThrusters(shuttle);
|
_thruster.DisableLinearThrusters(shuttle);
|
||||||
}
|
}
|
||||||
@@ -106,7 +107,7 @@ namespace Content.Server.Physics.Controllers
|
|||||||
// then do the movement input once for it.
|
// then do the movement input once for it.
|
||||||
foreach (var (shuttle, pilots) in _shuttlePilots)
|
foreach (var (shuttle, pilots) in _shuttlePilots)
|
||||||
{
|
{
|
||||||
if (Paused(shuttle.Owner) || !TryComp(shuttle.Owner, out PhysicsComponent? body)) continue;
|
if (Paused(shuttle.Owner) || FTLLocked(shuttle) || !TryComp(shuttle.Owner, out PhysicsComponent? body)) continue;
|
||||||
|
|
||||||
// Collate movement linear and angular inputs together
|
// Collate movement linear and angular inputs together
|
||||||
var linearInput = Vector2.Zero;
|
var linearInput = Vector2.Zero;
|
||||||
@@ -255,6 +256,13 @@ namespace Content.Server.Physics.Controllers
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private bool FTLLocked(ShuttleComponent shuttle)
|
||||||
|
{
|
||||||
|
return (TryComp<FTLComponent>(shuttle.Owner, out var ftl) &&
|
||||||
|
(ftl.State & (FTLState.Starting | FTLState.Travelling | FTLState.Arriving)) != 0x0);
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Add mobs riding vehicles to the list of mobs whose input
|
/// Add mobs riding vehicles to the list of mobs whose input
|
||||||
/// should be ignored.
|
/// should be ignored.
|
||||||
|
|||||||
@@ -13,6 +13,9 @@ namespace Content.Server.Shuttles.Components
|
|||||||
[ViewVariables]
|
[ViewVariables]
|
||||||
public Joint? DockJoint;
|
public Joint? DockJoint;
|
||||||
|
|
||||||
|
[ViewVariables, DataField("dockJointId")]
|
||||||
|
public string? DockJointId;
|
||||||
|
|
||||||
[ViewVariables]
|
[ViewVariables]
|
||||||
public override bool Docked => DockedWith != null;
|
public override bool Docked => DockedWith != null;
|
||||||
|
|
||||||
|
|||||||
52
Content.Server/Shuttles/Components/FTLComponent.cs
Normal file
52
Content.Server/Shuttles/Components/FTLComponent.cs
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
using Content.Shared.Shuttles.Systems;
|
||||||
|
using Content.Shared.Sound;
|
||||||
|
using Robust.Shared.Audio;
|
||||||
|
using Robust.Shared.Map;
|
||||||
|
|
||||||
|
namespace Content.Server.Shuttles.Components;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Added to a component when it is queued or is travelling via FTL.
|
||||||
|
/// </summary>
|
||||||
|
[RegisterComponent]
|
||||||
|
public sealed class FTLComponent : Component
|
||||||
|
{
|
||||||
|
[ViewVariables]
|
||||||
|
public FTLState State = FTLState.Available;
|
||||||
|
|
||||||
|
[ViewVariables(VVAccess.ReadWrite)]
|
||||||
|
public float StartupTime = 0f;
|
||||||
|
|
||||||
|
[ViewVariables(VVAccess.ReadWrite)]
|
||||||
|
public float TravelTime = 0f;
|
||||||
|
|
||||||
|
[ViewVariables(VVAccess.ReadWrite)]
|
||||||
|
public float Accumulator = 0f;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Target Uid to dock with at the end of FTL.
|
||||||
|
/// </summary>
|
||||||
|
[ViewVariables(VVAccess.ReadWrite), DataField("targetUid")]
|
||||||
|
public EntityUid? TargetUid;
|
||||||
|
|
||||||
|
[ViewVariables(VVAccess.ReadWrite), DataField("targetCoordinates")]
|
||||||
|
public EntityCoordinates TargetCoordinates;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Should we dock with the target when arriving or show up nearby.
|
||||||
|
/// </summary>
|
||||||
|
[ViewVariables(VVAccess.ReadWrite), DataField("dock")]
|
||||||
|
public bool Dock;
|
||||||
|
|
||||||
|
[ViewVariables(VVAccess.ReadWrite), DataField("soundTravel")]
|
||||||
|
public SoundSpecifier? TravelSound = new SoundPathSpecifier("/Audio/Effects/Shuttle/hyperspace_progress.ogg")
|
||||||
|
{
|
||||||
|
Params =
|
||||||
|
{
|
||||||
|
Volume = -10,
|
||||||
|
Loop = true,
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
public IPlayingAudioStream? TravelStream;
|
||||||
|
}
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
using Content.Shared.Whitelist;
|
||||||
|
|
||||||
|
namespace Content.Server.Shuttles.Components;
|
||||||
|
|
||||||
|
[RegisterComponent]
|
||||||
|
public sealed class FTLDestinationComponent : Component
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Should this destination be restricted in some form from console visibility.
|
||||||
|
/// </summary>
|
||||||
|
[ViewVariables(VVAccess.ReadWrite), DataField("whitelist")]
|
||||||
|
public EntityWhitelist? Whitelist;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Is this destination visible but available to be warped to?
|
||||||
|
/// </summary>
|
||||||
|
[ViewVariables(VVAccess.ReadWrite), DataField("enabled")]
|
||||||
|
public bool Enabled = true;
|
||||||
|
}
|
||||||
@@ -1,37 +0,0 @@
|
|||||||
using Robust.Shared.Map;
|
|
||||||
|
|
||||||
namespace Content.Server.Shuttles.Components;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Added to a component when it is queued or is travelling through hyperspace
|
|
||||||
/// </summary>
|
|
||||||
[RegisterComponent]
|
|
||||||
public sealed class HyperspaceComponent : Component
|
|
||||||
{
|
|
||||||
[ViewVariables]
|
|
||||||
public HyperspaceState State = HyperspaceState.Starting;
|
|
||||||
|
|
||||||
[ViewVariables(VVAccess.ReadWrite)]
|
|
||||||
public float StartupTime = 0f;
|
|
||||||
|
|
||||||
[ViewVariables(VVAccess.ReadWrite)]
|
|
||||||
public float TravelTime = 0f;
|
|
||||||
|
|
||||||
[ViewVariables(VVAccess.ReadWrite)]
|
|
||||||
public float Accumulator = 0f;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Target Uid to dock with at the end of hyperspace.
|
|
||||||
/// </summary>
|
|
||||||
[ViewVariables(VVAccess.ReadWrite), DataField("targetUid")]
|
|
||||||
public EntityUid? TargetUid;
|
|
||||||
|
|
||||||
[ViewVariables(VVAccess.ReadWrite), DataField("targetCoordinates")]
|
|
||||||
public EntityCoordinates TargetCoordinates;
|
|
||||||
}
|
|
||||||
|
|
||||||
public enum HyperspaceState : byte
|
|
||||||
{
|
|
||||||
Starting,
|
|
||||||
Travelling,
|
|
||||||
}
|
|
||||||
@@ -5,12 +5,6 @@ namespace Content.Server.Shuttles.Components
|
|||||||
[RegisterComponent]
|
[RegisterComponent]
|
||||||
public sealed class ShuttleComponent : Component
|
public sealed class ShuttleComponent : Component
|
||||||
{
|
{
|
||||||
/// <summary>
|
|
||||||
/// Should controls be enabled or disabled on this shuttle.
|
|
||||||
/// </summary>
|
|
||||||
[ViewVariables(VVAccess.ReadWrite)]
|
|
||||||
public bool CanPilot = true;
|
|
||||||
|
|
||||||
[ViewVariables]
|
[ViewVariables]
|
||||||
public bool Enabled = true;
|
public bool Enabled = true;
|
||||||
|
|
||||||
|
|||||||
@@ -5,12 +5,6 @@ namespace Content.Server.Shuttles.Components
|
|||||||
[RegisterComponent]
|
[RegisterComponent]
|
||||||
public sealed class ShuttleConsoleComponent : SharedShuttleConsoleComponent
|
public sealed class ShuttleConsoleComponent : SharedShuttleConsoleComponent
|
||||||
{
|
{
|
||||||
/// <summary>
|
|
||||||
/// Set by shuttlesystem if the grid should no longer be pilotable.
|
|
||||||
/// </summary>
|
|
||||||
[ViewVariables]
|
|
||||||
public bool CanPilot = true;
|
|
||||||
|
|
||||||
[ViewVariables]
|
[ViewVariables]
|
||||||
public readonly List<PilotComponent> SubscribedPilots = new();
|
public readonly List<PilotComponent> SubscribedPilots = new();
|
||||||
|
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ using Robust.Shared.Map;
|
|||||||
using Robust.Shared.Physics;
|
using Robust.Shared.Physics;
|
||||||
using Robust.Shared.Physics.Collision.Shapes;
|
using Robust.Shared.Physics.Collision.Shapes;
|
||||||
using Robust.Shared.Physics.Dynamics;
|
using Robust.Shared.Physics.Dynamics;
|
||||||
|
using Robust.Shared.Physics.Dynamics.Joints;
|
||||||
using Robust.Shared.Utility;
|
using Robust.Shared.Utility;
|
||||||
|
|
||||||
namespace Content.Server.Shuttles.Systems
|
namespace Content.Server.Shuttles.Systems
|
||||||
@@ -156,9 +157,11 @@ namespace Content.Server.Shuttles.Systems
|
|||||||
|
|
||||||
dockB.DockedWith = null;
|
dockB.DockedWith = null;
|
||||||
dockB.DockJoint = null;
|
dockB.DockJoint = null;
|
||||||
|
dockB.DockJointId = null;
|
||||||
|
|
||||||
dockA.DockJoint = null;
|
dockA.DockJoint = null;
|
||||||
dockA.DockedWith = null;
|
dockA.DockedWith = null;
|
||||||
|
dockA.DockJointId = null;
|
||||||
|
|
||||||
// If these grids are ever null then need to look at fixing ordering for unanchored events elsewhere.
|
// If these grids are ever null then need to look at fixing ordering for unanchored events elsewhere.
|
||||||
var gridAUid = EntityManager.GetComponent<TransformComponent>(dockA.Owner).GridUid;
|
var gridAUid = EntityManager.GetComponent<TransformComponent>(dockA.Owner).GridUid;
|
||||||
@@ -279,6 +282,11 @@ namespace Content.Server.Shuttles.Systems
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public void Dock(DockingComponent dockA, DockingComponent dockB)
|
public void Dock(DockingComponent dockA, DockingComponent dockB)
|
||||||
{
|
{
|
||||||
|
if (dockB.Owner.GetHashCode() < dockA.Owner.GetHashCode())
|
||||||
|
{
|
||||||
|
(dockA, dockB) = (dockB, dockA);
|
||||||
|
}
|
||||||
|
|
||||||
_sawmill.Debug($"Docking between {dockA.Owner} and {dockB.Owner}");
|
_sawmill.Debug($"Docking between {dockA.Owner} and {dockB.Owner}");
|
||||||
|
|
||||||
// https://gamedev.stackexchange.com/questions/98772/b2distancejoint-with-frequency-equal-to-0-vs-b2weldjoint
|
// https://gamedev.stackexchange.com/questions/98772/b2distancejoint-with-frequency-equal-to-0-vs-b2weldjoint
|
||||||
@@ -302,8 +310,18 @@ namespace Content.Server.Shuttles.Systems
|
|||||||
|
|
||||||
// These need playing around with
|
// These need playing around with
|
||||||
// Could also potentially have collideconnected false and stiffness 0 but it was a bit more suss???
|
// Could also potentially have collideconnected false and stiffness 0 but it was a bit more suss???
|
||||||
|
WeldJoint joint;
|
||||||
|
|
||||||
var joint = _jointSystem.GetOrCreateWeldJoint(gridA, gridB, DockingJoint + dockA.Owner);
|
// Pre-existing joint so use that.
|
||||||
|
if (dockA.DockJointId != null)
|
||||||
|
{
|
||||||
|
DebugTools.Assert(dockB.DockJointId == dockA.DockJointId);
|
||||||
|
joint = _jointSystem.GetOrCreateWeldJoint(gridA, gridB, dockA.DockJointId);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
joint = _jointSystem.GetOrCreateWeldJoint(gridA, gridB, DockingJoint + dockA.Owner);
|
||||||
|
}
|
||||||
|
|
||||||
var gridAXform = EntityManager.GetComponent<TransformComponent>(gridA);
|
var gridAXform = EntityManager.GetComponent<TransformComponent>(gridA);
|
||||||
var gridBXform = EntityManager.GetComponent<TransformComponent>(gridB);
|
var gridBXform = EntityManager.GetComponent<TransformComponent>(gridB);
|
||||||
@@ -320,8 +338,12 @@ namespace Content.Server.Shuttles.Systems
|
|||||||
|
|
||||||
dockA.DockedWith = dockB.Owner;
|
dockA.DockedWith = dockB.Owner;
|
||||||
dockB.DockedWith = dockA.Owner;
|
dockB.DockedWith = dockA.Owner;
|
||||||
|
|
||||||
dockA.DockJoint = joint;
|
dockA.DockJoint = joint;
|
||||||
|
dockA.DockJointId = joint.ID;
|
||||||
|
|
||||||
dockB.DockJoint = joint;
|
dockB.DockJoint = joint;
|
||||||
|
dockB.DockJointId = joint.ID;
|
||||||
|
|
||||||
if (TryComp<AirlockComponent>(dockA.Owner, out var airlockA))
|
if (TryComp<AirlockComponent>(dockA.Owner, out var airlockA))
|
||||||
{
|
{
|
||||||
@@ -439,10 +461,17 @@ namespace Content.Server.Shuttles.Systems
|
|||||||
_doorSystem.TryClose(doorB.Owner, doorB);
|
_doorSystem.TryClose(doorB.Owner, doorB);
|
||||||
}
|
}
|
||||||
|
|
||||||
var recentlyDocked = EnsureComp<RecentlyDockedComponent>(dock.Owner);
|
if (!Deleted(dock.Owner))
|
||||||
recentlyDocked.LastDocked = dock.DockedWith.Value;
|
{
|
||||||
recentlyDocked = EnsureComp<RecentlyDockedComponent>(dock.DockedWith.Value);
|
var recentlyDocked = EnsureComp<RecentlyDockedComponent>(dock.Owner);
|
||||||
recentlyDocked.LastDocked = dock.DockedWith.Value;
|
recentlyDocked.LastDocked = dock.DockedWith.Value;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!Deleted(dock.DockedWith.Value))
|
||||||
|
{
|
||||||
|
var recentlyDocked = EnsureComp<RecentlyDockedComponent>(dock.DockedWith.Value);
|
||||||
|
recentlyDocked.LastDocked = dock.DockedWith.Value;
|
||||||
|
}
|
||||||
|
|
||||||
Cleanup(dock);
|
Cleanup(dock);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,7 +6,6 @@ using Content.Server.Shuttles.Events;
|
|||||||
using Content.Server.UserInterface;
|
using Content.Server.UserInterface;
|
||||||
using Content.Shared.ActionBlocker;
|
using Content.Shared.ActionBlocker;
|
||||||
using Content.Shared.Alert;
|
using Content.Shared.Alert;
|
||||||
using Content.Shared.Light;
|
|
||||||
using Content.Shared.Popups;
|
using Content.Shared.Popups;
|
||||||
using Content.Shared.Shuttles.BUIStates;
|
using Content.Shared.Shuttles.BUIStates;
|
||||||
using Content.Shared.Shuttles.Components;
|
using Content.Shared.Shuttles.Components;
|
||||||
@@ -15,15 +14,19 @@ using Content.Shared.Shuttles.Systems;
|
|||||||
using Content.Shared.Tag;
|
using Content.Shared.Tag;
|
||||||
using Robust.Server.GameObjects;
|
using Robust.Server.GameObjects;
|
||||||
using Robust.Shared.GameStates;
|
using Robust.Shared.GameStates;
|
||||||
using Robust.Shared.Map;
|
using Robust.Shared.Player;
|
||||||
|
using Robust.Shared.Timing;
|
||||||
using Robust.Shared.Utility;
|
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 ActionBlockerSystem _blocker = default!;
|
||||||
[Dependency] private readonly AlertsSystem _alertsSystem = default!;
|
[Dependency] private readonly AlertsSystem _alertsSystem = default!;
|
||||||
|
[Dependency] private readonly SharedPopupSystem _popup = default!;
|
||||||
|
[Dependency] private readonly ShuttleSystem _shuttle = default!;
|
||||||
[Dependency] private readonly TagSystem _tags = default!;
|
[Dependency] private readonly TagSystem _tags = default!;
|
||||||
[Dependency] private readonly UserInterfaceSystem _ui = default!;
|
[Dependency] private readonly UserInterfaceSystem _ui = default!;
|
||||||
|
|
||||||
@@ -36,7 +39,9 @@ namespace Content.Server.Shuttles.Systems
|
|||||||
SubscribeLocalEvent<ShuttleConsoleComponent, AnchorStateChangedEvent>(OnConsoleAnchorChange);
|
SubscribeLocalEvent<ShuttleConsoleComponent, AnchorStateChangedEvent>(OnConsoleAnchorChange);
|
||||||
SubscribeLocalEvent<ShuttleConsoleComponent, ActivatableUIOpenAttemptEvent>(OnConsoleUIOpenAttempt);
|
SubscribeLocalEvent<ShuttleConsoleComponent, ActivatableUIOpenAttemptEvent>(OnConsoleUIOpenAttempt);
|
||||||
SubscribeLocalEvent<ShuttleConsoleComponent, ShuttleModeRequestMessage>(OnModeRequest);
|
SubscribeLocalEvent<ShuttleConsoleComponent, ShuttleModeRequestMessage>(OnModeRequest);
|
||||||
|
SubscribeLocalEvent<ShuttleConsoleComponent, ShuttleConsoleDestinationMessage>(OnDestinationMessage);
|
||||||
SubscribeLocalEvent<ShuttleConsoleComponent, BoundUIClosedEvent>(OnConsoleUIClose);
|
SubscribeLocalEvent<ShuttleConsoleComponent, BoundUIClosedEvent>(OnConsoleUIClose);
|
||||||
|
|
||||||
SubscribeLocalEvent<DockEvent>(OnDock);
|
SubscribeLocalEvent<DockEvent>(OnDock);
|
||||||
SubscribeLocalEvent<UndockEvent>(OnUndock);
|
SubscribeLocalEvent<UndockEvent>(OnUndock);
|
||||||
|
|
||||||
@@ -44,6 +49,46 @@ namespace Content.Server.Shuttles.Systems
|
|||||||
SubscribeLocalEvent<PilotComponent, ComponentGetState>(OnGetState);
|
SubscribeLocalEvent<PilotComponent, ComponentGetState>(OnGetState);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void OnDestinationMessage(EntityUid uid, ShuttleConsoleComponent component, ShuttleConsoleDestinationMessage args)
|
||||||
|
{
|
||||||
|
if (!TryComp<FTLDestinationComponent>(args.Destination, out var dest)) return;
|
||||||
|
|
||||||
|
if (!dest.Enabled) return;
|
||||||
|
|
||||||
|
EntityUid? entity = component.Owner;
|
||||||
|
|
||||||
|
var getShuttleEv = new ConsoleShuttleEvent
|
||||||
|
{
|
||||||
|
Console = uid,
|
||||||
|
};
|
||||||
|
|
||||||
|
RaiseLocalEvent(entity.Value, ref getShuttleEv);
|
||||||
|
entity = getShuttleEv.Console;
|
||||||
|
|
||||||
|
if (entity == null || dest.Whitelist?.IsValid(entity.Value, EntityManager) == false) return;
|
||||||
|
|
||||||
|
if (!TryComp<TransformComponent>(entity, out var xform) ||
|
||||||
|
!TryComp<ShuttleComponent>(xform.GridUid, out var shuttle)) return;
|
||||||
|
|
||||||
|
if (HasComp<FTLComponent>(xform.GridUid))
|
||||||
|
{
|
||||||
|
if (args.Session.AttachedEntity != null)
|
||||||
|
_popup.PopupCursor(Loc.GetString("shuttle-console-in-ftl"), Filter.Entities(args.Session.AttachedEntity.Value));
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!_shuttle.CanFTL(shuttle.Owner, out var reason))
|
||||||
|
{
|
||||||
|
if (args.Session.AttachedEntity != null)
|
||||||
|
_popup.PopupCursor(reason, Filter.Entities(args.Session.AttachedEntity.Value));
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_shuttle.FTLTravel(shuttle, args.Destination, hyperspaceTime: _shuttle.TransitTime);
|
||||||
|
}
|
||||||
|
|
||||||
private void OnDock(DockEvent ev)
|
private void OnDock(DockEvent ev)
|
||||||
{
|
{
|
||||||
RefreshShuttleConsoles();
|
RefreshShuttleConsoles();
|
||||||
@@ -54,12 +99,17 @@ namespace Content.Server.Shuttles.Systems
|
|||||||
RefreshShuttleConsoles();
|
RefreshShuttleConsoles();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void RefreshShuttleConsoles(EntityUid uid)
|
||||||
|
{
|
||||||
|
// TODO: Should really call this per shuttle in some instances.
|
||||||
|
RefreshShuttleConsoles();
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Refreshes all of the data for shuttle consoles.
|
/// Refreshes all of the data for shuttle consoles.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public void RefreshShuttleConsoles()
|
public void RefreshShuttleConsoles()
|
||||||
{
|
{
|
||||||
// TODO: Should really call this per shuttle in some instances.
|
|
||||||
var docks = GetAllDocks();
|
var docks = GetAllDocks();
|
||||||
|
|
||||||
foreach (var comp in EntityQuery<ShuttleConsoleComponent>(true))
|
foreach (var comp in EntityQuery<ShuttleConsoleComponent>(true))
|
||||||
@@ -87,7 +137,7 @@ namespace Content.Server.Shuttles.Systems
|
|||||||
|
|
||||||
private void OnConsoleUIOpenAttempt(EntityUid uid, ShuttleConsoleComponent component, ActivatableUIOpenAttemptEvent args)
|
private void OnConsoleUIOpenAttempt(EntityUid uid, ShuttleConsoleComponent component, ActivatableUIOpenAttemptEvent args)
|
||||||
{
|
{
|
||||||
if (!component.CanPilot || !TryPilot(args.User, uid))
|
if (!TryPilot(args.User, uid))
|
||||||
args.Cancel();
|
args.Cancel();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -174,7 +224,7 @@ namespace Content.Server.Shuttles.Systems
|
|||||||
if (!this.IsPowered(consoleComponent.Owner, EntityManager) ||
|
if (!this.IsPowered(consoleComponent.Owner, EntityManager) ||
|
||||||
!Resolve(consoleComponent.Owner, ref consoleXform) ||
|
!Resolve(consoleComponent.Owner, ref consoleXform) ||
|
||||||
!consoleXform.Anchored ||
|
!consoleXform.Anchored ||
|
||||||
consoleXform.GridID != Transform(shuttleComponent.Owner).GridID)
|
consoleXform.GridUid != Transform(shuttleComponent.Owner).GridUid)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -228,7 +278,7 @@ namespace Content.Server.Shuttles.Systems
|
|||||||
Console = entity,
|
Console = entity,
|
||||||
};
|
};
|
||||||
|
|
||||||
RaiseLocalEvent(entity.Value, ref getShuttleEv, false);
|
RaiseLocalEvent(entity.Value, ref getShuttleEv);
|
||||||
entity = getShuttleEv.Console;
|
entity = getShuttleEv.Console;
|
||||||
|
|
||||||
TryComp<TransformComponent>(entity, out var consoleXform);
|
TryComp<TransformComponent>(entity, out var consoleXform);
|
||||||
@@ -236,14 +286,64 @@ namespace Content.Server.Shuttles.Systems
|
|||||||
var range = radar?.MaxRange ?? 0f;
|
var range = radar?.MaxRange ?? 0f;
|
||||||
|
|
||||||
TryComp<ShuttleComponent>(consoleXform?.GridUid, out var shuttle);
|
TryComp<ShuttleComponent>(consoleXform?.GridUid, out var shuttle);
|
||||||
component.CanPilot = shuttle is { CanPilot: true };
|
|
||||||
var mode = shuttle?.Mode ?? ShuttleMode.Cruise;
|
var mode = shuttle?.Mode ?? ShuttleMode.Cruise;
|
||||||
|
|
||||||
|
var destinations = new List<(EntityUid, string, bool)>();
|
||||||
|
var ftlState = FTLState.Available;
|
||||||
|
var ftlTime = TimeSpan.Zero;
|
||||||
|
|
||||||
|
if (TryComp<FTLComponent>(shuttle?.Owner, out var shuttleFtl))
|
||||||
|
{
|
||||||
|
ftlState = shuttleFtl.State;
|
||||||
|
ftlTime = _timing.CurTime + TimeSpan.FromSeconds(shuttleFtl.Accumulator);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Mass too large
|
||||||
|
if (entity != null && shuttle?.Owner != null && (!TryComp<PhysicsComponent>(shuttle?.Owner, out var shuttleBody) ||
|
||||||
|
shuttleBody.Mass < 1000f))
|
||||||
|
{
|
||||||
|
var metaQuery = GetEntityQuery<MetaDataComponent>();
|
||||||
|
|
||||||
|
// Can't go anywhere when in FTL.
|
||||||
|
var locked = shuttleFtl != null || Paused(shuttle!.Owner);
|
||||||
|
|
||||||
|
// Can't cache it because it may have a whitelist for the particular console.
|
||||||
|
// Include paused as we still want to show centcomm.
|
||||||
|
foreach (var comp in EntityQuery<FTLDestinationComponent>(true))
|
||||||
|
{
|
||||||
|
// Can't warp to itself or if it's not on the whitelist.
|
||||||
|
if (comp.Owner == shuttle?.Owner ||
|
||||||
|
comp.Whitelist?.IsValid(entity.Value) == false) continue;
|
||||||
|
|
||||||
|
var meta = metaQuery.GetComponent(comp.Owner);
|
||||||
|
var name = meta.EntityName;
|
||||||
|
|
||||||
|
if (string.IsNullOrEmpty(name))
|
||||||
|
name = Loc.GetString("shuttle-console-unknown");
|
||||||
|
|
||||||
|
var canTravel = !locked &&
|
||||||
|
comp.Enabled &&
|
||||||
|
!Paused(comp.Owner, meta) &&
|
||||||
|
(!TryComp<FTLComponent>(comp.Owner, out var ftl) || ftl.State == FTLState.Cooldown);
|
||||||
|
|
||||||
|
// Can't travel to same map.
|
||||||
|
if (canTravel && consoleXform?.MapUid == Transform(comp.Owner).MapUid)
|
||||||
|
{
|
||||||
|
canTravel = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
destinations.Add((comp.Owner, name, canTravel));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
docks ??= GetAllDocks();
|
docks ??= GetAllDocks();
|
||||||
|
|
||||||
_ui.GetUiOrNull(component.Owner, ShuttleConsoleUiKey.Key)
|
_ui.GetUiOrNull(component.Owner, ShuttleConsoleUiKey.Key)
|
||||||
?.SetState(new ShuttleConsoleBoundInterfaceState(
|
?.SetState(new ShuttleConsoleBoundInterfaceState(
|
||||||
|
ftlState,
|
||||||
|
ftlTime,
|
||||||
mode,
|
mode,
|
||||||
|
destinations,
|
||||||
range,
|
range,
|
||||||
consoleXform?.Coordinates,
|
consoleXform?.Coordinates,
|
||||||
consoleXform?.LocalRotation,
|
consoleXform?.LocalRotation,
|
||||||
|
|||||||
@@ -52,7 +52,7 @@ public sealed partial class ShuttleSystem
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// <see cref="CCVars.EmergencyShuttleTransitTime"/>
|
/// <see cref="CCVars.EmergencyShuttleTransitTime"/>
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private float _transitTime;
|
public float TransitTime { get; private set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// <see cref="CCVars.EmergencyShuttleAuthorizeTime"/>
|
/// <see cref="CCVars.EmergencyShuttleAuthorizeTime"/>
|
||||||
@@ -69,6 +69,11 @@ public sealed partial class ShuttleSystem
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
private bool _launchedShuttles;
|
private bool _launchedShuttles;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Have we announced the launch?
|
||||||
|
/// </summary>
|
||||||
|
private bool _announced;
|
||||||
|
|
||||||
private void InitializeEmergencyConsole()
|
private void InitializeEmergencyConsole()
|
||||||
{
|
{
|
||||||
_configManager.OnValueChanged(CCVars.EmergencyShuttleTransitTime, SetTransitTime, true);
|
_configManager.OnValueChanged(CCVars.EmergencyShuttleTransitTime, SetTransitTime, true);
|
||||||
@@ -86,7 +91,7 @@ public sealed partial class ShuttleSystem
|
|||||||
|
|
||||||
private void SetTransitTime(float obj)
|
private void SetTransitTime(float obj)
|
||||||
{
|
{
|
||||||
_transitTime = obj;
|
TransitTime = obj;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ShutdownEmergencyConsole()
|
private void ShutdownEmergencyConsole()
|
||||||
@@ -106,6 +111,14 @@ public sealed partial class ShuttleSystem
|
|||||||
|
|
||||||
_consoleAccumulator -= frameTime;
|
_consoleAccumulator -= frameTime;
|
||||||
|
|
||||||
|
// No early launch but we're under the timer.
|
||||||
|
if (!_launchedShuttles && _consoleAccumulator <= _authorizeTime)
|
||||||
|
{
|
||||||
|
if (!EarlyLaunchAuthorized)
|
||||||
|
AnnounceLaunch();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Imminent departure
|
||||||
if (!_launchedShuttles && _consoleAccumulator <= DefaultStartupTime)
|
if (!_launchedShuttles && _consoleAccumulator <= DefaultStartupTime)
|
||||||
{
|
{
|
||||||
_launchedShuttles = true;
|
_launchedShuttles = true;
|
||||||
@@ -119,27 +132,33 @@ public sealed partial class ShuttleSystem
|
|||||||
if (Deleted(_centcomm))
|
if (Deleted(_centcomm))
|
||||||
{
|
{
|
||||||
// TODO: Need to get non-overlapping positions.
|
// TODO: Need to get non-overlapping positions.
|
||||||
Hyperspace(shuttle,
|
FTLTravel(shuttle,
|
||||||
new EntityCoordinates(
|
new EntityCoordinates(
|
||||||
_mapManager.GetMapEntityId(_centcommMap.Value),
|
_mapManager.GetMapEntityId(_centcommMap.Value),
|
||||||
Vector2.One * 1000f), _consoleAccumulator, _transitTime);
|
Vector2.One * 1000f), _consoleAccumulator, TransitTime);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Hyperspace(shuttle,
|
FTLTravel(shuttle,
|
||||||
_centcomm.Value, _consoleAccumulator, _transitTime);
|
_centcomm.Value, _consoleAccumulator, TransitTime);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Departed
|
||||||
if (_consoleAccumulator <= 0f)
|
if (_consoleAccumulator <= 0f)
|
||||||
{
|
{
|
||||||
_launchedShuttles = true;
|
_launchedShuttles = true;
|
||||||
_chatSystem.DispatchGlobalAnnouncement(Loc.GetString("emergency-shuttle-left", ("transitTime", $"{_transitTime:0}")));
|
_chatSystem.DispatchGlobalAnnouncement(Loc.GetString("emergency-shuttle-left", ("transitTime", $"{TransitTime:0}")));
|
||||||
|
|
||||||
_roundEndCancelToken = new CancellationTokenSource();
|
_roundEndCancelToken = new CancellationTokenSource();
|
||||||
Timer.Spawn((int) (_transitTime * 1000) + _bufferTime.Milliseconds, () => _roundEnd.EndRound(), _roundEndCancelToken.Token);
|
Timer.Spawn((int) (TransitTime * 1000) + _bufferTime.Milliseconds, () => _roundEnd.EndRound(), _roundEndCancelToken.Token);
|
||||||
|
|
||||||
|
// Guarantees that emergency shuttle arrives first before anyone else can FTL.
|
||||||
|
if (_centcomm != null)
|
||||||
|
AddFTLDestination(_centcomm.Value, true);
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -213,6 +232,7 @@ public sealed partial class ShuttleSystem
|
|||||||
|
|
||||||
private void CleanupEmergencyConsole()
|
private void CleanupEmergencyConsole()
|
||||||
{
|
{
|
||||||
|
_announced = false;
|
||||||
_roundEndCancelToken = null;
|
_roundEndCancelToken = null;
|
||||||
_launchedShuttles = false;
|
_launchedShuttles = false;
|
||||||
_consoleAccumulator = 0f;
|
_consoleAccumulator = 0f;
|
||||||
@@ -259,20 +279,28 @@ public sealed partial class ShuttleSystem
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public bool EarlyLaunch()
|
public bool EarlyLaunch()
|
||||||
{
|
{
|
||||||
if (EarlyLaunchAuthorized || !EmergencyShuttleArrived) return false;
|
if (EarlyLaunchAuthorized || !EmergencyShuttleArrived || _consoleAccumulator <= _authorizeTime) return false;
|
||||||
|
|
||||||
_logger.Add(LogType.EmergencyShuttle, LogImpact.Extreme, $"Emergency shuttle launch authorized");
|
_logger.Add(LogType.EmergencyShuttle, LogImpact.Extreme, $"Emergency shuttle launch authorized");
|
||||||
_consoleAccumulator = MathF.Max(1f, MathF.Min(_consoleAccumulator, _authorizeTime));
|
_consoleAccumulator =_authorizeTime;
|
||||||
EarlyLaunchAuthorized = true;
|
EarlyLaunchAuthorized = true;
|
||||||
RaiseLocalEvent(new EmergencyShuttleAuthorizedEvent());
|
RaiseLocalEvent(new EmergencyShuttleAuthorizedEvent());
|
||||||
|
AnnounceLaunch();
|
||||||
|
UpdateAllEmergencyConsoles();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void AnnounceLaunch()
|
||||||
|
{
|
||||||
|
if (_announced) return;
|
||||||
|
|
||||||
|
_announced = true;
|
||||||
_chatSystem.DispatchGlobalAnnouncement(
|
_chatSystem.DispatchGlobalAnnouncement(
|
||||||
Loc.GetString("emergency-shuttle-launch-time", ("consoleAccumulator", $"{_consoleAccumulator:0}")),
|
Loc.GetString("emergency-shuttle-launch-time", ("consoleAccumulator", $"{_consoleAccumulator:0}")),
|
||||||
playDefaultSound: false,
|
playDefaultSound: false,
|
||||||
colorOverride: DangerColor);
|
colorOverride: DangerColor);
|
||||||
|
|
||||||
SoundSystem.Play("/Audio/Misc/notice1.ogg", Filter.Broadcast());
|
SoundSystem.Play("/Audio/Misc/notice1.ogg", Filter.Broadcast());
|
||||||
UpdateAllEmergencyConsoles();
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool DelayEmergencyRoundEnd()
|
public bool DelayEmergencyRoundEnd()
|
||||||
|
|||||||
@@ -132,7 +132,6 @@ public sealed partial class ShuttleSystem
|
|||||||
var shuttleAABB = Comp<IMapGridComponent>(component.Owner).Grid.LocalAABB;
|
var shuttleAABB = Comp<IMapGridComponent>(component.Owner).Grid.LocalAABB;
|
||||||
|
|
||||||
var validDockConfigs = new List<DockingConfig>();
|
var validDockConfigs = new List<DockingConfig>();
|
||||||
SetPilotable(component, false);
|
|
||||||
|
|
||||||
if (shuttleDocks.Count > 0)
|
if (shuttleDocks.Count > 0)
|
||||||
{
|
{
|
||||||
@@ -165,7 +164,7 @@ public sealed partial class ShuttleSystem
|
|||||||
if (_mapManager.FindGridsIntersecting(targetGridXform.MapID,
|
if (_mapManager.FindGridsIntersecting(targetGridXform.MapID,
|
||||||
dockedBounds).Any(o => o.GridEntityId != targetGrid))
|
dockedBounds).Any(o => o.GridEntityId != targetGrid))
|
||||||
{
|
{
|
||||||
break;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Alright well the spawn is valid now to check how many we can connect
|
// Alright well the spawn is valid now to check how many we can connect
|
||||||
@@ -255,7 +254,7 @@ public sealed partial class ShuttleSystem
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (TryHyperspaceDock(shuttle, targetGrid.Value))
|
if (TryFTLDock(shuttle, targetGrid.Value))
|
||||||
{
|
{
|
||||||
var xformQuery = GetEntityQuery<TransformComponent>();
|
var xformQuery = GetEntityQuery<TransformComponent>();
|
||||||
|
|
||||||
@@ -417,6 +416,9 @@ public sealed partial class ShuttleSystem
|
|||||||
{
|
{
|
||||||
var (_, centcomm) = _loader.LoadBlueprint(_centcommMap.Value, "/Maps/centcomm.yml");
|
var (_, centcomm) = _loader.LoadBlueprint(_centcommMap.Value, "/Maps/centcomm.yml");
|
||||||
_centcomm = centcomm;
|
_centcomm = centcomm;
|
||||||
|
|
||||||
|
if (_centcomm != null)
|
||||||
|
AddFTLDestination(_centcomm.Value, false);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -3,7 +3,9 @@ using Content.Server.Buckle.Components;
|
|||||||
using Content.Server.Doors.Components;
|
using Content.Server.Doors.Components;
|
||||||
using Content.Server.Doors.Systems;
|
using Content.Server.Doors.Systems;
|
||||||
using Content.Server.Shuttles.Components;
|
using Content.Server.Shuttles.Components;
|
||||||
|
using Content.Server.Station.Systems;
|
||||||
using Content.Server.Stunnable;
|
using Content.Server.Stunnable;
|
||||||
|
using Content.Shared.Shuttles.Systems;
|
||||||
using Content.Shared.Sound;
|
using Content.Shared.Sound;
|
||||||
using Content.Shared.StatusEffect;
|
using Content.Shared.StatusEffect;
|
||||||
using Robust.Shared.Audio;
|
using Robust.Shared.Audio;
|
||||||
@@ -21,12 +23,23 @@ public sealed partial class ShuttleSystem
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
[Dependency] private readonly DoorSystem _doors = default!;
|
[Dependency] private readonly DoorSystem _doors = default!;
|
||||||
|
[Dependency] private readonly ShuttleConsoleSystem _console = default!;
|
||||||
[Dependency] private readonly StunSystem _stuns = default!;
|
[Dependency] private readonly StunSystem _stuns = default!;
|
||||||
|
[Dependency] private readonly ThrusterSystem _thruster = default!;
|
||||||
|
|
||||||
private MapId? _hyperSpaceMap;
|
private MapId? _hyperSpaceMap;
|
||||||
|
|
||||||
private const float DefaultStartupTime = 5.5f;
|
private const float DefaultStartupTime = 5.5f;
|
||||||
private const float DefaultTravelTime = 30f;
|
private const float DefaultTravelTime = 30f;
|
||||||
|
private const float DefaultArrivalTime = 5f;
|
||||||
|
private const float FTLCooldown = 30f;
|
||||||
|
|
||||||
|
private const float ShuttleFTLRange = 100f;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Minimum mass a grid needs to be to block a shuttle recall.
|
||||||
|
/// </summary>
|
||||||
|
private const float ShuttleFTLMassThreshold = 300f;
|
||||||
|
|
||||||
// I'm too lazy to make CVars.
|
// I'm too lazy to make CVars.
|
||||||
|
|
||||||
@@ -44,62 +57,144 @@ public sealed partial class ShuttleSystem
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
private const float Buffer = 5f;
|
private const float Buffer = 5f;
|
||||||
|
|
||||||
|
private void InitializeFTL()
|
||||||
|
{
|
||||||
|
SubscribeLocalEvent<StationGridAddedEvent>(OnStationGridAdd);
|
||||||
|
SubscribeLocalEvent<FTLDestinationComponent, EntityPausedEvent>(OnDestinationPause);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnDestinationPause(EntityUid uid, FTLDestinationComponent component, EntityPausedEvent args)
|
||||||
|
{
|
||||||
|
_console.RefreshShuttleConsoles();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnStationGridAdd(StationGridAddedEvent ev)
|
||||||
|
{
|
||||||
|
if (TryComp<PhysicsComponent>(ev.GridId, out var body) && body.Mass > 500f)
|
||||||
|
{
|
||||||
|
AddFTLDestination(ev.GridId, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool CanFTL(EntityUid? uid, [NotNullWhen(false)] out string? reason, TransformComponent? xform = null)
|
||||||
|
{
|
||||||
|
reason = null;
|
||||||
|
|
||||||
|
if (!TryComp<IMapGridComponent>(uid, out var grid) ||
|
||||||
|
!Resolve(uid.Value, ref xform)) return true;
|
||||||
|
|
||||||
|
var bounds = grid.Grid.WorldAABB.Enlarged(ShuttleFTLRange);
|
||||||
|
var bodyQuery = GetEntityQuery<PhysicsComponent>();
|
||||||
|
|
||||||
|
foreach (var other in _mapManager.FindGridsIntersecting(xform.MapID, bounds))
|
||||||
|
{
|
||||||
|
if (grid.GridIndex == other.Index ||
|
||||||
|
!bodyQuery.TryGetComponent(other.GridEntityId, out var body) ||
|
||||||
|
body.Mass < ShuttleFTLMassThreshold) continue;
|
||||||
|
|
||||||
|
reason = Loc.GetString("shuttle-console-proximity");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Adds a target for hyperspace to every shuttle console.
|
||||||
|
/// </summary>
|
||||||
|
public FTLDestinationComponent AddFTLDestination(EntityUid uid, bool enabled)
|
||||||
|
{
|
||||||
|
if (TryComp<FTLDestinationComponent>(uid, out var destination) && destination.Enabled == enabled) return destination;
|
||||||
|
|
||||||
|
destination = EnsureComp<FTLDestinationComponent>(uid);
|
||||||
|
|
||||||
|
if (HasComp<FTLComponent>(uid))
|
||||||
|
{
|
||||||
|
enabled = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
destination.Enabled = enabled;
|
||||||
|
_console.RefreshShuttleConsoles();
|
||||||
|
return destination;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void RemoveFTLDestination(EntityUid uid)
|
||||||
|
{
|
||||||
|
if (!RemComp<FTLDestinationComponent>(uid)) return;
|
||||||
|
_console.RefreshShuttleConsoles();
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Moves a shuttle from its current position to the target one. Goes through the hyperspace map while the timer is running.
|
/// Moves a shuttle from its current position to the target one. Goes through the hyperspace map while the timer is running.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public void Hyperspace(ShuttleComponent component,
|
public void FTLTravel(ShuttleComponent component,
|
||||||
EntityCoordinates coordinates,
|
EntityCoordinates coordinates,
|
||||||
float startupTime = DefaultStartupTime,
|
float startupTime = DefaultStartupTime,
|
||||||
float hyperspaceTime = DefaultTravelTime)
|
float hyperspaceTime = DefaultTravelTime)
|
||||||
{
|
{
|
||||||
if (!TrySetupHyperspace(component.Owner, out var hyperspace))
|
if (!TrySetupFTL(component, out var hyperspace))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
hyperspace.StartupTime = startupTime;
|
hyperspace.StartupTime = startupTime;
|
||||||
hyperspace.TravelTime = hyperspaceTime;
|
hyperspace.TravelTime = hyperspaceTime;
|
||||||
hyperspace.Accumulator = hyperspace.StartupTime;
|
hyperspace.Accumulator = hyperspace.StartupTime;
|
||||||
hyperspace.TargetCoordinates = coordinates;
|
hyperspace.TargetCoordinates = coordinates;
|
||||||
|
hyperspace.Dock = false;
|
||||||
|
_console.RefreshShuttleConsoles();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Moves a shuttle from its current position to docked on the target one. Goes through the hyperspace map while the timer is running.
|
/// Moves a shuttle from its current position to docked on the target one. Goes through the hyperspace map while the timer is running.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public void Hyperspace(ShuttleComponent component,
|
public void FTLTravel(ShuttleComponent component,
|
||||||
EntityUid target,
|
EntityUid target,
|
||||||
float startupTime = DefaultStartupTime,
|
float startupTime = DefaultStartupTime,
|
||||||
float hyperspaceTime = DefaultTravelTime)
|
float hyperspaceTime = DefaultTravelTime,
|
||||||
|
bool dock = false)
|
||||||
{
|
{
|
||||||
if (!TrySetupHyperspace(component.Owner, out var hyperspace))
|
if (!TrySetupFTL(component, out var hyperspace))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
hyperspace.State = FTLState.Starting;
|
||||||
hyperspace.StartupTime = startupTime;
|
hyperspace.StartupTime = startupTime;
|
||||||
hyperspace.TravelTime = hyperspaceTime;
|
hyperspace.TravelTime = hyperspaceTime;
|
||||||
hyperspace.Accumulator = hyperspace.StartupTime;
|
hyperspace.Accumulator = hyperspace.StartupTime;
|
||||||
hyperspace.TargetUid = target;
|
hyperspace.TargetUid = target;
|
||||||
|
hyperspace.Dock = dock;
|
||||||
|
_console.RefreshShuttleConsoles();
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool TrySetupHyperspace(EntityUid uid, [NotNullWhen(true)] out HyperspaceComponent? component)
|
private bool TrySetupFTL(ShuttleComponent shuttle, [NotNullWhen(true)] out FTLComponent? component)
|
||||||
{
|
{
|
||||||
|
var uid = shuttle.Owner;
|
||||||
component = null;
|
component = null;
|
||||||
|
|
||||||
if (HasComp<HyperspaceComponent>(uid))
|
if (HasComp<FTLComponent>(uid))
|
||||||
{
|
{
|
||||||
_sawmill.Warning($"Tried queuing {ToPrettyString(uid)} which already has HyperspaceComponent?");
|
_sawmill.Warning($"Tried queuing {ToPrettyString(uid)} which already has HyperspaceComponent?");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (TryComp<FTLDestinationComponent>(uid, out var dest))
|
||||||
|
{
|
||||||
|
dest.Enabled = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
_thruster.DisableLinearThrusters(shuttle);
|
||||||
|
_thruster.EnableLinearThrustDirection(shuttle, DirectionFlag.North);
|
||||||
|
_thruster.SetAngularThrust(shuttle, false);
|
||||||
// TODO: Maybe move this to docking instead?
|
// TODO: Maybe move this to docking instead?
|
||||||
SetDocks(uid, false);
|
SetDocks(uid, false);
|
||||||
|
|
||||||
component = AddComp<HyperspaceComponent>(uid);
|
component = AddComp<FTLComponent>(uid);
|
||||||
// TODO: Need BroadcastGrid to not be bad.
|
// TODO: Need BroadcastGrid to not be bad.
|
||||||
SoundSystem.Play(_startupSound.GetSound(), Filter.Pvs(component.Owner, GetSoundRange(component.Owner), entityManager: EntityManager), _startupSound.Params);
|
SoundSystem.Play(_startupSound.GetSound(), Filter.Empty().AddInRange(Transform(uid).MapPosition, GetSoundRange(component.Owner)), _startupSound.Params);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void UpdateHyperspace(float frameTime)
|
private void UpdateHyperspace(float frameTime)
|
||||||
{
|
{
|
||||||
foreach (var comp in EntityQuery<HyperspaceComponent>())
|
foreach (var comp in EntityQuery<FTLComponent>())
|
||||||
{
|
{
|
||||||
comp.Accumulator -= frameTime;
|
comp.Accumulator -= frameTime;
|
||||||
|
|
||||||
@@ -107,21 +202,22 @@ public sealed partial class ShuttleSystem
|
|||||||
|
|
||||||
var xform = Transform(comp.Owner);
|
var xform = Transform(comp.Owner);
|
||||||
PhysicsComponent? body;
|
PhysicsComponent? body;
|
||||||
|
ShuttleComponent? shuttle;
|
||||||
|
|
||||||
switch (comp.State)
|
switch (comp.State)
|
||||||
{
|
{
|
||||||
// Startup time has elapsed and in hyperspace.
|
// Startup time has elapsed and in hyperspace.
|
||||||
case HyperspaceState.Starting:
|
case FTLState.Starting:
|
||||||
DoTheDinosaur(xform);
|
DoTheDinosaur(xform);
|
||||||
|
|
||||||
comp.State = HyperspaceState.Travelling;
|
comp.State = FTLState.Travelling;
|
||||||
SetupHyperspace();
|
SetupHyperspace();
|
||||||
|
|
||||||
var width = Comp<IMapGridComponent>(comp.Owner).Grid.LocalAABB.Width;
|
var width = Comp<IMapGridComponent>(comp.Owner).Grid.LocalAABB.Width;
|
||||||
xform.Coordinates = new EntityCoordinates(_mapManager.GetMapEntityId(_hyperSpaceMap!.Value), new Vector2(_index + width / 2f, 0f));
|
xform.Coordinates = new EntityCoordinates(_mapManager.GetMapEntityId(_hyperSpaceMap!.Value), new Vector2(_index + width / 2f, 0f));
|
||||||
xform.LocalRotation = Angle.Zero;
|
xform.LocalRotation = Angle.Zero;
|
||||||
_index += width + Buffer;
|
_index += width + Buffer;
|
||||||
comp.Accumulator += comp.TravelTime;
|
comp.Accumulator += comp.TravelTime - DefaultArrivalTime;
|
||||||
|
|
||||||
if (TryComp(comp.Owner, out body))
|
if (TryComp(comp.Owner, out body))
|
||||||
{
|
{
|
||||||
@@ -131,11 +227,32 @@ public sealed partial class ShuttleSystem
|
|||||||
body.AngularDamping = 0f;
|
body.AngularDamping = 0f;
|
||||||
}
|
}
|
||||||
|
|
||||||
SetDockBolts(comp.Owner, true);
|
if (comp.TravelSound != null)
|
||||||
|
{
|
||||||
|
comp.TravelStream = SoundSystem.Play(comp.TravelSound.GetSound(),
|
||||||
|
Filter.Pvs(comp.Owner, 4f, entityManager: EntityManager), comp.TravelSound.Params);
|
||||||
|
}
|
||||||
|
|
||||||
|
SetDockBolts(comp.Owner, true);
|
||||||
|
_console.RefreshShuttleConsoles(comp.Owner);
|
||||||
break;
|
break;
|
||||||
// Arrive.
|
// Arriving, play effects
|
||||||
case HyperspaceState.Travelling:
|
case FTLState.Travelling:
|
||||||
|
comp.Accumulator += DefaultArrivalTime;
|
||||||
|
comp.State = FTLState.Arriving;
|
||||||
|
// TODO: Arrival effects
|
||||||
|
// For now we'll just use the ss13 bubbles but we can do fancier.
|
||||||
|
|
||||||
|
if (TryComp(comp.Owner, out shuttle))
|
||||||
|
{
|
||||||
|
_thruster.DisableLinearThrusters(shuttle);
|
||||||
|
_thruster.EnableLinearThrustDirection(shuttle, DirectionFlag.South);
|
||||||
|
}
|
||||||
|
|
||||||
|
_console.RefreshShuttleConsoles(comp.Owner);
|
||||||
|
break;
|
||||||
|
// Arrived
|
||||||
|
case FTLState.Arriving:
|
||||||
DoTheDinosaur(xform);
|
DoTheDinosaur(xform);
|
||||||
SetDockBolts(comp.Owner, false);
|
SetDockBolts(comp.Owner, false);
|
||||||
SetDocks(comp.Owner, true);
|
SetDocks(comp.Owner, true);
|
||||||
@@ -148,18 +265,45 @@ public sealed partial class ShuttleSystem
|
|||||||
body.AngularDamping = ShuttleIdleAngularDamping;
|
body.AngularDamping = ShuttleIdleAngularDamping;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (comp.TargetUid != null && TryComp<ShuttleComponent>(comp.Owner, out var shuttle))
|
TryComp(comp.Owner, out shuttle);
|
||||||
|
|
||||||
|
if (comp.TargetUid != null && shuttle != null)
|
||||||
{
|
{
|
||||||
TryHyperspaceDock(shuttle, comp.TargetUid.Value);
|
if (comp.Dock)
|
||||||
|
TryFTLDock(shuttle, comp.TargetUid.Value);
|
||||||
|
else
|
||||||
|
TryFTLProximity(shuttle, comp.TargetUid.Value);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
xform.Coordinates = comp.TargetCoordinates;
|
xform.Coordinates = comp.TargetCoordinates;
|
||||||
}
|
}
|
||||||
|
|
||||||
SoundSystem.Play(_arrivalSound.GetSound(),
|
if (shuttle != null)
|
||||||
Filter.Pvs(comp.Owner, GetSoundRange(comp.Owner), entityManager: EntityManager));
|
{
|
||||||
RemComp<HyperspaceComponent>(comp.Owner);
|
_thruster.DisableLinearThrusters(shuttle);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (comp.TravelStream != null)
|
||||||
|
{
|
||||||
|
comp.TravelStream?.Stop();
|
||||||
|
comp.TravelStream = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
SoundSystem.Play(_arrivalSound.GetSound(), Filter.Empty().AddInRange(Transform(comp.Owner).MapPosition, GetSoundRange(comp.Owner)), _arrivalSound.Params);
|
||||||
|
|
||||||
|
if (TryComp<FTLDestinationComponent>(comp.Owner, out var dest))
|
||||||
|
{
|
||||||
|
dest.Enabled = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
comp.State = FTLState.Cooldown;
|
||||||
|
comp.Accumulator += FTLCooldown;
|
||||||
|
_console.RefreshShuttleConsoles(comp.Owner);
|
||||||
|
break;
|
||||||
|
case FTLState.Cooldown:
|
||||||
|
RemComp<FTLComponent>(comp.Owner);
|
||||||
|
_console.RefreshShuttleConsoles(comp.Owner);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
throw new ArgumentOutOfRangeException();
|
throw new ArgumentOutOfRangeException();
|
||||||
@@ -248,7 +392,10 @@ public sealed partial class ShuttleSystem
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool TryHyperspaceDock(ShuttleComponent component, EntityUid targetUid)
|
/// <summary>
|
||||||
|
/// Tries to dock with the target grid, otherwise falls back to proximity.
|
||||||
|
/// </summary>
|
||||||
|
public bool TryFTLDock(ShuttleComponent component, EntityUid targetUid)
|
||||||
{
|
{
|
||||||
if (!TryComp<TransformComponent>(component.Owner, out var xform) ||
|
if (!TryComp<TransformComponent>(component.Owner, out var xform) ||
|
||||||
!TryComp<TransformComponent>(targetUid, out var targetXform) ||
|
!TryComp<TransformComponent>(targetUid, out var targetXform) ||
|
||||||
@@ -271,6 +418,17 @@ public sealed partial class ShuttleSystem
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TryFTLProximity(component, targetUid, xform, targetXform);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Tries to arrive nearby without overlapping with other grids.
|
||||||
|
/// </summary>
|
||||||
|
public bool TryFTLProximity(ShuttleComponent component, EntityUid targetUid, TransformComponent? xform = null, TransformComponent? targetXform = null)
|
||||||
|
{
|
||||||
|
if (!Resolve(targetUid, ref targetXform) || targetXform.MapUid == null || !Resolve(component.Owner, ref xform)) return false;
|
||||||
|
|
||||||
var shuttleAABB = Comp<IMapGridComponent>(component.Owner).Grid.WorldAABB;
|
var shuttleAABB = Comp<IMapGridComponent>(component.Owner).Grid.WorldAABB;
|
||||||
Box2? aabb = null;
|
Box2? aabb = null;
|
||||||
|
|
||||||
@@ -284,7 +442,7 @@ public sealed partial class ShuttleSystem
|
|||||||
aabb ??= new Box2();
|
aabb ??= new Box2();
|
||||||
|
|
||||||
var minRadius = MathF.Max(aabb.Value.Width, aabb.Value.Height) + MathF.Max(shuttleAABB.Width, shuttleAABB.Height);
|
var minRadius = MathF.Max(aabb.Value.Width, aabb.Value.Height) + MathF.Max(shuttleAABB.Width, shuttleAABB.Height);
|
||||||
var spawnPos = aabb.Value.Center + _random.NextVector2(minRadius, minRadius + 10f);
|
var spawnPos = aabb.Value.Center + _random.NextVector2(minRadius, minRadius + 256f);
|
||||||
|
|
||||||
if (TryComp<PhysicsComponent>(component.Owner, out var shuttleBody))
|
if (TryComp<PhysicsComponent>(component.Owner, out var shuttleBody))
|
||||||
{
|
{
|
||||||
@@ -1,8 +1,7 @@
|
|||||||
using Content.Server.RoundEnd;
|
|
||||||
using Content.Server.Shuttles.Components;
|
using Content.Server.Shuttles.Components;
|
||||||
using Content.Shared.CCVar;
|
using Content.Shared.CCVar;
|
||||||
using Content.Shared.GameTicking;
|
using Content.Shared.GameTicking;
|
||||||
using Content.Shared.Shuttles.Components;
|
using Content.Shared.Shuttles.Systems;
|
||||||
using JetBrains.Annotations;
|
using JetBrains.Annotations;
|
||||||
using Robust.Server.GameObjects;
|
using Robust.Server.GameObjects;
|
||||||
using Robust.Shared.Configuration;
|
using Robust.Shared.Configuration;
|
||||||
@@ -12,7 +11,7 @@ using Robust.Shared.Physics;
|
|||||||
namespace Content.Server.Shuttles.Systems
|
namespace Content.Server.Shuttles.Systems
|
||||||
{
|
{
|
||||||
[UsedImplicitly]
|
[UsedImplicitly]
|
||||||
public sealed partial class ShuttleSystem : EntitySystem
|
public sealed partial class ShuttleSystem : SharedShuttleSystem
|
||||||
{
|
{
|
||||||
[Dependency] private readonly IMapManager _mapManager = default!;
|
[Dependency] private readonly IMapManager _mapManager = default!;
|
||||||
[Dependency] private readonly FixtureSystem _fixtures = default!;
|
[Dependency] private readonly FixtureSystem _fixtures = default!;
|
||||||
@@ -38,6 +37,7 @@ namespace Content.Server.Shuttles.Systems
|
|||||||
|
|
||||||
InitializeEmergencyConsole();
|
InitializeEmergencyConsole();
|
||||||
InitializeEscape();
|
InitializeEscape();
|
||||||
|
InitializeFTL();
|
||||||
|
|
||||||
SubscribeLocalEvent<ShuttleComponent, ComponentAdd>(OnShuttleAdd);
|
SubscribeLocalEvent<ShuttleComponent, ComponentAdd>(OnShuttleAdd);
|
||||||
SubscribeLocalEvent<ShuttleComponent, ComponentStartup>(OnShuttleStartup);
|
SubscribeLocalEvent<ShuttleComponent, ComponentStartup>(OnShuttleStartup);
|
||||||
@@ -138,24 +138,6 @@ namespace Content.Server.Shuttles.Systems
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Enables or disables a shuttle's piloting controls.
|
|
||||||
/// </summary>
|
|
||||||
public void SetPilotable(ShuttleComponent component, bool value)
|
|
||||||
{
|
|
||||||
if (component.CanPilot == value) return;
|
|
||||||
component.CanPilot = value;
|
|
||||||
|
|
||||||
foreach (var comp in EntityQuery<ShuttleConsoleComponent>(true))
|
|
||||||
{
|
|
||||||
comp.CanPilot = value;
|
|
||||||
|
|
||||||
// I'm gonna pray if the UI is force closed and we block UI opens that BUI handles it.
|
|
||||||
if (!value)
|
|
||||||
_uiSystem.GetUiOrNull(comp.Owner, ShuttleConsoleUiKey.Key)?.CloseAll();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Toggle(ShuttleComponent component)
|
public void Toggle(ShuttleComponent component)
|
||||||
{
|
{
|
||||||
if (!EntityManager.TryGetComponent(component.Owner, out PhysicsComponent? physicsComponent)) return;
|
if (!EntityManager.TryGetComponent(component.Owner, out PhysicsComponent? physicsComponent)) return;
|
||||||
@@ -176,7 +158,6 @@ namespace Content.Server.Shuttles.Systems
|
|||||||
{
|
{
|
||||||
component.BodyType = BodyType.Dynamic;
|
component.BodyType = BodyType.Dynamic;
|
||||||
component.BodyStatus = BodyStatus.InAir;
|
component.BodyStatus = BodyStatus.InAir;
|
||||||
//component.FixedRotation = false; TODO WHEN ROTATING SHUTTLES FIXED.
|
|
||||||
component.FixedRotation = false;
|
component.FixedRotation = false;
|
||||||
component.LinearDamping = ShuttleIdleLinearDamping;
|
component.LinearDamping = ShuttleIdleLinearDamping;
|
||||||
component.AngularDamping = ShuttleIdleAngularDamping;
|
component.AngularDamping = ShuttleIdleAngularDamping;
|
||||||
|
|||||||
@@ -17,11 +17,12 @@ public sealed class SpaceGarbageSystem : EntitySystem
|
|||||||
|
|
||||||
private void OnCollide(EntityUid uid, SpaceGarbageComponent component, StartCollideEvent args)
|
private void OnCollide(EntityUid uid, SpaceGarbageComponent component, StartCollideEvent args)
|
||||||
{
|
{
|
||||||
|
if (args.OtherFixture.Body.BodyType != BodyType.Static) return;
|
||||||
|
|
||||||
var ourXform = Transform(args.OurFixture.Body.Owner);
|
var ourXform = Transform(args.OurFixture.Body.Owner);
|
||||||
var otherXform = Transform(args.OtherFixture.Body.Owner);
|
var otherXform = Transform(args.OtherFixture.Body.Owner);
|
||||||
|
|
||||||
if (ourXform.GridUid == otherXform.GridUid ||
|
if (ourXform.GridUid == otherXform.GridUid) return;
|
||||||
args.OtherFixture.Body.BodyType != BodyType.Static) return;
|
|
||||||
|
|
||||||
QueueDel(uid);
|
QueueDel(uid);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
using Content.Shared.Shuttles.Components;
|
using Content.Shared.Shuttles.Components;
|
||||||
|
using Content.Shared.Shuttles.Systems;
|
||||||
using Robust.Shared.Map;
|
using Robust.Shared.Map;
|
||||||
using Robust.Shared.Serialization;
|
using Robust.Shared.Serialization;
|
||||||
|
|
||||||
@@ -7,15 +8,31 @@ namespace Content.Shared.Shuttles.BUIStates;
|
|||||||
[Serializable, NetSerializable]
|
[Serializable, NetSerializable]
|
||||||
public sealed class ShuttleConsoleBoundInterfaceState : RadarConsoleBoundInterfaceState
|
public sealed class ShuttleConsoleBoundInterfaceState : RadarConsoleBoundInterfaceState
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The current FTL state.
|
||||||
|
/// </summary>
|
||||||
|
public readonly FTLState FTLState;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// When the next FTL state change happens.
|
||||||
|
/// </summary>
|
||||||
|
public readonly TimeSpan FTLTime;
|
||||||
public readonly ShuttleMode Mode;
|
public readonly ShuttleMode Mode;
|
||||||
|
public List<(EntityUid Entity, string Destination, bool Enabled)> Destinations;
|
||||||
|
|
||||||
public ShuttleConsoleBoundInterfaceState(
|
public ShuttleConsoleBoundInterfaceState(
|
||||||
|
FTLState ftlState,
|
||||||
|
TimeSpan ftlTime,
|
||||||
ShuttleMode mode,
|
ShuttleMode mode,
|
||||||
|
List<(EntityUid Entity, string Destination, bool Enabled)> destinations,
|
||||||
float maxRange,
|
float maxRange,
|
||||||
EntityCoordinates? coordinates,
|
EntityCoordinates? coordinates,
|
||||||
Angle? angle,
|
Angle? angle,
|
||||||
List<DockingInterfaceState> docks) : base(maxRange, coordinates, angle, docks)
|
List<DockingInterfaceState> docks) : base(maxRange, coordinates, angle, docks)
|
||||||
{
|
{
|
||||||
|
FTLState = ftlState;
|
||||||
|
FTLTime = ftlTime;
|
||||||
|
Destinations = destinations;
|
||||||
Mode = mode;
|
Mode = mode;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,12 @@
|
|||||||
|
using Robust.Shared.Serialization;
|
||||||
|
|
||||||
|
namespace Content.Shared.Shuttles.Events;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Raised on the client when it wishes to travel somewhere.
|
||||||
|
/// </summary>
|
||||||
|
[Serializable, NetSerializable]
|
||||||
|
public sealed class ShuttleConsoleDestinationMessage : BoundUserInterfaceMessage
|
||||||
|
{
|
||||||
|
public EntityUid Destination;
|
||||||
|
}
|
||||||
@@ -4,3 +4,31 @@ public abstract partial class SharedShuttleSystem : EntitySystem
|
|||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Flags]
|
||||||
|
public enum FTLState : byte
|
||||||
|
{
|
||||||
|
Invalid = 0,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// A dummy state for presentation
|
||||||
|
/// </summary>
|
||||||
|
Available = 1 << 0,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Sound played and launch started
|
||||||
|
/// </summary>
|
||||||
|
Starting = 1 << 1,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// When they're on the FTL map
|
||||||
|
/// </summary>
|
||||||
|
Travelling = 1 << 2,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Approaching destination, play effects or whatever,
|
||||||
|
/// </summary>
|
||||||
|
Arriving = 1 << 3,
|
||||||
|
Cooldown = 1 << 4,
|
||||||
|
}
|
||||||
|
|
||||||
|
|||||||
BIN
Resources/Audio/Effects/Shuttle/hyperspace_progress.ogg
Normal file
BIN
Resources/Audio/Effects/Shuttle/hyperspace_progress.ogg
Normal file
Binary file not shown.
@@ -2,4 +2,6 @@ The following sounds are taken from TGstation github (licensed under CC by 3.0):
|
|||||||
|
|
||||||
hyperspace_begin.ogg taken from https://github.com/tgstation/tgstation/tree/71a79f1f75902d2ccab27cbffb971b12b7ab042d/sound/runtime/hyperspace
|
hyperspace_begin.ogg taken from https://github.com/tgstation/tgstation/tree/71a79f1f75902d2ccab27cbffb971b12b7ab042d/sound/runtime/hyperspace
|
||||||
|
|
||||||
hyperspace_end.ogg taken from https://github.com/tgstation/tgstation/tree/71a79f1f75902d2ccab27cbffb971b12b7ab042d/sound/runtime/hyperspace
|
hyperspace_end.ogg taken from https://github.com/tgstation/tgstation/tree/71a79f1f75902d2ccab27cbffb971b12b7ab042d/sound/runtime/hyperspace
|
||||||
|
|
||||||
|
hyperspace_progress.ogg taken and modified for looping by metalgearsloth from https://github.com/tgstation/tgstation/tree/71a79f1f75902d2ccab27cbffb971b12b7ab042d/sound/runtime/hyperspace
|
||||||
@@ -41,5 +41,5 @@ cargo-console-paper-print-text =
|
|||||||
cargo-shuttle-console-menu-title = Cargo shuttle console
|
cargo-shuttle-console-menu-title = Cargo shuttle console
|
||||||
cargo-shuttle-console-station-unknown = Unknown
|
cargo-shuttle-console-station-unknown = Unknown
|
||||||
cargo-shuttle-console-shuttle-not-found = Not found
|
cargo-shuttle-console-shuttle-not-found = Not found
|
||||||
cargo-shuttle-console-proximity = Too close to nearby objects
|
|
||||||
cargo-shuttle-console-organics = Detected organic lifeforms on the shuttle
|
cargo-shuttle-console-organics = Detected organic lifeforms on the shuttle
|
||||||
|
cargo-no-shuttle = No cargo shuttle found!
|
||||||
|
|||||||
@@ -1,9 +1,21 @@
|
|||||||
shuttle-pilot-start = Piloting ship
|
shuttle-pilot-start = Piloting ship
|
||||||
shuttle-pilot-end = Stopped piloting
|
shuttle-pilot-end = Stopped piloting
|
||||||
|
|
||||||
|
shuttle-console-in-ftl = Can't FTL while in FTL!
|
||||||
|
shuttle-console-proximity = Too close to nearby objects
|
||||||
|
|
||||||
# Display
|
# Display
|
||||||
shuttle-console-display-label = Display
|
shuttle-console-display-label = Display
|
||||||
|
|
||||||
|
shuttle-console-ftl-state = FTL State
|
||||||
|
shuttle-console-ftl-available = Available
|
||||||
|
shuttle-console-ftl-starting = Starting
|
||||||
|
shuttle-console-ftl-travelling = Travelling
|
||||||
|
shuttle-console-ftl-arriving = Arriving
|
||||||
|
shuttle-console-ftl-cooldown = Cooldown
|
||||||
|
|
||||||
|
shuttle-console-ftl-timer = FTL Time
|
||||||
|
|
||||||
shuttle-console-max-radar = Max radar range:
|
shuttle-console-max-radar = Max radar range:
|
||||||
shuttle-console-radar = Radar range:
|
shuttle-console-radar = Radar range:
|
||||||
shuttle-console-position = Position:
|
shuttle-console-position = Position:
|
||||||
@@ -15,8 +27,11 @@ shuttle-console-dock-label = Docking ports
|
|||||||
shuttle-console-docked = {$index} (Docked)
|
shuttle-console-docked = {$index} (Docked)
|
||||||
shuttle-console-dock-button = Dock {$suffix}
|
shuttle-console-dock-button = Dock {$suffix}
|
||||||
|
|
||||||
|
shuttle-console-hyperspace-label = FTL destinations
|
||||||
|
shuttle-console-hyperspace-none = No destinations found
|
||||||
|
|
||||||
shuttle-console-unknown = Unknown
|
shuttle-console-unknown = Unknown
|
||||||
shuttle-console-iff-label = "{$name} ({$distance}m)
|
shuttle-console-iff-label = {$name} ({$distance}m)
|
||||||
|
|
||||||
# Buttons
|
# Buttons
|
||||||
shuttle-console-strafing = Strafing mode
|
shuttle-console-strafing = Strafing mode
|
||||||
|
|||||||
@@ -447,6 +447,8 @@ entities:
|
|||||||
- pos: -1.5406153,-0.3539288
|
- pos: -1.5406153,-0.3539288
|
||||||
parent: null
|
parent: null
|
||||||
type: Transform
|
type: Transform
|
||||||
|
- name: Central Command
|
||||||
|
type: MetaData
|
||||||
- index: 0
|
- index: 0
|
||||||
type: MapGrid
|
type: MapGrid
|
||||||
- angularDamping: 100
|
- angularDamping: 100
|
||||||
|
|||||||
8410
Resources/Maps/nukieplanet.yml
Normal file
8410
Resources/Maps/nukieplanet.yml
Normal file
File diff suppressed because it is too large
Load Diff
@@ -81,6 +81,9 @@
|
|||||||
name: syndicate shuttle console
|
name: syndicate shuttle console
|
||||||
description: Used to pilot a syndicate shuttle.
|
description: Used to pilot a syndicate shuttle.
|
||||||
components:
|
components:
|
||||||
|
- type: Tag
|
||||||
|
tags:
|
||||||
|
- Syndicate
|
||||||
- type: Appearance
|
- type: Appearance
|
||||||
visuals:
|
visuals:
|
||||||
- type: ComputerVisualizer
|
- type: ComputerVisualizer
|
||||||
|
|||||||
@@ -405,6 +405,9 @@
|
|||||||
- type: Tag
|
- type: Tag
|
||||||
id: StringInstrument
|
id: StringInstrument
|
||||||
|
|
||||||
|
- type: Tag
|
||||||
|
id: Syndicate
|
||||||
|
|
||||||
- type: Tag
|
- type: Tag
|
||||||
id: SyndicateSegwayKeys
|
id: SyndicateSegwayKeys
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user