@@ -1,5 +1,4 @@
|
|||||||
using Content.Client.Atmos.Overlays;
|
using Content.Client.Atmos.Overlays;
|
||||||
using Content.Shared.Atmos;
|
|
||||||
using Content.Shared.Atmos.Components;
|
using Content.Shared.Atmos.Components;
|
||||||
using Content.Shared.Atmos.EntitySystems;
|
using Content.Shared.Atmos.EntitySystems;
|
||||||
using JetBrains.Annotations;
|
using JetBrains.Annotations;
|
||||||
@@ -37,38 +36,28 @@ namespace Content.Client.Atmos.EntitySystems
|
|||||||
|
|
||||||
private void OnHandleState(EntityUid gridUid, GasTileOverlayComponent comp, ref ComponentHandleState args)
|
private void OnHandleState(EntityUid gridUid, GasTileOverlayComponent comp, ref ComponentHandleState args)
|
||||||
{
|
{
|
||||||
Dictionary<Vector2i, GasOverlayChunk> modifiedChunks;
|
if (args.Current is not GasTileOverlayState state)
|
||||||
|
return;
|
||||||
|
|
||||||
switch (args.Current)
|
// is this a delta or full state?
|
||||||
|
if (!state.FullState)
|
||||||
{
|
{
|
||||||
// is this a delta or full state?
|
foreach (var index in comp.Chunks.Keys)
|
||||||
case GasTileOverlayDeltaState delta:
|
|
||||||
{
|
{
|
||||||
modifiedChunks = delta.ModifiedChunks;
|
if (!state.AllChunks!.Contains(index))
|
||||||
foreach (var index in comp.Chunks.Keys)
|
comp.Chunks.Remove(index);
|
||||||
{
|
|
||||||
if (!delta.AllChunks.Contains(index))
|
|
||||||
comp.Chunks.Remove(index);
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
case GasTileOverlayState state:
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
foreach (var index in comp.Chunks.Keys)
|
||||||
{
|
{
|
||||||
modifiedChunks = state.Chunks;
|
if (!state.Chunks.ContainsKey(index))
|
||||||
foreach (var index in comp.Chunks.Keys)
|
comp.Chunks.Remove(index);
|
||||||
{
|
|
||||||
if (!state.Chunks.ContainsKey(index))
|
|
||||||
comp.Chunks.Remove(index);
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
default:
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (var (index, data) in modifiedChunks)
|
foreach (var (index, data) in state.Chunks)
|
||||||
{
|
{
|
||||||
comp.Chunks[index] = data;
|
comp.Chunks[index] = data;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -56,43 +56,34 @@ namespace Content.Client.Decals
|
|||||||
|
|
||||||
private void OnHandleState(EntityUid gridUid, DecalGridComponent gridComp, ref ComponentHandleState args)
|
private void OnHandleState(EntityUid gridUid, DecalGridComponent gridComp, ref ComponentHandleState args)
|
||||||
{
|
{
|
||||||
|
if (args.Current is not DecalGridState state)
|
||||||
|
return;
|
||||||
|
|
||||||
// is this a delta or full state?
|
// is this a delta or full state?
|
||||||
_removedChunks.Clear();
|
_removedChunks.Clear();
|
||||||
Dictionary<Vector2i, DecalChunk> modifiedChunks;
|
|
||||||
|
|
||||||
switch (args.Current)
|
if (!state.FullState)
|
||||||
{
|
{
|
||||||
case DecalGridDeltaState delta:
|
foreach (var key in gridComp.ChunkCollection.ChunkCollection.Keys)
|
||||||
{
|
{
|
||||||
modifiedChunks = delta.ModifiedChunks;
|
if (!state.AllChunks!.Contains(key))
|
||||||
foreach (var key in gridComp.ChunkCollection.ChunkCollection.Keys)
|
_removedChunks.Add(key);
|
||||||
{
|
|
||||||
if (!delta.AllChunks.Contains(key))
|
|
||||||
_removedChunks.Add(key);
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
case DecalGridState state:
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
foreach (var key in gridComp.ChunkCollection.ChunkCollection.Keys)
|
||||||
{
|
{
|
||||||
modifiedChunks = state.Chunks;
|
if (!state.Chunks.ContainsKey(key))
|
||||||
foreach (var key in gridComp.ChunkCollection.ChunkCollection.Keys)
|
_removedChunks.Add(key);
|
||||||
{
|
|
||||||
if (!state.Chunks.ContainsKey(key))
|
|
||||||
_removedChunks.Add(key);
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
default:
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_removedChunks.Count > 0)
|
if (_removedChunks.Count > 0)
|
||||||
RemoveChunks(gridUid, gridComp, _removedChunks);
|
RemoveChunks(gridUid, gridComp, _removedChunks);
|
||||||
|
|
||||||
if (modifiedChunks.Count > 0)
|
if (state.Chunks.Count > 0)
|
||||||
UpdateChunks(gridUid, gridComp, modifiedChunks);
|
UpdateChunks(gridUid, gridComp, state.Chunks);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnChunkUpdate(DecalChunkUpdateEvent ev)
|
private void OnChunkUpdate(DecalChunkUpdateEvent ev)
|
||||||
|
|||||||
@@ -239,10 +239,8 @@ namespace Content.Client.Examine
|
|||||||
|
|
||||||
if (knowTarget)
|
if (knowTarget)
|
||||||
{
|
{
|
||||||
// TODO: FormattedMessage.RemoveMarkupPermissive
|
var itemName = FormattedMessage.RemoveMarkup(Identity.Name(target, EntityManager, player));
|
||||||
// var itemName = FormattedMessage.RemoveMarkupPermissive(Identity.Name(target, EntityManager, player));
|
var labelMessage = FormattedMessage.FromMarkup($"[bold]{itemName}[/bold]");
|
||||||
var itemName = FormattedMessage.FromMarkupPermissive(Identity.Name(target, EntityManager, player)).ToString();
|
|
||||||
var labelMessage = FormattedMessage.FromMarkupPermissive($"[bold]{itemName}[/bold]");
|
|
||||||
var label = new RichTextLabel();
|
var label = new RichTextLabel();
|
||||||
label.SetMessage(labelMessage);
|
label.SetMessage(labelMessage);
|
||||||
hBox.AddChild(label);
|
hBox.AddChild(label);
|
||||||
|
|||||||
@@ -37,8 +37,14 @@ namespace Content.Client.Instruments.UI
|
|||||||
|
|
||||||
protected override void ReceiveMessage(BoundUserInterfaceMessage message)
|
protected override void ReceiveMessage(BoundUserInterfaceMessage message)
|
||||||
{
|
{
|
||||||
if (message is InstrumentBandResponseBuiMessage bandRx)
|
switch (message)
|
||||||
_bandMenu?.Populate(bandRx.Nearby, EntMan);
|
{
|
||||||
|
case InstrumentBandResponseBuiMessage bandRx:
|
||||||
|
_bandMenu?.Populate(bandRx.Nearby, EntMan);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void Open()
|
protected override void Open()
|
||||||
|
|||||||
@@ -4,6 +4,24 @@ using Robust.Shared.Containers;
|
|||||||
|
|
||||||
namespace Content.Client.Interactable
|
namespace Content.Client.Interactable
|
||||||
{
|
{
|
||||||
// TODO Remove Shared prefix
|
public sealed class InteractionSystem : SharedInteractionSystem
|
||||||
public sealed class InteractionSystem : SharedInteractionSystem;
|
{
|
||||||
|
[Dependency] private readonly SharedContainerSystem _container = default!;
|
||||||
|
|
||||||
|
public override bool CanAccessViaStorage(EntityUid user, EntityUid target)
|
||||||
|
{
|
||||||
|
if (!EntityManager.EntityExists(target))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (!_container.TryGetContainingContainer(target, out var container))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (!HasComp<StorageComponent>(container.Owner))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// we don't check if the user can access the storage entity itself. This should be handed by the UI system.
|
||||||
|
// Need to return if UI is open or not
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -73,6 +73,11 @@ public sealed class DragDropHelper<T>
|
|||||||
_cfg.OnValueChanged(CCVars.DragDropDeadZone, SetDeadZone, true);
|
_cfg.OnValueChanged(CCVars.DragDropDeadZone, SetDeadZone, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
~DragDropHelper()
|
||||||
|
{
|
||||||
|
_cfg.UnsubValueChanged(CCVars.DragDropDeadZone, SetDeadZone);
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Tell the helper that the mouse button was pressed down on
|
/// Tell the helper that the mouse button was pressed down on
|
||||||
/// a target, thus a drag has the possibility to begin for this target.
|
/// a target, thus a drag has the possibility to begin for this target.
|
||||||
|
|||||||
@@ -1,11 +1,13 @@
|
|||||||
<DefaultWindow xmlns="https://spacestation14.io"
|
<DefaultWindow xmlns="https://spacestation14.io"
|
||||||
xmlns:tabs="clr-namespace:Content.Client.Options.UI.Tabs"
|
xmlns:tabs="clr-namespace:Content.Client.Options.UI.Tabs"
|
||||||
Title="{Loc 'ui-options-title'}"
|
Title="{Loc 'ui-options-title'}"
|
||||||
MinSize="800 450">
|
MinSize="980 580">
|
||||||
<TabContainer Name="Tabs" Access="Public">
|
<TabContainer Name="Tabs" Access="Public">
|
||||||
<tabs:MiscTab Name="MiscTab" />
|
<tabs:MiscTab Name="MiscTab" />
|
||||||
<tabs:GraphicsTab Name="GraphicsTab" />
|
<tabs:GraphicsTab Name="GraphicsTab" />
|
||||||
<tabs:KeyRebindTab Name="KeyRebindTab" />
|
<tabs:KeyRebindTab Name="KeyRebindTab" />
|
||||||
<tabs:AudioTab Name="AudioTab" />
|
<tabs:AudioTab Name="AudioTab" />
|
||||||
|
<tabs:NetworkTab Name="NetworkTab" />
|
||||||
|
<tabs:AdminSettingsTab Name="AdminSettingsTab"/>
|
||||||
</TabContainer>
|
</TabContainer>
|
||||||
</DefaultWindow>
|
</DefaultWindow>
|
||||||
|
|||||||
@@ -1,15 +1,17 @@
|
|||||||
|
using Content.Client.Administration.Managers;
|
||||||
using Robust.Client.AutoGenerated;
|
using Robust.Client.AutoGenerated;
|
||||||
using Robust.Client.UserInterface.CustomControls;
|
using Robust.Client.UserInterface.CustomControls;
|
||||||
using Robust.Client.UserInterface.XAML;
|
using Robust.Client.UserInterface.XAML;
|
||||||
using Robust.Shared.IoC;
|
|
||||||
using Content.Client.Options.UI.Tabs;
|
using Content.Client.Options.UI.Tabs;
|
||||||
|
using Robust.Shared.Timing;
|
||||||
|
|
||||||
namespace Content.Client.Options.UI
|
namespace Content.Client.Options.UI
|
||||||
{
|
{
|
||||||
[GenerateTypedNameReferences]
|
[GenerateTypedNameReferences]
|
||||||
public sealed partial class OptionsMenu : DefaultWindow
|
public sealed partial class OptionsMenu : DefaultWindow
|
||||||
{
|
{
|
||||||
|
[Dependency] private readonly IClientAdminManager _clientAdminManager = default!;
|
||||||
|
|
||||||
public OptionsMenu()
|
public OptionsMenu()
|
||||||
{
|
{
|
||||||
RobustXamlLoader.Load(this);
|
RobustXamlLoader.Load(this);
|
||||||
@@ -19,6 +21,8 @@ namespace Content.Client.Options.UI
|
|||||||
Tabs.SetTabTitle(1, Loc.GetString("ui-options-tab-graphics"));
|
Tabs.SetTabTitle(1, Loc.GetString("ui-options-tab-graphics"));
|
||||||
Tabs.SetTabTitle(2, Loc.GetString("ui-options-tab-controls"));
|
Tabs.SetTabTitle(2, Loc.GetString("ui-options-tab-controls"));
|
||||||
Tabs.SetTabTitle(3, Loc.GetString("ui-options-tab-audio"));
|
Tabs.SetTabTitle(3, Loc.GetString("ui-options-tab-audio"));
|
||||||
|
Tabs.SetTabTitle(4, Loc.GetString("ui-options-tab-network"));
|
||||||
|
Tabs.SetTabTitle(5, "Админ");
|
||||||
|
|
||||||
UpdateTabs();
|
UpdateTabs();
|
||||||
}
|
}
|
||||||
@@ -27,5 +31,11 @@ namespace Content.Client.Options.UI
|
|||||||
{
|
{
|
||||||
GraphicsTab.UpdateProperties();
|
GraphicsTab.UpdateProperties();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected override void FrameUpdate(FrameEventArgs args)
|
||||||
|
{
|
||||||
|
Tabs.SetTabVisible(5, _clientAdminManager.IsActive());
|
||||||
|
base.FrameUpdate(args);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
103
Content.Client/Options/UI/Tabs/NetworkTab.xaml
Normal file
103
Content.Client/Options/UI/Tabs/NetworkTab.xaml
Normal file
@@ -0,0 +1,103 @@
|
|||||||
|
<Control xmlns="https://spacestation14.io"
|
||||||
|
xmlns:controls="clr-namespace:Content.Client.UserInterface.Controls"
|
||||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
|
x:Class="Content.Client.Options.UI.Tabs.NetworkTab">
|
||||||
|
<BoxContainer Orientation="Vertical" >
|
||||||
|
<BoxContainer Orientation="Vertical" Margin="8 8 8 8" VerticalExpand="True">
|
||||||
|
<BoxContainer Orientation="Horizontal" Margin="4 10 4 0">
|
||||||
|
<CheckBox Name="NetPredictCheckbox" Text="{Loc 'ui-options-net-predict'}" />
|
||||||
|
</BoxContainer>
|
||||||
|
<BoxContainer Orientation="Horizontal" Margin="4 10 4 0">
|
||||||
|
<Label Text="{Loc 'ui-options-net-interp-ratio'}" />
|
||||||
|
<Control MinSize="8 0" />
|
||||||
|
<Slider Name="NetInterpRatioSlider"
|
||||||
|
ToolTip="{Loc 'ui-options-net-interp-ratio-tooltip'}"
|
||||||
|
MaxValue="8"
|
||||||
|
HorizontalExpand="True"
|
||||||
|
MinSize="80 0"
|
||||||
|
Rounded="True" />
|
||||||
|
<Control MinSize="8 0" />
|
||||||
|
<Label Name="NetInterpRatioLabel" MinSize="48 0" Align="Right" />
|
||||||
|
<Control MinSize="4 0"/>
|
||||||
|
</BoxContainer>
|
||||||
|
<BoxContainer Orientation="Horizontal" Margin="4 10 4 0">
|
||||||
|
<Label Text="{Loc 'ui-options-net-predict-tick-bias'}" />
|
||||||
|
<Control MinSize="8 0" />
|
||||||
|
<Slider Name="NetPredictTickBiasSlider"
|
||||||
|
ToolTip="{Loc 'ui-options-net-predict-tick-bias-tooltip'}"
|
||||||
|
MaxValue="6"
|
||||||
|
MinValue="0"
|
||||||
|
HorizontalExpand="True"
|
||||||
|
MinSize="80 0"
|
||||||
|
Rounded="True" />
|
||||||
|
<Control MinSize="8 0" />
|
||||||
|
<Label Name="NetPredictTickBiasLabel" MinSize="48 0" Align="Right" />
|
||||||
|
<Control MinSize="4 0"/>
|
||||||
|
</BoxContainer>
|
||||||
|
<BoxContainer Orientation="Horizontal" Margin="4 10 4 0">
|
||||||
|
<Label Text="{Loc 'ui-options-net-pvs-spawn'}" />
|
||||||
|
<Control MinSize="8 0" />
|
||||||
|
<Slider Name="NetPvsSpawnSlider"
|
||||||
|
ToolTip="{Loc 'ui-options-net-pvs-spawn-tooltip'}"
|
||||||
|
MaxValue="150"
|
||||||
|
MinValue="20"
|
||||||
|
HorizontalExpand="True"
|
||||||
|
MinSize="80 0"
|
||||||
|
Rounded="True" />
|
||||||
|
<Control MinSize="8 0" />
|
||||||
|
<Label Name="NetPvsSpawnLabel" MinSize="48 0" Align="Right" />
|
||||||
|
<Control MinSize="4 0"/>
|
||||||
|
</BoxContainer>
|
||||||
|
<BoxContainer Orientation="Horizontal" Margin="4 10 4 0">
|
||||||
|
<Label Text="{Loc 'ui-options-net-pvs-entry'}" />
|
||||||
|
<Control MinSize="8 0" />
|
||||||
|
<Slider Name="NetPvsEntrySlider"
|
||||||
|
ToolTip="{Loc 'ui-options-net-pvs-entry-tooltip'}"
|
||||||
|
MaxValue="500"
|
||||||
|
MinValue="20"
|
||||||
|
HorizontalExpand="True"
|
||||||
|
MinSize="80 0"
|
||||||
|
Rounded="True" />
|
||||||
|
<Control MinSize="8 0" />
|
||||||
|
<Label Name="NetPvsEntryLabel" MinSize="48 0" Align="Right" />
|
||||||
|
<Control MinSize="4 0"/>
|
||||||
|
</BoxContainer>
|
||||||
|
<BoxContainer Orientation="Horizontal" Margin="4 10 4 10">
|
||||||
|
<Label Text="{Loc 'ui-options-net-pvs-leave'}" />
|
||||||
|
<Control MinSize="8 0" />
|
||||||
|
<Slider Name="NetPvsLeaveSlider"
|
||||||
|
ToolTip="{Loc 'ui-options-net-pvs-leave-tooltip'}"
|
||||||
|
MaxValue="300"
|
||||||
|
MinValue="20"
|
||||||
|
HorizontalExpand="True"
|
||||||
|
MinSize="80 0"
|
||||||
|
Rounded="True" />
|
||||||
|
<Control MinSize="8 0" />
|
||||||
|
<Label Name="NetPvsLeaveLabel" MinSize="48 0" Align="Right" />
|
||||||
|
<Control MinSize="4 0"/>
|
||||||
|
</BoxContainer>
|
||||||
|
</BoxContainer>
|
||||||
|
<controls:StripeBack HasBottomEdge="False" HasMargins="False">
|
||||||
|
<BoxContainer Orientation="Horizontal"
|
||||||
|
Align="End"
|
||||||
|
HorizontalExpand="True"
|
||||||
|
Margin="8 8"
|
||||||
|
VerticalExpand="True">
|
||||||
|
<Button Name="ResetButton"
|
||||||
|
Text="{Loc 'ui-options-reset-all'}"
|
||||||
|
StyleClasses="Caution"
|
||||||
|
HorizontalExpand="True"
|
||||||
|
HorizontalAlignment="Right" />
|
||||||
|
<Button Name="DefaultButton"
|
||||||
|
Text="{Loc 'ui-options-default'}"
|
||||||
|
TextAlign="Center"
|
||||||
|
HorizontalAlignment="Right" />
|
||||||
|
<Control MinSize="2 0" />
|
||||||
|
<Button Name="ApplyButton"
|
||||||
|
Text="{Loc 'ui-options-apply'}"
|
||||||
|
TextAlign="Center"
|
||||||
|
HorizontalAlignment="Right" />
|
||||||
|
</BoxContainer>
|
||||||
|
</controls:StripeBack>
|
||||||
|
</BoxContainer>
|
||||||
|
</Control>
|
||||||
125
Content.Client/Options/UI/Tabs/NetworkTab.xaml.cs
Normal file
125
Content.Client/Options/UI/Tabs/NetworkTab.xaml.cs
Normal file
@@ -0,0 +1,125 @@
|
|||||||
|
using System.Globalization;
|
||||||
|
using Robust.Client.AutoGenerated;
|
||||||
|
using Robust.Client.UserInterface;
|
||||||
|
using Robust.Client.UserInterface.Controls;
|
||||||
|
using Robust.Client.UserInterface.XAML;
|
||||||
|
using Robust.Shared;
|
||||||
|
using Robust.Shared.Configuration;
|
||||||
|
using Robust.Client.GameStates;
|
||||||
|
using Content.Client.Entry;
|
||||||
|
|
||||||
|
namespace Content.Client.Options.UI.Tabs
|
||||||
|
{
|
||||||
|
[GenerateTypedNameReferences]
|
||||||
|
public sealed partial class NetworkTab : Control
|
||||||
|
{
|
||||||
|
[Dependency] private readonly IConfigurationManager _cfg = default!;
|
||||||
|
[Dependency] private readonly IClientGameStateManager _stateMan = default!;
|
||||||
|
|
||||||
|
public NetworkTab()
|
||||||
|
{
|
||||||
|
|
||||||
|
RobustXamlLoader.Load(this);
|
||||||
|
IoCManager.InjectDependencies(this);
|
||||||
|
|
||||||
|
ApplyButton.OnPressed += OnApplyButtonPressed;
|
||||||
|
ResetButton.OnPressed += OnResetButtonPressed;
|
||||||
|
DefaultButton.OnPressed += OnDefaultButtonPressed;
|
||||||
|
NetPredictCheckbox.OnToggled += OnPredictToggled;
|
||||||
|
NetInterpRatioSlider.OnValueChanged += OnSliderChanged;
|
||||||
|
NetInterpRatioSlider.MinValue = _stateMan.MinBufferSize;
|
||||||
|
NetPredictTickBiasSlider.OnValueChanged += OnSliderChanged;
|
||||||
|
NetPvsSpawnSlider.OnValueChanged += OnSliderChanged;
|
||||||
|
NetPvsEntrySlider.OnValueChanged += OnSliderChanged;
|
||||||
|
NetPvsLeaveSlider.OnValueChanged += OnSliderChanged;
|
||||||
|
|
||||||
|
Reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void Dispose(bool disposing)
|
||||||
|
{
|
||||||
|
ApplyButton.OnPressed -= OnApplyButtonPressed;
|
||||||
|
ResetButton.OnPressed -= OnResetButtonPressed;
|
||||||
|
DefaultButton.OnPressed -= OnDefaultButtonPressed;
|
||||||
|
NetPredictCheckbox.OnToggled -= OnPredictToggled;
|
||||||
|
NetInterpRatioSlider.OnValueChanged -= OnSliderChanged;
|
||||||
|
NetPredictTickBiasSlider.OnValueChanged -= OnSliderChanged;
|
||||||
|
NetPvsSpawnSlider.OnValueChanged -= OnSliderChanged;
|
||||||
|
NetPvsEntrySlider.OnValueChanged -= OnSliderChanged;
|
||||||
|
NetPvsLeaveSlider.OnValueChanged -= OnSliderChanged;
|
||||||
|
base.Dispose(disposing);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnPredictToggled(BaseButton.ButtonToggledEventArgs obj)
|
||||||
|
{
|
||||||
|
UpdateChanges();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnSliderChanged(Robust.Client.UserInterface.Controls.Range range)
|
||||||
|
{
|
||||||
|
UpdateChanges();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnApplyButtonPressed(BaseButton.ButtonEventArgs args)
|
||||||
|
{
|
||||||
|
_cfg.SetCVar(CVars.NetBufferSize, (int) NetInterpRatioSlider.Value - _stateMan.MinBufferSize);
|
||||||
|
_cfg.SetCVar(CVars.NetPredictTickBias, (int) NetPredictTickBiasSlider.Value);
|
||||||
|
_cfg.SetCVar(CVars.NetPVSEntityBudget, (int) NetPvsSpawnSlider.Value);
|
||||||
|
_cfg.SetCVar(CVars.NetPVSEntityEnterBudget, (int) NetPvsEntrySlider.Value);
|
||||||
|
_cfg.SetCVar(CVars.NetPVSEntityExitBudget, (int) NetPvsLeaveSlider.Value);
|
||||||
|
_cfg.SetCVar(CVars.NetPredict, NetPredictCheckbox.Pressed);
|
||||||
|
|
||||||
|
_cfg.SaveToFile();
|
||||||
|
UpdateChanges();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnResetButtonPressed(BaseButton.ButtonEventArgs args)
|
||||||
|
{
|
||||||
|
Reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnDefaultButtonPressed(BaseButton.ButtonEventArgs obj)
|
||||||
|
{
|
||||||
|
NetPredictTickBiasSlider.Value = CVars.NetPredictTickBias.DefaultValue;
|
||||||
|
NetPvsSpawnSlider.Value = CVars.NetPVSEntityBudget.DefaultValue;
|
||||||
|
NetPvsEntrySlider.Value = CVars.NetPVSEntityEnterBudget.DefaultValue;
|
||||||
|
NetPvsLeaveSlider.Value = CVars.NetPVSEntityExitBudget.DefaultValue;
|
||||||
|
NetInterpRatioSlider.Value = CVars.NetBufferSize.DefaultValue + _stateMan.MinBufferSize;
|
||||||
|
|
||||||
|
UpdateChanges();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Reset()
|
||||||
|
{
|
||||||
|
NetInterpRatioSlider.Value = _cfg.GetCVar(CVars.NetBufferSize) + _stateMan.MinBufferSize;
|
||||||
|
NetPredictTickBiasSlider.Value = _cfg.GetCVar(CVars.NetPredictTickBias);
|
||||||
|
NetPvsSpawnSlider.Value = _cfg.GetCVar(CVars.NetPVSEntityBudget);
|
||||||
|
NetPvsEntrySlider.Value = _cfg.GetCVar(CVars.NetPVSEntityEnterBudget);
|
||||||
|
NetPvsLeaveSlider.Value = _cfg.GetCVar(CVars.NetPVSEntityExitBudget);
|
||||||
|
NetPredictCheckbox.Pressed = _cfg.GetCVar(CVars.NetPredict);
|
||||||
|
UpdateChanges();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void UpdateChanges()
|
||||||
|
{
|
||||||
|
var isEverythingSame =
|
||||||
|
NetInterpRatioSlider.Value == _cfg.GetCVar(CVars.NetBufferSize) + _stateMan.MinBufferSize &&
|
||||||
|
NetPredictTickBiasSlider.Value == _cfg.GetCVar(CVars.NetPredictTickBias) &&
|
||||||
|
NetPredictCheckbox.Pressed == _cfg.GetCVar(CVars.NetPredict) &&
|
||||||
|
NetPvsSpawnSlider.Value == _cfg.GetCVar(CVars.NetPVSEntityBudget) &&
|
||||||
|
NetPvsEntrySlider.Value == _cfg.GetCVar(CVars.NetPVSEntityEnterBudget) &&
|
||||||
|
NetPvsLeaveSlider.Value == _cfg.GetCVar(CVars.NetPVSEntityExitBudget);
|
||||||
|
|
||||||
|
ApplyButton.Disabled = isEverythingSame;
|
||||||
|
ResetButton.Disabled = isEverythingSame;
|
||||||
|
NetInterpRatioLabel.Text = NetInterpRatioSlider.Value.ToString(CultureInfo.InvariantCulture);
|
||||||
|
NetPredictTickBiasLabel.Text = NetPredictTickBiasSlider.Value.ToString(CultureInfo.InvariantCulture);
|
||||||
|
NetPvsSpawnLabel.Text = NetPvsSpawnSlider.Value.ToString(CultureInfo.InvariantCulture);
|
||||||
|
NetPvsEntryLabel.Text = NetPvsEntrySlider.Value.ToString(CultureInfo.InvariantCulture);
|
||||||
|
NetPvsLeaveLabel.Text = NetPvsLeaveSlider.Value.ToString(CultureInfo.InvariantCulture);
|
||||||
|
|
||||||
|
// TODO disable / grey-out the predict and interp sliders if prediction is disabled.
|
||||||
|
// Currently no option to do this, but should be added to the slider control in general
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,11 +1,8 @@
|
|||||||
using System.Numerics;
|
|
||||||
using Content.Client.UserInterface.Systems;
|
|
||||||
using Content.Shared.Damage;
|
using Content.Shared.Damage;
|
||||||
using Content.Shared.FixedPoint;
|
using Content.Shared.FixedPoint;
|
||||||
using Content.Shared.Mobs;
|
using Content.Shared.Mobs;
|
||||||
using Content.Shared.Mobs.Components;
|
using Content.Shared.Mobs.Components;
|
||||||
using Content.Shared.Mobs.Systems;
|
using Content.Shared.Mobs.Systems;
|
||||||
using Content.Shared.StatusIcon.Components;
|
|
||||||
using Robust.Client.GameObjects;
|
using Robust.Client.GameObjects;
|
||||||
using Robust.Client.Graphics;
|
using Robust.Client.Graphics;
|
||||||
using Robust.Shared.Enums;
|
using Robust.Shared.Enums;
|
||||||
@@ -88,10 +85,6 @@ public sealed class EntityHealthBarOverlay : Overlay
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// we are all progressing towards death every day
|
|
||||||
if (CalcProgress(uid, mobStateComponent, damageableComponent, mobThresholdsComponent) is not { } deathProgress)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
var worldPosition = _transform.GetWorldPosition(xform);
|
var worldPosition = _transform.GetWorldPosition(xform);
|
||||||
var worldMatrix = Matrix3.CreateTranslation(worldPosition);
|
var worldMatrix = Matrix3.CreateTranslation(worldPosition);
|
||||||
|
|
||||||
@@ -104,6 +97,10 @@ public sealed class EntityHealthBarOverlay : Overlay
|
|||||||
var widthOfMob = bounds.Width * EyeManager.PixelsPerMeter;
|
var widthOfMob = bounds.Width * EyeManager.PixelsPerMeter;
|
||||||
|
|
||||||
var position = new Vector2(-widthOfMob / EyeManager.PixelsPerMeter / 2, yOffset / EyeManager.PixelsPerMeter);
|
var position = new Vector2(-widthOfMob / EyeManager.PixelsPerMeter / 2, yOffset / EyeManager.PixelsPerMeter);
|
||||||
|
|
||||||
|
// we are all progressing towards death every day
|
||||||
|
(float ratio, bool inCrit) deathProgress = CalcProgress(uid, mobStateComponent, damageableComponent, mobThresholdsComponent);
|
||||||
|
|
||||||
var color = GetProgressColor(deathProgress.ratio, deathProgress.inCrit);
|
var color = GetProgressColor(deathProgress.ratio, deathProgress.inCrit);
|
||||||
|
|
||||||
// Hardcoded width of the progress bar because it doesn't match the texture.
|
// Hardcoded width of the progress bar because it doesn't match the texture.
|
||||||
@@ -131,13 +128,10 @@ public sealed class EntityHealthBarOverlay : Overlay
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Returns a ratio between 0 and 1, and whether the entity is in crit.
|
/// Returns a ratio between 0 and 1, and whether the entity is in crit.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private (float ratio, bool inCrit)? CalcProgress(EntityUid uid, MobStateComponent component, DamageableComponent dmg, MobThresholdsComponent thresholds)
|
private (float, bool) CalcProgress(EntityUid uid, MobStateComponent component, DamageableComponent dmg, MobThresholdsComponent thresholds)
|
||||||
{
|
{
|
||||||
if (_mobStateSystem.IsAlive(uid, component))
|
if (_mobStateSystem.IsAlive(uid, component))
|
||||||
{
|
{
|
||||||
if (dmg.HealthBarThreshold != null && dmg.TotalDamage < dmg.HealthBarThreshold)
|
|
||||||
return null;
|
|
||||||
|
|
||||||
if (!_mobThresholdSystem.TryGetThresholdForState(uid, MobState.Critical, out var threshold, thresholds) &&
|
if (!_mobThresholdSystem.TryGetThresholdForState(uid, MobState.Critical, out var threshold, thresholds) &&
|
||||||
!_mobThresholdSystem.TryGetThresholdForState(uid, MobState.Dead, out threshold, thresholds))
|
!_mobThresholdSystem.TryGetThresholdForState(uid, MobState.Dead, out threshold, thresholds))
|
||||||
return (1, false);
|
return (1, false);
|
||||||
|
|||||||
@@ -14,40 +14,27 @@ public sealed partial class NavMapSystem : SharedNavMapSystem
|
|||||||
|
|
||||||
private void OnHandleState(EntityUid uid, NavMapComponent component, ref ComponentHandleState args)
|
private void OnHandleState(EntityUid uid, NavMapComponent component, ref ComponentHandleState args)
|
||||||
{
|
{
|
||||||
Dictionary<Vector2i, int[]> modifiedChunks;
|
if (args.Current is not NavMapComponentState state)
|
||||||
Dictionary<NetEntity, NavMapBeacon> beacons;
|
return;
|
||||||
|
|
||||||
switch (args.Current)
|
if (!state.FullState)
|
||||||
{
|
{
|
||||||
case NavMapDeltaState delta:
|
foreach (var index in component.Chunks.Keys)
|
||||||
{
|
{
|
||||||
modifiedChunks = delta.ModifiedChunks;
|
if (!state.AllChunks!.Contains(index))
|
||||||
beacons = delta.Beacons;
|
component.Chunks.Remove(index);
|
||||||
foreach (var index in component.Chunks.Keys)
|
|
||||||
{
|
|
||||||
if (!delta.AllChunks!.Contains(index))
|
|
||||||
component.Chunks.Remove(index);
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
case NavMapState state:
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
foreach (var index in component.Chunks.Keys)
|
||||||
{
|
{
|
||||||
modifiedChunks = state.Chunks;
|
if (!state.Chunks.ContainsKey(index))
|
||||||
beacons = state.Beacons;
|
component.Chunks.Remove(index);
|
||||||
foreach (var index in component.Chunks.Keys)
|
|
||||||
{
|
|
||||||
if (!state.Chunks.ContainsKey(index))
|
|
||||||
component.Chunks.Remove(index);
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
default:
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (var (origin, chunk) in modifiedChunks)
|
foreach (var (origin, chunk) in state.Chunks)
|
||||||
{
|
{
|
||||||
var newChunk = new NavMapChunk(origin);
|
var newChunk = new NavMapChunk(origin);
|
||||||
Array.Copy(chunk, newChunk.TileData, chunk.Length);
|
Array.Copy(chunk, newChunk.TileData, chunk.Length);
|
||||||
@@ -55,7 +42,7 @@ public sealed partial class NavMapSystem : SharedNavMapSystem
|
|||||||
}
|
}
|
||||||
|
|
||||||
component.Beacons.Clear();
|
component.Beacons.Clear();
|
||||||
foreach (var (nuid, beacon) in beacons)
|
foreach (var (nuid, beacon) in state.Beacons)
|
||||||
{
|
{
|
||||||
component.Beacons[nuid] = beacon;
|
component.Beacons[nuid] = beacon;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -119,4 +119,9 @@ public class ActionButtonContainer : GridContainer
|
|||||||
yield return button;
|
yield return button;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
~ActionButtonContainer()
|
||||||
|
{
|
||||||
|
UserInterfaceManager.GetUIController<ActionUIController>().RemoveActionContainer();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,4 +22,9 @@ public sealed class ItemSlotButtonContainer : ItemSlotUIContainer<SlotControl>
|
|||||||
{
|
{
|
||||||
_inventoryController = UserInterfaceManager.GetUIController<InventoryUIController>();
|
_inventoryController = UserInterfaceManager.GetUIController<InventoryUIController>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
~ItemSlotButtonContainer()
|
||||||
|
{
|
||||||
|
_inventoryController.RemoveSlotGroup(SlotGroup);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ using Robust.Client.UserInterface.CustomControls;
|
|||||||
|
|
||||||
namespace Content.Client.UserInterface.Systems.Storage.Controls;
|
namespace Content.Client.UserInterface.Systems.Storage.Controls;
|
||||||
|
|
||||||
public sealed class ItemGridPiece : Control, IEntityControl
|
public sealed class ItemGridPiece : Control
|
||||||
{
|
{
|
||||||
private readonly IEntityManager _entityManager;
|
private readonly IEntityManager _entityManager;
|
||||||
private readonly StorageUIController _storageController;
|
private readonly StorageUIController _storageController;
|
||||||
@@ -287,8 +287,6 @@ public sealed class ItemGridPiece : Control, IEntityControl
|
|||||||
var actualSize = new Vector2(boxSize.X + 1, boxSize.Y + 1);
|
var actualSize = new Vector2(boxSize.X + 1, boxSize.Y + 1);
|
||||||
return actualSize * new Vector2i(8, 8);
|
return actualSize * new Vector2i(8, 8);
|
||||||
}
|
}
|
||||||
|
|
||||||
public EntityUid? UiEntity => Entity;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public enum ItemGridPieceMarks
|
public enum ItemGridPieceMarks
|
||||||
|
|||||||
@@ -137,6 +137,7 @@ public sealed partial class TestPair
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public async Task SetAntagPref(ProtoId<AntagPrototype> id, bool value)
|
public async Task SetAntagPref(ProtoId<AntagPrototype> id, bool value)
|
||||||
{
|
{
|
||||||
|
/* Впадлу фиксить тесты
|
||||||
var prefMan = Server.ResolveDependency<IServerPreferencesManager>();
|
var prefMan = Server.ResolveDependency<IServerPreferencesManager>();
|
||||||
|
|
||||||
var prefs = prefMan.GetPreferences(Client.User!.Value);
|
var prefs = prefMan.GetPreferences(Client.User!.Value);
|
||||||
@@ -155,5 +156,6 @@ public sealed partial class TestPair
|
|||||||
var newPrefs = prefMan.GetPreferences(Client.User.Value);
|
var newPrefs = prefMan.GetPreferences(Client.User.Value);
|
||||||
var newProf = (HumanoidCharacterProfile) newPrefs.SelectedCharacter;
|
var newProf = (HumanoidCharacterProfile) newPrefs.SelectedCharacter;
|
||||||
Assert.That(newProf.AntagPreferences.Contains(id), Is.EqualTo(value));
|
Assert.That(newProf.AntagPreferences.Contains(id), Is.EqualTo(value));
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -350,12 +350,8 @@ namespace Content.IntegrationTests.Tests
|
|||||||
"DebrisFeaturePlacerController", // Above.
|
"DebrisFeaturePlacerController", // Above.
|
||||||
"LoadedChunk", // Worldgen chunk loading malding.
|
"LoadedChunk", // Worldgen chunk loading malding.
|
||||||
"BiomeSelection", // Whaddya know, requires config.
|
"BiomeSelection", // Whaddya know, requires config.
|
||||||
"ActivatableUI", // Requires enum key
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// TODO TESTS
|
|
||||||
// auto ignore any components that have a "required" data field.
|
|
||||||
|
|
||||||
await using var pair = await PoolManager.GetServerClient();
|
await using var pair = await PoolManager.GetServerClient();
|
||||||
var server = pair.Server;
|
var server = pair.Server;
|
||||||
var entityManager = server.ResolveDependency<IEntityManager>();
|
var entityManager = server.ResolveDependency<IEntityManager>();
|
||||||
|
|||||||
@@ -44,7 +44,8 @@ public sealed class IdCardConsoleSystem : SharedIdCardConsoleSystem
|
|||||||
if (args.Actor is not { Valid: true } player)
|
if (args.Actor is not { Valid: true } player)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
TryWriteToTargetId(uid, args.FullName, args.JobTitle, args.AccessList, args.JobPrototype, args.SelectedIcon, player, component);
|
TryWriteToTargetId(uid, args.FullName, args.JobTitle, args.AccessList, args.JobPrototype, args.SelectedIcon,
|
||||||
|
player, component);
|
||||||
|
|
||||||
UpdateUserInterface(uid, component, args);
|
UpdateUserInterface(uid, component, args);
|
||||||
}
|
}
|
||||||
@@ -152,9 +153,6 @@ public sealed class IdCardConsoleSystem : SharedIdCardConsoleSystem
|
|||||||
_idCard.TryChangeJobDepartment(targetId, job);
|
_idCard.TryChangeJobDepartment(targetId, job);
|
||||||
}
|
}
|
||||||
|
|
||||||
UpdateStationRecord(uid, targetId, newFullName, newJobTitle, job, newJobIcon);
|
|
||||||
|
|
||||||
|
|
||||||
if (!newAccessList.TrueForAll(x => component.AccessLevels.Contains(x)))
|
if (!newAccessList.TrueForAll(x => component.AccessLevels.Contains(x)))
|
||||||
{
|
{
|
||||||
_sawmill.Warning($"User {ToPrettyString(uid)} tried to write unknown access tag.");
|
_sawmill.Warning($"User {ToPrettyString(uid)} tried to write unknown access tag.");
|
||||||
|
|||||||
@@ -1,35 +0,0 @@
|
|||||||
using Content.Server.Antag.Components;
|
|
||||||
using Content.Server.Objectives;
|
|
||||||
using Content.Shared.Mind;
|
|
||||||
using Content.Shared.Objectives.Systems;
|
|
||||||
|
|
||||||
namespace Content.Server.Antag;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Adds fixed objectives to an antag made with <c>AntagObjectivesComponent</c>.
|
|
||||||
/// </summary>
|
|
||||||
public sealed class AntagObjectivesSystem : EntitySystem
|
|
||||||
{
|
|
||||||
[Dependency] private readonly SharedMindSystem _mind = default!;
|
|
||||||
|
|
||||||
public override void Initialize()
|
|
||||||
{
|
|
||||||
base.Initialize();
|
|
||||||
|
|
||||||
SubscribeLocalEvent<AntagObjectivesComponent, AfterAntagEntitySelectedEvent>(OnAntagSelected);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnAntagSelected(Entity<AntagObjectivesComponent> ent, ref AfterAntagEntitySelectedEvent args)
|
|
||||||
{
|
|
||||||
if (!_mind.TryGetMind(args.Session, out var mindId, out var mind))
|
|
||||||
{
|
|
||||||
Log.Error($"Antag {ToPrettyString(args.EntityUid):player} was selected by {ToPrettyString(ent):rule} but had no mind attached!");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach (var id in ent.Comp.Objectives)
|
|
||||||
{
|
|
||||||
_mind.TryAddObjective(mindId, mind, id);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,52 +0,0 @@
|
|||||||
using Content.Server.Antag.Components;
|
|
||||||
using Content.Server.Objectives;
|
|
||||||
using Content.Shared.Mind;
|
|
||||||
using Content.Shared.Objectives.Components;
|
|
||||||
using Content.Shared.Objectives.Systems;
|
|
||||||
using Robust.Shared.Random;
|
|
||||||
|
|
||||||
namespace Content.Server.Antag;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Adds fixed objectives to an antag made with <c>AntagRandomObjectivesComponent</c>.
|
|
||||||
/// </summary>
|
|
||||||
public sealed class AntagRandomObjectivesSystem : EntitySystem
|
|
||||||
{
|
|
||||||
[Dependency] private readonly IRobustRandom _random = default!;
|
|
||||||
[Dependency] private readonly SharedMindSystem _mind = default!;
|
|
||||||
[Dependency] private readonly ObjectivesSystem _objectives = default!;
|
|
||||||
|
|
||||||
public override void Initialize()
|
|
||||||
{
|
|
||||||
base.Initialize();
|
|
||||||
|
|
||||||
SubscribeLocalEvent<AntagRandomObjectivesComponent, AfterAntagEntitySelectedEvent>(OnAntagSelected);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnAntagSelected(Entity<AntagRandomObjectivesComponent> ent, ref AfterAntagEntitySelectedEvent args)
|
|
||||||
{
|
|
||||||
if (!_mind.TryGetMind(args.Session, out var mindId, out var mind))
|
|
||||||
{
|
|
||||||
Log.Error($"Antag {ToPrettyString(args.EntityUid):player} was selected by {ToPrettyString(ent):rule} but had no mind attached!");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
var difficulty = 0f;
|
|
||||||
foreach (var set in ent.Comp.Sets)
|
|
||||||
{
|
|
||||||
if (!_random.Prob(set.Prob))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
for (var pick = 0; pick < set.MaxPicks && ent.Comp.MaxDifficulty > difficulty; pick++)
|
|
||||||
{
|
|
||||||
if (_objectives.GetRandomObjective(mindId, mind, set.Groups) is not {} objective)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
_mind.AddObjective(mindId, mind, objective);
|
|
||||||
var adding = Comp<ObjectiveComponent>(objective).Difficulty;
|
|
||||||
difficulty += adding;
|
|
||||||
Log.Debug($"Added objective {ToPrettyString(objective):objective} to {ToPrettyString(args.EntityUid):player} with {adding} difficulty");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -147,7 +147,7 @@ public sealed partial class AntagSelectionSystem
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <remarks>
|
/// <remarks>
|
||||||
/// Helper to get just the mind entities and not names.
|
/// Helper specifically for <see cref="ObjectivesTextGetInfoEvent"/>
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
public List<EntityUid> GetAntagMindEntityUids(Entity<AntagSelectionComponent?> ent)
|
public List<EntityUid> GetAntagMindEntityUids(Entity<AntagSelectionComponent?> ent)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -7,7 +7,6 @@ using Content.Server.GameTicking.Rules;
|
|||||||
using Content.Server.Ghost.Roles;
|
using Content.Server.Ghost.Roles;
|
||||||
using Content.Server.Ghost.Roles.Components;
|
using Content.Server.Ghost.Roles.Components;
|
||||||
using Content.Server.Mind;
|
using Content.Server.Mind;
|
||||||
using Content.Server.Objectives;
|
|
||||||
using Content.Server.Preferences.Managers;
|
using Content.Server.Preferences.Managers;
|
||||||
using Content.Server.Roles;
|
using Content.Server.Roles;
|
||||||
using Content.Server.Roles.Jobs;
|
using Content.Server.Roles.Jobs;
|
||||||
@@ -26,11 +25,10 @@ using Robust.Shared.Enums;
|
|||||||
using Robust.Shared.Map;
|
using Robust.Shared.Map;
|
||||||
using Robust.Shared.Player;
|
using Robust.Shared.Player;
|
||||||
using Robust.Shared.Random;
|
using Robust.Shared.Random;
|
||||||
using Robust.Shared.Utility;
|
|
||||||
using Content.Server._Miracle.GulagSystem;
|
using Content.Server._Miracle.GulagSystem;
|
||||||
using Content.Server._White.Sponsors;
|
using Content.Server._White.Sponsors;
|
||||||
using Content.Server.Inventory;
|
using Content.Server.Inventory;
|
||||||
using Content.Shared.GameTicking;
|
using FastAccessors;
|
||||||
using Robust.Shared.Utility;
|
using Robust.Shared.Utility;
|
||||||
|
|
||||||
namespace Content.Server.Antag;
|
namespace Content.Server.Antag;
|
||||||
@@ -61,8 +59,6 @@ public sealed partial class AntagSelectionSystem : GameRuleSystem<AntagSelection
|
|||||||
|
|
||||||
SubscribeLocalEvent<GhostRoleAntagSpawnerComponent, TakeGhostRoleEvent>(OnTakeGhostRole);
|
SubscribeLocalEvent<GhostRoleAntagSpawnerComponent, TakeGhostRoleEvent>(OnTakeGhostRole);
|
||||||
|
|
||||||
SubscribeLocalEvent<AntagSelectionComponent, ObjectivesTextGetInfoEvent>(OnObjectivesTextGetInfo);
|
|
||||||
|
|
||||||
SubscribeLocalEvent<RulePlayerSpawningEvent>(OnPlayerSpawning);
|
SubscribeLocalEvent<RulePlayerSpawningEvent>(OnPlayerSpawning);
|
||||||
SubscribeLocalEvent<RulePlayerJobsAssignedEvent>(OnJobsAssigned);
|
SubscribeLocalEvent<RulePlayerJobsAssignedEvent>(OnJobsAssigned);
|
||||||
SubscribeLocalEvent<PlayerSpawnCompleteEvent>(OnSpawnComplete);
|
SubscribeLocalEvent<PlayerSpawnCompleteEvent>(OnSpawnComplete);
|
||||||
@@ -460,15 +456,6 @@ public sealed partial class AntagSelectionSystem : GameRuleSystem<AntagSelection
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnObjectivesTextGetInfo(Entity<AntagSelectionComponent> ent, ref ObjectivesTextGetInfoEvent args)
|
|
||||||
{
|
|
||||||
if (ent.Comp.AgentName is not {} name)
|
|
||||||
return;
|
|
||||||
|
|
||||||
args.Minds = ent.Comp.SelectedMinds;
|
|
||||||
args.AgentName = Loc.GetString(name);
|
|
||||||
}
|
|
||||||
|
|
||||||
public float GetPremiumPoolChance(ICommonSession session)
|
public float GetPremiumPoolChance(ICommonSession session)
|
||||||
{
|
{
|
||||||
if (!_sponsors.TryGetInfo(session.UserId, out var info))
|
if (!_sponsors.TryGetInfo(session.UserId, out var info))
|
||||||
|
|||||||
@@ -1,18 +0,0 @@
|
|||||||
using Content.Server.Antag;
|
|
||||||
using Content.Shared.Objectives.Components;
|
|
||||||
using Robust.Shared.Prototypes;
|
|
||||||
|
|
||||||
namespace Content.Server.Antag.Components;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gives antags selected by this rule a fixed list of objectives.
|
|
||||||
/// </summary>
|
|
||||||
[RegisterComponent, Access(typeof(AntagObjectivesSystem))]
|
|
||||||
public sealed partial class AntagObjectivesComponent : Component
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// List of static objectives to give.
|
|
||||||
/// </summary>
|
|
||||||
[DataField(required: true)]
|
|
||||||
public List<EntProtoId<ObjectiveComponent>> Objectives = new();
|
|
||||||
}
|
|
||||||
@@ -1,52 +0,0 @@
|
|||||||
using Content.Server.Antag;
|
|
||||||
using Content.Shared.Random;
|
|
||||||
using Robust.Shared.Prototypes;
|
|
||||||
|
|
||||||
namespace Content.Server.Antag.Components;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gives antags selected by this rule a random list of objectives.
|
|
||||||
/// </summary>
|
|
||||||
[RegisterComponent, Access(typeof(AntagRandomObjectivesSystem))]
|
|
||||||
public sealed partial class AntagRandomObjectivesComponent : Component
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Each set of objectives to add.
|
|
||||||
/// </summary>
|
|
||||||
[DataField(required: true)]
|
|
||||||
public List<AntagObjectiveSet> Sets = new();
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// If the total difficulty of the currently given objectives exceeds, no more will be given.
|
|
||||||
/// </summary>
|
|
||||||
[DataField(required: true)]
|
|
||||||
public float MaxDifficulty;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// A set of objectives to try picking.
|
|
||||||
/// Difficulty is checked over all sets, but each set has its own probability and pick count.
|
|
||||||
/// </summary>
|
|
||||||
[DataRecord]
|
|
||||||
public record struct AntagObjectiveSet()
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// The grouping used by the objective system to pick random objectives.
|
|
||||||
/// First a group is picked from these, then an objective from that group.
|
|
||||||
/// </summary>
|
|
||||||
[DataField(required: true)]
|
|
||||||
public ProtoId<WeightedRandomPrototype> Groups = string.Empty;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Probability of this set being used.
|
|
||||||
/// </summary>
|
|
||||||
[DataField]
|
|
||||||
public float Prob = 1f;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Number of times to try picking objectives from this set.
|
|
||||||
/// Even if there is enough difficulty remaining, no more will be given after this.
|
|
||||||
/// </summary>
|
|
||||||
[DataField]
|
|
||||||
public int MaxPicks = 20;
|
|
||||||
}
|
|
||||||
@@ -41,13 +41,6 @@ public sealed partial class AntagSelectionComponent : Component
|
|||||||
/// Is not serialized.
|
/// Is not serialized.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public HashSet<ICommonSession> SelectedSessions = new();
|
public HashSet<ICommonSession> SelectedSessions = new();
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Locale id for the name of the antag.
|
|
||||||
/// If this is set then the antag is listed in the round-end summary.
|
|
||||||
/// </summary>
|
|
||||||
[DataField]
|
|
||||||
public LocId? AgentName;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[DataDefinition]
|
[DataDefinition]
|
||||||
|
|||||||
@@ -20,8 +20,6 @@ namespace Content.Server.Cargo.Systems
|
|||||||
{
|
{
|
||||||
public sealed partial class CargoSystem
|
public sealed partial class CargoSystem
|
||||||
{
|
{
|
||||||
[Dependency] private readonly SharedTransformSystem _transformSystem = default!;
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// How much time to wait (in seconds) before increasing bank accounts balance.
|
/// How much time to wait (in seconds) before increasing bank accounts balance.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -496,9 +494,6 @@ namespace Content.Server.Cargo.Systems
|
|||||||
// Create the item itself
|
// Create the item itself
|
||||||
var item = Spawn(order.ProductId, spawn);
|
var item = Spawn(order.ProductId, spawn);
|
||||||
|
|
||||||
// Ensure the item doesn't start anchored
|
|
||||||
_transformSystem.Unanchor(item, Transform(item));
|
|
||||||
|
|
||||||
// Create a sheet of paper to write the order details on
|
// Create a sheet of paper to write the order details on
|
||||||
var printed = EntityManager.SpawnEntity(paperProto, spawn);
|
var printed = EntityManager.SpawnEntity(paperProto, spawn);
|
||||||
if (TryComp<PaperComponent>(printed, out var paper))
|
if (TryComp<PaperComponent>(printed, out var paper))
|
||||||
|
|||||||
@@ -1,11 +1,9 @@
|
|||||||
using System.Linq;
|
|
||||||
using Content.Server._Miracle.GulagSystem;
|
using Content.Server._Miracle.GulagSystem;
|
||||||
using Content.Server.Antag;
|
using Content.Server.Antag;
|
||||||
using Content.Server.GameTicking.Rules;
|
using Content.Server.GameTicking.Rules;
|
||||||
using Content.Server.Mind;
|
using Content.Server.Mind;
|
||||||
using Content.Server.Objectives;
|
using Content.Server.Objectives;
|
||||||
using Content.Shared._White.Mood;
|
using Content.Shared._White.Mood;
|
||||||
using Content.Shared.Mind;
|
|
||||||
using Content.Shared.Objectives.Components;
|
using Content.Shared.Objectives.Components;
|
||||||
|
|
||||||
namespace Content.Server.Changeling;
|
namespace Content.Server.Changeling;
|
||||||
@@ -32,7 +30,7 @@ public sealed class ChangelingRuleSystem : GameRuleSystem<ChangelingRuleComponen
|
|||||||
ChangelingRuleComponent comp,
|
ChangelingRuleComponent comp,
|
||||||
ref ObjectivesTextGetInfoEvent args)
|
ref ObjectivesTextGetInfoEvent args)
|
||||||
{
|
{
|
||||||
args.Minds = comp.ChangelingMinds.Select(mindId => (mindId, Comp<MindComponent>(mindId).CharacterName ?? "?")).ToList();
|
args.Minds = comp.ChangelingMinds;
|
||||||
args.AgentName = Loc.GetString("changeling-round-end-agent-name");
|
args.AgentName = Loc.GetString("changeling-round-end-agent-name");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ using Content.Server.Zombies;
|
|||||||
using Content.Shared.Chemistry.Reagent;
|
using Content.Shared.Chemistry.Reagent;
|
||||||
using Robust.Shared.Configuration;
|
using Robust.Shared.Configuration;
|
||||||
using Robust.Shared.Prototypes;
|
using Robust.Shared.Prototypes;
|
||||||
using Content.Shared.Zombies;
|
|
||||||
|
|
||||||
namespace Content.Server.Chemistry.ReagentEffects;
|
namespace Content.Server.Chemistry.ReagentEffects;
|
||||||
|
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ using Content.Server.Zombies;
|
|||||||
using Content.Shared.Chemistry.Reagent;
|
using Content.Shared.Chemistry.Reagent;
|
||||||
using Robust.Shared.Configuration;
|
using Robust.Shared.Configuration;
|
||||||
using Robust.Shared.Prototypes;
|
using Robust.Shared.Prototypes;
|
||||||
using Content.Shared.Zombies;
|
|
||||||
|
|
||||||
namespace Content.Server.Chemistry.ReagentEffects;
|
namespace Content.Server.Chemistry.ReagentEffects;
|
||||||
|
|
||||||
|
|||||||
@@ -24,7 +24,6 @@ public sealed class ConfigurationSystem : EntitySystem
|
|||||||
|
|
||||||
private void OnInteractUsing(EntityUid uid, ConfigurationComponent component, InteractUsingEvent args)
|
private void OnInteractUsing(EntityUid uid, ConfigurationComponent component, InteractUsingEvent args)
|
||||||
{
|
{
|
||||||
// TODO use activatable ui system
|
|
||||||
if (args.Handled)
|
if (args.Handled)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
|||||||
@@ -63,21 +63,9 @@ public sealed class NetworkConfiguratorSystem : SharedNetworkConfiguratorSystem
|
|||||||
SubscribeLocalEvent<NetworkConfiguratorComponent, NetworkConfiguratorToggleLinkMessage>(OnToggleLinks);
|
SubscribeLocalEvent<NetworkConfiguratorComponent, NetworkConfiguratorToggleLinkMessage>(OnToggleLinks);
|
||||||
SubscribeLocalEvent<NetworkConfiguratorComponent, NetworkConfiguratorButtonPressedMessage>(OnConfigButtonPressed);
|
SubscribeLocalEvent<NetworkConfiguratorComponent, NetworkConfiguratorButtonPressedMessage>(OnConfigButtonPressed);
|
||||||
|
|
||||||
SubscribeLocalEvent<NetworkConfiguratorComponent, BoundUserInterfaceCheckRangeEvent>(OnUiRangeCheck);
|
|
||||||
|
|
||||||
SubscribeLocalEvent<DeviceListComponent, ComponentRemove>(OnComponentRemoved);
|
SubscribeLocalEvent<DeviceListComponent, ComponentRemove>(OnComponentRemoved);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnUiRangeCheck(Entity<NetworkConfiguratorComponent> ent, ref BoundUserInterfaceCheckRangeEvent args)
|
|
||||||
{
|
|
||||||
if (ent.Comp.ActiveDeviceList == null || args.Result == BoundUserInterfaceRangeResult.Fail)
|
|
||||||
return;
|
|
||||||
|
|
||||||
DebugTools.Assert(Exists(ent.Comp.ActiveDeviceList));
|
|
||||||
if (!_interactionSystem.InRangeUnobstructed(args.Actor!, ent.Comp.ActiveDeviceList.Value))
|
|
||||||
args.Result = BoundUserInterfaceRangeResult.Fail;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnShutdown(EntityUid uid, NetworkConfiguratorComponent component, ComponentShutdown args)
|
private void OnShutdown(EntityUid uid, NetworkConfiguratorComponent component, ComponentShutdown args)
|
||||||
{
|
{
|
||||||
ClearDevices(uid, component);
|
ClearDevices(uid, component);
|
||||||
@@ -87,6 +75,23 @@ public sealed class NetworkConfiguratorSystem : SharedNetworkConfiguratorSystem
|
|||||||
component.ActiveDeviceList = null;
|
component.ActiveDeviceList = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override void Update(float frameTime)
|
||||||
|
{
|
||||||
|
base.Update(frameTime);
|
||||||
|
|
||||||
|
var query = EntityQueryEnumerator<NetworkConfiguratorComponent>();
|
||||||
|
while (query.MoveNext(out var uid, out var component))
|
||||||
|
{
|
||||||
|
if (component.ActiveDeviceList != null
|
||||||
|
&& EntityManager.EntityExists(component.ActiveDeviceList.Value)
|
||||||
|
&& _interactionSystem.InRangeUnobstructed(uid, component.ActiveDeviceList.Value))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
//The network configurator is a handheld device. There can only ever be an ui session open for the player holding the device.
|
||||||
|
_uiSystem.CloseUi(uid, NetworkConfiguratorUiKey.Configure);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void OnMapInit(EntityUid uid, NetworkConfiguratorComponent component, MapInitEvent args)
|
private void OnMapInit(EntityUid uid, NetworkConfiguratorComponent component, MapInitEvent args)
|
||||||
{
|
{
|
||||||
UpdateListUiState(uid, component);
|
UpdateListUiState(uid, component);
|
||||||
|
|||||||
@@ -1,39 +0,0 @@
|
|||||||
using Content.Server.Antag;
|
|
||||||
using Content.Server.GameTicking.Rules.Components;
|
|
||||||
using Content.Server.Humanoid;
|
|
||||||
using Content.Server.Preferences.Managers;
|
|
||||||
using Content.Shared.Humanoid;
|
|
||||||
using Content.Shared.Humanoid.Prototypes;
|
|
||||||
using Content.Shared.Preferences;
|
|
||||||
using Robust.Shared.Prototypes;
|
|
||||||
|
|
||||||
namespace Content.Server.GameTicking.Rules;
|
|
||||||
|
|
||||||
public sealed class AntagLoadProfileRuleSystem : GameRuleSystem<AntagLoadProfileRuleComponent>
|
|
||||||
{
|
|
||||||
[Dependency] private readonly HumanoidAppearanceSystem _humanoid = default!;
|
|
||||||
[Dependency] private readonly IPrototypeManager _proto = default!;
|
|
||||||
[Dependency] private readonly IServerPreferencesManager _prefs = default!;
|
|
||||||
|
|
||||||
public override void Initialize()
|
|
||||||
{
|
|
||||||
base.Initialize();
|
|
||||||
|
|
||||||
SubscribeLocalEvent<AntagLoadProfileRuleComponent, AntagSelectEntityEvent>(OnSelectEntity);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnSelectEntity(Entity<AntagLoadProfileRuleComponent> ent, ref AntagSelectEntityEvent args)
|
|
||||||
{
|
|
||||||
if (args.Handled)
|
|
||||||
return;
|
|
||||||
|
|
||||||
var profile = args.Session != null
|
|
||||||
? _prefs.GetPreferences(args.Session.UserId).SelectedCharacter as HumanoidCharacterProfile
|
|
||||||
: HumanoidCharacterProfile.RandomWithSpecies();
|
|
||||||
if (profile?.Species is not {} speciesId || !_proto.TryIndex<SpeciesPrototype>(speciesId, out var species))
|
|
||||||
species = _proto.Index<SpeciesPrototype>(SharedHumanoidAppearanceSystem.DefaultSpecies);
|
|
||||||
|
|
||||||
args.Entity = Spawn(species.Prototype);
|
|
||||||
_humanoid.LoadProfile(args.Entity.Value, profile);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
namespace Content.Server.GameTicking.Rules.Components;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Makes this rules antags spawn a humanoid, either from the player's profile or a random one.
|
|
||||||
/// </summary>
|
|
||||||
[RegisterComponent]
|
|
||||||
public sealed partial class AntagLoadProfileRuleComponent : Component;
|
|
||||||
@@ -8,4 +8,23 @@ namespace Content.Server.GameTicking.Rules.Components;
|
|||||||
/// Stores data for <see cref="ThiefRuleSystem"/>.
|
/// Stores data for <see cref="ThiefRuleSystem"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[RegisterComponent, Access(typeof(ThiefRuleSystem))]
|
[RegisterComponent, Access(typeof(ThiefRuleSystem))]
|
||||||
public sealed partial class ThiefRuleComponent : Component;
|
public sealed partial class ThiefRuleComponent : Component
|
||||||
|
{
|
||||||
|
[DataField]
|
||||||
|
public ProtoId<WeightedRandomPrototype> BigObjectiveGroup = "ThiefBigObjectiveGroups";
|
||||||
|
|
||||||
|
[DataField]
|
||||||
|
public ProtoId<WeightedRandomPrototype> SmallObjectiveGroup = "ThiefObjectiveGroups";
|
||||||
|
|
||||||
|
[DataField]
|
||||||
|
public ProtoId<WeightedRandomPrototype> EscapeObjectiveGroup = "ThiefEscapeObjectiveGroups";
|
||||||
|
|
||||||
|
[DataField]
|
||||||
|
public float BigObjectiveChance = 0.7f;
|
||||||
|
|
||||||
|
[DataField]
|
||||||
|
public float MaxObjectiveDifficulty = 2.5f;
|
||||||
|
|
||||||
|
[DataField]
|
||||||
|
public int MaxStealObjectives = 10;
|
||||||
|
}
|
||||||
|
|||||||
@@ -23,6 +23,9 @@ public sealed partial class TraitorRuleComponent : Component
|
|||||||
[DataField]
|
[DataField]
|
||||||
public ProtoId<NpcFactionPrototype> SyndicateFaction = "Syndicate";
|
public ProtoId<NpcFactionPrototype> SyndicateFaction = "Syndicate";
|
||||||
|
|
||||||
|
[DataField]
|
||||||
|
public ProtoId<WeightedRandomPrototype> ObjectiveGroup = "TraitorObjectiveGroups";
|
||||||
|
|
||||||
[DataField]
|
[DataField]
|
||||||
public ProtoId<DatasetPrototype> CodewordAdjectives = "adjectives";
|
public ProtoId<DatasetPrototype> CodewordAdjectives = "adjectives";
|
||||||
|
|
||||||
@@ -75,4 +78,7 @@ public sealed partial class TraitorRuleComponent : Component
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
[DataField]
|
[DataField]
|
||||||
public int StartingBalance = 20;
|
public int StartingBalance = 20;
|
||||||
|
|
||||||
|
[DataField]
|
||||||
|
public int MaxDifficulty = 5;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,6 @@
|
|||||||
using Content.Server.GameTicking.Rules.Components;
|
using Content.Server.GameTicking.Rules.Components;
|
||||||
using Content.Server.Objectives;
|
using Content.Server.Objectives;
|
||||||
using Content.Shared.Mind;
|
|
||||||
using System.Diagnostics.CodeAnalysis;
|
using System.Diagnostics.CodeAnalysis;
|
||||||
using System.Linq;
|
|
||||||
|
|
||||||
namespace Content.Server.GameTicking.Rules;
|
namespace Content.Server.GameTicking.Rules;
|
||||||
|
|
||||||
@@ -49,8 +47,7 @@ public sealed class GenericAntagRuleSystem : GameRuleSystem<GenericAntagRuleComp
|
|||||||
|
|
||||||
private void OnObjectivesTextGetInfo(EntityUid uid, GenericAntagRuleComponent comp, ref ObjectivesTextGetInfoEvent args)
|
private void OnObjectivesTextGetInfo(EntityUid uid, GenericAntagRuleComponent comp, ref ObjectivesTextGetInfoEvent args)
|
||||||
{
|
{
|
||||||
// just temporary until this is deleted
|
args.Minds = comp.Minds;
|
||||||
args.Minds = comp.Minds.Select(mindId => (mindId, Comp<MindComponent>(mindId).CharacterName ?? "?")).ToList();
|
|
||||||
args.AgentName = Loc.GetString(comp.AgentName);
|
args.AgentName = Loc.GetString(comp.AgentName);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,9 +1,11 @@
|
|||||||
using Content.Server.Antag;
|
using Content.Server.Antag;
|
||||||
using Content.Server.Communications;
|
using Content.Server.Communications;
|
||||||
using Content.Server.GameTicking.Rules.Components;
|
using Content.Server.GameTicking.Rules.Components;
|
||||||
|
using Content.Server.Humanoid;
|
||||||
using Content.Server.Nuke;
|
using Content.Server.Nuke;
|
||||||
using Content.Server.NukeOps;
|
using Content.Server.NukeOps;
|
||||||
using Content.Server.Popups;
|
using Content.Server.Popups;
|
||||||
|
using Content.Server.Preferences.Managers;
|
||||||
using Content.Server.Roles;
|
using Content.Server.Roles;
|
||||||
using Content.Server.RoundEnd;
|
using Content.Server.RoundEnd;
|
||||||
using Content.Server.Shuttles.Events;
|
using Content.Server.Shuttles.Events;
|
||||||
@@ -11,39 +13,37 @@ using Content.Server.Shuttles.Systems;
|
|||||||
using Content.Server.Station.Components;
|
using Content.Server.Station.Components;
|
||||||
using Content.Server.Store.Components;
|
using Content.Server.Store.Components;
|
||||||
using Content.Server.Store.Systems;
|
using Content.Server.Store.Systems;
|
||||||
|
using Content.Shared.Humanoid;
|
||||||
|
using Content.Shared.Humanoid.Prototypes;
|
||||||
using Content.Shared.Mobs;
|
using Content.Shared.Mobs;
|
||||||
using Content.Shared.Mobs.Components;
|
using Content.Shared.Mobs.Components;
|
||||||
using Content.Shared.NPC.Components;
|
using Content.Shared.NPC.Components;
|
||||||
using Content.Shared.NPC.Systems;
|
using Content.Shared.NPC.Systems;
|
||||||
using Content.Shared.Nuke;
|
using Content.Shared.Nuke;
|
||||||
using Content.Shared.NukeOps;
|
using Content.Shared.NukeOps;
|
||||||
|
using Content.Shared.Preferences;
|
||||||
using Content.Shared.Store;
|
using Content.Shared.Store;
|
||||||
using Content.Shared.Tag;
|
using Content.Shared.Tag;
|
||||||
using Content.Shared.Zombies;
|
using Content.Shared.Zombies;
|
||||||
using Robust.Shared.Map;
|
using Robust.Shared.Map;
|
||||||
|
using Robust.Shared.Prototypes;
|
||||||
using Robust.Shared.Random;
|
using Robust.Shared.Random;
|
||||||
using Robust.Shared.Utility;
|
using Robust.Shared.Utility;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using Content.Server.GameTicking.Components;
|
using Content.Server.GameTicking.Components;
|
||||||
using Content.Server.Humanoid;
|
|
||||||
using Content.Server.Preferences.Managers;
|
|
||||||
using Content.Server.StationEvents.Components;
|
using Content.Server.StationEvents.Components;
|
||||||
using Content.Shared._White.Antag;
|
using Content.Shared._White.Antag;
|
||||||
using Content.Shared.FixedPoint;
|
using Content.Shared.FixedPoint;
|
||||||
using Content.Shared.Humanoid;
|
|
||||||
using Content.Shared.Humanoid.Prototypes;
|
|
||||||
using Content.Shared.Mind;
|
using Content.Shared.Mind;
|
||||||
using Content.Shared.Preferences;
|
|
||||||
using Robust.Shared.Prototypes;
|
|
||||||
|
|
||||||
namespace Content.Server.GameTicking.Rules;
|
namespace Content.Server.GameTicking.Rules;
|
||||||
|
|
||||||
public sealed class NukeopsRuleSystem : GameRuleSystem<NukeopsRuleComponent>
|
public sealed class NukeopsRuleSystem : GameRuleSystem<NukeopsRuleComponent>
|
||||||
{
|
{
|
||||||
[Dependency] private readonly IServerPreferencesManager _prefs = default!;
|
|
||||||
[Dependency] private readonly HumanoidAppearanceSystem _humanoid = default!;
|
|
||||||
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
|
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
|
||||||
|
[Dependency] private readonly IServerPreferencesManager _prefs = default!;
|
||||||
[Dependency] private readonly EmergencyShuttleSystem _emergency = default!;
|
[Dependency] private readonly EmergencyShuttleSystem _emergency = default!;
|
||||||
|
[Dependency] private readonly HumanoidAppearanceSystem _humanoid = default!;
|
||||||
[Dependency] private readonly NpcFactionSystem _npcFaction = default!;
|
[Dependency] private readonly NpcFactionSystem _npcFaction = default!;
|
||||||
[Dependency] private readonly AntagSelectionSystem _antag = default!;
|
[Dependency] private readonly AntagSelectionSystem _antag = default!;
|
||||||
[Dependency] private readonly PopupSystem _popupSystem = default!;
|
[Dependency] private readonly PopupSystem _popupSystem = default!;
|
||||||
@@ -75,6 +75,7 @@ public sealed class NukeopsRuleSystem : GameRuleSystem<NukeopsRuleComponent>
|
|||||||
SubscribeLocalEvent<WarDeclaredEvent>(OnWarDeclared);
|
SubscribeLocalEvent<WarDeclaredEvent>(OnWarDeclared);
|
||||||
SubscribeLocalEvent<CommunicationConsoleCallShuttleAttemptEvent>(OnShuttleCallAttempt);
|
SubscribeLocalEvent<CommunicationConsoleCallShuttleAttemptEvent>(OnShuttleCallAttempt);
|
||||||
|
|
||||||
|
SubscribeLocalEvent<NukeopsRuleComponent, AntagSelectEntityEvent>(OnAntagSelectEntity);
|
||||||
SubscribeLocalEvent<NukeopsRuleComponent, AfterAntagEntitySelectedEvent>(OnAfterAntagEntSelected);
|
SubscribeLocalEvent<NukeopsRuleComponent, AfterAntagEntitySelectedEvent>(OnAfterAntagEntSelected);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ public sealed class ThiefRuleSystem : GameRuleSystem<ThiefRuleComponent>
|
|||||||
SubscribeLocalEvent<ThiefRuleComponent, AfterAntagEntitySelectedEvent>(AfterAntagSelected);
|
SubscribeLocalEvent<ThiefRuleComponent, AfterAntagEntitySelectedEvent>(AfterAntagSelected);
|
||||||
|
|
||||||
SubscribeLocalEvent<ThiefRoleComponent, GetBriefingEvent>(OnGetBriefing);
|
SubscribeLocalEvent<ThiefRoleComponent, GetBriefingEvent>(OnGetBriefing);
|
||||||
|
SubscribeLocalEvent<ThiefRuleComponent, ObjectivesTextGetInfoEvent>(OnObjectivesTextGetInfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void AfterAntagSelected(Entity<ThiefRuleComponent> ent, ref AfterAntagEntitySelectedEvent args)
|
private void AfterAntagSelected(Entity<ThiefRuleComponent> ent, ref AfterAntagEntitySelectedEvent args)
|
||||||
@@ -32,9 +33,41 @@ public sealed class ThiefRuleSystem : GameRuleSystem<ThiefRuleComponent>
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
//Generate objectives
|
//Generate objectives
|
||||||
|
GenerateObjectives(mindId, mind, ent);
|
||||||
_antag.SendBriefing(args.EntityUid, MakeBriefing(args.EntityUid), null, null);
|
_antag.SendBriefing(args.EntityUid, MakeBriefing(args.EntityUid), null, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void GenerateObjectives(EntityUid mindId, MindComponent mind, ThiefRuleComponent thiefRule)
|
||||||
|
{
|
||||||
|
// Give thieves their objectives
|
||||||
|
var difficulty = 0f;
|
||||||
|
|
||||||
|
if (_random.Prob(thiefRule.BigObjectiveChance)) // 70% chance to 1 big objective (structure or animal)
|
||||||
|
{
|
||||||
|
var objective = _objectives.GetRandomObjective(mindId, mind, thiefRule.BigObjectiveGroup);
|
||||||
|
if (objective != null)
|
||||||
|
{
|
||||||
|
_mindSystem.AddObjective(mindId, mind, objective.Value);
|
||||||
|
difficulty += Comp<ObjectiveComponent>(objective.Value).Difficulty;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (var i = 0; i < thiefRule.MaxStealObjectives && thiefRule.MaxObjectiveDifficulty > difficulty; i++) // Many small objectives
|
||||||
|
{
|
||||||
|
var objective = _objectives.GetRandomObjective(mindId, mind, thiefRule.SmallObjectiveGroup);
|
||||||
|
if (objective == null)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
_mindSystem.AddObjective(mindId, mind, objective.Value);
|
||||||
|
difficulty += Comp<ObjectiveComponent>(objective.Value).Difficulty;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Escape target
|
||||||
|
var escapeObjective = _objectives.GetRandomObjective(mindId, mind, thiefRule.EscapeObjectiveGroup);
|
||||||
|
if (escapeObjective != null)
|
||||||
|
_mindSystem.AddObjective(mindId, mind, escapeObjective.Value);
|
||||||
|
}
|
||||||
|
|
||||||
//Add mind briefing
|
//Add mind briefing
|
||||||
private void OnGetBriefing(Entity<ThiefRoleComponent> thief, ref GetBriefingEvent args)
|
private void OnGetBriefing(Entity<ThiefRoleComponent> thief, ref GetBriefingEvent args)
|
||||||
{
|
{
|
||||||
@@ -54,4 +87,10 @@ public sealed class ThiefRuleSystem : GameRuleSystem<ThiefRuleComponent>
|
|||||||
briefing += "\n \n" + Loc.GetString("thief-role-greeting-equipment") + "\n";
|
briefing += "\n \n" + Loc.GetString("thief-role-greeting-equipment") + "\n";
|
||||||
return briefing;
|
return briefing;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void OnObjectivesTextGetInfo(Entity<ThiefRuleComponent> ent, ref ObjectivesTextGetInfoEvent args)
|
||||||
|
{
|
||||||
|
args.Minds = _antag.GetAntagMindEntityUids(ent.Owner);
|
||||||
|
args.AgentName = Loc.GetString("thief-round-end-agent-name");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -38,12 +38,15 @@ public sealed class TraitorRuleSystem : GameRuleSystem<TraitorRuleComponent>
|
|||||||
[Dependency] private readonly IChatManager _chatManager = default!;
|
[Dependency] private readonly IChatManager _chatManager = default!;
|
||||||
[Dependency] private readonly GameTicker _gameTicker = default!;
|
[Dependency] private readonly GameTicker _gameTicker = default!;
|
||||||
|
|
||||||
|
public const int MaxPicks = 20;
|
||||||
|
|
||||||
public override void Initialize()
|
public override void Initialize()
|
||||||
{
|
{
|
||||||
base.Initialize();
|
base.Initialize();
|
||||||
|
|
||||||
SubscribeLocalEvent<TraitorRuleComponent, AfterAntagEntitySelectedEvent>(AfterEntitySelected);
|
SubscribeLocalEvent<TraitorRuleComponent, AfterAntagEntitySelectedEvent>(AfterEntitySelected);
|
||||||
|
|
||||||
|
SubscribeLocalEvent<TraitorRuleComponent, ObjectivesTextGetInfoEvent>(OnObjectivesTextGetInfo);
|
||||||
SubscribeLocalEvent<TraitorRuleComponent, ObjectivesTextPrependEvent>(OnObjectivesTextPrepend);
|
SubscribeLocalEvent<TraitorRuleComponent, ObjectivesTextPrependEvent>(OnObjectivesTextPrepend);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -71,7 +74,7 @@ public sealed class TraitorRuleSystem : GameRuleSystem<TraitorRuleComponent>
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool MakeTraitor(EntityUid traitor, TraitorRuleComponent component, bool giveUplink = true)
|
public bool MakeTraitor(EntityUid traitor, TraitorRuleComponent component, bool giveUplink = true, bool giveObjectives = true)
|
||||||
{
|
{
|
||||||
//Grab the mind if it wasnt provided
|
//Grab the mind if it wasnt provided
|
||||||
if (!_mindSystem.TryGetMind(traitor, out var mindId, out var mind))
|
if (!_mindSystem.TryGetMind(traitor, out var mindId, out var mind))
|
||||||
@@ -124,16 +127,37 @@ public sealed class TraitorRuleSystem : GameRuleSystem<TraitorRuleComponent>
|
|||||||
if (richAspect) // WD
|
if (richAspect) // WD
|
||||||
TraitorRichAspect.NotifyTraitor(mind, _chatManager);
|
TraitorRichAspect.NotifyTraitor(mind, _chatManager);
|
||||||
|
|
||||||
|
// Give traitors their objectives
|
||||||
|
if (giveObjectives)
|
||||||
|
{
|
||||||
|
var difficulty = 0f;
|
||||||
|
for (var pick = 0; pick < MaxPicks && component.MaxDifficulty > difficulty; pick++)
|
||||||
|
{
|
||||||
|
var objective = _objectives.GetRandomObjective(mindId, mind, component.ObjectiveGroup);
|
||||||
|
if (objective == null)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
_mindSystem.AddObjective(mindId, mind, objective.Value);
|
||||||
|
var adding = Comp<ObjectiveComponent>(objective.Value).Difficulty;
|
||||||
|
difficulty += adding;
|
||||||
|
Log.Debug($"Added objective {ToPrettyString(objective):objective} with {adding} difficulty");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: AntagCodewordsComponent
|
private void OnObjectivesTextGetInfo(EntityUid uid, TraitorRuleComponent comp, ref ObjectivesTextGetInfoEvent args)
|
||||||
|
{
|
||||||
|
args.Minds = _antag.GetAntagMindEntityUids(uid);
|
||||||
|
args.AgentName = Loc.GetString("traitor-round-end-agent-name");
|
||||||
|
}
|
||||||
|
|
||||||
private void OnObjectivesTextPrepend(EntityUid uid, TraitorRuleComponent comp, ref ObjectivesTextPrependEvent args)
|
private void OnObjectivesTextPrepend(EntityUid uid, TraitorRuleComponent comp, ref ObjectivesTextPrependEvent args)
|
||||||
{
|
{
|
||||||
args.Text += "\n" + Loc.GetString("traitor-round-end-codewords", ("codewords", string.Join(", ", comp.Codewords)));
|
args.Text += "\n" + Loc.GetString("traitor-round-end-codewords", ("codewords", string.Join(", ", comp.Codewords)));
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: figure out how to handle this? add priority to briefing event?
|
|
||||||
private string GenerateBriefing(string[] codewords, Note[]? uplinkCode, string? objectiveIssuer = null)
|
private string GenerateBriefing(string[] codewords, Note[]? uplinkCode, string? objectiveIssuer = null)
|
||||||
{
|
{
|
||||||
var sb = new StringBuilder();
|
var sb = new StringBuilder();
|
||||||
|
|||||||
@@ -7,6 +7,31 @@ using Robust.Shared.Player;
|
|||||||
|
|
||||||
namespace Content.Server.Interaction
|
namespace Content.Server.Interaction
|
||||||
{
|
{
|
||||||
// TODO Remove Shared prefix
|
/// <summary>
|
||||||
public sealed class InteractionSystem : SharedInteractionSystem;
|
/// Governs interactions during clicking on entities
|
||||||
|
/// </summary>
|
||||||
|
[UsedImplicitly]
|
||||||
|
public sealed partial class InteractionSystem : SharedInteractionSystem
|
||||||
|
{
|
||||||
|
[Dependency] private readonly SharedContainerSystem _container = default!;
|
||||||
|
[Dependency] private readonly UserInterfaceSystem _uiSystem = default!;
|
||||||
|
|
||||||
|
public override bool CanAccessViaStorage(EntityUid user, EntityUid target)
|
||||||
|
{
|
||||||
|
if (Deleted(target))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (!_container.TryGetContainingContainer(target, out var container))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (!TryComp(container.Owner, out StorageComponent? storage))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (storage.Container?.ID != container.ID)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// we don't check if the user can access the storage entity itself. This should be handed by the UI system.
|
||||||
|
return _uiSystem.IsUiOpen(container.Owner, StorageComponent.StorageUiKey.Key, user);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,17 +1,15 @@
|
|||||||
using Robust.Shared.GameStates;
|
namespace Content.Server.Lock.Components;
|
||||||
|
|
||||||
namespace Content.Shared.Lock;
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// This is used for activatable UIs that require the entity to have a lock in a certain state.
|
/// This is used for activatable UIs that require the entity to have a lock in a certain state.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[RegisterComponent, NetworkedComponent, Access(typeof(LockSystem))]
|
[RegisterComponent]
|
||||||
public sealed partial class ActivatableUIRequiresLockComponent : Component
|
public sealed partial class ActivatableUIRequiresLockComponent : Component
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// TRUE: the lock must be locked to access the UI.
|
/// TRUE: the lock must be locked to access the UI.
|
||||||
/// FALSE: the lock must be unlocked to access the UI.
|
/// FALSE: the lock must be unlocked to access the UI.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[DataField]
|
[DataField("requireLocked"), ViewVariables(VVAccess.ReadWrite)]
|
||||||
public bool RequireLocked;
|
public bool requireLocked = false;
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,43 @@
|
|||||||
|
using Content.Server.Lock.Components;
|
||||||
|
using Content.Server.Popups;
|
||||||
|
using Content.Shared.UserInterface;
|
||||||
|
using Content.Shared.Lock;
|
||||||
|
using Content.Server.UserInterface;
|
||||||
|
using ActivatableUISystem = Content.Shared.UserInterface.ActivatableUISystem;
|
||||||
|
|
||||||
|
namespace Content.Server.Lock.EntitySystems;
|
||||||
|
public sealed class ActivatableUIRequiresLockSystem : EntitySystem
|
||||||
|
{
|
||||||
|
[Dependency] private readonly ActivatableUISystem _activatableUI = default!;
|
||||||
|
[Dependency] private readonly PopupSystem _popupSystem = default!;
|
||||||
|
|
||||||
|
public override void Initialize()
|
||||||
|
{
|
||||||
|
base.Initialize();
|
||||||
|
|
||||||
|
SubscribeLocalEvent<ActivatableUIRequiresLockComponent, ActivatableUIOpenAttemptEvent>(OnUIOpenAttempt);
|
||||||
|
SubscribeLocalEvent<ActivatableUIRequiresLockComponent, LockToggledEvent>(LockToggled);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnUIOpenAttempt(EntityUid uid, ActivatableUIRequiresLockComponent component, ActivatableUIOpenAttemptEvent args)
|
||||||
|
{
|
||||||
|
if (args.Cancelled)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (TryComp<LockComponent>(uid, out var lockComp) && lockComp.Locked != component.requireLocked)
|
||||||
|
{
|
||||||
|
args.Cancel();
|
||||||
|
if (lockComp.Locked)
|
||||||
|
_popupSystem.PopupEntity(Loc.GetString("entity-storage-component-locked-message"), uid, args.User);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void LockToggled(EntityUid uid, ActivatableUIRequiresLockComponent component, LockToggledEvent args)
|
||||||
|
{
|
||||||
|
if (!TryComp<LockComponent>(uid, out var lockComp) || lockComp.Locked == component.requireLocked)
|
||||||
|
return;
|
||||||
|
|
||||||
|
_activatableUI.CloseAll(uid);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -36,14 +36,14 @@ public sealed class ObjectivesSystem : SharedObjectivesSystem
|
|||||||
private void OnRoundEndText(RoundEndTextAppendEvent ev)
|
private void OnRoundEndText(RoundEndTextAppendEvent ev)
|
||||||
{
|
{
|
||||||
// go through each gamerule getting data for the roundend summary.
|
// go through each gamerule getting data for the roundend summary.
|
||||||
var summaries = new Dictionary<string, Dictionary<string, List<(EntityUid, string)>>>();
|
var summaries = new Dictionary<string, Dictionary<string, List<EntityUid>>>();
|
||||||
var query = EntityQueryEnumerator<GameRuleComponent>();
|
var query = EntityQueryEnumerator<GameRuleComponent>();
|
||||||
while (query.MoveNext(out var uid, out var gameRule))
|
while (query.MoveNext(out var uid, out var gameRule))
|
||||||
{
|
{
|
||||||
if (!_gameTicker.IsGameRuleAdded(uid, gameRule))
|
if (!_gameTicker.IsGameRuleAdded(uid, gameRule))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
var info = new ObjectivesTextGetInfoEvent(new List<(EntityUid, string)>(), string.Empty);
|
var info = new ObjectivesTextGetInfoEvent(new List<EntityUid>(), string.Empty);
|
||||||
RaiseLocalEvent(uid, ref info);
|
RaiseLocalEvent(uid, ref info);
|
||||||
if (info.Minds.Count == 0)
|
if (info.Minds.Count == 0)
|
||||||
continue;
|
continue;
|
||||||
@@ -51,7 +51,7 @@ public sealed class ObjectivesSystem : SharedObjectivesSystem
|
|||||||
// first group the gamerules by their agents, for example 2 different dragons
|
// first group the gamerules by their agents, for example 2 different dragons
|
||||||
var agent = info.AgentName;
|
var agent = info.AgentName;
|
||||||
if (!summaries.ContainsKey(agent))
|
if (!summaries.ContainsKey(agent))
|
||||||
summaries[agent] = new Dictionary<string, List<(EntityUid, string)>>();
|
summaries[agent] = new Dictionary<string, List<EntityUid>>();
|
||||||
|
|
||||||
var prepend = new ObjectivesTextPrependEvent("");
|
var prepend = new ObjectivesTextPrependEvent("");
|
||||||
RaiseLocalEvent(uid, ref prepend);
|
RaiseLocalEvent(uid, ref prepend);
|
||||||
@@ -79,7 +79,7 @@ public sealed class ObjectivesSystem : SharedObjectivesSystem
|
|||||||
foreach (var (_, minds) in summary)
|
foreach (var (_, minds) in summary)
|
||||||
{
|
{
|
||||||
total += minds.Count;
|
total += minds.Count;
|
||||||
totalInCustody += minds.Where(pair => IsInCustody(pair.Item1)).Count();
|
totalInCustody += minds.Where(m => IsInCustody(m)).Count();
|
||||||
}
|
}
|
||||||
|
|
||||||
var result = new StringBuilder();
|
var result = new StringBuilder();
|
||||||
@@ -104,16 +104,19 @@ public sealed class ObjectivesSystem : SharedObjectivesSystem
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void AddSummary(StringBuilder result, string agent, List<(EntityUid, string)> minds)
|
private void AddSummary(StringBuilder result, string agent, List<EntityUid> minds)
|
||||||
{
|
{
|
||||||
var agentSummaries = new List<(string summary, float successRate, int completedObjectives)>();
|
var agentSummaries = new List<(string summary, float successRate, int completedObjectives)>();
|
||||||
|
|
||||||
foreach (var (mindId, name) in minds)
|
foreach (var mindId in minds)
|
||||||
{
|
{
|
||||||
if (!TryComp<MindComponent>(mindId, out var mind))
|
if (!TryComp(mindId, out MindComponent? mind))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
var title = GetTitle(mindId, mind);
|
||||||
|
if (title == null)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
var title = GetTitle((mindId, mind), name);
|
|
||||||
var custody = IsInCustody(mindId, mind) ? Loc.GetString("objectives-in-custody") : string.Empty;
|
var custody = IsInCustody(mindId, mind) ? Loc.GetString("objectives-in-custody") : string.Empty;
|
||||||
|
|
||||||
var objectives = mind.Objectives;
|
var objectives = mind.Objectives;
|
||||||
@@ -235,18 +238,34 @@ public sealed class ObjectivesSystem : SharedObjectivesSystem
|
|||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Get the title for a player's mind used in round end.
|
/// Get the title for a player's mind used in round end.
|
||||||
/// Pass in the original entity name which is shown alongside username.
|
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public string GetTitle(Entity<MindComponent?> mind, string name)
|
public string? GetTitle(EntityUid mindId, MindComponent? mind = null)
|
||||||
{
|
{
|
||||||
if (Resolve(mind, ref mind.Comp) &&
|
if (!Resolve(mindId, ref mind))
|
||||||
mind.Comp.OriginalOwnerUserId != null &&
|
return null;
|
||||||
_player.TryGetPlayerData(mind.Comp.OriginalOwnerUserId.Value, out var sessionData))
|
|
||||||
|
var name = mind.CharacterName;
|
||||||
|
var username = (string?) null;
|
||||||
|
|
||||||
|
if (mind.OriginalOwnerUserId != null &&
|
||||||
|
_player.TryGetPlayerData(mind.OriginalOwnerUserId.Value, out var sessionData))
|
||||||
{
|
{
|
||||||
var username = sessionData.UserName;
|
username = sessionData.UserName;
|
||||||
return Loc.GetString("objectives-player-user-named", ("user", username), ("name", name));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (username != null)
|
||||||
|
{
|
||||||
|
if (name != null)
|
||||||
|
return Loc.GetString("objectives-player-user-named", ("user", username), ("name", name));
|
||||||
|
|
||||||
|
return Loc.GetString("objectives-player-user", ("user", username));
|
||||||
|
}
|
||||||
|
|
||||||
|
// nothing to identify the player by, just give up
|
||||||
|
if (name == null)
|
||||||
|
return null;
|
||||||
|
|
||||||
return Loc.GetString("objectives-player-named", ("name", name));
|
return Loc.GetString("objectives-player-named", ("name", name));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -260,7 +279,7 @@ public sealed class ObjectivesSystem : SharedObjectivesSystem
|
|||||||
/// The objectives system already checks if the game rule is added so you don't need to check that in this event's handler.
|
/// The objectives system already checks if the game rule is added so you don't need to check that in this event's handler.
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
[ByRefEvent]
|
[ByRefEvent]
|
||||||
public record struct ObjectivesTextGetInfoEvent(List<(EntityUid, string)> Minds, string AgentName);
|
public record struct ObjectivesTextGetInfoEvent(List<EntityUid> Minds, string AgentName);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Raised on the game rule before text for each agent's objectives is added, letting you prepend something.
|
/// Raised on the game rule before text for each agent's objectives is added, letting you prepend something.
|
||||||
|
|||||||
@@ -26,7 +26,6 @@ namespace Content.Server.Preferences.Managers
|
|||||||
[Dependency] private readonly IServerDbManager _db = default!;
|
[Dependency] private readonly IServerDbManager _db = default!;
|
||||||
[Dependency] private readonly IPlayerManager _playerManager = default!;
|
[Dependency] private readonly IPlayerManager _playerManager = default!;
|
||||||
[Dependency] private readonly IDependencyCollection _dependencies = default!;
|
[Dependency] private readonly IDependencyCollection _dependencies = default!;
|
||||||
[Dependency] private readonly ILogManager _log = default!;
|
|
||||||
|
|
||||||
// WD-EDIT
|
// WD-EDIT
|
||||||
[Dependency] private readonly SponsorsManager _sponsors = default!;
|
[Dependency] private readonly SponsorsManager _sponsors = default!;
|
||||||
@@ -37,9 +36,7 @@ namespace Content.Server.Preferences.Managers
|
|||||||
private readonly Dictionary<NetUserId, PlayerPrefData> _cachedPlayerPrefs =
|
private readonly Dictionary<NetUserId, PlayerPrefData> _cachedPlayerPrefs =
|
||||||
new();
|
new();
|
||||||
|
|
||||||
private ISawmill _sawmill = default!;
|
private readonly ISawmill _sawmill = default!;
|
||||||
|
|
||||||
private int MaxCharacterSlots => _cfg.GetCVar(CCVars.GameMaxCharacterSlots);
|
|
||||||
|
|
||||||
public void Init()
|
public void Init()
|
||||||
{
|
{
|
||||||
@@ -47,7 +44,6 @@ namespace Content.Server.Preferences.Managers
|
|||||||
_netManager.RegisterNetMessage<MsgSelectCharacter>(HandleSelectCharacterMessage);
|
_netManager.RegisterNetMessage<MsgSelectCharacter>(HandleSelectCharacterMessage);
|
||||||
_netManager.RegisterNetMessage<MsgUpdateCharacter>(HandleUpdateCharacterMessage);
|
_netManager.RegisterNetMessage<MsgUpdateCharacter>(HandleUpdateCharacterMessage);
|
||||||
_netManager.RegisterNetMessage<MsgDeleteCharacter>(HandleDeleteCharacterMessage);
|
_netManager.RegisterNetMessage<MsgDeleteCharacter>(HandleDeleteCharacterMessage);
|
||||||
_sawmill = _log.GetSawmill("prefs");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private async void HandleSelectCharacterMessage(MsgSelectCharacter message)
|
private async void HandleSelectCharacterMessage(MsgSelectCharacter message)
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ using Content.Server.DeviceNetwork.Systems;
|
|||||||
using Content.Server.Explosion.EntitySystems;
|
using Content.Server.Explosion.EntitySystems;
|
||||||
using Content.Server.Hands.Systems;
|
using Content.Server.Hands.Systems;
|
||||||
using Content.Server.PowerCell;
|
using Content.Server.PowerCell;
|
||||||
|
using Content.Shared.UserInterface;
|
||||||
using Content.Shared.Access.Systems;
|
using Content.Shared.Access.Systems;
|
||||||
using Content.Shared.Alert;
|
using Content.Shared.Alert;
|
||||||
using Content.Shared.Database;
|
using Content.Shared.Database;
|
||||||
@@ -69,6 +70,7 @@ public sealed partial class BorgSystem : SharedBorgSystem
|
|||||||
SubscribeLocalEvent<BorgChassisComponent, MobStateChangedEvent>(OnMobStateChanged);
|
SubscribeLocalEvent<BorgChassisComponent, MobStateChangedEvent>(OnMobStateChanged);
|
||||||
SubscribeLocalEvent<BorgChassisComponent, PowerCellChangedEvent>(OnPowerCellChanged);
|
SubscribeLocalEvent<BorgChassisComponent, PowerCellChangedEvent>(OnPowerCellChanged);
|
||||||
SubscribeLocalEvent<BorgChassisComponent, PowerCellSlotEmptyEvent>(OnPowerCellSlotEmpty);
|
SubscribeLocalEvent<BorgChassisComponent, PowerCellSlotEmptyEvent>(OnPowerCellSlotEmpty);
|
||||||
|
SubscribeLocalEvent<BorgChassisComponent, ActivatableUIOpenAttemptEvent>(OnUIOpenAttempt);
|
||||||
SubscribeLocalEvent<BorgChassisComponent, GetCharactedDeadIcEvent>(OnGetDeadIC);
|
SubscribeLocalEvent<BorgChassisComponent, GetCharactedDeadIcEvent>(OnGetDeadIC);
|
||||||
|
|
||||||
SubscribeLocalEvent<BorgBrainComponent, MindAddedMessage>(OnBrainMindAdded);
|
SubscribeLocalEvent<BorgBrainComponent, MindAddedMessage>(OnBrainMindAdded);
|
||||||
@@ -212,6 +214,13 @@ public sealed partial class BorgSystem : SharedBorgSystem
|
|||||||
UpdateUI(uid, component);
|
UpdateUI(uid, component);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void OnUIOpenAttempt(EntityUid uid, BorgChassisComponent component, ActivatableUIOpenAttemptEvent args)
|
||||||
|
{
|
||||||
|
// borgs can't view their own ui
|
||||||
|
if (args.User == uid)
|
||||||
|
args.Cancel();
|
||||||
|
}
|
||||||
|
|
||||||
private void OnGetDeadIC(EntityUid uid, BorgChassisComponent component, ref GetCharactedDeadIcEvent args)
|
private void OnGetDeadIC(EntityUid uid, BorgChassisComponent component, ref GetCharactedDeadIcEvent args)
|
||||||
{
|
{
|
||||||
args.Dead = true;
|
args.Dead = true;
|
||||||
|
|||||||
@@ -28,9 +28,7 @@ public sealed class ImmovableRodRule : StationEventSystem<ImmovableRodRuleCompon
|
|||||||
|
|
||||||
if (proto.TryGetComponent<ImmovableRodComponent>(out var rod) && proto.TryGetComponent<TimedDespawnComponent>(out var despawn))
|
if (proto.TryGetComponent<ImmovableRodComponent>(out var rod) && proto.TryGetComponent<TimedDespawnComponent>(out var despawn))
|
||||||
{
|
{
|
||||||
if (!TryFindRandomTile(out _, out _, out _, out var targetCoords))
|
TryFindRandomTile(out _, out _, out _, out var targetCoords);
|
||||||
return;
|
|
||||||
|
|
||||||
var speed = RobustRandom.NextFloat(rod.MinSpeed, rod.MaxSpeed);
|
var speed = RobustRandom.NextFloat(rod.MinSpeed, rod.MaxSpeed);
|
||||||
var angle = RobustRandom.NextAngle();
|
var angle = RobustRandom.NextAngle();
|
||||||
var direction = angle.ToVec();
|
var direction = angle.ToVec();
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
using System.Linq;
|
using System.Linq;
|
||||||
using Content.Server.Administration.Logs;
|
using Content.Server.Administration.Logs;
|
||||||
using Content.Server.Ensnaring;
|
using Content.Server.Ensnaring;
|
||||||
|
using Content.Shared.CombatMode;
|
||||||
using Content.Shared.Cuffs;
|
using Content.Shared.Cuffs;
|
||||||
using Content.Shared.Cuffs.Components;
|
using Content.Shared.Cuffs.Components;
|
||||||
using Content.Shared.Database;
|
using Content.Shared.Database;
|
||||||
@@ -9,6 +10,7 @@ using Content.Shared.Ensnaring.Components;
|
|||||||
using Content.Shared.Hands.Components;
|
using Content.Shared.Hands.Components;
|
||||||
using Content.Shared.Hands.EntitySystems;
|
using Content.Shared.Hands.EntitySystems;
|
||||||
using Content.Shared.IdentityManagement;
|
using Content.Shared.IdentityManagement;
|
||||||
|
using Content.Shared.Interaction;
|
||||||
using Content.Shared.Interaction.Events;
|
using Content.Shared.Interaction.Events;
|
||||||
using Content.Shared.Inventory;
|
using Content.Shared.Inventory;
|
||||||
using Content.Shared.Inventory.VirtualItem;
|
using Content.Shared.Inventory.VirtualItem;
|
||||||
@@ -27,6 +29,7 @@ namespace Content.Server.Strip
|
|||||||
{
|
{
|
||||||
[Dependency] private readonly InventorySystem _inventorySystem = default!;
|
[Dependency] private readonly InventorySystem _inventorySystem = default!;
|
||||||
[Dependency] private readonly EnsnareableSystem _ensnaringSystem = default!;
|
[Dependency] private readonly EnsnareableSystem _ensnaringSystem = default!;
|
||||||
|
[Dependency] private readonly UserInterfaceSystem _userInterfaceSystem = default!;
|
||||||
|
|
||||||
[Dependency] private readonly SharedCuffableSystem _cuffableSystem = default!;
|
[Dependency] private readonly SharedCuffableSystem _cuffableSystem = default!;
|
||||||
[Dependency] private readonly SharedDoAfterSystem _doAfterSystem = default!;
|
[Dependency] private readonly SharedDoAfterSystem _doAfterSystem = default!;
|
||||||
@@ -43,6 +46,7 @@ namespace Content.Server.Strip
|
|||||||
|
|
||||||
SubscribeLocalEvent<StrippableComponent, GetVerbsEvent<Verb>>(AddStripVerb);
|
SubscribeLocalEvent<StrippableComponent, GetVerbsEvent<Verb>>(AddStripVerb);
|
||||||
SubscribeLocalEvent<StrippableComponent, GetVerbsEvent<ExamineVerb>>(AddStripExamineVerb);
|
SubscribeLocalEvent<StrippableComponent, GetVerbsEvent<ExamineVerb>>(AddStripExamineVerb);
|
||||||
|
SubscribeLocalEvent<StrippableComponent, ActivateInWorldEvent>(OnActivateInWorld);
|
||||||
|
|
||||||
// BUI
|
// BUI
|
||||||
SubscribeLocalEvent<StrippableComponent, StrippingSlotButtonPressed>(OnStripButtonPressed);
|
SubscribeLocalEvent<StrippableComponent, StrippingSlotButtonPressed>(OnStripButtonPressed);
|
||||||
@@ -65,7 +69,7 @@ namespace Content.Server.Strip
|
|||||||
{
|
{
|
||||||
Text = Loc.GetString("strip-verb-get-data-text"),
|
Text = Loc.GetString("strip-verb-get-data-text"),
|
||||||
Icon = new SpriteSpecifier.Texture(new("/Textures/Interface/VerbIcons/outfit.svg.192dpi.png")),
|
Icon = new SpriteSpecifier.Texture(new("/Textures/Interface/VerbIcons/outfit.svg.192dpi.png")),
|
||||||
Act = () => TryOpenStrippingUi(args.User, (uid, component), true),
|
Act = () => StartOpeningStripper(args.User, (uid, component), true),
|
||||||
};
|
};
|
||||||
|
|
||||||
args.Verbs.Add(verb);
|
args.Verbs.Add(verb);
|
||||||
@@ -83,13 +87,37 @@ namespace Content.Server.Strip
|
|||||||
{
|
{
|
||||||
Text = Loc.GetString("strip-verb-get-data-text"),
|
Text = Loc.GetString("strip-verb-get-data-text"),
|
||||||
Icon = new SpriteSpecifier.Texture(new("/Textures/Interface/VerbIcons/outfit.svg.192dpi.png")),
|
Icon = new SpriteSpecifier.Texture(new("/Textures/Interface/VerbIcons/outfit.svg.192dpi.png")),
|
||||||
Act = () => TryOpenStrippingUi(args.User, (uid, component), true),
|
Act = () => StartOpeningStripper(args.User, (uid, component), true),
|
||||||
Category = VerbCategory.Examine,
|
Category = VerbCategory.Examine,
|
||||||
};
|
};
|
||||||
|
|
||||||
args.Verbs.Add(verb);
|
args.Verbs.Add(verb);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void OnActivateInWorld(EntityUid uid, StrippableComponent component, ActivateInWorldEvent args)
|
||||||
|
{
|
||||||
|
if (args.Target == args.User)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!HasComp<ActorComponent>(args.User))
|
||||||
|
return;
|
||||||
|
|
||||||
|
StartOpeningStripper(args.User, (uid, component));
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void StartOpeningStripper(EntityUid user, Entity<StrippableComponent> strippable, bool openInCombat = false)
|
||||||
|
{
|
||||||
|
base.StartOpeningStripper(user, strippable, openInCombat);
|
||||||
|
|
||||||
|
if (TryComp<CombatModeComponent>(user, out var mode) && mode.IsInCombatMode && !openInCombat)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (HasComp<StrippingComponent>(user))
|
||||||
|
{
|
||||||
|
_userInterfaceSystem.OpenUi(strippable.Owner, StrippingUiKey.Key, user);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void OnStripButtonPressed(Entity<StrippableComponent> strippable, ref StrippingSlotButtonPressed args)
|
private void OnStripButtonPressed(Entity<StrippableComponent> strippable, ref StrippingSlotButtonPressed args)
|
||||||
{
|
{
|
||||||
if (args.Actor is not { Valid: true } user ||
|
if (args.Actor is not { Valid: true } user ||
|
||||||
|
|||||||
@@ -187,10 +187,15 @@ public sealed class MeleeWeaponSystem : SharedMeleeWeaponSystem
|
|||||||
if (session is { } pSession)
|
if (session is { } pSession)
|
||||||
{
|
{
|
||||||
(targetCoordinates, targetLocalAngle) = _lag.GetCoordinatesAngle(target, pSession);
|
(targetCoordinates, targetLocalAngle) = _lag.GetCoordinatesAngle(target, pSession);
|
||||||
return Interaction.InRangeUnobstructed(user, target, targetCoordinates, targetLocalAngle, range);
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var xform = Transform(target);
|
||||||
|
targetCoordinates = xform.Coordinates;
|
||||||
|
targetLocalAngle = xform.LocalRotation;
|
||||||
}
|
}
|
||||||
|
|
||||||
return Interaction.InRangeUnobstructed(user, target, range);
|
return Interaction.InRangeUnobstructed(user, target, targetCoordinates, targetLocalAngle, range);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void DoDamageEffect(List<EntityUid> targets, EntityUid? user, TransformComponent targetXform)
|
protected override void DoDamageEffect(List<EntityUid> targets, EntityUid? user, TransformComponent targetXform)
|
||||||
|
|||||||
@@ -1,17 +1,15 @@
|
|||||||
using Robust.Shared.GameStates;
|
namespace Content.Server.Wires;
|
||||||
|
|
||||||
namespace Content.Shared.Wires;
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// This is used for activatable UIs that require the entity to have a panel in a certain state.
|
/// This is used for activatable UIs that require the entity to have a panel in a certain state.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[RegisterComponent, NetworkedComponent, Access(typeof(SharedWiresSystem))]
|
[RegisterComponent]
|
||||||
public sealed partial class ActivatableUIRequiresPanelComponent : Component
|
public sealed partial class ActivatableUIRequiresPanelComponent : Component
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// TRUE: the panel must be open to access the UI.
|
/// TRUE: the panel must be open to access the UI.
|
||||||
/// FALSE: the panel must be closed to access the UI.
|
/// FALSE: the panel must be closed to access the UI.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[DataField]
|
[DataField("requireOpen"), ViewVariables(VVAccess.ReadWrite)]
|
||||||
public bool RequireOpen = true;
|
public bool RequireOpen = true;
|
||||||
}
|
}
|
||||||
@@ -4,23 +4,27 @@ using System.Threading;
|
|||||||
using Content.Server.Construction;
|
using Content.Server.Construction;
|
||||||
using Content.Server.Construction.Components;
|
using Content.Server.Construction.Components;
|
||||||
using Content.Server.Power.Components;
|
using Content.Server.Power.Components;
|
||||||
|
using Content.Server.UserInterface;
|
||||||
using Content.Shared.DoAfter;
|
using Content.Shared.DoAfter;
|
||||||
using Content.Shared.GameTicking;
|
using Content.Shared.GameTicking;
|
||||||
using Content.Shared.Hands.Components;
|
using Content.Shared.Hands.Components;
|
||||||
using Content.Shared.Interaction;
|
using Content.Shared.Interaction;
|
||||||
using Content.Shared.Popups;
|
using Content.Shared.Popups;
|
||||||
using Content.Shared.Tools.Components;
|
using Content.Shared.Tools.Components;
|
||||||
|
using Content.Shared.UserInterface;
|
||||||
using Content.Shared.Wires;
|
using Content.Shared.Wires;
|
||||||
using Robust.Server.GameObjects;
|
using Robust.Server.GameObjects;
|
||||||
using Robust.Shared.Player;
|
using Robust.Shared.Player;
|
||||||
using Robust.Shared.Prototypes;
|
using Robust.Shared.Prototypes;
|
||||||
using Robust.Shared.Random;
|
using Robust.Shared.Random;
|
||||||
|
using ActivatableUISystem = Content.Shared.UserInterface.ActivatableUISystem;
|
||||||
|
|
||||||
namespace Content.Server.Wires;
|
namespace Content.Server.Wires;
|
||||||
|
|
||||||
public sealed class WiresSystem : SharedWiresSystem
|
public sealed class WiresSystem : SharedWiresSystem
|
||||||
{
|
{
|
||||||
[Dependency] private readonly IPrototypeManager _protoMan = default!;
|
[Dependency] private readonly IPrototypeManager _protoMan = default!;
|
||||||
|
[Dependency] private readonly ActivatableUISystem _activatableUI = default!;
|
||||||
[Dependency] private readonly SharedDoAfterSystem _doAfter = default!;
|
[Dependency] private readonly SharedDoAfterSystem _doAfter = default!;
|
||||||
[Dependency] private readonly SharedPopupSystem _popupSystem = default!;
|
[Dependency] private readonly SharedPopupSystem _popupSystem = default!;
|
||||||
[Dependency] private readonly SharedInteractionSystem _interactionSystem = default!;
|
[Dependency] private readonly SharedInteractionSystem _interactionSystem = default!;
|
||||||
@@ -48,6 +52,8 @@ public sealed class WiresSystem : SharedWiresSystem
|
|||||||
SubscribeLocalEvent<WiresComponent, TimedWireEvent>(OnTimedWire);
|
SubscribeLocalEvent<WiresComponent, TimedWireEvent>(OnTimedWire);
|
||||||
SubscribeLocalEvent<WiresComponent, PowerChangedEvent>(OnWiresPowered);
|
SubscribeLocalEvent<WiresComponent, PowerChangedEvent>(OnWiresPowered);
|
||||||
SubscribeLocalEvent<WiresComponent, WireDoAfterEvent>(OnDoAfter);
|
SubscribeLocalEvent<WiresComponent, WireDoAfterEvent>(OnDoAfter);
|
||||||
|
SubscribeLocalEvent<ActivatableUIRequiresPanelComponent, ActivatableUIOpenAttemptEvent>(OnAttemptOpenActivatableUI);
|
||||||
|
SubscribeLocalEvent<ActivatableUIRequiresPanelComponent, PanelChangedEvent>(OnActivatableUIPanelChanged);
|
||||||
SubscribeLocalEvent<WiresPanelSecurityComponent, WiresPanelSecurityEvent>(SetWiresPanelSecurity);
|
SubscribeLocalEvent<WiresPanelSecurityComponent, WiresPanelSecurityEvent>(SetWiresPanelSecurity);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -467,6 +473,23 @@ public sealed class WiresSystem : SharedWiresSystem
|
|||||||
_uiSystem.CloseUi(ent.Owner, WiresUiKey.Key);
|
_uiSystem.CloseUi(ent.Owner, WiresUiKey.Key);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void OnAttemptOpenActivatableUI(EntityUid uid, ActivatableUIRequiresPanelComponent component, ActivatableUIOpenAttemptEvent args)
|
||||||
|
{
|
||||||
|
if (args.Cancelled || !TryComp<WiresPanelComponent>(uid, out var wires))
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (component.RequireOpen != wires.Open)
|
||||||
|
args.Cancel();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnActivatableUIPanelChanged(EntityUid uid, ActivatableUIRequiresPanelComponent component, ref PanelChangedEvent args)
|
||||||
|
{
|
||||||
|
if (args.Open == component.RequireOpen)
|
||||||
|
return;
|
||||||
|
|
||||||
|
_activatableUI.CloseAll(uid);
|
||||||
|
}
|
||||||
|
|
||||||
private void OnMapInit(EntityUid uid, WiresComponent component, MapInitEvent args)
|
private void OnMapInit(EntityUid uid, WiresComponent component, MapInitEvent args)
|
||||||
{
|
{
|
||||||
if (!string.IsNullOrEmpty(component.LayoutId))
|
if (!string.IsNullOrEmpty(component.LayoutId))
|
||||||
|
|||||||
@@ -1,13 +1,12 @@
|
|||||||
using Content.Shared.Damage;
|
using Content.Shared.Damage;
|
||||||
using Robust.Shared.GameStates;
|
|
||||||
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom;
|
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom;
|
||||||
|
|
||||||
namespace Content.Shared.Zombies;
|
namespace Content.Server.Zombies;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Temporary because diseases suck.
|
/// Temporary because diseases suck.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[RegisterComponent, NetworkedComponent]
|
[RegisterComponent]
|
||||||
public sealed partial class PendingZombieComponent : Component
|
public sealed partial class PendingZombieComponent : Component
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -39,7 +39,7 @@ public sealed class WizardRuleSystem : GameRuleSystem<WizardRuleComponent>
|
|||||||
|
|
||||||
private void OnObjectivesTextGetInfo(Entity<WizardRuleComponent> ent, ref ObjectivesTextGetInfoEvent args)
|
private void OnObjectivesTextGetInfo(Entity<WizardRuleComponent> ent, ref ObjectivesTextGetInfoEvent args)
|
||||||
{
|
{
|
||||||
args.Minds = ent.Comp.WizardMinds.Select(mindId => (mindId, Comp<MindComponent>(mindId).CharacterName ?? "?")).ToList();
|
args.Minds = ent.Comp.WizardMinds;
|
||||||
args.AgentName = Loc.GetString("wizard-round-end-agent-name");
|
args.AgentName = Loc.GetString("wizard-round-end-agent-name");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -508,7 +508,13 @@ public abstract class SharedActionsSystem : EntitySystem
|
|||||||
return distance <= action.Range;
|
return distance <= action.Range;
|
||||||
}
|
}
|
||||||
|
|
||||||
return _interactionSystem.InRangeAndAccessible(user, target, range: action.Range);
|
if (_interactionSystem.InRangeUnobstructed(user, target, range: action.Range)
|
||||||
|
&& _containerSystem.IsInSameOrParentContainer(user, target))
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return _interactionSystem.CanAccessViaStorage(user, target);
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool ValidateWorldTarget(EntityUid user, EntityCoordinates coords, Entity<WorldTargetActionComponent> action)
|
public bool ValidateWorldTarget(EntityUid user, EntityCoordinates coords, Entity<WorldTargetActionComponent> action)
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
using Robust.Shared.GameStates;
|
using Robust.Shared.GameStates;
|
||||||
using Robust.Shared.Serialization;
|
using Robust.Shared.Serialization;
|
||||||
using Robust.Shared.Timing;
|
using Robust.Shared.Timing;
|
||||||
|
using Robust.Shared.Utility;
|
||||||
|
|
||||||
namespace Content.Shared.Atmos.Components;
|
namespace Content.Shared.Atmos.Components;
|
||||||
|
|
||||||
@@ -23,47 +24,55 @@ public sealed partial class GasTileOverlayComponent : Component
|
|||||||
public GameTick ForceTick { get; set; }
|
public GameTick ForceTick { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
[Serializable, NetSerializable]
|
|
||||||
public sealed class GasTileOverlayState(Dictionary<Vector2i, GasOverlayChunk> chunks) : ComponentState
|
|
||||||
{
|
|
||||||
public readonly Dictionary<Vector2i, GasOverlayChunk> Chunks = chunks;
|
|
||||||
}
|
|
||||||
|
|
||||||
[Serializable, NetSerializable]
|
[Serializable, NetSerializable]
|
||||||
public sealed class GasTileOverlayDeltaState(
|
public sealed class GasTileOverlayState : ComponentState, IComponentDeltaState
|
||||||
Dictionary<Vector2i, GasOverlayChunk> modifiedChunks,
|
|
||||||
HashSet<Vector2i> allChunks)
|
|
||||||
: ComponentState, IComponentDeltaState<GasTileOverlayState>
|
|
||||||
{
|
{
|
||||||
public readonly Dictionary<Vector2i, GasOverlayChunk> ModifiedChunks = modifiedChunks;
|
public readonly Dictionary<Vector2i, GasOverlayChunk> Chunks;
|
||||||
public readonly HashSet<Vector2i> AllChunks = allChunks;
|
public bool FullState => AllChunks == null;
|
||||||
|
|
||||||
public void ApplyToFullState(GasTileOverlayState state)
|
// required to infer deleted/missing chunks for delta states
|
||||||
|
public HashSet<Vector2i>? AllChunks;
|
||||||
|
|
||||||
|
public GasTileOverlayState(Dictionary<Vector2i, GasOverlayChunk> chunks)
|
||||||
{
|
{
|
||||||
|
Chunks = chunks;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ApplyToFullState(IComponentState fullState)
|
||||||
|
{
|
||||||
|
DebugTools.Assert(!FullState);
|
||||||
|
var state = (GasTileOverlayState) fullState;
|
||||||
|
DebugTools.Assert(state.FullState);
|
||||||
|
|
||||||
foreach (var key in state.Chunks.Keys)
|
foreach (var key in state.Chunks.Keys)
|
||||||
{
|
{
|
||||||
if (!AllChunks.Contains(key))
|
if (!AllChunks!.Contains(key))
|
||||||
state.Chunks.Remove(key);
|
state.Chunks.Remove(key);
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (var (chunk, data) in ModifiedChunks)
|
foreach (var (chunk, data) in Chunks)
|
||||||
{
|
{
|
||||||
state.Chunks[chunk] = new(data);
|
state.Chunks[chunk] = new(data);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public GasTileOverlayState CreateNewFullState(GasTileOverlayState state)
|
public IComponentState CreateNewFullState(IComponentState fullState)
|
||||||
{
|
{
|
||||||
var chunks = new Dictionary<Vector2i, GasOverlayChunk>(AllChunks.Count);
|
DebugTools.Assert(!FullState);
|
||||||
|
var state = (GasTileOverlayState) fullState;
|
||||||
|
DebugTools.Assert(state.FullState);
|
||||||
|
|
||||||
foreach (var (chunk, data) in ModifiedChunks)
|
var chunks = new Dictionary<Vector2i, GasOverlayChunk>(state.Chunks.Count);
|
||||||
|
|
||||||
|
foreach (var (chunk, data) in Chunks)
|
||||||
{
|
{
|
||||||
chunks[chunk] = new(data);
|
chunks[chunk] = new(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (var (chunk, data) in state.Chunks)
|
foreach (var (chunk, data) in state.Chunks)
|
||||||
{
|
{
|
||||||
if (AllChunks.Contains(chunk))
|
if (AllChunks!.Contains(chunk))
|
||||||
chunks.TryAdd(chunk, new(data));
|
chunks.TryAdd(chunk, new(data));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -55,7 +55,7 @@ namespace Content.Shared.Atmos.EntitySystems
|
|||||||
data[index] = chunk;
|
data[index] = chunk;
|
||||||
}
|
}
|
||||||
|
|
||||||
args.State = new GasTileOverlayDeltaState(data, new(component.Chunks.Keys));
|
args.State = new GasTileOverlayState(data) { AllChunks = new(component.Chunks.Keys) };
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Vector2i GetGasChunkIndices(Vector2i indices)
|
public static Vector2i GetGasChunkIndices(Vector2i indices)
|
||||||
|
|||||||
@@ -58,7 +58,7 @@ public abstract partial class SharedBuckleSystem
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
var strapPosition = Transform(strapUid).Coordinates;
|
var strapPosition = Transform(strapUid).Coordinates;
|
||||||
if (ev.NewPosition.EntityId.IsValid() && ev.NewPosition.InRange(EntityManager, _transform, strapPosition, strapComp.MaxBuckleDistance))
|
if (ev.NewPosition.InRange(EntityManager, _transform, strapPosition, strapComp.MaxBuckleDistance))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
TryUnbuckle(uid, uid, true, component);
|
TryUnbuckle(uid, uid, true, component);
|
||||||
|
|||||||
@@ -5,6 +5,8 @@ using Content.Shared.StatusIcon;
|
|||||||
using Robust.Shared.GameStates;
|
using Robust.Shared.GameStates;
|
||||||
using Robust.Shared.Prototypes;
|
using Robust.Shared.Prototypes;
|
||||||
using Robust.Shared.Serialization;
|
using Robust.Shared.Serialization;
|
||||||
|
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype;
|
||||||
|
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype.List;
|
||||||
|
|
||||||
namespace Content.Shared.Damage
|
namespace Content.Shared.Damage
|
||||||
{
|
{
|
||||||
@@ -16,7 +18,7 @@ namespace Content.Shared.Damage
|
|||||||
/// may also have resistances to certain damage types, defined via a <see cref="DamageModifierSetPrototype"/>.
|
/// may also have resistances to certain damage types, defined via a <see cref="DamageModifierSetPrototype"/>.
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
[RegisterComponent]
|
[RegisterComponent]
|
||||||
[NetworkedComponent]
|
[NetworkedComponent()]
|
||||||
[Access(typeof(DamageableSystem), Other = AccessPermissions.ReadExecute)]
|
[Access(typeof(DamageableSystem), Other = AccessPermissions.ReadExecute)]
|
||||||
public sealed partial class DamageableComponent : Component
|
public sealed partial class DamageableComponent : Component
|
||||||
{
|
{
|
||||||
@@ -24,8 +26,8 @@ namespace Content.Shared.Damage
|
|||||||
/// This <see cref="DamageContainerPrototype"/> specifies what damage types are supported by this component.
|
/// This <see cref="DamageContainerPrototype"/> specifies what damage types are supported by this component.
|
||||||
/// If null, all damage types will be supported.
|
/// If null, all damage types will be supported.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[DataField("damageContainer")]
|
[DataField("damageContainer", customTypeSerializer: typeof(PrototypeIdSerializer<DamageContainerPrototype>))]
|
||||||
public ProtoId<DamageContainerPrototype>? DamageContainerID;
|
public string? DamageContainerID;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// This <see cref="DamageModifierSetPrototype"/> will be applied to any damage that is dealt to this container,
|
/// This <see cref="DamageModifierSetPrototype"/> will be applied to any damage that is dealt to this container,
|
||||||
@@ -35,8 +37,8 @@ namespace Content.Shared.Damage
|
|||||||
/// Though DamageModifierSets can be deserialized directly, we only want to use the prototype version here
|
/// Though DamageModifierSets can be deserialized directly, we only want to use the prototype version here
|
||||||
/// to reduce duplication.
|
/// to reduce duplication.
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
[DataField("damageModifierSet")]
|
[DataField("damageModifierSet", customTypeSerializer: typeof(PrototypeIdSerializer<DamageModifierSetPrototype>))]
|
||||||
public ProtoId<DamageModifierSetPrototype>? DamageModifierSetId;
|
public string? DamageModifierSetId;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// All the damage information is stored in this <see cref="DamageSpecifier"/>.
|
/// All the damage information is stored in this <see cref="DamageSpecifier"/>.
|
||||||
@@ -44,7 +46,7 @@ namespace Content.Shared.Damage
|
|||||||
/// <remarks>
|
/// <remarks>
|
||||||
/// If this data-field is specified, this allows damageable components to be initialized with non-zero damage.
|
/// If this data-field is specified, this allows damageable components to be initialized with non-zero damage.
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
[DataField(readOnly: true)] //todo remove this readonly when implementing writing to damagespecifier
|
[DataField("damage", readOnly: true)] //todo remove this readonly when implementing writing to damagespecifier
|
||||||
public DamageSpecifier Damage = new();
|
public DamageSpecifier Damage = new();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -62,8 +64,8 @@ namespace Content.Shared.Damage
|
|||||||
[ViewVariables]
|
[ViewVariables]
|
||||||
public FixedPoint2 TotalDamage;
|
public FixedPoint2 TotalDamage;
|
||||||
|
|
||||||
[DataField("radiationDamageTypes")]
|
[DataField("radiationDamageTypes", customTypeSerializer: typeof(PrototypeIdListSerializer<DamageTypePrototype>))]
|
||||||
public List<ProtoId<DamageTypePrototype>> RadiationDamageTypeIDs = new() { "Radiation" };
|
public List<string> RadiationDamageTypeIDs = new() { "Radiation" };
|
||||||
|
|
||||||
[DataField]
|
[DataField]
|
||||||
public Dictionary<MobState, ProtoId<StatusIconPrototype>> HealthIcons = new()
|
public Dictionary<MobState, ProtoId<StatusIconPrototype>> HealthIcons = new()
|
||||||
@@ -75,9 +77,6 @@ namespace Content.Shared.Damage
|
|||||||
|
|
||||||
[DataField]
|
[DataField]
|
||||||
public ProtoId<StatusIconPrototype> RottingIcon = "HealthIconRotting";
|
public ProtoId<StatusIconPrototype> RottingIcon = "HealthIconRotting";
|
||||||
|
|
||||||
[DataField]
|
|
||||||
public FixedPoint2? HealthBarThreshold;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[Serializable, NetSerializable]
|
[Serializable, NetSerializable]
|
||||||
@@ -85,16 +84,13 @@ namespace Content.Shared.Damage
|
|||||||
{
|
{
|
||||||
public readonly Dictionary<string, FixedPoint2> DamageDict;
|
public readonly Dictionary<string, FixedPoint2> DamageDict;
|
||||||
public readonly string? ModifierSetId;
|
public readonly string? ModifierSetId;
|
||||||
public readonly FixedPoint2? HealthBarThreshold;
|
|
||||||
|
|
||||||
public DamageableComponentState(
|
public DamageableComponentState(
|
||||||
Dictionary<string, FixedPoint2> damageDict,
|
Dictionary<string, FixedPoint2> damageDict,
|
||||||
string? modifierSetId,
|
string? modifierSetId)
|
||||||
FixedPoint2? healthBarThreshold)
|
|
||||||
{
|
{
|
||||||
DamageDict = damageDict;
|
DamageDict = damageDict;
|
||||||
ModifierSetId = modifierSetId;
|
ModifierSetId = modifierSetId;
|
||||||
HealthBarThreshold = healthBarThreshold;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using Content.Shared.Administration.Logs;
|
||||||
using Content.Shared.Damage.Prototypes;
|
using Content.Shared.Damage.Prototypes;
|
||||||
using Content.Shared.FixedPoint;
|
using Content.Shared.FixedPoint;
|
||||||
using Content.Shared.Inventory;
|
using Content.Shared.Inventory;
|
||||||
@@ -239,12 +240,12 @@ namespace Content.Shared.Damage
|
|||||||
{
|
{
|
||||||
if (_netMan.IsServer)
|
if (_netMan.IsServer)
|
||||||
{
|
{
|
||||||
args.State = new DamageableComponentState(component.Damage.DamageDict, component.DamageModifierSetId, component.HealthBarThreshold);
|
args.State = new DamageableComponentState(component.Damage.DamageDict, component.DamageModifierSetId);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// avoid mispredicting damage on newly spawned entities.
|
// avoid mispredicting damage on newly spawned entities.
|
||||||
args.State = new DamageableComponentState(component.Damage.DamageDict.ShallowClone(), component.DamageModifierSetId, component.HealthBarThreshold);
|
args.State = new DamageableComponentState(component.Damage.DamageDict.ShallowClone(), component.DamageModifierSetId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -278,7 +279,6 @@ namespace Content.Shared.Damage
|
|||||||
}
|
}
|
||||||
|
|
||||||
component.DamageModifierSetId = state.ModifierSetId;
|
component.DamageModifierSetId = state.ModifierSetId;
|
||||||
component.HealthBarThreshold = state.HealthBarThreshold;
|
|
||||||
|
|
||||||
// Has the damage actually changed?
|
// Has the damage actually changed?
|
||||||
DamageSpecifier newDamage = new() { DamageDict = new(state.DamageDict) };
|
DamageSpecifier newDamage = new() { DamageDict = new(state.DamageDict) };
|
||||||
|
|||||||
@@ -62,37 +62,46 @@ namespace Content.Shared.Decals
|
|||||||
}
|
}
|
||||||
|
|
||||||
[Serializable, NetSerializable]
|
[Serializable, NetSerializable]
|
||||||
public sealed class DecalGridState(Dictionary<Vector2i, DecalChunk> chunks) : ComponentState
|
public sealed class DecalGridState : ComponentState, IComponentDeltaState
|
||||||
{
|
{
|
||||||
public Dictionary<Vector2i, DecalChunk> Chunks = chunks;
|
public Dictionary<Vector2i, DecalChunk> Chunks;
|
||||||
}
|
public bool FullState => AllChunks == null;
|
||||||
|
|
||||||
[Serializable, NetSerializable]
|
// required to infer deleted/missing chunks for delta states
|
||||||
public sealed class DecalGridDeltaState(Dictionary<Vector2i, DecalChunk> modifiedChunks, HashSet<Vector2i> allChunks)
|
public HashSet<Vector2i>? AllChunks;
|
||||||
: ComponentState, IComponentDeltaState<DecalGridState>
|
|
||||||
{
|
|
||||||
public Dictionary<Vector2i, DecalChunk> ModifiedChunks = modifiedChunks;
|
|
||||||
public HashSet<Vector2i> AllChunks = allChunks;
|
|
||||||
|
|
||||||
public void ApplyToFullState(DecalGridState state)
|
public DecalGridState(Dictionary<Vector2i, DecalChunk> chunks)
|
||||||
{
|
{
|
||||||
|
Chunks = chunks;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ApplyToFullState(IComponentState fullState)
|
||||||
|
{
|
||||||
|
DebugTools.Assert(!FullState);
|
||||||
|
var state = (DecalGridState) fullState;
|
||||||
|
DebugTools.Assert(state.FullState);
|
||||||
|
|
||||||
foreach (var key in state.Chunks.Keys)
|
foreach (var key in state.Chunks.Keys)
|
||||||
{
|
{
|
||||||
if (!AllChunks!.Contains(key))
|
if (!AllChunks!.Contains(key))
|
||||||
state.Chunks.Remove(key);
|
state.Chunks.Remove(key);
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (var (chunk, data) in ModifiedChunks)
|
foreach (var (chunk, data) in Chunks)
|
||||||
{
|
{
|
||||||
state.Chunks[chunk] = new(data);
|
state.Chunks[chunk] = new(data);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public DecalGridState CreateNewFullState(DecalGridState state)
|
public IComponentState CreateNewFullState(IComponentState fullState)
|
||||||
{
|
{
|
||||||
|
DebugTools.Assert(!FullState);
|
||||||
|
var state = (DecalGridState) fullState;
|
||||||
|
DebugTools.Assert(state.FullState);
|
||||||
|
|
||||||
var chunks = new Dictionary<Vector2i, DecalChunk>(state.Chunks.Count);
|
var chunks = new Dictionary<Vector2i, DecalChunk>(state.Chunks.Count);
|
||||||
|
|
||||||
foreach (var (chunk, data) in ModifiedChunks)
|
foreach (var (chunk, data) in Chunks)
|
||||||
{
|
{
|
||||||
chunks[chunk] = new(data);
|
chunks[chunk] = new(data);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -49,7 +49,7 @@ namespace Content.Shared.Decals
|
|||||||
data[index] = chunk;
|
data[index] = chunk;
|
||||||
}
|
}
|
||||||
|
|
||||||
args.State = new DecalGridDeltaState(data, new(component.ChunkCollection.ChunkCollection.Keys));
|
args.State = new DecalGridState(data) { AllChunks = new(component.ChunkCollection.ChunkCollection.Keys) };
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnGridInitialize(GridInitializeEvent msg)
|
private void OnGridInitialize(GridInitializeEvent msg)
|
||||||
|
|||||||
@@ -1,10 +1,11 @@
|
|||||||
using System.Diagnostics.CodeAnalysis;
|
using System.Diagnostics.CodeAnalysis;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using Content.Shared.ActionBlocker;
|
using Content.Shared.ActionBlocker;
|
||||||
|
using Content.Shared.Administration;
|
||||||
using Content.Shared.Administration.Logs;
|
using Content.Shared.Administration.Logs;
|
||||||
|
using Content.Shared.Administration.Managers;
|
||||||
using Content.Shared.CombatMode;
|
using Content.Shared.CombatMode;
|
||||||
using Content.Shared.Database;
|
using Content.Shared.Database;
|
||||||
using Content.Shared.Ghost;
|
|
||||||
using Content.Shared.Hands;
|
using Content.Shared.Hands;
|
||||||
using Content.Shared.Hands.Components;
|
using Content.Shared.Hands.Components;
|
||||||
using Content.Shared.Input;
|
using Content.Shared.Input;
|
||||||
@@ -14,20 +15,16 @@ using Content.Shared.Inventory;
|
|||||||
using Content.Shared.Inventory.Events;
|
using Content.Shared.Inventory.Events;
|
||||||
using Content.Shared.Item;
|
using Content.Shared.Item;
|
||||||
using Content.Shared.Movement.Components;
|
using Content.Shared.Movement.Components;
|
||||||
|
using Content.Shared.Movement.Pulling.Components;
|
||||||
using Content.Shared.Movement.Pulling.Systems;
|
using Content.Shared.Movement.Pulling.Systems;
|
||||||
using Content.Shared.Physics;
|
using Content.Shared.Physics;
|
||||||
using Content.Shared.Popups;
|
using Content.Shared.Popups;
|
||||||
using Content.Shared.Storage;
|
|
||||||
using Content.Shared.Tag;
|
using Content.Shared.Tag;
|
||||||
using Content.Shared.Timing;
|
using Content.Shared.Timing;
|
||||||
using Content.Shared.UserInterface;
|
|
||||||
using Content.Shared.Verbs;
|
using Content.Shared.Verbs;
|
||||||
using Content.Shared.Wall;
|
using Content.Shared.Wall;
|
||||||
using Content.Shared.Weapons.Ranged.Components;
|
using Content.Shared.Weapons.Ranged.Components;
|
||||||
using Content.Shared._White.MeatyOre;
|
using Content.Shared._White.MeatyOre;
|
||||||
using Content.Shared.Ghost;
|
|
||||||
using Content.Shared.Storage;
|
|
||||||
using Content.Shared.UserInterface;
|
|
||||||
using JetBrains.Annotations;
|
using JetBrains.Annotations;
|
||||||
using Robust.Shared.Containers;
|
using Robust.Shared.Containers;
|
||||||
using Robust.Shared.Input;
|
using Robust.Shared.Input;
|
||||||
@@ -41,8 +38,6 @@ using Robust.Shared.Player;
|
|||||||
using Robust.Shared.Random;
|
using Robust.Shared.Random;
|
||||||
using Robust.Shared.Serialization;
|
using Robust.Shared.Serialization;
|
||||||
using Robust.Shared.Timing;
|
using Robust.Shared.Timing;
|
||||||
using Robust.Shared.Utility;
|
|
||||||
using Robust.Shared.Utility;
|
|
||||||
|
|
||||||
#pragma warning disable 618
|
#pragma warning disable 618
|
||||||
|
|
||||||
@@ -57,11 +52,12 @@ namespace Content.Shared.Interaction
|
|||||||
[Dependency] private readonly IGameTiming _gameTiming = default!;
|
[Dependency] private readonly IGameTiming _gameTiming = default!;
|
||||||
[Dependency] private readonly INetManager _net = default!;
|
[Dependency] private readonly INetManager _net = default!;
|
||||||
[Dependency] private readonly IMapManager _mapManager = default!;
|
[Dependency] private readonly IMapManager _mapManager = default!;
|
||||||
|
[Dependency] private readonly ISharedAdminManager _adminManager = default!;
|
||||||
[Dependency] private readonly ISharedAdminLogManager _adminLogger = default!;
|
[Dependency] private readonly ISharedAdminLogManager _adminLogger = default!;
|
||||||
[Dependency] private readonly ActionBlockerSystem _actionBlockerSystem = default!;
|
[Dependency] private readonly ActionBlockerSystem _actionBlockerSystem = default!;
|
||||||
[Dependency] private readonly RotateToFaceSystem _rotateToFaceSystem = default!;
|
[Dependency] private readonly RotateToFaceSystem _rotateToFaceSystem = default!;
|
||||||
[Dependency] private readonly SharedContainerSystem _containerSystem = default!;
|
[Dependency] private readonly SharedContainerSystem _containerSystem = default!;
|
||||||
[Dependency] private readonly SharedPhysicsSystem _broadphase = default!;
|
[Dependency] private readonly SharedPhysicsSystem _sharedBroadphaseSystem = default!;
|
||||||
[Dependency] private readonly SharedTransformSystem _transform = default!;
|
[Dependency] private readonly SharedTransformSystem _transform = default!;
|
||||||
[Dependency] private readonly SharedVerbSystem _verbSystem = default!;
|
[Dependency] private readonly SharedVerbSystem _verbSystem = default!;
|
||||||
[Dependency] private readonly SharedPopupSystem _popupSystem = default!;
|
[Dependency] private readonly SharedPopupSystem _popupSystem = default!;
|
||||||
@@ -70,18 +66,6 @@ namespace Content.Shared.Interaction
|
|||||||
[Dependency] private readonly InventorySystem _inventory = default!;
|
[Dependency] private readonly InventorySystem _inventory = default!;
|
||||||
[Dependency] private readonly IRobustRandom _random = default!;
|
[Dependency] private readonly IRobustRandom _random = default!;
|
||||||
[Dependency] private readonly TagSystem _tagSystem = default!;
|
[Dependency] private readonly TagSystem _tagSystem = default!;
|
||||||
[Dependency] private readonly SharedUserInterfaceSystem _ui = default!;
|
|
||||||
|
|
||||||
private EntityQuery<IgnoreUIRangeComponent> _ignoreUiRangeQuery;
|
|
||||||
private EntityQuery<FixturesComponent> _fixtureQuery;
|
|
||||||
private EntityQuery<ItemComponent> _itemQuery;
|
|
||||||
private EntityQuery<PhysicsComponent> _physicsQuery;
|
|
||||||
private EntityQuery<HandsComponent> _handsQuery;
|
|
||||||
private EntityQuery<InteractionRelayComponent> _relayQuery;
|
|
||||||
private EntityQuery<CombatModeComponent> _combatQuery;
|
|
||||||
private EntityQuery<WallMountComponent> _wallMountQuery;
|
|
||||||
private EntityQuery<UseDelayComponent> _delayQuery;
|
|
||||||
private EntityQuery<ActivatableUIComponent> _uiQuery;
|
|
||||||
|
|
||||||
private const CollisionGroup InRangeUnobstructedMask = CollisionGroup.Impassable | CollisionGroup.InteractImpassable;
|
private const CollisionGroup InRangeUnobstructedMask = CollisionGroup.Impassable | CollisionGroup.InteractImpassable;
|
||||||
|
|
||||||
@@ -94,17 +78,6 @@ namespace Content.Shared.Interaction
|
|||||||
|
|
||||||
public override void Initialize()
|
public override void Initialize()
|
||||||
{
|
{
|
||||||
_ignoreUiRangeQuery = GetEntityQuery<IgnoreUIRangeComponent>();
|
|
||||||
_fixtureQuery = GetEntityQuery<FixturesComponent>();
|
|
||||||
_itemQuery = GetEntityQuery<ItemComponent>();
|
|
||||||
_physicsQuery = GetEntityQuery<PhysicsComponent>();
|
|
||||||
_handsQuery = GetEntityQuery<HandsComponent>();
|
|
||||||
_relayQuery = GetEntityQuery<InteractionRelayComponent>();
|
|
||||||
_combatQuery = GetEntityQuery<CombatModeComponent>();
|
|
||||||
_wallMountQuery = GetEntityQuery<WallMountComponent>();
|
|
||||||
_delayQuery = GetEntityQuery<UseDelayComponent>();
|
|
||||||
_uiQuery = GetEntityQuery<ActivatableUIComponent>();
|
|
||||||
|
|
||||||
SubscribeLocalEvent<BoundUserInterfaceCheckRangeEvent>(HandleUserInterfaceRangeCheck);
|
SubscribeLocalEvent<BoundUserInterfaceCheckRangeEvent>(HandleUserInterfaceRangeCheck);
|
||||||
SubscribeLocalEvent<BoundUserInterfaceMessageAttempt>(OnBoundInterfaceInteractAttempt);
|
SubscribeLocalEvent<BoundUserInterfaceMessageAttempt>(OnBoundInterfaceInteractAttempt);
|
||||||
|
|
||||||
@@ -140,57 +113,34 @@ namespace Content.Shared.Interaction
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
private void OnBoundInterfaceInteractAttempt(BoundUserInterfaceMessageAttempt ev)
|
private void OnBoundInterfaceInteractAttempt(BoundUserInterfaceMessageAttempt ev)
|
||||||
{
|
{
|
||||||
_uiQuery.TryComp(ev.Target, out var uiComp);
|
var user = ev.Actor;
|
||||||
if (!_actionBlockerSystem.CanInteract(ev.Actor, ev.Target))
|
|
||||||
{
|
|
||||||
// We permit ghosts to open uis unless explicitly blocked
|
|
||||||
if (ev.Message is not OpenBoundInterfaceMessage || !HasComp<GhostComponent>(ev.Actor) || uiComp?.BlockSpectators == true)
|
|
||||||
{
|
|
||||||
ev.Cancel();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var range = _ui.GetUiRange(ev.Target, ev.UiKey);
|
if (!_actionBlockerSystem.CanInteract(user, ev.Target))
|
||||||
|
|
||||||
// As long as range>0, the UI frame updates should have auto-closed the UI if it is out of range.
|
|
||||||
DebugTools.Assert(range <= 0 || UiRangeCheck(ev.Actor, ev.Target, range));
|
|
||||||
|
|
||||||
if (range <= 0 && !IsAccessible(ev.Actor, ev.Target))
|
|
||||||
{
|
{
|
||||||
ev.Cancel();
|
ev.Cancel();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (uiComp == null)
|
// Check if the bound entity is accessible. Note that we allow admins to ignore this restriction, so that
|
||||||
return;
|
// they can fiddle with UI's that people can't normally interact with (e.g., placing things directly into
|
||||||
|
// other people's backpacks).
|
||||||
if (uiComp.SingleUser && uiComp.CurrentSingleUser != ev.Actor)
|
if (!_containerSystem.IsInSameOrParentContainer(user, ev.Target)
|
||||||
|
&& !CanAccessViaStorage(user, ev.Target)
|
||||||
|
&& !_adminManager.HasAdminFlag(user, AdminFlags.Admin))
|
||||||
{
|
{
|
||||||
ev.Cancel();
|
ev.Cancel();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!uiComp.RequireHands)
|
if (CompOrNull<IgnorBUIInteractionRangeComponent>(ev.Target) != null)
|
||||||
|
{
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (!_handsQuery.TryComp(ev.Actor, out var hands) || hands.Hands.Count == 0)
|
if (!InRangeUnobstructed(user, ev.Target))
|
||||||
|
{
|
||||||
ev.Cancel();
|
ev.Cancel();
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool UiRangeCheck(Entity<TransformComponent?> user, Entity<TransformComponent?> target, float range)
|
|
||||||
{
|
|
||||||
if (!Resolve(target, ref target.Comp))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if (user.Owner == target.Owner)
|
|
||||||
return true;
|
|
||||||
|
|
||||||
// Fast check: if the user is the parent of the entity (e.g., holding it), we always assume that it is in range
|
|
||||||
if (target.Comp.ParentUid == user.Owner)
|
|
||||||
return true;
|
|
||||||
|
|
||||||
return InRangeAndAccessible(user, target, range) || _ignoreUiRangeQuery.HasComp(user);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -247,7 +197,10 @@ namespace Content.Shared.Interaction
|
|||||||
if (!InRangeUnobstructed(userEntity.Value, uid, popup: true))
|
if (!InRangeUnobstructed(userEntity.Value, uid, popup: true))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
_pullSystem.TogglePull(uid, userEntity.Value);
|
if (!TryComp(uid, out PullableComponent? pull))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
_pullSystem.TogglePull(uid, userEntity.Value, pull);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -323,7 +276,7 @@ namespace Content.Shared.Interaction
|
|||||||
public bool CombatModeCanHandInteract(EntityUid user, EntityUid? target)
|
public bool CombatModeCanHandInteract(EntityUid user, EntityUid? target)
|
||||||
{
|
{
|
||||||
// Always allow attack in these cases
|
// Always allow attack in these cases
|
||||||
if (target == null || !_handsQuery.TryComp(user, out var hands) || hands.ActiveHand?.HeldEntity is not null)
|
if (target == null || !TryComp<HandsComponent>(user, out var hands) || hands.ActiveHand?.HeldEntity is not null)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// Only eat input if:
|
// Only eat input if:
|
||||||
@@ -331,7 +284,7 @@ namespace Content.Shared.Interaction
|
|||||||
// - Target doesn't cancel should-interact event
|
// - Target doesn't cancel should-interact event
|
||||||
// This is intended to allow items to be picked up in combat mode,
|
// This is intended to allow items to be picked up in combat mode,
|
||||||
// but to also allow items to force attacks anyway (like mobs which are items, e.g. mice)
|
// but to also allow items to force attacks anyway (like mobs which are items, e.g. mice)
|
||||||
if (!_itemQuery.HasComp(target))
|
if (!HasComp<ItemComponent>(target))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
var combatEv = new CombatModeShouldHandInteractEvent();
|
var combatEv = new CombatModeShouldHandInteractEvent();
|
||||||
@@ -361,7 +314,7 @@ namespace Content.Shared.Interaction
|
|||||||
bool checkAccess = true,
|
bool checkAccess = true,
|
||||||
bool checkCanUse = true)
|
bool checkCanUse = true)
|
||||||
{
|
{
|
||||||
if (_relayQuery.TryComp(user, out var relay) && relay.RelayEntity is not null)
|
if (TryComp<InteractionRelayComponent>(user, out var relay) && relay.RelayEntity is not null)
|
||||||
{
|
{
|
||||||
// TODO this needs to be handled better. This probably bypasses many complex can-interact checks in weird roundabout ways.
|
// TODO this needs to be handled better. This probably bypasses many complex can-interact checks in weird roundabout ways.
|
||||||
if (_actionBlockerSystem.CanInteract(user, target))
|
if (_actionBlockerSystem.CanInteract(user, target))
|
||||||
@@ -375,7 +328,7 @@ namespace Content.Shared.Interaction
|
|||||||
if (target != null && Deleted(target.Value))
|
if (target != null && Deleted(target.Value))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (!altInteract && _combatQuery.TryComp(user, out var combatMode) && combatMode.IsInCombatMode)
|
if (!altInteract && TryComp<CombatModeComponent>(user, out var combatMode) && combatMode.IsInCombatMode)
|
||||||
{
|
{
|
||||||
if (!CombatModeCanHandInteract(user, target))
|
if (!CombatModeCanHandInteract(user, target))
|
||||||
return;
|
return;
|
||||||
@@ -397,7 +350,10 @@ namespace Content.Shared.Interaction
|
|||||||
|
|
||||||
// Check if interacted entity is in the same container, the direct child, or direct parent of the user.
|
// Check if interacted entity is in the same container, the direct child, or direct parent of the user.
|
||||||
// Also checks if the item is accessible via some storage UI (e.g., open backpack)
|
// Also checks if the item is accessible via some storage UI (e.g., open backpack)
|
||||||
if (checkAccess && target != null && !IsAccessible(user, target.Value))
|
if (checkAccess
|
||||||
|
&& target != null
|
||||||
|
&& !_containerSystem.IsInSameOrParentContainer(user, target.Value)
|
||||||
|
&& !CanAccessViaStorage(user, target.Value))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var inRangeUnobstructed = target == null
|
var inRangeUnobstructed = target == null
|
||||||
@@ -405,7 +361,7 @@ namespace Content.Shared.Interaction
|
|||||||
: !checkAccess || InRangeUnobstructed(user, target.Value); // permits interactions with wall mounted entities
|
: !checkAccess || InRangeUnobstructed(user, target.Value); // permits interactions with wall mounted entities
|
||||||
|
|
||||||
// Does the user have hands?
|
// Does the user have hands?
|
||||||
if (!_handsQuery.TryComp(user, out var hands) || hands.ActiveHand == null)
|
if (!TryComp<HandsComponent>(user, out var hands) || hands.ActiveHand == null)
|
||||||
{
|
{
|
||||||
var ev = new InteractNoHandEvent(user, target, coordinates);
|
var ev = new InteractNoHandEvent(user, target, coordinates);
|
||||||
RaiseLocalEvent(user, ev);
|
RaiseLocalEvent(user, ev);
|
||||||
@@ -545,7 +501,7 @@ namespace Content.Shared.Interaction
|
|||||||
|
|
||||||
predicate ??= _ => false;
|
predicate ??= _ => false;
|
||||||
var ray = new CollisionRay(origin.Position, dir.Normalized(), collisionMask);
|
var ray = new CollisionRay(origin.Position, dir.Normalized(), collisionMask);
|
||||||
var rayResults = _broadphase.IntersectRayWithPredicate(origin.MapId, ray, dir.Length(), predicate.Invoke, false).ToList();
|
var rayResults = _sharedBroadphaseSystem.IntersectRayWithPredicate(origin.MapId, ray, dir.Length(), predicate.Invoke, false).ToList();
|
||||||
|
|
||||||
if (rayResults.Count == 0)
|
if (rayResults.Count == 0)
|
||||||
return dir.Length();
|
return dir.Length();
|
||||||
@@ -608,29 +564,23 @@ namespace Content.Shared.Interaction
|
|||||||
}
|
}
|
||||||
|
|
||||||
var ray = new CollisionRay(origin.Position, dir.Normalized(), (int) collisionMask);
|
var ray = new CollisionRay(origin.Position, dir.Normalized(), (int) collisionMask);
|
||||||
var rayResults = _broadphase.IntersectRayWithPredicate(origin.MapId, ray, length, predicate.Invoke, false).ToList();
|
var rayResults = _sharedBroadphaseSystem.IntersectRayWithPredicate(origin.MapId, ray, length, predicate.Invoke, false).ToList();
|
||||||
|
|
||||||
return rayResults.Count == 0;
|
return rayResults.Count == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool InRangeUnobstructed(
|
public bool InRangeUnobstructed(
|
||||||
Entity<TransformComponent?> origin,
|
EntityUid origin,
|
||||||
Entity<TransformComponent?> other,
|
EntityUid other,
|
||||||
float range = InteractionRange,
|
float range = InteractionRange,
|
||||||
CollisionGroup collisionMask = InRangeUnobstructedMask,
|
CollisionGroup collisionMask = InRangeUnobstructedMask,
|
||||||
Ignored? predicate = null,
|
Ignored? predicate = null,
|
||||||
bool popup = false)
|
bool popup = false)
|
||||||
{
|
{
|
||||||
if (!Resolve(other, ref other.Comp))
|
if (!TryComp(other, out TransformComponent? otherXform))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
return InRangeUnobstructed(origin,
|
return InRangeUnobstructed(origin, other, otherXform.Coordinates, otherXform.LocalRotation, range, collisionMask, predicate,
|
||||||
other,
|
|
||||||
other.Comp.Coordinates,
|
|
||||||
other.Comp.LocalRotation,
|
|
||||||
range,
|
|
||||||
collisionMask,
|
|
||||||
predicate,
|
|
||||||
popup);
|
popup);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -662,8 +612,8 @@ namespace Content.Shared.Interaction
|
|||||||
/// True if the two points are within a given range without being obstructed.
|
/// True if the two points are within a given range without being obstructed.
|
||||||
/// </returns>
|
/// </returns>
|
||||||
public bool InRangeUnobstructed(
|
public bool InRangeUnobstructed(
|
||||||
Entity<TransformComponent?> origin,
|
EntityUid origin,
|
||||||
Entity<TransformComponent?> other,
|
EntityUid other,
|
||||||
EntityCoordinates otherCoordinates,
|
EntityCoordinates otherCoordinates,
|
||||||
Angle otherAngle,
|
Angle otherAngle,
|
||||||
float range = InteractionRange,
|
float range = InteractionRange,
|
||||||
@@ -671,10 +621,10 @@ namespace Content.Shared.Interaction
|
|||||||
Ignored? predicate = null,
|
Ignored? predicate = null,
|
||||||
bool popup = false)
|
bool popup = false)
|
||||||
{
|
{
|
||||||
Ignored combinedPredicate = e => e == origin.Owner || (predicate?.Invoke(e) ?? false);
|
Ignored combinedPredicate = e => e == origin || (predicate?.Invoke(e) ?? false);
|
||||||
var inRange = true;
|
var inRange = true;
|
||||||
MapCoordinates originPos = default;
|
MapCoordinates originPos = default;
|
||||||
var targetPos = _transform.ToMapCoordinates(otherCoordinates);
|
var targetPos = otherCoordinates.ToMap(EntityManager, _transform);
|
||||||
Angle targetRot = default;
|
Angle targetRot = default;
|
||||||
|
|
||||||
// So essentially:
|
// So essentially:
|
||||||
@@ -684,30 +634,23 @@ namespace Content.Shared.Interaction
|
|||||||
// Alternatively we could check centre distances first though
|
// Alternatively we could check centre distances first though
|
||||||
// that means we wouldn't be able to easily check overlap interactions.
|
// that means we wouldn't be able to easily check overlap interactions.
|
||||||
if (range > 0f &&
|
if (range > 0f &&
|
||||||
_fixtureQuery.TryComp(origin, out var fixtureA) &&
|
TryComp<FixturesComponent>(origin, out var fixtureA) &&
|
||||||
// These fixture counts are stuff that has the component but no fixtures for <reasons> (e.g. buttons).
|
// These fixture counts are stuff that has the component but no fixtures for <reasons> (e.g. buttons).
|
||||||
// At least until they get removed.
|
// At least until they get removed.
|
||||||
fixtureA.FixtureCount > 0 &&
|
fixtureA.FixtureCount > 0 &&
|
||||||
_fixtureQuery.TryComp(other, out var fixtureB) &&
|
TryComp<FixturesComponent>(other, out var fixtureB) &&
|
||||||
fixtureB.FixtureCount > 0 &&
|
fixtureB.FixtureCount > 0 &&
|
||||||
Resolve(origin, ref origin.Comp))
|
TryComp(origin, out TransformComponent? xformA))
|
||||||
{
|
{
|
||||||
var (worldPosA, worldRotA) = origin.Comp.GetWorldPositionRotation();
|
var (worldPosA, worldRotA) = xformA.GetWorldPositionRotation();
|
||||||
var xfA = new Transform(worldPosA, worldRotA);
|
var xfA = new Transform(worldPosA, worldRotA);
|
||||||
var parentRotB = _transform.GetWorldRotation(otherCoordinates.EntityId);
|
var parentRotB = _transform.GetWorldRotation(otherCoordinates.EntityId);
|
||||||
var xfB = new Transform(targetPos.Position, parentRotB + otherAngle);
|
var xfB = new Transform(targetPos.Position, parentRotB + otherAngle);
|
||||||
|
|
||||||
// Different map or the likes.
|
// Different map or the likes.
|
||||||
if (!_broadphase.TryGetNearest(
|
if (!_sharedBroadphaseSystem.TryGetNearest(origin, other,
|
||||||
origin,
|
out _, out _, out var distance,
|
||||||
other,
|
xfA, xfB, fixtureA, fixtureB))
|
||||||
out _,
|
|
||||||
out _,
|
|
||||||
out var distance,
|
|
||||||
xfA,
|
|
||||||
xfB,
|
|
||||||
fixtureA,
|
|
||||||
fixtureB))
|
|
||||||
{
|
{
|
||||||
inRange = false;
|
inRange = false;
|
||||||
}
|
}
|
||||||
@@ -729,15 +672,15 @@ namespace Content.Shared.Interaction
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
// We'll still do the raycast from the centres but we'll bump the range as we know they're in range.
|
// We'll still do the raycast from the centres but we'll bump the range as we know they're in range.
|
||||||
originPos = _transform.GetMapCoordinates(origin, xform: origin.Comp);
|
originPos = _transform.GetMapCoordinates(origin, xform: xformA);
|
||||||
range = (originPos.Position - targetPos.Position).Length();
|
range = (originPos.Position - targetPos.Position).Length();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// No fixtures, e.g. wallmounts.
|
// No fixtures, e.g. wallmounts.
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
originPos = _transform.GetMapCoordinates(origin, origin);
|
originPos = _transform.GetMapCoordinates(origin);
|
||||||
var otherParent = (other.Comp ?? Transform(other)).ParentUid;
|
var otherParent = Transform(other).ParentUid;
|
||||||
targetRot = otherParent.IsValid() ? Transform(otherParent).LocalRotation + otherAngle : otherAngle;
|
targetRot = otherParent.IsValid() ? Transform(otherParent).LocalRotation + otherAngle : otherAngle;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -788,13 +731,13 @@ namespace Content.Shared.Interaction
|
|||||||
{
|
{
|
||||||
HashSet<EntityUid> ignored = new();
|
HashSet<EntityUid> ignored = new();
|
||||||
|
|
||||||
if (_itemQuery.HasComp(target) && _physicsQuery.TryComp(target, out var physics) && physics.CanCollide)
|
if (HasComp<ItemComponent>(target) && TryComp(target, out PhysicsComponent? physics) && physics.CanCollide)
|
||||||
{
|
{
|
||||||
// If the target is an item, we ignore any colliding entities. Currently done so that if items get stuck
|
// If the target is an item, we ignore any colliding entities. Currently done so that if items get stuck
|
||||||
// inside of walls, users can still pick them up.
|
// inside of walls, users can still pick them up.
|
||||||
ignored.UnionWith(_broadphase.GetEntitiesIntersectingBody(target, (int) collisionMask, false, physics));
|
ignored.UnionWith(_sharedBroadphaseSystem.GetEntitiesIntersectingBody(target, (int) collisionMask, false, physics));
|
||||||
}
|
}
|
||||||
else if (_wallMountQuery.TryComp(target, out var wallMount))
|
else if (TryComp(target, out WallMountComponent? wallMount))
|
||||||
{
|
{
|
||||||
// wall-mount exemptions may be restricted to a specific angle range.da
|
// wall-mount exemptions may be restricted to a specific angle range.da
|
||||||
|
|
||||||
@@ -812,7 +755,13 @@ namespace Content.Shared.Interaction
|
|||||||
ignored.UnionWith(grid.GetAnchoredEntities(targetCoords));
|
ignored.UnionWith(grid.GetAnchoredEntities(targetCoords));
|
||||||
}
|
}
|
||||||
|
|
||||||
Ignored combinedPredicate = e => e == target || (predicate?.Invoke(e) ?? false) || ignored.Contains(e);
|
Ignored combinedPredicate = e =>
|
||||||
|
{
|
||||||
|
return e == target
|
||||||
|
|| (predicate?.Invoke(e) ?? false)
|
||||||
|
|| ignored.Contains(e);
|
||||||
|
};
|
||||||
|
|
||||||
return combinedPredicate;
|
return combinedPredicate;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1009,8 +958,10 @@ namespace Content.Shared.Interaction
|
|||||||
bool checkUseDelay = true,
|
bool checkUseDelay = true,
|
||||||
bool checkAccess = true)
|
bool checkAccess = true)
|
||||||
{
|
{
|
||||||
_delayQuery.TryComp(used, out var delayComponent);
|
UseDelayComponent? delayComponent = null;
|
||||||
if (checkUseDelay && delayComponent != null && _useDelay.IsDelayed((used, delayComponent)))
|
if (checkUseDelay
|
||||||
|
&& TryComp(used, out delayComponent)
|
||||||
|
&& _useDelay.IsDelayed((used, delayComponent)))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (checkCanInteract && !_actionBlockerSystem.CanInteract(user, used))
|
if (checkCanInteract && !_actionBlockerSystem.CanInteract(user, used))
|
||||||
@@ -1021,11 +972,11 @@ namespace Content.Shared.Interaction
|
|||||||
|
|
||||||
// Check if interacted entity is in the same container, the direct child, or direct parent of the user.
|
// Check if interacted entity is in the same container, the direct child, or direct parent of the user.
|
||||||
// This is bypassed IF the interaction happened through an item slot (e.g., backpack UI)
|
// This is bypassed IF the interaction happened through an item slot (e.g., backpack UI)
|
||||||
if (checkAccess && !IsAccessible(user, used))
|
if (checkAccess && !_containerSystem.IsInSameOrParentContainer(user, used) && !CanAccessViaStorage(user, used))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// Does the user have hands?
|
// Does the user have hands?
|
||||||
if (!_handsQuery.HasComp(user))
|
if (!HasComp<HandsComponent>(user))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
var activateMsg = new ActivateInWorldEvent(user, used);
|
var activateMsg = new ActivateInWorldEvent(user, used);
|
||||||
@@ -1035,9 +986,7 @@ namespace Content.Shared.Interaction
|
|||||||
|
|
||||||
DoContactInteraction(user, used, activateMsg);
|
DoContactInteraction(user, used, activateMsg);
|
||||||
// Still need to call this even without checkUseDelay in case this gets relayed from Activate.
|
// Still need to call this even without checkUseDelay in case this gets relayed from Activate.
|
||||||
if (delayComponent != null)
|
_useDelay.TryResetDelay(used, component: delayComponent);
|
||||||
_useDelay.TryResetDelay(used, component: delayComponent);
|
|
||||||
|
|
||||||
if (!activateMsg.WasLogged)
|
if (!activateMsg.WasLogged)
|
||||||
_adminLogger.Add(LogType.InteractActivate, LogImpact.Low, $"{ToPrettyString(user):user} activated {ToPrettyString(used):used}");
|
_adminLogger.Add(LogType.InteractActivate, LogImpact.Low, $"{ToPrettyString(user):user} activated {ToPrettyString(used):used}");
|
||||||
return true;
|
return true;
|
||||||
@@ -1058,8 +1007,11 @@ namespace Content.Shared.Interaction
|
|||||||
bool checkCanInteract = true,
|
bool checkCanInteract = true,
|
||||||
bool checkUseDelay = true)
|
bool checkUseDelay = true)
|
||||||
{
|
{
|
||||||
_delayQuery.TryComp(used, out var delayComponent);
|
UseDelayComponent? delayComponent = null;
|
||||||
if (checkUseDelay && delayComponent != null && _useDelay.IsDelayed((used, delayComponent)))
|
|
||||||
|
if (checkUseDelay
|
||||||
|
&& TryComp(used, out delayComponent)
|
||||||
|
&& _useDelay.IsDelayed((used, delayComponent)))
|
||||||
return true; // if the item is on cooldown, we consider this handled.
|
return true; // if the item is on cooldown, we consider this handled.
|
||||||
|
|
||||||
if (checkCanInteract && !_actionBlockerSystem.CanInteract(user, used))
|
if (checkCanInteract && !_actionBlockerSystem.CanInteract(user, used))
|
||||||
@@ -1121,60 +1073,11 @@ namespace Content.Shared.Interaction
|
|||||||
}
|
}
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Check if a user can access a target (stored in the same containers) and is in range without obstructions.
|
|
||||||
/// </summary>
|
|
||||||
public bool InRangeAndAccessible(
|
|
||||||
Entity<TransformComponent?> user,
|
|
||||||
Entity<TransformComponent?> target,
|
|
||||||
float range = InteractionRange,
|
|
||||||
CollisionGroup collisionMask = InRangeUnobstructedMask,
|
|
||||||
Ignored? predicate = null)
|
|
||||||
{
|
|
||||||
if (user == target)
|
|
||||||
return true;
|
|
||||||
|
|
||||||
if (!Resolve(user, ref user.Comp))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if (!Resolve(target, ref target.Comp))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
return IsAccessible(user, target) && InRangeUnobstructed(user, target, range, collisionMask, predicate);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Check if a user can access a target or if they are stored in different containers.
|
|
||||||
/// </summary>
|
|
||||||
public bool IsAccessible(Entity<TransformComponent?> user, Entity<TransformComponent?> target)
|
|
||||||
{
|
|
||||||
if (_containerSystem.IsInSameOrParentContainer(user, target, out _, out var container))
|
|
||||||
return true;
|
|
||||||
|
|
||||||
return container != null && CanAccessViaStorage(user, target, container);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// If a target is in range, but not in the same container as the user, it may be inside of a backpack. This
|
/// If a target is in range, but not in the same container as the user, it may be inside of a backpack. This
|
||||||
/// checks if the user can access the item in these situations.
|
/// checks if the user can access the item in these situations.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public bool CanAccessViaStorage(EntityUid user, EntityUid target)
|
public abstract bool CanAccessViaStorage(EntityUid user, EntityUid target);
|
||||||
{
|
|
||||||
if (!_containerSystem.TryGetContainingContainer(target, out var container))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
return CanAccessViaStorage(user, target, container);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc cref="CanAccessViaStorage(Robust.Shared.GameObjects.EntityUid,Robust.Shared.GameObjects.EntityUid)"/>
|
|
||||||
public bool CanAccessViaStorage(EntityUid user, EntityUid target, BaseContainer container)
|
|
||||||
{
|
|
||||||
if (StorageComponent.ContainerId != container.ID)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
// we don't check if the user can access the storage entity itself. This should be handed by the UI system.
|
|
||||||
return _ui.IsUiOpen(container.Owner, StorageComponent.StorageUiKey.Key, user);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Checks whether an entity currently equipped by another player is accessible to some user. This shouldn't
|
/// Checks whether an entity currently equipped by another player is accessible to some user. This shouldn't
|
||||||
@@ -1255,15 +1158,19 @@ namespace Content.Shared.Interaction
|
|||||||
RaiseLocalEvent(uidB.Value, new ContactInteractionEvent(uidA));
|
RaiseLocalEvent(uidB.Value, new ContactInteractionEvent(uidA));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private void HandleUserInterfaceRangeCheck(ref BoundUserInterfaceCheckRangeEvent ev)
|
private void HandleUserInterfaceRangeCheck(ref BoundUserInterfaceCheckRangeEvent ev)
|
||||||
{
|
{
|
||||||
if (ev.Result == BoundUserInterfaceRangeResult.Fail)
|
if (ev.Result == BoundUserInterfaceRangeResult.Fail)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
ev.Result = UiRangeCheck(ev.Actor!, ev.Target, ev.Data.InteractionRange)
|
if (InRangeUnobstructed(ev.Actor, ev.Target, ev.Data.InteractionRange))
|
||||||
? BoundUserInterfaceRangeResult.Pass
|
{
|
||||||
: BoundUserInterfaceRangeResult.Fail;
|
ev.Result = BoundUserInterfaceRangeResult.Pass;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ev.Result = BoundUserInterfaceRangeResult.Fail;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -210,7 +210,11 @@ public abstract partial class InventorySystem
|
|||||||
return false;
|
return false;
|
||||||
|
|
||||||
// Can the actor reach the item?
|
// Can the actor reach the item?
|
||||||
if (_interactionSystem.InRangeAndAccessible(actor, itemUid))
|
if (_interactionSystem.InRangeUnobstructed(actor, itemUid) && _containerSystem.IsInSameOrParentContainer(actor, itemUid))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
// Is the item in an open storage UI, i.e., is the user quick-equipping from an open backpack?
|
||||||
|
if (_interactionSystem.CanAccessViaStorage(actor, itemUid))
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
// Is the actor currently stripping the target? Here we could check if the actor has the stripping UI open, but
|
// Is the actor currently stripping the target? Here we could check if the actor has the stripping UI open, but
|
||||||
|
|||||||
@@ -9,7 +9,6 @@ using Content.Shared.IdentityManagement;
|
|||||||
using Content.Shared.Interaction;
|
using Content.Shared.Interaction;
|
||||||
using Content.Shared.Popups;
|
using Content.Shared.Popups;
|
||||||
using Content.Shared.Storage.Components;
|
using Content.Shared.Storage.Components;
|
||||||
using Content.Shared.UserInterface;
|
|
||||||
using Content.Shared.Verbs;
|
using Content.Shared.Verbs;
|
||||||
using Content.Shared.Wires;
|
using Content.Shared.Wires;
|
||||||
using JetBrains.Annotations;
|
using JetBrains.Annotations;
|
||||||
@@ -25,7 +24,6 @@ namespace Content.Shared.Lock;
|
|||||||
public sealed class LockSystem : EntitySystem
|
public sealed class LockSystem : EntitySystem
|
||||||
{
|
{
|
||||||
[Dependency] private readonly AccessReaderSystem _accessReader = default!;
|
[Dependency] private readonly AccessReaderSystem _accessReader = default!;
|
||||||
[Dependency] private readonly ActivatableUISystem _activatableUI = default!;
|
|
||||||
[Dependency] private readonly SharedAppearanceSystem _appearanceSystem = default!;
|
[Dependency] private readonly SharedAppearanceSystem _appearanceSystem = default!;
|
||||||
[Dependency] private readonly SharedAudioSystem _audio = default!;
|
[Dependency] private readonly SharedAudioSystem _audio = default!;
|
||||||
[Dependency] private readonly SharedPopupSystem _sharedPopupSystem = default!;
|
[Dependency] private readonly SharedPopupSystem _sharedPopupSystem = default!;
|
||||||
@@ -48,9 +46,6 @@ public sealed class LockSystem : EntitySystem
|
|||||||
SubscribeLocalEvent<LockedWiresPanelComponent, LockToggleAttemptEvent>(OnLockToggleAttempt);
|
SubscribeLocalEvent<LockedWiresPanelComponent, LockToggleAttemptEvent>(OnLockToggleAttempt);
|
||||||
SubscribeLocalEvent<LockedWiresPanelComponent, AttemptChangePanelEvent>(OnAttemptChangePanel);
|
SubscribeLocalEvent<LockedWiresPanelComponent, AttemptChangePanelEvent>(OnAttemptChangePanel);
|
||||||
SubscribeLocalEvent<LockedAnchorableComponent, UnanchorAttemptEvent>(OnUnanchorAttempt);
|
SubscribeLocalEvent<LockedAnchorableComponent, UnanchorAttemptEvent>(OnUnanchorAttempt);
|
||||||
|
|
||||||
SubscribeLocalEvent<ActivatableUIRequiresLockComponent, ActivatableUIOpenAttemptEvent>(OnUIOpenAttempt);
|
|
||||||
SubscribeLocalEvent<ActivatableUIRequiresLockComponent, LockToggledEvent>(LockToggled);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnStartup(EntityUid uid, LockComponent lockComp, ComponentStartup args)
|
private void OnStartup(EntityUid uid, LockComponent lockComp, ComponentStartup args)
|
||||||
@@ -352,25 +347,4 @@ public sealed class LockSystem : EntitySystem
|
|||||||
args.User);
|
args.User);
|
||||||
args.Cancel();
|
args.Cancel();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
private void OnUIOpenAttempt(EntityUid uid, ActivatableUIRequiresLockComponent component, ActivatableUIOpenAttemptEvent args)
|
|
||||||
{
|
|
||||||
if (args.Cancelled)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (TryComp<LockComponent>(uid, out var lockComp) && lockComp.Locked != component.RequireLocked)
|
|
||||||
{
|
|
||||||
args.Cancel();
|
|
||||||
if (lockComp.Locked)
|
|
||||||
_sharedPopupSystem.PopupEntity(Loc.GetString("entity-storage-component-locked-message"), uid, args.User);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void LockToggled(EntityUid uid, ActivatableUIRequiresLockComponent component, LockToggledEvent args)
|
|
||||||
{
|
|
||||||
if (!TryComp<LockComponent>(uid, out var lockComp) || lockComp.Locked == component.RequireLocked)
|
|
||||||
return;
|
|
||||||
|
|
||||||
_activatableUI.CloseAll(uid);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -2,7 +2,6 @@ using Content.Shared.DoAfter;
|
|||||||
using Content.Shared.Humanoid.Markings;
|
using Content.Shared.Humanoid.Markings;
|
||||||
using Content.Shared.Interaction;
|
using Content.Shared.Interaction;
|
||||||
using Robust.Shared.Serialization;
|
using Robust.Shared.Serialization;
|
||||||
using Robust.Shared.Utility;
|
|
||||||
|
|
||||||
namespace Content.Shared.MagicMirror;
|
namespace Content.Shared.MagicMirror;
|
||||||
|
|
||||||
@@ -18,13 +17,10 @@ public abstract class SharedMagicMirrorSystem : EntitySystem
|
|||||||
|
|
||||||
private void OnMirrorRangeCheck(EntityUid uid, MagicMirrorComponent component, ref BoundUserInterfaceCheckRangeEvent args)
|
private void OnMirrorRangeCheck(EntityUid uid, MagicMirrorComponent component, ref BoundUserInterfaceCheckRangeEvent args)
|
||||||
{
|
{
|
||||||
if (args.Result == BoundUserInterfaceRangeResult.Fail)
|
if (!Exists(component.Target) || !_interaction.InRangeUnobstructed(uid, component.Target.Value))
|
||||||
return;
|
{
|
||||||
|
|
||||||
DebugTools.Assert(component.Target != null && Exists(component.Target));
|
|
||||||
|
|
||||||
if (!_interaction.InRangeUnobstructed(uid, component.Target.Value))
|
|
||||||
args.Result = BoundUserInterfaceRangeResult.Fail;
|
args.Result = BoundUserInterfaceRangeResult.Fail;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -344,17 +344,14 @@ public sealed class PullingSystem : EntitySystem
|
|||||||
return !startPull.Cancelled && !getPulled.Cancelled;
|
return !startPull.Cancelled && !getPulled.Cancelled;
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool TogglePull(Entity<PullableComponent?> pullable, EntityUid pullerUid)
|
public bool TogglePull(EntityUid pullableUid, EntityUid pullerUid, PullableComponent pullable)
|
||||||
{
|
{
|
||||||
if (!Resolve(pullable, ref pullable.Comp, false))
|
if (pullable.Puller == pullerUid)
|
||||||
return false;
|
|
||||||
|
|
||||||
if (pullable.Comp.Puller == pullerUid)
|
|
||||||
{
|
{
|
||||||
return TryStopPull(pullable, pullable.Comp);
|
return TryStopPull(pullableUid, pullable);
|
||||||
}
|
}
|
||||||
|
|
||||||
return TryStartPull(pullerUid, pullable, pullableComp: pullable);
|
return TryStartPull(pullerUid, pullableUid, pullableComp: pullable);
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool TogglePull(EntityUid pullerUid, PullerComponent puller)
|
public bool TogglePull(EntityUid pullerUid, PullerComponent puller)
|
||||||
@@ -362,7 +359,7 @@ public sealed class PullingSystem : EntitySystem
|
|||||||
if (!TryComp<PullableComponent>(puller.Pulling, out var pullable))
|
if (!TryComp<PullableComponent>(puller.Pulling, out var pullable))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
return TogglePull((puller.Pulling.Value, pullable), pullerUid);
|
return TogglePull(puller.Pulling.Value, pullerUid, pullable);
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool TryStartPull(EntityUid pullerUid, EntityUid pullableUid,
|
public bool TryStartPull(EntityUid pullerUid, EntityUid pullableUid,
|
||||||
|
|||||||
@@ -96,7 +96,7 @@ public abstract class SharedNavMapSystem : EntitySystem
|
|||||||
chunks.Add(origin, chunk.TileData);
|
chunks.Add(origin, chunk.TileData);
|
||||||
}
|
}
|
||||||
|
|
||||||
args.State = new NavMapState(chunks, component.Beacons);
|
args.State = new NavMapComponentState(chunks, component.Beacons);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -109,7 +109,12 @@ public abstract class SharedNavMapSystem : EntitySystem
|
|||||||
chunks.Add(origin, chunk.TileData);
|
chunks.Add(origin, chunk.TileData);
|
||||||
}
|
}
|
||||||
|
|
||||||
args.State = new NavMapDeltaState(chunks, component.Beacons, new(component.Chunks.Keys));
|
args.State = new NavMapComponentState(chunks, component.Beacons)
|
||||||
|
{
|
||||||
|
// TODO NAVMAP cache a single AllChunks hashset in the component.
|
||||||
|
// Or maybe just only send them if a chunk gets removed.
|
||||||
|
AllChunks = new(component.Chunks.Keys),
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
@@ -117,35 +122,32 @@ public abstract class SharedNavMapSystem : EntitySystem
|
|||||||
#region: System messages
|
#region: System messages
|
||||||
|
|
||||||
[Serializable, NetSerializable]
|
[Serializable, NetSerializable]
|
||||||
protected sealed class NavMapState(
|
protected sealed class NavMapComponentState(
|
||||||
Dictionary<Vector2i, int[]> chunks,
|
Dictionary<Vector2i, int[]> chunks,
|
||||||
Dictionary<NetEntity, NavMapBeacon> beacons)
|
Dictionary<NetEntity, NavMapBeacon> beacons)
|
||||||
: ComponentState
|
: ComponentState, IComponentDeltaState
|
||||||
{
|
{
|
||||||
public Dictionary<Vector2i, int[]> Chunks = chunks;
|
public Dictionary<Vector2i, int[]> Chunks = chunks;
|
||||||
public Dictionary<NetEntity, NavMapBeacon> Beacons = beacons;
|
public Dictionary<NetEntity, NavMapBeacon> Beacons = beacons;
|
||||||
}
|
|
||||||
|
|
||||||
[Serializable, NetSerializable]
|
// Required to infer deleted/missing chunks for delta states
|
||||||
protected sealed class NavMapDeltaState(
|
public HashSet<Vector2i>? AllChunks;
|
||||||
Dictionary<Vector2i, int[]> modifiedChunks,
|
|
||||||
Dictionary<NetEntity, NavMapBeacon> beacons,
|
|
||||||
HashSet<Vector2i> allChunks)
|
|
||||||
: ComponentState, IComponentDeltaState<NavMapState>
|
|
||||||
{
|
|
||||||
public Dictionary<Vector2i, int[]> ModifiedChunks = modifiedChunks;
|
|
||||||
public Dictionary<NetEntity, NavMapBeacon> Beacons = beacons;
|
|
||||||
public HashSet<Vector2i> AllChunks = allChunks;
|
|
||||||
|
|
||||||
public void ApplyToFullState(NavMapState state)
|
public bool FullState => AllChunks == null;
|
||||||
|
|
||||||
|
public void ApplyToFullState(IComponentState fullState)
|
||||||
{
|
{
|
||||||
|
DebugTools.Assert(!FullState);
|
||||||
|
var state = (NavMapComponentState) fullState;
|
||||||
|
DebugTools.Assert(state.FullState);
|
||||||
|
|
||||||
foreach (var key in state.Chunks.Keys)
|
foreach (var key in state.Chunks.Keys)
|
||||||
{
|
{
|
||||||
if (!AllChunks!.Contains(key))
|
if (!AllChunks!.Contains(key))
|
||||||
state.Chunks.Remove(key);
|
state.Chunks.Remove(key);
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (var (index, data) in ModifiedChunks)
|
foreach (var (index, data) in Chunks)
|
||||||
{
|
{
|
||||||
if (!state.Chunks.TryGetValue(index, out var stateValue))
|
if (!state.Chunks.TryGetValue(index, out var stateValue))
|
||||||
state.Chunks[index] = stateValue = new int[data.Length];
|
state.Chunks[index] = stateValue = new int[data.Length];
|
||||||
@@ -160,8 +162,12 @@ public abstract class SharedNavMapSystem : EntitySystem
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public NavMapState CreateNewFullState(NavMapState state)
|
public IComponentState CreateNewFullState(IComponentState fullState)
|
||||||
{
|
{
|
||||||
|
DebugTools.Assert(!FullState);
|
||||||
|
var state = (NavMapComponentState) fullState;
|
||||||
|
DebugTools.Assert(state.FullState);
|
||||||
|
|
||||||
var chunks = new Dictionary<Vector2i, int[]>(state.Chunks.Count);
|
var chunks = new Dictionary<Vector2i, int[]>(state.Chunks.Count);
|
||||||
foreach (var (index, data) in state.Chunks)
|
foreach (var (index, data) in state.Chunks)
|
||||||
{
|
{
|
||||||
@@ -170,13 +176,13 @@ public abstract class SharedNavMapSystem : EntitySystem
|
|||||||
|
|
||||||
var newData = chunks[index] = new int[ArraySize];
|
var newData = chunks[index] = new int[ArraySize];
|
||||||
|
|
||||||
if (ModifiedChunks.TryGetValue(index, out var updatedData))
|
if (Chunks.TryGetValue(index, out var updatedData))
|
||||||
Array.Copy(newData, updatedData, ArraySize);
|
Array.Copy(newData, updatedData, ArraySize);
|
||||||
else
|
else
|
||||||
Array.Copy(newData, data, ArraySize);
|
Array.Copy(newData, data, ArraySize);
|
||||||
}
|
}
|
||||||
|
|
||||||
return new NavMapState(chunks, new(Beacons));
|
return new NavMapComponentState(chunks, new(Beacons));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -74,19 +74,18 @@ public sealed class RoleLoadout
|
|||||||
{
|
{
|
||||||
var loadout = loadouts[i];
|
var loadout = loadouts[i];
|
||||||
|
|
||||||
// Old prototype or otherwise invalid.
|
|
||||||
if (!protoManager.TryIndex(loadout.Prototype, out var loadoutProto))
|
if (!protoManager.TryIndex(loadout.Prototype, out var loadoutProto))
|
||||||
{
|
{
|
||||||
loadouts.RemoveAt(i);
|
loadouts.RemoveAt(i);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Malicious client maybe, check the group even has it.
|
// Похуй FIXME
|
||||||
if (!groupProto.Loadouts.Contains(loadout.Prototype))
|
//if (!IsValid(profile, session, loadout.Prototype, collection, out _))
|
||||||
{
|
// {
|
||||||
loadouts.RemoveAt(i);
|
// loadouts.RemoveAt(i);
|
||||||
continue;
|
// continue;
|
||||||
}
|
// }
|
||||||
|
|
||||||
Apply(loadoutProto);
|
Apply(loadoutProto);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,7 +6,6 @@ using Content.Shared.Movement.Systems;
|
|||||||
using Content.Shared.Popups;
|
using Content.Shared.Popups;
|
||||||
using Content.Shared.PowerCell.Components;
|
using Content.Shared.PowerCell.Components;
|
||||||
using Content.Shared.Silicons.Borgs.Components;
|
using Content.Shared.Silicons.Borgs.Components;
|
||||||
using Content.Shared.UserInterface;
|
|
||||||
using Content.Shared.Wires;
|
using Content.Shared.Wires;
|
||||||
using Robust.Shared.Containers;
|
using Robust.Shared.Containers;
|
||||||
using Robust.Shared.Prototypes;
|
using Robust.Shared.Prototypes;
|
||||||
@@ -38,8 +37,6 @@ public abstract partial class SharedBorgSystem : EntitySystem
|
|||||||
SubscribeLocalEvent<BorgChassisComponent, EntInsertedIntoContainerMessage>(OnInserted);
|
SubscribeLocalEvent<BorgChassisComponent, EntInsertedIntoContainerMessage>(OnInserted);
|
||||||
SubscribeLocalEvent<BorgChassisComponent, EntRemovedFromContainerMessage>(OnRemoved);
|
SubscribeLocalEvent<BorgChassisComponent, EntRemovedFromContainerMessage>(OnRemoved);
|
||||||
SubscribeLocalEvent<BorgChassisComponent, RefreshMovementSpeedModifiersEvent>(OnRefreshMovementSpeedModifiers);
|
SubscribeLocalEvent<BorgChassisComponent, RefreshMovementSpeedModifiersEvent>(OnRefreshMovementSpeedModifiers);
|
||||||
SubscribeLocalEvent<BorgChassisComponent, ActivatableUIOpenAttemptEvent>(OnUIOpenAttempt);
|
|
||||||
|
|
||||||
|
|
||||||
//Honk
|
//Honk
|
||||||
SubscribeLocalEvent<SharedTTSComponent, ComponentInit>(RandomTTS);
|
SubscribeLocalEvent<SharedTTSComponent, ComponentInit>(RandomTTS);
|
||||||
@@ -110,13 +107,6 @@ public abstract partial class SharedBorgSystem : EntitySystem
|
|||||||
component.ModuleContainer = Container.EnsureContainer<Container>(uid, component.ModuleContainerId, containerManager);
|
component.ModuleContainer = Container.EnsureContainer<Container>(uid, component.ModuleContainerId, containerManager);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnUIOpenAttempt(EntityUid uid, BorgChassisComponent component, ActivatableUIOpenAttemptEvent args)
|
|
||||||
{
|
|
||||||
// borgs can't view their own ui
|
|
||||||
if (args.User == uid)
|
|
||||||
args.Cancel();
|
|
||||||
}
|
|
||||||
|
|
||||||
protected virtual void OnInserted(EntityUid uid, BorgChassisComponent component, EntInsertedIntoContainerMessage args)
|
protected virtual void OnInserted(EntityUid uid, BorgChassisComponent component, EntInsertedIntoContainerMessage args)
|
||||||
{
|
{
|
||||||
|
|
||||||
|
|||||||
@@ -25,7 +25,6 @@ using Content.Shared.Stacks;
|
|||||||
using Content.Shared.Storage.Components;
|
using Content.Shared.Storage.Components;
|
||||||
using Content.Shared.Timing;
|
using Content.Shared.Timing;
|
||||||
using Content.Shared.Verbs;
|
using Content.Shared.Verbs;
|
||||||
using Content.Shared.Whitelist;
|
|
||||||
using Robust.Shared.Audio.Systems;
|
using Robust.Shared.Audio.Systems;
|
||||||
using Robust.Shared.Containers;
|
using Robust.Shared.Containers;
|
||||||
using Robust.Shared.GameStates;
|
using Robust.Shared.GameStates;
|
||||||
@@ -157,9 +156,7 @@ public abstract class SharedStorageSystem : EntitySystem
|
|||||||
Grid = new List<Box2i>(component.Grid),
|
Grid = new List<Box2i>(component.Grid),
|
||||||
MaxItemSize = component.MaxItemSize,
|
MaxItemSize = component.MaxItemSize,
|
||||||
StoredItems = storedItems,
|
StoredItems = storedItems,
|
||||||
SavedLocations = component.SavedLocations,
|
SavedLocations = component.SavedLocations
|
||||||
Whitelist = component.Whitelist,
|
|
||||||
Blacklist = component.Blacklist
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -171,8 +168,6 @@ public abstract class SharedStorageSystem : EntitySystem
|
|||||||
component.Grid.Clear();
|
component.Grid.Clear();
|
||||||
component.Grid.AddRange(state.Grid);
|
component.Grid.AddRange(state.Grid);
|
||||||
component.MaxItemSize = state.MaxItemSize;
|
component.MaxItemSize = state.MaxItemSize;
|
||||||
component.Whitelist = state.Whitelist;
|
|
||||||
component.Blacklist = state.Blacklist;
|
|
||||||
|
|
||||||
component.StoredItems.Clear();
|
component.StoredItems.Clear();
|
||||||
|
|
||||||
@@ -1105,7 +1100,7 @@ public abstract class SharedStorageSystem : EntitySystem
|
|||||||
/// <returns>true if inserted, false otherwise</returns>
|
/// <returns>true if inserted, false otherwise</returns>
|
||||||
public bool PlayerInsertEntityInWorld(Entity<StorageComponent?> uid, EntityUid player, EntityUid toInsert)
|
public bool PlayerInsertEntityInWorld(Entity<StorageComponent?> uid, EntityUid player, EntityUid toInsert)
|
||||||
{
|
{
|
||||||
if (!Resolve(uid, ref uid.Comp) || !_interactionSystem.InRangeUnobstructed(player, uid.Owner))
|
if (!Resolve(uid, ref uid.Comp) || !_interactionSystem.InRangeUnobstructed(player, uid))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (!Insert(uid, toInsert, out _, user: player, uid.Comp))
|
if (!Insert(uid, toInsert, out _, user: player, uid.Comp))
|
||||||
@@ -1506,9 +1501,5 @@ public abstract class SharedStorageSystem : EntitySystem
|
|||||||
public List<Box2i> Grid = new();
|
public List<Box2i> Grid = new();
|
||||||
|
|
||||||
public ProtoId<ItemSizePrototype>? MaxItemSize;
|
public ProtoId<ItemSizePrototype>? MaxItemSize;
|
||||||
|
|
||||||
public EntityWhitelist? Whitelist;
|
|
||||||
|
|
||||||
public EntityWhitelist? Blacklist;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,31 +1,17 @@
|
|||||||
using Content.Shared.CombatMode;
|
|
||||||
using Content.Shared.DragDrop;
|
using Content.Shared.DragDrop;
|
||||||
using Content.Shared.Hands.Components;
|
using Content.Shared.Hands.Components;
|
||||||
using Content.Shared.Interaction;
|
|
||||||
using Content.Shared.Strip.Components;
|
using Content.Shared.Strip.Components;
|
||||||
|
|
||||||
namespace Content.Shared.Strip;
|
namespace Content.Shared.Strip;
|
||||||
|
|
||||||
public abstract class SharedStrippableSystem : EntitySystem
|
public abstract class SharedStrippableSystem : EntitySystem
|
||||||
{
|
{
|
||||||
[Dependency] private readonly SharedUserInterfaceSystem _ui = default!;
|
|
||||||
|
|
||||||
public override void Initialize()
|
public override void Initialize()
|
||||||
{
|
{
|
||||||
base.Initialize();
|
base.Initialize();
|
||||||
SubscribeLocalEvent<StrippingComponent, CanDropTargetEvent>(OnCanDropOn);
|
SubscribeLocalEvent<StrippingComponent, CanDropTargetEvent>(OnCanDropOn);
|
||||||
SubscribeLocalEvent<StrippableComponent, CanDropDraggedEvent>(OnCanDrop);
|
SubscribeLocalEvent<StrippableComponent, CanDropDraggedEvent>(OnCanDrop);
|
||||||
SubscribeLocalEvent<StrippableComponent, DragDropDraggedEvent>(OnDragDrop);
|
SubscribeLocalEvent<StrippableComponent, DragDropDraggedEvent>(OnDragDrop);
|
||||||
SubscribeLocalEvent<StrippableComponent, ActivateInWorldEvent>(OnActivateInWorld);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnActivateInWorld(EntityUid uid, StrippableComponent component, ActivateInWorldEvent args)
|
|
||||||
{
|
|
||||||
if (args.Handled || args.Target == args.User)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (TryOpenStrippingUi(args.User, (uid, component)))
|
|
||||||
args.Handled = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public (TimeSpan Time, bool Stealth) GetStripTimeModifiers(EntityUid user, EntityUid target, TimeSpan initialTime)
|
public (TimeSpan Time, bool Stealth) GetStripTimeModifiers(EntityUid user, EntityUid target, TimeSpan initialTime)
|
||||||
@@ -43,20 +29,13 @@ public abstract class SharedStrippableSystem : EntitySystem
|
|||||||
if (args.Handled || args.Target != args.User)
|
if (args.Handled || args.Target != args.User)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (TryOpenStrippingUi(args.User, (uid, component)))
|
StartOpeningStripper(args.User, (uid, component));
|
||||||
args.Handled = true;
|
args.Handled = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool TryOpenStrippingUi(EntityUid user, Entity<StrippableComponent> target, bool openInCombat = false)
|
public virtual void StartOpeningStripper(EntityUid user, Entity<StrippableComponent> component, bool openInCombat = false)
|
||||||
{
|
{
|
||||||
if (!openInCombat && TryComp<CombatModeComponent>(user, out var mode) && mode.IsInCombatMode)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if (!HasComp<StrippingComponent>(user))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
_ui.OpenUi(target.Owner, StrippingUiKey.Key, user);
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnCanDropOn(EntityUid uid, StrippingComponent component, ref CanDropTargetEvent args)
|
private void OnCanDropOn(EntityUid uid, StrippingComponent component, ref CanDropTargetEvent args)
|
||||||
|
|||||||
@@ -57,7 +57,7 @@ namespace Content.Shared.UserInterface
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
[ViewVariables(VVAccess.ReadWrite)]
|
[ViewVariables(VVAccess.ReadWrite)]
|
||||||
[DataField]
|
[DataField]
|
||||||
public bool BlockSpectators;
|
public bool AllowSpectator = true;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Whether the item must be in the user's currently selected/active hand.
|
/// Whether the item must be in the user's currently selected/active hand.
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ using Content.Shared.Interaction;
|
|||||||
using Content.Shared.Interaction.Events;
|
using Content.Shared.Interaction.Events;
|
||||||
using Content.Shared.Popups;
|
using Content.Shared.Popups;
|
||||||
using Content.Shared.Verbs;
|
using Content.Shared.Verbs;
|
||||||
using Robust.Shared.Utility;
|
using Robust.Shared.Containers;
|
||||||
|
|
||||||
namespace Content.Shared.UserInterface;
|
namespace Content.Shared.UserInterface;
|
||||||
|
|
||||||
@@ -19,12 +19,15 @@ public sealed partial class ActivatableUISystem : EntitySystem
|
|||||||
[Dependency] private readonly SharedUserInterfaceSystem _uiSystem = default!;
|
[Dependency] private readonly SharedUserInterfaceSystem _uiSystem = default!;
|
||||||
[Dependency] private readonly SharedPopupSystem _popupSystem = default!;
|
[Dependency] private readonly SharedPopupSystem _popupSystem = default!;
|
||||||
[Dependency] private readonly SharedHandsSystem _hands = default!;
|
[Dependency] private readonly SharedHandsSystem _hands = default!;
|
||||||
|
[Dependency] private readonly SharedContainerSystem _container = default!;
|
||||||
|
[Dependency] private readonly SharedInteractionSystem _interaction = default!;
|
||||||
|
|
||||||
|
private readonly List<EntityUid> _toClose = new();
|
||||||
|
|
||||||
public override void Initialize()
|
public override void Initialize()
|
||||||
{
|
{
|
||||||
base.Initialize();
|
base.Initialize();
|
||||||
|
|
||||||
SubscribeLocalEvent<ActivatableUIComponent, ComponentStartup>(OnStartup);
|
|
||||||
SubscribeLocalEvent<ActivatableUIComponent, UseInHandEvent>(OnUseInHand);
|
SubscribeLocalEvent<ActivatableUIComponent, UseInHandEvent>(OnUseInHand);
|
||||||
SubscribeLocalEvent<ActivatableUIComponent, ActivateInWorldEvent>(OnActivate);
|
SubscribeLocalEvent<ActivatableUIComponent, ActivateInWorldEvent>(OnActivate);
|
||||||
SubscribeLocalEvent<ActivatableUIComponent, InteractUsingEvent>(OnInteractUsing);
|
SubscribeLocalEvent<ActivatableUIComponent, InteractUsingEvent>(OnInteractUsing);
|
||||||
@@ -34,24 +37,28 @@ public sealed partial class ActivatableUISystem : EntitySystem
|
|||||||
SubscribeLocalEvent<ActivatableUIComponent, GetVerbsEvent<ActivationVerb>>(GetActivationVerb);
|
SubscribeLocalEvent<ActivatableUIComponent, GetVerbsEvent<ActivationVerb>>(GetActivationVerb);
|
||||||
SubscribeLocalEvent<ActivatableUIComponent, GetVerbsEvent<Verb>>(GetVerb);
|
SubscribeLocalEvent<ActivatableUIComponent, GetVerbsEvent<Verb>>(GetVerb);
|
||||||
|
|
||||||
|
// TODO ActivatableUI
|
||||||
|
// Add UI-user component, and listen for user container changes.
|
||||||
|
// I.e., should lose a computer UI if a player gets shut into a locker.
|
||||||
|
SubscribeLocalEvent<ActivatableUIComponent, EntGotInsertedIntoContainerMessage>(OnGotInserted);
|
||||||
|
SubscribeLocalEvent<ActivatableUIComponent, EntGotRemovedFromContainerMessage>(OnGotRemoved);
|
||||||
|
|
||||||
|
SubscribeLocalEvent<BoundUserInterfaceMessageAttempt>(OnBoundInterfaceInteractAttempt);
|
||||||
SubscribeLocalEvent<UserInterfaceComponent, OpenUiActionEvent>(OnActionPerform);
|
SubscribeLocalEvent<UserInterfaceComponent, OpenUiActionEvent>(OnActionPerform);
|
||||||
|
|
||||||
InitializePower();
|
InitializePower();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnStartup(Entity<ActivatableUIComponent> ent, ref ComponentStartup args)
|
private void OnBoundInterfaceInteractAttempt(BoundUserInterfaceMessageAttempt ev)
|
||||||
{
|
{
|
||||||
if (ent.Comp.Key == null)
|
if (!TryComp(ev.Target, out ActivatableUIComponent? comp))
|
||||||
{
|
|
||||||
Log.Error($"Missing UI Key for entity: {ToPrettyString(ent)}");
|
|
||||||
return;
|
return;
|
||||||
}
|
|
||||||
|
|
||||||
// TODO BUI
|
if (!comp.RequireHands)
|
||||||
// set interaction range to zero to avoid constant range checks.
|
return;
|
||||||
//
|
|
||||||
// if (ent.Comp.InHandsOnly && _uiSystem.TryGetInterfaceData(ent.Owner, ent.Comp.Key, out var data))
|
if (!TryComp(ev.Actor, out HandsComponent? hands) || hands.Hands.Count == 0)
|
||||||
// data.InteractionRange = 0;
|
ev.Cancel();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnActionPerform(EntityUid uid, UserInterfaceComponent component, OpenUiActionEvent args)
|
private void OnActionPerform(EntityUid uid, UserInterfaceComponent component, OpenUiActionEvent args)
|
||||||
@@ -70,10 +77,9 @@ public sealed partial class ActivatableUISystem : EntitySystem
|
|||||||
|
|
||||||
args.Verbs.Add(new ActivationVerb
|
args.Verbs.Add(new ActivationVerb
|
||||||
{
|
{
|
||||||
|
// TODO VERBS add "open UI" icon
|
||||||
Act = () => InteractUI(args.User, uid, component),
|
Act = () => InteractUI(args.User, uid, component),
|
||||||
Text = Loc.GetString(component.VerbText),
|
Text = Loc.GetString(component.VerbText)
|
||||||
// TODO VERB ICON find a better icon
|
|
||||||
Icon = new SpriteSpecifier.Texture(new ResPath("/Textures/Interface/VerbIcons/settings.svg.192dpi.png")),
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -84,10 +90,9 @@ public sealed partial class ActivatableUISystem : EntitySystem
|
|||||||
|
|
||||||
args.Verbs.Add(new Verb
|
args.Verbs.Add(new Verb
|
||||||
{
|
{
|
||||||
|
// TODO VERBS add "open UI" icon
|
||||||
Act = () => InteractUI(args.User, uid, component),
|
Act = () => InteractUI(args.User, uid, component),
|
||||||
Text = Loc.GetString(component.VerbText),
|
Text = Loc.GetString(component.VerbText)
|
||||||
// TODO VERB ICON find a better icon
|
|
||||||
Icon = new SpriteSpecifier.Texture(new ResPath("/Textures/Interface/VerbIcons/settings.svg.192dpi.png")),
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -114,7 +119,7 @@ public sealed partial class ActivatableUISystem : EntitySystem
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return args.CanInteract || HasComp<GhostComponent>(args.User) && !component.BlockSpectators;
|
return args.CanInteract || component.AllowSpectator && HasComp<GhostComponent>(args.User);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnUseInHand(EntityUid uid, ActivatableUIComponent component, UseInHandEvent args)
|
private void OnUseInHand(EntityUid uid, ActivatableUIComponent component, UseInHandEvent args)
|
||||||
@@ -186,7 +191,7 @@ public sealed partial class ActivatableUISystem : EntitySystem
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!_blockerSystem.CanInteract(user, uiEntity) && (!HasComp<GhostComponent>(user) || aui.BlockSpectators))
|
if (!_blockerSystem.CanInteract(user, uiEntity) && (!aui.AllowSpectator || !HasComp<GhostComponent>(user)))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (aui.RequireHands)
|
if (aui.RequireHands)
|
||||||
@@ -281,4 +286,47 @@ public sealed partial class ActivatableUISystem : EntitySystem
|
|||||||
if (ent.Comp.RequireHands && ent.Comp.InHandsOnly)
|
if (ent.Comp.RequireHands && ent.Comp.InHandsOnly)
|
||||||
CloseAll(ent, ent);
|
CloseAll(ent, ent);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void OnGotInserted(Entity<ActivatableUIComponent> ent, ref EntGotInsertedIntoContainerMessage args)
|
||||||
|
{
|
||||||
|
CheckAccess((ent, ent));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnGotRemoved(Entity<ActivatableUIComponent> ent, ref EntGotRemovedFromContainerMessage args)
|
||||||
|
{
|
||||||
|
CheckAccess((ent, ent));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void CheckAccess(Entity<ActivatableUIComponent?> ent)
|
||||||
|
{
|
||||||
|
if (!Resolve(ent, ref ent.Comp))
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (ent.Comp.Key == null)
|
||||||
|
{
|
||||||
|
Log.Error($"Encountered null key in activatable ui on entity {ToPrettyString(ent)}");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var user in _uiSystem.GetActors(ent.Owner, ent.Comp.Key))
|
||||||
|
{
|
||||||
|
if (!_container.IsInSameOrParentContainer(user, ent)
|
||||||
|
&& !_interaction.CanAccessViaStorage(user, ent))
|
||||||
|
{
|
||||||
|
_toClose.Add(user);
|
||||||
|
continue;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!_interaction.InRangeUnobstructed(user, ent))
|
||||||
|
_toClose.Add(user);
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var user in _toClose)
|
||||||
|
{
|
||||||
|
_uiSystem.CloseUi(ent.Owner, ent.Comp.Key, user);
|
||||||
|
}
|
||||||
|
|
||||||
|
_toClose.Clear();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -72,7 +72,19 @@ namespace Content.Shared.Verbs
|
|||||||
extraCategories = new();
|
extraCategories = new();
|
||||||
|
|
||||||
// accessibility checks
|
// accessibility checks
|
||||||
var canAccess = force || _interactionSystem.InRangeAndAccessible(user, target);
|
bool canAccess = false;
|
||||||
|
if (force || target == user)
|
||||||
|
canAccess = true;
|
||||||
|
else if (_interactionSystem.InRangeUnobstructed(user, target))
|
||||||
|
{
|
||||||
|
// Note that being in a container does not count as an obstruction for InRangeUnobstructed
|
||||||
|
// Therefore, we need extra checks to ensure the item is actually accessible:
|
||||||
|
if (ContainerSystem.IsInSameOrParentContainer(user, target))
|
||||||
|
canAccess = true;
|
||||||
|
else
|
||||||
|
// the item might be in a backpack that the user has open
|
||||||
|
canAccess = _interactionSystem.CanAccessViaStorage(user, target);
|
||||||
|
}
|
||||||
|
|
||||||
// A large number of verbs need to check action blockers. Instead of repeatedly having each system individually
|
// A large number of verbs need to check action blockers. Instead of repeatedly having each system individually
|
||||||
// call ActionBlocker checks, just cache it for the verb request.
|
// call ActionBlocker checks, just cache it for the verb request.
|
||||||
|
|||||||
@@ -1,8 +1,6 @@
|
|||||||
using System.Diagnostics.CodeAnalysis;
|
using System.Diagnostics.CodeAnalysis;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Numerics;
|
using System.Numerics;
|
||||||
using Content.Shared._White;
|
|
||||||
using Content.Shared._White.Implants.NeuroControl;
|
|
||||||
using Content.Shared.ActionBlocker;
|
using Content.Shared.ActionBlocker;
|
||||||
using Content.Shared.Administration.Logs;
|
using Content.Shared.Administration.Logs;
|
||||||
using Content.Shared.CombatMode;
|
using Content.Shared.CombatMode;
|
||||||
@@ -15,7 +13,6 @@ using Content.Shared.Hands.Components;
|
|||||||
using Content.Shared.Interaction;
|
using Content.Shared.Interaction;
|
||||||
using Content.Shared.Inventory;
|
using Content.Shared.Inventory;
|
||||||
using Content.Shared.Item.ItemToggle.Components;
|
using Content.Shared.Item.ItemToggle.Components;
|
||||||
using Content.Shared.Movement.Components;
|
|
||||||
using Content.Shared.Physics;
|
using Content.Shared.Physics;
|
||||||
using Content.Shared.Popups;
|
using Content.Shared.Popups;
|
||||||
using Content.Shared.Weapons.Melee.Components;
|
using Content.Shared.Weapons.Melee.Components;
|
||||||
@@ -23,6 +20,9 @@ using Content.Shared.Weapons.Melee.Events;
|
|||||||
using Content.Shared.Weapons.Ranged.Components;
|
using Content.Shared.Weapons.Ranged.Components;
|
||||||
using Content.Shared.Weapons.Ranged.Events;
|
using Content.Shared.Weapons.Ranged.Events;
|
||||||
using Content.Shared.Weapons.Ranged.Systems;
|
using Content.Shared.Weapons.Ranged.Systems;
|
||||||
|
using Content.Shared._White;
|
||||||
|
using Content.Shared._White.Implants.NeuroControl;
|
||||||
|
using Content.Shared.Movement.Components;
|
||||||
using Robust.Shared.Configuration;
|
using Robust.Shared.Configuration;
|
||||||
using Robust.Shared.Map;
|
using Robust.Shared.Map;
|
||||||
using Robust.Shared.Physics;
|
using Robust.Shared.Physics;
|
||||||
@@ -205,39 +205,49 @@ public abstract class SharedMeleeWeaponSystem : EntitySystem
|
|||||||
|
|
||||||
private void OnLightAttack(LightAttackEvent msg, EntitySessionEventArgs args)
|
private void OnLightAttack(LightAttackEvent msg, EntitySessionEventArgs args)
|
||||||
{
|
{
|
||||||
if (args.SenderSession.AttachedEntity is not {} user)
|
var user = args.SenderSession.AttachedEntity;
|
||||||
|
|
||||||
|
if (user == null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (!TryGetWeapon(user, out var weaponUid, out var weapon) ||
|
if (!TryGetWeapon(user.Value, out var weaponUid, out var weapon) ||
|
||||||
weaponUid != GetEntity(msg.Weapon))
|
weaponUid != GetEntity(msg.Weapon))
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
AttemptAttack(user, weaponUid, weapon, msg, args.SenderSession);
|
AttemptAttack(args.SenderSession.AttachedEntity!.Value, weaponUid, weapon, msg, args.SenderSession);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnHeavyAttack(HeavyAttackEvent msg, EntitySessionEventArgs args)
|
private void OnHeavyAttack(HeavyAttackEvent msg, EntitySessionEventArgs args)
|
||||||
{
|
{
|
||||||
if (args.SenderSession.AttachedEntity is not {} user)
|
if (args.SenderSession.AttachedEntity == null)
|
||||||
|
{
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (!TryGetWeapon(user, out var weaponUid, out var weapon) ||
|
if (!TryGetWeapon(args.SenderSession.AttachedEntity.Value, out var weaponUid, out var weapon) ||
|
||||||
weaponUid != GetEntity(msg.Weapon))
|
weaponUid != GetEntity(msg.Weapon))
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
AttemptAttack(user, weaponUid, weapon, msg, args.SenderSession);
|
AttemptAttack(args.SenderSession.AttachedEntity.Value, weaponUid, weapon, msg, args.SenderSession);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnDisarmAttack(DisarmAttackEvent msg, EntitySessionEventArgs args)
|
private void OnDisarmAttack(DisarmAttackEvent msg, EntitySessionEventArgs args)
|
||||||
{
|
{
|
||||||
if (args.SenderSession.AttachedEntity is not {} user)
|
if (args.SenderSession.AttachedEntity == null)
|
||||||
|
{
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (TryGetWeapon(user, out var weaponUid, out var weapon))
|
if (!TryGetWeapon(args.SenderSession.AttachedEntity.Value, out var weaponUid, out var weapon))
|
||||||
AttemptAttack(user, weaponUid, weapon, msg, args.SenderSession);
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
AttemptAttack(args.SenderSession.AttachedEntity.Value, weaponUid, weapon, msg, args.SenderSession);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -371,22 +381,18 @@ public abstract class SharedMeleeWeaponSystem : EntitySystem
|
|||||||
return false;
|
return false;
|
||||||
|
|
||||||
var update = UpdateNextAttack.Both; // WD
|
var update = UpdateNextAttack.Both; // WD
|
||||||
EntityUid? target = null;
|
|
||||||
switch (attack)
|
switch (attack)
|
||||||
{
|
{
|
||||||
case LightAttackEvent light:
|
case LightAttackEvent light:
|
||||||
var lightTarget = GetEntity(light.Target);
|
var lightTarget = GetEntity(light.Target);
|
||||||
if (light.Target != null && !TryGetEntity(light.Target, out target))
|
update = lightTarget == null ? UpdateNextAttack.Both :
|
||||||
{
|
IsMob(lightTarget.Value) ? UpdateNextAttack.Mob : UpdateNextAttack.NonMob; // WD
|
||||||
// Target was lightly attacked & deleted.
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!Blocker.CanAttack(user, target, (weaponUid, weapon)))
|
if (!Blocker.CanAttack(user, lightTarget, (weaponUid, weapon)))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// Can't self-attack if you're the weapon
|
// Can't self-attack if you're the weapon
|
||||||
if (weaponUid == target)
|
if (weaponUid == lightTarget)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// WD START
|
// WD START
|
||||||
@@ -415,13 +421,11 @@ public abstract class SharedMeleeWeaponSystem : EntitySystem
|
|||||||
|
|
||||||
break;
|
break;
|
||||||
case DisarmAttackEvent disarm:
|
case DisarmAttackEvent disarm:
|
||||||
if (disarm.Target != null && !TryGetEntity(disarm.Target, out target))
|
var disarmTarget = GetEntity(disarm.Target);
|
||||||
{
|
update = disarmTarget == null ? UpdateNextAttack.Both :
|
||||||
// Target was lightly attacked & deleted.
|
IsMob(disarmTarget.Value) ? UpdateNextAttack.Mob : UpdateNextAttack.NonMob; // WD
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!Blocker.CanAttack(user, target, (weaponUid, weapon), true))
|
if (!Blocker.CanAttack(user, disarmTarget, (weaponUid, weapon), true))
|
||||||
return false;
|
return false;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
|||||||
@@ -3,7 +3,6 @@ using Content.Shared.Database;
|
|||||||
using Content.Shared.Examine;
|
using Content.Shared.Examine;
|
||||||
using Content.Shared.Interaction;
|
using Content.Shared.Interaction;
|
||||||
using Content.Shared.Tools.Systems;
|
using Content.Shared.Tools.Systems;
|
||||||
using Content.Shared.UserInterface;
|
|
||||||
using Robust.Shared.Audio.Systems;
|
using Robust.Shared.Audio.Systems;
|
||||||
|
|
||||||
namespace Content.Shared.Wires;
|
namespace Content.Shared.Wires;
|
||||||
@@ -11,7 +10,6 @@ namespace Content.Shared.Wires;
|
|||||||
public abstract class SharedWiresSystem : EntitySystem
|
public abstract class SharedWiresSystem : EntitySystem
|
||||||
{
|
{
|
||||||
[Dependency] protected readonly ISharedAdminLogManager AdminLogger = default!;
|
[Dependency] protected readonly ISharedAdminLogManager AdminLogger = default!;
|
||||||
[Dependency] private readonly ActivatableUISystem _activatableUI = default!;
|
|
||||||
[Dependency] protected readonly SharedAppearanceSystem Appearance = default!;
|
[Dependency] protected readonly SharedAppearanceSystem Appearance = default!;
|
||||||
[Dependency] protected readonly SharedAudioSystem Audio = default!;
|
[Dependency] protected readonly SharedAudioSystem Audio = default!;
|
||||||
[Dependency] protected readonly SharedToolSystem Tool = default!;
|
[Dependency] protected readonly SharedToolSystem Tool = default!;
|
||||||
@@ -23,9 +21,6 @@ public abstract class SharedWiresSystem : EntitySystem
|
|||||||
SubscribeLocalEvent<WiresPanelComponent, WirePanelDoAfterEvent>(OnPanelDoAfter);
|
SubscribeLocalEvent<WiresPanelComponent, WirePanelDoAfterEvent>(OnPanelDoAfter);
|
||||||
SubscribeLocalEvent<WiresPanelComponent, InteractUsingEvent>(OnInteractUsing);
|
SubscribeLocalEvent<WiresPanelComponent, InteractUsingEvent>(OnInteractUsing);
|
||||||
SubscribeLocalEvent<WiresPanelComponent, ExaminedEvent>(OnExamine);
|
SubscribeLocalEvent<WiresPanelComponent, ExaminedEvent>(OnExamine);
|
||||||
|
|
||||||
SubscribeLocalEvent<ActivatableUIRequiresPanelComponent, ActivatableUIOpenAttemptEvent>(OnAttemptOpenActivatableUI);
|
|
||||||
SubscribeLocalEvent<ActivatableUIRequiresPanelComponent, PanelChangedEvent>(OnActivatableUIPanelChanged);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnPanelDoAfter(EntityUid uid, WiresPanelComponent panel, WirePanelDoAfterEvent args)
|
private void OnPanelDoAfter(EntityUid uid, WiresPanelComponent panel, WirePanelDoAfterEvent args)
|
||||||
@@ -137,21 +132,4 @@ public abstract class SharedWiresSystem : EntitySystem
|
|||||||
|
|
||||||
return entity.Comp.Open;
|
return entity.Comp.Open;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnAttemptOpenActivatableUI(EntityUid uid, ActivatableUIRequiresPanelComponent component, ActivatableUIOpenAttemptEvent args)
|
|
||||||
{
|
|
||||||
if (args.Cancelled || !TryComp<WiresPanelComponent>(uid, out var wires))
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (component.RequireOpen != wires.Open)
|
|
||||||
args.Cancel();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnActivatableUIPanelChanged(EntityUid uid, ActivatableUIRequiresPanelComponent component, ref PanelChangedEvent args)
|
|
||||||
{
|
|
||||||
if (args.Open == component.RequireOpen)
|
|
||||||
return;
|
|
||||||
|
|
||||||
_activatableUI.CloseAll(uid);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ objectives-round-end-result = {$count ->
|
|||||||
objectives-round-end-result-in-custody = {$custody} out of {$count} {MAKEPLURAL($agent)} were in custody.
|
objectives-round-end-result-in-custody = {$custody} out of {$count} {MAKEPLURAL($agent)} were in custody.
|
||||||
|
|
||||||
objectives-player-user-named = [color=White]{$name}[/color] ([color=gray]{$user}[/color])
|
objectives-player-user-named = [color=White]{$name}[/color] ([color=gray]{$user}[/color])
|
||||||
|
objectives-player-user = [color=gray]{$user}[/color]
|
||||||
objectives-player-named = [color=White]{$name}[/color]
|
objectives-player-named = [color=White]{$name}[/color]
|
||||||
|
|
||||||
objectives-no-objectives = {$custody}{$title} was a {$agent}.
|
objectives-no-objectives = {$custody}{$title} was a {$agent}.
|
||||||
|
|||||||
@@ -133,7 +133,7 @@
|
|||||||
icon:
|
icon:
|
||||||
sprite: Structures/Piping/Atmospherics/Portable/portable_sheater.rsi
|
sprite: Structures/Piping/Atmospherics/Portable/portable_sheater.rsi
|
||||||
state: sheaterOff
|
state: sheaterOff
|
||||||
product: CrateEngineeringSpaceHeater
|
product: SpaceHeaterAnchored
|
||||||
cost: 300
|
cost: 300
|
||||||
category: cargoproduct-category-name-engineering
|
category: cargoproduct-category-name-engineering
|
||||||
group: market
|
group: market
|
||||||
|
|||||||
@@ -194,13 +194,3 @@
|
|||||||
contents:
|
contents:
|
||||||
- id: WeaponParticleDecelerator
|
- id: WeaponParticleDecelerator
|
||||||
amount: 3
|
amount: 3
|
||||||
|
|
||||||
- type: entity
|
|
||||||
id: CrateEngineeringSpaceHeater
|
|
||||||
parent: CrateEngineering
|
|
||||||
name: space heater crate
|
|
||||||
description: Contains a space heater for climate control.
|
|
||||||
components:
|
|
||||||
- type: StorageFill
|
|
||||||
contents:
|
|
||||||
- id: SpaceHeaterFlatpack
|
|
||||||
|
|||||||
@@ -42,7 +42,7 @@
|
|||||||
components:
|
components:
|
||||||
- type: StorageFill
|
- type: StorageFill
|
||||||
contents:
|
contents:
|
||||||
- id: EmitterFlatpack
|
- id: Emitter # TODO change to flatpack
|
||||||
|
|
||||||
- type: entity
|
- type: entity
|
||||||
id: CrateEngineeringSingularityCollector
|
id: CrateEngineeringSingularityCollector
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
- type: entity
|
- type: entity
|
||||||
id: MobSpawnCrabQuartz
|
id: MobSpawnCrabQuartz
|
||||||
name: mobspawner quartzcrab
|
name: mobspawner quartzcrab
|
||||||
noSpawn: True
|
|
||||||
components:
|
components:
|
||||||
- type: Transform
|
- type: Transform
|
||||||
anchored: True
|
anchored: True
|
||||||
@@ -31,7 +30,6 @@
|
|||||||
id: MobSpawnCrabIron
|
id: MobSpawnCrabIron
|
||||||
parent: MobSpawnCrabQuartz
|
parent: MobSpawnCrabQuartz
|
||||||
name: mobspawner ironcrab
|
name: mobspawner ironcrab
|
||||||
noSpawn: True
|
|
||||||
components:
|
components:
|
||||||
- type: Sprite
|
- type: Sprite
|
||||||
sprite: /Textures/Effects/mobspawn.rsi
|
sprite: /Textures/Effects/mobspawn.rsi
|
||||||
@@ -43,7 +41,6 @@
|
|||||||
id: MobSpawnCrabSilver
|
id: MobSpawnCrabSilver
|
||||||
parent: MobSpawnCrabQuartz
|
parent: MobSpawnCrabQuartz
|
||||||
name: mobspawner silvercrab
|
name: mobspawner silvercrab
|
||||||
noSpawn: True
|
|
||||||
components:
|
components:
|
||||||
- type: Sprite
|
- type: Sprite
|
||||||
sprite: /Textures/Effects/mobspawn.rsi
|
sprite: /Textures/Effects/mobspawn.rsi
|
||||||
@@ -55,7 +52,6 @@
|
|||||||
id: MobSpawnCrabUranium
|
id: MobSpawnCrabUranium
|
||||||
parent: MobSpawnCrabQuartz
|
parent: MobSpawnCrabQuartz
|
||||||
name: mobspawner uraniumcrab
|
name: mobspawner uraniumcrab
|
||||||
noSpawn: True
|
|
||||||
components:
|
components:
|
||||||
- type: Sprite
|
- type: Sprite
|
||||||
sprite: /Textures/Effects/mobspawn.rsi
|
sprite: /Textures/Effects/mobspawn.rsi
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
- type: entity
|
- type: entity
|
||||||
id: WallSpawnAsteroid
|
id: WallSpawnAsteroid
|
||||||
noSpawn: True
|
|
||||||
components:
|
components:
|
||||||
- type: Transform
|
- type: Transform
|
||||||
anchored: True
|
anchored: True
|
||||||
@@ -29,7 +28,6 @@
|
|||||||
- type: entity
|
- type: entity
|
||||||
id: WallSpawnAsteroidUraniumCrab
|
id: WallSpawnAsteroidUraniumCrab
|
||||||
parent: WallSpawnAsteroid
|
parent: WallSpawnAsteroid
|
||||||
noSpawn: True
|
|
||||||
components:
|
components:
|
||||||
- type: SpawnOnDespawn
|
- type: SpawnOnDespawn
|
||||||
prototype: AsteroidRockUraniumCrab
|
prototype: AsteroidRockUraniumCrab
|
||||||
@@ -37,7 +35,6 @@
|
|||||||
- type: entity
|
- type: entity
|
||||||
id: WallSpawnAsteroidUranium
|
id: WallSpawnAsteroidUranium
|
||||||
parent: WallSpawnAsteroid
|
parent: WallSpawnAsteroid
|
||||||
noSpawn: True
|
|
||||||
components:
|
components:
|
||||||
- type: SpawnOnDespawn
|
- type: SpawnOnDespawn
|
||||||
prototype: AsteroidRockUranium
|
prototype: AsteroidRockUranium
|
||||||
@@ -45,7 +42,6 @@
|
|||||||
- type: entity
|
- type: entity
|
||||||
id: WallSpawnAsteroidQuartzCrab
|
id: WallSpawnAsteroidQuartzCrab
|
||||||
parent: WallSpawnAsteroid
|
parent: WallSpawnAsteroid
|
||||||
noSpawn: True
|
|
||||||
components:
|
components:
|
||||||
- type: SpawnOnDespawn
|
- type: SpawnOnDespawn
|
||||||
prototype: AsteroidRockQuartzCrab
|
prototype: AsteroidRockQuartzCrab
|
||||||
@@ -53,7 +49,6 @@
|
|||||||
- type: entity
|
- type: entity
|
||||||
id: WallSpawnAsteroidQuartz
|
id: WallSpawnAsteroidQuartz
|
||||||
parent: WallSpawnAsteroid
|
parent: WallSpawnAsteroid
|
||||||
noSpawn: True
|
|
||||||
components:
|
components:
|
||||||
- type: SpawnOnDespawn
|
- type: SpawnOnDespawn
|
||||||
prototype: AsteroidRockQuartz
|
prototype: AsteroidRockQuartz
|
||||||
@@ -61,7 +56,6 @@
|
|||||||
- type: entity
|
- type: entity
|
||||||
id: WallSpawnAsteroidSilverCrab
|
id: WallSpawnAsteroidSilverCrab
|
||||||
parent: WallSpawnAsteroid
|
parent: WallSpawnAsteroid
|
||||||
noSpawn: True
|
|
||||||
components:
|
components:
|
||||||
- type: SpawnOnDespawn
|
- type: SpawnOnDespawn
|
||||||
prototype: AsteroidRockSilverCrab
|
prototype: AsteroidRockSilverCrab
|
||||||
@@ -69,7 +63,6 @@
|
|||||||
- type: entity
|
- type: entity
|
||||||
id: WallSpawnAsteroidSilver
|
id: WallSpawnAsteroidSilver
|
||||||
parent: WallSpawnAsteroid
|
parent: WallSpawnAsteroid
|
||||||
noSpawn: True
|
|
||||||
components:
|
components:
|
||||||
- type: SpawnOnDespawn
|
- type: SpawnOnDespawn
|
||||||
prototype: AsteroidRockSilver
|
prototype: AsteroidRockSilver
|
||||||
@@ -77,7 +70,6 @@
|
|||||||
- type: entity
|
- type: entity
|
||||||
id: WallSpawnAsteroidIronCrab
|
id: WallSpawnAsteroidIronCrab
|
||||||
parent: WallSpawnAsteroid
|
parent: WallSpawnAsteroid
|
||||||
noSpawn: True
|
|
||||||
components:
|
components:
|
||||||
- type: SpawnOnDespawn
|
- type: SpawnOnDespawn
|
||||||
prototype: AsteroidRockTinCrab
|
prototype: AsteroidRockTinCrab
|
||||||
@@ -85,7 +77,6 @@
|
|||||||
- type: entity
|
- type: entity
|
||||||
id: WallSpawnAsteroidIron
|
id: WallSpawnAsteroidIron
|
||||||
parent: WallSpawnAsteroid
|
parent: WallSpawnAsteroid
|
||||||
noSpawn: True
|
|
||||||
components:
|
components:
|
||||||
- type: SpawnOnDespawn
|
- type: SpawnOnDespawn
|
||||||
prototype: AsteroidRockTin
|
prototype: AsteroidRockTin
|
||||||
@@ -1,92 +0,0 @@
|
|||||||
# Most of these have DO NOT MAP, since stations are completely unequipped to deal with ship combat + these are basically placeholder.
|
|
||||||
|
|
||||||
- type: entity
|
|
||||||
id: ShuttleGunSvalinnMachineGunCircuitboard
|
|
||||||
parent: BaseMachineCircuitboard
|
|
||||||
name: LSE-400c "Svalinn machine gun" machine board
|
|
||||||
description: A machine printed circuit board for an LSE-400c "Svalinn machine gun"
|
|
||||||
suffix: DO NOT MAP, Machine Board
|
|
||||||
components:
|
|
||||||
- type: Sprite
|
|
||||||
state: security
|
|
||||||
- type: MachineBoard
|
|
||||||
prototype: ShuttleGunSvalinnMachineGun
|
|
||||||
requirements:
|
|
||||||
MatterBin: 2
|
|
||||||
Manipulator: 4
|
|
||||||
materialRequirements:
|
|
||||||
Steel: 5
|
|
||||||
CableHV: 5
|
|
||||||
|
|
||||||
- type: entity
|
|
||||||
id: ShuttleGunPerforatorCircuitboard
|
|
||||||
parent: BaseMachineCircuitboard
|
|
||||||
name: LSE-1200c "Perforator" machine board
|
|
||||||
description: A machine printed circuit board for an LSE-1200c "Perforator"
|
|
||||||
suffix: DO NOT MAP, Machine Board
|
|
||||||
components:
|
|
||||||
- type: Sprite
|
|
||||||
state: security
|
|
||||||
- type: MachineBoard
|
|
||||||
prototype: ShuttleGunPerforator
|
|
||||||
requirements:
|
|
||||||
MatterBin: 4
|
|
||||||
Manipulator: 6
|
|
||||||
materialRequirements:
|
|
||||||
Steel: 10
|
|
||||||
CableHV: 5
|
|
||||||
|
|
||||||
- type: entity
|
|
||||||
id: ShuttleGunFriendshipCircuitboard
|
|
||||||
parent: BaseMachineCircuitboard
|
|
||||||
name: EXP-320g "Friendship" machine board
|
|
||||||
description: A machine printed circuit board for an EXP-320g "Friendship"
|
|
||||||
suffix: DO NOT MAP, Machine Board
|
|
||||||
components:
|
|
||||||
- type: Sprite
|
|
||||||
state: security
|
|
||||||
- type: MachineBoard
|
|
||||||
prototype: ShuttleGunFriendship
|
|
||||||
requirements:
|
|
||||||
MatterBin: 3
|
|
||||||
Manipulator: 2
|
|
||||||
materialRequirements:
|
|
||||||
Steel: 7
|
|
||||||
CableHV: 5
|
|
||||||
|
|
||||||
- type: entity
|
|
||||||
id: ShuttleGunDusterCircuitboard
|
|
||||||
parent: BaseMachineCircuitboard
|
|
||||||
name: EXP-2100g "Duster" machine board
|
|
||||||
description: A machine printed circuit board for an EXP-2100g "Duster"
|
|
||||||
suffix: DO NOT MAP, Machine Board
|
|
||||||
components:
|
|
||||||
- type: Sprite
|
|
||||||
state: security
|
|
||||||
- type: MachineBoard
|
|
||||||
prototype: ShuttleGunDuster
|
|
||||||
requirements:
|
|
||||||
MatterBin: 6
|
|
||||||
Manipulator: 4
|
|
||||||
materialRequirements:
|
|
||||||
Steel: 10
|
|
||||||
CableHV: 5
|
|
||||||
Uranium: 2
|
|
||||||
|
|
||||||
- type: entity
|
|
||||||
id: ShuttleGunKineticCircuitboard
|
|
||||||
parent: BaseMachineCircuitboard
|
|
||||||
name: PTK-800 "Matter Dematerializer" machine board
|
|
||||||
description: A machine printed circuit board for an PTK-800 "Matter Dematerializer"
|
|
||||||
suffix: DO NOT MAP, Machine Board
|
|
||||||
components:
|
|
||||||
- type: Sprite
|
|
||||||
state: security
|
|
||||||
- type: MachineBoard
|
|
||||||
prototype: ShuttleGunKinetic
|
|
||||||
requirements:
|
|
||||||
MatterBin: 2
|
|
||||||
Manipulator: 3
|
|
||||||
materialRequirements:
|
|
||||||
Steel: 5
|
|
||||||
CableHV: 2
|
|
||||||
@@ -1277,6 +1277,92 @@
|
|||||||
CableHV: 5
|
CableHV: 5
|
||||||
Uranium: 2
|
Uranium: 2
|
||||||
|
|
||||||
|
- type: entity
|
||||||
|
id: ShuttleGunSvalinnMachineGunCircuitboard
|
||||||
|
parent: BaseMachineCircuitboard
|
||||||
|
name: LSE-400c "Svalinn machine gun" machine board
|
||||||
|
description: A machine printed circuit board for an LSE-400c "Svalinn machine gun"
|
||||||
|
components:
|
||||||
|
- type: Sprite
|
||||||
|
state: security
|
||||||
|
- type: MachineBoard
|
||||||
|
prototype: ShuttleGunSvalinnMachineGun
|
||||||
|
requirements:
|
||||||
|
MatterBin: 2
|
||||||
|
Manipulator: 4
|
||||||
|
materialRequirements:
|
||||||
|
Steel: 5
|
||||||
|
CableHV: 5
|
||||||
|
|
||||||
|
- type: entity
|
||||||
|
id: ShuttleGunPerforatorCircuitboard
|
||||||
|
parent: BaseMachineCircuitboard
|
||||||
|
name: LSE-1200c "Perforator" machine board
|
||||||
|
description: A machine printed circuit board for an LSE-1200c "Perforator"
|
||||||
|
components:
|
||||||
|
- type: Sprite
|
||||||
|
state: security
|
||||||
|
- type: MachineBoard
|
||||||
|
prototype: ShuttleGunPerforator
|
||||||
|
requirements:
|
||||||
|
MatterBin: 4
|
||||||
|
Manipulator: 6
|
||||||
|
materialRequirements:
|
||||||
|
Steel: 10
|
||||||
|
CableHV: 5
|
||||||
|
|
||||||
|
- type: entity
|
||||||
|
id: ShuttleGunFriendshipCircuitboard
|
||||||
|
parent: BaseMachineCircuitboard
|
||||||
|
name: EXP-320g "Friendship" machine board
|
||||||
|
description: A machine printed circuit board for an EXP-320g "Friendship"
|
||||||
|
components:
|
||||||
|
- type: Sprite
|
||||||
|
state: security
|
||||||
|
- type: MachineBoard
|
||||||
|
prototype: ShuttleGunFriendship
|
||||||
|
requirements:
|
||||||
|
MatterBin: 3
|
||||||
|
Manipulator: 2
|
||||||
|
materialRequirements:
|
||||||
|
Steel: 7
|
||||||
|
CableHV: 5
|
||||||
|
|
||||||
|
- type: entity
|
||||||
|
id: ShuttleGunDusterCircuitboard
|
||||||
|
parent: BaseMachineCircuitboard
|
||||||
|
name: EXP-2100g "Duster" machine board
|
||||||
|
description: A machine printed circuit board for an EXP-2100g "Duster"
|
||||||
|
components:
|
||||||
|
- type: Sprite
|
||||||
|
state: security
|
||||||
|
- type: MachineBoard
|
||||||
|
prototype: ShuttleGunDuster
|
||||||
|
requirements:
|
||||||
|
MatterBin: 6
|
||||||
|
Manipulator: 4
|
||||||
|
materialRequirements:
|
||||||
|
Steel: 10
|
||||||
|
CableHV: 5
|
||||||
|
Uranium: 2
|
||||||
|
|
||||||
|
- type: entity
|
||||||
|
id: ShuttleGunKineticCircuitboard
|
||||||
|
parent: BaseMachineCircuitboard
|
||||||
|
name: PTK-800 "Matter Dematerializer" machine board
|
||||||
|
description: A machine printed circuit board for an PTK-800 "Matter Dematerializer"
|
||||||
|
components:
|
||||||
|
- type: Sprite
|
||||||
|
state: security
|
||||||
|
- type: MachineBoard
|
||||||
|
prototype: ShuttleGunKinetic
|
||||||
|
requirements:
|
||||||
|
MatterBin: 2
|
||||||
|
Manipulator: 3
|
||||||
|
materialRequirements:
|
||||||
|
Steel: 5
|
||||||
|
CableHV: 2
|
||||||
|
|
||||||
- type: entity
|
- type: entity
|
||||||
parent: BaseMachineCircuitboard
|
parent: BaseMachineCircuitboard
|
||||||
id: ReagentGrinderIndustrialMachineCircuitboard
|
id: ReagentGrinderIndustrialMachineCircuitboard
|
||||||
|
|||||||
@@ -184,12 +184,3 @@
|
|||||||
- state: overlay
|
- state: overlay
|
||||||
color: "#cec8ac"
|
color: "#cec8ac"
|
||||||
- state: icon-default
|
- state: icon-default
|
||||||
|
|
||||||
- type: entity
|
|
||||||
parent: BaseFlatpack
|
|
||||||
id: SpaceHeaterFlatpack
|
|
||||||
name: space heater flatpack
|
|
||||||
description: A flatpack used for constructing a space heater.
|
|
||||||
components:
|
|
||||||
- type: Flatpack
|
|
||||||
entity: SpaceHeaterAnchored
|
|
||||||
|
|||||||
@@ -29,7 +29,7 @@
|
|||||||
components:
|
components:
|
||||||
- type: Instrument
|
- type: Instrument
|
||||||
- type: ActivatableUI
|
- type: ActivatableUI
|
||||||
blockSpectators: true # otherwise they can play client-side music
|
allowSpectator: false # otherwise they can play client-side music
|
||||||
inHandsOnly: false
|
inHandsOnly: false
|
||||||
singleUser: true
|
singleUser: true
|
||||||
requireHands: true
|
requireHands: true
|
||||||
|
|||||||
@@ -126,8 +126,8 @@
|
|||||||
maxVol: 7
|
maxVol: 7
|
||||||
- type: SolutionInjectOnEmbed
|
- type: SolutionInjectOnEmbed
|
||||||
transferAmount: 7
|
transferAmount: 7
|
||||||
blockSlots: NONE
|
|
||||||
solution: melee
|
solution: melee
|
||||||
|
blockSlots: NONE
|
||||||
- type: SolutionTransfer
|
- type: SolutionTransfer
|
||||||
maxTransferAmount: 7
|
maxTransferAmount: 7
|
||||||
|
|
||||||
|
|||||||
@@ -325,12 +325,11 @@
|
|||||||
emptyCase: { state: empty }
|
emptyCase: { state: empty }
|
||||||
wiredCase: { state: wired }
|
wiredCase: { state: wired }
|
||||||
caseWithTrigger: { state: no-payload }
|
caseWithTrigger: { state: no-payload }
|
||||||
caseWithPayload: { state: no-trigger }
|
|
||||||
grenade: { state: complete }
|
grenade: { state: complete }
|
||||||
enum.Trigger.TriggerVisuals.VisualState:
|
enum.Trigger.TriggerVisuals.VisualState:
|
||||||
enum.ConstructionVisuals.Layer:
|
enum.ConstructionVisuals.Layer:
|
||||||
Primed: { state: primed }
|
Primed: { state: primed }
|
||||||
# Unprimed: <Use state determined by enum.ConstructionVisuals.Layer>
|
Unprimed: { state: complete }
|
||||||
- type: StaticPrice
|
- type: StaticPrice
|
||||||
price: 25
|
price: 25
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
# Most of these have DO NOT MAP, since stations are completely unequipped to deal with ship combat + these are basically placeholder.
|
|
||||||
|
|
||||||
- type: entity
|
- type: entity
|
||||||
id: ShuttleGunBase
|
id: ShuttleGunBase
|
||||||
name: shittle gun
|
name: shittle gun
|
||||||
@@ -60,8 +58,7 @@
|
|||||||
id: ShuttleGunSvalinnMachineGun
|
id: ShuttleGunSvalinnMachineGun
|
||||||
parent: [ ShuttleGunBase, ConstructibleMachine]
|
parent: [ ShuttleGunBase, ConstructibleMachine]
|
||||||
name: LSE-400c "Svalinn machine gun"
|
name: LSE-400c "Svalinn machine gun"
|
||||||
description: Basic stationary laser unit. Effective against live targets and electronics. Uses regular power cells to fire, and has an extremely high rate of fire.
|
description: Basic stationary laser unit. Effective against live targets and electronics. Uses regular power cells to fire, and has an extremely high rate of fire
|
||||||
suffix: DO NOT MAP
|
|
||||||
components:
|
components:
|
||||||
- type: Sprite
|
- type: Sprite
|
||||||
sprite: Objects/Weapons/Guns/Shuttles/laser.rsi
|
sprite: Objects/Weapons/Guns/Shuttles/laser.rsi
|
||||||
@@ -116,7 +113,6 @@
|
|||||||
parent: [ ShuttleGunBase, ConstructibleMachine]
|
parent: [ ShuttleGunBase, ConstructibleMachine]
|
||||||
name: LSE-1200c "Perforator"
|
name: LSE-1200c "Perforator"
|
||||||
description: Advanced stationary laser unit. Annihilates electronics and is extremely dangerous to health! Uses the power cage to fire.
|
description: Advanced stationary laser unit. Annihilates electronics and is extremely dangerous to health! Uses the power cage to fire.
|
||||||
suffix: DO NOT MAP
|
|
||||||
components:
|
components:
|
||||||
- type: Sprite
|
- type: Sprite
|
||||||
sprite: Objects/Weapons/Guns/Shuttles/laser.rsi
|
sprite: Objects/Weapons/Guns/Shuttles/laser.rsi
|
||||||
@@ -173,7 +169,6 @@
|
|||||||
parent: [ShuttleGunBase, ConstructibleMachine]
|
parent: [ShuttleGunBase, ConstructibleMachine]
|
||||||
name: EXP-320g "Friendship"
|
name: EXP-320g "Friendship"
|
||||||
description: A small stationary grenade launcher that holds 2 grenades.
|
description: A small stationary grenade launcher that holds 2 grenades.
|
||||||
suffix: DO NOT MAP
|
|
||||||
components:
|
components:
|
||||||
- type: Sprite
|
- type: Sprite
|
||||||
sprite: Objects/Weapons/Guns/Shuttles/launcher.rsi
|
sprite: Objects/Weapons/Guns/Shuttles/launcher.rsi
|
||||||
@@ -227,7 +222,6 @@
|
|||||||
parent: [ShuttleGunBase, ConstructibleMachine]
|
parent: [ShuttleGunBase, ConstructibleMachine]
|
||||||
name: EXP-2100g "Duster"
|
name: EXP-2100g "Duster"
|
||||||
description: A powerful stationary grenade launcher. A cartridge is required for use.
|
description: A powerful stationary grenade launcher. A cartridge is required for use.
|
||||||
suffix: DO NOT MAP
|
|
||||||
components:
|
components:
|
||||||
- type: Sprite
|
- type: Sprite
|
||||||
sprite: Objects/Weapons/Guns/Shuttles/launcher.rsi
|
sprite: Objects/Weapons/Guns/Shuttles/launcher.rsi
|
||||||
@@ -325,7 +319,6 @@
|
|||||||
parent: [ ShuttleGunBase, ConstructibleMachine]
|
parent: [ ShuttleGunBase, ConstructibleMachine]
|
||||||
name: PTK-800 "Matter Dematerializer"
|
name: PTK-800 "Matter Dematerializer"
|
||||||
description: Salvage stationary mining turret. Gradually accumulates charges on its own, extremely effective for asteroid excavation.
|
description: Salvage stationary mining turret. Gradually accumulates charges on its own, extremely effective for asteroid excavation.
|
||||||
suffix: DO NOT MAP
|
|
||||||
components:
|
components:
|
||||||
- type: Sprite
|
- type: Sprite
|
||||||
sprite: Objects/Weapons/Guns/Shuttles/kinetic.rsi
|
sprite: Objects/Weapons/Guns/Shuttles/kinetic.rsi
|
||||||
|
|||||||
@@ -413,9 +413,9 @@
|
|||||||
prototype: InitialInfected
|
prototype: InitialInfected
|
||||||
|
|
||||||
- type: entity
|
- type: entity
|
||||||
noSpawn: true
|
|
||||||
parent: BaseNukeopsRule
|
|
||||||
id: LoneOpsSpawn
|
id: LoneOpsSpawn
|
||||||
|
parent: BaseGameRule
|
||||||
|
noSpawn: true
|
||||||
components:
|
components:
|
||||||
- type: StationEvent
|
- type: StationEvent
|
||||||
earliestStart: 35
|
earliestStart: 35
|
||||||
@@ -447,9 +447,9 @@
|
|||||||
prototype: Nukeops
|
prototype: Nukeops
|
||||||
|
|
||||||
- type: entity
|
- type: entity
|
||||||
noSpawn: true
|
|
||||||
parent: BaseTraitorRule
|
|
||||||
id: SleeperAgentsRule
|
id: SleeperAgentsRule
|
||||||
|
parent: BaseGameRule
|
||||||
|
noSpawn: true
|
||||||
components:
|
components:
|
||||||
- type: StationEvent
|
- type: StationEvent
|
||||||
earliestStart: 30
|
earliestStart: 30
|
||||||
@@ -460,6 +460,7 @@
|
|||||||
startAudio:
|
startAudio:
|
||||||
path: /Audio/Announcements/intercept.ogg
|
path: /Audio/Announcements/intercept.ogg
|
||||||
- type: AlertLevelInterceptionRule
|
- type: AlertLevelInterceptionRule
|
||||||
|
- type: TraitorRule
|
||||||
- type: AntagSelection
|
- type: AntagSelection
|
||||||
definitions:
|
definitions:
|
||||||
- prefRoles: [ Traitor ]
|
- prefRoles: [ Traitor ]
|
||||||
|
|||||||
@@ -35,19 +35,7 @@
|
|||||||
id: Thief
|
id: Thief
|
||||||
components:
|
components:
|
||||||
- type: ThiefRule
|
- type: ThiefRule
|
||||||
- type: AntagObjectives
|
|
||||||
objectives:
|
|
||||||
- EscapeThiefShuttleObjective
|
|
||||||
- type: AntagRandomObjectives
|
|
||||||
sets:
|
|
||||||
- groups: ThiefBigObjectiveGroups
|
|
||||||
prob: 0.7
|
|
||||||
maxPicks: 1
|
|
||||||
- groups: ThiefObjectiveGroups
|
|
||||||
maxPicks: 10
|
|
||||||
maxDifficulty: 2.5
|
|
||||||
- type: AntagSelection
|
- type: AntagSelection
|
||||||
agentName: thief-round-end-agent-name
|
|
||||||
definitions:
|
definitions:
|
||||||
- prefRoles: [ Thief ]
|
- prefRoles: [ Thief ]
|
||||||
maxRange:
|
maxRange:
|
||||||
|
|||||||
@@ -64,9 +64,9 @@
|
|||||||
roundEndDelay: 10
|
roundEndDelay: 10
|
||||||
|
|
||||||
- type: entity
|
- type: entity
|
||||||
abstract: true
|
id: Nukeops
|
||||||
parent: BaseGameRule
|
parent: BaseGameRule
|
||||||
id: BaseNukeopsRule
|
noSpawn: true
|
||||||
components:
|
components:
|
||||||
- type: GameRule
|
- type: GameRule
|
||||||
minPlayers: 20 # Honk
|
minPlayers: 20 # Honk
|
||||||
@@ -75,16 +75,6 @@
|
|||||||
- operationPrefix
|
- operationPrefix
|
||||||
- operationSuffix
|
- operationSuffix
|
||||||
- type: NukeopsRule
|
- type: NukeopsRule
|
||||||
- type: AntagSelection
|
|
||||||
- type: AntagLoadProfileRule
|
|
||||||
|
|
||||||
- type: entity
|
|
||||||
noSpawn: true
|
|
||||||
parent: BaseNukeopsRule
|
|
||||||
id: Nukeops
|
|
||||||
components:
|
|
||||||
- type: GameRule
|
|
||||||
minPlayers: 20
|
|
||||||
- type: LoadMapRule
|
- type: LoadMapRule
|
||||||
gameMap: NukieOutpost
|
gameMap: NukieOutpost
|
||||||
- type: AntagSelection
|
- type: AntagSelection
|
||||||
@@ -148,30 +138,16 @@
|
|||||||
prototype: Nukeops
|
prototype: Nukeops
|
||||||
|
|
||||||
- type: entity
|
- type: entity
|
||||||
abstract: true
|
|
||||||
parent: BaseGameRule
|
|
||||||
id: BaseTraitorRule
|
|
||||||
components:
|
|
||||||
- type: TraitorRule
|
|
||||||
# TODO: codewords in yml
|
|
||||||
# TODO: uplink in yml
|
|
||||||
- type: AntagRandomObjectives
|
|
||||||
sets:
|
|
||||||
- groups: TraitorObjectiveGroups
|
|
||||||
maxDifficulty: 5
|
|
||||||
- type: AntagSelection
|
|
||||||
agentName: traitor-round-end-agent-name
|
|
||||||
|
|
||||||
- type: entity
|
|
||||||
noSpawn: true
|
|
||||||
parent: BaseTraitorRule
|
|
||||||
id: Traitor
|
id: Traitor
|
||||||
|
parent: BaseGameRule
|
||||||
|
noSpawn: true
|
||||||
components:
|
components:
|
||||||
- type: GameRule
|
- type: GameRule
|
||||||
minPlayers: 5
|
minPlayers: 5
|
||||||
delay:
|
delay:
|
||||||
min: 240
|
min: 240
|
||||||
max: 420
|
max: 420
|
||||||
|
- type: TraitorRule
|
||||||
- type: AntagSelection
|
- type: AntagSelection
|
||||||
definitions:
|
definitions:
|
||||||
- prefRoles: [ Traitor ]
|
- prefRoles: [ Traitor ]
|
||||||
|
|||||||
@@ -55,6 +55,13 @@
|
|||||||
ThiefObjectiveGroupStructure: 0 #Temporarily disabled until obvious ways to steal structures are added
|
ThiefObjectiveGroupStructure: 0 #Temporarily disabled until obvious ways to steal structures are added
|
||||||
ThiefObjectiveGroupAnimal: 2
|
ThiefObjectiveGroupAnimal: 2
|
||||||
|
|
||||||
|
- type: weightedRandom
|
||||||
|
id: ThiefEscapeObjectiveGroups
|
||||||
|
weights:
|
||||||
|
ThiefObjectiveGroupEscape: 1
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
- type: weightedRandom
|
- type: weightedRandom
|
||||||
id: ThiefObjectiveGroupCollection
|
id: ThiefObjectiveGroupCollection
|
||||||
weights:
|
weights:
|
||||||
|
|||||||
@@ -50,12 +50,6 @@
|
|||||||
store: payloadTrigger
|
store: payloadTrigger
|
||||||
name: триггер
|
name: триггер
|
||||||
doAfter: 0.5
|
doAfter: 0.5
|
||||||
- to: caseWithPayload
|
|
||||||
steps:
|
|
||||||
- tag: Payload
|
|
||||||
store: payload
|
|
||||||
name: Payload
|
|
||||||
doAfter: 0.5
|
|
||||||
|
|
||||||
- node: caseWithTrigger
|
- node: caseWithTrigger
|
||||||
actions:
|
actions:
|
||||||
@@ -77,26 +71,6 @@
|
|||||||
name: заряд
|
name: заряд
|
||||||
doAfter: 0.5
|
doAfter: 0.5
|
||||||
|
|
||||||
- node: caseWithPayload
|
|
||||||
actions:
|
|
||||||
- !type:AppearanceChange
|
|
||||||
- !type:PlaySound
|
|
||||||
sound: /Audio/Machines/button.ogg
|
|
||||||
edges:
|
|
||||||
- to: wiredCase
|
|
||||||
steps:
|
|
||||||
- tool: Prying
|
|
||||||
doAfter: 0.5
|
|
||||||
completed:
|
|
||||||
- !type:EmptyContainer
|
|
||||||
container: payload
|
|
||||||
- to: grenade
|
|
||||||
steps:
|
|
||||||
- component: PayloadTrigger
|
|
||||||
store: payloadTrigger
|
|
||||||
name: Trigger
|
|
||||||
doAfter: 0.5
|
|
||||||
|
|
||||||
- node: grenade
|
- node: grenade
|
||||||
actions:
|
actions:
|
||||||
- !type:AppearanceChange
|
- !type:AppearanceChange
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"version": 1,
|
"version": 1,
|
||||||
"license": "CC-BY-SA-3.0",
|
"license": "CC-BY-SA-3.0",
|
||||||
"copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/29c0ed1b000619cb5398ef921000a8d4502ba0b6 and modified by Swept & ElectroSR",
|
"copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/29c0ed1b000619cb5398ef921000a8d4502ba0b6 and modified by Swept",
|
||||||
"size": {
|
"size": {
|
||||||
"x": 32,
|
"x": 32,
|
||||||
"y": 32
|
"y": 32
|
||||||
@@ -19,10 +19,6 @@
|
|||||||
"name": "no-payload",
|
"name": "no-payload",
|
||||||
"directions": 1
|
"directions": 1
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"name": "no-trigger",
|
|
||||||
"directions": 1
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"name": "complete",
|
"name": "complete",
|
||||||
"directions": 1
|
"directions": 1
|
||||||
|
|||||||
Binary file not shown.
|
Before Width: | Height: | Size: 347 B |
Submodule RobustToolbox updated: 721408bb37...ec794ce4e4
Reference in New Issue
Block a user