Merge branch 'master' into pr/39203
This commit is contained in:
1
.github/CODEOWNERS
vendored
1
.github/CODEOWNERS
vendored
@@ -9,6 +9,7 @@
|
|||||||
/Resources/ServerInfo/Guidebook/ServerRules/ @crazybrain23
|
/Resources/ServerInfo/Guidebook/ServerRules/ @crazybrain23
|
||||||
|
|
||||||
/Resources/Prototypes/Maps/** @Emisse @ArtisticRoomba
|
/Resources/Prototypes/Maps/** @Emisse @ArtisticRoomba
|
||||||
|
/Resources/Maps/** @Emisse @ArtisticRoomba
|
||||||
|
|
||||||
/Resources/Prototypes/Body/ @DrSmugleaf # suffering
|
/Resources/Prototypes/Body/ @DrSmugleaf # suffering
|
||||||
/Resources/Prototypes/Entities/Mobs/Player/ @DrSmugleaf
|
/Resources/Prototypes/Entities/Mobs/Player/ @DrSmugleaf
|
||||||
|
|||||||
@@ -6,7 +6,6 @@ using BenchmarkDotNet.Attributes;
|
|||||||
using Content.IntegrationTests;
|
using Content.IntegrationTests;
|
||||||
using Content.IntegrationTests.Pair;
|
using Content.IntegrationTests.Pair;
|
||||||
using Content.Server.Mind;
|
using Content.Server.Mind;
|
||||||
using Content.Server.Warps;
|
|
||||||
using Content.Shared.Warps;
|
using Content.Shared.Warps;
|
||||||
using Robust.Shared;
|
using Robust.Shared;
|
||||||
using Robust.Shared.Analyzers;
|
using Robust.Shared.Analyzers;
|
||||||
|
|||||||
@@ -1,10 +0,0 @@
|
|||||||
using Content.Shared.Administration.Components;
|
|
||||||
using Robust.Shared.GameStates;
|
|
||||||
|
|
||||||
namespace Content.Client.Administration.Components;
|
|
||||||
|
|
||||||
[RegisterComponent]
|
|
||||||
public sealed partial class HeadstandComponent : SharedHeadstandComponent
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
using Content.Client.Administration.Components;
|
using Content.Shared.Administration.Components;
|
||||||
using Robust.Client.GameObjects;
|
using Robust.Client.GameObjects;
|
||||||
|
|
||||||
namespace Content.Client.Administration.Systems;
|
namespace Content.Client.Administration.Systems;
|
||||||
|
|||||||
5
Content.Client/Animals/Systems/ParrotMemorySystem.cs
Normal file
5
Content.Client/Animals/Systems/ParrotMemorySystem.cs
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
using Content.Shared.Animals.Systems;
|
||||||
|
|
||||||
|
namespace Content.Client.Animals.Systems;
|
||||||
|
|
||||||
|
public sealed class ParrotMemorySystem : SharedParrotMemorySystem;
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
using Content.Shared.Anomaly.Components;
|
using Content.Shared.Anomaly.Components;
|
||||||
using Content.Shared.Anomaly.Effects;
|
using Content.Shared.Anomaly.Effects;
|
||||||
using Content.Shared.Body.Components;
|
using Content.Shared.Humanoid;
|
||||||
using Robust.Client.GameObjects;
|
using Robust.Client.GameObjects;
|
||||||
|
|
||||||
namespace Content.Client.Anomaly.Effects;
|
namespace Content.Client.Anomaly.Effects;
|
||||||
@@ -25,9 +25,8 @@ public sealed class ClientInnerBodyAnomalySystem : SharedInnerBodyAnomalySystem
|
|||||||
|
|
||||||
var index = _sprite.LayerMapReserve((ent.Owner, sprite), ent.Comp.LayerMap);
|
var index = _sprite.LayerMapReserve((ent.Owner, sprite), ent.Comp.LayerMap);
|
||||||
|
|
||||||
if (TryComp<BodyComponent>(ent, out var body) &&
|
if (TryComp<HumanoidAppearanceComponent>(ent, out var humanoidAppearance) &&
|
||||||
body.Prototype is not null &&
|
ent.Comp.SpeciesSprites.TryGetValue(humanoidAppearance.Species, out var speciesSprite))
|
||||||
ent.Comp.SpeciesSprites.TryGetValue(body.Prototype.Value, out var speciesSprite))
|
|
||||||
{
|
{
|
||||||
_sprite.LayerSetSprite((ent.Owner, sprite), index, speciesSprite);
|
_sprite.LayerSetSprite((ent.Owner, sprite), index, speciesSprite);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,46 +1,11 @@
|
|||||||
using Content.Client.Atmos.Components;
|
using Content.Client.Atmos.Components;
|
||||||
using Robust.Client.GameObjects;
|
using Robust.Client.GameObjects;
|
||||||
using Content.Client.UserInterface.Systems.Storage.Controls;
|
|
||||||
using Content.Shared.Atmos.Piping;
|
using Content.Shared.Atmos.Piping;
|
||||||
using Content.Shared.Hands;
|
|
||||||
using Content.Shared.Atmos.Components;
|
|
||||||
using Content.Shared.Item;
|
|
||||||
|
|
||||||
namespace Content.Client.Atmos.EntitySystems;
|
namespace Content.Client.Atmos.EntitySystems;
|
||||||
|
|
||||||
public sealed class PipeColorVisualizerSystem : VisualizerSystem<PipeColorVisualsComponent>
|
public sealed class PipeColorVisualizerSystem : VisualizerSystem<PipeColorVisualsComponent>
|
||||||
{
|
{
|
||||||
[Dependency] private readonly SharedItemSystem _itemSystem = default!;
|
|
||||||
|
|
||||||
public override void Initialize()
|
|
||||||
{
|
|
||||||
base.Initialize();
|
|
||||||
|
|
||||||
SubscribeLocalEvent<PipeColorVisualsComponent, GetInhandVisualsEvent>(OnGetVisuals);
|
|
||||||
SubscribeLocalEvent<PipeColorVisualsComponent, BeforeRenderInGridEvent>(OnDrawInGrid);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// This method is used to display the color changes of the pipe on the screen..
|
|
||||||
/// </summary>
|
|
||||||
private void OnGetVisuals(Entity<PipeColorVisualsComponent> item, ref GetInhandVisualsEvent args)
|
|
||||||
{
|
|
||||||
foreach (var (_, layerData) in args.Layers)
|
|
||||||
{
|
|
||||||
if (TryComp(item.Owner, out AtmosPipeColorComponent? pipeColor))
|
|
||||||
layerData.Color = pipeColor.Color;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// This method is used to change the pipe's color in a container grid.
|
|
||||||
/// </summary>
|
|
||||||
private void OnDrawInGrid(Entity<PipeColorVisualsComponent> item, ref BeforeRenderInGridEvent args)
|
|
||||||
{
|
|
||||||
if (TryComp(item.Owner, out AtmosPipeColorComponent? pipeColor))
|
|
||||||
args.Color = pipeColor.Color;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void OnAppearanceChange(EntityUid uid, PipeColorVisualsComponent component, ref AppearanceChangeEvent args)
|
protected override void OnAppearanceChange(EntityUid uid, PipeColorVisualsComponent component, ref AppearanceChangeEvent args)
|
||||||
{
|
{
|
||||||
if (TryComp<SpriteComponent>(uid, out var sprite)
|
if (TryComp<SpriteComponent>(uid, out var sprite)
|
||||||
@@ -50,8 +15,6 @@ public sealed class PipeColorVisualizerSystem : VisualizerSystem<PipeColorVisual
|
|||||||
var layer = sprite[PipeVisualLayers.Pipe];
|
var layer = sprite[PipeVisualLayers.Pipe];
|
||||||
layer.Color = color.WithAlpha(layer.Color.A);
|
layer.Color = color.WithAlpha(layer.Color.A);
|
||||||
}
|
}
|
||||||
|
|
||||||
_itemSystem.VisualsChanged(uid);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -59,7 +59,7 @@ public sealed partial class PumpControl : BoxContainer
|
|||||||
|
|
||||||
foreach (var value in Enum.GetValues<VentPumpDirection>())
|
foreach (var value in Enum.GetValues<VentPumpDirection>())
|
||||||
{
|
{
|
||||||
_pumpDirection.AddItem(Loc.GetString($"{value}"), (int) value);
|
_pumpDirection.AddItem(Loc.GetString($"air-alarm-ui-pump-direction-{value.ToString().ToLower()}"), (int) value);
|
||||||
}
|
}
|
||||||
|
|
||||||
_pumpDirection.SelectId((int) _data.PumpDirection);
|
_pumpDirection.SelectId((int) _data.PumpDirection);
|
||||||
@@ -72,7 +72,7 @@ public sealed partial class PumpControl : BoxContainer
|
|||||||
|
|
||||||
foreach (var value in Enum.GetValues<VentPressureBound>())
|
foreach (var value in Enum.GetValues<VentPressureBound>())
|
||||||
{
|
{
|
||||||
_pressureCheck.AddItem(Loc.GetString($"{value}"), (int) value);
|
_pressureCheck.AddItem(Loc.GetString($"air-alarm-ui-pressure-bound-{value.ToString().ToLower()}"), (int) value);
|
||||||
}
|
}
|
||||||
|
|
||||||
_pressureCheck.SelectId((int) _data.PressureChecks);
|
_pressureCheck.SelectId((int) _data.PressureChecks);
|
||||||
|
|||||||
@@ -27,9 +27,15 @@
|
|||||||
</BoxContainer>
|
</BoxContainer>
|
||||||
<!-- Lower row: every single gas -->
|
<!-- Lower row: every single gas -->
|
||||||
<Collapsible Margin="2 2 2 2">
|
<Collapsible Margin="2 2 2 2">
|
||||||
<CollapsibleHeading Title="Gas filters" />
|
<CollapsibleHeading Title="{Loc 'air-alarm-ui-widget-gas-filters'}" />
|
||||||
<CollapsibleBody Margin="20 0 0 0">
|
<CollapsibleBody Margin="20 0 0 0">
|
||||||
<GridContainer HorizontalExpand="True" Name="CGasContainer" Columns="3" />
|
<BoxContainer Orientation="Vertical">
|
||||||
|
<BoxContainer Margin="2">
|
||||||
|
<Button Name="CSelectAll" Text="{Loc 'air-alarm-ui-scrubber-select-all-gases-label'}" />
|
||||||
|
<Button Name="CDeselectAll" Text="{Loc 'air-alarm-ui-scrubber-deselect-all-gases-label'}" />
|
||||||
|
</BoxContainer>
|
||||||
|
<GridContainer Name="CGasContainer" Columns="3" />
|
||||||
|
</BoxContainer>
|
||||||
</CollapsibleBody>
|
</CollapsibleBody>
|
||||||
</Collapsible>
|
</Collapsible>
|
||||||
</BoxContainer>
|
</BoxContainer>
|
||||||
|
|||||||
@@ -1,15 +1,21 @@
|
|||||||
using Content.Shared.Atmos;
|
using Content.Shared.Atmos;
|
||||||
|
using Content.Shared.Atmos.EntitySystems;
|
||||||
using Content.Shared.Atmos.Monitor.Components;
|
using Content.Shared.Atmos.Monitor.Components;
|
||||||
using Content.Shared.Atmos.Piping.Unary.Components;
|
using Content.Shared.Atmos.Piping.Unary.Components;
|
||||||
|
using Content.Shared.Atmos.Prototypes;
|
||||||
using Robust.Client.AutoGenerated;
|
using Robust.Client.AutoGenerated;
|
||||||
using Robust.Client.UserInterface.Controls;
|
using Robust.Client.UserInterface.Controls;
|
||||||
using Robust.Client.UserInterface.XAML;
|
using Robust.Client.UserInterface.XAML;
|
||||||
|
using Robust.Shared.Prototypes;
|
||||||
|
|
||||||
namespace Content.Client.Atmos.Monitor.UI.Widgets;
|
namespace Content.Client.Atmos.Monitor.UI.Widgets;
|
||||||
|
|
||||||
[GenerateTypedNameReferences]
|
[GenerateTypedNameReferences]
|
||||||
public sealed partial class ScrubberControl : BoxContainer
|
public sealed partial class ScrubberControl : BoxContainer
|
||||||
{
|
{
|
||||||
|
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
|
||||||
|
[Dependency] private readonly IEntityManager _entMan = default!;
|
||||||
|
|
||||||
private GasVentScrubberData _data;
|
private GasVentScrubberData _data;
|
||||||
private string _address;
|
private string _address;
|
||||||
|
|
||||||
@@ -22,12 +28,18 @@ public sealed partial class ScrubberControl : BoxContainer
|
|||||||
private FloatSpinBox _volumeRate => CVolumeRate;
|
private FloatSpinBox _volumeRate => CVolumeRate;
|
||||||
private CheckBox _wideNet => CWideNet;
|
private CheckBox _wideNet => CWideNet;
|
||||||
private Button _copySettings => CCopySettings;
|
private Button _copySettings => CCopySettings;
|
||||||
|
private Button _selectAll => CSelectAll;
|
||||||
|
private Button _deselectAll => CDeselectAll;
|
||||||
|
|
||||||
private GridContainer _gases => CGasContainer;
|
private GridContainer _gases => CGasContainer;
|
||||||
private Dictionary<Gas, Button> _gasControls = new();
|
private Dictionary<Gas, Button> _gasControls = new();
|
||||||
|
|
||||||
public ScrubberControl(GasVentScrubberData data, string address)
|
public ScrubberControl(GasVentScrubberData data, string address)
|
||||||
{
|
{
|
||||||
|
|
||||||
|
IoCManager.InjectDependencies(this);
|
||||||
|
var atmosphereSystem = _entMan.System<SharedAtmosphereSystem>();
|
||||||
|
|
||||||
RobustXamlLoader.Load(this);
|
RobustXamlLoader.Load(this);
|
||||||
|
|
||||||
Name = address;
|
Name = address;
|
||||||
@@ -61,7 +73,7 @@ public sealed partial class ScrubberControl : BoxContainer
|
|||||||
|
|
||||||
foreach (var value in Enum.GetValues<ScrubberPumpDirection>())
|
foreach (var value in Enum.GetValues<ScrubberPumpDirection>())
|
||||||
{
|
{
|
||||||
_pumpDirection.AddItem(Loc.GetString($"{value}"), (int) value);
|
_pumpDirection.AddItem(Loc.GetString($"air-alarm-ui-pump-direction-{value.ToString().ToLower()}"), (int) value);
|
||||||
}
|
}
|
||||||
|
|
||||||
_pumpDirection.SelectId((int) _data.PumpDirection);
|
_pumpDirection.SelectId((int) _data.PumpDirection);
|
||||||
@@ -78,12 +90,28 @@ public sealed partial class ScrubberControl : BoxContainer
|
|||||||
ScrubberDataCopied?.Invoke(_data);
|
ScrubberDataCopied?.Invoke(_data);
|
||||||
};
|
};
|
||||||
|
|
||||||
foreach (var value in Enum.GetValues<Gas>())
|
var allGases = Enum.GetValues<Gas>();
|
||||||
|
_selectAll.OnPressed += _ =>
|
||||||
{
|
{
|
||||||
|
_data.FilterGases = new HashSet<Gas>(allGases);
|
||||||
|
ScrubberDataChanged?.Invoke(_address, _data);
|
||||||
|
};
|
||||||
|
|
||||||
|
_deselectAll.OnPressed += _ =>
|
||||||
|
{
|
||||||
|
_data.FilterGases = [];
|
||||||
|
ScrubberDataChanged?.Invoke(_address, _data);
|
||||||
|
};
|
||||||
|
|
||||||
|
foreach (var value in allGases)
|
||||||
|
{
|
||||||
|
ProtoId<GasPrototype> gasProtoId = atmosphereSystem.GetGas(value);
|
||||||
|
var gasName = _prototypeManager.Index(gasProtoId).Name;
|
||||||
|
|
||||||
var gasButton = new Button
|
var gasButton = new Button
|
||||||
{
|
{
|
||||||
Name = value.ToString(),
|
Name = value.ToString(),
|
||||||
Text = Loc.GetString($"{value}"),
|
Text = Loc.GetString(gasName),
|
||||||
ToggleMode = true,
|
ToggleMode = true,
|
||||||
HorizontalExpand = true,
|
HorizontalExpand = true,
|
||||||
Pressed = _data.FilterGases.Contains(value)
|
Pressed = _data.FilterGases.Contains(value)
|
||||||
|
|||||||
@@ -1,16 +1,22 @@
|
|||||||
using Content.Client.Message;
|
using Content.Client.Message;
|
||||||
using Content.Shared.Atmos;
|
using Content.Shared.Atmos;
|
||||||
|
using Content.Shared.Atmos.EntitySystems;
|
||||||
using Content.Shared.Atmos.Monitor;
|
using Content.Shared.Atmos.Monitor;
|
||||||
|
using Content.Shared.Atmos.Prototypes;
|
||||||
using Content.Shared.Temperature;
|
using Content.Shared.Temperature;
|
||||||
using Robust.Client.AutoGenerated;
|
using Robust.Client.AutoGenerated;
|
||||||
using Robust.Client.UserInterface.Controls;
|
using Robust.Client.UserInterface.Controls;
|
||||||
using Robust.Client.UserInterface.XAML;
|
using Robust.Client.UserInterface.XAML;
|
||||||
|
using Robust.Shared.Prototypes;
|
||||||
|
|
||||||
namespace Content.Client.Atmos.Monitor.UI.Widgets;
|
namespace Content.Client.Atmos.Monitor.UI.Widgets;
|
||||||
|
|
||||||
[GenerateTypedNameReferences]
|
[GenerateTypedNameReferences]
|
||||||
public sealed partial class SensorInfo : BoxContainer
|
public sealed partial class SensorInfo : BoxContainer
|
||||||
{
|
{
|
||||||
|
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
|
||||||
|
[Dependency] private readonly IEntityManager _entMan = default!;
|
||||||
|
|
||||||
public Action<string, AtmosMonitorThresholdType, AtmosAlarmThreshold, Gas?>? OnThresholdUpdate;
|
public Action<string, AtmosMonitorThresholdType, AtmosAlarmThreshold, Gas?>? OnThresholdUpdate;
|
||||||
public event Action<AtmosSensorData>? SensorDataCopied;
|
public event Action<AtmosSensorData>? SensorDataCopied;
|
||||||
private string _address;
|
private string _address;
|
||||||
@@ -23,6 +29,9 @@ public sealed partial class SensorInfo : BoxContainer
|
|||||||
|
|
||||||
public SensorInfo(AtmosSensorData data, string address)
|
public SensorInfo(AtmosSensorData data, string address)
|
||||||
{
|
{
|
||||||
|
IoCManager.InjectDependencies(this);
|
||||||
|
var atmosphereSystem = _entMan.System<SharedAtmosphereSystem>();
|
||||||
|
|
||||||
RobustXamlLoader.Load(this);
|
RobustXamlLoader.Load(this);
|
||||||
|
|
||||||
_address = address;
|
_address = address;
|
||||||
@@ -45,8 +54,12 @@ public sealed partial class SensorInfo : BoxContainer
|
|||||||
var label = new RichTextLabel();
|
var label = new RichTextLabel();
|
||||||
|
|
||||||
var fractionGas = amount / data.TotalMoles;
|
var fractionGas = amount / data.TotalMoles;
|
||||||
|
|
||||||
|
ProtoId<GasPrototype> gasProtoId = atmosphereSystem.GetGas(gas);
|
||||||
|
var gasName = _prototypeManager.Index(gasProtoId).Name;
|
||||||
|
|
||||||
label.SetMarkup(Loc.GetString("air-alarm-ui-gases-indicator",
|
label.SetMarkup(Loc.GetString("air-alarm-ui-gases-indicator",
|
||||||
("gas", $"{gas}"),
|
("gas", Loc.GetString(gasName)),
|
||||||
("color", AirAlarmWindow.ColorForThreshold(fractionGas, data.GasThresholds[gas])),
|
("color", AirAlarmWindow.ColorForThreshold(fractionGas, data.GasThresholds[gas])),
|
||||||
("amount", $"{amount:0.####}"),
|
("amount", $"{amount:0.####}"),
|
||||||
("percentage", $"{(100 * fractionGas):0.##}")));
|
("percentage", $"{(100 * fractionGas):0.##}")));
|
||||||
@@ -54,7 +67,7 @@ public sealed partial class SensorInfo : BoxContainer
|
|||||||
_gasLabels.Add(gas, label);
|
_gasLabels.Add(gas, label);
|
||||||
|
|
||||||
var threshold = data.GasThresholds[gas];
|
var threshold = data.GasThresholds[gas];
|
||||||
var gasThresholdControl = new ThresholdControl(Loc.GetString($"air-alarm-ui-thresholds-gas-title", ("gas", $"{gas}")), threshold, AtmosMonitorThresholdType.Gas, gas, 100);
|
var gasThresholdControl = new ThresholdControl(Loc.GetString($"air-alarm-ui-thresholds-gas-title"), threshold, AtmosMonitorThresholdType.Gas, gas, 100);
|
||||||
gasThresholdControl.Margin = new Thickness(20, 2, 2, 2);
|
gasThresholdControl.Margin = new Thickness(20, 2, 2, 2);
|
||||||
gasThresholdControl.ThresholdDataChanged += (type, alarmThreshold, arg3) =>
|
gasThresholdControl.ThresholdDataChanged += (type, alarmThreshold, arg3) =>
|
||||||
{
|
{
|
||||||
@@ -90,6 +103,9 @@ public sealed partial class SensorInfo : BoxContainer
|
|||||||
|
|
||||||
public void ChangeData(AtmosSensorData data)
|
public void ChangeData(AtmosSensorData data)
|
||||||
{
|
{
|
||||||
|
IoCManager.InjectDependencies(this);
|
||||||
|
var atmosphereSystem = _entMan.System<SharedAtmosphereSystem>();
|
||||||
|
|
||||||
SensorAddress.Title = Loc.GetString("air-alarm-ui-window-listing-title", ("address", _address), ("state", data.AlarmState));
|
SensorAddress.Title = Loc.GetString("air-alarm-ui-window-listing-title", ("address", _address), ("state", data.AlarmState));
|
||||||
|
|
||||||
AlarmStateLabel.SetMarkup(Loc.GetString("air-alarm-ui-window-alarm-state-indicator",
|
AlarmStateLabel.SetMarkup(Loc.GetString("air-alarm-ui-window-alarm-state-indicator",
|
||||||
@@ -112,8 +128,12 @@ public sealed partial class SensorInfo : BoxContainer
|
|||||||
}
|
}
|
||||||
|
|
||||||
var fractionGas = amount / data.TotalMoles;
|
var fractionGas = amount / data.TotalMoles;
|
||||||
|
|
||||||
|
ProtoId<GasPrototype> gasProtoId = atmosphereSystem.GetGas(gas);
|
||||||
|
var gasName = _prototypeManager.Index(gasProtoId).Name;
|
||||||
|
|
||||||
label.SetMarkup(Loc.GetString("air-alarm-ui-gases-indicator",
|
label.SetMarkup(Loc.GetString("air-alarm-ui-gases-indicator",
|
||||||
("gas", $"{gas}"),
|
("gas", Loc.GetString(gasName)),
|
||||||
("color", AirAlarmWindow.ColorForThreshold(fractionGas, data.GasThresholds[gas])),
|
("color", AirAlarmWindow.ColorForThreshold(fractionGas, data.GasThresholds[gas])),
|
||||||
("amount", $"{amount:0.####}"),
|
("amount", $"{amount:0.####}"),
|
||||||
("percentage", $"{(100 * fractionGas):0.##}")));
|
("percentage", $"{(100 * fractionGas):0.##}")));
|
||||||
|
|||||||
@@ -2,6 +2,6 @@
|
|||||||
HorizontalExpand="True" Orientation="Vertical"
|
HorizontalExpand="True" Orientation="Vertical"
|
||||||
Margin = "20 0 0 0" MinSize="160 0" >
|
Margin = "20 0 0 0" MinSize="160 0" >
|
||||||
<Label Name="CBoundLabel" HorizontalAlignment="Center" />
|
<Label Name="CBoundLabel" HorizontalAlignment="Center" />
|
||||||
<CheckBox Name="CBoundEnabled" HorizontalAlignment="Center" Text="{Loc 'Enable'}" Pressed="True" />
|
<CheckBox Name="CBoundEnabled" HorizontalAlignment="Center" Text="{Loc 'air-alarm-ui-widget-enable'}" Pressed="True" />
|
||||||
<FloatSpinBox Name="CSpinner" />
|
<FloatSpinBox Name="CSpinner" />
|
||||||
</BoxContainer>
|
</BoxContainer>
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
<CollapsibleBody Margin="20 0 0 0">
|
<CollapsibleBody Margin="20 0 0 0">
|
||||||
<BoxContainer Orientation="Vertical">
|
<BoxContainer Orientation="Vertical">
|
||||||
<BoxContainer Orientation="Horizontal">
|
<BoxContainer Orientation="Horizontal">
|
||||||
<CheckBox Name="CEnabled" Text="{Loc 'Enabled'}" />
|
<CheckBox Name="CEnabled" Text="{Loc 'air-alarm-ui-widget-enable'}" />
|
||||||
</BoxContainer>
|
</BoxContainer>
|
||||||
<!-- Upper row: Danger bounds -->
|
<!-- Upper row: Danger bounds -->
|
||||||
<BoxContainer Name="CDangerBounds" Orientation="Horizontal" Margin="0 0 0 2"/>
|
<BoxContainer Name="CDangerBounds" Orientation="Horizontal" Margin="0 0 0 2"/>
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
using System.Numerics;
|
using System.Numerics;
|
||||||
using Content.Shared.Body.Components;
|
|
||||||
using Content.Shared.CardboardBox;
|
using Content.Shared.CardboardBox;
|
||||||
using Content.Shared.CardboardBox.Components;
|
using Content.Shared.CardboardBox.Components;
|
||||||
using Content.Shared.Examine;
|
using Content.Shared.Examine;
|
||||||
|
using Content.Shared.Mobs.Components;
|
||||||
using Content.Shared.Movement.Components;
|
using Content.Shared.Movement.Components;
|
||||||
using Robust.Client.GameObjects;
|
using Robust.Client.GameObjects;
|
||||||
|
|
||||||
@@ -15,13 +15,13 @@ public sealed class CardboardBoxSystem : SharedCardboardBoxSystem
|
|||||||
[Dependency] private readonly ExamineSystemShared _examine = default!;
|
[Dependency] private readonly ExamineSystemShared _examine = default!;
|
||||||
[Dependency] private readonly SpriteSystem _sprite = default!;
|
[Dependency] private readonly SpriteSystem _sprite = default!;
|
||||||
|
|
||||||
private EntityQuery<BodyComponent> _bodyQuery;
|
private EntityQuery<MobStateComponent> _mobStateQuery;
|
||||||
|
|
||||||
public override void Initialize()
|
public override void Initialize()
|
||||||
{
|
{
|
||||||
base.Initialize();
|
base.Initialize();
|
||||||
|
|
||||||
_bodyQuery = GetEntityQuery<BodyComponent>();
|
_mobStateQuery = GetEntityQuery<MobStateComponent>();
|
||||||
|
|
||||||
SubscribeNetworkEvent<PlayBoxEffectMessage>(OnBoxEffect);
|
SubscribeNetworkEvent<PlayBoxEffectMessage>(OnBoxEffect);
|
||||||
}
|
}
|
||||||
@@ -66,8 +66,8 @@ public sealed class CardboardBoxSystem : SharedCardboardBoxSystem
|
|||||||
if (!_examine.InRangeUnOccluded(sourcePos, mapPos, box.Distance, null))
|
if (!_examine.InRangeUnOccluded(sourcePos, mapPos, box.Distance, null))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
// no effect for anything too exotic
|
// no effect for non-mobs that have MobMover, such as mechs and vehicles.
|
||||||
if (!_bodyQuery.HasComp(mob))
|
if (!_mobStateQuery.HasComp(mob))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
var ent = Spawn(box.Effect, mapPos);
|
var ent = Spawn(box.Effect, mapPos);
|
||||||
|
|||||||
@@ -0,0 +1,35 @@
|
|||||||
|
using Content.Shared.Changeling.Transform;
|
||||||
|
using JetBrains.Annotations;
|
||||||
|
using Robust.Client.UserInterface;
|
||||||
|
|
||||||
|
namespace Content.Client.Changeling.Transform;
|
||||||
|
|
||||||
|
[UsedImplicitly]
|
||||||
|
public sealed partial class ChangelingTransformBoundUserInterface(EntityUid owner, Enum uiKey) : BoundUserInterface(owner, uiKey)
|
||||||
|
{
|
||||||
|
private ChangelingTransformMenu? _window;
|
||||||
|
|
||||||
|
protected override void Open()
|
||||||
|
{
|
||||||
|
base.Open();
|
||||||
|
|
||||||
|
_window = this.CreateWindow<ChangelingTransformMenu>();
|
||||||
|
|
||||||
|
_window.OnIdentitySelect += SendIdentitySelect;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void UpdateState(BoundUserInterfaceState state)
|
||||||
|
{
|
||||||
|
base.UpdateState(state);
|
||||||
|
|
||||||
|
if (state is not ChangelingTransformBoundUserInterfaceState current)
|
||||||
|
return;
|
||||||
|
|
||||||
|
_window?.UpdateState(current);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SendIdentitySelect(NetEntity identityId)
|
||||||
|
{
|
||||||
|
SendPredictedMessage(new ChangelingTransformIdentitySelectMessage(identityId));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
<ui:RadialMenu
|
||||||
|
xmlns:ui="clr-namespace:Content.Client.UserInterface.Controls"
|
||||||
|
CloseButtonStyleClass="RadialMenuCloseButton"
|
||||||
|
VerticalExpand="True"
|
||||||
|
HorizontalExpand="True">
|
||||||
|
<ui:RadialContainer Name="Main">
|
||||||
|
</ui:RadialContainer>
|
||||||
|
</ui:RadialMenu>
|
||||||
@@ -0,0 +1,60 @@
|
|||||||
|
using System.Numerics;
|
||||||
|
using Content.Client.UserInterface.Controls;
|
||||||
|
using Content.Shared.Changeling.Transform;
|
||||||
|
using Robust.Client.AutoGenerated;
|
||||||
|
using Robust.Client.UserInterface.Controls;
|
||||||
|
using Robust.Client.UserInterface.XAML;
|
||||||
|
|
||||||
|
namespace Content.Client.Changeling.Transform;
|
||||||
|
|
||||||
|
[GenerateTypedNameReferences]
|
||||||
|
public sealed partial class ChangelingTransformMenu : RadialMenu
|
||||||
|
{
|
||||||
|
[Dependency] private readonly IEntityManager _entity = default!;
|
||||||
|
public event Action<NetEntity>? OnIdentitySelect;
|
||||||
|
|
||||||
|
public ChangelingTransformMenu()
|
||||||
|
{
|
||||||
|
RobustXamlLoader.Load(this);
|
||||||
|
IoCManager.InjectDependencies(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void UpdateState(ChangelingTransformBoundUserInterfaceState state)
|
||||||
|
{
|
||||||
|
Main.DisposeAllChildren();
|
||||||
|
foreach (var identity in state.Identites)
|
||||||
|
{
|
||||||
|
var identityUid = _entity.GetEntity(identity);
|
||||||
|
|
||||||
|
if (!_entity.TryGetComponent<MetaDataComponent>(identityUid, out var metadata))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
var identityName = metadata.EntityName;
|
||||||
|
|
||||||
|
var button = new ChangelingTransformMenuButton()
|
||||||
|
{
|
||||||
|
StyleClasses = { "RadialMenuButton" },
|
||||||
|
SetSize = new Vector2(64, 64),
|
||||||
|
ToolTip = identityName,
|
||||||
|
};
|
||||||
|
|
||||||
|
var entView = new SpriteView()
|
||||||
|
{
|
||||||
|
SetSize = new Vector2(48, 48),
|
||||||
|
VerticalAlignment = VAlignment.Center,
|
||||||
|
HorizontalAlignment = HAlignment.Center,
|
||||||
|
Stretch = SpriteView.StretchMode.Fill,
|
||||||
|
};
|
||||||
|
entView.SetEntity(identityUid);
|
||||||
|
button.OnButtonUp += _ =>
|
||||||
|
{
|
||||||
|
OnIdentitySelect?.Invoke(identity);
|
||||||
|
Close();
|
||||||
|
};
|
||||||
|
button.AddChild(entView);
|
||||||
|
Main.AddChild(button);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public sealed class ChangelingTransformMenuButton : RadialMenuTextureButtonWithSector;
|
||||||
5
Content.Client/Cloning/CloningSystem.cs
Normal file
5
Content.Client/Cloning/CloningSystem.cs
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
using Content.Shared.Cloning;
|
||||||
|
|
||||||
|
namespace Content.Client.Cloning;
|
||||||
|
|
||||||
|
public sealed partial class CloningSystem : SharedCloningSystem;
|
||||||
@@ -59,7 +59,7 @@ public sealed class ClientClothingSystem : ClothingSystem
|
|||||||
base.Initialize();
|
base.Initialize();
|
||||||
|
|
||||||
SubscribeLocalEvent<ClothingComponent, GetEquipmentVisualsEvent>(OnGetVisuals);
|
SubscribeLocalEvent<ClothingComponent, GetEquipmentVisualsEvent>(OnGetVisuals);
|
||||||
SubscribeLocalEvent<ClothingComponent, InventoryTemplateUpdated>(OnInventoryTemplateUpdated);
|
SubscribeLocalEvent<InventoryComponent, InventoryTemplateUpdated>(OnInventoryTemplateUpdated);
|
||||||
|
|
||||||
SubscribeLocalEvent<InventoryComponent, VisualsChangedEvent>(OnVisualsChanged);
|
SubscribeLocalEvent<InventoryComponent, VisualsChangedEvent>(OnVisualsChanged);
|
||||||
SubscribeLocalEvent<SpriteComponent, DidUnequipEvent>(OnDidUnequip);
|
SubscribeLocalEvent<SpriteComponent, DidUnequipEvent>(OnDidUnequip);
|
||||||
@@ -82,20 +82,19 @@ public sealed class ClientClothingSystem : ClothingSystem
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnInventoryTemplateUpdated(Entity<ClothingComponent> ent, ref InventoryTemplateUpdated args)
|
private void OnInventoryTemplateUpdated(Entity<InventoryComponent> ent, ref InventoryTemplateUpdated args)
|
||||||
{
|
{
|
||||||
UpdateAllSlots(ent.Owner, clothing: ent.Comp);
|
UpdateAllSlots(ent.Owner, ent.Comp);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void UpdateAllSlots(
|
private void UpdateAllSlots(
|
||||||
EntityUid uid,
|
EntityUid uid,
|
||||||
InventoryComponent? inventoryComponent = null,
|
InventoryComponent? inventoryComponent = null)
|
||||||
ClothingComponent? clothing = null)
|
|
||||||
{
|
{
|
||||||
var enumerator = _inventorySystem.GetSlotEnumerator((uid, inventoryComponent));
|
var enumerator = _inventorySystem.GetSlotEnumerator((uid, inventoryComponent));
|
||||||
while (enumerator.NextItem(out var item, out var slot))
|
while (enumerator.NextItem(out var item, out var slot))
|
||||||
{
|
{
|
||||||
RenderEquipment(uid, item, slot.Name, inventoryComponent, clothingComponent: clothing);
|
RenderEquipment(uid, item, slot.Name, inventoryComponent);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,53 +1,42 @@
|
|||||||
using Content.Client.Markers;
|
using Content.Client.Markers;
|
||||||
using Content.Client.Popups;
|
using Content.Client.Popups;
|
||||||
using Content.Client.SubFloor;
|
using Content.Client.SubFloor;
|
||||||
using Content.Shared.SubFloor;
|
|
||||||
using Robust.Client.GameObjects;
|
|
||||||
using Robust.Shared.Console;
|
using Robust.Shared.Console;
|
||||||
using DrawDepth = Content.Shared.DrawDepth.DrawDepth;
|
|
||||||
|
|
||||||
namespace Content.Client.Commands;
|
namespace Content.Client.Commands;
|
||||||
|
|
||||||
internal sealed class ShowMarkersCommand : LocalizedCommands
|
internal sealed class ShowMarkersCommand : LocalizedEntityCommands
|
||||||
{
|
{
|
||||||
[Dependency] private readonly IEntitySystemManager _entitySystemManager = default!;
|
[Dependency] private readonly MarkerSystem _markerSystem = default!;
|
||||||
|
|
||||||
public override string Command => "showmarkers";
|
public override string Command => "showmarkers";
|
||||||
|
|
||||||
public override string Help => LocalizationManager.GetString($"cmd-{Command}-help", ("command", Command));
|
|
||||||
|
|
||||||
public override void Execute(IConsoleShell shell, string argStr, string[] args)
|
public override void Execute(IConsoleShell shell, string argStr, string[] args)
|
||||||
{
|
{
|
||||||
_entitySystemManager.GetEntitySystem<MarkerSystem>().MarkersVisible ^= true;
|
_markerSystem.MarkersVisible ^= true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal sealed class ShowSubFloor : LocalizedCommands
|
internal sealed class ShowSubFloor : LocalizedEntityCommands
|
||||||
{
|
{
|
||||||
[Dependency] private readonly IEntitySystemManager _entitySystemManager = default!;
|
[Dependency] private readonly SubFloorHideSystem _subfloorSystem = default!;
|
||||||
|
|
||||||
public override string Command => "showsubfloor";
|
public override string Command => "showsubfloor";
|
||||||
|
|
||||||
public override string Help => LocalizationManager.GetString($"cmd-{Command}-help", ("command", Command));
|
|
||||||
|
|
||||||
public override void Execute(IConsoleShell shell, string argStr, string[] args)
|
public override void Execute(IConsoleShell shell, string argStr, string[] args)
|
||||||
{
|
{
|
||||||
_entitySystemManager.GetEntitySystem<SubFloorHideSystem>().ShowAll ^= true;
|
_subfloorSystem.ShowAll ^= true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal sealed class NotifyCommand : LocalizedCommands
|
internal sealed class NotifyCommand : LocalizedEntityCommands
|
||||||
{
|
{
|
||||||
[Dependency] private readonly IEntitySystemManager _entitySystemManager = default!;
|
[Dependency] private readonly PopupSystem _popupSystem = default!;
|
||||||
|
|
||||||
public override string Command => "notify";
|
public override string Command => "notify";
|
||||||
|
|
||||||
public override string Help => LocalizationManager.GetString($"cmd-{Command}-help", ("command", Command));
|
|
||||||
|
|
||||||
public override void Execute(IConsoleShell shell, string argStr, string[] args)
|
public override void Execute(IConsoleShell shell, string argStr, string[] args)
|
||||||
{
|
{
|
||||||
var message = args[0];
|
_popupSystem.PopupCursor(args[0]);
|
||||||
|
|
||||||
_entitySystemManager.GetEntitySystem<PopupSystem>().PopupCursor(message);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,32 +1,29 @@
|
|||||||
using Content.Client.Actions;
|
using Content.Client.Actions;
|
||||||
using Content.Client.Mapping;
|
|
||||||
using Content.Client.Markers;
|
using Content.Client.Markers;
|
||||||
using JetBrains.Annotations;
|
using Content.Client.SubFloor;
|
||||||
using Robust.Client.Graphics;
|
using Robust.Client.Graphics;
|
||||||
using Robust.Client.State;
|
|
||||||
using Robust.Shared.Console;
|
using Robust.Shared.Console;
|
||||||
|
|
||||||
namespace Content.Client.Commands;
|
namespace Content.Client.Commands;
|
||||||
|
|
||||||
[UsedImplicitly]
|
internal sealed class MappingClientSideSetupCommand : LocalizedEntityCommands
|
||||||
internal sealed class MappingClientSideSetupCommand : LocalizedCommands
|
|
||||||
{
|
{
|
||||||
[Dependency] private readonly IEntitySystemManager _entitySystemManager = default!;
|
|
||||||
[Dependency] private readonly ILightManager _lightManager = default!;
|
[Dependency] private readonly ILightManager _lightManager = default!;
|
||||||
|
[Dependency] private readonly ActionsSystem _actionSystem = default!;
|
||||||
|
[Dependency] private readonly MarkerSystem _markerSystem = default!;
|
||||||
|
[Dependency] private readonly SubFloorHideSystem _subfloorSystem = default!;
|
||||||
|
|
||||||
public override string Command => "mappingclientsidesetup";
|
public override string Command => "mappingclientsidesetup";
|
||||||
|
|
||||||
public override string Help => LocalizationManager.GetString($"cmd-{Command}-help", ("command", Command));
|
|
||||||
|
|
||||||
public override void Execute(IConsoleShell shell, string argStr, string[] args)
|
public override void Execute(IConsoleShell shell, string argStr, string[] args)
|
||||||
{
|
{
|
||||||
if (!_lightManager.LockConsoleAccess)
|
if (_lightManager.LockConsoleAccess)
|
||||||
{
|
return;
|
||||||
_entitySystemManager.GetEntitySystem<MarkerSystem>().MarkersVisible = true;
|
|
||||||
|
_markerSystem.MarkersVisible = true;
|
||||||
_lightManager.Enabled = false;
|
_lightManager.Enabled = false;
|
||||||
shell.ExecuteCommand("showsubfloor");
|
_subfloorSystem.ShowAll = true;
|
||||||
_entitySystemManager.GetEntitySystem<ActionsSystem>().LoadActionAssignments("/mapping_actions.yml", false);
|
_actionSystem.LoadActionAssignments("/mapping_actions.yml", false);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ using Content.Shared.Damage.Systems;
|
|||||||
using Content.Shared.Mobs;
|
using Content.Shared.Mobs;
|
||||||
using Content.Shared.Mobs.Systems;
|
using Content.Shared.Mobs.Systems;
|
||||||
using Robust.Client.GameObjects;
|
using Robust.Client.GameObjects;
|
||||||
|
using Robust.Shared.Utility;
|
||||||
|
|
||||||
namespace Content.Client.Damage.Systems;
|
namespace Content.Client.Damage.Systems;
|
||||||
|
|
||||||
@@ -104,6 +105,8 @@ public sealed partial class StaminaSystem : SharedStaminaSystem
|
|||||||
|
|
||||||
private void PlayAnimation(Entity<StaminaComponent, SpriteComponent> entity)
|
private void PlayAnimation(Entity<StaminaComponent, SpriteComponent> entity)
|
||||||
{
|
{
|
||||||
|
DebugTools.Assert(entity.Comp1.CritThreshold > entity.Comp1.AnimationThreshold, $"Animation threshold on {ToPrettyString(entity)} was not less than the crit threshold. This will cause errors, animation has been cancelled.");
|
||||||
|
|
||||||
var step = Math.Clamp((entity.Comp1.StaminaDamage - entity.Comp1.AnimationThreshold) /
|
var step = Math.Clamp((entity.Comp1.StaminaDamage - entity.Comp1.AnimationThreshold) /
|
||||||
(entity.Comp1.CritThreshold - entity.Comp1.AnimationThreshold),
|
(entity.Comp1.CritThreshold - entity.Comp1.AnimationThreshold),
|
||||||
0f,
|
0f,
|
||||||
|
|||||||
@@ -1,7 +0,0 @@
|
|||||||
using Content.Shared.Explosion.EntitySystems;
|
|
||||||
|
|
||||||
namespace Content.Client.Explosion;
|
|
||||||
|
|
||||||
public sealed class SmokeOnTriggerSystem : SharedSmokeOnTriggerSystem
|
|
||||||
{
|
|
||||||
}
|
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
using Content.Shared.Explosion;
|
|
||||||
using Content.Shared.Explosion.Components;
|
|
||||||
|
|
||||||
namespace Content.Client.Explosion;
|
|
||||||
|
|
||||||
[RegisterComponent, Access(typeof(TriggerSystem))]
|
|
||||||
public sealed partial class TriggerOnProximityComponent : SharedTriggerOnProximityComponent {}
|
|
||||||
@@ -1,10 +0,0 @@
|
|||||||
namespace Content.Client.Explosion;
|
|
||||||
|
|
||||||
public sealed partial class TriggerSystem : EntitySystem
|
|
||||||
{
|
|
||||||
public override void Initialize()
|
|
||||||
{
|
|
||||||
base.Initialize();
|
|
||||||
InitializeProximity();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
5
Content.Client/Forensics/Systems/ForensicsSystem.cs
Normal file
5
Content.Client/Forensics/Systems/ForensicsSystem.cs
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
using Content.Shared.Forensics.Systems;
|
||||||
|
|
||||||
|
namespace Content.Client.Forensics.Systems;
|
||||||
|
|
||||||
|
public sealed class ForensicsSystem : SharedForensicsSystem;
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
using Content.Shared.HotPotato;
|
using Content.Shared.HotPotato;
|
||||||
using Robust.Shared.Random;
|
using Robust.Shared.Random;
|
||||||
|
using Robust.Shared.Prototypes;
|
||||||
using Robust.Shared.Timing;
|
using Robust.Shared.Timing;
|
||||||
|
|
||||||
namespace Content.Client.HotPotato;
|
namespace Content.Client.HotPotato;
|
||||||
@@ -10,6 +11,9 @@ public sealed class HotPotatoSystem : SharedHotPotatoSystem
|
|||||||
[Dependency] private readonly IRobustRandom _random = default!;
|
[Dependency] private readonly IRobustRandom _random = default!;
|
||||||
[Dependency] private readonly SharedTransformSystem _transform = default!;
|
[Dependency] private readonly SharedTransformSystem _transform = default!;
|
||||||
|
|
||||||
|
private readonly EntProtoId _hotPotatoEffectId = "HotPotatoEffect";
|
||||||
|
|
||||||
|
// TODO: particle system
|
||||||
public override void Update(float frameTime)
|
public override void Update(float frameTime)
|
||||||
{
|
{
|
||||||
base.Update(frameTime);
|
base.Update(frameTime);
|
||||||
@@ -23,7 +27,7 @@ public sealed class HotPotatoSystem : SharedHotPotatoSystem
|
|||||||
if (_timing.CurTime < comp.TargetTime)
|
if (_timing.CurTime < comp.TargetTime)
|
||||||
continue;
|
continue;
|
||||||
comp.TargetTime = _timing.CurTime + TimeSpan.FromSeconds(comp.EffectCooldown);
|
comp.TargetTime = _timing.CurTime + TimeSpan.FromSeconds(comp.EffectCooldown);
|
||||||
Spawn("HotPotatoEffect", _transform.GetMapCoordinates(uid).Offset(_random.NextVector2(0.25f)));
|
Spawn(_hotPotatoEffectId, _transform.GetMapCoordinates(uid).Offset(_random.NextVector2(0.25f)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -294,7 +294,6 @@ public sealed partial class InstrumentSystem : SharedInstrumentSystem
|
|||||||
SetMaster(uid, null);
|
SetMaster(uid, null);
|
||||||
TrySetChannels(uid, data);
|
TrySetChannels(uid, data);
|
||||||
|
|
||||||
instrument.MidiEventBuffer.Clear();
|
|
||||||
instrument.Renderer.OnMidiEvent += instrument.MidiEventBuffer.Add;
|
instrument.Renderer.OnMidiEvent += instrument.MidiEventBuffer.Add;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
using System.Linq;
|
||||||
using Content.Client.Clothing;
|
using Content.Client.Clothing;
|
||||||
using Content.Client.Examine;
|
using Content.Client.Examine;
|
||||||
using Content.Client.Verbs.UI;
|
using Content.Client.Verbs.UI;
|
||||||
@@ -11,6 +12,7 @@ using Robust.Client.UserInterface;
|
|||||||
using Robust.Shared.Containers;
|
using Robust.Shared.Containers;
|
||||||
using Robust.Shared.Input.Binding;
|
using Robust.Shared.Input.Binding;
|
||||||
using Robust.Shared.Player;
|
using Robust.Shared.Player;
|
||||||
|
using Robust.Shared.Timing;
|
||||||
|
|
||||||
namespace Content.Client.Inventory
|
namespace Content.Client.Inventory
|
||||||
{
|
{
|
||||||
@@ -19,7 +21,7 @@ namespace Content.Client.Inventory
|
|||||||
{
|
{
|
||||||
[Dependency] private readonly IPlayerManager _playerManager = default!;
|
[Dependency] private readonly IPlayerManager _playerManager = default!;
|
||||||
[Dependency] private readonly IUserInterfaceManager _ui = default!;
|
[Dependency] private readonly IUserInterfaceManager _ui = default!;
|
||||||
|
[Dependency] private readonly IGameTiming _timing = default!;
|
||||||
[Dependency] private readonly ClientClothingSystem _clothingVisualsSystem = default!;
|
[Dependency] private readonly ClientClothingSystem _clothingVisualsSystem = default!;
|
||||||
[Dependency] private readonly ExamineSystem _examine = default!;
|
[Dependency] private readonly ExamineSystem _examine = default!;
|
||||||
|
|
||||||
@@ -91,6 +93,14 @@ namespace Content.Client.Inventory
|
|||||||
|
|
||||||
private void OnShutdown(EntityUid uid, InventoryComponent component, ComponentShutdown args)
|
private void OnShutdown(EntityUid uid, InventoryComponent component, ComponentShutdown args)
|
||||||
{
|
{
|
||||||
|
if (TryComp(uid, out InventorySlotsComponent? inventorySlots))
|
||||||
|
{
|
||||||
|
foreach (var slot in component.Slots)
|
||||||
|
{
|
||||||
|
TryRemoveSlotData((uid, inventorySlots), (SlotData)slot);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (uid == _playerManager.LocalEntity)
|
if (uid == _playerManager.LocalEntity)
|
||||||
OnUnlinkInventory?.Invoke();
|
OnUnlinkInventory?.Invoke();
|
||||||
}
|
}
|
||||||
@@ -102,46 +112,22 @@ namespace Content.Client.Inventory
|
|||||||
|
|
||||||
private void OnPlayerAttached(EntityUid uid, InventorySlotsComponent component, LocalPlayerAttachedEvent args)
|
private void OnPlayerAttached(EntityUid uid, InventorySlotsComponent component, LocalPlayerAttachedEvent args)
|
||||||
{
|
{
|
||||||
if (TryGetSlots(uid, out var definitions))
|
|
||||||
{
|
|
||||||
foreach (var definition in definitions)
|
|
||||||
{
|
|
||||||
if (!TryGetSlotContainer(uid, definition.Name, out var container, out _))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (!component.SlotData.TryGetValue(definition.Name, out var data))
|
|
||||||
{
|
|
||||||
data = new SlotData(definition);
|
|
||||||
component.SlotData[definition.Name] = data;
|
|
||||||
}
|
|
||||||
|
|
||||||
data.Container = container;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
OnLinkInventorySlots?.Invoke(uid, component);
|
OnLinkInventorySlots?.Invoke(uid, component);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected override void OnInit(Entity<InventoryComponent> ent, ref ComponentInit args)
|
||||||
|
{
|
||||||
|
base.OnInit(ent, ref args);
|
||||||
|
|
||||||
|
_clothingVisualsSystem.InitClothing(ent.Owner, ent.Comp);
|
||||||
|
}
|
||||||
|
|
||||||
public override void Shutdown()
|
public override void Shutdown()
|
||||||
{
|
{
|
||||||
CommandBinds.Unregister<ClientInventorySystem>();
|
CommandBinds.Unregister<ClientInventorySystem>();
|
||||||
base.Shutdown();
|
base.Shutdown();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void OnInit(EntityUid uid, InventoryComponent component, ComponentInit args)
|
|
||||||
{
|
|
||||||
base.OnInit(uid, component, args);
|
|
||||||
_clothingVisualsSystem.InitClothing(uid, component);
|
|
||||||
|
|
||||||
if (!TryComp(uid, out InventorySlotsComponent? inventorySlots))
|
|
||||||
return;
|
|
||||||
|
|
||||||
foreach (var slot in component.Slots)
|
|
||||||
{
|
|
||||||
TryAddSlotDef(uid, inventorySlots, slot);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void ReloadInventory(InventorySlotsComponent? component = null)
|
public void ReloadInventory(InventorySlotsComponent? component = null)
|
||||||
{
|
{
|
||||||
var player = _playerManager.LocalEntity;
|
var player = _playerManager.LocalEntity;
|
||||||
@@ -165,7 +151,10 @@ namespace Content.Client.Inventory
|
|||||||
public void UpdateSlot(EntityUid owner, InventorySlotsComponent component, string slotName,
|
public void UpdateSlot(EntityUid owner, InventorySlotsComponent component, string slotName,
|
||||||
bool? blocked = null, bool? highlight = null)
|
bool? blocked = null, bool? highlight = null)
|
||||||
{
|
{
|
||||||
var oldData = component.SlotData[slotName];
|
// The slot might have been removed when changing templates, which can cause items to be dropped.
|
||||||
|
if (!component.SlotData.TryGetValue(slotName, out var oldData))
|
||||||
|
return;
|
||||||
|
|
||||||
var newHighlight = oldData.Highlighted;
|
var newHighlight = oldData.Highlighted;
|
||||||
var newBlocked = oldData.Blocked;
|
var newBlocked = oldData.Blocked;
|
||||||
|
|
||||||
@@ -181,14 +170,28 @@ namespace Content.Client.Inventory
|
|||||||
EntitySlotUpdate?.Invoke(newData);
|
EntitySlotUpdate?.Invoke(newData);
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool TryAddSlotDef(EntityUid owner, InventorySlotsComponent component, SlotDefinition newSlotDef)
|
public bool TryAddSlotData(Entity<InventorySlotsComponent> ent, SlotData newSlotData)
|
||||||
{
|
{
|
||||||
SlotData newSlotData = newSlotDef; //convert to slotData
|
if (!ent.Comp.SlotData.TryAdd(newSlotData.SlotName, newSlotData))
|
||||||
if (!component.SlotData.TryAdd(newSlotDef.Name, newSlotData))
|
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (owner == _playerManager.LocalEntity)
|
if (TryGetSlotContainer(ent.Owner, newSlotData.SlotName, out var newContainer, out _))
|
||||||
|
ent.Comp.SlotData[newSlotData.SlotName].Container = newContainer;
|
||||||
|
|
||||||
|
if (ent.Owner == _playerManager.LocalEntity)
|
||||||
OnSlotAdded?.Invoke(newSlotData);
|
OnSlotAdded?.Invoke(newSlotData);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool TryRemoveSlotData(Entity<InventorySlotsComponent> ent, SlotData removedSlotData)
|
||||||
|
{
|
||||||
|
if (!ent.Comp.SlotData.Remove(removedSlotData.SlotName))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (ent.Owner == _playerManager.LocalEntity)
|
||||||
|
OnSlotRemoved?.Invoke(removedSlotData);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -239,33 +242,51 @@ namespace Content.Client.Inventory
|
|||||||
{
|
{
|
||||||
base.UpdateInventoryTemplate(ent);
|
base.UpdateInventoryTemplate(ent);
|
||||||
|
|
||||||
if (TryComp(ent, out InventorySlotsComponent? inventorySlots))
|
if (!TryComp<InventorySlotsComponent>(ent, out var inventorySlots))
|
||||||
|
return;
|
||||||
|
|
||||||
|
List<SlotData> slotDataToRemove = new(); // don't modify dict while iterating
|
||||||
|
|
||||||
|
foreach (var slotData in inventorySlots.SlotData.Values)
|
||||||
{
|
{
|
||||||
|
if (!ent.Comp.Slots.Any(s => s.Name == slotData.SlotName))
|
||||||
|
slotDataToRemove.Add(slotData);
|
||||||
|
}
|
||||||
|
|
||||||
|
// remove slots that are no longer in the new template
|
||||||
|
foreach (var slotData in slotDataToRemove)
|
||||||
|
{
|
||||||
|
TryRemoveSlotData((ent.Owner, inventorySlots), slotData);
|
||||||
|
}
|
||||||
|
|
||||||
|
// update existing slots or add them if they don't exist yet
|
||||||
foreach (var slot in ent.Comp.Slots)
|
foreach (var slot in ent.Comp.Slots)
|
||||||
{
|
{
|
||||||
if (inventorySlots.SlotData.TryGetValue(slot.Name, out var slotData))
|
if (inventorySlots.SlotData.TryGetValue(slot.Name, out var slotData))
|
||||||
slotData.SlotDef = slot;
|
slotData.SlotDef = slot;
|
||||||
|
else
|
||||||
|
TryAddSlotData((ent.Owner, inventorySlots), (SlotData)slot);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
if (ent.Owner == _playerManager.LocalEntity)
|
||||||
|
ReloadInventory(inventorySlots);
|
||||||
}
|
}
|
||||||
|
|
||||||
public sealed class SlotData
|
public sealed class SlotData
|
||||||
{
|
{
|
||||||
public SlotDefinition SlotDef;
|
[ViewVariables] public SlotDefinition SlotDef;
|
||||||
public EntityUid? HeldEntity => Container?.ContainedEntity;
|
[ViewVariables] public EntityUid? HeldEntity => Container?.ContainedEntity;
|
||||||
public bool Blocked;
|
[ViewVariables] public bool Blocked;
|
||||||
public bool Highlighted;
|
[ViewVariables] public bool Highlighted;
|
||||||
|
[ViewVariables] public ContainerSlot? Container;
|
||||||
[ViewVariables]
|
[ViewVariables] public bool HasSlotGroup => SlotDef.SlotGroup != "Default";
|
||||||
public ContainerSlot? Container;
|
[ViewVariables] public Vector2i ButtonOffset => SlotDef.UIWindowPosition;
|
||||||
public bool HasSlotGroup => SlotDef.SlotGroup != "Default";
|
[ViewVariables] public string SlotName => SlotDef.Name;
|
||||||
public Vector2i ButtonOffset => SlotDef.UIWindowPosition;
|
[ViewVariables] public bool ShowInWindow => SlotDef.ShowInWindow;
|
||||||
public string SlotName => SlotDef.Name;
|
[ViewVariables] public string SlotGroup => SlotDef.SlotGroup;
|
||||||
public bool ShowInWindow => SlotDef.ShowInWindow;
|
[ViewVariables] public string SlotDisplayName => SlotDef.DisplayName;
|
||||||
public string SlotGroup => SlotDef.SlotGroup;
|
[ViewVariables] public string TextureName => "Slots/" + SlotDef.TextureName;
|
||||||
public string SlotDisplayName => SlotDef.DisplayName;
|
[ViewVariables] public string FullTextureName => SlotDef.FullTextureName;
|
||||||
public string TextureName => "Slots/" + SlotDef.TextureName;
|
|
||||||
public string FullTextureName => SlotDef.FullTextureName;
|
|
||||||
|
|
||||||
public SlotData(SlotDefinition slotDef, ContainerSlot? container = null, bool highlighted = false,
|
public SlotData(SlotDefinition slotDef, ContainerSlot? container = null, bool highlighted = false,
|
||||||
bool blocked = false)
|
bool blocked = false)
|
||||||
|
|||||||
@@ -1020,7 +1020,7 @@ namespace Content.Client.Lobby.UI
|
|||||||
|
|
||||||
_loadoutWindow = new LoadoutWindow(Profile, roleLoadout, roleLoadoutProto, _playerManager.LocalSession, collection)
|
_loadoutWindow = new LoadoutWindow(Profile, roleLoadout, roleLoadoutProto, _playerManager.LocalSession, collection)
|
||||||
{
|
{
|
||||||
Title = jobProto?.ID + "-loadout",
|
Title = Loc.GetString("loadout-window-title-loadout", ("job", $"{jobProto?.LocalizedName}")),
|
||||||
};
|
};
|
||||||
|
|
||||||
// Refresh the buttons etc.
|
// Refresh the buttons etc.
|
||||||
|
|||||||
@@ -1,7 +1,5 @@
|
|||||||
using System.Numerics;
|
using System.Numerics;
|
||||||
using Content.Shared.Emag.Systems;
|
|
||||||
using Content.Shared.Medical.Cryogenics;
|
using Content.Shared.Medical.Cryogenics;
|
||||||
using Content.Shared.Verbs;
|
|
||||||
using Robust.Client.GameObjects;
|
using Robust.Client.GameObjects;
|
||||||
|
|
||||||
namespace Content.Client.Medical.Cryogenics;
|
namespace Content.Client.Medical.Cryogenics;
|
||||||
@@ -15,11 +13,6 @@ public sealed class CryoPodSystem : SharedCryoPodSystem
|
|||||||
{
|
{
|
||||||
base.Initialize();
|
base.Initialize();
|
||||||
|
|
||||||
SubscribeLocalEvent<CryoPodComponent, ComponentInit>(OnComponentInit);
|
|
||||||
SubscribeLocalEvent<CryoPodComponent, GetVerbsEvent<AlternativeVerb>>(AddAlternativeVerbs);
|
|
||||||
SubscribeLocalEvent<CryoPodComponent, GotEmaggedEvent>(OnEmagged);
|
|
||||||
SubscribeLocalEvent<CryoPodComponent, CryoPodPryFinished>(OnCryoPodPryFinished);
|
|
||||||
|
|
||||||
SubscribeLocalEvent<CryoPodComponent, AppearanceChangeEvent>(OnAppearanceChange);
|
SubscribeLocalEvent<CryoPodComponent, AppearanceChangeEvent>(OnAppearanceChange);
|
||||||
SubscribeLocalEvent<InsideCryoPodComponent, ComponentStartup>(OnCryoPodInsertion);
|
SubscribeLocalEvent<InsideCryoPodComponent, ComponentStartup>(OnCryoPodInsertion);
|
||||||
SubscribeLocalEvent<InsideCryoPodComponent, ComponentRemove>(OnCryoPodRemoval);
|
SubscribeLocalEvent<InsideCryoPodComponent, ComponentRemove>(OnCryoPodRemoval);
|
||||||
@@ -53,8 +46,8 @@ public sealed class CryoPodSystem : SharedCryoPodSystem
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!_appearance.TryGetData<bool>(uid, CryoPodComponent.CryoPodVisuals.ContainsEntity, out var isOpen, args.Component)
|
if (!_appearance.TryGetData<bool>(uid, CryoPodVisuals.ContainsEntity, out var isOpen, args.Component)
|
||||||
|| !_appearance.TryGetData<bool>(uid, CryoPodComponent.CryoPodVisuals.IsOn, out var isOn, args.Component))
|
|| !_appearance.TryGetData<bool>(uid, CryoPodVisuals.IsOn, out var isOn, args.Component))
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,15 +5,15 @@
|
|||||||
<BoxContainer Orientation="Vertical" VerticalExpand="True" HorizontalExpand="True">
|
<BoxContainer Orientation="Vertical" VerticalExpand="True" HorizontalExpand="True">
|
||||||
<networkConfigurator:NetworkConfiguratorDeviceList Name="DeviceList" MinHeight="500" />
|
<networkConfigurator:NetworkConfiguratorDeviceList Name="DeviceList" MinHeight="500" />
|
||||||
<BoxContainer Orientation="Horizontal" HorizontalExpand="True" Margin="8 8 8 1">
|
<BoxContainer Orientation="Horizontal" HorizontalExpand="True" Margin="8 8 8 1">
|
||||||
<Button Name="Set" Text="Set" Access="Public" ToolTip="{Loc 'network-configurator-tooltip-set'}" HorizontalExpand="True" StyleClasses="ButtonSquare"/>
|
<Button Name="Set" Text="{Loc 'network-configurator-text-set'}" Access="Public" ToolTip="{Loc 'network-configurator-tooltip-set'}" HorizontalExpand="True" StyleClasses="ButtonSquare"/>
|
||||||
<Button Name="Add" Text="Add" Access="Public" ToolTip="{Loc 'network-configurator-tooltip-add'}" HorizontalExpand="True" StyleClasses="ButtonSquare"/>
|
<Button Name="Add" Text="{Loc 'network-configurator-text-add'}" Access="Public" ToolTip="{Loc 'network-configurator-tooltip-add'}" HorizontalExpand="True" StyleClasses="ButtonSquare"/>
|
||||||
<!-- Edit might not be needed -->
|
<!-- Edit might not be needed -->
|
||||||
<!--<Button Name="Edit" Text="Edit" Access="Public" ToolTip="{Loc 'network-configurator-tooltip-edit'}" HorizontalExpand="True" StyleClasses="ButtonSquare"/>-->
|
<!--<Button Name="Edit" Text="Edit" Access="Public" ToolTip="{Loc 'network-configurator-tooltip-edit'}" HorizontalExpand="True" StyleClasses="ButtonSquare"/>-->
|
||||||
<Button Name="Clear" Text="Clear" Access="Public" ToolTip="{Loc 'network-configurator-tooltip-clear'}" HorizontalExpand="True"/>
|
<Button Name="Clear" Text="{Loc 'network-configurator-text-clear'}" Access="Public" ToolTip="{Loc 'network-configurator-tooltip-clear'}" HorizontalExpand="True"/>
|
||||||
</BoxContainer>
|
</BoxContainer>
|
||||||
<BoxContainer Orientation="Horizontal" HorizontalExpand="True" Margin="8 0 8 8">
|
<BoxContainer Orientation="Horizontal" HorizontalExpand="True" Margin="8 0 8 8">
|
||||||
<Button Name="Copy" Text="Copy" Access="Public" ToolTip="{Loc 'network-configurator-tooltip-copy'}" HorizontalExpand="True" StyleClasses="OpenRight"/>
|
<Button Name="Copy" Text="{Loc 'network-configurator-text-copy'}" Access="Public" ToolTip="{Loc 'network-configurator-tooltip-copy'}" HorizontalExpand="True" StyleClasses="OpenRight"/>
|
||||||
<Button Name="Show" Text="Show" Access="Public" ToggleMode="True" ToolTip="{Loc 'network-configurator-tooltip-show'}" HorizontalExpand="True" StyleClasses="ButtonSquare"/>
|
<Button Name="Show" Text="{Loc 'network-configurator-text-show'}" Access="Public" ToggleMode="True" ToolTip="{Loc 'network-configurator-tooltip-show'}" HorizontalExpand="True" StyleClasses="ButtonSquare"/>
|
||||||
</BoxContainer>
|
</BoxContainer>
|
||||||
<Label Name="Count" StyleClasses="LabelSubText" HorizontalAlignment="Right" Margin="0 0 12 8"/>
|
<Label Name="Count" StyleClasses="LabelSubText" HorizontalAlignment="Right" Margin="0 0 12 8"/>
|
||||||
</BoxContainer>
|
</BoxContainer>
|
||||||
|
|||||||
@@ -25,6 +25,7 @@
|
|||||||
<CheckBox Name="IntegerScalingCheckBox"
|
<CheckBox Name="IntegerScalingCheckBox"
|
||||||
Text="{Loc 'ui-options-vp-integer-scaling'}"
|
Text="{Loc 'ui-options-vp-integer-scaling'}"
|
||||||
ToolTip="{Loc 'ui-options-vp-integer-scaling-tooltip'}" />
|
ToolTip="{Loc 'ui-options-vp-integer-scaling-tooltip'}" />
|
||||||
|
<ui:OptionDropDown Name="DropDownFilterMode" Title="{Loc 'ui-options-filter-label'}" />
|
||||||
<CheckBox Name="ViewportVerticalFitCheckBox"
|
<CheckBox Name="ViewportVerticalFitCheckBox"
|
||||||
Text="{Loc 'ui-options-vp-vertical-fit'}"
|
Text="{Loc 'ui-options-vp-vertical-fit'}"
|
||||||
ToolTip="{Loc 'ui-options-vp-vertical-fit-tooltip'}" />
|
ToolTip="{Loc 'ui-options-vp-vertical-fit-tooltip'}" />
|
||||||
|
|||||||
@@ -39,6 +39,14 @@ public sealed partial class GraphicsTab : Control
|
|||||||
new OptionDropDownCVar<float>.ValueOption(2.00f, Loc.GetString("ui-options-scale-200")),
|
new OptionDropDownCVar<float>.ValueOption(2.00f, Loc.GetString("ui-options-scale-200")),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
Control.AddOptionDropDown(
|
||||||
|
CCVars.ViewportScalingFilterMode,
|
||||||
|
DropDownFilterMode,
|
||||||
|
[
|
||||||
|
new OptionDropDownCVar<string>.ValueOption("nearest", Loc.GetString("ui-options-filter-nearest")),
|
||||||
|
new OptionDropDownCVar<string>.ValueOption("bilinear", Loc.GetString("ui-options-filter-bilinear")),
|
||||||
|
]);
|
||||||
|
|
||||||
var vpStretch = Control.AddOptionCheckBox(CCVars.ViewportStretch, ViewportStretchCheckBox);
|
var vpStretch = Control.AddOptionCheckBox(CCVars.ViewportStretch, ViewportStretchCheckBox);
|
||||||
var vpVertFit = Control.AddOptionCheckBox(CCVars.ViewportVerticalFit, ViewportVerticalFitCheckBox);
|
var vpVertFit = Control.AddOptionCheckBox(CCVars.ViewportVerticalFit, ViewportVerticalFitCheckBox);
|
||||||
Control.AddOptionSlider(
|
Control.AddOptionSlider(
|
||||||
@@ -50,6 +58,7 @@ public sealed partial class GraphicsTab : Control
|
|||||||
|
|
||||||
vpStretch.ImmediateValueChanged += _ => UpdateViewportSettingsVisibility();
|
vpStretch.ImmediateValueChanged += _ => UpdateViewportSettingsVisibility();
|
||||||
vpVertFit.ImmediateValueChanged += _ => UpdateViewportSettingsVisibility();
|
vpVertFit.ImmediateValueChanged += _ => UpdateViewportSettingsVisibility();
|
||||||
|
IntegerScalingCheckBox.OnToggled += _ => UpdateViewportSettingsVisibility();
|
||||||
|
|
||||||
Control.AddOptionSlider(
|
Control.AddOptionSlider(
|
||||||
CCVars.ViewportWidth,
|
CCVars.ViewportWidth,
|
||||||
@@ -77,6 +86,7 @@ public sealed partial class GraphicsTab : Control
|
|||||||
IntegerScalingCheckBox.Visible = ViewportStretchCheckBox.Pressed;
|
IntegerScalingCheckBox.Visible = ViewportStretchCheckBox.Pressed;
|
||||||
ViewportVerticalFitCheckBox.Visible = ViewportStretchCheckBox.Pressed;
|
ViewportVerticalFitCheckBox.Visible = ViewportStretchCheckBox.Pressed;
|
||||||
ViewportWidthSlider.Visible = !ViewportStretchCheckBox.Pressed || !ViewportVerticalFitCheckBox.Pressed;
|
ViewportWidthSlider.Visible = !ViewportStretchCheckBox.Pressed || !ViewportVerticalFitCheckBox.Pressed;
|
||||||
|
DropDownFilterMode.Visible = !IntegerScalingCheckBox.Pressed && ViewportStretchCheckBox.Pressed;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void UpdateViewportWidthRange()
|
private void UpdateViewportWidthRange()
|
||||||
|
|||||||
@@ -94,7 +94,7 @@ public sealed class ClientsidePlaytimeTrackingManager
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// At less than 1 minute of time diff, there's not much point, and saving regardless will brick tests
|
// At less than 1 minute of time diff, there's not much point
|
||||||
// The reason this isn't checking for 0 is because TotalMinutes is fractional, rather than solely whole minutes
|
// The reason this isn't checking for 0 is because TotalMinutes is fractional, rather than solely whole minutes
|
||||||
if (timeDiffMinutes < 1)
|
if (timeDiffMinutes < 1)
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ public sealed class RotationVisualizerSystem : SharedRotationVisualsSystem
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
if (!_appearance.TryGetData<RotationState>(uid, RotationVisuals.RotationState, out var state, args.Component))
|
if (!_appearance.TryGetData<RotationState>(uid, RotationVisuals.RotationState, out var state, args.Component))
|
||||||
return;
|
state = RotationState.Vertical;
|
||||||
|
|
||||||
switch (state)
|
switch (state)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -12,6 +12,8 @@ public sealed class EmitterSystem : SharedEmitterSystem
|
|||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public override void Initialize()
|
public override void Initialize()
|
||||||
{
|
{
|
||||||
|
base.Initialize();
|
||||||
|
|
||||||
SubscribeLocalEvent<EmitterComponent, AppearanceChangeEvent>(OnAppearanceChange);
|
SubscribeLocalEvent<EmitterComponent, AppearanceChangeEvent>(OnAppearanceChange);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
38
Content.Client/Sprite/ScaleVisualsSystem.cs
Normal file
38
Content.Client/Sprite/ScaleVisualsSystem.cs
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
using System.Numerics;
|
||||||
|
using Content.Shared.Sprite;
|
||||||
|
using Robust.Client.GameObjects;
|
||||||
|
|
||||||
|
namespace Content.Client.Sprite;
|
||||||
|
|
||||||
|
public sealed class ScaleVisualsSystem : SharedScaleVisualsSystem
|
||||||
|
{
|
||||||
|
[Dependency] private readonly SpriteSystem _sprite = default!;
|
||||||
|
|
||||||
|
public override void Initialize()
|
||||||
|
{
|
||||||
|
base.Initialize();
|
||||||
|
|
||||||
|
SubscribeLocalEvent<ScaleVisualsComponent, AppearanceChangeEvent>(OnChangeData);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnChangeData(Entity<ScaleVisualsComponent> ent, ref AppearanceChangeEvent args)
|
||||||
|
{
|
||||||
|
if (!args.AppearanceData.TryGetValue(ScaleVisuals.Scale, out var scale) ||
|
||||||
|
args.Sprite == null) return;
|
||||||
|
|
||||||
|
// save the original scale
|
||||||
|
ent.Comp.OriginalScale ??= args.Sprite.Scale;
|
||||||
|
|
||||||
|
var vecScale = (Vector2)scale;
|
||||||
|
_sprite.SetScale((ent.Owner, args.Sprite), vecScale);
|
||||||
|
}
|
||||||
|
|
||||||
|
// revert to the original scale
|
||||||
|
protected override void ResetScale(Entity<ScaleVisualsComponent> ent)
|
||||||
|
{
|
||||||
|
base.ResetScale(ent);
|
||||||
|
|
||||||
|
if (ent.Comp.OriginalScale != null)
|
||||||
|
_sprite.SetScale(ent.Owner, ent.Comp.OriginalScale.Value);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -40,6 +40,11 @@ public sealed class StorageSystem : SharedStorageSystem
|
|||||||
component.MaxItemSize = state.MaxItemSize;
|
component.MaxItemSize = state.MaxItemSize;
|
||||||
component.Whitelist = state.Whitelist;
|
component.Whitelist = state.Whitelist;
|
||||||
component.Blacklist = state.Blacklist;
|
component.Blacklist = state.Blacklist;
|
||||||
|
component.StorageInsertSound = state.StorageInsertSound;
|
||||||
|
component.StorageRemoveSound = state.StorageRemoveSound;
|
||||||
|
component.StorageOpenSound = state.StorageOpenSound;
|
||||||
|
component.StorageCloseSound = state.StorageCloseSound;
|
||||||
|
component.DefaultStorageOrientation = state.DefaultStorageOrientation;
|
||||||
|
|
||||||
_oldStoredItems.Clear();
|
_oldStoredItems.Clear();
|
||||||
|
|
||||||
|
|||||||
@@ -21,7 +21,7 @@
|
|||||||
Name="RefundButton"
|
Name="RefundButton"
|
||||||
MinWidth="64"
|
MinWidth="64"
|
||||||
HorizontalAlignment="Right"
|
HorizontalAlignment="Right"
|
||||||
Text="Refund" />
|
Text="{Loc 'store-ui-refund-text'}" />
|
||||||
</BoxContainer>
|
</BoxContainer>
|
||||||
<LineEdit Name="SearchBar" Margin="4" PlaceHolder="Search" HorizontalExpand="True"/>
|
<LineEdit Name="SearchBar" Margin="4" PlaceHolder="Search" HorizontalExpand="True"/>
|
||||||
<PanelContainer VerticalExpand="True">
|
<PanelContainer VerticalExpand="True">
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
|
using Content.Client.Trigger.Systems;
|
||||||
using Robust.Client.Animations;
|
using Robust.Client.Animations;
|
||||||
using Robust.Shared.Audio;
|
using Robust.Shared.Audio;
|
||||||
|
|
||||||
namespace Content.Client.Trigger;
|
namespace Content.Client.Trigger.Components;
|
||||||
|
|
||||||
[RegisterComponent]
|
[RegisterComponent]
|
||||||
[Access(typeof(TimerTriggerVisualizerSystem))]
|
[Access(typeof(TimerTriggerVisualizerSystem))]
|
||||||
@@ -16,28 +17,27 @@ public sealed partial class TimerTriggerVisualsComponent : Component
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// The RSI state used while the device has not been primed.
|
/// The RSI state used while the device has not been primed.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[DataField("unprimedSprite")]
|
[DataField]
|
||||||
[ViewVariables(VVAccess.ReadWrite)]
|
|
||||||
public string UnprimedSprite = "icon";
|
public string UnprimedSprite = "icon";
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The RSI state used when the device is primed.
|
/// The RSI state used when the device is primed.
|
||||||
/// Not VVWrite-able because it's only used at component init to construct the priming animation.
|
/// Not VVWrite-able because it's only used at component init to construct the priming animation.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[DataField("primingSprite")]
|
[DataField]
|
||||||
public string PrimingSprite = "primed";
|
public string PrimingSprite = "primed";
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The sound played when the device is primed.
|
/// The sound played when the device is primed.
|
||||||
/// Not VVWrite-able because it's only used at component init to construct the priming animation.
|
/// Not VVWrite-able because it's only used at component init to construct the priming animation.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[DataField("primingSound")]
|
[DataField, ViewVariables]
|
||||||
public SoundSpecifier? PrimingSound;
|
public SoundSpecifier? PrimingSound;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The actual priming animation.
|
/// The actual priming animation.
|
||||||
/// Constructed at component init from the sprite and sound.
|
/// Constructed at component init from the sprite and sound.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[ViewVariables(VVAccess.ReadWrite)]
|
[ViewVariables]
|
||||||
public Animation PrimingAnimation = default!;
|
public Animation PrimingAnimation = default!;
|
||||||
}
|
}
|
||||||
@@ -1,11 +1,12 @@
|
|||||||
using Content.Shared.Trigger;
|
using Content.Shared.Trigger;
|
||||||
|
using Content.Shared.Trigger.Components.Triggers;
|
||||||
using Robust.Client.Animations;
|
using Robust.Client.Animations;
|
||||||
using Robust.Client.GameObjects;
|
using Robust.Client.GameObjects;
|
||||||
using Robust.Shared.Animations;
|
using Robust.Shared.Animations;
|
||||||
|
|
||||||
namespace Content.Client.Explosion;
|
namespace Content.Client.Trigger.Systems;
|
||||||
|
|
||||||
public sealed partial class TriggerSystem
|
public sealed class ProximityTriggerAnimationSystem : EntitySystem
|
||||||
{
|
{
|
||||||
[Dependency] private readonly AnimationPlayerSystem _player = default!;
|
[Dependency] private readonly AnimationPlayerSystem _player = default!;
|
||||||
[Dependency] private readonly SharedAppearanceSystem _appearance = default!;
|
[Dependency] private readonly SharedAppearanceSystem _appearance = default!;
|
||||||
@@ -18,7 +19,7 @@ public sealed partial class TriggerSystem
|
|||||||
|
|
||||||
private const string AnimKey = "proximity";
|
private const string AnimKey = "proximity";
|
||||||
|
|
||||||
private static readonly Animation _flasherAnimation = new Animation
|
private static readonly Animation FlasherAnimation = new Animation
|
||||||
{
|
{
|
||||||
Length = TimeSpan.FromSeconds(0.6f),
|
Length = TimeSpan.FromSeconds(0.6f),
|
||||||
AnimationTracks = {
|
AnimationTracks = {
|
||||||
@@ -42,8 +43,10 @@ public sealed partial class TriggerSystem
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
private void InitializeProximity()
|
public override void Initialize()
|
||||||
{
|
{
|
||||||
|
base.Initialize();
|
||||||
|
|
||||||
SubscribeLocalEvent<TriggerOnProximityComponent, ComponentInit>(OnProximityInit);
|
SubscribeLocalEvent<TriggerOnProximityComponent, ComponentInit>(OnProximityInit);
|
||||||
SubscribeLocalEvent<TriggerOnProximityComponent, AppearanceChangeEvent>(OnProxAppChange);
|
SubscribeLocalEvent<TriggerOnProximityComponent, AppearanceChangeEvent>(OnProxAppChange);
|
||||||
SubscribeLocalEvent<TriggerOnProximityComponent, AnimationCompletedEvent>(OnProxAnimation);
|
SubscribeLocalEvent<TriggerOnProximityComponent, AnimationCompletedEvent>(OnProxAnimation);
|
||||||
@@ -94,7 +97,7 @@ public sealed partial class TriggerSystem
|
|||||||
break;
|
break;
|
||||||
case ProximityTriggerVisuals.Active:
|
case ProximityTriggerVisuals.Active:
|
||||||
if (_player.HasRunningAnimation(uid, player, AnimKey)) return;
|
if (_player.HasRunningAnimation(uid, player, AnimKey)) return;
|
||||||
_player.Play((uid, player), _flasherAnimation, AnimKey);
|
_player.Play((uid, player), FlasherAnimation, AnimKey);
|
||||||
break;
|
break;
|
||||||
case ProximityTriggerVisuals.Off:
|
case ProximityTriggerVisuals.Off:
|
||||||
default:
|
default:
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
using Content.Shared.Trigger.Systems;
|
||||||
|
|
||||||
|
namespace Content.Client.Trigger.Systems;
|
||||||
|
|
||||||
|
public sealed class ReleaseGasOnTriggerSystem : SharedReleaseGasOnTriggerSystem;
|
||||||
@@ -1,11 +1,10 @@
|
|||||||
|
using Content.Client.Trigger.Components;
|
||||||
using Content.Shared.Trigger;
|
using Content.Shared.Trigger;
|
||||||
using Robust.Client.Animations;
|
using Robust.Client.Animations;
|
||||||
using Robust.Client.GameObjects;
|
using Robust.Client.GameObjects;
|
||||||
using Robust.Shared.Audio;
|
|
||||||
using Robust.Shared.Audio.Systems;
|
using Robust.Shared.Audio.Systems;
|
||||||
using Robust.Shared.GameObjects;
|
|
||||||
|
|
||||||
namespace Content.Client.Trigger;
|
namespace Content.Client.Trigger.Systems;
|
||||||
|
|
||||||
public sealed class TimerTriggerVisualizerSystem : VisualizerSystem<TimerTriggerVisualsComponent>
|
public sealed class TimerTriggerVisualizerSystem : VisualizerSystem<TimerTriggerVisualsComponent>
|
||||||
{
|
{
|
||||||
@@ -17,25 +16,26 @@ public sealed class TimerTriggerVisualizerSystem : VisualizerSystem<TimerTrigger
|
|||||||
SubscribeLocalEvent<TimerTriggerVisualsComponent, ComponentInit>(OnComponentInit);
|
SubscribeLocalEvent<TimerTriggerVisualsComponent, ComponentInit>(OnComponentInit);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnComponentInit(EntityUid uid, TimerTriggerVisualsComponent comp, ComponentInit args)
|
private void OnComponentInit(Entity<TimerTriggerVisualsComponent> ent, ref ComponentInit args)
|
||||||
{
|
{
|
||||||
comp.PrimingAnimation = new Animation
|
ent.Comp.PrimingAnimation = new Animation
|
||||||
{
|
{
|
||||||
Length = TimeSpan.MaxValue,
|
Length = TimeSpan.MaxValue,
|
||||||
AnimationTracks = {
|
AnimationTracks = {
|
||||||
new AnimationTrackSpriteFlick() {
|
new AnimationTrackSpriteFlick()
|
||||||
|
{
|
||||||
LayerKey = TriggerVisualLayers.Base,
|
LayerKey = TriggerVisualLayers.Base,
|
||||||
KeyFrames = { new AnimationTrackSpriteFlick.KeyFrame(comp.PrimingSprite, 0f) }
|
KeyFrames = { new AnimationTrackSpriteFlick.KeyFrame(ent.Comp.PrimingSprite, 0f) }
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
if (comp.PrimingSound != null)
|
if (ent.Comp.PrimingSound != null)
|
||||||
{
|
{
|
||||||
comp.PrimingAnimation.AnimationTracks.Add(
|
ent.Comp.PrimingAnimation.AnimationTracks.Add(
|
||||||
new AnimationTrackPlaySound()
|
new AnimationTrackPlaySound()
|
||||||
{
|
{
|
||||||
KeyFrames = { new AnimationTrackPlaySound.KeyFrame(_audioSystem.ResolveSound(comp.PrimingSound), 0) }
|
KeyFrames = { new AnimationTrackPlaySound.KeyFrame(_audioSystem.ResolveSound(ent.Comp.PrimingSound), 0) }
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -30,6 +30,8 @@ namespace Content.Client.UserInterface.Controls
|
|||||||
};
|
};
|
||||||
|
|
||||||
AddChild(Viewport);
|
AddChild(Viewport);
|
||||||
|
|
||||||
|
_cfg.OnValueChanged(CCVars.ViewportScalingFilterMode, _ => UpdateCfg(), true);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void EnteredTree()
|
protected override void EnteredTree()
|
||||||
@@ -52,6 +54,7 @@ namespace Content.Client.UserInterface.Controls
|
|||||||
var renderScaleUp = _cfg.GetCVar(CCVars.ViewportScaleRender);
|
var renderScaleUp = _cfg.GetCVar(CCVars.ViewportScaleRender);
|
||||||
var fixedFactor = _cfg.GetCVar(CCVars.ViewportFixedScaleFactor);
|
var fixedFactor = _cfg.GetCVar(CCVars.ViewportFixedScaleFactor);
|
||||||
var verticalFit = _cfg.GetCVar(CCVars.ViewportVerticalFit);
|
var verticalFit = _cfg.GetCVar(CCVars.ViewportVerticalFit);
|
||||||
|
var filterMode = _cfg.GetCVar(CCVars.ViewportScalingFilterMode);
|
||||||
|
|
||||||
if (stretch)
|
if (stretch)
|
||||||
{
|
{
|
||||||
@@ -60,7 +63,11 @@ namespace Content.Client.UserInterface.Controls
|
|||||||
{
|
{
|
||||||
// Did not find a snap, enable stretching.
|
// Did not find a snap, enable stretching.
|
||||||
Viewport.FixedStretchSize = null;
|
Viewport.FixedStretchSize = null;
|
||||||
Viewport.StretchMode = ScalingViewportStretchMode.Bilinear;
|
Viewport.StretchMode = filterMode switch
|
||||||
|
{
|
||||||
|
"nearest" => ScalingViewportStretchMode.Nearest,
|
||||||
|
"bilinear" => ScalingViewportStretchMode.Bilinear
|
||||||
|
};
|
||||||
Viewport.IgnoreDimension = verticalFit ? ScalingViewportIgnoreDimension.Horizontal : ScalingViewportIgnoreDimension.None;
|
Viewport.IgnoreDimension = verticalFit ? ScalingViewportIgnoreDimension.Horizontal : ScalingViewportIgnoreDimension.None;
|
||||||
|
|
||||||
if (renderScaleUp)
|
if (renderScaleUp)
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
<ScrollContainer HorizontalExpand="True"
|
<ScrollContainer HorizontalExpand="True"
|
||||||
VerticalExpand="True"
|
VerticalExpand="True"
|
||||||
SizeFlagsStretchRatio="6">
|
SizeFlagsStretchRatio="6">
|
||||||
<GridContainer Name="Values"/>
|
<GridContainer Name="Values" HSeparationOverride="0" VSeparationOverride="15"/>
|
||||||
</ScrollContainer>
|
</ScrollContainer>
|
||||||
</BoxContainer>
|
</BoxContainer>
|
||||||
</DefaultWindow>
|
</DefaultWindow>
|
||||||
|
|||||||
@@ -194,8 +194,6 @@ public sealed class InventoryUIController : UIController, IOnStateEntered<Gamepl
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return;
|
|
||||||
|
|
||||||
int GetIndex(Vector2i position)
|
int GetIndex(Vector2i position)
|
||||||
{
|
{
|
||||||
return position.Y * maxWidth + position.X;
|
return position.Y * maxWidth + position.X;
|
||||||
|
|||||||
@@ -185,12 +185,7 @@ public sealed class ItemGridPiece : Control, IEntityControl
|
|||||||
|
|
||||||
handle.SetTransform(pos, iconRotation);
|
handle.SetTransform(pos, iconRotation);
|
||||||
var box = new UIBox2(root, root + sprite.Size * scale);
|
var box = new UIBox2(root, root + sprite.Size * scale);
|
||||||
|
handle.DrawTextureRect(sprite, box);
|
||||||
var ev = new BeforeRenderInGridEvent(new Color(255, 255, 255));
|
|
||||||
_entityManager.EventBus.RaiseLocalEvent(Entity, ev);
|
|
||||||
|
|
||||||
handle.DrawTextureRect(sprite, box, ev.Color);
|
|
||||||
|
|
||||||
handle.SetTransform(GlobalPixelPosition, Angle.Zero);
|
handle.SetTransform(GlobalPixelPosition, Angle.Zero);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -303,19 +298,6 @@ public sealed class ItemGridPiece : Control, IEntityControl
|
|||||||
public EntityUid? UiEntity => Entity;
|
public EntityUid? UiEntity => Entity;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// This event gets raised before a sprite gets drawn in a grid and lets to change the sprite color for several gameobjects that have special sprites to render in containers.
|
|
||||||
/// </summary>
|
|
||||||
public sealed class BeforeRenderInGridEvent : EntityEventArgs
|
|
||||||
{
|
|
||||||
public Color Color { get; set; }
|
|
||||||
|
|
||||||
public BeforeRenderInGridEvent(Color color)
|
|
||||||
{
|
|
||||||
Color = color;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public enum ItemGridPieceMarks
|
public enum ItemGridPieceMarks
|
||||||
{
|
{
|
||||||
First,
|
First,
|
||||||
|
|||||||
@@ -0,0 +1,29 @@
|
|||||||
|
using Content.Shared.Damage.Components;
|
||||||
|
|
||||||
|
namespace Content.IntegrationTests.Tests.Damageable;
|
||||||
|
|
||||||
|
public sealed class StaminaComponentTest
|
||||||
|
{
|
||||||
|
[Test]
|
||||||
|
public async Task ValidatePrototypes()
|
||||||
|
{
|
||||||
|
await using var pair = await PoolManager.GetServerClient();
|
||||||
|
var server = pair.Server;
|
||||||
|
|
||||||
|
var protos = pair.GetPrototypesWithComponent<StaminaComponent>();
|
||||||
|
|
||||||
|
await server.WaitAssertion(() =>
|
||||||
|
{
|
||||||
|
Assert.Multiple(() =>
|
||||||
|
{
|
||||||
|
foreach (var (proto, comp) in protos)
|
||||||
|
{
|
||||||
|
Assert.That(comp.AnimationThreshold, Is.LessThan(comp.CritThreshold),
|
||||||
|
$"Animation threshold on {proto.ID} must be less than its crit threshold.");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
await pair.CleanReturnAsync();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,11 +1,9 @@
|
|||||||
#nullable enable
|
#nullable enable
|
||||||
using Content.Server.Cuffs;
|
using Content.Server.Cuffs;
|
||||||
using Content.Shared.Body.Components;
|
|
||||||
using Content.Shared.Cuffs.Components;
|
using Content.Shared.Cuffs.Components;
|
||||||
using Content.Shared.Hands.Components;
|
using Content.Shared.Hands.Components;
|
||||||
using Robust.Server.Console;
|
using Robust.Server.Console;
|
||||||
using Robust.Shared.GameObjects;
|
using Robust.Shared.GameObjects;
|
||||||
using Robust.Shared.Map;
|
|
||||||
|
|
||||||
namespace Content.IntegrationTests.Tests.GameObjects.Components.ActionBlocking
|
namespace Content.IntegrationTests.Tests.GameObjects.Components.ActionBlocking
|
||||||
{
|
{
|
||||||
@@ -22,9 +20,15 @@ namespace Content.IntegrationTests.Tests.GameObjects.Components.ActionBlocking
|
|||||||
components:
|
components:
|
||||||
- type: Cuffable
|
- type: Cuffable
|
||||||
- type: Hands
|
- type: Hands
|
||||||
|
hands:
|
||||||
|
hand_right:
|
||||||
|
location: Right
|
||||||
|
hand_left:
|
||||||
|
location: Left
|
||||||
|
sortedHands:
|
||||||
|
- hand_right
|
||||||
|
- hand_left
|
||||||
- type: ComplexInteraction
|
- type: ComplexInteraction
|
||||||
- type: Body
|
|
||||||
prototype: Human
|
|
||||||
|
|
||||||
- type: entity
|
- type: entity
|
||||||
name: HandcuffsDummy
|
name: HandcuffsDummy
|
||||||
@@ -47,7 +51,6 @@ namespace Content.IntegrationTests.Tests.GameObjects.Components.ActionBlocking
|
|||||||
HandsComponent hands = default!;
|
HandsComponent hands = default!;
|
||||||
|
|
||||||
var entityManager = server.ResolveDependency<IEntityManager>();
|
var entityManager = server.ResolveDependency<IEntityManager>();
|
||||||
var mapManager = server.ResolveDependency<IMapManager>();
|
|
||||||
var host = server.ResolveDependency<IServerConsoleHost>();
|
var host = server.ResolveDependency<IServerConsoleHost>();
|
||||||
|
|
||||||
var map = await pair.CreateTestMap();
|
var map = await pair.CreateTestMap();
|
||||||
@@ -73,7 +76,6 @@ namespace Content.IntegrationTests.Tests.GameObjects.Components.ActionBlocking
|
|||||||
{
|
{
|
||||||
Assert.That(entityManager.TryGetComponent(human, out cuffed!), $"Human has no {nameof(CuffableComponent)}");
|
Assert.That(entityManager.TryGetComponent(human, out cuffed!), $"Human has no {nameof(CuffableComponent)}");
|
||||||
Assert.That(entityManager.TryGetComponent(human, out hands!), $"Human has no {nameof(HandsComponent)}");
|
Assert.That(entityManager.TryGetComponent(human, out hands!), $"Human has no {nameof(HandsComponent)}");
|
||||||
Assert.That(entityManager.TryGetComponent(human, out BodyComponent? _), $"Human has no {nameof(BodyComponent)}");
|
|
||||||
Assert.That(entityManager.TryGetComponent(cuffs, out HandcuffComponent? _), $"Handcuff has no {nameof(HandcuffComponent)}");
|
Assert.That(entityManager.TryGetComponent(cuffs, out HandcuffComponent? _), $"Handcuff has no {nameof(HandcuffComponent)}");
|
||||||
Assert.That(entityManager.TryGetComponent(secondCuffs, out HandcuffComponent? _), $"Second handcuffs has no {nameof(HandcuffComponent)}");
|
Assert.That(entityManager.TryGetComponent(secondCuffs, out HandcuffComponent? _), $"Second handcuffs has no {nameof(HandcuffComponent)}");
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
using Content.IntegrationTests.Tests.Interaction;
|
using Content.IntegrationTests.Tests.Interaction;
|
||||||
using Content.Server.Explosion.Components;
|
using Content.Shared.Trigger.Components;
|
||||||
using Content.Shared.Explosion.Components;
|
using Content.Shared.Trigger.Systems;
|
||||||
using Robust.Shared.Containers;
|
using Robust.Shared.Containers;
|
||||||
using Robust.Shared.GameObjects;
|
using Robust.Shared.GameObjects;
|
||||||
|
|
||||||
@@ -25,19 +25,19 @@ public sealed class ModularGrenadeTests : InteractionTest
|
|||||||
await InteractUsing(Cable);
|
await InteractUsing(Cable);
|
||||||
|
|
||||||
// Insert & remove trigger
|
// Insert & remove trigger
|
||||||
AssertComp<OnUseTimerTriggerComponent>(false);
|
AssertComp<TimerTriggerComponent>(false);
|
||||||
await InteractUsing(Trigger);
|
await InteractUsing(Trigger);
|
||||||
AssertComp<OnUseTimerTriggerComponent>();
|
AssertComp<TimerTriggerComponent>();
|
||||||
await FindEntity(Trigger, LookupFlags.Uncontained, shouldSucceed: false);
|
await FindEntity(Trigger, LookupFlags.Uncontained, shouldSucceed: false);
|
||||||
await InteractUsing(Pry);
|
await InteractUsing(Pry);
|
||||||
AssertComp<OnUseTimerTriggerComponent>(false);
|
AssertComp<TimerTriggerComponent>(false);
|
||||||
|
|
||||||
// Trigger was dropped to floor, not deleted.
|
// Trigger was dropped to floor, not deleted.
|
||||||
await FindEntity(Trigger, LookupFlags.Uncontained);
|
await FindEntity(Trigger, LookupFlags.Uncontained);
|
||||||
|
|
||||||
// Re-insert
|
// Re-insert
|
||||||
await InteractUsing(Trigger);
|
await InteractUsing(Trigger);
|
||||||
AssertComp<OnUseTimerTriggerComponent>();
|
AssertComp<TimerTriggerComponent>();
|
||||||
|
|
||||||
// Insert & remove payload.
|
// Insert & remove payload.
|
||||||
await InteractUsing(Payload);
|
await InteractUsing(Payload);
|
||||||
@@ -56,13 +56,14 @@ public sealed class ModularGrenadeTests : InteractionTest
|
|||||||
await Pickup();
|
await Pickup();
|
||||||
AssertComp<ActiveTimerTriggerComponent>(false);
|
AssertComp<ActiveTimerTriggerComponent>(false);
|
||||||
await UseInHand();
|
await UseInHand();
|
||||||
|
AssertComp<ActiveTimerTriggerComponent>(true);
|
||||||
|
|
||||||
// So uhhh grenades in hands don't destroy themselves when exploding. Maybe that will be fixed eventually.
|
// So uhhh grenades in hands don't destroy themselves when exploding. Maybe that will be fixed eventually.
|
||||||
await Drop();
|
await Drop();
|
||||||
|
|
||||||
// Wait until grenade explodes
|
// Wait until grenade explodes
|
||||||
var timer = Comp<ActiveTimerTriggerComponent>();
|
var triggerSys = SEntMan.System<TriggerSystem>();
|
||||||
while (timer.TimeRemaining >= 0)
|
while (Target != null && triggerSys.GetRemainingTime(SEntMan.GetEntity(Target.Value))?.TotalSeconds >= 0.0)
|
||||||
{
|
{
|
||||||
await RunTicks(10);
|
await RunTicks(10);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -128,7 +128,7 @@ public sealed class StoreTests
|
|||||||
|
|
||||||
|
|
||||||
var buyMsg = new StoreBuyListingMessage(discountedListingItem.ID){Actor = human};
|
var buyMsg = new StoreBuyListingMessage(discountedListingItem.ID){Actor = human};
|
||||||
server.EntMan.EventBus.RaiseComponentEvent(pda, storeComponent, buyMsg);
|
server.EntMan.EventBus.RaiseLocalEvent(pda, buyMsg);
|
||||||
|
|
||||||
var newBalance = storeComponent.Balance[UplinkSystem.TelecrystalCurrencyPrototype];
|
var newBalance = storeComponent.Balance[UplinkSystem.TelecrystalCurrencyPrototype];
|
||||||
Assert.That(newBalance.Value, Is.EqualTo((originalBalance - plainDiscountedCost).Value), "Expected to have balance reduced by discounted cost");
|
Assert.That(newBalance.Value, Is.EqualTo((originalBalance - plainDiscountedCost).Value), "Expected to have balance reduced by discounted cost");
|
||||||
@@ -141,7 +141,7 @@ public sealed class StoreTests
|
|||||||
Assert.That(costAfterBuy.Value, Is.EqualTo(prototypeCost.Value), "Expected cost after discount refund to be equal to prototype cost.");
|
Assert.That(costAfterBuy.Value, Is.EqualTo(prototypeCost.Value), "Expected cost after discount refund to be equal to prototype cost.");
|
||||||
|
|
||||||
var refundMsg = new StoreRequestRefundMessage { Actor = human };
|
var refundMsg = new StoreRequestRefundMessage { Actor = human };
|
||||||
server.EntMan.EventBus.RaiseComponentEvent(pda, storeComponent, refundMsg);
|
server.EntMan.EventBus.RaiseLocalEvent(pda, refundMsg);
|
||||||
|
|
||||||
// get refreshed item after refund re-generated items
|
// get refreshed item after refund re-generated items
|
||||||
discountedListingItem = storeComponent.FullListingsCatalog.First(x => x.ID == itemId);
|
discountedListingItem = storeComponent.FullListingsCatalog.First(x => x.ID == itemId);
|
||||||
|
|||||||
@@ -1,70 +0,0 @@
|
|||||||
using Content.Shared.Alert;
|
|
||||||
using Robust.Shared.Prototypes;
|
|
||||||
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom;
|
|
||||||
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype;
|
|
||||||
|
|
||||||
namespace Content.Server.Abilities.Mime
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Lets its owner entity use mime powers, like placing invisible walls.
|
|
||||||
/// </summary>
|
|
||||||
[RegisterComponent]
|
|
||||||
public sealed partial class MimePowersComponent : Component
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Whether this component is active or not.
|
|
||||||
/// </summarY>
|
|
||||||
[DataField("enabled")]
|
|
||||||
public bool Enabled = true;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The wall prototype to use.
|
|
||||||
/// </summary>
|
|
||||||
[DataField("wallPrototype", customTypeSerializer: typeof(PrototypeIdSerializer<EntityPrototype>))]
|
|
||||||
public string WallPrototype = "WallInvisible";
|
|
||||||
|
|
||||||
[DataField("invisibleWallAction", customTypeSerializer: typeof(PrototypeIdSerializer<EntityPrototype>))]
|
|
||||||
public string? InvisibleWallAction = "ActionMimeInvisibleWall";
|
|
||||||
|
|
||||||
[DataField("invisibleWallActionEntity")] public EntityUid? InvisibleWallActionEntity;
|
|
||||||
|
|
||||||
// The vow zone lies below
|
|
||||||
public bool VowBroken = false;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Whether this mime is ready to take the vow again.
|
|
||||||
/// Note that if they already have the vow, this is also false.
|
|
||||||
/// </summary>
|
|
||||||
public bool ReadyToRepent = false;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Time when the mime can repent their vow
|
|
||||||
/// </summary>
|
|
||||||
[DataField("vowRepentTime", customTypeSerializer: typeof(TimeOffsetSerializer))]
|
|
||||||
public TimeSpan VowRepentTime = TimeSpan.Zero;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// How long it takes the mime to get their powers back
|
|
||||||
/// </summary>
|
|
||||||
[DataField("vowCooldown")]
|
|
||||||
public TimeSpan VowCooldown = TimeSpan.FromMinutes(5);
|
|
||||||
|
|
||||||
[DataField]
|
|
||||||
public ProtoId<AlertPrototype> VowAlert = "VowOfSilence";
|
|
||||||
|
|
||||||
[DataField]
|
|
||||||
public ProtoId<AlertPrototype> VowBrokenAlert = "VowBroken";
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Does this component prevent the mime from writing on paper while their vow is active?
|
|
||||||
/// </summary>
|
|
||||||
[DataField]
|
|
||||||
public bool PreventWriting = false;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// What message is displayed when the mime fails to write?
|
|
||||||
/// </summary>
|
|
||||||
[DataField]
|
|
||||||
public LocId FailWriteMessage = "paper-component-illiterate-mime";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,171 +0,0 @@
|
|||||||
using Content.Server.Popups;
|
|
||||||
using Content.Shared.Abilities.Mime;
|
|
||||||
using Content.Shared.Actions;
|
|
||||||
using Content.Shared.Actions.Events;
|
|
||||||
using Content.Shared.Alert;
|
|
||||||
using Content.Shared.Coordinates.Helpers;
|
|
||||||
using Content.Shared.Maps;
|
|
||||||
using Content.Shared.Paper;
|
|
||||||
using Content.Shared.Physics;
|
|
||||||
using Robust.Shared.Containers;
|
|
||||||
using Robust.Shared.Map;
|
|
||||||
using Robust.Shared.Timing;
|
|
||||||
using Content.Shared.Speech.Muting;
|
|
||||||
|
|
||||||
namespace Content.Server.Abilities.Mime
|
|
||||||
{
|
|
||||||
public sealed class MimePowersSystem : EntitySystem
|
|
||||||
{
|
|
||||||
[Dependency] private readonly PopupSystem _popupSystem = default!;
|
|
||||||
[Dependency] private readonly SharedActionsSystem _actionsSystem = default!;
|
|
||||||
[Dependency] private readonly AlertsSystem _alertsSystem = default!;
|
|
||||||
[Dependency] private readonly TurfSystem _turf = default!;
|
|
||||||
[Dependency] private readonly IMapManager _mapMan = default!;
|
|
||||||
[Dependency] private readonly SharedContainerSystem _container = default!;
|
|
||||||
[Dependency] private readonly IGameTiming _timing = default!;
|
|
||||||
|
|
||||||
public override void Initialize()
|
|
||||||
{
|
|
||||||
base.Initialize();
|
|
||||||
SubscribeLocalEvent<MimePowersComponent, ComponentInit>(OnComponentInit);
|
|
||||||
SubscribeLocalEvent<MimePowersComponent, InvisibleWallActionEvent>(OnInvisibleWall);
|
|
||||||
|
|
||||||
SubscribeLocalEvent<MimePowersComponent, BreakVowAlertEvent>(OnBreakVowAlert);
|
|
||||||
SubscribeLocalEvent<MimePowersComponent, RetakeVowAlertEvent>(OnRetakeVowAlert);
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void Update(float frameTime)
|
|
||||||
{
|
|
||||||
base.Update(frameTime);
|
|
||||||
// Queue to track whether mimes can retake vows yet
|
|
||||||
|
|
||||||
var query = EntityQueryEnumerator<MimePowersComponent>();
|
|
||||||
while (query.MoveNext(out var uid, out var mime))
|
|
||||||
{
|
|
||||||
if (!mime.VowBroken || mime.ReadyToRepent)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (_timing.CurTime < mime.VowRepentTime)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
mime.ReadyToRepent = true;
|
|
||||||
_popupSystem.PopupEntity(Loc.GetString("mime-ready-to-repent"), uid, uid);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnComponentInit(EntityUid uid, MimePowersComponent component, ComponentInit args)
|
|
||||||
{
|
|
||||||
EnsureComp<MutedComponent>(uid);
|
|
||||||
if (component.PreventWriting)
|
|
||||||
{
|
|
||||||
EnsureComp<BlockWritingComponent>(uid, out var illiterateComponent);
|
|
||||||
illiterateComponent.FailWriteMessage = component.FailWriteMessage;
|
|
||||||
Dirty(uid, illiterateComponent);
|
|
||||||
}
|
|
||||||
|
|
||||||
_alertsSystem.ShowAlert(uid, component.VowAlert);
|
|
||||||
_actionsSystem.AddAction(uid, ref component.InvisibleWallActionEntity, component.InvisibleWallAction, uid);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Creates an invisible wall in a free space after some checks.
|
|
||||||
/// </summary>
|
|
||||||
private void OnInvisibleWall(EntityUid uid, MimePowersComponent component, InvisibleWallActionEvent args)
|
|
||||||
{
|
|
||||||
if (!component.Enabled)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (_container.IsEntityOrParentInContainer(uid))
|
|
||||||
return;
|
|
||||||
|
|
||||||
var xform = Transform(uid);
|
|
||||||
// Get the tile in front of the mime
|
|
||||||
var offsetValue = xform.LocalRotation.ToWorldVec();
|
|
||||||
var coords = xform.Coordinates.Offset(offsetValue).SnapToGrid(EntityManager, _mapMan);
|
|
||||||
var tile = _turf.GetTileRef(coords);
|
|
||||||
if (tile == null)
|
|
||||||
return;
|
|
||||||
|
|
||||||
// Check if the tile is blocked by a wall or mob, and don't create the wall if so
|
|
||||||
if (_turf.IsTileBlocked(tile.Value, CollisionGroup.Impassable | CollisionGroup.Opaque))
|
|
||||||
{
|
|
||||||
_popupSystem.PopupEntity(Loc.GetString("mime-invisible-wall-failed"), uid, uid);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
_popupSystem.PopupEntity(Loc.GetString("mime-invisible-wall-popup", ("mime", uid)), uid);
|
|
||||||
// Make sure we set the invisible wall to despawn properly
|
|
||||||
Spawn(component.WallPrototype, _turf.GetTileCenter(tile.Value));
|
|
||||||
// Handle args so cooldown works
|
|
||||||
args.Handled = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnBreakVowAlert(Entity<MimePowersComponent> ent, ref BreakVowAlertEvent args)
|
|
||||||
{
|
|
||||||
if (args.Handled)
|
|
||||||
return;
|
|
||||||
BreakVow(ent, ent);
|
|
||||||
args.Handled = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnRetakeVowAlert(Entity<MimePowersComponent> ent, ref RetakeVowAlertEvent args)
|
|
||||||
{
|
|
||||||
if (args.Handled)
|
|
||||||
return;
|
|
||||||
RetakeVow(ent, ent);
|
|
||||||
args.Handled = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Break this mime's vow to not speak.
|
|
||||||
/// </summary>
|
|
||||||
public void BreakVow(EntityUid uid, MimePowersComponent? mimePowers = null)
|
|
||||||
{
|
|
||||||
if (!Resolve(uid, ref mimePowers))
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (mimePowers.VowBroken)
|
|
||||||
return;
|
|
||||||
|
|
||||||
mimePowers.Enabled = false;
|
|
||||||
mimePowers.VowBroken = true;
|
|
||||||
mimePowers.VowRepentTime = _timing.CurTime + mimePowers.VowCooldown;
|
|
||||||
RemComp<MutedComponent>(uid);
|
|
||||||
if (mimePowers.PreventWriting)
|
|
||||||
RemComp<BlockWritingComponent>(uid);
|
|
||||||
_alertsSystem.ClearAlert(uid, mimePowers.VowAlert);
|
|
||||||
_alertsSystem.ShowAlert(uid, mimePowers.VowBrokenAlert);
|
|
||||||
_actionsSystem.RemoveAction(uid, mimePowers.InvisibleWallActionEntity);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Retake this mime's vow to not speak.
|
|
||||||
/// </summary>
|
|
||||||
public void RetakeVow(EntityUid uid, MimePowersComponent? mimePowers = null)
|
|
||||||
{
|
|
||||||
if (!Resolve(uid, ref mimePowers))
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (!mimePowers.ReadyToRepent)
|
|
||||||
{
|
|
||||||
_popupSystem.PopupEntity(Loc.GetString("mime-not-ready-repent"), uid, uid);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
mimePowers.Enabled = true;
|
|
||||||
mimePowers.ReadyToRepent = false;
|
|
||||||
mimePowers.VowBroken = false;
|
|
||||||
AddComp<MutedComponent>(uid);
|
|
||||||
if (mimePowers.PreventWriting)
|
|
||||||
{
|
|
||||||
EnsureComp<BlockWritingComponent>(uid, out var illiterateComponent);
|
|
||||||
illiterateComponent.FailWriteMessage = mimePowers.FailWriteMessage;
|
|
||||||
Dirty(uid, illiterateComponent);
|
|
||||||
}
|
|
||||||
|
|
||||||
_alertsSystem.ClearAlert(uid, mimePowers.VowBrokenAlert);
|
|
||||||
_alertsSystem.ShowAlert(uid, mimePowers.VowAlert);
|
|
||||||
_actionsSystem.AddAction(uid, ref mimePowers.InvisibleWallActionEntity, mimePowers.InvisibleWallAction, uid);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -44,7 +44,7 @@ public sealed class VariantizeCommand : IConsoleCommand
|
|||||||
foreach (var tile in mapsSystem.GetAllTiles(euid.Value, gridComp))
|
foreach (var tile in mapsSystem.GetAllTiles(euid.Value, gridComp))
|
||||||
{
|
{
|
||||||
var def = turfSystem.GetContentTileDefinition(tile);
|
var def = turfSystem.GetContentTileDefinition(tile);
|
||||||
var newTile = new Tile(tile.Tile.TypeId, tile.Tile.Flags, tileSystem.PickVariant(def));
|
var newTile = new Tile(tile.Tile.TypeId, tile.Tile.Flags, tileSystem.PickVariant(def), tile.Tile.RotationMirroring);
|
||||||
mapsSystem.SetTile(euid.Value, gridComp, tile.GridIndices, newTile);
|
mapsSystem.SetTile(euid.Value, gridComp, tile.GridIndices, newTile);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Numerics;
|
using System.Numerics;
|
||||||
using Content.Server.Warps;
|
|
||||||
using Content.Shared.Administration;
|
using Content.Shared.Administration;
|
||||||
using Content.Shared.Follower;
|
using Content.Shared.Follower;
|
||||||
using Content.Shared.Ghost;
|
using Content.Shared.Ghost;
|
||||||
|
|||||||
@@ -1,10 +0,0 @@
|
|||||||
using Content.Shared.Administration.Components;
|
|
||||||
using Robust.Shared.GameStates;
|
|
||||||
|
|
||||||
namespace Content.Server.Administration.Components;
|
|
||||||
|
|
||||||
[RegisterComponent]
|
|
||||||
public sealed partial class HeadstandComponent : SharedHeadstandComponent
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -27,9 +27,9 @@ public sealed partial class AdminVerbSystem
|
|||||||
private static readonly EntProtoId DefaultNukeOpRule = "LoneOpsSpawn";
|
private static readonly EntProtoId DefaultNukeOpRule = "LoneOpsSpawn";
|
||||||
private static readonly EntProtoId DefaultRevsRule = "Revolutionary";
|
private static readonly EntProtoId DefaultRevsRule = "Revolutionary";
|
||||||
private static readonly EntProtoId DefaultThiefRule = "Thief";
|
private static readonly EntProtoId DefaultThiefRule = "Thief";
|
||||||
private static readonly ProtoId<StartingGearPrototype> PirateGearId = "PirateGear";
|
private static readonly EntProtoId DefaultChangelingRule = "Changeling";
|
||||||
|
|
||||||
private static readonly EntProtoId ParadoxCloneRuleId = "ParadoxCloneSpawn";
|
private static readonly EntProtoId ParadoxCloneRuleId = "ParadoxCloneSpawn";
|
||||||
|
private static readonly ProtoId<StartingGearPrototype> PirateGearId = "PirateGear";
|
||||||
|
|
||||||
// All antag verbs have names so invokeverb works.
|
// All antag verbs have names so invokeverb works.
|
||||||
private void AddAntagVerbs(GetVerbsEvent<Verb> args)
|
private void AddAntagVerbs(GetVerbsEvent<Verb> args)
|
||||||
@@ -153,6 +153,21 @@ public sealed partial class AdminVerbSystem
|
|||||||
};
|
};
|
||||||
args.Verbs.Add(thief);
|
args.Verbs.Add(thief);
|
||||||
|
|
||||||
|
var changelingName = Loc.GetString("admin-verb-text-make-changeling");
|
||||||
|
Verb changeling = new()
|
||||||
|
{
|
||||||
|
Text = changelingName,
|
||||||
|
Category = VerbCategory.Antag,
|
||||||
|
Icon = new SpriteSpecifier.Rsi(new ResPath("/Textures/Objects/Weapons/Melee/armblade.rsi"), "icon"),
|
||||||
|
Act = () =>
|
||||||
|
{
|
||||||
|
_antag.ForceMakeAntag<ChangelingRuleComponent>(targetPlayer, DefaultChangelingRule);
|
||||||
|
},
|
||||||
|
Impact = LogImpact.High,
|
||||||
|
Message = string.Join(": ", changelingName, Loc.GetString("admin-verb-make-changeling")),
|
||||||
|
};
|
||||||
|
args.Verbs.Add(changeling);
|
||||||
|
|
||||||
var paradoxCloneName = Loc.GetString("admin-verb-text-make-paradox-clone");
|
var paradoxCloneName = Loc.GetString("admin-verb-text-make-paradox-clone");
|
||||||
Verb paradox = new()
|
Verb paradox = new()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,33 +0,0 @@
|
|||||||
using Content.Server.AlertLevel.Systems;
|
|
||||||
|
|
||||||
namespace Content.Server.AlertLevel;
|
|
||||||
/// <summary>
|
|
||||||
/// This component is for changing the alert level of the station when triggered.
|
|
||||||
/// </summary>
|
|
||||||
[RegisterComponent, Access(typeof(AlertLevelChangeOnTriggerSystem))]
|
|
||||||
public sealed partial class AlertLevelChangeOnTriggerComponent : Component
|
|
||||||
{
|
|
||||||
///<summary>
|
|
||||||
///The alert level to change to when triggered.
|
|
||||||
///</summary>
|
|
||||||
[DataField]
|
|
||||||
public string Level = "blue";
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
///Whether to play the sound when the alert level changes.
|
|
||||||
/// </summary>
|
|
||||||
[DataField]
|
|
||||||
public bool PlaySound = true;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
///Whether to say the announcement when the alert level changes.
|
|
||||||
/// </summary>
|
|
||||||
[DataField]
|
|
||||||
public bool Announce = true;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
///Force the alert change. This applies if the alert level is not selectable or not.
|
|
||||||
/// </summary>
|
|
||||||
[DataField]
|
|
||||||
public bool Force = false;
|
|
||||||
}
|
|
||||||
@@ -5,13 +5,13 @@ using Content.Server.Animals.Components;
|
|||||||
using Content.Server.Mind;
|
using Content.Server.Mind;
|
||||||
using Content.Server.Popups;
|
using Content.Server.Popups;
|
||||||
using Content.Server.Radio;
|
using Content.Server.Radio;
|
||||||
using Content.Server.Speech;
|
|
||||||
using Content.Server.Speech.Components;
|
|
||||||
using Content.Server.Vocalization.Systems;
|
using Content.Server.Vocalization.Systems;
|
||||||
|
using Content.Shared.Animals.Components;
|
||||||
|
using Content.Shared.Animals.Systems;
|
||||||
using Content.Shared.Database;
|
using Content.Shared.Database;
|
||||||
using Content.Shared.Mobs.Systems;
|
using Content.Shared.Mobs.Systems;
|
||||||
using Content.Shared.Popups;
|
using Content.Shared.Speech;
|
||||||
using Content.Shared.Verbs;
|
using Content.Shared.Speech.Components;
|
||||||
using Content.Shared.Whitelist;
|
using Content.Shared.Whitelist;
|
||||||
using Robust.Shared.Network;
|
using Robust.Shared.Network;
|
||||||
using Robust.Shared.Random;
|
using Robust.Shared.Random;
|
||||||
@@ -25,7 +25,7 @@ namespace Content.Server.Animals.Systems;
|
|||||||
/// (radiovocalizer) and stores them in a list. When an entity with a VocalizerComponent attempts to vocalize, this will
|
/// (radiovocalizer) and stores them in a list. When an entity with a VocalizerComponent attempts to vocalize, this will
|
||||||
/// try to set the message from memory.
|
/// try to set the message from memory.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public sealed partial class ParrotMemorySystem : EntitySystem
|
public sealed partial class ParrotMemorySystem : SharedParrotMemorySystem
|
||||||
{
|
{
|
||||||
[Dependency] private readonly EntityWhitelistSystem _whitelist = default!;
|
[Dependency] private readonly EntityWhitelistSystem _whitelist = default!;
|
||||||
[Dependency] private readonly IAdminLogManager _adminLogger = default!;
|
[Dependency] private readonly IAdminLogManager _adminLogger = default!;
|
||||||
@@ -42,8 +42,6 @@ public sealed partial class ParrotMemorySystem : EntitySystem
|
|||||||
|
|
||||||
SubscribeLocalEvent<EraseEvent>(OnErase);
|
SubscribeLocalEvent<EraseEvent>(OnErase);
|
||||||
|
|
||||||
SubscribeLocalEvent<ParrotMemoryComponent, GetVerbsEvent<Verb>>(OnGetVerbs);
|
|
||||||
|
|
||||||
SubscribeLocalEvent<ParrotListenerComponent, MapInitEvent>(ListenerOnMapInit);
|
SubscribeLocalEvent<ParrotListenerComponent, MapInitEvent>(ListenerOnMapInit);
|
||||||
|
|
||||||
SubscribeLocalEvent<ParrotListenerComponent, ListenEvent>(OnListen);
|
SubscribeLocalEvent<ParrotListenerComponent, ListenEvent>(OnListen);
|
||||||
@@ -57,30 +55,6 @@ public sealed partial class ParrotMemorySystem : EntitySystem
|
|||||||
DeletePlayerMessages(args.PlayerNetUserId);
|
DeletePlayerMessages(args.PlayerNetUserId);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnGetVerbs(Entity<ParrotMemoryComponent> entity, ref GetVerbsEvent<Verb> args)
|
|
||||||
{
|
|
||||||
var user = args.User;
|
|
||||||
|
|
||||||
// limit this to admins
|
|
||||||
if (!_admin.IsAdmin(user))
|
|
||||||
return;
|
|
||||||
|
|
||||||
// simple verb that just clears the memory list
|
|
||||||
var clearMemoryVerb = new Verb()
|
|
||||||
{
|
|
||||||
Text = Loc.GetString("parrot-verb-clear-memory"),
|
|
||||||
Category = VerbCategory.Admin,
|
|
||||||
Icon = new SpriteSpecifier.Texture(new("/Textures/Interface/AdminActions/clear-parrot.png")),
|
|
||||||
Act = () =>
|
|
||||||
{
|
|
||||||
entity.Comp.SpeechMemories.Clear();
|
|
||||||
_popup.PopupEntity(Loc.GetString("parrot-popup-memory-cleared"), entity, user, PopupType.Medium);
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
args.Verbs.Add(clearMemoryVerb);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void ListenerOnMapInit(Entity<ParrotListenerComponent> entity, ref MapInitEvent args)
|
private void ListenerOnMapInit(Entity<ParrotListenerComponent> entity, ref MapInitEvent args)
|
||||||
{
|
{
|
||||||
// If an entity has a ParrotListenerComponent it really ought to have an ActiveListenerComponent
|
// If an entity has a ParrotListenerComponent it really ought to have an ActiveListenerComponent
|
||||||
|
|||||||
@@ -48,7 +48,7 @@ public sealed partial class AtmosAlarmableComponent : Component
|
|||||||
public HashSet<string> SyncWithTags { get; private set; } = new();
|
public HashSet<string> SyncWithTags { get; private set; } = new();
|
||||||
|
|
||||||
[DataField("monitorAlertTypes")]
|
[DataField("monitorAlertTypes")]
|
||||||
public HashSet<AtmosMonitorThresholdType>? MonitorAlertTypes { get; private set; }
|
public AtmosMonitorThresholdTypeFlags MonitorAlertTypes { get; private set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// If this device should receive only. If it can only
|
/// If this device should receive only. If it can only
|
||||||
|
|||||||
@@ -59,7 +59,7 @@ public sealed partial class AtmosMonitorComponent : Component
|
|||||||
public AtmosAlarmType LastAlarmState = AtmosAlarmType.Normal;
|
public AtmosAlarmType LastAlarmState = AtmosAlarmType.Normal;
|
||||||
|
|
||||||
[DataField("trippedThresholds")]
|
[DataField("trippedThresholds")]
|
||||||
public HashSet<AtmosMonitorThresholdType> TrippedThresholds = new();
|
public AtmosMonitorThresholdTypeFlags TrippedThresholds;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Registered devices in this atmos monitor. Alerts will be sent directly
|
/// Registered devices in this atmos monitor. Alerts will be sent directly
|
||||||
|
|||||||
@@ -108,9 +108,9 @@ public sealed class AtmosAlarmableSystem : EntitySystem
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (args.Data.TryGetValue(AlertTypes, out HashSet<AtmosMonitorThresholdType>? types) && component.MonitorAlertTypes != null)
|
if (args.Data.TryGetValue(AlertTypes, out AtmosMonitorThresholdTypeFlags types) && component.MonitorAlertTypes != AtmosMonitorThresholdTypeFlags.None)
|
||||||
{
|
{
|
||||||
isValid = types.Any(type => component.MonitorAlertTypes.Contains(type));
|
isValid = (types & component.MonitorAlertTypes) != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!component.NetworkAlarmStates.ContainsKey(args.SenderAddress))
|
if (!component.NetworkAlarmStates.ContainsKey(args.SenderAddress))
|
||||||
|
|||||||
@@ -207,7 +207,7 @@ public sealed class AtmosMonitorSystem : EntitySystem
|
|||||||
if (component.MonitorFire
|
if (component.MonitorFire
|
||||||
&& component.LastAlarmState != AtmosAlarmType.Danger)
|
&& component.LastAlarmState != AtmosAlarmType.Danger)
|
||||||
{
|
{
|
||||||
component.TrippedThresholds.Add(AtmosMonitorThresholdType.Temperature);
|
component.TrippedThresholds |= AtmosMonitorThresholdTypeFlags.Temperature;
|
||||||
Alert(uid, AtmosAlarmType.Danger, null, component); // technically???
|
Alert(uid, AtmosAlarmType.Danger, null, component); // technically???
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -218,7 +218,7 @@ public sealed class AtmosMonitorSystem : EntitySystem
|
|||||||
&& component.TemperatureThreshold.CheckThreshold(args.Temperature, out var temperatureState)
|
&& component.TemperatureThreshold.CheckThreshold(args.Temperature, out var temperatureState)
|
||||||
&& temperatureState > component.LastAlarmState)
|
&& temperatureState > component.LastAlarmState)
|
||||||
{
|
{
|
||||||
component.TrippedThresholds.Add(AtmosMonitorThresholdType.Temperature);
|
component.TrippedThresholds |= AtmosMonitorThresholdTypeFlags.Temperature;
|
||||||
Alert(uid, AtmosAlarmType.Danger, null, component);
|
Alert(uid, AtmosAlarmType.Danger, null, component);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -259,7 +259,7 @@ public sealed class AtmosMonitorSystem : EntitySystem
|
|||||||
if (!Resolve(uid, ref monitor)) return;
|
if (!Resolve(uid, ref monitor)) return;
|
||||||
|
|
||||||
var state = AtmosAlarmType.Normal;
|
var state = AtmosAlarmType.Normal;
|
||||||
HashSet<AtmosMonitorThresholdType> alarmTypes = new(monitor.TrippedThresholds);
|
var alarmTypes = monitor.TrippedThresholds;
|
||||||
|
|
||||||
if (monitor.TemperatureThreshold != null
|
if (monitor.TemperatureThreshold != null
|
||||||
&& monitor.TemperatureThreshold.CheckThreshold(air.Temperature, out var temperatureState))
|
&& monitor.TemperatureThreshold.CheckThreshold(air.Temperature, out var temperatureState))
|
||||||
@@ -267,11 +267,11 @@ public sealed class AtmosMonitorSystem : EntitySystem
|
|||||||
if (temperatureState > state)
|
if (temperatureState > state)
|
||||||
{
|
{
|
||||||
state = temperatureState;
|
state = temperatureState;
|
||||||
alarmTypes.Add(AtmosMonitorThresholdType.Temperature);
|
alarmTypes |= AtmosMonitorThresholdTypeFlags.Temperature;
|
||||||
}
|
}
|
||||||
else if (temperatureState == AtmosAlarmType.Normal)
|
else if (temperatureState == AtmosAlarmType.Normal)
|
||||||
{
|
{
|
||||||
alarmTypes.Remove(AtmosMonitorThresholdType.Temperature);
|
alarmTypes &= ~AtmosMonitorThresholdTypeFlags.Temperature;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -282,11 +282,11 @@ public sealed class AtmosMonitorSystem : EntitySystem
|
|||||||
if (pressureState > state)
|
if (pressureState > state)
|
||||||
{
|
{
|
||||||
state = pressureState;
|
state = pressureState;
|
||||||
alarmTypes.Add(AtmosMonitorThresholdType.Pressure);
|
alarmTypes |= AtmosMonitorThresholdTypeFlags.Pressure;
|
||||||
}
|
}
|
||||||
else if (pressureState == AtmosAlarmType.Normal)
|
else if (pressureState == AtmosAlarmType.Normal)
|
||||||
{
|
{
|
||||||
alarmTypes.Remove(AtmosMonitorThresholdType.Pressure);
|
alarmTypes &= ~AtmosMonitorThresholdTypeFlags.Pressure;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -306,17 +306,17 @@ public sealed class AtmosMonitorSystem : EntitySystem
|
|||||||
|
|
||||||
if (tripped)
|
if (tripped)
|
||||||
{
|
{
|
||||||
alarmTypes.Add(AtmosMonitorThresholdType.Gas);
|
alarmTypes |= AtmosMonitorThresholdTypeFlags.Gas;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
alarmTypes.Remove(AtmosMonitorThresholdType.Gas);
|
alarmTypes &= ~AtmosMonitorThresholdTypeFlags.Gas;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// if the state of the current air doesn't match the last alarm state,
|
// if the state of the current air doesn't match the last alarm state,
|
||||||
// we update the state
|
// we update the state
|
||||||
if (state != monitor.LastAlarmState || !alarmTypes.SetEquals(monitor.TrippedThresholds))
|
if (state != monitor.LastAlarmState || alarmTypes != monitor.TrippedThresholds)
|
||||||
{
|
{
|
||||||
Alert(uid, state, alarmTypes, monitor);
|
Alert(uid, state, alarmTypes, monitor);
|
||||||
}
|
}
|
||||||
@@ -327,7 +327,7 @@ public sealed class AtmosMonitorSystem : EntitySystem
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="state">The alarm state to set this monitor to.</param>
|
/// <param name="state">The alarm state to set this monitor to.</param>
|
||||||
/// <param name="alarms">The alarms that caused this alarm state.</param>
|
/// <param name="alarms">The alarms that caused this alarm state.</param>
|
||||||
public void Alert(EntityUid uid, AtmosAlarmType state, HashSet<AtmosMonitorThresholdType>? alarms = null, AtmosMonitorComponent? monitor = null)
|
public void Alert(EntityUid uid, AtmosAlarmType state, AtmosMonitorThresholdTypeFlags? alarms = null, AtmosMonitorComponent? monitor = null)
|
||||||
{
|
{
|
||||||
if (!Resolve(uid, ref monitor))
|
if (!Resolve(uid, ref monitor))
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -1,22 +1,19 @@
|
|||||||
using Content.Shared.Atmos.EntitySystems;
|
using Content.Server.Atmos.Piping.EntitySystems;
|
||||||
using Robust.Shared.GameStates;
|
|
||||||
using JetBrains.Annotations;
|
using JetBrains.Annotations;
|
||||||
|
|
||||||
namespace Content.Shared.Atmos.Components;
|
namespace Content.Server.Atmos.Piping.Components;
|
||||||
|
|
||||||
[RegisterComponent, NetworkedComponent]
|
[RegisterComponent]
|
||||||
[AutoGenerateComponentState]
|
|
||||||
public sealed partial class AtmosPipeColorComponent : Component
|
public sealed partial class AtmosPipeColorComponent : Component
|
||||||
{
|
{
|
||||||
[DataField]
|
[DataField]
|
||||||
[AutoNetworkedField]
|
|
||||||
public Color Color { get; set; } = Color.White;
|
public Color Color { get; set; } = Color.White;
|
||||||
|
|
||||||
[ViewVariables(VVAccess.ReadWrite), UsedImplicitly]
|
[ViewVariables(VVAccess.ReadWrite), UsedImplicitly]
|
||||||
public Color ColorVV
|
public Color ColorVV
|
||||||
{
|
{
|
||||||
get => Color;
|
get => Color;
|
||||||
set => IoCManager.Resolve<IEntityManager>().System<AtmosPipeColorSystem>().SetColor((Owner, this), value);
|
set => IoCManager.Resolve<IEntityManager>().System<AtmosPipeColorSystem>().SetColor(Owner, this, value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,48 @@
|
|||||||
|
using Content.Server.Atmos.Piping.Components;
|
||||||
|
using Content.Shared.Atmos.Piping;
|
||||||
|
using Robust.Server.GameObjects;
|
||||||
|
|
||||||
|
namespace Content.Server.Atmos.Piping.EntitySystems
|
||||||
|
{
|
||||||
|
public sealed class AtmosPipeColorSystem : EntitySystem
|
||||||
|
{
|
||||||
|
[Dependency] private readonly SharedAppearanceSystem _appearance = default!;
|
||||||
|
|
||||||
|
public override void Initialize()
|
||||||
|
{
|
||||||
|
base.Initialize();
|
||||||
|
|
||||||
|
SubscribeLocalEvent<AtmosPipeColorComponent, ComponentStartup>(OnStartup);
|
||||||
|
SubscribeLocalEvent<AtmosPipeColorComponent, ComponentShutdown>(OnShutdown);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnStartup(EntityUid uid, AtmosPipeColorComponent component, ComponentStartup args)
|
||||||
|
{
|
||||||
|
if (!TryComp(uid, out AppearanceComponent? appearance))
|
||||||
|
return;
|
||||||
|
|
||||||
|
_appearance.SetData(uid, PipeColorVisuals.Color, component.Color, appearance);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnShutdown(EntityUid uid, AtmosPipeColorComponent component, ComponentShutdown args)
|
||||||
|
{
|
||||||
|
if (!TryComp(uid, out AppearanceComponent? appearance))
|
||||||
|
return;
|
||||||
|
|
||||||
|
_appearance.SetData(uid, PipeColorVisuals.Color, Color.White, appearance);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SetColor(EntityUid uid, AtmosPipeColorComponent component, Color color)
|
||||||
|
{
|
||||||
|
component.Color = color;
|
||||||
|
|
||||||
|
if (!TryComp(uid, out AppearanceComponent? appearance))
|
||||||
|
return;
|
||||||
|
|
||||||
|
_appearance.SetData(uid, PipeColorVisuals.Color, color, appearance);
|
||||||
|
|
||||||
|
var ev = new AtmosPipeColorChangedEvent(color);
|
||||||
|
RaiseLocalEvent(uid, ref ev);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,13 +1,13 @@
|
|||||||
using Content.Server.Body.Components;
|
using Content.Server.Body.Components;
|
||||||
using Content.Server.Ghost.Components;
|
using Content.Server.Ghost.Components;
|
||||||
using Content.Shared.Body.Components;
|
|
||||||
using Content.Shared.Body.Events;
|
using Content.Shared.Body.Events;
|
||||||
using Content.Shared.Mind;
|
using Content.Shared.Mind;
|
||||||
using Content.Shared.Mind.Components;
|
using Content.Shared.Mind.Components;
|
||||||
|
using Content.Shared.Mobs.Components;
|
||||||
using Content.Shared.Pointing;
|
using Content.Shared.Pointing;
|
||||||
|
|
||||||
namespace Content.Server.Body.Systems
|
namespace Content.Server.Body.Systems;
|
||||||
{
|
|
||||||
public sealed class BrainSystem : EntitySystem
|
public sealed class BrainSystem : EntitySystem
|
||||||
{
|
{
|
||||||
[Dependency] private readonly SharedMindSystem _mindSystem = default!;
|
[Dependency] private readonly SharedMindSystem _mindSystem = default!;
|
||||||
@@ -30,8 +30,7 @@ namespace Content.Server.Body.Systems
|
|||||||
EnsureComp<MindContainerComponent>(oldEntity);
|
EnsureComp<MindContainerComponent>(oldEntity);
|
||||||
|
|
||||||
var ghostOnMove = EnsureComp<GhostOnMoveComponent>(newEntity);
|
var ghostOnMove = EnsureComp<GhostOnMoveComponent>(newEntity);
|
||||||
if (HasComp<BodyComponent>(newEntity))
|
ghostOnMove.MustBeDead = HasComp<MobStateComponent>(newEntity); // Don't ghost living players out of their bodies.
|
||||||
ghostOnMove.MustBeDead = true;
|
|
||||||
|
|
||||||
if (!_mindSystem.TryGetMind(oldEntity, out var mindId, out var mind))
|
if (!_mindSystem.TryGetMind(oldEntity, out var mindId, out var mind))
|
||||||
return;
|
return;
|
||||||
@@ -44,4 +43,4 @@ namespace Content.Server.Body.Systems
|
|||||||
args.Cancel();
|
args.Cancel();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|||||||
@@ -90,19 +90,22 @@ public sealed class PricingSystem : EntitySystem
|
|||||||
if (args.Handled)
|
if (args.Handled)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (!TryComp<BodyComponent>(uid, out var body) || !TryComp<MobStateComponent>(uid, out var state))
|
if (!TryComp<MobStateComponent>(uid, out var state))
|
||||||
{
|
{
|
||||||
Log.Error($"Tried to get the mob price of {ToPrettyString(uid)}, which has no {nameof(BodyComponent)} and no {nameof(MobStateComponent)}.");
|
Log.Error($"Tried to get the mob price of {ToPrettyString(uid)}, which has no {nameof(MobStateComponent)}.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Better handling of missing.
|
var partPenalty = 0.0;
|
||||||
|
if (TryComp<BodyComponent>(uid, out var body))
|
||||||
|
{
|
||||||
var partList = _bodySystem.GetBodyChildren(uid, body).ToList();
|
var partList = _bodySystem.GetBodyChildren(uid, body).ToList();
|
||||||
var totalPartsPresent = partList.Sum(_ => 1);
|
var totalPartsPresent = partList.Sum(_ => 1);
|
||||||
var totalParts = partList.Count;
|
var totalParts = partList.Count;
|
||||||
|
|
||||||
var partRatio = totalPartsPresent / (double) totalParts;
|
var partRatio = totalPartsPresent / (double) totalParts;
|
||||||
var partPenalty = component.Price * (1 - partRatio) * component.MissingBodyPartPenalty;
|
partPenalty = component.Price * (1 - partRatio) * component.MissingBodyPartPenalty;
|
||||||
|
}
|
||||||
|
|
||||||
args.Price += (component.Price - partPenalty) * (_mobStateSystem.IsAlive(uid, state) ? 1.0 : component.DeathPenalty);
|
args.Price += (component.Price - partPenalty) * (_mobStateSystem.IsAlive(uid, state) ? 1.0 : component.DeathPenalty);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,86 +12,86 @@ namespace Content.Server.Chat.Managers;
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public sealed class ChatSanitizationManager : IChatSanitizationManager
|
public sealed class ChatSanitizationManager : IChatSanitizationManager
|
||||||
{
|
{
|
||||||
private static readonly Dictionary<string, string> ShorthandToEmote = new()
|
private static readonly (Regex regex, string emoteKey)[] ShorthandToEmote =
|
||||||
{
|
[
|
||||||
{ ":)", "chatsan-smiles" },
|
Entry(":)", "chatsan-smiles"),
|
||||||
{ ":]", "chatsan-smiles" },
|
Entry(":]", "chatsan-smiles"),
|
||||||
{ "=)", "chatsan-smiles" },
|
Entry("=)", "chatsan-smiles"),
|
||||||
{ "=]", "chatsan-smiles" },
|
Entry("=]", "chatsan-smiles"),
|
||||||
{ "(:", "chatsan-smiles" },
|
Entry("(:", "chatsan-smiles"),
|
||||||
{ "[:", "chatsan-smiles" },
|
Entry("[:", "chatsan-smiles"),
|
||||||
{ "(=", "chatsan-smiles" },
|
Entry("(=", "chatsan-smiles"),
|
||||||
{ "[=", "chatsan-smiles" },
|
Entry("[=", "chatsan-smiles"),
|
||||||
{ "^^", "chatsan-smiles" },
|
Entry("^^", "chatsan-smiles"),
|
||||||
{ "^-^", "chatsan-smiles" },
|
Entry("^-^", "chatsan-smiles"),
|
||||||
{ ":(", "chatsan-frowns" },
|
Entry(":(", "chatsan-frowns"),
|
||||||
{ ":[", "chatsan-frowns" },
|
Entry(":[", "chatsan-frowns"),
|
||||||
{ "=(", "chatsan-frowns" },
|
Entry("=(", "chatsan-frowns"),
|
||||||
{ "=[", "chatsan-frowns" },
|
Entry("=[", "chatsan-frowns"),
|
||||||
{ "):", "chatsan-frowns" },
|
Entry("):", "chatsan-frowns"),
|
||||||
{ ")=", "chatsan-frowns" },
|
Entry(")=", "chatsan-frowns"),
|
||||||
{ "]:", "chatsan-frowns" },
|
Entry("]:", "chatsan-frowns"),
|
||||||
{ "]=", "chatsan-frowns" },
|
Entry("]=", "chatsan-frowns"),
|
||||||
{ ":D", "chatsan-smiles-widely" },
|
Entry(":D", "chatsan-smiles-widely"),
|
||||||
{ "D:", "chatsan-frowns-deeply" },
|
Entry("D:", "chatsan-frowns-deeply"),
|
||||||
{ ":O", "chatsan-surprised" },
|
Entry(":O", "chatsan-surprised"),
|
||||||
{ ":3", "chatsan-smiles" },
|
Entry(":3", "chatsan-smiles"),
|
||||||
{ ":S", "chatsan-uncertain" },
|
Entry(":S", "chatsan-uncertain"),
|
||||||
{ ":>", "chatsan-grins" },
|
Entry(":>", "chatsan-grins"),
|
||||||
{ ":<", "chatsan-pouts" },
|
Entry(":<", "chatsan-pouts"),
|
||||||
{ "xD", "chatsan-laughs" },
|
Entry("xD", "chatsan-laughs"),
|
||||||
{ ":'(", "chatsan-cries" },
|
Entry(":'(", "chatsan-cries"),
|
||||||
{ ":'[", "chatsan-cries" },
|
Entry(":'[", "chatsan-cries"),
|
||||||
{ "='(", "chatsan-cries" },
|
Entry("='(", "chatsan-cries"),
|
||||||
{ "='[", "chatsan-cries" },
|
Entry("='[", "chatsan-cries"),
|
||||||
{ ")':", "chatsan-cries" },
|
Entry(")':", "chatsan-cries"),
|
||||||
{ "]':", "chatsan-cries" },
|
Entry("]':", "chatsan-cries"),
|
||||||
{ ")'=", "chatsan-cries" },
|
Entry(")'=", "chatsan-cries"),
|
||||||
{ "]'=", "chatsan-cries" },
|
Entry("]'=", "chatsan-cries"),
|
||||||
{ ";-;", "chatsan-cries" },
|
Entry(";-;", "chatsan-cries"),
|
||||||
{ ";_;", "chatsan-cries" },
|
Entry(";_;", "chatsan-cries"),
|
||||||
{ "qwq", "chatsan-cries" },
|
Entry("qwq", "chatsan-cries"),
|
||||||
{ ":u", "chatsan-smiles-smugly" },
|
Entry(":u", "chatsan-smiles-smugly"),
|
||||||
{ ":v", "chatsan-smiles-smugly" },
|
Entry(":v", "chatsan-smiles-smugly"),
|
||||||
{ ">:i", "chatsan-annoyed" },
|
Entry(">:i", "chatsan-annoyed"),
|
||||||
{ ":i", "chatsan-sighs" },
|
Entry(":i", "chatsan-sighs"),
|
||||||
{ ":|", "chatsan-sighs" },
|
Entry(":|", "chatsan-sighs"),
|
||||||
{ ":p", "chatsan-stick-out-tongue" },
|
Entry(":p", "chatsan-stick-out-tongue"),
|
||||||
{ ";p", "chatsan-stick-out-tongue" },
|
Entry(";p", "chatsan-stick-out-tongue"),
|
||||||
{ ":b", "chatsan-stick-out-tongue" },
|
Entry(":b", "chatsan-stick-out-tongue"),
|
||||||
{ "0-0", "chatsan-wide-eyed" },
|
Entry("0-0", "chatsan-wide-eyed"),
|
||||||
{ "o-o", "chatsan-wide-eyed" },
|
Entry("o-o", "chatsan-wide-eyed"),
|
||||||
{ "o.o", "chatsan-wide-eyed" },
|
Entry("o.o", "chatsan-wide-eyed"),
|
||||||
{ "._.", "chatsan-surprised" },
|
Entry("._.", "chatsan-surprised"),
|
||||||
{ ".-.", "chatsan-confused" },
|
Entry(".-.", "chatsan-confused"),
|
||||||
{ "-_-", "chatsan-unimpressed" },
|
Entry("-_-", "chatsan-unimpressed"),
|
||||||
{ "smh", "chatsan-unimpressed" },
|
Entry("smh", "chatsan-unimpressed"),
|
||||||
{ "o/", "chatsan-waves" },
|
Entry("o/", "chatsan-waves"),
|
||||||
{ "^^/", "chatsan-waves" },
|
Entry("^^/", "chatsan-waves"),
|
||||||
{ ":/", "chatsan-uncertain" },
|
Entry(":/", "chatsan-uncertain"),
|
||||||
{ ":\\", "chatsan-uncertain" },
|
Entry(":\\", "chatsan-uncertain"),
|
||||||
{ "lmao", "chatsan-laughs" },
|
Entry("lmao", "chatsan-laughs"),
|
||||||
{ "lmfao", "chatsan-laughs" },
|
Entry("lmfao", "chatsan-laughs"),
|
||||||
{ "lol", "chatsan-laughs" },
|
Entry("lol", "chatsan-laughs"),
|
||||||
{ "lel", "chatsan-laughs" },
|
Entry("lel", "chatsan-laughs"),
|
||||||
{ "kek", "chatsan-laughs" },
|
Entry("kek", "chatsan-laughs"),
|
||||||
{ "rofl", "chatsan-laughs" },
|
Entry("rofl", "chatsan-laughs"),
|
||||||
{ "o7", "chatsan-salutes" },
|
Entry("o7", "chatsan-salutes"),
|
||||||
{ ";_;7", "chatsan-tearfully-salutes" },
|
Entry(";_;7", "chatsan-tearfully-salutes"),
|
||||||
{ "idk", "chatsan-shrugs" },
|
Entry("idk", "chatsan-shrugs"),
|
||||||
{ ";)", "chatsan-winks" },
|
Entry(";)", "chatsan-winks"),
|
||||||
{ ";]", "chatsan-winks" },
|
Entry(";]", "chatsan-winks"),
|
||||||
{ "(;", "chatsan-winks" },
|
Entry("(;", "chatsan-winks"),
|
||||||
{ "[;", "chatsan-winks" },
|
Entry("[;", "chatsan-winks"),
|
||||||
{ ":')", "chatsan-tearfully-smiles" },
|
Entry(":')", "chatsan-tearfully-smiles"),
|
||||||
{ ":']", "chatsan-tearfully-smiles" },
|
Entry(":']", "chatsan-tearfully-smiles"),
|
||||||
{ "=')", "chatsan-tearfully-smiles" },
|
Entry("=')", "chatsan-tearfully-smiles"),
|
||||||
{ "=']", "chatsan-tearfully-smiles" },
|
Entry("=']", "chatsan-tearfully-smiles"),
|
||||||
{ "(':", "chatsan-tearfully-smiles" },
|
Entry("(':", "chatsan-tearfully-smiles"),
|
||||||
{ "[':", "chatsan-tearfully-smiles" },
|
Entry("[':", "chatsan-tearfully-smiles"),
|
||||||
{ "('=", "chatsan-tearfully-smiles" },
|
Entry("('=", "chatsan-tearfully-smiles"),
|
||||||
{ "['=", "chatsan-tearfully-smiles" }
|
Entry("['=", "chatsan-tearfully-smiles"),
|
||||||
};
|
];
|
||||||
|
|
||||||
[Dependency] private readonly IConfigurationManager _configurationManager = default!;
|
[Dependency] private readonly IConfigurationManager _configurationManager = default!;
|
||||||
[Dependency] private readonly ILocalizationManager _loc = default!;
|
[Dependency] private readonly ILocalizationManager _loc = default!;
|
||||||
@@ -125,21 +125,8 @@ public sealed class ChatSanitizationManager : IChatSanitizationManager
|
|||||||
// -1 is just a canary for nothing found yet
|
// -1 is just a canary for nothing found yet
|
||||||
var lastEmoteIndex = -1;
|
var lastEmoteIndex = -1;
|
||||||
|
|
||||||
foreach (var (shorthand, emoteKey) in ShorthandToEmote)
|
foreach (var (r, emoteKey) in ShorthandToEmote)
|
||||||
{
|
{
|
||||||
// We have to escape it because shorthands like ":)" or "-_-" would break the regex otherwise.
|
|
||||||
var escaped = Regex.Escape(shorthand);
|
|
||||||
|
|
||||||
// So there are 2 cases:
|
|
||||||
// - If there is whitespace before it and after it is either punctuation, whitespace, or the end of the line
|
|
||||||
// Delete the word and the whitespace before
|
|
||||||
// - If it is at the start of the string and is followed by punctuation, whitespace, or the end of the line
|
|
||||||
// Delete the word and the punctuation if it exists.
|
|
||||||
var pattern =
|
|
||||||
$@"\s{escaped}(?=\p{{P}}|\s|$)|^{escaped}(?:\p{{P}}|(?=\s|$))";
|
|
||||||
|
|
||||||
var r = new Regex(pattern, RegexOptions.RightToLeft | RegexOptions.IgnoreCase);
|
|
||||||
|
|
||||||
// We're using sanitized as the original message until the end so that we can make sure the indices of
|
// We're using sanitized as the original message until the end so that we can make sure the indices of
|
||||||
// the emotes are accurate.
|
// the emotes are accurate.
|
||||||
var lastMatch = r.Match(sanitized);
|
var lastMatch = r.Match(sanitized);
|
||||||
@@ -159,4 +146,21 @@ public sealed class ChatSanitizationManager : IChatSanitizationManager
|
|||||||
sanitized = message.Trim();
|
sanitized = message.Trim();
|
||||||
return emote is not null;
|
return emote is not null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static (Regex regex, string emoteKey) Entry(string shorthand, string emoteKey)
|
||||||
|
{
|
||||||
|
// We have to escape it because shorthands like ":)" or "-_-" would break the regex otherwise.
|
||||||
|
var escaped = Regex.Escape(shorthand);
|
||||||
|
|
||||||
|
// So there are 2 cases:
|
||||||
|
// - If there is whitespace before it and after it is either punctuation, whitespace, or the end of the line
|
||||||
|
// Delete the word and the whitespace before
|
||||||
|
// - If it is at the start of the string and is followed by punctuation, whitespace, or the end of the line
|
||||||
|
// Delete the word and the punctuation if it exists.
|
||||||
|
var pattern = new Regex(
|
||||||
|
$@"\s{escaped}(?=\p{{P}}|\s|$)|^{escaped}(?:\p{{P}}|(?=\s|$))",
|
||||||
|
RegexOptions.RightToLeft | RegexOptions.IgnoreCase | RegexOptions.Compiled);
|
||||||
|
|
||||||
|
return (pattern, emoteKey);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,17 +0,0 @@
|
|||||||
using Content.Shared.Dataset;
|
|
||||||
using Robust.Shared.Prototypes;
|
|
||||||
|
|
||||||
namespace Content.Server.Chat;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Makes the entity speak when triggered. If the item has UseDelay component, the system will respect that cooldown.
|
|
||||||
/// </summary>
|
|
||||||
[RegisterComponent]
|
|
||||||
public sealed partial class SpeakOnTriggerComponent : Component
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// The identifier for the dataset prototype containing messages to be spoken by this entity.
|
|
||||||
/// </summary>
|
|
||||||
[DataField(required: true)]
|
|
||||||
public ProtoId<LocalizedDatasetPrototype> Pack = string.Empty;
|
|
||||||
}
|
|
||||||
@@ -67,6 +67,9 @@ public sealed class SuicideSystem : EntitySystem
|
|||||||
if (!suicideGhostEvent.Handled || _tagSystem.HasTag(victim, CannotSuicideTag))
|
if (!suicideGhostEvent.Handled || _tagSystem.HasTag(victim, CannotSuicideTag))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
// TODO: fix this
|
||||||
|
// This is a handled event, but the result is never used
|
||||||
|
// It looks like TriggerOnMobstateChange is supposed to prevent you from suiciding
|
||||||
var suicideEvent = new SuicideEvent(victim);
|
var suicideEvent = new SuicideEvent(victim);
|
||||||
RaiseLocalEvent(victim, suicideEvent);
|
RaiseLocalEvent(victim, suicideEvent);
|
||||||
|
|
||||||
|
|||||||
@@ -60,11 +60,6 @@ public sealed partial class ChatSystem : SharedChatSystem
|
|||||||
[Dependency] private readonly EntityWhitelistSystem _whitelistSystem = default!;
|
[Dependency] private readonly EntityWhitelistSystem _whitelistSystem = default!;
|
||||||
[Dependency] private readonly ExamineSystemShared _examineSystem = default!;
|
[Dependency] private readonly ExamineSystemShared _examineSystem = default!;
|
||||||
|
|
||||||
public const int VoiceRange = 10; // how far voice goes in world units
|
|
||||||
public const int WhisperClearRange = 2; // how far whisper goes while still being understandable, in world units
|
|
||||||
public const int WhisperMuffledRange = 5; // how far whisper goes at all, in world units
|
|
||||||
public const string DefaultAnnouncementSound = "/Audio/Announcements/announce.ogg";
|
|
||||||
|
|
||||||
private bool _loocEnabled = true;
|
private bool _loocEnabled = true;
|
||||||
private bool _deadLoocEnabled;
|
private bool _deadLoocEnabled;
|
||||||
private bool _critLoocEnabled;
|
private bool _critLoocEnabled;
|
||||||
|
|||||||
@@ -1,11 +1,16 @@
|
|||||||
using Content.Server.Forensics;
|
using Content.Server.Forensics;
|
||||||
|
using Content.Server.Speech.EntitySystems;
|
||||||
using Content.Shared.Cloning.Events;
|
using Content.Shared.Cloning.Events;
|
||||||
using Content.Shared.Clothing.Components;
|
|
||||||
using Content.Shared.FixedPoint;
|
using Content.Shared.FixedPoint;
|
||||||
|
using Content.Shared.Inventory;
|
||||||
using Content.Shared.Labels.Components;
|
using Content.Shared.Labels.Components;
|
||||||
using Content.Shared.Labels.EntitySystems;
|
using Content.Shared.Labels.EntitySystems;
|
||||||
|
using Content.Shared.Movement.Components;
|
||||||
|
using Content.Shared.Movement.Systems;
|
||||||
using Content.Shared.Paper;
|
using Content.Shared.Paper;
|
||||||
using Content.Shared.Stacks;
|
using Content.Shared.Stacks;
|
||||||
|
using Content.Shared.Speech.Components;
|
||||||
|
using Content.Shared.Storage;
|
||||||
using Content.Shared.Store;
|
using Content.Shared.Store;
|
||||||
using Content.Shared.Store.Components;
|
using Content.Shared.Store.Components;
|
||||||
using Robust.Shared.Prototypes;
|
using Robust.Shared.Prototypes;
|
||||||
@@ -14,46 +19,57 @@ namespace Content.Server.Cloning;
|
|||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The part of item cloning responsible for copying over important components.
|
/// The part of item cloning responsible for copying over important components.
|
||||||
/// This is used for <see cref="CopyItem"/>.
|
|
||||||
/// Anything not copied over here gets reverted to the values the item had in its prototype.
|
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <remarks>
|
/// <remarks>
|
||||||
/// This method of copying items is of course not perfect as we cannot clone every single component, which would be pretty much impossible with our ECS.
|
/// These are all not part of their corresponding systems because we don't want systems every system to depend on a CloningSystem namespace import, which is still heavily coupled to med code.
|
||||||
/// We only consider the most important components so the paradox clone gets similar equipment.
|
/// TODO: Create a more generic "CopyEntity" method/event (probably in RT) that doesn't have this problem and then move all these subscriptions.
|
||||||
/// This method of using subscriptions was chosen to make it easy for forks to add their own custom components that need to be copied.
|
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
public sealed partial class CloningSystem : EntitySystem
|
public sealed partial class CloningSystem
|
||||||
{
|
{
|
||||||
[Dependency] private readonly SharedStackSystem _stack = default!;
|
[Dependency] private readonly SharedStackSystem _stack = default!;
|
||||||
[Dependency] private readonly LabelSystem _label = default!;
|
[Dependency] private readonly LabelSystem _label = default!;
|
||||||
[Dependency] private readonly ForensicsSystem _forensics = default!;
|
[Dependency] private readonly ForensicsSystem _forensics = default!;
|
||||||
[Dependency] private readonly PaperSystem _paper = default!;
|
[Dependency] private readonly PaperSystem _paper = default!;
|
||||||
|
[Dependency] private readonly VocalSystem _vocal = default!;
|
||||||
|
[Dependency] private readonly MovementSpeedModifierSystem _movementSpeedModifier = default!;
|
||||||
|
|
||||||
public override void Initialize()
|
public override void Initialize()
|
||||||
{
|
{
|
||||||
base.Initialize();
|
base.Initialize();
|
||||||
|
|
||||||
SubscribeLocalEvent<StackComponent, CloningItemEvent>(OnCloneStack);
|
// These are used for <see cref="CopyItem"/>.
|
||||||
SubscribeLocalEvent<LabelComponent, CloningItemEvent>(OnCloneLabel);
|
// Anything not copied over here gets reverted to the values the item had in its prototype.
|
||||||
SubscribeLocalEvent<PaperComponent, CloningItemEvent>(OnClonePaper);
|
// This method of copying items is of course not perfect as we cannot clone every single component, which would be pretty much impossible with our ECS.
|
||||||
SubscribeLocalEvent<ForensicsComponent, CloningItemEvent>(OnCloneForensics);
|
// We only consider the most important components so the paradox clone gets similar equipment.
|
||||||
SubscribeLocalEvent<StoreComponent, CloningItemEvent>(OnCloneStore);
|
// This method of using subscriptions was chosen to make it easy for forks to add their own custom components that need to be copied.
|
||||||
|
SubscribeLocalEvent<StackComponent, CloningItemEvent>(OnCloneItemStack);
|
||||||
|
SubscribeLocalEvent<LabelComponent, CloningItemEvent>(OnCloneItemLabel);
|
||||||
|
SubscribeLocalEvent<PaperComponent, CloningItemEvent>(OnCloneItemPaper);
|
||||||
|
SubscribeLocalEvent<ForensicsComponent, CloningItemEvent>(OnCloneItemForensics);
|
||||||
|
SubscribeLocalEvent<StoreComponent, CloningItemEvent>(OnCloneItemStore);
|
||||||
|
|
||||||
|
// These are for cloning components that cannot be cloned using CopyComp.
|
||||||
|
// Put them into CloningSettingsPrototype.EventComponents to have them be applied to the clone.
|
||||||
|
SubscribeLocalEvent<VocalComponent, CloningEvent>(OnCloneVocal);
|
||||||
|
SubscribeLocalEvent<StorageComponent, CloningEvent>(OnCloneStorage);
|
||||||
|
SubscribeLocalEvent<InventoryComponent, CloningEvent>(OnCloneInventory);
|
||||||
|
SubscribeLocalEvent<MovementSpeedModifierComponent, CloningEvent>(OnCloneInventory);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnCloneStack(Entity<StackComponent> ent, ref CloningItemEvent args)
|
private void OnCloneItemStack(Entity<StackComponent> ent, ref CloningItemEvent args)
|
||||||
{
|
{
|
||||||
// if the clone is a stack as well, adjust the count of the copy
|
// if the clone is a stack as well, adjust the count of the copy
|
||||||
if (TryComp<StackComponent>(args.CloneUid, out var cloneStackComp))
|
if (TryComp<StackComponent>(args.CloneUid, out var cloneStackComp))
|
||||||
_stack.SetCount(args.CloneUid, ent.Comp.Count, cloneStackComp);
|
_stack.SetCount(args.CloneUid, ent.Comp.Count, cloneStackComp);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnCloneLabel(Entity<LabelComponent> ent, ref CloningItemEvent args)
|
private void OnCloneItemLabel(Entity<LabelComponent> ent, ref CloningItemEvent args)
|
||||||
{
|
{
|
||||||
// copy the label
|
// copy the label
|
||||||
_label.Label(args.CloneUid, ent.Comp.CurrentLabel);
|
_label.Label(args.CloneUid, ent.Comp.CurrentLabel);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnClonePaper(Entity<PaperComponent> ent, ref CloningItemEvent args)
|
private void OnCloneItemPaper(Entity<PaperComponent> ent, ref CloningItemEvent args)
|
||||||
{
|
{
|
||||||
// copy the text and any stamps
|
// copy the text and any stamps
|
||||||
if (TryComp<PaperComponent>(args.CloneUid, out var clonePaperComp))
|
if (TryComp<PaperComponent>(args.CloneUid, out var clonePaperComp))
|
||||||
@@ -63,13 +79,13 @@ public sealed partial class CloningSystem : EntitySystem
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnCloneForensics(Entity<ForensicsComponent> ent, ref CloningItemEvent args)
|
private void OnCloneItemForensics(Entity<ForensicsComponent> ent, ref CloningItemEvent args)
|
||||||
{
|
{
|
||||||
// copy any forensics to the cloned item
|
// copy any forensics to the cloned item
|
||||||
_forensics.CopyForensicsFrom(ent.Comp, args.CloneUid);
|
_forensics.CopyForensicsFrom(ent.Comp, args.CloneUid);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnCloneStore(Entity<StoreComponent> ent, ref CloningItemEvent args)
|
private void OnCloneItemStore(Entity<StoreComponent> ent, ref CloningItemEvent args)
|
||||||
{
|
{
|
||||||
// copy the current amount of currency in the store
|
// copy the current amount of currency in the store
|
||||||
// at the moment this takes care of uplink implants and the portable nukie uplinks
|
// at the moment this takes care of uplink implants and the portable nukie uplinks
|
||||||
@@ -80,4 +96,35 @@ public sealed partial class CloningSystem : EntitySystem
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void OnCloneVocal(Entity<VocalComponent> ent, ref CloningEvent args)
|
||||||
|
{
|
||||||
|
if (!args.Settings.EventComponents.Contains(Factory.GetRegistration(ent.Comp.GetType()).Name))
|
||||||
|
return;
|
||||||
|
|
||||||
|
_vocal.CopyComponent(ent.AsNullable(), args.CloneUid);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnCloneStorage(Entity<StorageComponent> ent, ref CloningEvent args)
|
||||||
|
{
|
||||||
|
if (!args.Settings.EventComponents.Contains(Factory.GetRegistration(ent.Comp.GetType()).Name))
|
||||||
|
return;
|
||||||
|
|
||||||
|
_storage.CopyComponent(ent.AsNullable(), args.CloneUid);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnCloneInventory(Entity<InventoryComponent> ent, ref CloningEvent args)
|
||||||
|
{
|
||||||
|
if (!args.Settings.EventComponents.Contains(Factory.GetRegistration(ent.Comp.GetType()).Name))
|
||||||
|
return;
|
||||||
|
|
||||||
|
_inventory.CopyComponent(ent.AsNullable(), args.CloneUid);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnCloneInventory(Entity<MovementSpeedModifierComponent> ent, ref CloningEvent args)
|
||||||
|
{
|
||||||
|
if (!args.Settings.EventComponents.Contains(Factory.GetRegistration(ent.Comp.GetType()).Name))
|
||||||
|
return;
|
||||||
|
|
||||||
|
_movementSpeedModifier.CopyComponent(ent.AsNullable(), args.CloneUid);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ namespace Content.Server.Cloning;
|
|||||||
/// System responsible for making a copy of a humanoid's body.
|
/// System responsible for making a copy of a humanoid's body.
|
||||||
/// For the cloning machines themselves look at CloningPodSystem, CloningConsoleSystem and MedicalScannerSystem instead.
|
/// For the cloning machines themselves look at CloningPodSystem, CloningConsoleSystem and MedicalScannerSystem instead.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public sealed partial class CloningSystem : EntitySystem
|
public sealed partial class CloningSystem : SharedCloningSystem
|
||||||
{
|
{
|
||||||
[Dependency] private readonly HumanoidAppearanceSystem _humanoidSystem = default!;
|
[Dependency] private readonly HumanoidAppearanceSystem _humanoidSystem = default!;
|
||||||
[Dependency] private readonly InventorySystem _inventory = default!;
|
[Dependency] private readonly InventorySystem _inventory = default!;
|
||||||
@@ -84,13 +84,7 @@ public sealed partial class CloningSystem : EntitySystem
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
public override void CloneComponents(EntityUid original, EntityUid clone, CloningSettingsPrototype settings)
|
||||||
/// Copy components from one entity to another based on a CloningSettingsPrototype.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="original">The orignal Entity to clone components from.</param>
|
|
||||||
/// <param name="clone">The target Entity to clone components to.</param>
|
|
||||||
/// <param name="settings">The clone settings prototype containing the list of components to clone.</param>
|
|
||||||
public void CloneComponents(EntityUid original, EntityUid clone, CloningSettingsPrototype settings)
|
|
||||||
{
|
{
|
||||||
var componentsToCopy = settings.Components;
|
var componentsToCopy = settings.Components;
|
||||||
var componentsToEvent = settings.EventComponents;
|
var componentsToEvent = settings.EventComponents;
|
||||||
@@ -128,6 +122,7 @@ public sealed partial class CloningSystem : EntitySystem
|
|||||||
}
|
}
|
||||||
|
|
||||||
// If the original does not have the component, then the clone shouldn't have it either.
|
// If the original does not have the component, then the clone shouldn't have it either.
|
||||||
|
if (!HasComp(original, componentRegistration.Type))
|
||||||
RemComp(clone, componentRegistration.Type);
|
RemComp(clone, componentRegistration.Type);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,50 +0,0 @@
|
|||||||
using Content.Server.Explosion.EntitySystems;
|
|
||||||
using Content.Shared.Damage;
|
|
||||||
using Content.Shared.Damage.Components;
|
|
||||||
|
|
||||||
namespace Content.Server.Damage.Systems;
|
|
||||||
|
|
||||||
// System for damage that occurs on specific trigger, towards the user..
|
|
||||||
public sealed class DamageUserOnTriggerSystem : EntitySystem
|
|
||||||
{
|
|
||||||
[Dependency] private readonly DamageableSystem _damageableSystem = default!;
|
|
||||||
|
|
||||||
public override void Initialize()
|
|
||||||
{
|
|
||||||
SubscribeLocalEvent<DamageUserOnTriggerComponent, TriggerEvent>(OnTrigger);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnTrigger(EntityUid uid, DamageUserOnTriggerComponent component, TriggerEvent args)
|
|
||||||
{
|
|
||||||
if (args.User is null)
|
|
||||||
return;
|
|
||||||
|
|
||||||
args.Handled |= OnDamageTrigger(uid, args.User.Value, component);
|
|
||||||
}
|
|
||||||
|
|
||||||
private bool OnDamageTrigger(EntityUid source, EntityUid target, DamageUserOnTriggerComponent? component = null)
|
|
||||||
{
|
|
||||||
if (!Resolve(source, ref component))
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
var damage = new DamageSpecifier(component.Damage);
|
|
||||||
var ev = new BeforeDamageUserOnTriggerEvent(damage, target);
|
|
||||||
RaiseLocalEvent(source, ev);
|
|
||||||
|
|
||||||
return _damageableSystem.TryChangeDamage(target, ev.Damage, component.IgnoreResistances, origin: source) is not null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public sealed class BeforeDamageUserOnTriggerEvent : EntityEventArgs
|
|
||||||
{
|
|
||||||
public DamageSpecifier Damage { get; set; }
|
|
||||||
public EntityUid Tripper { get; }
|
|
||||||
|
|
||||||
public BeforeDamageUserOnTriggerEvent(DamageSpecifier damage, EntityUid target)
|
|
||||||
{
|
|
||||||
Damage = damage;
|
|
||||||
Tripper = target;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,5 +1,4 @@
|
|||||||
using Content.Server.Defusable.Components;
|
using Content.Server.Defusable.Components;
|
||||||
using Content.Server.Explosion.Components;
|
|
||||||
using Content.Server.Explosion.EntitySystems;
|
using Content.Server.Explosion.EntitySystems;
|
||||||
using Content.Server.Popups;
|
using Content.Server.Popups;
|
||||||
using Content.Server.Wires;
|
using Content.Server.Wires;
|
||||||
@@ -8,13 +7,13 @@ using Content.Shared.Construction.Components;
|
|||||||
using Content.Shared.Database;
|
using Content.Shared.Database;
|
||||||
using Content.Shared.Defusable;
|
using Content.Shared.Defusable;
|
||||||
using Content.Shared.Examine;
|
using Content.Shared.Examine;
|
||||||
using Content.Shared.Explosion.Components;
|
|
||||||
using Content.Shared.Explosion.Components.OnTrigger;
|
|
||||||
using Content.Shared.Popups;
|
using Content.Shared.Popups;
|
||||||
|
using Content.Shared.Trigger.Components;
|
||||||
|
using Content.Shared.Trigger.Components.Effects;
|
||||||
|
using Content.Shared.Trigger.Systems;
|
||||||
using Content.Shared.Verbs;
|
using Content.Shared.Verbs;
|
||||||
using Content.Shared.Wires;
|
using Content.Shared.Wires;
|
||||||
using Robust.Server.GameObjects;
|
using Robust.Server.GameObjects;
|
||||||
using Robust.Shared.Audio;
|
|
||||||
using Robust.Shared.Audio.Systems;
|
using Robust.Shared.Audio.Systems;
|
||||||
|
|
||||||
namespace Content.Server.Defusable.Systems;
|
namespace Content.Server.Defusable.Systems;
|
||||||
@@ -74,12 +73,13 @@ public sealed class DefusableSystem : SharedDefusableSystem
|
|||||||
{
|
{
|
||||||
args.PushMarkup(Loc.GetString("defusable-examine-defused", ("name", uid)));
|
args.PushMarkup(Loc.GetString("defusable-examine-defused", ("name", uid)));
|
||||||
}
|
}
|
||||||
else if (comp.Activated && TryComp<ActiveTimerTriggerComponent>(uid, out var activeComp))
|
else if (comp.Activated)
|
||||||
{
|
{
|
||||||
if (comp.DisplayTime)
|
var remaining = _trigger.GetRemainingTime(uid);
|
||||||
|
if (comp.DisplayTime && remaining != null)
|
||||||
{
|
{
|
||||||
args.PushMarkup(Loc.GetString("defusable-examine-live", ("name", uid),
|
args.PushMarkup(Loc.GetString("defusable-examine-live", ("name", uid),
|
||||||
("time", MathF.Floor(activeComp.TimeRemaining))));
|
("time", Math.Floor(remaining.Value.TotalSeconds))));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -139,16 +139,9 @@ public sealed class DefusableSystem : SharedDefusableSystem
|
|||||||
SetActivated(comp, true);
|
SetActivated(comp, true);
|
||||||
|
|
||||||
_popup.PopupEntity(Loc.GetString("defusable-popup-begun", ("name", uid)), uid);
|
_popup.PopupEntity(Loc.GetString("defusable-popup-begun", ("name", uid)), uid);
|
||||||
if (TryComp<OnUseTimerTriggerComponent>(uid, out var timerTrigger))
|
if (TryComp<TimerTriggerComponent>(uid, out var timerTrigger))
|
||||||
{
|
{
|
||||||
_trigger.HandleTimerTrigger(
|
_trigger.ActivateTimerTrigger((uid, timerTrigger));
|
||||||
uid,
|
|
||||||
user,
|
|
||||||
timerTrigger.Delay,
|
|
||||||
timerTrigger.BeepInterval,
|
|
||||||
timerTrigger.InitialBeepDelay,
|
|
||||||
timerTrigger.BeepSound
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
RaiseLocalEvent(uid, new BombArmedEvent(uid));
|
RaiseLocalEvent(uid, new BombArmedEvent(uid));
|
||||||
@@ -188,7 +181,7 @@ public sealed class DefusableSystem : SharedDefusableSystem
|
|||||||
{
|
{
|
||||||
SetUsable(comp, false);
|
SetUsable(comp, false);
|
||||||
RemComp<ExplodeOnTriggerComponent>(uid);
|
RemComp<ExplodeOnTriggerComponent>(uid);
|
||||||
RemComp<OnUseTimerTriggerComponent>(uid);
|
RemComp<TimerTriggerComponent>(uid);
|
||||||
}
|
}
|
||||||
RemComp<ActiveTimerTriggerComponent>(uid);
|
RemComp<ActiveTimerTriggerComponent>(uid);
|
||||||
|
|
||||||
@@ -246,7 +239,7 @@ public sealed class DefusableSystem : SharedDefusableSystem
|
|||||||
if (comp is not { Activated: true, DelayWireUsed: false })
|
if (comp is not { Activated: true, DelayWireUsed: false })
|
||||||
return;
|
return;
|
||||||
|
|
||||||
_trigger.TryDelay(wire.Owner, 30f);
|
_trigger.TryDelay(wire.Owner, TimeSpan.FromSeconds(30));
|
||||||
_popup.PopupEntity(Loc.GetString("defusable-popup-wire-chirp", ("name", wire.Owner)), wire.Owner);
|
_popup.PopupEntity(Loc.GetString("defusable-popup-wire-chirp", ("name", wire.Owner)), wire.Owner);
|
||||||
comp.DelayWireUsed = true;
|
comp.DelayWireUsed = true;
|
||||||
}
|
}
|
||||||
@@ -268,7 +261,7 @@ public sealed class DefusableSystem : SharedDefusableSystem
|
|||||||
if (comp is { Activated: true, ProceedWireUsed: false })
|
if (comp is { Activated: true, ProceedWireUsed: false })
|
||||||
{
|
{
|
||||||
comp.ProceedWireUsed = true;
|
comp.ProceedWireUsed = true;
|
||||||
_trigger.TryDelay(wire.Owner, -15f);
|
_trigger.TryDelay(wire.Owner, TimeSpan.FromSeconds(-15));
|
||||||
}
|
}
|
||||||
|
|
||||||
_popup.PopupEntity(Loc.GetString("defusable-popup-wire-proceed-pulse", ("name", wire.Owner)), wire.Owner);
|
_popup.PopupEntity(Loc.GetString("defusable-popup-wire-proceed-pulse", ("name", wire.Owner)), wire.Owner);
|
||||||
@@ -298,7 +291,7 @@ public sealed class DefusableSystem : SharedDefusableSystem
|
|||||||
{
|
{
|
||||||
if (!comp.ActivatedWireUsed)
|
if (!comp.ActivatedWireUsed)
|
||||||
{
|
{
|
||||||
_trigger.TryDelay(wire.Owner, 30f);
|
_trigger.TryDelay(wire.Owner, TimeSpan.FromSeconds(30));
|
||||||
_popup.PopupEntity(Loc.GetString("defusable-popup-wire-chirp", ("name", wire.Owner)), wire.Owner);
|
_popup.PopupEntity(Loc.GetString("defusable-popup-wire-chirp", ("name", wire.Owner)), wire.Owner);
|
||||||
comp.ActivatedWireUsed = true;
|
comp.ActivatedWireUsed = true;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
using System.Diagnostics.CodeAnalysis;
|
using System.Diagnostics.CodeAnalysis;
|
||||||
|
using System.Linq;
|
||||||
using Content.Server.Administration.Logs;
|
using Content.Server.Administration.Logs;
|
||||||
using Content.Server.Atmos.EntitySystems;
|
using Content.Server.Atmos.EntitySystems;
|
||||||
using Content.Server.Body.Systems;
|
using Content.Server.Body.Systems;
|
||||||
@@ -14,15 +15,13 @@ using Content.Shared.Damage;
|
|||||||
using Content.Shared.Database;
|
using Content.Shared.Database;
|
||||||
using Content.Shared.Destructible;
|
using Content.Shared.Destructible;
|
||||||
using Content.Shared.FixedPoint;
|
using Content.Shared.FixedPoint;
|
||||||
|
using Content.Shared.Humanoid;
|
||||||
|
using Content.Shared.Trigger.Systems;
|
||||||
using JetBrains.Annotations;
|
using JetBrains.Annotations;
|
||||||
using Robust.Server.Audio;
|
using Robust.Server.Audio;
|
||||||
using Robust.Server.GameObjects;
|
|
||||||
using Robust.Shared.Containers;
|
using Robust.Shared.Containers;
|
||||||
using Robust.Shared.Prototypes;
|
using Robust.Shared.Prototypes;
|
||||||
using Robust.Shared.Random;
|
using Robust.Shared.Random;
|
||||||
using System.Linq;
|
|
||||||
using Content.Shared.Humanoid;
|
|
||||||
using Robust.Shared.Player;
|
|
||||||
|
|
||||||
namespace Content.Server.Destructible
|
namespace Content.Server.Destructible
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -5,6 +5,6 @@ public sealed partial class TimerStartBehavior : IThresholdBehavior
|
|||||||
{
|
{
|
||||||
public void Execute(EntityUid owner, DestructibleSystem system, EntityUid? cause = null)
|
public void Execute(EntityUid owner, DestructibleSystem system, EntityUid? cause = null)
|
||||||
{
|
{
|
||||||
system.TriggerSystem.StartTimer(owner, cause);
|
system.TriggerSystem.ActivateTimerTrigger(owner, cause);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,10 +1,18 @@
|
|||||||
namespace Content.Server.Destructible.Thresholds.Behaviors;
|
using Content.Shared.Trigger.Systems;
|
||||||
|
|
||||||
|
namespace Content.Server.Destructible.Thresholds.Behaviors;
|
||||||
|
|
||||||
[DataDefinition]
|
[DataDefinition]
|
||||||
public sealed partial class TriggerBehavior : IThresholdBehavior
|
public sealed partial class TriggerBehavior : IThresholdBehavior
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The trigger key to use when triggering.
|
||||||
|
/// </summary>
|
||||||
|
[DataField]
|
||||||
|
public string? KeyOut { get; set; } = TriggerSystem.DefaultTriggerKey;
|
||||||
|
|
||||||
public void Execute(EntityUid owner, DestructibleSystem system, EntityUid? cause = null)
|
public void Execute(EntityUid owner, DestructibleSystem system, EntityUid? cause = null)
|
||||||
{
|
{
|
||||||
system.TriggerSystem.Trigger(owner, cause);
|
system.TriggerSystem.Trigger(owner, cause, KeyOut);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,6 @@
|
|||||||
using Content.Server.DeviceLinking.Components;
|
using Content.Server.DeviceLinking.Components;
|
||||||
|
using Content.Server.DeviceNetwork;
|
||||||
|
using Content.Server.DeviceNetwork.Components;
|
||||||
using Content.Server.DeviceNetwork.Systems;
|
using Content.Server.DeviceNetwork.Systems;
|
||||||
using Content.Shared.DeviceLinking;
|
using Content.Shared.DeviceLinking;
|
||||||
using Content.Shared.DeviceLinking.Events;
|
using Content.Shared.DeviceLinking.Events;
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
using Content.Server.DeviceLinking.Components;
|
using Content.Server.DeviceLinking.Components;
|
||||||
using Content.Server.DeviceNetwork;
|
|
||||||
using Content.Shared.DeviceLinking;
|
using Content.Shared.DeviceLinking;
|
||||||
using Content.Shared.DeviceLinking.Events;
|
using Content.Shared.DeviceLinking.Events;
|
||||||
using Content.Shared.DeviceNetwork;
|
using Content.Shared.DeviceNetwork;
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
using Content.Server.Administration.Logs;
|
using Content.Server.Administration.Logs;
|
||||||
using Content.Server.DeviceLinking.Components;
|
using Content.Server.DeviceLinking.Components;
|
||||||
using Content.Server.Explosion.EntitySystems;
|
|
||||||
using Content.Shared.Database;
|
using Content.Shared.Database;
|
||||||
using Content.Shared.Interaction.Events;
|
using Content.Shared.Interaction.Events;
|
||||||
using Content.Shared.Timing;
|
using Content.Shared.Timing;
|
||||||
@@ -10,7 +9,6 @@ namespace Content.Server.DeviceLinking.Systems;
|
|||||||
public sealed class SignallerSystem : EntitySystem
|
public sealed class SignallerSystem : EntitySystem
|
||||||
{
|
{
|
||||||
[Dependency] private readonly DeviceLinkSystem _link = default!;
|
[Dependency] private readonly DeviceLinkSystem _link = default!;
|
||||||
[Dependency] private readonly UseDelaySystem _useDelay = default!;
|
|
||||||
[Dependency] private readonly IAdminLogManager _adminLogger = default!;
|
[Dependency] private readonly IAdminLogManager _adminLogger = default!;
|
||||||
|
|
||||||
public override void Initialize()
|
public override void Initialize()
|
||||||
@@ -19,7 +17,6 @@ public sealed class SignallerSystem : EntitySystem
|
|||||||
|
|
||||||
SubscribeLocalEvent<SignallerComponent, ComponentInit>(OnInit);
|
SubscribeLocalEvent<SignallerComponent, ComponentInit>(OnInit);
|
||||||
SubscribeLocalEvent<SignallerComponent, UseInHandEvent>(OnUseInHand);
|
SubscribeLocalEvent<SignallerComponent, UseInHandEvent>(OnUseInHand);
|
||||||
SubscribeLocalEvent<SignallerComponent, TriggerEvent>(OnTrigger);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnInit(EntityUid uid, SignallerComponent component, ComponentInit args)
|
private void OnInit(EntityUid uid, SignallerComponent component, ComponentInit args)
|
||||||
@@ -36,16 +33,4 @@ public sealed class SignallerSystem : EntitySystem
|
|||||||
_link.InvokePort(uid, component.Port);
|
_link.InvokePort(uid, component.Port);
|
||||||
args.Handled = true;
|
args.Handled = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnTrigger(EntityUid uid, SignallerComponent component, TriggerEvent args)
|
|
||||||
{
|
|
||||||
if (!TryComp(uid, out UseDelayComponent? useDelay)
|
|
||||||
// if on cooldown, do nothing
|
|
||||||
// and set cooldown to prevent clocks
|
|
||||||
|| !_useDelay.TryResetDelay((uid, useDelay), true))
|
|
||||||
return;
|
|
||||||
|
|
||||||
_link.InvokePort(uid, component.Port);
|
|
||||||
args.Handled = true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -58,7 +58,7 @@ public sealed class ElectrocutionSystem : SharedElectrocutionSystem
|
|||||||
[Dependency] private readonly MetaDataSystem _metaData = default!;
|
[Dependency] private readonly MetaDataSystem _metaData = default!;
|
||||||
[Dependency] private readonly TurfSystem _turf = default!;
|
[Dependency] private readonly TurfSystem _turf = default!;
|
||||||
|
|
||||||
private static readonly ProtoId<StatusEffectPrototype> StatusEffectKey = "Electrocution";
|
private static readonly ProtoId<StatusEffectPrototype> StatusKeyIn = "Electrocution";
|
||||||
private static readonly ProtoId<DamageTypePrototype> DamageType = "Shock";
|
private static readonly ProtoId<DamageTypePrototype> DamageType = "Shock";
|
||||||
private static readonly ProtoId<TagPrototype> WindowTag = "Window";
|
private static readonly ProtoId<TagPrototype> WindowTag = "Window";
|
||||||
|
|
||||||
@@ -386,12 +386,12 @@ public sealed class ElectrocutionSystem : SharedElectrocutionSystem
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!Resolve(uid, ref statusEffects, false) ||
|
if (!Resolve(uid, ref statusEffects, false) ||
|
||||||
!_statusEffects.CanApplyEffect(uid, StatusEffectKey, statusEffects))
|
!_statusEffects.CanApplyEffect(uid, StatusKeyIn, statusEffects))
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!_statusEffects.TryAddStatusEffect<ElectrocutedComponent>(uid, StatusEffectKey, time, refresh, statusEffects))
|
if (!_statusEffects.TryAddStatusEffect<ElectrocutedComponent>(uid, StatusKeyIn, time, refresh, statusEffects))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
var shouldStun = siemensCoefficient > 0.5f;
|
var shouldStun = siemensCoefficient > 0.5f;
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
using Content.Server.Emoting.Systems;
|
using Content.Server.Emoting.Systems;
|
||||||
using Content.Shared.Chat.Prototypes;
|
using Content.Shared.Chat.Prototypes;
|
||||||
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype;
|
using Robust.Shared.Prototypes;
|
||||||
|
|
||||||
namespace Content.Server.Emoting.Components;
|
namespace Content.Server.Emoting.Components;
|
||||||
|
|
||||||
@@ -14,11 +14,6 @@ public sealed partial class BodyEmotesComponent : Component
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Emote sounds prototype id for body emotes.
|
/// Emote sounds prototype id for body emotes.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[DataField("soundsId", customTypeSerializer: typeof(PrototypeIdSerializer<EmoteSoundsPrototype>))]
|
[DataField]
|
||||||
public string? SoundsId;
|
public ProtoId<EmoteSoundsPrototype>? SoundsId;
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Loaded emote sounds prototype used for body emotes.
|
|
||||||
/// </summary>
|
|
||||||
public EmoteSoundsPrototype? Sounds;
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,15 +14,8 @@ public sealed class BodyEmotesSystem : EntitySystem
|
|||||||
public override void Initialize()
|
public override void Initialize()
|
||||||
{
|
{
|
||||||
base.Initialize();
|
base.Initialize();
|
||||||
SubscribeLocalEvent<BodyEmotesComponent, ComponentStartup>(OnStartup);
|
|
||||||
SubscribeLocalEvent<BodyEmotesComponent, EmoteEvent>(OnEmote);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnStartup(EntityUid uid, BodyEmotesComponent component, ComponentStartup args)
|
SubscribeLocalEvent<BodyEmotesComponent, EmoteEvent>(OnEmote);
|
||||||
{
|
|
||||||
if (component.SoundsId == null)
|
|
||||||
return;
|
|
||||||
_proto.TryIndex(component.SoundsId, out component.Sounds);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnEmote(EntityUid uid, BodyEmotesComponent component, ref EmoteEvent args)
|
private void OnEmote(EntityUid uid, BodyEmotesComponent component, ref EmoteEvent args)
|
||||||
@@ -43,6 +36,9 @@ public sealed class BodyEmotesSystem : EntitySystem
|
|||||||
if (!TryComp(uid, out HandsComponent? hands) || hands.Count <= 0)
|
if (!TryComp(uid, out HandsComponent? hands) || hands.Count <= 0)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
return _chat.TryPlayEmoteSound(uid, component.Sounds, emote);
|
if (!_proto.Resolve(component.SoundsId, out var sounds))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return _chat.TryPlayEmoteSound(uid, sounds, emote);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,24 +0,0 @@
|
|||||||
namespace Content.Server.Emp;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Upon being triggered will EMP area around it.
|
|
||||||
/// </summary>
|
|
||||||
[RegisterComponent]
|
|
||||||
[Access(typeof(EmpSystem))]
|
|
||||||
public sealed partial class EmpOnTriggerComponent : Component
|
|
||||||
{
|
|
||||||
[DataField("range"), ViewVariables(VVAccess.ReadWrite)]
|
|
||||||
public float Range = 1.0f;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// How much energy will be consumed per battery in range
|
|
||||||
/// </summary>
|
|
||||||
[DataField("energyConsumption"), ViewVariables(VVAccess.ReadWrite)]
|
|
||||||
public float EnergyConsumption;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// How long it disables targets in seconds
|
|
||||||
/// </summary>
|
|
||||||
[DataField("disableDuration"), ViewVariables(VVAccess.ReadWrite)]
|
|
||||||
public float DisableDuration = 60f;
|
|
||||||
}
|
|
||||||
@@ -1,10 +1,7 @@
|
|||||||
using Content.Server.Explosion.EntitySystems;
|
|
||||||
using Content.Server.Power.EntitySystems;
|
using Content.Server.Power.EntitySystems;
|
||||||
using Content.Server.Radio;
|
using Content.Server.Radio;
|
||||||
using Content.Server.SurveillanceCamera;
|
using Content.Server.SurveillanceCamera;
|
||||||
using Content.Shared.Emp;
|
using Content.Shared.Emp;
|
||||||
using Content.Shared.Examine;
|
|
||||||
using Robust.Server.GameObjects;
|
|
||||||
using Robust.Shared.Map;
|
using Robust.Shared.Map;
|
||||||
|
|
||||||
namespace Content.Server.Emp;
|
namespace Content.Server.Emp;
|
||||||
@@ -12,15 +9,12 @@ namespace Content.Server.Emp;
|
|||||||
public sealed class EmpSystem : SharedEmpSystem
|
public sealed class EmpSystem : SharedEmpSystem
|
||||||
{
|
{
|
||||||
[Dependency] private readonly EntityLookupSystem _lookup = default!;
|
[Dependency] private readonly EntityLookupSystem _lookup = default!;
|
||||||
[Dependency] private readonly TransformSystem _transform = default!;
|
|
||||||
|
|
||||||
public const string EmpPulseEffectPrototype = "EffectEmpPulse";
|
public const string EmpPulseEffectPrototype = "EffectEmpPulse";
|
||||||
|
|
||||||
public override void Initialize()
|
public override void Initialize()
|
||||||
{
|
{
|
||||||
base.Initialize();
|
base.Initialize();
|
||||||
SubscribeLocalEvent<EmpDisabledComponent, ExaminedEvent>(OnExamine);
|
|
||||||
SubscribeLocalEvent<EmpOnTriggerComponent, TriggerEvent>(HandleEmpTrigger);
|
|
||||||
|
|
||||||
SubscribeLocalEvent<EmpDisabledComponent, RadioSendAttemptEvent>(OnRadioSendAttempt);
|
SubscribeLocalEvent<EmpDisabledComponent, RadioSendAttemptEvent>(OnRadioSendAttempt);
|
||||||
SubscribeLocalEvent<EmpDisabledComponent, RadioReceiveAttemptEvent>(OnRadioReceiveAttempt);
|
SubscribeLocalEvent<EmpDisabledComponent, RadioReceiveAttemptEvent>(OnRadioReceiveAttempt);
|
||||||
@@ -28,14 +22,7 @@ public sealed class EmpSystem : SharedEmpSystem
|
|||||||
SubscribeLocalEvent<EmpDisabledComponent, SurveillanceCameraSetActiveAttemptEvent>(OnCameraSetActive);
|
SubscribeLocalEvent<EmpDisabledComponent, SurveillanceCameraSetActiveAttemptEvent>(OnCameraSetActive);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
public override void EmpPulse(MapCoordinates coordinates, float range, float energyConsumption, float duration)
|
||||||
/// Triggers an EMP pulse at the given location, by first raising an <see cref="EmpAttemptEvent"/>, then a raising <see cref="EmpPulseEvent"/> on all entities in range.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="coordinates">The location to trigger the EMP pulse at.</param>
|
|
||||||
/// <param name="range">The range of the EMP pulse.</param>
|
|
||||||
/// <param name="energyConsumption">The amount of energy consumed by the EMP pulse.</param>
|
|
||||||
/// <param name="duration">The duration of the EMP effects.</param>
|
|
||||||
public void EmpPulse(MapCoordinates coordinates, float range, float energyConsumption, float duration)
|
|
||||||
{
|
{
|
||||||
foreach (var uid in _lookup.GetEntitiesInRange(coordinates, range))
|
foreach (var uid in _lookup.GetEntitiesInRange(coordinates, range))
|
||||||
{
|
{
|
||||||
@@ -86,16 +73,16 @@ public sealed class EmpSystem : SharedEmpSystem
|
|||||||
{
|
{
|
||||||
var ev = new EmpPulseEvent(energyConsumption, false, false, TimeSpan.FromSeconds(duration));
|
var ev = new EmpPulseEvent(energyConsumption, false, false, TimeSpan.FromSeconds(duration));
|
||||||
RaiseLocalEvent(uid, ref ev);
|
RaiseLocalEvent(uid, ref ev);
|
||||||
|
|
||||||
if (ev.Affected)
|
if (ev.Affected)
|
||||||
{
|
|
||||||
Spawn(EmpDisabledEffectPrototype, Transform(uid).Coordinates);
|
Spawn(EmpDisabledEffectPrototype, Transform(uid).Coordinates);
|
||||||
}
|
|
||||||
if (ev.Disabled)
|
if (!ev.Disabled)
|
||||||
{
|
return;
|
||||||
|
|
||||||
var disabled = EnsureComp<EmpDisabledComponent>(uid);
|
var disabled = EnsureComp<EmpDisabledComponent>(uid);
|
||||||
disabled.DisabledUntil = Timing.CurTime + TimeSpan.FromSeconds(duration);
|
disabled.DisabledUntil = Timing.CurTime + TimeSpan.FromSeconds(duration);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
public override void Update(float frameTime)
|
public override void Update(float frameTime)
|
||||||
{
|
{
|
||||||
@@ -113,17 +100,6 @@ public sealed class EmpSystem : SharedEmpSystem
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnExamine(EntityUid uid, EmpDisabledComponent component, ExaminedEvent args)
|
|
||||||
{
|
|
||||||
args.PushMarkup(Loc.GetString("emp-disabled-comp-on-examine"));
|
|
||||||
}
|
|
||||||
|
|
||||||
private void HandleEmpTrigger(EntityUid uid, EmpOnTriggerComponent comp, TriggerEvent args)
|
|
||||||
{
|
|
||||||
EmpPulse(_transform.GetMapCoordinates(uid), comp.Range, comp.EnergyConsumption, comp.DisableDuration);
|
|
||||||
args.Handled = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnRadioSendAttempt(EntityUid uid, EmpDisabledComponent component, ref RadioSendAttemptEvent args)
|
private void OnRadioSendAttempt(EntityUid uid, EmpDisabledComponent component, ref RadioSendAttemptEvent args)
|
||||||
{
|
{
|
||||||
args.Cancelled = true;
|
args.Cancelled = true;
|
||||||
@@ -148,9 +124,7 @@ public sealed class EmpSystem : SharedEmpSystem
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Raised on an entity before <see cref="EmpPulseEvent"/>. Cancel this to prevent the emp event being raised.
|
/// Raised on an entity before <see cref="EmpPulseEvent"/>. Cancel this to prevent the emp event being raised.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public sealed partial class EmpAttemptEvent : CancellableEntityEventArgs
|
public sealed partial class EmpAttemptEvent : CancellableEntityEventArgs;
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
[ByRefEvent]
|
[ByRefEvent]
|
||||||
public record struct EmpPulseEvent(float EnergyConsumption, bool Affected, bool Disabled, TimeSpan Duration);
|
public record struct EmpPulseEvent(float EnergyConsumption, bool Affected, bool Disabled, TimeSpan Duration);
|
||||||
|
|||||||
@@ -133,7 +133,7 @@ public sealed class EntityEffectSystem : EntitySystem
|
|||||||
args.Result = false;
|
args.Result = false;
|
||||||
if (TryComp(args.Args.TargetEntity, out TemperatureComponent? temp))
|
if (TryComp(args.Args.TargetEntity, out TemperatureComponent? temp))
|
||||||
{
|
{
|
||||||
if (temp.CurrentTemperature > args.Condition.Min && temp.CurrentTemperature < args.Condition.Max)
|
if (temp.CurrentTemperature >= args.Condition.Min && temp.CurrentTemperature <= args.Condition.Max)
|
||||||
args.Result = true;
|
args.Result = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +0,0 @@
|
|||||||
namespace Content.Server.Explosion.Components;
|
|
||||||
|
|
||||||
[RegisterComponent]
|
|
||||||
public sealed partial class ActiveTriggerOnTimedCollideComponent : Component { }
|
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
namespace Content.Server.Explosion.Components;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Disallows starting the timer by hand, must be stuck or triggered by a system using <c>StartTimer</c>.
|
|
||||||
/// </summary>
|
|
||||||
[RegisterComponent]
|
|
||||||
public sealed partial class AutomatedTimerComponent : Component
|
|
||||||
{
|
|
||||||
}
|
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
using Content.Server.Explosion.EntitySystems;
|
|
||||||
|
|
||||||
namespace Content.Server.Explosion.Components;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Will anchor the attached entity upon a <see cref="TriggerEvent"/>.
|
|
||||||
/// </summary>
|
|
||||||
[RegisterComponent]
|
|
||||||
public sealed partial class AnchorOnTriggerComponent : Component
|
|
||||||
{
|
|
||||||
[DataField("removeOnTrigger")]
|
|
||||||
public bool RemoveOnTrigger = true;
|
|
||||||
}
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
using Content.Server.Explosion.EntitySystems;
|
|
||||||
|
|
||||||
namespace Content.Server.Explosion.Components;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Will delete the attached entity upon a <see cref="TriggerEvent"/>.
|
|
||||||
/// </summary>
|
|
||||||
[RegisterComponent]
|
|
||||||
public sealed partial class DeleteOnTriggerComponent : Component
|
|
||||||
{
|
|
||||||
}
|
|
||||||
@@ -1,16 +0,0 @@
|
|||||||
namespace Content.Server.Explosion.Components;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gibs on trigger, self explanatory.
|
|
||||||
/// Also in case of an implant using this, gibs the implant user instead.
|
|
||||||
/// </summary>
|
|
||||||
[RegisterComponent]
|
|
||||||
public sealed partial class GibOnTriggerComponent : Component
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Should gibbing also delete the owners items?
|
|
||||||
/// </summary>
|
|
||||||
[ViewVariables(VVAccess.ReadWrite)]
|
|
||||||
[DataField("deleteItems")]
|
|
||||||
public bool DeleteItems = false;
|
|
||||||
}
|
|
||||||
@@ -1,17 +0,0 @@
|
|||||||
using Content.Server.Explosion.EntitySystems;
|
|
||||||
using Robust.Shared.Audio;
|
|
||||||
|
|
||||||
namespace Content.Server.Explosion.Components;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Will play sound from the attached entity upon a <see cref="TriggerEvent"/>.
|
|
||||||
/// </summary>
|
|
||||||
[RegisterComponent]
|
|
||||||
public sealed partial class SoundOnTriggerComponent : Component
|
|
||||||
{
|
|
||||||
[DataField("removeOnTrigger")]
|
|
||||||
public bool RemoveOnTrigger = true;
|
|
||||||
|
|
||||||
[DataField("sound")]
|
|
||||||
public SoundSpecifier? Sound = new SoundPathSpecifier("/Audio/Effects/Grenades/supermatter_start.ogg");
|
|
||||||
}
|
|
||||||
@@ -1,34 +0,0 @@
|
|||||||
using Robust.Shared.Prototypes;
|
|
||||||
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom;
|
|
||||||
|
|
||||||
namespace Content.Server.Explosion.Components.OnTrigger;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// After being triggered applies the specified components and runs triggers again.
|
|
||||||
/// </summary>
|
|
||||||
[RegisterComponent, AutoGenerateComponentPause]
|
|
||||||
public sealed partial class TwoStageTriggerComponent : Component
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// How long it takes for the second stage to be triggered.
|
|
||||||
/// </summary>
|
|
||||||
[ViewVariables(VVAccess.ReadWrite)]
|
|
||||||
[DataField("triggerDelay")]
|
|
||||||
public TimeSpan TriggerDelay = TimeSpan.FromSeconds(10);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// This list of components that will be added for the second trigger.
|
|
||||||
/// </summary>
|
|
||||||
[DataField("components", required: true)]
|
|
||||||
public ComponentRegistry SecondStageComponents = new();
|
|
||||||
|
|
||||||
[DataField("nextTriggerTime", customTypeSerializer: typeof(TimeOffsetSerializer))]
|
|
||||||
[AutoPausedField]
|
|
||||||
public TimeSpan? NextTriggerTime;
|
|
||||||
|
|
||||||
[DataField("triggered")]
|
|
||||||
public bool Triggered = false;
|
|
||||||
|
|
||||||
[DataField("ComponentsIsLoaded")]
|
|
||||||
public bool ComponentsIsLoaded = false;
|
|
||||||
}
|
|
||||||
@@ -45,4 +45,10 @@ public sealed partial class ProjectileGrenadeComponent : Component
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
[DataField]
|
[DataField]
|
||||||
public float MaxVelocity = 6f;
|
public float MaxVelocity = 6f;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The trigger key that will activate the grenade.
|
||||||
|
/// </summary>
|
||||||
|
[DataField]
|
||||||
|
public string TriggerKey = "timer";
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,37 +0,0 @@
|
|||||||
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom;
|
|
||||||
using Content.Server.Explosion.EntitySystems;
|
|
||||||
|
|
||||||
namespace Content.Server.Explosion.Components;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// A component that electrocutes an entity having this component when a trigger is triggered.
|
|
||||||
/// </summary>
|
|
||||||
[RegisterComponent, AutoGenerateComponentPause]
|
|
||||||
[Access(typeof(TriggerSystem))]
|
|
||||||
public sealed partial class ShockOnTriggerComponent : Component
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// The force of an electric shock when the trigger is triggered.
|
|
||||||
/// </summary>
|
|
||||||
[DataField]
|
|
||||||
public int Damage = 5;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Duration of electric shock when the trigger is triggered.
|
|
||||||
/// </summary>
|
|
||||||
[DataField]
|
|
||||||
public TimeSpan Duration = TimeSpan.FromSeconds(2);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The minimum delay between repeating triggers.
|
|
||||||
/// </summary>
|
|
||||||
[DataField]
|
|
||||||
public TimeSpan Cooldown = TimeSpan.FromSeconds(4);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// When can the trigger run again?
|
|
||||||
/// </summary>
|
|
||||||
[DataField(customTypeSerializer: typeof(TimeOffsetSerializer))]
|
|
||||||
[AutoPausedField]
|
|
||||||
public TimeSpan NextTrigger = TimeSpan.Zero;
|
|
||||||
}
|
|
||||||
@@ -1,24 +0,0 @@
|
|||||||
using Content.Server.Explosion.EntitySystems;
|
|
||||||
using Robust.Shared.Prototypes;
|
|
||||||
|
|
||||||
namespace Content.Server.Explosion.Components;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Spawns a protoype when triggered.
|
|
||||||
/// </summary>
|
|
||||||
[RegisterComponent, Access(typeof(TriggerSystem))]
|
|
||||||
public sealed partial class SpawnOnTriggerComponent : Component
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// The prototype to spawn.
|
|
||||||
/// </summary>
|
|
||||||
[DataField(required: true)]
|
|
||||||
public EntProtoId Proto = string.Empty;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Use MapCoordinates for spawning?
|
|
||||||
/// Set to true if you don't want the new entity parented to the spawner.
|
|
||||||
/// </summary>
|
|
||||||
[DataField]
|
|
||||||
public bool mapCoords;
|
|
||||||
}
|
|
||||||
@@ -1,15 +0,0 @@
|
|||||||
using Content.Shared.DeviceLinking;
|
|
||||||
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype;
|
|
||||||
|
|
||||||
namespace Content.Server.Explosion.Components
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Sends a trigger when signal is received.
|
|
||||||
/// </summary>
|
|
||||||
[RegisterComponent]
|
|
||||||
public sealed partial class TimerStartOnSignalComponent : Component
|
|
||||||
{
|
|
||||||
[DataField("port", customTypeSerializer: typeof(PrototypeIdSerializer<SinkPortPrototype>))]
|
|
||||||
public string Port = "Timer";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
namespace Content.Server.Explosion.Components;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Triggers on click.
|
|
||||||
/// </summary>
|
|
||||||
[RegisterComponent]
|
|
||||||
public sealed partial class TriggerOnActivateComponent : Component { }
|
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user