Compare commits
188 Commits
ed-09-12-2
...
MagicWands
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
fff4287ad5 | ||
|
|
d1e4501b6f | ||
|
|
fc4f51f0dd | ||
|
|
c42b77d0c9 | ||
|
|
6c8b0a07f3 | ||
|
|
06cb93fb1d | ||
|
|
af918c1253 | ||
|
|
be15a4097c | ||
|
|
cd736e4fd4 | ||
|
|
576bbe91d0 | ||
|
|
14dbb5d3ed | ||
|
|
337d248884 | ||
|
|
e4b60b31c0 | ||
|
|
596c329c96 | ||
|
|
bae34b8318 | ||
|
|
e7e4e61972 | ||
|
|
99786342fb | ||
|
|
fc90485838 | ||
|
|
ac5579c7fd | ||
|
|
cd618efc31 | ||
|
|
3844352fee | ||
|
|
8472603b76 | ||
|
|
3300ff2a06 | ||
|
|
b66fd98514 | ||
|
|
e244472546 | ||
|
|
de19418126 | ||
|
|
6add781c4a | ||
|
|
d6d95f1a7a | ||
|
|
7d410d6094 | ||
|
|
2d6e52b21c | ||
|
|
623a35b3fe | ||
|
|
94090f7403 | ||
|
|
274c3ab0b9 | ||
|
|
38c8ffb9b5 | ||
|
|
52a886947f | ||
|
|
d6ba7598bd | ||
|
|
207c849e2d | ||
|
|
cd1177d9ba | ||
|
|
3e0b93d071 | ||
|
|
0e6ec2e1af | ||
|
|
8f3973b2eb | ||
|
|
97ece026d5 | ||
|
|
dc8b859916 | ||
|
|
ce672acf91 | ||
|
|
6f51aa4b15 | ||
|
|
59bce41390 | ||
|
|
bcf2b9afeb | ||
|
|
90c8776a60 | ||
|
|
da68ae94c1 | ||
|
|
6b41aa71ca | ||
|
|
a4395f2066 | ||
|
|
685a9616ab | ||
|
|
fbfcccbe16 | ||
|
|
82528dce37 | ||
|
|
152cf3388b | ||
|
|
2e26ca786d | ||
|
|
fc8f7fb0ba | ||
|
|
c10a72be39 | ||
|
|
7ffd8012f6 | ||
|
|
cf202e805d | ||
|
|
87182635b6 | ||
|
|
2c2a435dbd | ||
|
|
bfd005a37f | ||
|
|
e50c98c618 | ||
|
|
029b0374e9 | ||
|
|
c1491e91b8 | ||
|
|
2e31eb32cb | ||
|
|
f0829a6652 | ||
|
|
e4e84aea74 | ||
|
|
b800d98260 | ||
|
|
cc804bf316 | ||
|
|
638a1dc489 | ||
|
|
7f966ab9b1 | ||
|
|
86168288a3 | ||
|
|
81dd06ac2c | ||
|
|
560fd8dd77 | ||
|
|
b3841e8414 | ||
|
|
d4067bcaab | ||
|
|
237324e268 | ||
|
|
bf312f2306 | ||
|
|
5fdf03c216 | ||
|
|
2d405c9652 | ||
|
|
3984f0aa0a | ||
|
|
a46323d9f9 | ||
|
|
061b1b8adb | ||
|
|
44ef60a642 | ||
|
|
efb35d7953 | ||
|
|
720fccf3f3 | ||
|
|
ab36b15080 | ||
|
|
766389a66b | ||
|
|
fb76cd952e | ||
|
|
3d984603f1 | ||
|
|
450bf813b8 | ||
|
|
973f42b3b2 | ||
|
|
021c9832ef | ||
|
|
86791583f9 | ||
|
|
08db47cb28 | ||
|
|
b45c9d5129 | ||
|
|
e9ef00f475 | ||
|
|
54a9dce68d | ||
|
|
17a224c86a | ||
|
|
9236e9e5b9 | ||
|
|
6c86d7b32b | ||
|
|
f99331aa00 | ||
|
|
87d6b0b79b | ||
|
|
bbdadd7144 | ||
|
|
3ad227a904 | ||
|
|
422d1a9d32 | ||
|
|
2e340578ff | ||
|
|
360f6982f4 | ||
|
|
93bdd813c4 | ||
|
|
b53c8ea60e | ||
|
|
4a21ed87db | ||
|
|
6463e7e08e | ||
|
|
a790955b76 | ||
|
|
f6813e39c7 | ||
|
|
a206acc220 | ||
|
|
de613e45f8 | ||
|
|
ac65c5a55d | ||
|
|
9704ed7a00 | ||
|
|
56fd7cbb6f | ||
|
|
1bc65624c8 | ||
|
|
1b6c9e866b | ||
|
|
8ea388b309 | ||
|
|
6187675c27 | ||
|
|
c861c56a69 | ||
|
|
eb9540364e | ||
|
|
ab7221efad | ||
|
|
dfc3562bfc | ||
|
|
41d2cf166d | ||
|
|
470c869ce2 | ||
|
|
d5225d1f46 | ||
|
|
a69fc39fc0 | ||
|
|
f27fa1ed30 | ||
|
|
e9eca826d8 | ||
|
|
f0e9de8489 | ||
|
|
b8c8f7d0f8 | ||
|
|
b8466d8321 | ||
|
|
49724a9b9d | ||
|
|
ae576abe1f | ||
|
|
45cf4ec340 | ||
|
|
ea7f5433ac | ||
|
|
32f48d974f | ||
|
|
14103e7a86 | ||
|
|
da9b2e6a10 | ||
|
|
f53e3ec3c1 | ||
|
|
9a898bb98e | ||
|
|
86a3d1636f | ||
|
|
ed2cd23309 | ||
|
|
3c6c5ab6c9 | ||
|
|
d642ee7707 | ||
|
|
cae49ae0d2 | ||
|
|
91b9d4a7f0 | ||
|
|
e436a50c36 | ||
|
|
84df2b857e | ||
|
|
aa80a88cc4 | ||
|
|
2229a6a04b | ||
|
|
f706170ee1 | ||
|
|
ef89d5cc21 | ||
|
|
e958c0c9b0 | ||
|
|
11dbf50ed6 | ||
|
|
8522ffe8ce | ||
|
|
fab9993a3b | ||
|
|
4cecf99e65 | ||
|
|
855547a2d4 | ||
|
|
45af6a13fc | ||
|
|
11dae2ff93 | ||
|
|
bde85858a3 | ||
|
|
c3786a56dc | ||
|
|
bdf4a46edf | ||
|
|
a42bacd3a9 | ||
|
|
1e93e12330 | ||
|
|
0a587c9ccc | ||
|
|
7feafcbe95 | ||
|
|
5409815be9 | ||
|
|
d8ecf12fca | ||
|
|
616907009d | ||
|
|
6bc205484f | ||
|
|
a28adf4ae4 | ||
|
|
de516905f0 | ||
|
|
306277afe0 | ||
|
|
08bfb43feb | ||
|
|
5a9a2d463b | ||
|
|
3758715bdc | ||
|
|
c02a027cf1 | ||
|
|
e96e80bc95 | ||
|
|
f23b6522b2 | ||
|
|
693e5f1fad |
2
.github/workflows/labeler-review.yml
vendored
2
.github/workflows/labeler-review.yml
vendored
@@ -16,7 +16,7 @@ jobs:
|
||||
with:
|
||||
username: ${{ github.actor }}
|
||||
team: "content-maintainers,junior-maintainers"
|
||||
GITHUB_TOKEN: ${{ secrets.GH_PAT }}
|
||||
GITHUB_TOKEN: ${{ secrets.LABELER_PAT }}
|
||||
- if: ${{ steps.checkUserMember.outputs.isTeamMember == 'true' }}
|
||||
uses: actions-ecosystem/action-add-labels@v1
|
||||
with:
|
||||
|
||||
@@ -258,13 +258,13 @@ namespace Content.Client.Actions
|
||||
|
||||
public void LinkAllActions(ActionsComponent? actions = null)
|
||||
{
|
||||
if (_playerManager.LocalEntity is not { } user ||
|
||||
!Resolve(user, ref actions, false))
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (_playerManager.LocalEntity is not { } user ||
|
||||
!Resolve(user, ref actions, false))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
LinkActions?.Invoke(actions);
|
||||
LinkActions?.Invoke(actions);
|
||||
}
|
||||
|
||||
public override void Shutdown()
|
||||
|
||||
@@ -159,6 +159,7 @@ public sealed partial class NoteEdit : FancyWindow
|
||||
SecretCheckBox.Pressed = false;
|
||||
SeverityOption.Disabled = false;
|
||||
PermanentCheckBox.Pressed = true;
|
||||
SubmitButton.Disabled = true;
|
||||
UpdatePermanentCheckboxFields();
|
||||
break;
|
||||
case (int) NoteType.Message: // Message: these are shown to the player when they log on
|
||||
|
||||
@@ -1,8 +1,4 @@
|
||||
using Robust.Shared.GameObjects;
|
||||
|
||||
namespace Content.Client.Atmos.Components;
|
||||
|
||||
[RegisterComponent]
|
||||
public sealed partial class PipeColorVisualsComponent : Component
|
||||
{
|
||||
}
|
||||
public sealed partial class PipeColorVisualsComponent : Component;
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
<BoxContainer xmlns="https://spacestation14.io"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:s="clr-namespace:Content.Client.Stylesheets"
|
||||
xmlns:gfx="clr-namespace:Robust.Client.Graphics;assembly=Robust.Client"
|
||||
xmlns:controls="clr-namespace:Content.Client.UserInterface.Controls"
|
||||
Orientation="Vertical" HorizontalExpand ="True" Margin="0 0 0 3">
|
||||
@@ -62,7 +61,7 @@
|
||||
</PanelContainer>
|
||||
</BoxContainer>
|
||||
|
||||
<!-- If the alarm is inactive, this is label is diplayed instead -->
|
||||
<!-- If the alarm is inactive, this is label is displayed instead -->
|
||||
<Label Name="NoDataLabel" Text="{Loc 'atmos-alerts-window-no-data-available'}" HorizontalAlignment="Center" Margin="0 15" FontColorOverride="#a9a9a9" ReservesSpace="False" Visible="False"></Label>
|
||||
|
||||
<!-- Silencing progress bar -->
|
||||
|
||||
@@ -136,8 +136,9 @@ public sealed partial class AtmosAlarmEntryContainer : BoxContainer
|
||||
GasGridContainer.RemoveAllChildren();
|
||||
|
||||
var gasData = focusData.Value.GasData.Where(g => g.Key != Gas.Oxygen);
|
||||
var keyValuePairs = gasData.ToList();
|
||||
|
||||
if (gasData.Count() == 0)
|
||||
if (keyValuePairs.Count == 0)
|
||||
{
|
||||
// No other gases
|
||||
var gasLabel = new Label()
|
||||
@@ -158,13 +159,11 @@ public sealed partial class AtmosAlarmEntryContainer : BoxContainer
|
||||
else
|
||||
{
|
||||
// Add an entry for each gas
|
||||
foreach ((var gas, (var mol, var percent, var alert)) in gasData)
|
||||
foreach ((var gas, (var mol, var percent, var alert)) in keyValuePairs)
|
||||
{
|
||||
var gasPercent = (FixedPoint2)0f;
|
||||
gasPercent = percent * 100f;
|
||||
FixedPoint2 gasPercent = percent * 100f;
|
||||
|
||||
if (!_gasShorthands.TryGetValue(gas, out var gasShorthand))
|
||||
gasShorthand = "X";
|
||||
var gasShorthand = _gasShorthands.GetValueOrDefault(gas, "X");
|
||||
|
||||
var gasLabel = new Label()
|
||||
{
|
||||
|
||||
@@ -14,8 +14,6 @@ public sealed class AtmosAlertsComputerBoundUserInterface : BoundUserInterface
|
||||
_menu = new AtmosAlertsComputerWindow(this, Owner);
|
||||
_menu.OpenCentered();
|
||||
_menu.OnClose += Close;
|
||||
|
||||
EntMan.TryGetComponent<TransformComponent>(Owner, out var xform);
|
||||
}
|
||||
|
||||
protected override void UpdateState(BoundUserInterfaceState state)
|
||||
@@ -24,9 +22,6 @@ public sealed class AtmosAlertsComputerBoundUserInterface : BoundUserInterface
|
||||
|
||||
var castState = (AtmosAlertsComputerBoundInterfaceState) state;
|
||||
|
||||
if (castState == null)
|
||||
return;
|
||||
|
||||
EntMan.TryGetComponent<TransformComponent>(Owner, out var xform);
|
||||
_menu?.UpdateUI(xform?.Coordinates, castState.AirAlarms, castState.FireAlarms, castState.FocusData);
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
<controls:FancyWindow xmlns="https://spacestation14.io"
|
||||
xmlns:ui="clr-namespace:Content.Client.Pinpointer.UI"
|
||||
xmlns:controls="clr-namespace:Content.Client.UserInterface.Controls"
|
||||
xmlns:gfx="clr-namespace:Robust.Client.Graphics;assembly=Robust.Client"
|
||||
Title="{Loc 'atmos-alerts-window-title'}"
|
||||
Resizable="False"
|
||||
SetSize="1120 750"
|
||||
|
||||
@@ -4,8 +4,6 @@ using Content.Shared.Atmos.Components;
|
||||
using Content.Shared.Atmos.Piping;
|
||||
using JetBrains.Annotations;
|
||||
using Robust.Client.GameObjects;
|
||||
using Robust.Client.ResourceManagement;
|
||||
using Robust.Shared.Serialization.TypeSerializers.Implementations;
|
||||
|
||||
namespace Content.Client.Atmos.EntitySystems;
|
||||
|
||||
@@ -19,7 +17,7 @@ public sealed class AtmosPipeAppearanceSystem : EntitySystem
|
||||
base.Initialize();
|
||||
|
||||
SubscribeLocalEvent<PipeAppearanceComponent, ComponentInit>(OnInit);
|
||||
SubscribeLocalEvent<PipeAppearanceComponent, AppearanceChangeEvent>(OnAppearanceChanged, after: new[] { typeof(SubFloorHideSystem) });
|
||||
SubscribeLocalEvent<PipeAppearanceComponent, AppearanceChangeEvent>(OnAppearanceChanged, after: [typeof(SubFloorHideSystem)]);
|
||||
}
|
||||
|
||||
private void OnInit(EntityUid uid, PipeAppearanceComponent component, ComponentInit args)
|
||||
@@ -84,7 +82,8 @@ public sealed class AtmosPipeAppearanceSystem : EntitySystem
|
||||
|
||||
layer.Visible &= visible;
|
||||
|
||||
if (!visible) continue;
|
||||
if (!visible)
|
||||
continue;
|
||||
|
||||
layer.Color = color;
|
||||
}
|
||||
|
||||
@@ -1,12 +1,7 @@
|
||||
using System.Collections.Generic;
|
||||
using Content.Shared.Atmos.Monitor;
|
||||
using Content.Shared.Power;
|
||||
using Robust.Client.GameObjects;
|
||||
using Robust.Client.Graphics;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.IoC;
|
||||
using Robust.Shared.Maths;
|
||||
using Robust.Shared.Serialization.Manager.Attributes;
|
||||
|
||||
namespace Content.Client.Atmos.Monitor;
|
||||
|
||||
@@ -27,7 +22,7 @@ public sealed class AtmosAlarmableVisualsSystem : VisualizerSystem<AtmosAlarmabl
|
||||
{
|
||||
foreach (var visLayer in component.HideOnDepowered)
|
||||
{
|
||||
if (args.Sprite.LayerMapTryGet(visLayer, out int powerVisibilityLayer))
|
||||
if (args.Sprite.LayerMapTryGet(visLayer, out var powerVisibilityLayer))
|
||||
args.Sprite.LayerSetVisible(powerVisibilityLayer, powered);
|
||||
}
|
||||
}
|
||||
@@ -36,7 +31,7 @@ public sealed class AtmosAlarmableVisualsSystem : VisualizerSystem<AtmosAlarmabl
|
||||
{
|
||||
foreach (var (setLayer, powerState) in component.SetOnDepowered)
|
||||
{
|
||||
if (args.Sprite.LayerMapTryGet(setLayer, out int setStateLayer))
|
||||
if (args.Sprite.LayerMapTryGet(setLayer, out var setStateLayer))
|
||||
args.Sprite.LayerSetState(setStateLayer, new RSI.StateId(powerState));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,11 +1,7 @@
|
||||
using Content.Shared.Atmos;
|
||||
using Content.Shared.Atmos.Monitor;
|
||||
using Content.Shared.Atmos.Monitor.Components;
|
||||
using Robust.Client.GameObjects;
|
||||
using Robust.Client.UserInterface;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.IoC;
|
||||
using Robust.Shared.Log;
|
||||
|
||||
namespace Content.Client.Atmos.Monitor.UI;
|
||||
|
||||
@@ -78,6 +74,7 @@ public sealed class AirAlarmBoundUserInterface : BoundUserInterface
|
||||
{
|
||||
base.Dispose(disposing);
|
||||
|
||||
if (disposing) _window?.Dispose();
|
||||
if (disposing)
|
||||
_window?.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,7 +8,6 @@ using Content.Shared.Atmos.Monitor.Components;
|
||||
using Content.Shared.Atmos.Piping.Unary.Components;
|
||||
using Content.Shared.Temperature;
|
||||
using Robust.Client.AutoGenerated;
|
||||
using Robust.Client.GameObjects;
|
||||
using Robust.Client.UserInterface.Controls;
|
||||
using Robust.Client.UserInterface.XAML;
|
||||
|
||||
@@ -59,7 +58,7 @@ public sealed partial class AirAlarmWindow : FancyWindow
|
||||
AirAlarmMode.Fill => "air-alarm-ui-mode-fill",
|
||||
AirAlarmMode.Panic => "air-alarm-ui-mode-panic",
|
||||
AirAlarmMode.None => "air-alarm-ui-mode-none",
|
||||
_ => "error"
|
||||
_ => "error",
|
||||
};
|
||||
_modes.AddItem(Loc.GetString(text));
|
||||
}
|
||||
@@ -70,7 +69,7 @@ public sealed partial class AirAlarmWindow : FancyWindow
|
||||
AirAlarmModeChanged!.Invoke((AirAlarmMode) args.Id);
|
||||
};
|
||||
|
||||
_autoMode.OnToggled += args =>
|
||||
_autoMode.OnToggled += _ =>
|
||||
{
|
||||
AutoModeChanged!.Invoke(_autoMode.Pressed);
|
||||
};
|
||||
@@ -176,22 +175,18 @@ public sealed partial class AirAlarmWindow : FancyWindow
|
||||
|
||||
public static Color ColorForThreshold(float amount, AtmosAlarmThreshold threshold)
|
||||
{
|
||||
threshold.CheckThreshold(amount, out AtmosAlarmType curAlarm);
|
||||
threshold.CheckThreshold(amount, out var curAlarm);
|
||||
return ColorForAlarm(curAlarm);
|
||||
}
|
||||
|
||||
public static Color ColorForAlarm(AtmosAlarmType curAlarm)
|
||||
{
|
||||
if(curAlarm == AtmosAlarmType.Danger)
|
||||
return curAlarm switch
|
||||
{
|
||||
return StyleNano.DangerousRedFore;
|
||||
}
|
||||
else if(curAlarm == AtmosAlarmType.Warning)
|
||||
{
|
||||
return StyleNano.ConcerningOrangeFore;
|
||||
}
|
||||
|
||||
return StyleNano.GoodGreenFore;
|
||||
AtmosAlarmType.Danger => StyleNano.DangerousRedFore,
|
||||
AtmosAlarmType.Warning => StyleNano.ConcerningOrangeFore,
|
||||
_ => StyleNano.GoodGreenFore,
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -1,12 +1,8 @@
|
||||
using System;
|
||||
using Content.Shared.Atmos.Monitor;
|
||||
using Content.Shared.Atmos.Monitor.Components;
|
||||
using Content.Shared.Atmos.Piping.Unary.Components;
|
||||
using Robust.Client.AutoGenerated;
|
||||
using Robust.Client.UserInterface.Controls;
|
||||
using Robust.Client.UserInterface.CustomControls;
|
||||
using Robust.Client.UserInterface.XAML;
|
||||
using Robust.Shared.Localization;
|
||||
|
||||
namespace Content.Client.Atmos.Monitor.UI.Widgets;
|
||||
|
||||
@@ -25,7 +21,7 @@ public sealed partial class PumpControl : BoxContainer
|
||||
private OptionButton _pressureCheck => CPressureCheck;
|
||||
private FloatSpinBox _externalBound => CExternalBound;
|
||||
private FloatSpinBox _internalBound => CInternalBound;
|
||||
private Button _copySettings => CCopySettings;
|
||||
private Button _copySettings => CCopySettings;
|
||||
|
||||
public PumpControl(GasVentPumpData data, string address)
|
||||
{
|
||||
@@ -86,7 +82,7 @@ public sealed partial class PumpControl : BoxContainer
|
||||
_data.PressureChecks = (VentPressureBound) args.Id;
|
||||
PumpDataChanged?.Invoke(_address, _data);
|
||||
};
|
||||
|
||||
|
||||
_copySettings.OnPressed += _ =>
|
||||
{
|
||||
PumpDataCopied?.Invoke(_data);
|
||||
|
||||
@@ -1,15 +1,9 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Content.Shared.Atmos;
|
||||
using Content.Shared.Atmos.Monitor;
|
||||
using Content.Shared.Atmos.Monitor.Components;
|
||||
using Content.Shared.Atmos.Piping.Unary.Components;
|
||||
using Robust.Client.AutoGenerated;
|
||||
using Robust.Client.UserInterface.Controls;
|
||||
using Robust.Client.UserInterface.CustomControls;
|
||||
using Robust.Client.UserInterface.XAML;
|
||||
using Robust.Shared.Localization;
|
||||
|
||||
namespace Content.Client.Atmos.Monitor.UI.Widgets;
|
||||
|
||||
@@ -27,7 +21,7 @@ public sealed partial class ScrubberControl : BoxContainer
|
||||
private OptionButton _pumpDirection => CPumpDirection;
|
||||
private FloatSpinBox _volumeRate => CVolumeRate;
|
||||
private CheckBox _wideNet => CWideNet;
|
||||
private Button _copySettings => CCopySettings;
|
||||
private Button _copySettings => CCopySettings;
|
||||
|
||||
private GridContainer _gases => CGasContainer;
|
||||
private Dictionary<Gas, Button> _gasControls = new();
|
||||
@@ -77,7 +71,7 @@ public sealed partial class ScrubberControl : BoxContainer
|
||||
_data.PumpDirection = (ScrubberPumpDirection) args.Id;
|
||||
ScrubberDataChanged?.Invoke(_address, _data);
|
||||
};
|
||||
|
||||
|
||||
_copySettings.OnPressed += _ =>
|
||||
{
|
||||
ScrubberDataCopied?.Invoke(_data);
|
||||
|
||||
@@ -43,7 +43,8 @@ public sealed partial class SensorInfo : BoxContainer
|
||||
var label = new RichTextLabel();
|
||||
|
||||
var fractionGas = amount / data.TotalMoles;
|
||||
label.SetMarkup(Loc.GetString("air-alarm-ui-gases-indicator", ("gas", $"{gas}"),
|
||||
label.SetMarkup(Loc.GetString("air-alarm-ui-gases-indicator",
|
||||
("gas", $"{gas}"),
|
||||
("color", AirAlarmWindow.ColorForThreshold(fractionGas, data.GasThresholds[gas])),
|
||||
("amount", $"{amount:0.####}"),
|
||||
("percentage", $"{(100 * fractionGas):0.##}")));
|
||||
@@ -53,9 +54,9 @@ public sealed partial class SensorInfo : BoxContainer
|
||||
var threshold = data.GasThresholds[gas];
|
||||
var gasThresholdControl = new ThresholdControl(Loc.GetString($"air-alarm-ui-thresholds-gas-title", ("gas", $"{gas}")), threshold, AtmosMonitorThresholdType.Gas, gas, 100);
|
||||
gasThresholdControl.Margin = new Thickness(20, 2, 2, 2);
|
||||
gasThresholdControl.ThresholdDataChanged += (type, threshold, arg3) =>
|
||||
gasThresholdControl.ThresholdDataChanged += (type, alarmThreshold, arg3) =>
|
||||
{
|
||||
OnThresholdUpdate!(_address, type, threshold, arg3);
|
||||
OnThresholdUpdate!(_address, type, alarmThreshold, arg3);
|
||||
};
|
||||
|
||||
_gasThresholds.Add(gas, gasThresholdControl);
|
||||
@@ -64,7 +65,8 @@ public sealed partial class SensorInfo : BoxContainer
|
||||
|
||||
_pressureThreshold = new ThresholdControl(Loc.GetString("air-alarm-ui-thresholds-pressure-title"), data.PressureThreshold, AtmosMonitorThresholdType.Pressure);
|
||||
PressureThresholdContainer.AddChild(_pressureThreshold);
|
||||
_temperatureThreshold = new ThresholdControl(Loc.GetString("air-alarm-ui-thresholds-temperature-title"), data.TemperatureThreshold,
|
||||
_temperatureThreshold = new ThresholdControl(Loc.GetString("air-alarm-ui-thresholds-temperature-title"),
|
||||
data.TemperatureThreshold,
|
||||
AtmosMonitorThresholdType.Temperature);
|
||||
TemperatureThresholdContainer.AddChild(_temperatureThreshold);
|
||||
|
||||
@@ -103,7 +105,8 @@ public sealed partial class SensorInfo : BoxContainer
|
||||
}
|
||||
|
||||
var fractionGas = amount / data.TotalMoles;
|
||||
label.SetMarkup(Loc.GetString("air-alarm-ui-gases-indicator", ("gas", $"{gas}"),
|
||||
label.SetMarkup(Loc.GetString("air-alarm-ui-gases-indicator",
|
||||
("gas", $"{gas}"),
|
||||
("color", AirAlarmWindow.ColorForThreshold(fractionGas, data.GasThresholds[gas])),
|
||||
("amount", $"{amount:0.####}"),
|
||||
("percentage", $"{(100 * fractionGas):0.##}")));
|
||||
|
||||
@@ -1,7 +1,4 @@
|
||||
using Content.Client.Message;
|
||||
using Content.Shared.Atmos;
|
||||
using Content.Shared.Atmos.Monitor;
|
||||
using Content.Shared.Temperature;
|
||||
using Robust.Client.AutoGenerated;
|
||||
using Robust.Client.UserInterface.Controls;
|
||||
using Robust.Client.UserInterface.XAML;
|
||||
|
||||
@@ -1,12 +1,8 @@
|
||||
using System;
|
||||
using Content.Shared.Atmos;
|
||||
using Content.Shared.Atmos.Monitor;
|
||||
using Content.Shared.Atmos.Monitor.Components;
|
||||
using Robust.Client.AutoGenerated;
|
||||
using Robust.Client.UserInterface.Controls;
|
||||
using Robust.Client.UserInterface.CustomControls;
|
||||
using Robust.Client.UserInterface.XAML;
|
||||
using Robust.Shared.Localization;
|
||||
|
||||
// holy FUCK
|
||||
// this technically works because some of this you can *not* do in XAML but holy FUCK
|
||||
@@ -115,29 +111,38 @@ public sealed partial class ThresholdControl : BoxContainer
|
||||
_enabled.Pressed = !_threshold.Ignore;
|
||||
}
|
||||
|
||||
private String LabelForBound(string boundType) //<todo.eoin Replace this with enums
|
||||
private string LabelForBound(string boundType) //<todo.eoin Replace this with enums
|
||||
{
|
||||
return Loc.GetString($"air-alarm-ui-thresholds-{boundType}");
|
||||
}
|
||||
|
||||
public void UpdateThresholdData(AtmosAlarmThreshold threshold, float currentAmount)
|
||||
{
|
||||
threshold.CheckThreshold(currentAmount, out AtmosAlarmType alarm, out AtmosMonitorThresholdBound which);
|
||||
threshold.CheckThreshold(currentAmount, out var alarm, out var bound);
|
||||
|
||||
var upperDangerState = AtmosAlarmType.Normal;
|
||||
var lowerDangerState = AtmosAlarmType.Normal;
|
||||
var upperWarningState = AtmosAlarmType.Normal;
|
||||
var lowerWarningState = AtmosAlarmType.Normal;
|
||||
|
||||
if(alarm == AtmosAlarmType.Danger)
|
||||
switch (alarm)
|
||||
{
|
||||
if(which == AtmosMonitorThresholdBound.Upper) upperDangerState = alarm;
|
||||
else lowerDangerState = alarm;
|
||||
}
|
||||
else if(alarm == AtmosAlarmType.Warning)
|
||||
{
|
||||
if(which == AtmosMonitorThresholdBound.Upper) upperWarningState = alarm;
|
||||
else lowerWarningState = alarm;
|
||||
case AtmosAlarmType.Danger:
|
||||
{
|
||||
if (bound == AtmosMonitorThresholdBound.Upper)
|
||||
upperDangerState = alarm;
|
||||
else
|
||||
lowerDangerState = alarm;
|
||||
break;
|
||||
}
|
||||
case AtmosAlarmType.Warning:
|
||||
{
|
||||
if (bound == AtmosMonitorThresholdBound.Upper)
|
||||
upperWarningState = alarm;
|
||||
else
|
||||
lowerWarningState = alarm;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
_upperBoundControl.SetValue(threshold.UpperBound.Value);
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Numerics;
|
||||
using Content.Client.Atmos.EntitySystems;
|
||||
@@ -101,14 +102,9 @@ public sealed class AtmosDebugOverlay : Overlay
|
||||
else
|
||||
{
|
||||
// Red-Green-Blue interpolation
|
||||
if (interp < 0.5f)
|
||||
{
|
||||
res = Color.InterpolateBetween(Color.Red, Color.LimeGreen, interp * 2);
|
||||
}
|
||||
else
|
||||
{
|
||||
res = Color.InterpolateBetween(Color.LimeGreen, Color.Blue, (interp - 0.5f) * 2);
|
||||
}
|
||||
res = interp < 0.5f
|
||||
? Color.InterpolateBetween(Color.Red, Color.LimeGreen, interp * 2)
|
||||
: Color.InterpolateBetween(Color.LimeGreen, Color.Blue, (interp - 0.5f) * 2);
|
||||
}
|
||||
|
||||
res = res.WithAlpha(0.75f);
|
||||
@@ -181,7 +177,10 @@ public sealed class AtmosDebugOverlay : Overlay
|
||||
handle.DrawCircle(tileCentre, 0.05f, Color.Black);
|
||||
}
|
||||
|
||||
private void CheckAndShowBlockDir(AtmosDebugOverlayData data, DrawingHandleWorld handle, AtmosDirection dir,
|
||||
private void CheckAndShowBlockDir(
|
||||
AtmosDebugOverlayData data,
|
||||
DrawingHandleWorld handle,
|
||||
AtmosDirection dir,
|
||||
Vector2 tileCentre)
|
||||
{
|
||||
if (!data.BlockDirection.HasFlag(dir))
|
||||
@@ -243,7 +242,7 @@ public sealed class AtmosDebugOverlay : Overlay
|
||||
|
||||
var moles = data.Moles == null
|
||||
? "No Air"
|
||||
: data.Moles.Sum().ToString();
|
||||
: data.Moles.Sum().ToString(CultureInfo.InvariantCulture);
|
||||
|
||||
handle.DrawString(_font, pos, $"Moles: {moles}");
|
||||
pos += offset;
|
||||
@@ -263,7 +262,12 @@ public sealed class AtmosDebugOverlay : Overlay
|
||||
private void GetGrids(MapId mapId, Box2Rotated box)
|
||||
{
|
||||
_grids.Clear();
|
||||
_mapManager.FindGridsIntersecting(mapId, box, ref _grids, (EntityUid uid, MapGridComponent grid,
|
||||
_mapManager.FindGridsIntersecting(
|
||||
mapId,
|
||||
box,
|
||||
ref _grids,
|
||||
(EntityUid uid,
|
||||
MapGridComponent grid,
|
||||
ref List<(Entity<MapGridComponent>, DebugMessage)> state) =>
|
||||
{
|
||||
if (_system.TileData.TryGetValue(uid, out var data))
|
||||
|
||||
@@ -7,7 +7,7 @@ using Robust.Client.GameObjects;
|
||||
|
||||
namespace Content.Client.Clothing;
|
||||
|
||||
public sealed class FlippableClothingVisualizerSystem : VisualizerSystem<FlippableClothingVisualsComponent>
|
||||
public sealed class FlippableClothingVisualizerSystem : VisualizerSystem<FlippableClothingVisualsComponent>
|
||||
{
|
||||
[Dependency] private readonly SharedItemSystem _itemSys = default!;
|
||||
|
||||
|
||||
@@ -0,0 +1,95 @@
|
||||
using Content.Shared.Electrocution;
|
||||
using Robust.Client.GameObjects;
|
||||
using Robust.Client.Player;
|
||||
using Robust.Shared.Player;
|
||||
|
||||
namespace Content.Client.Electrocution;
|
||||
|
||||
/// <summary>
|
||||
/// Shows the Electrocution HUD to entities with the ShowElectrocutionHUDComponent.
|
||||
/// </summary>
|
||||
public sealed class ElectrocutionHUDVisualizerSystem : VisualizerSystem<ElectrocutionHUDVisualsComponent>
|
||||
{
|
||||
[Dependency] private readonly IPlayerManager _playerMan = default!;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
|
||||
SubscribeLocalEvent<ShowElectrocutionHUDComponent, ComponentInit>(OnInit);
|
||||
SubscribeLocalEvent<ShowElectrocutionHUDComponent, ComponentShutdown>(OnShutdown);
|
||||
SubscribeLocalEvent<ShowElectrocutionHUDComponent, LocalPlayerAttachedEvent>(OnPlayerAttached);
|
||||
SubscribeLocalEvent<ShowElectrocutionHUDComponent, LocalPlayerDetachedEvent>(OnPlayerDetached);
|
||||
}
|
||||
|
||||
private void OnPlayerAttached(Entity<ShowElectrocutionHUDComponent> ent, ref LocalPlayerAttachedEvent args)
|
||||
{
|
||||
ShowHUD();
|
||||
}
|
||||
|
||||
private void OnPlayerDetached(Entity<ShowElectrocutionHUDComponent> ent, ref LocalPlayerDetachedEvent args)
|
||||
{
|
||||
RemoveHUD();
|
||||
}
|
||||
|
||||
private void OnInit(Entity<ShowElectrocutionHUDComponent> ent, ref ComponentInit args)
|
||||
{
|
||||
if (_playerMan.LocalEntity == ent)
|
||||
{
|
||||
ShowHUD();
|
||||
}
|
||||
}
|
||||
|
||||
private void OnShutdown(Entity<ShowElectrocutionHUDComponent> ent, ref ComponentShutdown args)
|
||||
{
|
||||
if (_playerMan.LocalEntity == ent)
|
||||
{
|
||||
RemoveHUD();
|
||||
}
|
||||
}
|
||||
|
||||
// Show the HUD to the client.
|
||||
// We have to look for all current entities that can be electrified and toggle the HUD layer on if they are.
|
||||
private void ShowHUD()
|
||||
{
|
||||
var electrifiedQuery = AllEntityQuery<ElectrocutionHUDVisualsComponent, AppearanceComponent, SpriteComponent>();
|
||||
while (electrifiedQuery.MoveNext(out var uid, out var _, out var appearanceComp, out var spriteComp))
|
||||
{
|
||||
if (!AppearanceSystem.TryGetData<bool>(uid, ElectrifiedVisuals.IsElectrified, out var electrified, appearanceComp))
|
||||
continue;
|
||||
|
||||
if (electrified)
|
||||
spriteComp.LayerSetVisible(ElectrifiedLayers.HUD, true);
|
||||
else
|
||||
spriteComp.LayerSetVisible(ElectrifiedLayers.HUD, false);
|
||||
}
|
||||
}
|
||||
|
||||
// Remove the HUD from the client.
|
||||
// Find all current entities that can be electrified and hide the HUD layer.
|
||||
private void RemoveHUD()
|
||||
{
|
||||
var electrifiedQuery = AllEntityQuery<ElectrocutionHUDVisualsComponent, AppearanceComponent, SpriteComponent>();
|
||||
while (electrifiedQuery.MoveNext(out var uid, out var _, out var appearanceComp, out var spriteComp))
|
||||
{
|
||||
|
||||
spriteComp.LayerSetVisible(ElectrifiedLayers.HUD, false);
|
||||
}
|
||||
}
|
||||
|
||||
// Toggle the HUD layer if an entity becomes (de-)electrified
|
||||
protected override void OnAppearanceChange(EntityUid uid, ElectrocutionHUDVisualsComponent comp, ref AppearanceChangeEvent args)
|
||||
{
|
||||
if (args.Sprite == null)
|
||||
return;
|
||||
|
||||
if (!AppearanceSystem.TryGetData<bool>(uid, ElectrifiedVisuals.IsElectrified, out var electrified, args.Component))
|
||||
return;
|
||||
|
||||
var player = _playerMan.LocalEntity;
|
||||
if (electrified && HasComp<ShowElectrocutionHUDComponent>(player))
|
||||
args.Sprite.LayerSetVisible(ElectrifiedLayers.HUD, true);
|
||||
else
|
||||
args.Sprite.LayerSetVisible(ElectrifiedLayers.HUD, false);
|
||||
}
|
||||
}
|
||||
@@ -55,7 +55,7 @@ namespace Content.Client.Eui
|
||||
/// </summary>
|
||||
protected void SendMessage(EuiMessageBase msg)
|
||||
{
|
||||
var netMsg = _netManager.CreateNetMessage<MsgEuiMessage>();
|
||||
var netMsg = new MsgEuiMessage();
|
||||
netMsg.Id = Id;
|
||||
netMsg.Message = msg;
|
||||
|
||||
|
||||
@@ -112,7 +112,12 @@ namespace Content.Client.Ghost
|
||||
_actions.RemoveAction(uid, component.ToggleLightingActionEntity);
|
||||
_actions.RemoveAction(uid, component.ToggleFoVActionEntity);
|
||||
_actions.RemoveAction(uid, component.ToggleGhostsActionEntity);
|
||||
_actions.RemoveAction(uid, component.ToggleGhostHearingActionEntity);
|
||||
//_actions.RemoveAction(uid, component.ToggleGhostHearingActionEntity); //Dont need in CP14
|
||||
//CP14
|
||||
_actions.RemoveAction(uid, component.CP14ZLevelUpActionEntity);
|
||||
_actions.RemoveAction(uid, component.CP14ZLevelDownActionEntity);
|
||||
_actions.RemoveAction(uid, component.CP14ToggleRoofActionEntity);
|
||||
//CP14 end
|
||||
|
||||
if (uid != _playerManager.LocalEntity)
|
||||
return;
|
||||
|
||||
@@ -191,9 +191,15 @@ namespace Content.Client.Inventory
|
||||
return;
|
||||
|
||||
if (ev.Function == ContentKeyFunctions.ExamineEntity)
|
||||
{
|
||||
_examine.DoExamine(slot.Entity.Value);
|
||||
ev.Handle();
|
||||
}
|
||||
else if (ev.Function == EngineKeyFunctions.UseSecondary)
|
||||
{
|
||||
_ui.GetUIController<VerbMenuUIController>().OpenVerbMenu(slot.Entity.Value);
|
||||
ev.Handle();
|
||||
}
|
||||
}
|
||||
|
||||
private void AddInventoryButton(EntityUid invUid, string slotId, InventoryComponent inv)
|
||||
|
||||
@@ -21,6 +21,22 @@ public sealed class HandheldLightSystem : SharedHandheldLightSystem
|
||||
SubscribeLocalEvent<HandheldLightComponent, AppearanceChangeEvent>(OnAppearanceChange);
|
||||
}
|
||||
|
||||
/// <remarks>
|
||||
/// TODO: Not properly predicted yet. Don't call this function if you want a the actual return value!
|
||||
/// </remarks>
|
||||
public override bool TurnOff(Entity<HandheldLightComponent> ent, bool makeNoise = true)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <remarks>
|
||||
/// TODO: Not properly predicted yet. Don't call this function if you want a the actual return value!
|
||||
/// </remarks>
|
||||
public override bool TurnOn(EntityUid user, Entity<HandheldLightComponent> uid)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
private void OnAppearanceChange(EntityUid uid, HandheldLightComponent? component, ref AppearanceChangeEvent args)
|
||||
{
|
||||
if (!Resolve(uid, ref component))
|
||||
|
||||
@@ -116,7 +116,7 @@ namespace Content.Client.Lobby
|
||||
return;
|
||||
}
|
||||
|
||||
Lobby!.StationTime.Text = Loc.GetString("lobby-state-player-status-round-not-started");
|
||||
Lobby!.StationTime.Text = Loc.GetString("lobby-state-player-status-round-not-started");
|
||||
string text;
|
||||
|
||||
if (_gameTicker.Paused)
|
||||
@@ -136,6 +136,10 @@ namespace Content.Client.Lobby
|
||||
{
|
||||
text = Loc.GetString(seconds < -5 ? "lobby-state-right-now-question" : "lobby-state-right-now-confirmation");
|
||||
}
|
||||
else if (difference.TotalHours >= 1)
|
||||
{
|
||||
text = $"{Math.Floor(difference.TotalHours)}:{difference.Minutes:D2}:{difference.Seconds:D2}";
|
||||
}
|
||||
else
|
||||
{
|
||||
text = $"{difference.Minutes}:{difference.Seconds:D2}";
|
||||
|
||||
@@ -35,7 +35,7 @@ public sealed partial class StencilOverlay
|
||||
var matty = Matrix3x2.Multiply(matrix, invMatrix);
|
||||
worldHandle.SetTransform(matty);
|
||||
|
||||
foreach (var tile in grid.Comp.GetTilesIntersecting(worldAABB))
|
||||
foreach (var tile in _map.GetTilesIntersecting(grid.Owner, grid, worldAABB))
|
||||
{
|
||||
// Ignored tiles for stencil
|
||||
if (_weather.CanWeatherAffect(grid.Owner, grid, tile))
|
||||
|
||||
@@ -26,6 +26,7 @@ public sealed partial class StencilOverlay : Overlay
|
||||
[Dependency] private readonly IPrototypeManager _protoManager = default!;
|
||||
private readonly ParallaxSystem _parallax;
|
||||
private readonly SharedTransformSystem _transform;
|
||||
private readonly SharedMapSystem _map;
|
||||
private readonly SpriteSystem _sprite;
|
||||
private readonly WeatherSystem _weather;
|
||||
|
||||
@@ -35,11 +36,12 @@ public sealed partial class StencilOverlay : Overlay
|
||||
|
||||
private readonly ShaderInstance _shader;
|
||||
|
||||
public StencilOverlay(ParallaxSystem parallax, SharedTransformSystem transform, SpriteSystem sprite, WeatherSystem weather)
|
||||
public StencilOverlay(ParallaxSystem parallax, SharedTransformSystem transform, SharedMapSystem map, SpriteSystem sprite, WeatherSystem weather)
|
||||
{
|
||||
ZIndex = ParallaxSystem.ParallaxZIndex + 1;
|
||||
_parallax = parallax;
|
||||
_transform = transform;
|
||||
_map = map;
|
||||
_sprite = sprite;
|
||||
_weather = weather;
|
||||
IoCManager.InjectDependencies(this);
|
||||
|
||||
@@ -10,13 +10,14 @@ public sealed class StencilOverlaySystem : EntitySystem
|
||||
[Dependency] private readonly IOverlayManager _overlay = default!;
|
||||
[Dependency] private readonly ParallaxSystem _parallax = default!;
|
||||
[Dependency] private readonly SharedTransformSystem _transform = default!;
|
||||
[Dependency] private readonly SharedMapSystem _map = default!;
|
||||
[Dependency] private readonly SpriteSystem _sprite = default!;
|
||||
[Dependency] private readonly WeatherSystem _weather = default!;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
_overlay.AddOverlay(new StencilOverlay(_parallax, _transform, _sprite, _weather));
|
||||
_overlay.AddOverlay(new StencilOverlay(_parallax, _transform, _map, _sprite, _weather));
|
||||
}
|
||||
|
||||
public override void Shutdown()
|
||||
|
||||
@@ -116,7 +116,7 @@ public partial class BaseShuttleControl : MapGridControl
|
||||
}
|
||||
}
|
||||
|
||||
protected void DrawGrid(DrawingHandleScreen handle, Matrix3x2 matrix, Entity<MapGridComponent> grid, Color color, float alpha = 0.01f)
|
||||
protected void DrawGrid(DrawingHandleScreen handle, Matrix3x2 gridToView, Entity<MapGridComponent> grid, Color color, float alpha = 0.01f)
|
||||
{
|
||||
var rator = Maps.GetAllTilesEnumerator(grid.Owner, grid.Comp);
|
||||
var minimapScale = MinimapScale;
|
||||
@@ -264,7 +264,7 @@ public partial class BaseShuttleControl : MapGridControl
|
||||
Extensions.EnsureLength(ref _allVertices, totalData);
|
||||
|
||||
_drawJob.MidPoint = midpoint;
|
||||
_drawJob.Matrix = matrix;
|
||||
_drawJob.Matrix = gridToView;
|
||||
_drawJob.MinimapScale = minimapScale;
|
||||
_drawJob.Vertices = gridData.Vertices;
|
||||
_drawJob.ScaledVertices = _allVertices;
|
||||
@@ -286,7 +286,7 @@ public partial class BaseShuttleControl : MapGridControl
|
||||
|
||||
private record struct GridDrawJob : IParallelRobustJob
|
||||
{
|
||||
public int BatchSize => 16;
|
||||
public int BatchSize => 64;
|
||||
|
||||
public float MinimapScale;
|
||||
public Vector2 MidPoint;
|
||||
@@ -297,12 +297,7 @@ public partial class BaseShuttleControl : MapGridControl
|
||||
|
||||
public void Execute(int index)
|
||||
{
|
||||
var vert = Vertices[index];
|
||||
var adjustedVert = Vector2.Transform(vert, Matrix);
|
||||
adjustedVert = adjustedVert with { Y = -adjustedVert.Y };
|
||||
|
||||
var scaledVert = ScalePosition(adjustedVert, MinimapScale, MidPoint);
|
||||
ScaledVertices[index] = scaledVert;
|
||||
ScaledVertices[index] = Vector2.Transform(Vertices[index], Matrix);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,6 +15,7 @@ public sealed partial class NavScreen : BoxContainer
|
||||
[Dependency] private readonly IEntityManager _entManager = default!;
|
||||
private SharedTransformSystem _xformSystem;
|
||||
|
||||
private EntityUid? _consoleEntity; // Entity of controlling console
|
||||
private EntityUid? _shuttleEntity;
|
||||
|
||||
public NavScreen()
|
||||
@@ -35,6 +36,12 @@ public sealed partial class NavScreen : BoxContainer
|
||||
_shuttleEntity = shuttle;
|
||||
}
|
||||
|
||||
public void SetConsole(EntityUid? console)
|
||||
{
|
||||
_consoleEntity = console;
|
||||
NavRadar.SetConsole(console);
|
||||
}
|
||||
|
||||
private void OnIFFTogglePressed(BaseButton.ButtonEventArgs args)
|
||||
{
|
||||
NavRadar.ShowIFF ^= true;
|
||||
|
||||
@@ -138,6 +138,7 @@ public sealed partial class ShuttleConsoleWindow : FancyWindow,
|
||||
{
|
||||
var coordinates = _entManager.GetCoordinates(cState.NavState.Coordinates);
|
||||
NavContainer.SetShuttle(coordinates?.EntityId);
|
||||
NavContainer.SetConsole(owner);
|
||||
MapContainer.SetShuttle(coordinates?.EntityId);
|
||||
MapContainer.SetConsole(owner);
|
||||
|
||||
|
||||
@@ -107,16 +107,19 @@ public sealed partial class ShuttleDockControl : BaseShuttleControl
|
||||
DrawCircles(handle);
|
||||
var gridNent = EntManager.GetNetEntity(GridEntity);
|
||||
var mapPos = _xformSystem.ToMapCoordinates(_coordinates.Value);
|
||||
var ourGridMatrix = _xformSystem.GetWorldMatrix(GridEntity.Value);
|
||||
var dockMatrix = Matrix3Helpers.CreateTransform(_coordinates.Value.Position, Angle.Zero);
|
||||
var worldFromDock = Matrix3x2.Multiply(dockMatrix, ourGridMatrix);
|
||||
var ourGridToWorld = _xformSystem.GetWorldMatrix(GridEntity.Value);
|
||||
var selectedDockToOurGrid = Matrix3Helpers.CreateTransform(_coordinates.Value.Position, Angle.Zero);
|
||||
var selectedDockToWorld = Matrix3x2.Multiply(selectedDockToOurGrid, ourGridToWorld);
|
||||
|
||||
Matrix3x2.Invert(worldFromDock, out var offsetMatrix);
|
||||
Box2 viewBoundsWorld = Matrix3Helpers.TransformBox(selectedDockToWorld, new Box2(-WorldRangeVector, WorldRangeVector));
|
||||
|
||||
Matrix3x2.Invert(selectedDockToWorld, out var worldToSelectedDock);
|
||||
var selectedDockToView = Matrix3x2.CreateScale(new Vector2(MinimapScale, -MinimapScale)) * Matrix3x2.CreateTranslation(MidPointVector);
|
||||
|
||||
// Draw nearby grids
|
||||
var controlBounds = PixelSizeBox;
|
||||
_grids.Clear();
|
||||
_mapManager.FindGridsIntersecting(gridXform.MapID, new Box2(mapPos.Position - WorldRangeVector, mapPos.Position + WorldRangeVector), ref _grids);
|
||||
_mapManager.FindGridsIntersecting(gridXform.MapID, viewBoundsWorld, ref _grids);
|
||||
|
||||
// offset the dotted-line position to the bounds.
|
||||
Vector2? viewedDockPos = _viewedState != null ? MidPointVector : null;
|
||||
@@ -136,11 +139,11 @@ public sealed partial class ShuttleDockControl : BaseShuttleControl
|
||||
if (grid.Owner != GridEntity && !_shuttles.CanDraw(grid.Owner, iffComp: iffComp))
|
||||
continue;
|
||||
|
||||
var gridMatrix = _xformSystem.GetWorldMatrix(grid.Owner);
|
||||
var matty = Matrix3x2.Multiply(gridMatrix, offsetMatrix);
|
||||
var curGridToWorld = _xformSystem.GetWorldMatrix(grid.Owner);
|
||||
var curGridToView = curGridToWorld * worldToSelectedDock * selectedDockToView;
|
||||
var color = _shuttles.GetIFFColor(grid.Owner, grid.Owner == GridEntity, component: iffComp);
|
||||
|
||||
DrawGrid(handle, matty, grid, color);
|
||||
DrawGrid(handle, curGridToView, grid, color);
|
||||
|
||||
// Draw any docks on that grid
|
||||
if (!DockState.Docks.TryGetValue(EntManager.GetNetEntity(grid), out var gridDocks))
|
||||
@@ -151,23 +154,24 @@ public sealed partial class ShuttleDockControl : BaseShuttleControl
|
||||
if (ViewedDock == dock.Entity)
|
||||
continue;
|
||||
|
||||
var position = Vector2.Transform(dock.Coordinates.Position, matty);
|
||||
|
||||
var otherDockRotation = Matrix3Helpers.CreateRotation(dock.Angle);
|
||||
var scaledPos = ScalePosition(position with {Y = -position.Y});
|
||||
|
||||
if (!controlBounds.Contains(scaledPos.Floored()))
|
||||
// This box is the AABB of all the vertices we draw below.
|
||||
var dockRenderBoundsLocal = new Box2(-0.5f, -0.7f, 0.5f, 0.5f);
|
||||
var currentDockToCurGrid = Matrix3Helpers.CreateTransform(dock.Coordinates.Position, dock.Angle);
|
||||
var currentDockToWorld = Matrix3x2.Multiply(currentDockToCurGrid, curGridToWorld);
|
||||
var dockRenderBoundsWorld = Matrix3Helpers.TransformBox(currentDockToWorld, dockRenderBoundsLocal);
|
||||
if (!viewBoundsWorld.Intersects(dockRenderBoundsWorld))
|
||||
continue;
|
||||
|
||||
// Draw the dock's collision
|
||||
var collisionBL = Vector2.Transform(dock.Coordinates.Position +
|
||||
Vector2.Transform(new Vector2(-0.2f, -0.7f), otherDockRotation), matty);
|
||||
Vector2.Transform(new Vector2(-0.2f, -0.7f), otherDockRotation), curGridToView);
|
||||
var collisionBR = Vector2.Transform(dock.Coordinates.Position +
|
||||
Vector2.Transform(new Vector2(0.2f, -0.7f), otherDockRotation), matty);
|
||||
Vector2.Transform(new Vector2(0.2f, -0.7f), otherDockRotation), curGridToView);
|
||||
var collisionTR = Vector2.Transform(dock.Coordinates.Position +
|
||||
Vector2.Transform(new Vector2(0.2f, -0.5f), otherDockRotation), matty);
|
||||
Vector2.Transform(new Vector2(0.2f, -0.5f), otherDockRotation), curGridToView);
|
||||
var collisionTL = Vector2.Transform(dock.Coordinates.Position +
|
||||
Vector2.Transform(new Vector2(-0.2f, -0.5f), otherDockRotation), matty);
|
||||
Vector2.Transform(new Vector2(-0.2f, -0.5f), otherDockRotation), curGridToView);
|
||||
|
||||
var verts = new[]
|
||||
{
|
||||
@@ -181,13 +185,6 @@ public sealed partial class ShuttleDockControl : BaseShuttleControl
|
||||
collisionBL,
|
||||
};
|
||||
|
||||
for (var i = 0; i < verts.Length; i++)
|
||||
{
|
||||
var vert = verts[i];
|
||||
vert.Y = -vert.Y;
|
||||
verts[i] = ScalePosition(vert);
|
||||
}
|
||||
|
||||
var collisionCenter = verts[0] + verts[1] + verts[3] + verts[5];
|
||||
|
||||
var otherDockConnection = Color.ToSrgb(Color.Pink);
|
||||
@@ -195,10 +192,10 @@ public sealed partial class ShuttleDockControl : BaseShuttleControl
|
||||
handle.DrawPrimitives(DrawPrimitiveTopology.LineList, verts, otherDockConnection);
|
||||
|
||||
// Draw the dock itself
|
||||
var dockBL = Vector2.Transform(dock.Coordinates.Position + new Vector2(-0.5f, -0.5f), matty);
|
||||
var dockBR = Vector2.Transform(dock.Coordinates.Position + new Vector2(0.5f, -0.5f), matty);
|
||||
var dockTR = Vector2.Transform(dock.Coordinates.Position + new Vector2(0.5f, 0.5f), matty);
|
||||
var dockTL = Vector2.Transform(dock.Coordinates.Position + new Vector2(-0.5f, 0.5f), matty);
|
||||
var dockBL = Vector2.Transform(dock.Coordinates.Position + new Vector2(-0.5f, -0.5f), curGridToView);
|
||||
var dockBR = Vector2.Transform(dock.Coordinates.Position + new Vector2(0.5f, -0.5f), curGridToView);
|
||||
var dockTR = Vector2.Transform(dock.Coordinates.Position + new Vector2(0.5f, 0.5f), curGridToView);
|
||||
var dockTL = Vector2.Transform(dock.Coordinates.Position + new Vector2(-0.5f, 0.5f), curGridToView);
|
||||
|
||||
verts = new[]
|
||||
{
|
||||
@@ -212,13 +209,6 @@ public sealed partial class ShuttleDockControl : BaseShuttleControl
|
||||
dockBL
|
||||
};
|
||||
|
||||
for (var i = 0; i < verts.Length; i++)
|
||||
{
|
||||
var vert = verts[i];
|
||||
vert.Y = -vert.Y;
|
||||
verts[i] = ScalePosition(vert);
|
||||
}
|
||||
|
||||
Color otherDockColor;
|
||||
|
||||
if (HighlightedDock == dock.Entity)
|
||||
@@ -253,9 +243,11 @@ public sealed partial class ShuttleDockControl : BaseShuttleControl
|
||||
collisionCenter /= 4;
|
||||
var range = viewedDockPos.Value - collisionCenter;
|
||||
|
||||
if (range.Length() < SharedDockingSystem.DockingHiglightRange * MinimapScale)
|
||||
var maxRange = SharedDockingSystem.DockingHiglightRange * MinimapScale;
|
||||
var maxRangeSq = maxRange * maxRange;
|
||||
if (range.LengthSquared() < maxRangeSq)
|
||||
{
|
||||
if (_viewedState?.GridDockedWith == null)
|
||||
if (dock.GridDockedWith == null)
|
||||
{
|
||||
var coordsOne = EntManager.GetCoordinates(_viewedState!.Coordinates);
|
||||
var coordsTwo = EntManager.GetCoordinates(dock.Coordinates);
|
||||
@@ -265,10 +257,11 @@ public sealed partial class ShuttleDockControl : BaseShuttleControl
|
||||
var rotA = _xformSystem.GetWorldRotation(coordsOne.EntityId) + _viewedState!.Angle;
|
||||
var rotB = _xformSystem.GetWorldRotation(coordsTwo.EntityId) + dock.Angle;
|
||||
|
||||
var distance = (mapOne.Position - mapTwo.Position).Length();
|
||||
var distanceSq = (mapOne.Position - mapTwo.Position).LengthSquared();
|
||||
|
||||
var inAlignment = _dockSystem.InAlignment(mapOne, rotA, mapTwo, rotB);
|
||||
var canDock = distance < SharedDockingSystem.DockRange && inAlignment;
|
||||
var maxDockDistSq = SharedDockingSystem.DockRange * SharedDockingSystem.DockRange;
|
||||
var canDock = distanceSq < maxDockDistSq && inAlignment;
|
||||
|
||||
if (dockButton != null)
|
||||
dockButton.Disabled = !canDock || !canDockChange;
|
||||
@@ -297,7 +290,8 @@ public sealed partial class ShuttleDockControl : BaseShuttleControl
|
||||
{
|
||||
// Because it's being layed out top-down we have to arrange for first frame.
|
||||
container.Arrange(PixelRect);
|
||||
var containerPos = scaledPos / UIScale - container.DesiredSize / 2 - new Vector2(0f, 0.75f) * MinimapScale;
|
||||
var dockPositionInView = Vector2.Transform(dock.Coordinates.Position, curGridToView);
|
||||
var containerPos = dockPositionInView / UIScale - container.DesiredSize / 2 - new Vector2(0f, 0.75f) * MinimapScale;
|
||||
SetPosition(container, containerPos);
|
||||
}
|
||||
|
||||
|
||||
@@ -29,6 +29,11 @@ public sealed partial class ShuttleNavControl : BaseShuttleControl
|
||||
/// </summary>
|
||||
private EntityCoordinates? _coordinates;
|
||||
|
||||
/// <summary>
|
||||
/// Entity of controlling console
|
||||
/// </summary>
|
||||
private EntityUid? _consoleEntity;
|
||||
|
||||
private Angle? _rotation;
|
||||
|
||||
private Dictionary<NetEntity, List<DockingPortState>> _docks = new();
|
||||
@@ -57,6 +62,11 @@ public sealed partial class ShuttleNavControl : BaseShuttleControl
|
||||
_rotation = angle;
|
||||
}
|
||||
|
||||
public void SetConsole(EntityUid? consoleEntity)
|
||||
{
|
||||
_consoleEntity = consoleEntity;
|
||||
}
|
||||
|
||||
protected override void KeyBindUp(GUIBoundKeyEventArgs args)
|
||||
{
|
||||
base.KeyBindUp(args);
|
||||
@@ -139,40 +149,35 @@ public sealed partial class ShuttleNavControl : BaseShuttleControl
|
||||
}
|
||||
|
||||
var mapPos = _transform.ToMapCoordinates(_coordinates.Value);
|
||||
var offset = _coordinates.Value.Position;
|
||||
var posMatrix = Matrix3Helpers.CreateTransform(offset, _rotation.Value);
|
||||
var posMatrix = Matrix3Helpers.CreateTransform(_coordinates.Value.Position, _rotation.Value);
|
||||
var ourEntRot = RotateWithEntity ? _transform.GetWorldRotation(xform) : _rotation.Value;
|
||||
var ourEntMatrix = Matrix3Helpers.CreateTransform(_transform.GetWorldPosition(xform), ourEntRot);
|
||||
var ourWorldMatrix = Matrix3x2.Multiply(posMatrix, ourEntMatrix);
|
||||
Matrix3x2.Invert(ourWorldMatrix, out var ourWorldMatrixInvert);
|
||||
var shuttleToWorld = Matrix3x2.Multiply(posMatrix, ourEntMatrix);
|
||||
Matrix3x2.Invert(shuttleToWorld, out var worldToShuttle);
|
||||
var shuttleToView = Matrix3x2.CreateScale(new Vector2(MinimapScale, -MinimapScale)) * Matrix3x2.CreateTranslation(MidPointVector);
|
||||
|
||||
// Draw our grid in detail
|
||||
var ourGridId = xform.GridUid;
|
||||
if (EntManager.TryGetComponent<MapGridComponent>(ourGridId, out var ourGrid) &&
|
||||
fixturesQuery.HasComponent(ourGridId.Value))
|
||||
{
|
||||
var ourGridMatrix = _transform.GetWorldMatrix(ourGridId.Value);
|
||||
var matrix = Matrix3x2.Multiply(ourGridMatrix, ourWorldMatrixInvert);
|
||||
var ourGridToWorld = _transform.GetWorldMatrix(ourGridId.Value);
|
||||
var ourGridToShuttle = Matrix3x2.Multiply(ourGridToWorld, worldToShuttle);
|
||||
var ourGridToView = ourGridToShuttle * shuttleToView;
|
||||
var color = _shuttles.GetIFFColor(ourGridId.Value, self: true);
|
||||
|
||||
DrawGrid(handle, matrix, (ourGridId.Value, ourGrid), color);
|
||||
DrawDocks(handle, ourGridId.Value, matrix);
|
||||
DrawGrid(handle, ourGridToView, (ourGridId.Value, ourGrid), color);
|
||||
DrawDocks(handle, ourGridId.Value, ourGridToView);
|
||||
}
|
||||
|
||||
var invertedPosition = _coordinates.Value.Position - offset;
|
||||
invertedPosition.Y = -invertedPosition.Y;
|
||||
// Don't need to transform the InvWorldMatrix again as it's already offset to its position.
|
||||
|
||||
// Draw radar position on the station
|
||||
var radarPos = invertedPosition;
|
||||
const float radarVertRadius = 2f;
|
||||
|
||||
var radarPosVerts = new Vector2[]
|
||||
{
|
||||
ScalePosition(radarPos + new Vector2(0f, -radarVertRadius)),
|
||||
ScalePosition(radarPos + new Vector2(radarVertRadius / 2f, 0f)),
|
||||
ScalePosition(radarPos + new Vector2(0f, radarVertRadius)),
|
||||
ScalePosition(radarPos + new Vector2(radarVertRadius / -2f, 0f)),
|
||||
ScalePosition(new Vector2(0f, -radarVertRadius)),
|
||||
ScalePosition(new Vector2(radarVertRadius / 2f, 0f)),
|
||||
ScalePosition(new Vector2(0f, radarVertRadius)),
|
||||
ScalePosition(new Vector2(radarVertRadius / -2f, 0f)),
|
||||
};
|
||||
|
||||
handle.DrawPrimitives(DrawPrimitiveTopology.TriangleFan, radarPosVerts, Color.Lime);
|
||||
@@ -197,8 +202,8 @@ public sealed partial class ShuttleNavControl : BaseShuttleControl
|
||||
if (!_shuttles.CanDraw(gUid, gridBody, iff))
|
||||
continue;
|
||||
|
||||
var gridMatrix = _transform.GetWorldMatrix(gUid);
|
||||
var matty = Matrix3x2.Multiply(gridMatrix, ourWorldMatrixInvert);
|
||||
var curGridToWorld = _transform.GetWorldMatrix(gUid);
|
||||
var curGridToView = curGridToWorld * worldToShuttle * shuttleToView;
|
||||
|
||||
var labelColor = _shuttles.GetIFFColor(grid, self: false, iff);
|
||||
var coordColor = new Color(labelColor.R * 0.8f, labelColor.G * 0.8f, labelColor.B * 0.8f, 0.5f);
|
||||
@@ -213,8 +218,7 @@ public sealed partial class ShuttleNavControl : BaseShuttleControl
|
||||
{
|
||||
var gridBounds = grid.Comp.LocalAABB;
|
||||
|
||||
var gridCentre = Vector2.Transform(gridBody.LocalCenter, matty);
|
||||
gridCentre.Y = -gridCentre.Y;
|
||||
var gridCentre = Vector2.Transform(gridBody.LocalCenter, curGridToView);
|
||||
|
||||
var distance = gridCentre.Length();
|
||||
var labelText = Loc.GetString("shuttle-console-iff-label", ("name", labelName),
|
||||
@@ -230,9 +234,8 @@ public sealed partial class ShuttleNavControl : BaseShuttleControl
|
||||
// y-offset the control to always render below the grid (vertically)
|
||||
var yOffset = Math.Max(gridBounds.Height, gridBounds.Width) * MinimapScale / 1.8f;
|
||||
|
||||
// The actual position in the UI. We centre the label by offsetting the matrix position
|
||||
// by half the label's width, plus the y-offset
|
||||
var gridScaledPosition = ScalePosition(gridCentre) - new Vector2(0, -yOffset);
|
||||
// The actual position in the UI.
|
||||
var gridScaledPosition = gridCentre - new Vector2(0, -yOffset);
|
||||
|
||||
// Normalize the grid position if it exceeds the viewport bounds
|
||||
// normalizing it instead of clamping it preserves the direction of the vector and prevents corner-hugging
|
||||
@@ -264,18 +267,32 @@ public sealed partial class ShuttleNavControl : BaseShuttleControl
|
||||
}
|
||||
|
||||
// Detailed view
|
||||
var gridAABB = gridMatrix.TransformBox(grid.Comp.LocalAABB);
|
||||
var gridAABB = curGridToWorld.TransformBox(grid.Comp.LocalAABB);
|
||||
|
||||
// Skip drawing if it's out of range.
|
||||
if (!gridAABB.Intersects(viewAABB))
|
||||
continue;
|
||||
|
||||
DrawGrid(handle, matty, grid, labelColor);
|
||||
DrawDocks(handle, gUid, matty);
|
||||
DrawGrid(handle, curGridToView, grid, labelColor);
|
||||
DrawDocks(handle, gUid, curGridToView);
|
||||
}
|
||||
|
||||
// If we've set the controlling console, and it's on a different grid
|
||||
// to the shuttle itself, then draw an additional marker to help the
|
||||
// player determine where they are relative to the shuttle.
|
||||
if (_consoleEntity != null && xformQuery.TryGetComponent(_consoleEntity, out var consoleXform))
|
||||
{
|
||||
if (consoleXform.ParentUid != _coordinates.Value.EntityId)
|
||||
{
|
||||
var consolePositionWorld = _transform.GetWorldPosition((EntityUid)_consoleEntity);
|
||||
var p = Vector2.Transform(consolePositionWorld, worldToShuttle * shuttleToView);
|
||||
handle.DrawCircle(p, 5, Color.ToSrgb(Color.Cyan), true);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void DrawDocks(DrawingHandleScreen handle, EntityUid uid, Matrix3x2 matrix)
|
||||
private void DrawDocks(DrawingHandleScreen handle, EntityUid uid, Matrix3x2 gridToView)
|
||||
{
|
||||
if (!ShowDocks)
|
||||
return;
|
||||
@@ -283,33 +300,32 @@ public sealed partial class ShuttleNavControl : BaseShuttleControl
|
||||
const float DockScale = 0.6f;
|
||||
var nent = EntManager.GetNetEntity(uid);
|
||||
|
||||
const float sqrt2 = 1.41421356f;
|
||||
const float dockRadius = DockScale * sqrt2;
|
||||
// Worst-case bounds used to cull a dock:
|
||||
Box2 viewBounds = new Box2(-dockRadius, -dockRadius, Size.X + dockRadius, Size.Y + dockRadius);
|
||||
if (_docks.TryGetValue(nent, out var docks))
|
||||
{
|
||||
foreach (var state in docks)
|
||||
{
|
||||
var position = state.Coordinates.Position;
|
||||
var uiPosition = Vector2.Transform(position, matrix);
|
||||
|
||||
if (uiPosition.Length() > (WorldRange * 2f) - DockScale)
|
||||
var positionInView = Vector2.Transform(position, gridToView);
|
||||
if (!viewBounds.Contains(positionInView))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var color = Color.ToSrgb(Color.Magenta);
|
||||
|
||||
var verts = new[]
|
||||
{
|
||||
Vector2.Transform(position + new Vector2(-DockScale, -DockScale), matrix),
|
||||
Vector2.Transform(position + new Vector2(DockScale, -DockScale), matrix),
|
||||
Vector2.Transform(position + new Vector2(DockScale, DockScale), matrix),
|
||||
Vector2.Transform(position + new Vector2(-DockScale, DockScale), matrix),
|
||||
Vector2.Transform(position + new Vector2(-DockScale, -DockScale), gridToView),
|
||||
Vector2.Transform(position + new Vector2(DockScale, -DockScale), gridToView),
|
||||
Vector2.Transform(position + new Vector2(DockScale, DockScale), gridToView),
|
||||
Vector2.Transform(position + new Vector2(-DockScale, DockScale), gridToView),
|
||||
};
|
||||
|
||||
for (var i = 0; i < verts.Length; i++)
|
||||
{
|
||||
var vert = verts[i];
|
||||
vert.Y = -vert.Y;
|
||||
verts[i] = ScalePosition(vert);
|
||||
}
|
||||
|
||||
handle.DrawPrimitives(DrawPrimitiveTopology.TriangleFan, verts, color.WithAlpha(0.8f));
|
||||
handle.DrawPrimitives(DrawPrimitiveTopology.LineStrip, verts, color);
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@ using Robust.Client.UserInterface;
|
||||
using Robust.Client.UserInterface.Controls;
|
||||
using Robust.Client.UserInterface.XAML;
|
||||
using Robust.Shared.Prototypes;
|
||||
using Robust.Shared.Timing;
|
||||
using Robust.Shared.Utility;
|
||||
|
||||
namespace Content.Client.Silicons.Laws.Ui;
|
||||
@@ -18,8 +19,13 @@ public sealed partial class LawDisplay : Control
|
||||
{
|
||||
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
|
||||
[Dependency] private readonly IChatManager _chatManager = default!;
|
||||
[Dependency] private readonly IGameTiming _timing = default!;
|
||||
[Dependency] private readonly EntityManager _entityManager = default!;
|
||||
|
||||
private static readonly TimeSpan PressCooldown = TimeSpan.FromSeconds(3);
|
||||
|
||||
private readonly Dictionary<Button, TimeSpan> _nextAllowedPress = new();
|
||||
|
||||
public LawDisplay(EntityUid uid, SiliconLaw law, HashSet<string>? radioChannels)
|
||||
{
|
||||
RobustXamlLoader.Load(this);
|
||||
@@ -47,9 +53,12 @@ public sealed partial class LawDisplay : Control
|
||||
MinWidth = 75,
|
||||
};
|
||||
|
||||
_nextAllowedPress[localButton] = TimeSpan.Zero;
|
||||
|
||||
localButton.OnPressed += _ =>
|
||||
{
|
||||
_chatManager.SendMessage($"{lawIdentifierPlaintext}: {lawDescriptionPlaintext}", ChatSelectChannel.Local);
|
||||
_nextAllowedPress[localButton] = _timing.CurTime + PressCooldown;
|
||||
};
|
||||
|
||||
LawAnnouncementButtons.AddChild(localButton);
|
||||
@@ -71,6 +80,8 @@ public sealed partial class LawDisplay : Control
|
||||
MinWidth = 75,
|
||||
};
|
||||
|
||||
_nextAllowedPress[radioChannelButton] = TimeSpan.Zero;
|
||||
|
||||
radioChannelButton.OnPressed += _ =>
|
||||
{
|
||||
switch (radioChannel)
|
||||
@@ -80,9 +91,21 @@ public sealed partial class LawDisplay : Control
|
||||
default:
|
||||
_chatManager.SendMessage($"{SharedChatSystem.RadioChannelPrefix}{radioChannelProto.KeyCode} {lawIdentifierPlaintext}: {lawDescriptionPlaintext}", ChatSelectChannel.Radio); break;
|
||||
}
|
||||
_nextAllowedPress[radioChannelButton] = _timing.CurTime + PressCooldown;
|
||||
};
|
||||
|
||||
LawAnnouncementButtons.AddChild(radioChannelButton);
|
||||
}
|
||||
}
|
||||
|
||||
protected override void FrameUpdate(FrameEventArgs args)
|
||||
{
|
||||
base.FrameUpdate(args);
|
||||
|
||||
var curTime = _timing.CurTime;
|
||||
foreach (var (button, nextPress) in _nextAllowedPress)
|
||||
{
|
||||
button.Disabled = curTime < nextPress;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,9 +16,8 @@ using static Robust.Client.UserInterface.Controls.LineEdit;
|
||||
namespace Content.Client.UserInterface.Systems.Chat.Widgets;
|
||||
|
||||
[GenerateTypedNameReferences]
|
||||
#pragma warning disable RA0003
|
||||
[Virtual]
|
||||
public partial class ChatBox : UIWidget
|
||||
#pragma warning restore RA0003
|
||||
{
|
||||
private readonly ChatUIController _controller;
|
||||
private readonly IEntityManager _entManager;
|
||||
|
||||
@@ -71,6 +71,7 @@ namespace Content.Client.UserInterface.Systems.Ghost.Controls.Roles
|
||||
buttonHeading.AddStyleClass(ContainerButton.StyleClassButton);
|
||||
buttonHeading.Label.HorizontalAlignment = HAlignment.Center;
|
||||
buttonHeading.Label.HorizontalExpand = true;
|
||||
buttonHeading.Margin = new Thickness(8, 0, 8, 2);
|
||||
|
||||
var body = new CollapsibleBody
|
||||
{
|
||||
|
||||
@@ -83,22 +83,27 @@ public sealed class HandsUIController : UIController, IOnStateEntered<GameplaySt
|
||||
if (args.Function == EngineKeyFunctions.UIClick)
|
||||
{
|
||||
_handsSystem.UIHandClick(_playerHandsComponent, hand.SlotName);
|
||||
args.Handle();
|
||||
}
|
||||
else if (args.Function == EngineKeyFunctions.UseSecondary)
|
||||
{
|
||||
_handsSystem.UIHandOpenContextMenu(hand.SlotName);
|
||||
args.Handle();
|
||||
}
|
||||
else if (args.Function == ContentKeyFunctions.ActivateItemInWorld)
|
||||
{
|
||||
_handsSystem.UIHandActivate(hand.SlotName);
|
||||
args.Handle();
|
||||
}
|
||||
else if (args.Function == ContentKeyFunctions.AltActivateItemInWorld)
|
||||
{
|
||||
_handsSystem.UIHandAltActivateItem(hand.SlotName);
|
||||
args.Handle();
|
||||
}
|
||||
else if (args.Function == ContentKeyFunctions.ExamineEntity)
|
||||
{
|
||||
_handsSystem.UIInventoryExamine(hand.SlotName);
|
||||
args.Handle();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -206,8 +206,7 @@ namespace Content.Client.Wires.UI
|
||||
(_statusContainer = new GridContainer
|
||||
{
|
||||
Margin = new Thickness(8, 4),
|
||||
// TODO: automatically change columns count.
|
||||
Columns = 3
|
||||
Rows = 2
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -227,7 +226,8 @@ namespace Content.Client.Wires.UI
|
||||
PanelOverride = new StyleBoxFlat {BackgroundColor = Color.FromHex("#525252ff")}
|
||||
});
|
||||
CloseButton.OnPressed += _ => Close();
|
||||
SetSize = new Vector2(320, 200);
|
||||
SetHeight = 200;
|
||||
MinWidth = 320;
|
||||
}
|
||||
|
||||
|
||||
@@ -503,6 +503,8 @@ namespace Content.Client.Wires.UI
|
||||
|
||||
public StatusLight(StatusLightData data, IResourceCache resourceCache)
|
||||
{
|
||||
HorizontalAlignment = HAlignment.Right;
|
||||
|
||||
var hsv = Color.ToHsv(data.Color);
|
||||
hsv.Z /= 2;
|
||||
var dimColor = Color.FromHsv(hsv);
|
||||
|
||||
127
Content.Client/_CP14/Roof/CP14RoofSystem.cs
Normal file
127
Content.Client/_CP14/Roof/CP14RoofSystem.cs
Normal file
@@ -0,0 +1,127 @@
|
||||
using Content.Shared._CP14.Roof;
|
||||
using Content.Shared.Ghost;
|
||||
using Robust.Client.GameObjects;
|
||||
using Robust.Client.Player;
|
||||
using Robust.Shared.Console;
|
||||
using Robust.Shared.Map.Components;
|
||||
|
||||
namespace Content.Client._CP14.Roof;
|
||||
|
||||
public sealed class CP14RoofSystem : EntitySystem
|
||||
{
|
||||
[Dependency] private readonly IPlayerManager _playerManager = default!;
|
||||
[Dependency] private readonly SharedMapSystem _map = default!;
|
||||
|
||||
private bool _roofVisible = true;
|
||||
public bool DisabledByCommand = false;
|
||||
|
||||
private EntityQuery<GhostComponent> _ghostQuery;
|
||||
private EntityQuery<TransformComponent> _xformQuery;
|
||||
|
||||
public bool RoofVisibility
|
||||
{
|
||||
get => _roofVisible && !DisabledByCommand;
|
||||
set
|
||||
{
|
||||
_roofVisible = value;
|
||||
UpdateRoofVisibilityAll();
|
||||
}
|
||||
}
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
|
||||
_ghostQuery = GetEntityQuery<GhostComponent>();
|
||||
_xformQuery = GetEntityQuery<TransformComponent>();
|
||||
|
||||
SubscribeLocalEvent<CP14RoofComponent, ComponentStartup>(RoofStartup);
|
||||
SubscribeLocalEvent<GhostComponent, CP14ToggleRoofVisibilityAction>(OnToggleRoof);
|
||||
}
|
||||
|
||||
public override void Update(float frameTime)
|
||||
{
|
||||
base.Update(frameTime);
|
||||
|
||||
var player = _playerManager.LocalEntity;
|
||||
|
||||
if (_ghostQuery.HasComp(player))
|
||||
return;
|
||||
|
||||
if (_xformQuery.TryComp(player, out var playerXform))
|
||||
{
|
||||
var grid = playerXform.GridUid;
|
||||
if (grid == null || !TryComp<MapGridComponent>(grid, out var gridComp))
|
||||
return;
|
||||
|
||||
var roofQuery = GetEntityQuery<CP14RoofComponent>();
|
||||
var anchored = _map.GetAnchoredEntities(grid.Value, gridComp, playerXform.Coordinates);
|
||||
|
||||
var underRoof = false;
|
||||
foreach (var ent in anchored)
|
||||
{
|
||||
if (!roofQuery.HasComp(ent))
|
||||
continue;
|
||||
|
||||
underRoof = true;
|
||||
}
|
||||
if (underRoof && _roofVisible)
|
||||
{
|
||||
RoofVisibility = false;
|
||||
}
|
||||
if (!underRoof && !_roofVisible)
|
||||
{
|
||||
RoofVisibility = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void OnToggleRoof(Entity<GhostComponent> ent, ref CP14ToggleRoofVisibilityAction args)
|
||||
{
|
||||
if (args.Handled)
|
||||
return;
|
||||
|
||||
DisabledByCommand = !DisabledByCommand;
|
||||
UpdateRoofVisibilityAll();
|
||||
|
||||
args.Handled = true;
|
||||
}
|
||||
|
||||
private void RoofStartup(Entity<CP14RoofComponent> ent, ref ComponentStartup args)
|
||||
{
|
||||
if (!TryComp<SpriteComponent>(ent, out var sprite))
|
||||
return;
|
||||
|
||||
UpdateVisibility(ent, sprite);
|
||||
}
|
||||
|
||||
private void UpdateVisibility(Entity<CP14RoofComponent> ent, SpriteComponent sprite)
|
||||
{
|
||||
sprite.Visible = RoofVisibility;
|
||||
}
|
||||
|
||||
public void UpdateRoofVisibilityAll()
|
||||
{
|
||||
var query = EntityQueryEnumerator<CP14RoofComponent, SpriteComponent>();
|
||||
while (query.MoveNext(out var uid, out var marker, out var sprite))
|
||||
{
|
||||
UpdateVisibility((uid, marker), sprite);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal sealed class ShowRoof : LocalizedCommands
|
||||
{
|
||||
[Dependency] private readonly IEntitySystemManager _entitySystemManager = default!;
|
||||
|
||||
public override string Command => "cp14_toggleroof";
|
||||
|
||||
public override string Help => "Toggle roof visibility";
|
||||
|
||||
public override void Execute(IConsoleShell shell, string argStr, string[] args)
|
||||
{
|
||||
var roofSystem = _entitySystemManager.GetEntitySystem<CP14RoofSystem>();
|
||||
roofSystem.DisabledByCommand = !roofSystem.DisabledByCommand;
|
||||
roofSystem.UpdateRoofVisibilityAll();
|
||||
}
|
||||
}
|
||||
@@ -197,6 +197,7 @@ namespace Content.IntegrationTests.Tests
|
||||
targetGrid = gridEnt;
|
||||
}
|
||||
}
|
||||
|
||||
// Test shuttle can dock.
|
||||
// This is done inside gamemap test because loading the map takes ages and we already have it.
|
||||
var station = entManager.GetComponent<StationMemberComponent>(targetGrid!.Value).Station;
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>net7.0</TargetFramework>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
<ManagePackageVersionsCentrally>true</ManagePackageVersionsCentrally>
|
||||
|
||||
@@ -16,6 +16,7 @@ public sealed class GasProducerAnomalySystem : EntitySystem
|
||||
{
|
||||
[Dependency] private readonly AtmosphereSystem _atmosphere = default!;
|
||||
[Dependency] private readonly IRobustRandom _random = default!;
|
||||
[Dependency] private readonly SharedMapSystem _map = default!;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
@@ -56,8 +57,11 @@ public sealed class GasProducerAnomalySystem : EntitySystem
|
||||
return;
|
||||
|
||||
var localpos = xform.Coordinates.Position;
|
||||
var tilerefs = grid.GetLocalTilesIntersecting(
|
||||
new Box2(localpos + new Vector2(-radius, -radius), localpos + new Vector2(radius, radius))).ToArray();
|
||||
var tilerefs = _map.GetLocalTilesIntersecting(
|
||||
xform.GridUid.Value,
|
||||
grid,
|
||||
new Box2(localpos + new Vector2(-radius, -radius), localpos + new Vector2(radius, radius)))
|
||||
.ToArray();
|
||||
|
||||
if (tilerefs.Length == 0)
|
||||
return;
|
||||
|
||||
@@ -102,10 +102,12 @@ public sealed class LogicGateSystem : EntitySystem
|
||||
if (args.Port == comp.InputPortA)
|
||||
{
|
||||
comp.StateA = state;
|
||||
_appearance.SetData(uid, LogicGateVisuals.InputA, state == SignalState.High); //If A == High => Sets input A sprite to True
|
||||
}
|
||||
else if (args.Port == comp.InputPortB)
|
||||
{
|
||||
comp.StateB = state;
|
||||
_appearance.SetData(uid, LogicGateVisuals.InputB, state == SignalState.High); //If B == High => Sets input B sprite to True
|
||||
}
|
||||
|
||||
UpdateOutput(uid, comp);
|
||||
@@ -143,6 +145,8 @@ public sealed class LogicGateSystem : EntitySystem
|
||||
break;
|
||||
}
|
||||
|
||||
_appearance.SetData(uid, LogicGateVisuals.Output, output);
|
||||
|
||||
// only send a payload if it actually changed
|
||||
if (output != comp.LastOutput)
|
||||
{
|
||||
|
||||
@@ -18,7 +18,7 @@ using JetBrains.Annotations;
|
||||
using Robust.Server.Audio;
|
||||
using Robust.Server.GameObjects;
|
||||
using Robust.Shared.Audio;
|
||||
using Robust.Shared.Player;
|
||||
using Robust.Shared.Map.Events;
|
||||
using Robust.Shared.Timing;
|
||||
using Robust.Shared.Utility;
|
||||
|
||||
@@ -66,6 +66,42 @@ public sealed class NetworkConfiguratorSystem : SharedNetworkConfiguratorSystem
|
||||
SubscribeLocalEvent<NetworkConfiguratorComponent, BoundUserInterfaceCheckRangeEvent>(OnUiRangeCheck);
|
||||
|
||||
SubscribeLocalEvent<DeviceListComponent, ComponentRemove>(OnComponentRemoved);
|
||||
|
||||
SubscribeLocalEvent<BeforeSaveEvent>(OnMapSave);
|
||||
}
|
||||
|
||||
private void OnMapSave(BeforeSaveEvent ev)
|
||||
{
|
||||
var enumerator = AllEntityQuery<NetworkConfiguratorComponent>();
|
||||
while (enumerator.MoveNext(out var uid, out var conf))
|
||||
{
|
||||
if (CompOrNull<TransformComponent>(conf.ActiveDeviceList)?.MapUid != ev.Map)
|
||||
continue;
|
||||
|
||||
// The linked device list is (probably) being saved. Make sure that the configurator is also being saved
|
||||
// (i.e., not in the hands of a mapper/ghost). In the future, map saving should raise a separate event
|
||||
// containing a set of all entities that are about to be saved, which would make checking this much easier.
|
||||
// This is a shitty bandaid, and will force close the UI during auto-saves.
|
||||
// TODO Map serialization refactor
|
||||
|
||||
var xform = Transform(uid);
|
||||
if (xform.MapUid == ev.Map && IsSaveable(uid))
|
||||
continue;
|
||||
|
||||
_uiSystem.CloseUi(uid, NetworkConfiguratorUiKey.Configure);
|
||||
DebugTools.AssertNull(conf.ActiveDeviceList);
|
||||
}
|
||||
|
||||
bool IsSaveable(EntityUid uid)
|
||||
{
|
||||
while (uid.IsValid())
|
||||
{
|
||||
if (Prototype(uid)?.MapSavable == false)
|
||||
return false;
|
||||
uid = Transform(uid).ParentUid;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
private void OnUiRangeCheck(Entity<NetworkConfiguratorComponent> ent, ref BoundUserInterfaceCheckRangeEvent args)
|
||||
@@ -485,6 +521,9 @@ public sealed class NetworkConfiguratorSystem : SharedNetworkConfiguratorSystem
|
||||
if (!TryComp(targetUid, out DeviceListComponent? list))
|
||||
return;
|
||||
|
||||
if (TryComp(configurator.ActiveDeviceList, out DeviceListComponent? oldList))
|
||||
oldList.Configurators.Remove(configuratorUid);
|
||||
|
||||
list.Configurators.Add(configuratorUid);
|
||||
configurator.ActiveDeviceList = targetUid;
|
||||
Dirty(configuratorUid, configurator);
|
||||
@@ -758,7 +797,7 @@ public sealed class NetworkConfiguratorSystem : SharedNetworkConfiguratorSystem
|
||||
{
|
||||
if (query.TryGetComponent(device, out var comp))
|
||||
{
|
||||
component.Devices[addr] = device;
|
||||
component.Devices.Add(addr, device);
|
||||
comp.Configurators.Add(uid);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,6 +28,7 @@ public sealed partial class DragonSystem : EntitySystem
|
||||
[Dependency] private readonly SharedActionsSystem _actions = default!;
|
||||
[Dependency] private readonly SharedAudioSystem _audio = default!;
|
||||
[Dependency] private readonly SharedTransformSystem _transform = default!;
|
||||
[Dependency] private readonly SharedMapSystem _map = default!;
|
||||
[Dependency] private readonly MobStateSystem _mobState = default!;
|
||||
|
||||
private EntityQuery<CarpRiftsConditionComponent> _objQuery;
|
||||
@@ -156,7 +157,7 @@ public sealed partial class DragonSystem : EntitySystem
|
||||
}
|
||||
|
||||
// cant put a rift on solars
|
||||
foreach (var tile in grid.GetTilesIntersecting(new Circle(_transform.GetWorldPosition(xform), RiftTileRadius), false))
|
||||
foreach (var tile in _map.GetTilesIntersecting(xform.GridUid.Value, grid, new Circle(_transform.GetWorldPosition(xform), RiftTileRadius), false))
|
||||
{
|
||||
if (!tile.IsSpace(_tileDef))
|
||||
continue;
|
||||
|
||||
@@ -121,7 +121,7 @@ public sealed class ElectrocutionSystem : SharedElectrocutionSystem
|
||||
activated.TimeLeft -= frameTime;
|
||||
if (activated.TimeLeft <= 0 || !IsPowered(uid, electrified, transform))
|
||||
{
|
||||
_appearance.SetData(uid, ElectrifiedVisuals.IsPowered, false);
|
||||
_appearance.SetData(uid, ElectrifiedVisuals.ShowSparks, false);
|
||||
RemComp<ActivatedElectrifiedComponent>(uid);
|
||||
}
|
||||
}
|
||||
@@ -217,7 +217,7 @@ public sealed class ElectrocutionSystem : SharedElectrocutionSystem
|
||||
return false;
|
||||
|
||||
EnsureComp<ActivatedElectrifiedComponent>(uid);
|
||||
_appearance.SetData(uid, ElectrifiedVisuals.IsPowered, true);
|
||||
_appearance.SetData(uid, ElectrifiedVisuals.ShowSparks, true);
|
||||
|
||||
siemens *= electrified.SiemensCoefficient;
|
||||
if (!DoCommonElectrocutionAttempt(targetUid, uid, ref siemens) || siemens <= 0)
|
||||
@@ -488,15 +488,4 @@ public sealed class ElectrocutionSystem : SharedElectrocutionSystem
|
||||
}
|
||||
_audio.PlayPvs(electrified.ShockNoises, targetUid, AudioParams.Default.WithVolume(electrified.ShockVolume));
|
||||
}
|
||||
|
||||
public void SetElectrifiedWireCut(Entity<ElectrifiedComponent> ent, bool value)
|
||||
{
|
||||
if (ent.Comp.IsWireCut == value)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
ent.Comp.IsWireCut = value;
|
||||
Dirty(ent);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -134,13 +134,6 @@ public sealed class DrainSystem : SharedDrainSystem
|
||||
}
|
||||
drain.Accumulator -= drain.DrainFrequency;
|
||||
|
||||
// Disable ambient sound from emptying manually
|
||||
if (!drain.AutoDrain)
|
||||
{
|
||||
_ambientSoundSystem.SetAmbience(uid, false);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!managerQuery.TryGetComponent(uid, out var manager))
|
||||
continue;
|
||||
|
||||
@@ -160,41 +153,44 @@ public sealed class DrainSystem : SharedDrainSystem
|
||||
// This will ensure that UnitsPerSecond is per second...
|
||||
var amount = drain.UnitsPerSecond * drain.DrainFrequency;
|
||||
|
||||
_puddles.Clear();
|
||||
_lookup.GetEntitiesInRange(Transform(uid).Coordinates, drain.Range, _puddles);
|
||||
|
||||
if (_puddles.Count == 0)
|
||||
if (drain.AutoDrain)
|
||||
{
|
||||
_ambientSoundSystem.SetAmbience(uid, false);
|
||||
continue;
|
||||
}
|
||||
_puddles.Clear();
|
||||
_lookup.GetEntitiesInRange(Transform(uid).Coordinates, drain.Range, _puddles);
|
||||
|
||||
_ambientSoundSystem.SetAmbience(uid, true);
|
||||
|
||||
amount /= _puddles.Count;
|
||||
|
||||
foreach (var puddle in _puddles)
|
||||
{
|
||||
// Queue the solution deletion if it's empty. EvaporationSystem might also do this
|
||||
// but queuedelete should be pretty safe.
|
||||
if (!_solutionContainerSystem.ResolveSolution(puddle.Owner, puddle.Comp.SolutionName, ref puddle.Comp.Solution, out var puddleSolution))
|
||||
if (_puddles.Count == 0)
|
||||
{
|
||||
EntityManager.QueueDeleteEntity(puddle);
|
||||
_ambientSoundSystem.SetAmbience(uid, false);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Removes the lowest of:
|
||||
// the drain component's units per second adjusted for # of puddles
|
||||
// the puddle's remaining volume (making it cleanly zero)
|
||||
// the drain's remaining volume in its buffer.
|
||||
var transferSolution = _solutionContainerSystem.SplitSolution(puddle.Comp.Solution.Value,
|
||||
FixedPoint2.Min(FixedPoint2.New(amount), puddleSolution.Volume, drainSolution.AvailableVolume));
|
||||
_ambientSoundSystem.SetAmbience(uid, true);
|
||||
|
||||
drainSolution.AddSolution(transferSolution, _prototypeManager);
|
||||
amount /= _puddles.Count;
|
||||
|
||||
if (puddleSolution.Volume <= 0)
|
||||
foreach (var puddle in _puddles)
|
||||
{
|
||||
QueueDel(puddle);
|
||||
// Queue the solution deletion if it's empty. EvaporationSystem might also do this
|
||||
// but queuedelete should be pretty safe.
|
||||
if (!_solutionContainerSystem.ResolveSolution(puddle.Owner, puddle.Comp.SolutionName, ref puddle.Comp.Solution, out var puddleSolution))
|
||||
{
|
||||
EntityManager.QueueDeleteEntity(puddle);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Removes the lowest of:
|
||||
// the drain component's units per second adjusted for # of puddles
|
||||
// the puddle's remaining volume (making it cleanly zero)
|
||||
// the drain's remaining volume in its buffer.
|
||||
var transferSolution = _solutionContainerSystem.SplitSolution(puddle.Comp.Solution.Value,
|
||||
FixedPoint2.Min(FixedPoint2.New(amount), puddleSolution.Volume, drainSolution.AvailableVolume));
|
||||
|
||||
drainSolution.AddSolution(transferSolution, _prototypeManager);
|
||||
|
||||
if (puddleSolution.Volume <= 0)
|
||||
{
|
||||
QueueDel(puddle);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -25,7 +25,7 @@ public sealed partial class PuddleSystem
|
||||
var tileRef = _maps.GetTileRef(xform.GridUid.Value, mapGrid, xform.Coordinates);
|
||||
var tileDef = (ContentTileDefinition) _tileDefManager[tileRef.Tile.TypeId];
|
||||
|
||||
entity.Comp.CP14ForceEvaporation = tileDef.Weather;
|
||||
entity.Comp.CP14ForceEvaporation = tileDef.SuckReagents;
|
||||
}
|
||||
//CP14 End force evaporation under sky
|
||||
}
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
using Content.Server.Popups;
|
||||
using Content.Shared.Administration;
|
||||
using Content.Shared.GameTicking;
|
||||
using Content.Shared.Mind;
|
||||
using Robust.Shared.Console;
|
||||
using Content.Server.GameTicking;
|
||||
|
||||
namespace Content.Server.Ghost
|
||||
{
|
||||
@@ -23,6 +25,14 @@ namespace Content.Server.Ghost
|
||||
return;
|
||||
}
|
||||
|
||||
var gameTicker = _entities.System<GameTicker>();
|
||||
if (!gameTicker.PlayerGameStatuses.TryGetValue(player.UserId, out var playerStatus) ||
|
||||
playerStatus is not PlayerGameStatus.JoinedGame)
|
||||
{
|
||||
shell.WriteLine("ghost-command-error-lobby");
|
||||
return;
|
||||
}
|
||||
|
||||
if (player.AttachedEntity is { Valid: true } frozen &&
|
||||
_entities.HasComponent<AdminFrozenComponent>(frozen))
|
||||
{
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
using System.Linq;
|
||||
using System.Numerics;
|
||||
using Content.Server.Administration.Logs;
|
||||
using Content.Server.Chat.Managers;
|
||||
using Content.Server.GameTicking;
|
||||
@@ -32,14 +34,13 @@ using Robust.Shared.Physics.Systems;
|
||||
using Robust.Shared.Player;
|
||||
using Robust.Shared.Prototypes;
|
||||
using Robust.Shared.Timing;
|
||||
using System.Linq;
|
||||
using System.Numerics;
|
||||
|
||||
namespace Content.Server.Ghost
|
||||
{
|
||||
public sealed class GhostSystem : SharedGhostSystem
|
||||
{
|
||||
[Dependency] private readonly SharedActionsSystem _actions = default!;
|
||||
[Dependency] private readonly IAdminLogManager _adminLog = default!;
|
||||
[Dependency] private readonly SharedEyeSystem _eye = default!;
|
||||
[Dependency] private readonly FollowerSystem _followerSystem = default!;
|
||||
[Dependency] private readonly IGameTiming _gameTiming = default!;
|
||||
@@ -213,21 +214,22 @@ namespace Content.Server.Ghost
|
||||
|
||||
private void OnMapInit(EntityUid uid, GhostComponent component, MapInitEvent args)
|
||||
{
|
||||
//if (_actions.AddAction(uid, ref component.BooActionEntity, out var act, component.BooAction)
|
||||
// && act.UseDelay != null)
|
||||
//{
|
||||
// var start = _gameTiming.CurTime;
|
||||
// var end = start + act.UseDelay.Value;
|
||||
// _actions.SetCooldown(component.BooActionEntity.Value, start, end);
|
||||
//}
|
||||
if (_actions.AddAction(uid, ref component.BooActionEntity, out var act, component.BooAction)
|
||||
&& act.UseDelay != null)
|
||||
{
|
||||
var start = _gameTiming.CurTime;
|
||||
var end = start + act.UseDelay.Value;
|
||||
_actions.SetCooldown(component.BooActionEntity.Value, start, end);
|
||||
}
|
||||
|
||||
_actions.AddAction(uid, ref component.ToggleGhostHearingActionEntity, component.ToggleGhostHearingAction);
|
||||
//_actions.AddAction(uid, ref component.ToggleGhostHearingActionEntity, component.ToggleGhostHearingAction); //Dont need in CP14
|
||||
_actions.AddAction(uid, ref component.ToggleLightingActionEntity, component.ToggleLightingAction);
|
||||
_actions.AddAction(uid, ref component.ToggleFoVActionEntity, component.ToggleFoVAction);
|
||||
_actions.AddAction(uid, ref component.ToggleGhostsActionEntity, component.ToggleGhostsAction);
|
||||
//CP14
|
||||
_actions.AddAction(uid, ref component.CP14ZLevelUpActionEntity, component.CP14ZLevelUpAction);
|
||||
_actions.AddAction(uid, ref component.CP14ZLevelDownActionEntity, component.CP14ZLevelDownAction);
|
||||
_actions.AddAction(uid, ref component.CP14ToggleRoofActionEntity, component.CP14ToggleRoofAction);
|
||||
//CP14 end
|
||||
}
|
||||
|
||||
@@ -334,6 +336,8 @@ namespace Content.Server.Ghost
|
||||
|
||||
private void WarpTo(EntityUid uid, EntityUid target)
|
||||
{
|
||||
_adminLog.Add(LogType.GhostWarp, $"{ToPrettyString(uid)} ghost warped to {ToPrettyString(target)}");
|
||||
|
||||
if ((TryComp(target, out WarpPointComponent? warp) && warp.Follow) || HasComp<MobStateComponent>(target))
|
||||
{
|
||||
_followerSystem.StartFollowingEntity(uid, target);
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
using System.Linq;
|
||||
using System.Linq;
|
||||
using Content.Server.Administration;
|
||||
using Content.Server.Ghost.Roles.Components;
|
||||
using Content.Server.Ghost.Roles.Raffles;
|
||||
@@ -77,13 +77,13 @@ namespace Content.Server.Ghost.Roles
|
||||
|
||||
if (isProto)
|
||||
{
|
||||
if (!_protoManager.TryIndex<GhostRoleRaffleSettingsPrototype>(args[4], out var proto))
|
||||
if (!_protoManager.TryIndex<GhostRoleRaffleSettingsPrototype>(args[3], out var proto))
|
||||
{
|
||||
var validProtos = string.Join(", ",
|
||||
_protoManager.EnumeratePrototypes<GhostRoleRaffleSettingsPrototype>().Select(p => p.ID)
|
||||
);
|
||||
|
||||
shell.WriteLine($"{args[4]} is not a valid raffle settings prototype. Valid options: {validProtos}");
|
||||
shell.WriteLine($"{args[3]} is not a valid raffle settings prototype. Valid options: {validProtos}");
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -9,7 +9,6 @@ using Content.Shared.Light;
|
||||
using Content.Shared.Light.Components;
|
||||
using Content.Shared.Rounding;
|
||||
using Content.Shared.Toggleable;
|
||||
using Content.Shared.Verbs;
|
||||
using JetBrains.Annotations;
|
||||
using Robust.Server.GameObjects;
|
||||
using Robust.Shared.Audio;
|
||||
@@ -46,7 +45,6 @@ namespace Content.Server.Light.EntitySystems
|
||||
SubscribeLocalEvent<HandheldLightComponent, ComponentShutdown>(OnShutdown);
|
||||
|
||||
SubscribeLocalEvent<HandheldLightComponent, ExaminedEvent>(OnExamine);
|
||||
SubscribeLocalEvent<HandheldLightComponent, GetVerbsEvent<ActivationVerb>>(AddToggleLightVerb);
|
||||
|
||||
SubscribeLocalEvent<HandheldLightComponent, ActivateInWorldEvent>(OnActivate);
|
||||
|
||||
@@ -179,25 +177,7 @@ namespace Content.Server.Light.EntitySystems
|
||||
}
|
||||
}
|
||||
|
||||
private void AddToggleLightVerb(Entity<HandheldLightComponent> ent, ref GetVerbsEvent<ActivationVerb> args)
|
||||
{
|
||||
if (!args.CanAccess || !args.CanInteract || !ent.Comp.ToggleOnInteract)
|
||||
return;
|
||||
|
||||
var @event = args;
|
||||
ActivationVerb verb = new()
|
||||
{
|
||||
Text = Loc.GetString("verb-common-toggle-light"),
|
||||
Icon = new SpriteSpecifier.Texture(new ("/Textures/Interface/VerbIcons/light.svg.192dpi.png")),
|
||||
Act = ent.Comp.Activated
|
||||
? () => TurnOff(ent)
|
||||
: () => TurnOn(@event.User, ent)
|
||||
};
|
||||
|
||||
args.Verbs.Add(verb);
|
||||
}
|
||||
|
||||
public bool TurnOff(Entity<HandheldLightComponent> ent, bool makeNoise = true)
|
||||
public override bool TurnOff(Entity<HandheldLightComponent> ent, bool makeNoise = true)
|
||||
{
|
||||
if (!ent.Comp.Activated || !_lights.TryGetLight(ent, out var pointLightComponent))
|
||||
{
|
||||
@@ -211,7 +191,7 @@ namespace Content.Server.Light.EntitySystems
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool TurnOn(EntityUid user, Entity<HandheldLightComponent> uid)
|
||||
public override bool TurnOn(EntityUid user, Entity<HandheldLightComponent> uid)
|
||||
{
|
||||
var component = uid.Comp;
|
||||
if (component.Activated || !_lights.TryGetLight(uid, out var pointLightComponent))
|
||||
|
||||
@@ -40,6 +40,7 @@ public sealed class NukeSystem : EntitySystem
|
||||
[Dependency] private readonly SharedAudioSystem _audio = default!;
|
||||
[Dependency] private readonly SharedDoAfterSystem _doAfter = default!;
|
||||
[Dependency] private readonly SharedTransformSystem _transform = default!;
|
||||
[Dependency] private readonly SharedMapSystem _map = default!;
|
||||
[Dependency] private readonly StationSystem _station = default!;
|
||||
[Dependency] private readonly UserInterfaceSystem _ui = default!;
|
||||
[Dependency] private readonly AppearanceSystem _appearance = default!;
|
||||
@@ -190,7 +191,7 @@ public sealed class NukeSystem : EntitySystem
|
||||
|
||||
var worldPos = _transform.GetWorldPosition(xform);
|
||||
|
||||
foreach (var tile in grid.GetTilesIntersecting(new Circle(worldPos, component.RequiredFloorRadius), false))
|
||||
foreach (var tile in _map.GetTilesIntersecting(xform.GridUid.Value, grid, new Circle(worldPos, component.RequiredFloorRadius), false))
|
||||
{
|
||||
if (!tile.IsSpace(_tileDefManager))
|
||||
continue;
|
||||
|
||||
@@ -18,8 +18,11 @@ public sealed partial class CableComponent : Component
|
||||
[DataField]
|
||||
public EntProtoId CableDroppedOnCutPrototype = "CableHVStack1";
|
||||
|
||||
/// <summary>
|
||||
/// The tool quality needed to cut the cable. Setting to null prevents cutting.
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public ProtoId<ToolQualityPrototype> CuttingQuality = SharedToolSystem.CutQuality;
|
||||
public ProtoId<ToolQualityPrototype>? CuttingQuality = SharedToolSystem.CutQuality;
|
||||
|
||||
/// <summary>
|
||||
/// Checked by <see cref="CablePlacerComponent"/> to determine if there is
|
||||
|
||||
@@ -35,7 +35,7 @@ public sealed partial class CableSystem
|
||||
var snapPos = grid.TileIndicesFor(args.ClickLocation);
|
||||
var tileDef = (ContentTileDefinition) _tileManager[_map.GetTileRef(gridUid, grid,snapPos).Tile.TypeId];
|
||||
|
||||
if ((!tileDef.IsSubFloor || !tileDef.Sturdy) && placer.Comp.CP14OnlySubfloor) //CP14 if only subfloor
|
||||
if (!tileDef.IsSubFloor || !tileDef.Sturdy)
|
||||
return;
|
||||
|
||||
foreach (var anchored in grid.GetAnchoredEntities(snapPos))
|
||||
|
||||
@@ -35,7 +35,10 @@ public sealed partial class CableSystem : EntitySystem
|
||||
if (args.Handled)
|
||||
return;
|
||||
|
||||
args.Handled = _toolSystem.UseTool(args.Used, args.User, uid, cable.CuttingDelay, cable.CuttingQuality, new CableCuttingFinishedEvent());
|
||||
if (cable.CuttingQuality != null)
|
||||
{
|
||||
args.Handled = _toolSystem.UseTool(args.Used, args.User, uid, cable.CuttingDelay, cable.CuttingQuality, new CableCuttingFinishedEvent());
|
||||
}
|
||||
}
|
||||
|
||||
private void OnCableCut(EntityUid uid, CableComponent cable, DoAfterEvent args)
|
||||
|
||||
@@ -17,7 +17,7 @@ public sealed partial class PowerWireAction : BaseWireAction
|
||||
[DataField("pulseTimeout")]
|
||||
private int _pulseTimeout = 30;
|
||||
|
||||
private ElectrocutionSystem _electrocutionSystem = default!;
|
||||
private ElectrocutionSystem _electrocution = default!;
|
||||
|
||||
public override object StatusKey { get; } = PowerWireActionKey.Status;
|
||||
|
||||
@@ -105,8 +105,8 @@ public sealed partial class PowerWireAction : BaseWireAction
|
||||
&& !EntityManager.TryGetComponent(used, out electrified))
|
||||
return;
|
||||
|
||||
_electrocutionSystem.SetElectrifiedWireCut((used, electrified), setting);
|
||||
electrified.Enabled = setting;
|
||||
_electrocution.SetElectrifiedWireCut((used, electrified), setting);
|
||||
_electrocution.SetElectrified((used, electrified), setting);
|
||||
}
|
||||
|
||||
/// <returns>false if failed, true otherwise, or if the entity cannot be electrified</returns>
|
||||
@@ -120,7 +120,7 @@ public sealed partial class PowerWireAction : BaseWireAction
|
||||
// always set this to true
|
||||
SetElectrified(wire.Owner, true, electrified);
|
||||
|
||||
var electrifiedAttempt = _electrocutionSystem.TryDoElectrifiedAct(wire.Owner, user);
|
||||
var electrifiedAttempt = _electrocution.TryDoElectrifiedAct(wire.Owner, user);
|
||||
|
||||
// if we were electrified, then return false
|
||||
return !electrifiedAttempt;
|
||||
@@ -161,7 +161,7 @@ public sealed partial class PowerWireAction : BaseWireAction
|
||||
{
|
||||
base.Initialize();
|
||||
|
||||
_electrocutionSystem = EntityManager.System<ElectrocutionSystem>();
|
||||
_electrocution = EntityManager.System<ElectrocutionSystem>();
|
||||
}
|
||||
|
||||
// This should add a wire into the entity's state, whether it be
|
||||
|
||||
@@ -58,7 +58,7 @@ public sealed partial class DungeonJob
|
||||
}
|
||||
}
|
||||
|
||||
if (tile is not null && biomeSystem.TryGetEntity(node, indexedBiome.Layers, tile.Value, seed, _grid, out var entityProto))
|
||||
if (biomeSystem.TryGetEntity(node, indexedBiome.Layers, tile ?? tileRef.Value.Tile, seed, _grid, out var entityProto))
|
||||
{
|
||||
var ent = _entManager.SpawnEntity(entityProto, new EntityCoordinates(_gridUid, node + _grid.TileSizeHalfVector));
|
||||
var xform = xformQuery.Get(ent);
|
||||
|
||||
@@ -20,7 +20,11 @@ public sealed partial class DungeonJob
|
||||
}
|
||||
|
||||
var tileDef = _prototype.Index(tileProto);
|
||||
data.SpawnGroups.TryGetValue(DungeonDataKey.WallMounts, out var spawnProto);
|
||||
if (!data.SpawnGroups.TryGetValue(DungeonDataKey.WallMounts, out var spawnProto))
|
||||
{
|
||||
// caves can have no walls
|
||||
return;
|
||||
}
|
||||
|
||||
var checkedTiles = new HashSet<Vector2i>();
|
||||
var allExterior = new HashSet<Vector2i>(dungeon.CorridorExteriorTiles);
|
||||
|
||||
@@ -45,7 +45,6 @@ public sealed class ProjectileSystem : SharedProjectileSystem
|
||||
RaiseLocalEvent(uid, ref ev);
|
||||
|
||||
var otherName = ToPrettyString(target);
|
||||
var direction = args.OurBody.LinearVelocity.Normalized();
|
||||
var modifiedDamage = _damageableSystem.TryChangeDamage(target, ev.Damage, component.IgnoreResistances, origin: component.Shooter);
|
||||
var deleted = Deleted(target);
|
||||
|
||||
@@ -64,7 +63,9 @@ public sealed class ProjectileSystem : SharedProjectileSystem
|
||||
if (!deleted)
|
||||
{
|
||||
_guns.PlayImpactSound(target, modifiedDamage, component.SoundHit, component.ForceSound);
|
||||
_sharedCameraRecoil.KickCamera(target, direction);
|
||||
|
||||
if (!args.OurBody.LinearVelocity.IsLengthZero())
|
||||
_sharedCameraRecoil.KickCamera(target, args.OurBody.LinearVelocity.Normalized());
|
||||
}
|
||||
|
||||
component.DamagedEntity = true;
|
||||
|
||||
@@ -21,6 +21,7 @@ public sealed class SpecialRespawnSystem : SharedSpecialRespawnSystem
|
||||
[Dependency] private readonly AtmosphereSystem _atmosphere = default!;
|
||||
[Dependency] private readonly IRobustRandom _random = default!;
|
||||
[Dependency] private readonly SharedTransformSystem _transform = default!;
|
||||
[Dependency] private readonly SharedMapSystem _map = default!;
|
||||
[Dependency] private readonly TurfSystem _turf = default!;
|
||||
[Dependency] private readonly IChatManager _chat = default!;
|
||||
[Dependency] private readonly IPrototypeManager _proto = default!;
|
||||
@@ -105,7 +106,7 @@ public sealed class SpecialRespawnSystem : SharedSpecialRespawnSystem
|
||||
|
||||
var found = false;
|
||||
|
||||
foreach (var tile in grid.GetTilesIntersecting(circle))
|
||||
foreach (var tile in _map.GetTilesIntersecting(entityGridUid.Value, grid, circle))
|
||||
{
|
||||
if (tile.IsSpace(_tileDefinitionManager)
|
||||
|| _turf.IsTileBlocked(tile, CollisionGroup.MobMask)
|
||||
@@ -176,7 +177,7 @@ public sealed class SpecialRespawnSystem : SharedSpecialRespawnSystem
|
||||
var mapTarget = grid.WorldToTile(mapPos);
|
||||
var circle = new Circle(mapPos, 2);
|
||||
|
||||
foreach (var newTileRef in grid.GetTilesIntersecting(circle))
|
||||
foreach (var newTileRef in _map.GetTilesIntersecting(targetGrid, grid, circle))
|
||||
{
|
||||
if (newTileRef.IsSpace(_tileDefinitionManager) || _turf.IsTileBlocked(newTileRef, CollisionGroup.MobMask) || !_atmosphere.IsTileMixtureProbablySafe(targetGrid, targetMap, mapTarget))
|
||||
continue;
|
||||
|
||||
@@ -43,6 +43,7 @@ public sealed partial class RevenantSystem
|
||||
[Dependency] private readonly TileSystem _tile = default!;
|
||||
[Dependency] private readonly EntityWhitelistSystem _whitelistSystem = default!;
|
||||
[Dependency] private readonly SharedTransformSystem _transformSystem = default!;
|
||||
[Dependency] private readonly SharedMapSystem _mapSystem = default!;
|
||||
|
||||
private void InitializeAbilities()
|
||||
{
|
||||
@@ -228,8 +229,12 @@ public sealed partial class RevenantSystem
|
||||
var xform = Transform(uid);
|
||||
if (!TryComp<MapGridComponent>(xform.GridUid, out var map))
|
||||
return;
|
||||
var tiles = map.GetTilesIntersecting(Box2.CenteredAround(_transformSystem.GetWorldPosition(xform),
|
||||
new Vector2(component.DefileRadius * 2, component.DefileRadius))).ToArray();
|
||||
var tiles = _mapSystem.GetTilesIntersecting(
|
||||
xform.GridUid.Value,
|
||||
map,
|
||||
Box2.CenteredAround(_transformSystem.GetWorldPosition(xform),
|
||||
new Vector2(component.DefileRadius * 2, component.DefileRadius)))
|
||||
.ToArray();
|
||||
|
||||
_random.Shuffle(tiles);
|
||||
|
||||
|
||||
@@ -193,7 +193,7 @@ public sealed class SpawnSalvageMissionJob : Job<bool>
|
||||
|
||||
List<Vector2i> reservedTiles = new();
|
||||
|
||||
foreach (var tile in grid.GetTilesIntersecting(new Circle(Vector2.Zero, landingPadRadius), false))
|
||||
foreach (var tile in _map.GetTilesIntersecting(mapUid, grid, new Circle(Vector2.Zero, landingPadRadius), false))
|
||||
{
|
||||
if (!_biome.TryGetBiomeTile(mapUid, grid, tile.GridIndices, out _))
|
||||
continue;
|
||||
|
||||
@@ -253,12 +253,6 @@ public sealed partial class ShuttleSystem
|
||||
|
||||
if (TryComp<PhysicsComponent>(shuttleUid, out var shuttlePhysics))
|
||||
{
|
||||
// Static physics type is set when station anchor is enabled
|
||||
if (shuttlePhysics.BodyType == BodyType.Static)
|
||||
{
|
||||
reason = Loc.GetString("shuttle-console-static");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Too large to FTL
|
||||
if (FTLMassLimit > 0 && shuttlePhysics.Mass > FTLMassLimit)
|
||||
@@ -1027,6 +1021,7 @@ public sealed partial class ShuttleSystem
|
||||
continue;
|
||||
}
|
||||
|
||||
// If it has the FTLSmashImmuneComponent ignore it.
|
||||
if (_immuneQuery.HasComponent(ent))
|
||||
{
|
||||
continue;
|
||||
|
||||
37
Content.Server/Silicons/Laws/StartIonStormedSystem.cs
Normal file
37
Content.Server/Silicons/Laws/StartIonStormedSystem.cs
Normal file
@@ -0,0 +1,37 @@
|
||||
using Content.Shared.Silicons.Laws.Components;
|
||||
using Content.Shared.Administration.Logs;
|
||||
using Content.Shared.Database;
|
||||
|
||||
namespace Content.Server.Silicons.Laws;
|
||||
|
||||
/// <summary>
|
||||
/// This handles running the ion storm event a on specific entity when that entity is spawned in.
|
||||
/// </summary>
|
||||
public sealed class StartIonStormedSystem : EntitySystem
|
||||
{
|
||||
[Dependency] private readonly IonStormSystem _ionStorm = default!;
|
||||
[Dependency] private readonly ISharedAdminLogManager _adminLogger = default!;
|
||||
[Dependency] private readonly SiliconLawSystem _siliconLaw = default!;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
SubscribeLocalEvent<StartIonStormedComponent, MapInitEvent>(OnMapInit);
|
||||
}
|
||||
|
||||
private void OnMapInit(Entity<StartIonStormedComponent> ent, ref MapInitEvent args)
|
||||
{
|
||||
if (!TryComp<SiliconLawBoundComponent>(ent.Owner, out var lawBound))
|
||||
return;
|
||||
if (!TryComp<IonStormTargetComponent>(ent.Owner, out var target))
|
||||
return;
|
||||
|
||||
for (int currentIonStorm = 0; currentIonStorm < ent.Comp.IonStormAmount; currentIonStorm++)
|
||||
{
|
||||
_ionStorm.IonStormTarget((ent.Owner, lawBound, target), false);
|
||||
}
|
||||
|
||||
var laws = _siliconLaw.GetLaws(ent.Owner, lawBound);
|
||||
_adminLogger.Add(LogType.Mind, LogImpact.High, $"{ToPrettyString(ent.Owner):silicon} spawned with ion stormed laws: {laws.LoggingString()}");
|
||||
}
|
||||
}
|
||||
@@ -308,7 +308,7 @@ public sealed class EventHorizonSystem : SharedEventHorizonSystem
|
||||
foreach (var grid in grids)
|
||||
{
|
||||
// TODO: Remover grid.Owner when this iterator returns entityuids as well.
|
||||
AttemptConsumeTiles(uid, grid.Comp.GetTilesIntersecting(circle), grid, grid, eventHorizon);
|
||||
AttemptConsumeTiles(uid, _mapSystem.GetTilesIntersecting(grid.Owner, grid.Comp, circle), grid, grid, eventHorizon);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
using Content.Server.StationEvents.Events;
|
||||
using Content.Shared.Access;
|
||||
using Content.Shared.Destructible.Thresholds;
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
namespace Content.Server.StationEvents.Components;
|
||||
|
||||
/// <summary>
|
||||
/// Greytide Virus event specific configuration
|
||||
/// </summary>
|
||||
[RegisterComponent, Access(typeof(GreytideVirusRule))]
|
||||
public sealed partial class GreytideVirusRuleComponent : Component
|
||||
{
|
||||
/// <summary>
|
||||
/// Range from which the severity is randomly picked from.
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public MinMax SeverityRange = new(1, 3);
|
||||
|
||||
/// <summary>
|
||||
/// Severity corresponding to the number of access groups affected.
|
||||
/// Will pick randomly from the SeverityRange if not specified.
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public int? Severity;
|
||||
|
||||
/// <summary>
|
||||
/// Access groups to pick from.
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public List<ProtoId<AccessGroupPrototype>> AccessGroups = new();
|
||||
|
||||
/// <summary>
|
||||
/// Entities with this access level will be ignored.
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public List<ProtoId<AccessLevelPrototype>> Blacklist = new();
|
||||
}
|
||||
@@ -148,20 +148,20 @@ public sealed class EventManagerSystem : EntitySystem
|
||||
return null;
|
||||
}
|
||||
|
||||
var sumOfWeights = 0;
|
||||
var sumOfWeights = 0.0f;
|
||||
|
||||
foreach (var stationEvent in availableEvents.Values)
|
||||
{
|
||||
sumOfWeights += (int) stationEvent.Weight;
|
||||
sumOfWeights += stationEvent.Weight;
|
||||
}
|
||||
|
||||
sumOfWeights = _random.Next(sumOfWeights);
|
||||
sumOfWeights = _random.NextFloat(sumOfWeights);
|
||||
|
||||
foreach (var (proto, stationEvent) in availableEvents)
|
||||
{
|
||||
sumOfWeights -= (int) stationEvent.Weight;
|
||||
sumOfWeights -= stationEvent.Weight;
|
||||
|
||||
if (sumOfWeights <= 0)
|
||||
if (sumOfWeights <= 0.0f)
|
||||
{
|
||||
return proto.ID;
|
||||
}
|
||||
|
||||
96
Content.Server/StationEvents/Events/GreytideVirusRule.cs
Normal file
96
Content.Server/StationEvents/Events/GreytideVirusRule.cs
Normal file
@@ -0,0 +1,96 @@
|
||||
using Content.Server.StationEvents.Components;
|
||||
using Content.Shared.Access;
|
||||
using Content.Shared.Access.Systems;
|
||||
using Content.Shared.Access.Components;
|
||||
using Content.Shared.Doors.Components;
|
||||
using Content.Shared.Doors.Systems;
|
||||
using Content.Shared.Lock;
|
||||
using Content.Shared.GameTicking.Components;
|
||||
using Robust.Shared.Prototypes;
|
||||
using Robust.Shared.Random;
|
||||
|
||||
namespace Content.Server.StationEvents.Events;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Greytide Virus event
|
||||
/// This will open and bolt airlocks and unlock lockers from randomly selected access groups.
|
||||
/// </summary>
|
||||
public sealed class GreytideVirusRule : StationEventSystem<GreytideVirusRuleComponent>
|
||||
{
|
||||
[Dependency] private readonly AccessReaderSystem _access = default!;
|
||||
[Dependency] private readonly SharedDoorSystem _door = default!;
|
||||
[Dependency] private readonly LockSystem _lock = default!;
|
||||
[Dependency] private readonly IPrototypeManager _prototype = default!;
|
||||
[Dependency] private readonly IRobustRandom _random = default!;
|
||||
|
||||
protected override void Added(EntityUid uid, GreytideVirusRuleComponent virusComp, GameRuleComponent gameRule, GameRuleAddedEvent args)
|
||||
{
|
||||
if (!TryComp<StationEventComponent>(uid, out var stationEvent))
|
||||
return;
|
||||
|
||||
// pick severity randomly from range if not specified otherwise
|
||||
virusComp.Severity ??= virusComp.SeverityRange.Next(_random);
|
||||
virusComp.Severity = Math.Min(virusComp.Severity.Value, virusComp.AccessGroups.Count);
|
||||
|
||||
stationEvent.StartAnnouncement = Loc.GetString("station-event-greytide-virus-start-announcement", ("severity", virusComp.Severity.Value));
|
||||
base.Added(uid, virusComp, gameRule, args);
|
||||
}
|
||||
protected override void Started(EntityUid uid, GreytideVirusRuleComponent virusComp, GameRuleComponent gameRule, GameRuleStartedEvent args)
|
||||
{
|
||||
base.Started(uid, virusComp, gameRule, args);
|
||||
|
||||
if (virusComp.Severity == null)
|
||||
return;
|
||||
|
||||
// pick random access groups
|
||||
var chosen = _random.GetItems(virusComp.AccessGroups, virusComp.Severity.Value, allowDuplicates: false);
|
||||
|
||||
// combine all the selected access groups
|
||||
var accessIds = new HashSet<ProtoId<AccessLevelPrototype>>();
|
||||
foreach (var group in chosen)
|
||||
{
|
||||
if (_prototype.TryIndex(group, out var proto))
|
||||
accessIds.UnionWith(proto.Tags);
|
||||
}
|
||||
|
||||
var firelockQuery = GetEntityQuery<FirelockComponent>();
|
||||
var accessQuery = GetEntityQuery<AccessReaderComponent>();
|
||||
|
||||
var lockQuery = AllEntityQuery<LockComponent>();
|
||||
while (lockQuery.MoveNext(out var lockUid, out var lockComp))
|
||||
{
|
||||
if (!accessQuery.TryComp(lockUid, out var accessComp))
|
||||
continue;
|
||||
|
||||
// check access
|
||||
// the AreAccessTagsAllowed function is a little weird because it technically has support for certain tags to be locked out of opening something
|
||||
// which might have unintened side effects (see the comments in the function itself)
|
||||
// but no one uses that yet, so it is fine for now
|
||||
if (!_access.AreAccessTagsAllowed(accessIds, accessComp) || _access.AreAccessTagsAllowed(virusComp.Blacklist, accessComp))
|
||||
continue;
|
||||
|
||||
// open lockers
|
||||
_lock.Unlock(lockUid, null, lockComp);
|
||||
}
|
||||
|
||||
var airlockQuery = AllEntityQuery<AirlockComponent, DoorComponent>();
|
||||
while (airlockQuery.MoveNext(out var airlockUid, out var airlockComp, out var doorComp))
|
||||
{
|
||||
// don't space everything
|
||||
if (firelockQuery.HasComp(airlockUid))
|
||||
continue;
|
||||
|
||||
// use the access reader from the door electronics if they exist
|
||||
if (!_access.GetMainAccessReader(airlockUid, out var accessComp))
|
||||
continue;
|
||||
|
||||
// check access
|
||||
if (!_access.AreAccessTagsAllowed(accessIds, accessComp) || _access.AreAccessTagsAllowed(virusComp.Blacklist, accessComp))
|
||||
continue;
|
||||
|
||||
// open and bolt airlocks
|
||||
_door.TryOpenAndBolt(airlockUid, doorComp, airlockComp);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -38,6 +38,7 @@ namespace Content.Server.VendingMachines
|
||||
[Dependency] private readonly ThrowingSystem _throwingSystem = default!;
|
||||
[Dependency] private readonly IGameTiming _timing = default!;
|
||||
[Dependency] private readonly SpeakOnUIClosedSystem _speakOnUIClosed = default!;
|
||||
[Dependency] private readonly SharedPointLightSystem _light = default!;
|
||||
|
||||
private const float WallVendEjectDistanceFromWall = 1f;
|
||||
|
||||
@@ -334,6 +335,12 @@ namespace Content.Server.VendingMachines
|
||||
finalState = VendingMachineVisualState.Off;
|
||||
}
|
||||
|
||||
if (_light.TryGetLight(uid, out var pointlight))
|
||||
{
|
||||
var lightState = finalState != VendingMachineVisualState.Broken && finalState != VendingMachineVisualState.Off;
|
||||
_light.SetEnabled(uid, lightState, pointlight);
|
||||
}
|
||||
|
||||
_appearanceSystem.SetData(uid, VendingMachineVisuals.VisualState, finalState);
|
||||
}
|
||||
|
||||
|
||||
@@ -22,13 +22,14 @@ public abstract partial class ComponentWireAction<TComponent> : BaseWireAction w
|
||||
public override bool Cut(EntityUid user, Wire wire)
|
||||
{
|
||||
base.Cut(user, wire);
|
||||
return EntityManager.TryGetComponent(wire.Owner, out TComponent? component) && Cut(user, wire, component);
|
||||
// if the entity doesn't exist, we need to return true otherwise the wire sprite is never updated
|
||||
return EntityManager.TryGetComponent(wire.Owner, out TComponent? component) ? Cut(user, wire, component) : true;
|
||||
}
|
||||
|
||||
public override bool Mend(EntityUid user, Wire wire)
|
||||
{
|
||||
base.Mend(user, wire);
|
||||
return EntityManager.TryGetComponent(wire.Owner, out TComponent? component) && Mend(user, wire, component);
|
||||
return EntityManager.TryGetComponent(wire.Owner, out TComponent? component) ? Mend(user, wire, component) : true;
|
||||
}
|
||||
|
||||
public override void Pulse(EntityUid user, Wire wire)
|
||||
|
||||
@@ -4,7 +4,6 @@ using Content.Server.Xenoarchaeology.XenoArtifacts.Events;
|
||||
using Content.Shared.Maps;
|
||||
using Content.Shared.Physics;
|
||||
using Content.Shared.Throwing;
|
||||
using Robust.Server.GameObjects;
|
||||
using Robust.Shared.Map.Components;
|
||||
using Robust.Shared.Physics.Components;
|
||||
using Robust.Shared.Random;
|
||||
@@ -17,7 +16,8 @@ public sealed class ThrowArtifactSystem : EntitySystem
|
||||
[Dependency] private readonly EntityLookupSystem _lookup = default!;
|
||||
[Dependency] private readonly ThrowingSystem _throwing = default!;
|
||||
[Dependency] private readonly TileSystem _tile = default!;
|
||||
[Dependency] private readonly TransformSystem _transform = default!;
|
||||
[Dependency] private readonly SharedTransformSystem _transform = default!;
|
||||
[Dependency] private readonly SharedMapSystem _mapSystem = default!;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override void Initialize()
|
||||
@@ -30,7 +30,9 @@ public sealed class ThrowArtifactSystem : EntitySystem
|
||||
var xform = Transform(uid);
|
||||
if (TryComp<MapGridComponent>(xform.GridUid, out var grid))
|
||||
{
|
||||
var tiles = grid.GetTilesIntersecting(
|
||||
var tiles = _mapSystem.GetTilesIntersecting(
|
||||
xform.GridUid.Value,
|
||||
grid,
|
||||
Box2.CenteredAround(_transform.GetWorldPosition(xform), new Vector2(component.Range * 2, component.Range)));
|
||||
|
||||
foreach (var tile in tiles)
|
||||
|
||||
@@ -108,9 +108,9 @@ public sealed class CP14SpawnRandomDemiplaneJob : Job<bool>
|
||||
}
|
||||
|
||||
//Setup gravity
|
||||
var gravity = _entManager.EnsureComponent<GravityComponent>(DemiplaneMapUid);
|
||||
var gravity = _entManager.EnsureComponent<GravityComponent>(grid);
|
||||
gravity.Enabled = true;
|
||||
_entManager.Dirty(DemiplaneMapUid, gravity, metadata);
|
||||
_entManager.Dirty(grid, gravity, metadata);
|
||||
|
||||
// Setup default atmos
|
||||
var moles = new float[Atmospherics.AdjustedNumberOfGases];
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
namespace Content.Server._CP14.MapDamage;
|
||||
|
||||
/// <summary>
|
||||
/// can take damage from being directly on the map (not on the grid)
|
||||
/// </summary>
|
||||
[RegisterComponent, AutoGenerateComponentPause]
|
||||
public sealed partial class CP14DamageableByMapComponent : Component
|
||||
{
|
||||
[DataField, AutoPausedField]
|
||||
public TimeSpan NextDamageTime = TimeSpan.Zero;
|
||||
|
||||
[DataField]
|
||||
public bool Enabled = false;
|
||||
|
||||
[DataField]
|
||||
public Entity<CP14MapDamageComponent>? CurrentMap;
|
||||
}
|
||||
24
Content.Server/_CP14/MapDamage/CP14MapDamageComponent.cs
Normal file
24
Content.Server/_CP14/MapDamage/CP14MapDamageComponent.cs
Normal file
@@ -0,0 +1,24 @@
|
||||
using Content.Shared.Damage;
|
||||
using Content.Shared.FixedPoint;
|
||||
|
||||
namespace Content.Server._CP14.MapDamage;
|
||||
|
||||
/// <summary>
|
||||
/// The map deals damage to entities that are on it (not on the grid)
|
||||
/// </summary>
|
||||
[RegisterComponent]
|
||||
public sealed partial class CP14MapDamageComponent : Component
|
||||
{
|
||||
//Damage every second
|
||||
[DataField]
|
||||
public DamageSpecifier Damage = new()
|
||||
{
|
||||
DamageDict = new Dictionary<string, FixedPoint2>()
|
||||
{
|
||||
{"Asphyxiation", 10}
|
||||
}
|
||||
};
|
||||
|
||||
[DataField]
|
||||
public float StaminaDamage = 7f;
|
||||
}
|
||||
82
Content.Server/_CP14/MapDamage/CP14MapDamageSystem.cs
Normal file
82
Content.Server/_CP14/MapDamage/CP14MapDamageSystem.cs
Normal file
@@ -0,0 +1,82 @@
|
||||
using Content.Shared.Damage;
|
||||
using Content.Shared.Damage.Systems;
|
||||
using Content.Shared.Mobs.Components;
|
||||
using Content.Shared.Mobs.Systems;
|
||||
using Robust.Shared.Timing;
|
||||
|
||||
namespace Content.Server._CP14.MapDamage;
|
||||
|
||||
public sealed partial class CP14MapDamageSystem : EntitySystem
|
||||
{
|
||||
[Dependency] private readonly SharedTransformSystem _transform = default!;
|
||||
[Dependency] private readonly IGameTiming _timing = default!;
|
||||
[Dependency] private readonly DamageableSystem _damageable = default!;
|
||||
[Dependency] private readonly StaminaSystem _stamina = default!;
|
||||
[Dependency] private readonly MobStateSystem _mobState = default!;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
|
||||
SubscribeLocalEvent<CP14DamageableByMapComponent, EntParentChangedMessage>(OnParentChanged);
|
||||
}
|
||||
|
||||
public override void Update(float frameTime)
|
||||
{
|
||||
base.Update(frameTime);
|
||||
|
||||
var query = EntityQueryEnumerator<CP14DamageableByMapComponent, DamageableComponent, MobStateComponent>();
|
||||
while (query.MoveNext(out var uid, out var damage, out var damageable, out var mobState))
|
||||
{
|
||||
if (!damage.Enabled)
|
||||
continue;
|
||||
|
||||
if (damage.NextDamageTime > _timing.CurTime)
|
||||
continue;
|
||||
|
||||
damage.NextDamageTime = _timing.CurTime + TimeSpan.FromSeconds(2f);
|
||||
|
||||
if (damage.CurrentMap is null)
|
||||
continue;
|
||||
|
||||
if (!_mobState.IsAlive(uid, mobState))
|
||||
continue;
|
||||
|
||||
_damageable.TryChangeDamage(uid, damage.CurrentMap.Value.Comp.Damage, damageable: damageable);
|
||||
_stamina.TakeStaminaDamage(uid, damage.CurrentMap.Value.Comp.StaminaDamage);
|
||||
}
|
||||
}
|
||||
|
||||
private void OnParentChanged(Entity<CP14DamageableByMapComponent> ent, ref EntParentChangedMessage args)
|
||||
{
|
||||
DisableDamage(ent);
|
||||
if (args.OldParent == null || TerminatingOrDeleted(ent))
|
||||
return;
|
||||
|
||||
var newParent = _transform.GetParentUid(ent);
|
||||
if (!TryComp<CP14MapDamageComponent>(newParent, out var mapDamage))
|
||||
return;
|
||||
|
||||
EnableDamage(ent, (newParent, mapDamage));
|
||||
}
|
||||
|
||||
private void DisableDamage(Entity<CP14DamageableByMapComponent> ent)
|
||||
{
|
||||
if (!ent.Comp.Enabled)
|
||||
return;
|
||||
|
||||
ent.Comp.Enabled = false;
|
||||
ent.Comp.CurrentMap = null;
|
||||
Dirty(ent);
|
||||
}
|
||||
|
||||
private void EnableDamage(Entity<CP14DamageableByMapComponent> ent, Entity<CP14MapDamageComponent> map)
|
||||
{
|
||||
if (ent.Comp.Enabled)
|
||||
return;
|
||||
|
||||
ent.Comp.Enabled = true;
|
||||
ent.Comp.CurrentMap = map;
|
||||
Dirty(ent);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
using Content.Shared._CP14.ModularCraft;
|
||||
using Content.Shared._CP14.ModularCraft.Components;
|
||||
using Content.Shared._CP14.MagicSpellStorage;
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
namespace Content.Server._CP14.ModularCraft.Modifiers;
|
||||
|
||||
public sealed partial class AddSpellsToSpellStorage : CP14ModularCraftModifier
|
||||
{
|
||||
[DataField]
|
||||
public List<EntProtoId> Spells;
|
||||
|
||||
public override void Effect(EntityManager entManager, Entity<CP14ModularCraftStartPointComponent> start, Entity<CP14ModularCraftPartComponent>? part)
|
||||
{
|
||||
if (!entManager.TryGetComponent<CP14SpellStorageComponent>(start, out var storageComp))
|
||||
return;
|
||||
|
||||
var spellStorageSystem = entManager.System<CP14SpellStorageSystem>();
|
||||
|
||||
foreach (var spell in Spells)
|
||||
{
|
||||
spellStorageSystem.TryAddSpellToStorage((start.Owner, storageComp), spell);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
using Content.Shared._CP14.ModularCraft;
|
||||
using Content.Shared._CP14.ModularCraft.Components;
|
||||
using Content.Shared._CP14.MagicManacostModify;
|
||||
using Content.Shared._CP14.MagicRitual.Prototypes;
|
||||
using Content.Shared.FixedPoint;
|
||||
using Content.Shared._CP14.MagicSpellStorage;
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
namespace Content.Server._CP14.ModularCraft.Modifiers;
|
||||
|
||||
public sealed partial class EditManacostModify : CP14ModularCraftModifier
|
||||
{
|
||||
[DataField]
|
||||
public Dictionary<ProtoId<CP14MagicTypePrototype>, FixedPoint2> Modifiers = new();
|
||||
public override void Effect(EntityManager entManager, Entity<CP14ModularCraftStartPointComponent> start, Entity<CP14ModularCraftPartComponent>? part)
|
||||
{
|
||||
if (!entManager.TryGetComponent<CP14MagicManacostModifyComponent>(start, out var manacostModifyComp))
|
||||
return;
|
||||
|
||||
foreach (var (magicType, modifier) in Modifiers)
|
||||
{
|
||||
if (manacostModifyComp.Modifiers.ContainsKey(magicType))
|
||||
{
|
||||
if (modifier >= 1f)
|
||||
manacostModifyComp.Modifiers[magicType] += modifier - 1f;
|
||||
else
|
||||
manacostModifyComp.Modifiers[magicType] -= 1f - modifier;
|
||||
}
|
||||
else
|
||||
{
|
||||
manacostModifyComp.Modifiers[magicType] = modifier;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -15,12 +15,22 @@ public sealed partial class CP14StationZLevelsSystem
|
||||
|
||||
private void OnZLevelDown(Entity<GhostComponent> ent, ref CP14ZLevelActionDown args)
|
||||
{
|
||||
if (args.Handled)
|
||||
return;
|
||||
|
||||
ZLevelMove(ent, -1);
|
||||
|
||||
args.Handled = true;
|
||||
}
|
||||
|
||||
private void OnZLevelUp(Entity<GhostComponent> ent, ref CP14ZLevelActionUp args)
|
||||
{
|
||||
if (args.Handled)
|
||||
return;
|
||||
|
||||
ZLevelMove(ent, 1);
|
||||
|
||||
args.Handled = true;
|
||||
}
|
||||
|
||||
private void ZLevelMove(EntityUid ent, int offset)
|
||||
|
||||
@@ -44,6 +44,7 @@ public sealed partial class CP14StationZLevelsSystem
|
||||
|
||||
var otherSidePortal = Spawn(autoPortal.Comp.OtherSideProto, targetMapPos);
|
||||
|
||||
_transform.SetWorldRotation(otherSidePortal, _transform.GetWorldRotation(autoPortal));
|
||||
if (_linkedEntity.TryLink(autoPortal, otherSidePortal, true))
|
||||
RemComp<CP14ZLevelAutoPortalComponent>(autoPortal);
|
||||
}
|
||||
|
||||
@@ -115,10 +115,14 @@ public enum LogType
|
||||
/// Storage & entity-storage related interactions
|
||||
/// </summary>
|
||||
Storage = 93,
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// A player got hit by an explosion and was dealt damage.
|
||||
/// </summary>
|
||||
ExplosionHit = 94,
|
||||
|
||||
/// <summary>
|
||||
/// A ghost warped to an entity through the ghost warp menu.
|
||||
/// </summary>
|
||||
GhostWarp = 95,
|
||||
}
|
||||
|
||||
@@ -34,6 +34,7 @@ public abstract class SharedAnomalySystem : EntitySystem
|
||||
[Dependency] protected readonly SharedPopupSystem Popup = default!;
|
||||
[Dependency] private readonly IPrototypeManager _prototype = default!;
|
||||
[Dependency] private readonly SharedTransformSystem _transform = default!;
|
||||
[Dependency] private readonly SharedMapSystem _map = default!;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
@@ -358,8 +359,11 @@ public abstract class SharedAnomalySystem : EntitySystem
|
||||
var amount = (int) (MathHelper.Lerp(settings.MinAmount, settings.MaxAmount, severity * stability * powerModifier) + 0.5f);
|
||||
|
||||
var localpos = xform.Coordinates.Position;
|
||||
var tilerefs = grid.GetLocalTilesIntersecting(
|
||||
new Box2(localpos + new Vector2(-settings.MaxRange, -settings.MaxRange), localpos + new Vector2(settings.MaxRange, settings.MaxRange))).ToList();
|
||||
var tilerefs = _map.GetLocalTilesIntersecting(
|
||||
xform.GridUid.Value,
|
||||
grid,
|
||||
new Box2(localpos + new Vector2(-settings.MaxRange, -settings.MaxRange), localpos + new Vector2(settings.MaxRange, settings.MaxRange)))
|
||||
.ToList();
|
||||
|
||||
if (tilerefs.Count == 0)
|
||||
return null;
|
||||
|
||||
@@ -115,10 +115,9 @@ public abstract partial class SharedBuckleSystem
|
||||
return;
|
||||
|
||||
if (ent.Comp.BuckledTo != null)
|
||||
TryUnbuckle(ent!, args.User, popup: true);
|
||||
args.Handled = TryUnbuckle(ent!, args.User, popup: true);
|
||||
|
||||
// TODO BUCKLE add out bool for whether a pop-up was generated or not.
|
||||
args.Handled = true;
|
||||
}
|
||||
|
||||
private void AddStrapVerbs(EntityUid uid, StrapComponent component, GetVerbsEvent<InteractionVerb> args)
|
||||
|
||||
@@ -4,6 +4,12 @@ namespace Content.Shared.CCVar;
|
||||
|
||||
public sealed partial class CCVars
|
||||
{
|
||||
/// <summary>
|
||||
/// Delay for auto-orientation. Used for people arriving via arrivals.
|
||||
/// </summary>
|
||||
public static readonly CVarDef<double> AutoOrientDelay =
|
||||
CVarDef.Create("shuttle.auto_orient_delay", 2.0, CVar.SERVER | CVar.REPLICATED);
|
||||
|
||||
/// <summary>
|
||||
/// If true then the camera will match the grid / map and is unchangeable.
|
||||
/// - When traversing grids it will snap to 0 degrees rotation.
|
||||
|
||||
@@ -32,7 +32,7 @@ public sealed class SelfBeforeHyposprayInjectsEvent : BeforeHyposprayInjectsTarg
|
||||
/// This event is raised on the target before the hypospray is injected.
|
||||
/// The event is triggered on the target itself and all its clothing.
|
||||
/// </summary>
|
||||
public sealed class TargetBeforeHyposprayInjectsEvent : BeforeHyposprayInjectsTargetEvent
|
||||
public sealed class TargetBeforeHyposprayInjectsEvent : BeforeHyposprayInjectsTargetEvent
|
||||
{
|
||||
public TargetBeforeHyposprayInjectsEvent (EntityUid user, EntityUid hypospray, EntityUid target) : base(user, hypospray, target) { }
|
||||
public TargetBeforeHyposprayInjectsEvent(EntityUid user, EntityUid hypospray, EntityUid target) : base(user, hypospray, target) { }
|
||||
}
|
||||
|
||||
@@ -151,6 +151,10 @@ public sealed partial class ClimbSystem : VirtualController
|
||||
if (args.Handled)
|
||||
return;
|
||||
|
||||
// If already climbing then don't show outlines.
|
||||
if (TryComp(args.Dragged, out ClimbingComponent? climbing) && climbing.IsClimbing)
|
||||
return;
|
||||
|
||||
var canVault = args.User == args.Dragged
|
||||
? CanVault(component, args.User, uid, out _)
|
||||
: CanVault(component, args.User, args.Dragged, uid, out _);
|
||||
|
||||
@@ -58,4 +58,46 @@ public sealed partial class ClumsyComponent : Component
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public SoundSpecifier GunShootFailSound = new SoundPathSpecifier("/Audio/Weapons/Guns/Gunshots/bang.ogg");
|
||||
|
||||
/// <summary>
|
||||
/// Whether or not to apply Clumsy to hyposprays.
|
||||
/// </summary>
|
||||
[DataField, AutoNetworkedField]
|
||||
public bool ClumsyHypo = true;
|
||||
|
||||
/// <summary>
|
||||
/// Whether or not to apply Clumsy to defibs.
|
||||
/// </summary>
|
||||
[DataField, AutoNetworkedField]
|
||||
public bool ClumsyDefib = true;
|
||||
|
||||
/// <summary>
|
||||
/// Whether or not to apply Clumsy to guns.
|
||||
/// </summary>
|
||||
[DataField, AutoNetworkedField]
|
||||
public bool ClumsyGuns = true;
|
||||
|
||||
/// <summary>
|
||||
/// Whether or not to apply Clumsy to vaulting.
|
||||
/// </summary>
|
||||
[DataField, AutoNetworkedField]
|
||||
public bool ClumsyVaulting = true;
|
||||
|
||||
/// <summary>
|
||||
/// Lets you define a new "failed" message for each event.
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public LocId HypoFailedMessage = "hypospray-component-inject-self-clumsy-message";
|
||||
|
||||
[DataField]
|
||||
public LocId GunFailedMessage = "gun-clumsy";
|
||||
|
||||
[DataField]
|
||||
public LocId VaulingFailedMessageSelf = "bonkable-success-message-user";
|
||||
|
||||
[DataField]
|
||||
public LocId VaulingFailedMessageOthers = "bonkable-success-message-others";
|
||||
|
||||
[DataField]
|
||||
public LocId VaulingFailedMessageForced = "forced-bonkable-success-message";
|
||||
}
|
||||
|
||||
@@ -38,6 +38,11 @@ public sealed class ClumsySystem : EntitySystem
|
||||
private void BeforeHyposprayEvent(Entity<ClumsyComponent> ent, ref SelfBeforeHyposprayInjectsEvent args)
|
||||
{
|
||||
// Clumsy people sometimes inject themselves! Apparently syringes are clumsy proof...
|
||||
|
||||
// checks if ClumsyHypo is false, if so, skips.
|
||||
if (!ent.Comp.ClumsyHypo)
|
||||
return;
|
||||
|
||||
if (!_random.Prob(ent.Comp.ClumsyDefaultCheck))
|
||||
return;
|
||||
|
||||
@@ -49,6 +54,11 @@ public sealed class ClumsySystem : EntitySystem
|
||||
private void BeforeDefibrillatorZapsEvent(Entity<ClumsyComponent> ent, ref SelfBeforeDefibrillatorZapsEvent args)
|
||||
{
|
||||
// Clumsy people sometimes defib themselves!
|
||||
|
||||
// checks if ClumsyDefib is false, if so, skips.
|
||||
if (!ent.Comp.ClumsyDefib)
|
||||
return;
|
||||
|
||||
if (!_random.Prob(ent.Comp.ClumsyDefaultCheck))
|
||||
return;
|
||||
|
||||
@@ -61,6 +71,10 @@ public sealed class ClumsySystem : EntitySystem
|
||||
{
|
||||
// Clumsy people sometimes can't shoot :(
|
||||
|
||||
// checks if ClumsyGuns is false, if so, skips.
|
||||
if (!ent.Comp.ClumsyGuns)
|
||||
return;
|
||||
|
||||
if (args.Gun.Comp.ClumsyProof)
|
||||
return;
|
||||
|
||||
@@ -82,6 +96,10 @@ public sealed class ClumsySystem : EntitySystem
|
||||
|
||||
private void OnBeforeClimbEvent(Entity<ClumsyComponent> ent, ref SelfBeforeClimbEvent args)
|
||||
{
|
||||
// checks if ClumsyVaulting is false, if so, skips.
|
||||
if (!ent.Comp.ClumsyVaulting)
|
||||
return;
|
||||
|
||||
// This event is called in shared, thats why it has all the extra prediction stuff.
|
||||
var rand = new System.Random((int)_timing.CurTick.Value);
|
||||
|
||||
@@ -102,8 +120,8 @@ public sealed class ClumsySystem : EntitySystem
|
||||
{
|
||||
// You are slamming yourself onto the table.
|
||||
_popup.PopupPredicted(
|
||||
Loc.GetString("bonkable-success-message-user", ("bonkable", args.BeingClimbedOn)),
|
||||
Loc.GetString("bonkable-success-message-others", ("victim", gettingPutOnTableName), ("bonkable", args.BeingClimbedOn)),
|
||||
Loc.GetString(ent.Comp.VaulingFailedMessageSelf, ("bonkable", args.BeingClimbedOn)),
|
||||
Loc.GetString(ent.Comp.VaulingFailedMessageOthers, ("victim", gettingPutOnTableName), ("bonkable", args.BeingClimbedOn)),
|
||||
ent,
|
||||
ent);
|
||||
}
|
||||
@@ -112,7 +130,7 @@ public sealed class ClumsySystem : EntitySystem
|
||||
// Someone else slamed you onto the table.
|
||||
// This is only run in server so you need to use popup entity.
|
||||
_popup.PopupPredicted(
|
||||
Loc.GetString("forced-bonkable-success-message",
|
||||
Loc.GetString(ent.Comp.VaulingFailedMessageForced,
|
||||
("bonker", puttingOnTableName),
|
||||
("victim", gettingPutOnTableName),
|
||||
("bonkable", args.BeingClimbedOn)),
|
||||
|
||||
@@ -461,6 +461,12 @@ namespace Content.Shared.Cuffs
|
||||
if (!_interaction.InRangeUnobstructed(handcuff, target))
|
||||
return false;
|
||||
|
||||
// if the amount of hands the target has is equal to or less than the amount of hands that are cuffed
|
||||
// don't apply the new set of cuffs
|
||||
// (how would you even end up with more cuffed hands than actual hands? either way accounting for it)
|
||||
if (TryComp<HandsComponent>(target, out var hands) && hands.Count <= component.CuffedHandCount)
|
||||
return false;
|
||||
|
||||
// Success!
|
||||
_hands.TryDrop(user, handcuff);
|
||||
|
||||
|
||||
@@ -23,7 +23,10 @@ public enum LogicGate : byte
|
||||
[Serializable, NetSerializable]
|
||||
public enum LogicGateVisuals : byte
|
||||
{
|
||||
Gate
|
||||
Gate,
|
||||
InputA,
|
||||
InputB,
|
||||
Output
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -32,5 +35,8 @@ public enum LogicGateVisuals : byte
|
||||
[Serializable, NetSerializable]
|
||||
public enum LogicGateLayers : byte
|
||||
{
|
||||
Gate
|
||||
Gate,
|
||||
InputA,
|
||||
InputB,
|
||||
Output
|
||||
}
|
||||
|
||||
@@ -66,7 +66,7 @@ public sealed partial class DoorComponent : Component
|
||||
/// <summary>
|
||||
/// When the door is active, this is the time when the state will next update.
|
||||
/// </summary>
|
||||
[AutoNetworkedField]
|
||||
[AutoNetworkedField, ViewVariables]
|
||||
public TimeSpan? NextStateChange;
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -15,6 +15,19 @@ namespace Content.Shared.Doors
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Raised when the door's bolt status was changed.
|
||||
/// </summary>
|
||||
public sealed class DoorBoltsChangedEvent : EntityEventArgs
|
||||
{
|
||||
public readonly bool BoltsDown;
|
||||
|
||||
public DoorBoltsChangedEvent(bool boltsDown)
|
||||
{
|
||||
BoltsDown = boltsDown;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Raised when the door is determining whether it is able to open.
|
||||
/// Cancel to stop the door from being opened.
|
||||
|
||||
@@ -22,6 +22,7 @@ public abstract class SharedAirlockSystem : EntitySystem
|
||||
|
||||
SubscribeLocalEvent<AirlockComponent, BeforeDoorClosedEvent>(OnBeforeDoorClosed);
|
||||
SubscribeLocalEvent<AirlockComponent, DoorStateChangedEvent>(OnStateChanged);
|
||||
SubscribeLocalEvent<AirlockComponent, DoorBoltsChangedEvent>(OnBoltsChanged);
|
||||
SubscribeLocalEvent<AirlockComponent, BeforeDoorOpenedEvent>(OnBeforeDoorOpened);
|
||||
SubscribeLocalEvent<AirlockComponent, BeforeDoorDeniedEvent>(OnBeforeDoorDenied);
|
||||
SubscribeLocalEvent<AirlockComponent, GetPryTimeModifierEvent>(OnGetPryMod);
|
||||
@@ -70,6 +71,13 @@ public abstract class SharedAirlockSystem : EntitySystem
|
||||
}
|
||||
}
|
||||
|
||||
private void OnBoltsChanged(EntityUid uid, AirlockComponent component, DoorBoltsChangedEvent args)
|
||||
{
|
||||
// If unbolted, reset the auto close timer
|
||||
if (!args.BoltsDown)
|
||||
UpdateAutoClose(uid, component);
|
||||
}
|
||||
|
||||
private void OnBeforeDoorOpened(EntityUid uid, AirlockComponent component, BeforeDoorOpenedEvent args)
|
||||
{
|
||||
if (!CanChangeState(uid, component))
|
||||
@@ -145,7 +153,7 @@ public abstract class SharedAirlockSystem : EntitySystem
|
||||
ent.Comp.EmergencyAccess = value;
|
||||
Dirty(ent, ent.Comp); // This only runs on the server apparently so we need this.
|
||||
UpdateEmergencyLightStatus(ent, ent.Comp);
|
||||
|
||||
|
||||
var sound = ent.Comp.EmergencyAccess ? ent.Comp.EmergencyOnSound : ent.Comp.EmergencyOffSound;
|
||||
if (predicted)
|
||||
Audio.PlayPredicted(sound, ent, user: user);
|
||||
|
||||
@@ -96,6 +96,10 @@ public abstract partial class SharedDoorSystem
|
||||
Dirty(ent, ent.Comp);
|
||||
UpdateBoltLightStatus(ent);
|
||||
|
||||
// used to reset the auto-close timer after unbolting
|
||||
var ev = new DoorBoltsChangedEvent(value);
|
||||
RaiseLocalEvent(ent.Owner, ev);
|
||||
|
||||
var sound = value ? ent.Comp.BoltDownSound : ent.Comp.BoltUpSound;
|
||||
if (predicted)
|
||||
Audio.PlayPredicted(sound, ent, user: user);
|
||||
|
||||
@@ -396,6 +396,25 @@ public abstract partial class SharedDoorSystem : EntitySystem
|
||||
Dirty(uid, door);
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Opens and then bolts a door.
|
||||
/// Different from emagging this does not remove the access reader, so it can be repaired by simply unbolting the door.
|
||||
/// </summary>
|
||||
public bool TryOpenAndBolt(EntityUid uid, DoorComponent? door = null, AirlockComponent? airlock = null)
|
||||
{
|
||||
if (!Resolve(uid, ref door, ref airlock))
|
||||
return false;
|
||||
|
||||
if (IsBolted(uid) || !airlock.Powered || door.State != DoorState.Closed)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
SetState(uid, DoorState.Emagging, door);
|
||||
|
||||
return true;
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Closing
|
||||
@@ -461,17 +480,17 @@ public abstract partial class SharedDoorSystem : EntitySystem
|
||||
if (!Resolve(uid, ref door, ref physics))
|
||||
return false;
|
||||
|
||||
door.Partial = true;
|
||||
|
||||
// Make sure no entity walked into the airlock when it started closing.
|
||||
if (!CanClose(uid, door))
|
||||
{
|
||||
door.NextStateChange = GameTiming.CurTime + door.OpenTimeTwo;
|
||||
door.State = DoorState.Opening;
|
||||
AppearanceSystem.SetData(uid, DoorVisuals.State, DoorState.Opening);
|
||||
door.State = DoorState.Open;
|
||||
AppearanceSystem.SetData(uid, DoorVisuals.State, DoorState.Open);
|
||||
Dirty(uid, door);
|
||||
return false;
|
||||
}
|
||||
|
||||
door.Partial = true;
|
||||
SetCollidable(uid, true, door, physics);
|
||||
door.NextStateChange = GameTiming.CurTime + door.CloseTimeTwo;
|
||||
Dirty(uid, door);
|
||||
@@ -700,6 +719,8 @@ public abstract partial class SharedDoorSystem : EntitySystem
|
||||
}
|
||||
|
||||
door.NextStateChange = GameTiming.CurTime + delay.Value;
|
||||
Dirty(uid, door);
|
||||
|
||||
_activeDoors.Add((uid, door));
|
||||
}
|
||||
|
||||
|
||||
@@ -74,33 +74,38 @@ namespace Content.Shared.DrawDepth
|
||||
/// </summary>
|
||||
Items = DrawDepthTag.Default + 3,
|
||||
|
||||
Mobs = DrawDepthTag.Default + 4,
|
||||
|
||||
OverMobs = DrawDepthTag.Default + 5,
|
||||
/// <summary>
|
||||
/// Stuff that should be drawn below mobs, but on top of items. Like muzzle flash.
|
||||
/// </summary>
|
||||
BelowMobs = DrawDepthTag.Default + 4,
|
||||
|
||||
Doors = DrawDepthTag.Default + 6,
|
||||
Mobs = DrawDepthTag.Default + 5,
|
||||
|
||||
OverMobs = DrawDepthTag.Default + 6,
|
||||
|
||||
Doors = DrawDepthTag.Default + 7,
|
||||
|
||||
/// <summary>
|
||||
/// Blast doors and shutters which go over the usual doors.
|
||||
/// </summary>
|
||||
BlastDoors = DrawDepthTag.Default + 7,
|
||||
BlastDoors = DrawDepthTag.Default + 8,
|
||||
|
||||
/// <summary>
|
||||
/// Stuff that needs to draw over most things, but not effects, like Kudzu.
|
||||
/// </summary>
|
||||
Overdoors = DrawDepthTag.Default + 8,
|
||||
Overdoors = DrawDepthTag.Default + 9,
|
||||
|
||||
/// <summary>
|
||||
/// Explosions, fire, melee swings. Whatever.
|
||||
/// </summary>
|
||||
Effects = DrawDepthTag.Default + 9,
|
||||
Effects = DrawDepthTag.Default + 10,
|
||||
|
||||
Ghosts = DrawDepthTag.Default + 10,
|
||||
Ghosts = DrawDepthTag.Default + 11,
|
||||
|
||||
/// <summary>
|
||||
/// Use this selectively if it absolutely needs to be drawn above (almost) everything else. Examples include
|
||||
/// the pointing arrow, the drag & drop ghost-entity, and some debug tools.
|
||||
/// </summary>
|
||||
Overlays = DrawDepthTag.Default + 11,
|
||||
Overlays = DrawDepthTag.Default + 12,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
namespace Content.Shared.Electrocution;
|
||||
|
||||
/// <summary>
|
||||
/// Handles toggling sprite layers for the electrocution HUD to show if an entity with the ElectrifiedComponent is electrified.
|
||||
/// </summary>
|
||||
[RegisterComponent]
|
||||
public sealed partial class ElectrocutionHUDVisualsComponent : Component;
|
||||
@@ -0,0 +1,9 @@
|
||||
using Robust.Shared.GameStates;
|
||||
|
||||
namespace Content.Shared.Electrocution;
|
||||
|
||||
/// <summary>
|
||||
/// Allow an entity to see the Electrocution HUD showing electrocuted doors.
|
||||
/// </summary>
|
||||
[RegisterComponent, NetworkedComponent]
|
||||
public sealed partial class ShowElectrocutionHUDComponent : Component;
|
||||
@@ -5,11 +5,13 @@ namespace Content.Shared.Electrocution;
|
||||
[Serializable, NetSerializable]
|
||||
public enum ElectrifiedLayers : byte
|
||||
{
|
||||
Powered
|
||||
Sparks,
|
||||
HUD,
|
||||
}
|
||||
|
||||
[Serializable, NetSerializable]
|
||||
public enum ElectrifiedVisuals : byte
|
||||
{
|
||||
IsPowered
|
||||
ShowSparks, // only shown when zapping someone, deactivated after a short time
|
||||
IsElectrified, // if the entity is electrified or not, used for the AI HUD
|
||||
}
|
||||
|
||||
@@ -5,6 +5,8 @@ namespace Content.Shared.Electrocution
|
||||
{
|
||||
public abstract class SharedElectrocutionSystem : EntitySystem
|
||||
{
|
||||
[Dependency] private readonly SharedAppearanceSystem _appearance = default!;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
@@ -35,6 +37,19 @@ namespace Content.Shared.Electrocution
|
||||
|
||||
ent.Comp.Enabled = value;
|
||||
Dirty(ent, ent.Comp);
|
||||
|
||||
_appearance.SetData(ent.Owner, ElectrifiedVisuals.IsElectrified, value);
|
||||
}
|
||||
|
||||
public void SetElectrifiedWireCut(Entity<ElectrifiedComponent> ent, bool value)
|
||||
{
|
||||
if (ent.Comp.IsWireCut == value)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
ent.Comp.IsWireCut = value;
|
||||
Dirty(ent);
|
||||
}
|
||||
|
||||
/// <param name="uid">Entity being electrocuted.</param>
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user