Merge remote-tracking branch 'refs/remotes/wizards/master'
# Conflicts: # Content.Shared/MagicMirror/MagicMirrorComponent.cs # Resources/Prototypes/Catalog/Fills/Lockers/misc.yml # Resources/Prototypes/Entities/Stations/base.yml # Resources/Textures/Clothing/Head/Hats/beret_security.rsi/equipped-HELMET-hamster.png # Resources/Textures/Clothing/Head/Hats/beret_security.rsi/equipped-HELMET.png # Resources/Textures/Clothing/Head/Hats/beret_security.rsi/icon.png # Resources/Textures/Clothing/Head/Hats/beret_security.rsi/inhand-left.png # Resources/Textures/Clothing/Head/Hats/beret_security.rsi/inhand-right.png # Resources/Textures/Clothing/Head/Hats/beret_security.rsi/meta.json # Resources/Textures/Clothing/Head/Hoods/Bio/security.rsi/equipped-HELMET.png # Resources/Textures/Clothing/Head/Hoods/Bio/security.rsi/icon.png # Resources/Textures/Clothing/Head/Hoods/Bio/security.rsi/inhand-left.png # Resources/Textures/Clothing/Head/Hoods/Bio/security.rsi/inhand-right.png # Resources/Textures/Clothing/Head/Hoods/Bio/security.rsi/meta.json # Resources/Textures/Clothing/OuterClothing/Bio/security.rsi/equipped-OUTERCLOTHING.png # Resources/Textures/Clothing/OuterClothing/Bio/security.rsi/icon.png # Resources/Textures/Clothing/OuterClothing/Bio/security.rsi/inhand-left.png # Resources/Textures/Clothing/OuterClothing/Bio/security.rsi/inhand-right.png # Resources/Textures/Clothing/OuterClothing/Bio/security.rsi/meta.json # Resources/Textures/Clothing/OuterClothing/Coats/warden.rsi/equipped-OUTERCLOTHING.png # Resources/Textures/Clothing/OuterClothing/Coats/warden.rsi/icon.png # Resources/Textures/Clothing/OuterClothing/Coats/warden.rsi/inhand-left.png # Resources/Textures/Clothing/OuterClothing/Coats/warden.rsi/inhand-right.png # Resources/Textures/Clothing/OuterClothing/WinterCoats/coatwarden.rsi/meta.json # Resources/Textures/Clothing/Uniforms/Jumpskirt/hos.rsi/equipped-INNERCLOTHING.png # Resources/Textures/Clothing/Uniforms/Jumpskirt/hos.rsi/icon.png # Resources/Textures/Clothing/Uniforms/Jumpskirt/security.rsi/equipped-INNERCLOTHING.png # Resources/Textures/Clothing/Uniforms/Jumpskirt/security.rsi/icon.png # Resources/Textures/Clothing/Uniforms/Jumpskirt/warden.rsi/equipped-INNERCLOTHING.png # Resources/Textures/Clothing/Uniforms/Jumpskirt/warden.rsi/icon.png # Resources/Textures/Clothing/Uniforms/Jumpsuit/hos.rsi/equipped-INNERCLOTHING.png # Resources/Textures/Clothing/Uniforms/Jumpsuit/hos.rsi/icon.png # Resources/Textures/Clothing/Uniforms/Jumpsuit/security.rsi/equipped-INNERCLOTHING.png # Resources/Textures/Clothing/Uniforms/Jumpsuit/security.rsi/icon.png # Resources/Textures/Clothing/Uniforms/Jumpsuit/warden.rsi/equipped-INNERCLOTHING.png # Resources/Textures/Clothing/Uniforms/Jumpsuit/warden.rsi/icon.png # Resources/migration.yml
This commit is contained in:
commit
31b2d24e30
172 changed files with 17323 additions and 17369 deletions
4
.github/labeler.yml
vendored
4
.github/labeler.yml
vendored
|
|
@ -12,6 +12,10 @@
|
|||
- changed-files:
|
||||
- any-glob-to-any-file: '**/*.xaml*'
|
||||
|
||||
"Changes: Shaders":
|
||||
- changed-files:
|
||||
- any-glob-to-any-file: '**/*.swsl'
|
||||
|
||||
"No C#":
|
||||
- changed-files:
|
||||
# Equiv to any-glob-to-all as long as this has one matcher. If ALL changed files are not C# files, then apply label.
|
||||
|
|
|
|||
|
|
@ -30,7 +30,11 @@ namespace Content.Client.Administration.UI.Bwoink
|
|||
}
|
||||
};
|
||||
|
||||
OnOpen += () => Bwoink.PopulateList();
|
||||
OnOpen += () =>
|
||||
{
|
||||
Bwoink.ChannelSelector.StopFiltering();
|
||||
Bwoink.PopulateList();
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,154 +4,155 @@ using Content.Client.UserInterface.Controls;
|
|||
using Content.Client.Verbs.UI;
|
||||
using Content.Shared.Administration;
|
||||
using Robust.Client.AutoGenerated;
|
||||
using Robust.Client.GameObjects;
|
||||
using Robust.Client.Graphics;
|
||||
using Robust.Client.UserInterface;
|
||||
using Robust.Client.UserInterface.Controls;
|
||||
using Robust.Client.UserInterface.XAML;
|
||||
using Robust.Shared.Input;
|
||||
using Robust.Shared.Utility;
|
||||
|
||||
namespace Content.Client.Administration.UI.CustomControls
|
||||
namespace Content.Client.Administration.UI.CustomControls;
|
||||
|
||||
[GenerateTypedNameReferences]
|
||||
public sealed partial class PlayerListControl : BoxContainer
|
||||
{
|
||||
[GenerateTypedNameReferences]
|
||||
public sealed partial class PlayerListControl : BoxContainer
|
||||
private readonly AdminSystem _adminSystem;
|
||||
|
||||
private readonly IEntityManager _entManager;
|
||||
private readonly IUserInterfaceManager _uiManager;
|
||||
|
||||
private PlayerInfo? _selectedPlayer;
|
||||
|
||||
private List<PlayerInfo> _playerList = new();
|
||||
private readonly List<PlayerInfo> _sortedPlayerList = new();
|
||||
|
||||
public Comparison<PlayerInfo>? Comparison;
|
||||
public Func<PlayerInfo, string, string>? OverrideText;
|
||||
|
||||
public PlayerListControl()
|
||||
{
|
||||
private readonly AdminSystem _adminSystem;
|
||||
|
||||
private List<PlayerInfo> _playerList = new();
|
||||
private readonly List<PlayerInfo> _sortedPlayerList = new();
|
||||
|
||||
public event Action<PlayerInfo?>? OnSelectionChanged;
|
||||
public IReadOnlyList<PlayerInfo> PlayerInfo => _playerList;
|
||||
|
||||
public Func<PlayerInfo, string, string>? OverrideText;
|
||||
public Comparison<PlayerInfo>? Comparison;
|
||||
|
||||
private IEntityManager _entManager;
|
||||
private IUserInterfaceManager _uiManager;
|
||||
|
||||
private PlayerInfo? _selectedPlayer;
|
||||
|
||||
public PlayerListControl()
|
||||
{
|
||||
_entManager = IoCManager.Resolve<IEntityManager>();
|
||||
_uiManager = IoCManager.Resolve<IUserInterfaceManager>();
|
||||
_adminSystem = _entManager.System<AdminSystem>();
|
||||
RobustXamlLoader.Load(this);
|
||||
// Fill the Option data
|
||||
PlayerListContainer.ItemPressed += PlayerListItemPressed;
|
||||
PlayerListContainer.ItemKeyBindDown += PlayerListItemKeyBindDown;
|
||||
PlayerListContainer.GenerateItem += GenerateButton;
|
||||
PlayerListContainer.NoItemSelected += PlayerListNoItemSelected;
|
||||
PopulateList(_adminSystem.PlayerList);
|
||||
FilterLineEdit.OnTextChanged += _ => FilterList();
|
||||
_adminSystem.PlayerListChanged += PopulateList;
|
||||
BackgroundPanel.PanelOverride = new StyleBoxFlat {BackgroundColor = new Color(32, 32, 40)};
|
||||
}
|
||||
|
||||
private void PlayerListNoItemSelected()
|
||||
{
|
||||
_selectedPlayer = null;
|
||||
OnSelectionChanged?.Invoke(null);
|
||||
}
|
||||
|
||||
private void PlayerListItemPressed(BaseButton.ButtonEventArgs? args, ListData? data)
|
||||
{
|
||||
if (args == null || data is not PlayerListData {Info: var selectedPlayer})
|
||||
return;
|
||||
|
||||
if (selectedPlayer == _selectedPlayer)
|
||||
return;
|
||||
|
||||
if (args.Event.Function != EngineKeyFunctions.UIClick)
|
||||
return;
|
||||
|
||||
OnSelectionChanged?.Invoke(selectedPlayer);
|
||||
_selectedPlayer = selectedPlayer;
|
||||
|
||||
// update label text. Only required if there is some override (e.g. unread bwoink count).
|
||||
if (OverrideText != null && args.Button.Children.FirstOrDefault()?.Children?.FirstOrDefault() is Label label)
|
||||
label.Text = GetText(selectedPlayer);
|
||||
}
|
||||
|
||||
private void PlayerListItemKeyBindDown(GUIBoundKeyEventArgs? args, ListData? data)
|
||||
{
|
||||
if (args == null || data is not PlayerListData { Info: var selectedPlayer })
|
||||
return;
|
||||
|
||||
if (args.Function != EngineKeyFunctions.UIRightClick || selectedPlayer.NetEntity == null)
|
||||
return;
|
||||
|
||||
_uiManager.GetUIController<VerbMenuUIController>().OpenVerbMenu(selectedPlayer.NetEntity.Value, true);
|
||||
args.Handle();
|
||||
}
|
||||
|
||||
public void StopFiltering()
|
||||
{
|
||||
FilterLineEdit.Text = string.Empty;
|
||||
}
|
||||
|
||||
private void FilterList()
|
||||
{
|
||||
_sortedPlayerList.Clear();
|
||||
foreach (var info in _playerList)
|
||||
{
|
||||
var displayName = $"{info.CharacterName} ({info.Username})";
|
||||
if (info.IdentityName != info.CharacterName)
|
||||
displayName += $" [{info.IdentityName}]";
|
||||
if (!string.IsNullOrEmpty(FilterLineEdit.Text)
|
||||
&& !displayName.ToLowerInvariant().Contains(FilterLineEdit.Text.Trim().ToLowerInvariant()))
|
||||
continue;
|
||||
_sortedPlayerList.Add(info);
|
||||
}
|
||||
|
||||
if (Comparison != null)
|
||||
_sortedPlayerList.Sort((a, b) => Comparison(a, b));
|
||||
|
||||
PlayerListContainer.PopulateList(_sortedPlayerList.Select(info => new PlayerListData(info)).ToList());
|
||||
if (_selectedPlayer != null)
|
||||
PlayerListContainer.Select(new PlayerListData(_selectedPlayer));
|
||||
}
|
||||
|
||||
public void PopulateList(IReadOnlyList<PlayerInfo>? players = null)
|
||||
{
|
||||
players ??= _adminSystem.PlayerList;
|
||||
|
||||
_playerList = players.ToList();
|
||||
if (_selectedPlayer != null && !_playerList.Contains(_selectedPlayer))
|
||||
_selectedPlayer = null;
|
||||
|
||||
FilterList();
|
||||
}
|
||||
|
||||
private string GetText(PlayerInfo info)
|
||||
{
|
||||
var text = $"{info.CharacterName} ({info.Username})";
|
||||
if (OverrideText != null)
|
||||
text = OverrideText.Invoke(info, text);
|
||||
return text;
|
||||
}
|
||||
|
||||
private void GenerateButton(ListData data, ListContainerButton button)
|
||||
{
|
||||
if (data is not PlayerListData { Info: var info })
|
||||
return;
|
||||
|
||||
button.AddChild(new BoxContainer
|
||||
{
|
||||
Orientation = LayoutOrientation.Vertical,
|
||||
Children =
|
||||
{
|
||||
new Label
|
||||
{
|
||||
ClipText = true,
|
||||
Text = GetText(info)
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
button.AddStyleClass(ListContainer.StyleClassListContainerButton);
|
||||
}
|
||||
_entManager = IoCManager.Resolve<IEntityManager>();
|
||||
_uiManager = IoCManager.Resolve<IUserInterfaceManager>();
|
||||
_adminSystem = _entManager.System<AdminSystem>();
|
||||
RobustXamlLoader.Load(this);
|
||||
// Fill the Option data
|
||||
PlayerListContainer.ItemPressed += PlayerListItemPressed;
|
||||
PlayerListContainer.ItemKeyBindDown += PlayerListItemKeyBindDown;
|
||||
PlayerListContainer.GenerateItem += GenerateButton;
|
||||
PlayerListContainer.NoItemSelected += PlayerListNoItemSelected;
|
||||
PopulateList(_adminSystem.PlayerList);
|
||||
FilterLineEdit.OnTextChanged += _ => FilterList();
|
||||
_adminSystem.PlayerListChanged += PopulateList;
|
||||
BackgroundPanel.PanelOverride = new StyleBoxFlat { BackgroundColor = new Color(32, 32, 40) };
|
||||
}
|
||||
|
||||
public record PlayerListData(PlayerInfo Info) : ListData;
|
||||
public IReadOnlyList<PlayerInfo> PlayerInfo => _playerList;
|
||||
|
||||
public event Action<PlayerInfo?>? OnSelectionChanged;
|
||||
|
||||
private void PlayerListNoItemSelected()
|
||||
{
|
||||
_selectedPlayer = null;
|
||||
OnSelectionChanged?.Invoke(null);
|
||||
}
|
||||
|
||||
private void PlayerListItemPressed(BaseButton.ButtonEventArgs? args, ListData? data)
|
||||
{
|
||||
if (args == null || data is not PlayerListData { Info: var selectedPlayer })
|
||||
return;
|
||||
|
||||
if (selectedPlayer == _selectedPlayer)
|
||||
return;
|
||||
|
||||
if (args.Event.Function != EngineKeyFunctions.UIClick)
|
||||
return;
|
||||
|
||||
OnSelectionChanged?.Invoke(selectedPlayer);
|
||||
_selectedPlayer = selectedPlayer;
|
||||
|
||||
// update label text. Only required if there is some override (e.g. unread bwoink count).
|
||||
if (OverrideText != null && args.Button.Children.FirstOrDefault()?.Children?.FirstOrDefault() is Label label)
|
||||
label.Text = GetText(selectedPlayer);
|
||||
}
|
||||
|
||||
private void PlayerListItemKeyBindDown(GUIBoundKeyEventArgs? args, ListData? data)
|
||||
{
|
||||
if (args == null || data is not PlayerListData { Info: var selectedPlayer })
|
||||
return;
|
||||
|
||||
if (args.Function != EngineKeyFunctions.UIRightClick || selectedPlayer.NetEntity == null)
|
||||
return;
|
||||
|
||||
_uiManager.GetUIController<VerbMenuUIController>().OpenVerbMenu(selectedPlayer.NetEntity.Value, true);
|
||||
args.Handle();
|
||||
}
|
||||
|
||||
public void StopFiltering()
|
||||
{
|
||||
FilterLineEdit.Text = string.Empty;
|
||||
}
|
||||
|
||||
private void FilterList()
|
||||
{
|
||||
_sortedPlayerList.Clear();
|
||||
foreach (var info in _playerList)
|
||||
{
|
||||
var displayName = $"{info.CharacterName} ({info.Username})";
|
||||
if (info.IdentityName != info.CharacterName)
|
||||
displayName += $" [{info.IdentityName}]";
|
||||
if (!string.IsNullOrEmpty(FilterLineEdit.Text)
|
||||
&& !displayName.ToLowerInvariant().Contains(FilterLineEdit.Text.Trim().ToLowerInvariant()))
|
||||
continue;
|
||||
_sortedPlayerList.Add(info);
|
||||
}
|
||||
|
||||
if (Comparison != null)
|
||||
_sortedPlayerList.Sort((a, b) => Comparison(a, b));
|
||||
|
||||
// Ensure pinned players are always at the top
|
||||
_sortedPlayerList.Sort((a, b) => a.IsPinned != b.IsPinned && a.IsPinned ? -1 : 1);
|
||||
|
||||
PlayerListContainer.PopulateList(_sortedPlayerList.Select(info => new PlayerListData(info)).ToList());
|
||||
if (_selectedPlayer != null)
|
||||
PlayerListContainer.Select(new PlayerListData(_selectedPlayer));
|
||||
}
|
||||
|
||||
public void PopulateList(IReadOnlyList<PlayerInfo>? players = null)
|
||||
{
|
||||
players ??= _adminSystem.PlayerList;
|
||||
|
||||
_playerList = players.ToList();
|
||||
if (_selectedPlayer != null && !_playerList.Contains(_selectedPlayer))
|
||||
_selectedPlayer = null;
|
||||
|
||||
FilterList();
|
||||
}
|
||||
|
||||
|
||||
private string GetText(PlayerInfo info)
|
||||
{
|
||||
var text = $"{info.CharacterName} ({info.Username})";
|
||||
if (OverrideText != null)
|
||||
text = OverrideText.Invoke(info, text);
|
||||
return text;
|
||||
}
|
||||
|
||||
private void GenerateButton(ListData data, ListContainerButton button)
|
||||
{
|
||||
if (data is not PlayerListData { Info: var info })
|
||||
return;
|
||||
|
||||
var entry = new PlayerListEntry();
|
||||
entry.Setup(info, OverrideText);
|
||||
entry.OnPinStatusChanged += _ =>
|
||||
{
|
||||
FilterList();
|
||||
};
|
||||
|
||||
button.AddChild(entry);
|
||||
button.AddStyleClass(ListContainer.StyleClassListContainerButton);
|
||||
}
|
||||
}
|
||||
|
||||
public record PlayerListData(PlayerInfo Info) : ListData;
|
||||
|
|
|
|||
|
|
@ -0,0 +1,6 @@
|
|||
<BoxContainer xmlns="https://spacestation14.io"
|
||||
Orientation="Horizontal" HorizontalExpand="true">
|
||||
<Label Name="PlayerEntryLabel" Text="" ClipText="True" HorizontalExpand="True" />
|
||||
<TextureButton Name="PlayerEntryPinButton"
|
||||
HorizontalAlignment="Right" />
|
||||
</BoxContainer>
|
||||
|
|
@ -0,0 +1,58 @@
|
|||
using Content.Client.Stylesheets;
|
||||
using Content.Shared.Administration;
|
||||
using Robust.Client.AutoGenerated;
|
||||
using Robust.Client.GameObjects;
|
||||
using Robust.Client.UserInterface.Controls;
|
||||
using Robust.Client.UserInterface.XAML;
|
||||
using Robust.Shared.Utility;
|
||||
|
||||
namespace Content.Client.Administration.UI.CustomControls;
|
||||
|
||||
[GenerateTypedNameReferences]
|
||||
public sealed partial class PlayerListEntry : BoxContainer
|
||||
{
|
||||
public PlayerListEntry()
|
||||
{
|
||||
RobustXamlLoader.Load(this);
|
||||
}
|
||||
|
||||
public event Action<PlayerInfo>? OnPinStatusChanged;
|
||||
|
||||
public void Setup(PlayerInfo info, Func<PlayerInfo, string, string>? overrideText)
|
||||
{
|
||||
Update(info, overrideText);
|
||||
PlayerEntryPinButton.OnPressed += HandlePinButtonPressed(info);
|
||||
}
|
||||
|
||||
private Action<BaseButton.ButtonEventArgs> HandlePinButtonPressed(PlayerInfo info)
|
||||
{
|
||||
return args =>
|
||||
{
|
||||
info.IsPinned = !info.IsPinned;
|
||||
UpdatePinButtonTexture(info.IsPinned);
|
||||
OnPinStatusChanged?.Invoke(info);
|
||||
};
|
||||
}
|
||||
|
||||
private void Update(PlayerInfo info, Func<PlayerInfo, string, string>? overrideText)
|
||||
{
|
||||
PlayerEntryLabel.Text = overrideText?.Invoke(info, $"{info.CharacterName} ({info.Username})") ??
|
||||
$"{info.CharacterName} ({info.Username})";
|
||||
|
||||
UpdatePinButtonTexture(info.IsPinned);
|
||||
}
|
||||
|
||||
private void UpdatePinButtonTexture(bool isPinned)
|
||||
{
|
||||
if (isPinned)
|
||||
{
|
||||
PlayerEntryPinButton?.RemoveStyleClass(StyleNano.StyleClassPinButtonUnpinned);
|
||||
PlayerEntryPinButton?.AddStyleClass(StyleNano.StyleClassPinButtonPinned);
|
||||
}
|
||||
else
|
||||
{
|
||||
PlayerEntryPinButton?.RemoveStyleClass(StyleNano.StyleClassPinButtonPinned);
|
||||
PlayerEntryPinButton?.AddStyleClass(StyleNano.StyleClassPinButtonUnpinned);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -22,21 +22,29 @@ public sealed class LatheSystem : SharedLatheSystem
|
|||
if (args.Sprite == null)
|
||||
return;
|
||||
|
||||
// Lathe specific stuff
|
||||
if (_appearance.TryGetData<bool>(uid, LatheVisuals.IsRunning, out var isRunning, args.Component))
|
||||
{
|
||||
if (args.Sprite.LayerMapTryGet(LatheVisualLayers.IsRunning, out var runningLayer) &&
|
||||
component.RunningState != null &&
|
||||
component.IdleState != null)
|
||||
{
|
||||
var state = isRunning ? component.RunningState : component.IdleState;
|
||||
args.Sprite.LayerSetState(runningLayer, state);
|
||||
}
|
||||
}
|
||||
|
||||
if (_appearance.TryGetData<bool>(uid, PowerDeviceVisuals.Powered, out var powered, args.Component) &&
|
||||
args.Sprite.LayerMapTryGet(PowerDeviceVisualLayers.Powered, out var powerLayer))
|
||||
{
|
||||
args.Sprite.LayerSetVisible(powerLayer, powered);
|
||||
}
|
||||
|
||||
// Lathe specific stuff
|
||||
if (_appearance.TryGetData<bool>(uid, LatheVisuals.IsRunning, out var isRunning, args.Component) &&
|
||||
args.Sprite.LayerMapTryGet(LatheVisualLayers.IsRunning, out var runningLayer) &&
|
||||
component.RunningState != null &&
|
||||
component.IdleState != null)
|
||||
{
|
||||
var state = isRunning ? component.RunningState : component.IdleState;
|
||||
args.Sprite.LayerSetAnimationTime(runningLayer, 0f);
|
||||
args.Sprite.LayerSetState(runningLayer, state);
|
||||
if (component.UnlitIdleState != null &&
|
||||
component.UnlitRunningState != null)
|
||||
{
|
||||
var state = isRunning ? component.UnlitRunningState : component.UnlitIdleState;
|
||||
args.Sprite.LayerSetState(powerLayer, state);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
35
Content.Client/Paper/EnvelopeSystem.cs
Normal file
35
Content.Client/Paper/EnvelopeSystem.cs
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
using Content.Shared.Paper;
|
||||
using Robust.Client.GameObjects;
|
||||
|
||||
namespace Content.Client.Paper;
|
||||
|
||||
public sealed class EnvelopeSystem : VisualizerSystem<EnvelopeComponent>
|
||||
{
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
SubscribeLocalEvent<EnvelopeComponent, AfterAutoHandleStateEvent>(OnAfterAutoHandleState);
|
||||
}
|
||||
|
||||
private void OnAfterAutoHandleState(Entity<EnvelopeComponent> ent, ref AfterAutoHandleStateEvent args)
|
||||
{
|
||||
UpdateAppearance(ent);
|
||||
}
|
||||
|
||||
private void UpdateAppearance(Entity<EnvelopeComponent> ent, SpriteComponent? sprite = null)
|
||||
{
|
||||
if (!Resolve(ent.Owner, ref sprite))
|
||||
return;
|
||||
|
||||
sprite.LayerSetVisible(EnvelopeVisualLayers.Open, ent.Comp.State == EnvelopeComponent.EnvelopeState.Open);
|
||||
sprite.LayerSetVisible(EnvelopeVisualLayers.Sealed, ent.Comp.State == EnvelopeComponent.EnvelopeState.Sealed);
|
||||
sprite.LayerSetVisible(EnvelopeVisualLayers.Torn, ent.Comp.State == EnvelopeComponent.EnvelopeState.Torn);
|
||||
}
|
||||
|
||||
public enum EnvelopeVisualLayers : byte
|
||||
{
|
||||
Open,
|
||||
Sealed,
|
||||
Torn
|
||||
}
|
||||
}
|
||||
|
|
@ -3,6 +3,7 @@ using Content.Client.Message;
|
|||
using Content.Client.Resources;
|
||||
using Content.Client.UserInterface.Controls;
|
||||
using Content.Shared.Singularity.Components;
|
||||
using Content.Shared.Access.Systems;
|
||||
using Robust.Client.Animations;
|
||||
using Robust.Client.AutoGenerated;
|
||||
using Robust.Client.Graphics;
|
||||
|
|
@ -13,6 +14,7 @@ using Robust.Client.UserInterface.XAML;
|
|||
using Robust.Shared.Noise;
|
||||
using Robust.Shared.Prototypes;
|
||||
using Robust.Shared.Timing;
|
||||
using Robust.Client.Player;
|
||||
|
||||
namespace Content.Client.ParticleAccelerator.UI;
|
||||
|
||||
|
|
@ -21,6 +23,11 @@ public sealed partial class ParticleAcceleratorControlMenu : FancyWindow
|
|||
{
|
||||
[Dependency] private readonly IResourceCache _cache = default!;
|
||||
|
||||
[Dependency] private readonly IEntityManager _entityManager = default!;
|
||||
[Dependency] private readonly IPlayerManager _player = default!;
|
||||
|
||||
private readonly AccessReaderSystem _accessReader;
|
||||
|
||||
private readonly FastNoiseLite _drawNoiseGenerator;
|
||||
|
||||
private readonly Animation _alarmControlAnimation;
|
||||
|
|
@ -44,6 +51,7 @@ public sealed partial class ParticleAcceleratorControlMenu : FancyWindow
|
|||
RobustXamlLoader.Load(this);
|
||||
IoCManager.InjectDependencies(this);
|
||||
|
||||
_accessReader = _entityManager.System<AccessReaderSystem>();
|
||||
_drawNoiseGenerator = new();
|
||||
_drawNoiseGenerator.SetFractalType(FastNoiseLite.FractalType.FBm);
|
||||
_drawNoiseGenerator.SetFrequency(0.5f);
|
||||
|
|
@ -150,7 +158,7 @@ public sealed partial class ParticleAcceleratorControlMenu : FancyWindow
|
|||
|
||||
private bool StrengthSpinBoxValid(int n)
|
||||
{
|
||||
return n >= 0 && n <= _maxStrength ;
|
||||
return n >= 0 && n <= _maxStrength;
|
||||
}
|
||||
|
||||
protected override DragMode GetDragModeFor(Vector2 relativeMousePos)
|
||||
|
|
@ -201,13 +209,16 @@ public sealed partial class ParticleAcceleratorControlMenu : FancyWindow
|
|||
|
||||
private void UpdateUI(bool assembled, bool blocked, bool enabled, bool powerBlock)
|
||||
{
|
||||
bool hasAccess = _player.LocalSession?.AttachedEntity is {} player
|
||||
&& _accessReader.IsAllowed(player, _entity);
|
||||
|
||||
OnButton.Pressed = enabled;
|
||||
OffButton.Pressed = !enabled;
|
||||
|
||||
var cantUse = !assembled || blocked || powerBlock;
|
||||
var cantUse = !assembled || blocked || powerBlock || !hasAccess;
|
||||
OnButton.Disabled = cantUse;
|
||||
OffButton.Disabled = cantUse;
|
||||
ScanButton.Disabled = blocked;
|
||||
ScanButton.Disabled = blocked || !hasAccess;
|
||||
|
||||
var cantChangeLevel = !assembled || blocked || !enabled || cantUse;
|
||||
StateSpinBox.SetButtonDisabled(cantChangeLevel);
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
using Content.Client.Power.Components;
|
||||
using Content.Client.Power.Components;
|
||||
using Content.Shared.Power.Components;
|
||||
using Content.Shared.Power.EntitySystems;
|
||||
using Content.Shared.Examine;
|
||||
using Robust.Shared.GameStates;
|
||||
|
||||
namespace Content.Client.Power.EntitySystems;
|
||||
|
|
@ -10,9 +11,15 @@ public sealed class PowerReceiverSystem : SharedPowerReceiverSystem
|
|||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
SubscribeLocalEvent<ApcPowerReceiverComponent, ExaminedEvent>(OnExamined);
|
||||
SubscribeLocalEvent<ApcPowerReceiverComponent, ComponentHandleState>(OnHandleState);
|
||||
}
|
||||
|
||||
private void OnExamined(Entity<ApcPowerReceiverComponent> ent, ref ExaminedEvent args)
|
||||
{
|
||||
args.PushMarkup(GetExamineText(ent.Comp.Powered));
|
||||
}
|
||||
|
||||
private void OnHandleState(EntityUid uid, ApcPowerReceiverComponent component, ref ComponentHandleState args)
|
||||
{
|
||||
if (args.Current is not ApcPowerReceiverComponentState state)
|
||||
|
|
|
|||
|
|
@ -102,12 +102,21 @@ public sealed class SalvageExpeditionConsoleBoundUserInterface : BoundUserInterf
|
|||
|
||||
offering.AddContent(new Label
|
||||
{
|
||||
Text = faction,
|
||||
Text = string.IsNullOrWhiteSpace(Loc.GetString(_protoManager.Index<SalvageFactionPrototype>(faction).Description))
|
||||
? LogAndReturnDefaultFactionDescription(faction)
|
||||
: Loc.GetString(_protoManager.Index<SalvageFactionPrototype>(faction).Description),
|
||||
FontColorOverride = StyleNano.NanoGold,
|
||||
HorizontalAlignment = Control.HAlignment.Left,
|
||||
Margin = new Thickness(0f, 0f, 0f, 5f),
|
||||
});
|
||||
|
||||
string LogAndReturnDefaultFactionDescription(string faction)
|
||||
{
|
||||
Logger.Error($"Description is null or white space for SalvageFactionPrototype: {faction}");
|
||||
return Loc.GetString(_protoManager.Index<SalvageFactionPrototype>(faction).ID);
|
||||
}
|
||||
|
||||
|
||||
// Duration
|
||||
offering.AddContent(new Label
|
||||
{
|
||||
|
|
@ -132,12 +141,20 @@ public sealed class SalvageExpeditionConsoleBoundUserInterface : BoundUserInterf
|
|||
|
||||
offering.AddContent(new Label
|
||||
{
|
||||
Text = Loc.GetString(_protoManager.Index<SalvageBiomeModPrototype>(biome).ID),
|
||||
Text = string.IsNullOrWhiteSpace(Loc.GetString(_protoManager.Index<SalvageBiomeModPrototype>(biome).Description))
|
||||
? LogAndReturnDefaultBiomDescription(biome)
|
||||
: Loc.GetString(_protoManager.Index<SalvageBiomeModPrototype>(biome).Description),
|
||||
FontColorOverride = StyleNano.NanoGold,
|
||||
HorizontalAlignment = Control.HAlignment.Left,
|
||||
Margin = new Thickness(0f, 0f, 0f, 5f),
|
||||
});
|
||||
|
||||
string LogAndReturnDefaultBiomDescription(string biome)
|
||||
{
|
||||
Logger.Error($"Description is null or white space for SalvageBiomeModPrototype: {biome}");
|
||||
return Loc.GetString(_protoManager.Index<SalvageBiomeModPrototype>(biome).ID);
|
||||
}
|
||||
|
||||
// Modifiers
|
||||
offering.AddContent(new Label
|
||||
{
|
||||
|
|
|
|||
|
|
@ -100,6 +100,8 @@ namespace Content.Client.Singularity
|
|||
/// </summary>
|
||||
private void OnProjectFromScreenToMap(ref PixelToMapEvent args)
|
||||
{ // Mostly copypasta from the singularity shader.
|
||||
if (args.Viewport.Eye == null)
|
||||
return;
|
||||
var maxDistance = MaxDistance * EyeManager.PixelsPerMeter;
|
||||
var finalCoords = args.VisiblePosition;
|
||||
|
||||
|
|
@ -112,10 +114,11 @@ namespace Content.Client.Singularity
|
|||
// and in local space 'Y' is measured in pixels from the top of the viewport.
|
||||
// As a minor optimization the locations of the singularities are transformed into fragment space in BeforeDraw so the shader doesn't need to.
|
||||
// We need to undo that here or this will transform the cursor position as if the singularities were mirrored vertically relative to the center of the viewport.
|
||||
|
||||
var localPosition = _positions[i];
|
||||
localPosition.Y = args.Viewport.Size.Y - localPosition.Y;
|
||||
var delta = args.VisiblePosition - localPosition;
|
||||
var distance = (delta / args.Viewport.RenderScale).Length();
|
||||
var distance = (delta / (args.Viewport.RenderScale * args.Viewport.Eye.Scale)).Length();
|
||||
|
||||
var deformation = _intensities[i] / MathF.Pow(distance, _falloffPowers[i]);
|
||||
|
||||
|
|
|
|||
|
|
@ -151,6 +151,11 @@ namespace Content.Client.Stylesheets
|
|||
|
||||
public static readonly Color ChatBackgroundColor = Color.FromHex("#25252ADD");
|
||||
|
||||
//Bwoink
|
||||
public const string StyleClassPinButtonPinned = "pinButtonPinned";
|
||||
public const string StyleClassPinButtonUnpinned = "pinButtonUnpinned";
|
||||
|
||||
|
||||
public override Stylesheet Stylesheet { get; }
|
||||
|
||||
public StyleNano(IResourceCache resCache) : base(resCache)
|
||||
|
|
@ -1608,6 +1613,21 @@ namespace Content.Client.Stylesheets
|
|||
{
|
||||
BackgroundColor = FancyTreeSelectedRowColor,
|
||||
}),
|
||||
// Pinned button style
|
||||
new StyleRule(
|
||||
new SelectorElement(typeof(TextureButton), new[] { StyleClassPinButtonPinned }, null, null),
|
||||
new[]
|
||||
{
|
||||
new StyleProperty(TextureButton.StylePropertyTexture, resCache.GetTexture("/Textures/Interface/Bwoink/pinned.png"))
|
||||
}),
|
||||
|
||||
// Unpinned button style
|
||||
new StyleRule(
|
||||
new SelectorElement(typeof(TextureButton), new[] { StyleClassPinButtonUnpinned }, null, null),
|
||||
new[]
|
||||
{
|
||||
new StyleProperty(TextureButton.StylePropertyTexture, resCache.GetTexture("/Textures/Interface/Bwoink/un_pinned.png"))
|
||||
})
|
||||
}).ToList());
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -45,6 +45,10 @@ public sealed class NPCTest
|
|||
var count = counts.GetOrNew(compound.ID);
|
||||
count++;
|
||||
|
||||
// Compound tasks marked with AllowRecursion are only evaluated once
|
||||
if (counts.ContainsKey(compound.ID) && compound.AllowRecursion)
|
||||
continue;
|
||||
|
||||
Assert.That(count, Is.LessThan(50));
|
||||
counts[compound.ID] = count;
|
||||
Count(protoManager.Index<HTNCompoundPrototype>(compoundTask.Task), counts, htnSystem, protoManager);
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@ public sealed partial class LogWireAction : ComponentWireAction<AccessReaderComp
|
|||
return comp.LoggingDisabled ? StatusLightState.Off : StatusLightState.On;
|
||||
}
|
||||
|
||||
public override object StatusKey => AccessWireActionKey.Status;
|
||||
public override object StatusKey => LogWireActionKey.Status;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -361,9 +361,9 @@ public sealed partial class AdminVerbSystem
|
|||
Icon = new SpriteSpecifier.Rsi(new ("/Textures/Mobs/Species/Human/organs.rsi"), "stomach"),
|
||||
Act = () =>
|
||||
{
|
||||
foreach (var (component, _) in _bodySystem.GetBodyOrganComponents<StomachComponent>(args.Target, body))
|
||||
foreach (var entity in _bodySystem.GetBodyOrganEntityComps<StomachComponent>((args.Target, body)))
|
||||
{
|
||||
QueueDel(component.Owner);
|
||||
QueueDel(entity.Owner);
|
||||
}
|
||||
|
||||
_popupSystem.PopupEntity(Loc.GetString("admin-smite-stomach-removal-self"), args.Target,
|
||||
|
|
@ -381,9 +381,9 @@ public sealed partial class AdminVerbSystem
|
|||
Icon = new SpriteSpecifier.Rsi(new ("/Textures/Mobs/Species/Human/organs.rsi"), "lung-r"),
|
||||
Act = () =>
|
||||
{
|
||||
foreach (var (component, _) in _bodySystem.GetBodyOrganComponents<LungComponent>(args.Target, body))
|
||||
foreach (var entity in _bodySystem.GetBodyOrganEntityComps<LungComponent>((args.Target, body)))
|
||||
{
|
||||
QueueDel(component.Owner);
|
||||
QueueDel(entity.Owner);
|
||||
}
|
||||
|
||||
_popupSystem.PopupEntity(Loc.GetString("admin-smite-lung-removal-self"), args.Target,
|
||||
|
|
|
|||
|
|
@ -7,11 +7,13 @@ using System.Text.RegularExpressions;
|
|||
using System.Threading.Tasks;
|
||||
using Content.Server.Administration.Managers;
|
||||
using Content.Server.Afk;
|
||||
using Content.Server.Database;
|
||||
using Content.Server.Discord;
|
||||
using Content.Server.GameTicking;
|
||||
using Content.Server.Players.RateLimiting;
|
||||
using Content.Shared.Administration;
|
||||
using Content.Shared.CCVar;
|
||||
using Content.Shared.GameTicking;
|
||||
using Content.Shared.Mind;
|
||||
using JetBrains.Annotations;
|
||||
using Robust.Server.Player;
|
||||
|
|
@ -39,6 +41,7 @@ namespace Content.Server.Administration.Systems
|
|||
[Dependency] private readonly GameTicker _gameTicker = default!;
|
||||
[Dependency] private readonly SharedMindSystem _minds = default!;
|
||||
[Dependency] private readonly IAfkManager _afkManager = default!;
|
||||
[Dependency] private readonly IServerDbManager _dbManager = default!;
|
||||
[Dependency] private readonly PlayerRateLimitManager _rateLimit = default!;
|
||||
private ISharedSponsorsManager? _sponsorsManager; // Sunrise-Sponsors
|
||||
|
||||
|
|
@ -52,7 +55,11 @@ namespace Content.Server.Administration.Systems
|
|||
private string _footerIconUrl = string.Empty;
|
||||
private string _avatarUrl = string.Empty;
|
||||
private string _serverName = string.Empty;
|
||||
private readonly Dictionary<NetUserId, (string? id, string username, string description, string? characterName, GameRunLevel lastRunLevel)> _relayMessages = new();
|
||||
|
||||
private readonly
|
||||
Dictionary<NetUserId, (string? id, string username, string description, string? characterName, GameRunLevel
|
||||
lastRunLevel)> _relayMessages = new();
|
||||
|
||||
private Dictionary<NetUserId, string> _oldMessageIds = new();
|
||||
private readonly Dictionary<NetUserId, Queue<string>> _messageQueues = new();
|
||||
private readonly HashSet<NetUserId> _processingChannels = new();
|
||||
|
|
@ -71,6 +78,7 @@ namespace Content.Server.Administration.Systems
|
|||
private const string TooLongText = "... **(too long)**";
|
||||
|
||||
private int _maxAdditionalChars;
|
||||
private readonly Dictionary<NetUserId, DateTime> _activeConversations = new();
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
|
|
@ -81,13 +89,22 @@ namespace Content.Server.Administration.Systems
|
|||
Subs.CVar(_config, CVars.GameHostName, OnServerNameChanged, true);
|
||||
Subs.CVar(_config, CCVars.AdminAhelpOverrideClientName, OnOverrideChanged, true);
|
||||
_sawmill = IoCManager.Resolve<ILogManager>().GetSawmill("AHELP");
|
||||
_maxAdditionalChars = GenerateAHelpMessage("", "", true, _gameTicker.RoundDuration().ToString("hh\\:mm\\:ss"), _gameTicker.RunLevel, playedSound: false).Length;
|
||||
var defaultParams = new AHelpMessageParams(
|
||||
string.Empty,
|
||||
string.Empty,
|
||||
true,
|
||||
_gameTicker.RoundDuration().ToString("hh\\:mm\\:ss"),
|
||||
_gameTicker.RunLevel,
|
||||
playedSound: false
|
||||
);
|
||||
_maxAdditionalChars = GenerateAHelpMessage(defaultParams).Length;
|
||||
_playerManager.PlayerStatusChanged += OnPlayerStatusChanged;
|
||||
|
||||
SubscribeLocalEvent<GameRunLevelChangedEvent>(OnGameRunLevelChanged);
|
||||
SubscribeNetworkEvent<BwoinkClientTypingUpdated>(OnClientTypingUpdated);
|
||||
SubscribeLocalEvent<RoundRestartCleanupEvent>(_ => _activeConversations.Clear());
|
||||
|
||||
_rateLimit.Register(
|
||||
_rateLimit.Register(
|
||||
RateLimitKey,
|
||||
new RateLimitRegistration
|
||||
{
|
||||
|
|
@ -111,14 +128,129 @@ namespace Content.Server.Administration.Systems
|
|||
_overrideClientName = obj;
|
||||
}
|
||||
|
||||
private void OnPlayerStatusChanged(object? sender, SessionStatusEventArgs e)
|
||||
private async void OnPlayerStatusChanged(object? sender, SessionStatusEventArgs e)
|
||||
{
|
||||
if (e.NewStatus == SessionStatus.Disconnected)
|
||||
{
|
||||
if (_activeConversations.TryGetValue(e.Session.UserId, out var lastMessageTime))
|
||||
{
|
||||
var timeSinceLastMessage = DateTime.Now - lastMessageTime;
|
||||
if (timeSinceLastMessage > TimeSpan.FromMinutes(5))
|
||||
{
|
||||
_activeConversations.Remove(e.Session.UserId);
|
||||
return; // Do not send disconnect message if timeout exceeded
|
||||
}
|
||||
}
|
||||
|
||||
// Check if the user has been banned
|
||||
var ban = await _dbManager.GetServerBanAsync(null, e.Session.UserId, null);
|
||||
if (ban != null)
|
||||
{
|
||||
var banMessage = Loc.GetString("bwoink-system-player-banned", ("banReason", ban.Reason));
|
||||
NotifyAdmins(e.Session, banMessage, PlayerStatusType.Banned);
|
||||
_activeConversations.Remove(e.Session.UserId);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Notify all admins if a player disconnects or reconnects
|
||||
var message = e.NewStatus switch
|
||||
{
|
||||
SessionStatus.Connected => Loc.GetString("bwoink-system-player-reconnecting"),
|
||||
SessionStatus.Disconnected => Loc.GetString("bwoink-system-player-disconnecting"),
|
||||
_ => null
|
||||
};
|
||||
|
||||
if (message != null)
|
||||
{
|
||||
var statusType = e.NewStatus == SessionStatus.Connected
|
||||
? PlayerStatusType.Connected
|
||||
: PlayerStatusType.Disconnected;
|
||||
NotifyAdmins(e.Session, message, statusType);
|
||||
}
|
||||
|
||||
if (e.NewStatus != SessionStatus.InGame)
|
||||
return;
|
||||
|
||||
RaiseNetworkEvent(new BwoinkDiscordRelayUpdated(!string.IsNullOrWhiteSpace(_webhookUrl)), e.Session);
|
||||
}
|
||||
|
||||
private void NotifyAdmins(ICommonSession session, string message, PlayerStatusType statusType)
|
||||
{
|
||||
if (!_activeConversations.ContainsKey(session.UserId))
|
||||
{
|
||||
// If the user is not part of an active conversation, do not notify admins.
|
||||
return;
|
||||
}
|
||||
|
||||
// Get the current timestamp
|
||||
var timestamp = DateTime.Now.ToString("HH:mm:ss");
|
||||
var roundTime = _gameTicker.RoundDuration().ToString("hh\\:mm\\:ss");
|
||||
|
||||
// Determine the icon based on the status type
|
||||
string icon = statusType switch
|
||||
{
|
||||
PlayerStatusType.Connected => ":green_circle:",
|
||||
PlayerStatusType.Disconnected => ":red_circle:",
|
||||
PlayerStatusType.Banned => ":no_entry:",
|
||||
_ => ":question:"
|
||||
};
|
||||
|
||||
// Create the message parameters for Discord
|
||||
var messageParams = new AHelpMessageParams(
|
||||
session.Name,
|
||||
message,
|
||||
true,
|
||||
roundTime,
|
||||
_gameTicker.RunLevel,
|
||||
playedSound: true,
|
||||
icon: icon
|
||||
);
|
||||
|
||||
// Create the message for in-game with username
|
||||
var color = statusType switch
|
||||
{
|
||||
PlayerStatusType.Connected => Color.Green.ToHex(),
|
||||
PlayerStatusType.Disconnected => Color.Yellow.ToHex(),
|
||||
PlayerStatusType.Banned => Color.Orange.ToHex(),
|
||||
_ => Color.Gray.ToHex(),
|
||||
};
|
||||
var inGameMessage = $"[color={color}]{session.Name} {message}[/color]";
|
||||
|
||||
var bwoinkMessage = new BwoinkTextMessage(
|
||||
userId: session.UserId,
|
||||
trueSender: SystemUserId,
|
||||
text: inGameMessage,
|
||||
sentAt: DateTime.Now,
|
||||
playSound: false
|
||||
);
|
||||
|
||||
var admins = GetTargetAdmins();
|
||||
foreach (var admin in admins)
|
||||
{
|
||||
RaiseNetworkEvent(bwoinkMessage, admin);
|
||||
}
|
||||
|
||||
// Enqueue the message for Discord relay
|
||||
if (_webhookUrl != string.Empty)
|
||||
{
|
||||
// if (!_messageQueues.ContainsKey(session.UserId))
|
||||
// _messageQueues[session.UserId] = new Queue<string>();
|
||||
//
|
||||
// var escapedText = FormattedMessage.EscapeText(message);
|
||||
// messageParams.Message = escapedText;
|
||||
//
|
||||
// var discordMessage = GenerateAHelpMessage(messageParams);
|
||||
// _messageQueues[session.UserId].Enqueue(discordMessage);
|
||||
|
||||
var queue = _messageQueues.GetOrNew(session.UserId);
|
||||
var escapedText = FormattedMessage.EscapeText(message);
|
||||
messageParams.Message = escapedText;
|
||||
var discordMessage = GenerateAHelpMessage(messageParams);
|
||||
queue.Enqueue(discordMessage);
|
||||
}
|
||||
}
|
||||
|
||||
private void OnGameRunLevelChanged(GameRunLevelChangedEvent args)
|
||||
{
|
||||
// Don't make a new embed if we
|
||||
|
|
@ -213,7 +345,8 @@ namespace Content.Server.Administration.Systems
|
|||
var content = await response.Content.ReadAsStringAsync();
|
||||
if (!response.IsSuccessStatusCode)
|
||||
{
|
||||
_sawmill.Log(LogLevel.Error, $"Discord returned bad status code when trying to get webhook data (perhaps the webhook URL is invalid?): {response.StatusCode}\nResponse: {content}");
|
||||
_sawmill.Log(LogLevel.Error,
|
||||
$"Discord returned bad status code when trying to get webhook data (perhaps the webhook URL is invalid?): {response.StatusCode}\nResponse: {content}");
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -237,7 +370,7 @@ namespace Content.Server.Administration.Systems
|
|||
|
||||
// Whether the message will become too long after adding these new messages
|
||||
var tooLong = exists && messages.Sum(msg => Math.Min(msg.Length, MessageLengthCap) + "\n".Length)
|
||||
+ existingEmbed.description.Length > DescriptionMax;
|
||||
+ existingEmbed.description.Length > DescriptionMax;
|
||||
|
||||
// If there is no existing embed, or it is getting too long, we create a new embed
|
||||
if (!exists || tooLong)
|
||||
|
|
@ -246,7 +379,8 @@ namespace Content.Server.Administration.Systems
|
|||
|
||||
if (lookup == null)
|
||||
{
|
||||
_sawmill.Log(LogLevel.Error, $"Unable to find player for NetUserId {userId} when sending discord webhook.");
|
||||
_sawmill.Log(LogLevel.Error,
|
||||
$"Unable to find player for NetUserId {userId} when sending discord webhook.");
|
||||
_relayMessages.Remove(userId);
|
||||
return;
|
||||
}
|
||||
|
|
@ -258,11 +392,13 @@ namespace Content.Server.Administration.Systems
|
|||
{
|
||||
if (tooLong && existingEmbed.id != null)
|
||||
{
|
||||
linkToPrevious = $"**[Go to previous embed of this round](https://discord.com/channels/{guildId}/{channelId}/{existingEmbed.id})**\n";
|
||||
linkToPrevious =
|
||||
$"**[Go to previous embed of this round](https://discord.com/channels/{guildId}/{channelId}/{existingEmbed.id})**\n";
|
||||
}
|
||||
else if (_oldMessageIds.TryGetValue(userId, out var id) && !string.IsNullOrEmpty(id))
|
||||
{
|
||||
linkToPrevious = $"**[Go to last round's conversation with this player](https://discord.com/channels/{guildId}/{channelId}/{id})**\n";
|
||||
linkToPrevious =
|
||||
$"**[Go to last round's conversation with this player](https://discord.com/channels/{guildId}/{channelId}/{id})**\n";
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -278,7 +414,8 @@ namespace Content.Server.Administration.Systems
|
|||
GameRunLevel.PreRoundLobby => "\n\n:arrow_forward: _**Pre-round lobby started**_\n",
|
||||
GameRunLevel.InRound => "\n\n:arrow_forward: _**Round started**_\n",
|
||||
GameRunLevel.PostRound => "\n\n:stop_button: _**Post-round started**_\n",
|
||||
_ => throw new ArgumentOutOfRangeException(nameof(_gameTicker.RunLevel), $"{_gameTicker.RunLevel} was not matched."),
|
||||
_ => throw new ArgumentOutOfRangeException(nameof(_gameTicker.RunLevel),
|
||||
$"{_gameTicker.RunLevel} was not matched."),
|
||||
};
|
||||
|
||||
existingEmbed.lastRunLevel = _gameTicker.RunLevel;
|
||||
|
|
@ -294,7 +431,9 @@ namespace Content.Server.Administration.Systems
|
|||
existingEmbed.description += $"\n{message}";
|
||||
}
|
||||
|
||||
var payload = GeneratePayload(existingEmbed.description, existingEmbed.username, existingEmbed.characterName);
|
||||
var payload = GeneratePayload(existingEmbed.description,
|
||||
existingEmbed.username,
|
||||
existingEmbed.characterName);
|
||||
|
||||
// If there is no existing embed, create a new one
|
||||
// Otherwise patch (edit) it
|
||||
|
|
@ -306,7 +445,8 @@ namespace Content.Server.Administration.Systems
|
|||
var content = await request.Content.ReadAsStringAsync();
|
||||
if (!request.IsSuccessStatusCode)
|
||||
{
|
||||
_sawmill.Log(LogLevel.Error, $"Discord returned bad status code when posting message (perhaps the message is too long?): {request.StatusCode}\nResponse: {content}");
|
||||
_sawmill.Log(LogLevel.Error,
|
||||
$"Discord returned bad status code when posting message (perhaps the message is too long?): {request.StatusCode}\nResponse: {content}");
|
||||
_relayMessages.Remove(userId);
|
||||
return;
|
||||
}
|
||||
|
|
@ -314,7 +454,8 @@ namespace Content.Server.Administration.Systems
|
|||
var id = JsonNode.Parse(content)?["id"];
|
||||
if (id == null)
|
||||
{
|
||||
_sawmill.Log(LogLevel.Error, $"Could not find id in json-content returned from discord webhook: {content}");
|
||||
_sawmill.Log(LogLevel.Error,
|
||||
$"Could not find id in json-content returned from discord webhook: {content}");
|
||||
_relayMessages.Remove(userId);
|
||||
return;
|
||||
}
|
||||
|
|
@ -329,7 +470,8 @@ namespace Content.Server.Administration.Systems
|
|||
if (!request.IsSuccessStatusCode)
|
||||
{
|
||||
var content = await request.Content.ReadAsStringAsync();
|
||||
_sawmill.Log(LogLevel.Error, $"Discord returned bad status code when patching message (perhaps the message is too long?): {request.StatusCode}\nResponse: {content}");
|
||||
_sawmill.Log(LogLevel.Error,
|
||||
$"Discord returned bad status code when patching message (perhaps the message is too long?): {request.StatusCode}\nResponse: {content}");
|
||||
_relayMessages.Remove(userId);
|
||||
return;
|
||||
}
|
||||
|
|
@ -359,7 +501,8 @@ namespace Content.Server.Administration.Systems
|
|||
: $"pre-round lobby for round {_gameTicker.RoundId + 1}",
|
||||
GameRunLevel.InRound => $"round {_gameTicker.RoundId}",
|
||||
GameRunLevel.PostRound => $"post-round {_gameTicker.RoundId}",
|
||||
_ => throw new ArgumentOutOfRangeException(nameof(_gameTicker.RunLevel), $"{_gameTicker.RunLevel} was not matched."),
|
||||
_ => throw new ArgumentOutOfRangeException(nameof(_gameTicker.RunLevel),
|
||||
$"{_gameTicker.RunLevel} was not matched."),
|
||||
};
|
||||
|
||||
return new WebhookPayload
|
||||
|
|
@ -405,6 +548,7 @@ namespace Content.Server.Administration.Systems
|
|||
protected override void OnBwoinkTextMessage(BwoinkTextMessage message, EntitySessionEventArgs eventArgs)
|
||||
{
|
||||
base.OnBwoinkTextMessage(message, eventArgs);
|
||||
_activeConversations[message.UserId] = DateTime.Now;
|
||||
var senderSession = eventArgs.SenderSession;
|
||||
|
||||
// TODO: Sanitize text?
|
||||
|
|
@ -427,7 +571,9 @@ namespace Content.Server.Administration.Systems
|
|||
// Sunrise-Sponsors-Start
|
||||
string bwoinkText;
|
||||
|
||||
if (senderAdmin is not null && senderAdmin.Flags == AdminFlags.Adminhelp) // Mentor. Not full admin. That's why it's colored differently.
|
||||
if (senderAdmin is not null &&
|
||||
senderAdmin.Flags ==
|
||||
AdminFlags.Adminhelp) // Mentor. Not full admin. That's why it's colored differently.
|
||||
{
|
||||
bwoinkText = $"[color=purple]\\[{senderAdmin.Title}\\]{senderSession.Name}[/color]";
|
||||
}
|
||||
|
|
@ -481,7 +627,9 @@ namespace Content.Server.Administration.Systems
|
|||
{
|
||||
string overrideMsgText;
|
||||
// Doing the same thing as above, but with the override name. Theres probably a better way to do this.
|
||||
if (senderAdmin is not null && senderAdmin.Flags == AdminFlags.Adminhelp) // Mentor. Not full admin. That's why it's colored differently.
|
||||
if (senderAdmin is not null &&
|
||||
senderAdmin.Flags ==
|
||||
AdminFlags.Adminhelp) // Mentor. Not full admin. That's why it's colored differently.
|
||||
{
|
||||
overrideMsgText = $"[color=purple]{_overrideClientName}[/color]";
|
||||
}
|
||||
|
|
@ -496,7 +644,11 @@ namespace Content.Server.Administration.Systems
|
|||
|
||||
overrideMsgText = $"{(message.PlaySound ? "" : "(S) ")}{overrideMsgText}: {escapedText}";
|
||||
|
||||
RaiseNetworkEvent(new BwoinkTextMessage(message.UserId, senderSession.UserId, overrideMsgText, playSound: playSound), session.Channel);
|
||||
RaiseNetworkEvent(new BwoinkTextMessage(message.UserId,
|
||||
senderSession.UserId,
|
||||
overrideMsgText,
|
||||
playSound: playSound),
|
||||
session.Channel);
|
||||
}
|
||||
else
|
||||
RaiseNetworkEvent(msg, session.Channel);
|
||||
|
|
@ -516,8 +668,18 @@ namespace Content.Server.Administration.Systems
|
|||
{
|
||||
str = str[..(DescriptionMax - _maxAdditionalChars - unameLength)];
|
||||
}
|
||||
|
||||
var nonAfkAdmins = GetNonAfkAdmins();
|
||||
_messageQueues[msg.UserId].Enqueue(GenerateAHelpMessage(senderSession.Name, str, !personalChannel, _gameTicker.RoundDuration().ToString("hh\\:mm\\:ss"), _gameTicker.RunLevel, playedSound: playSound, noReceivers: nonAfkAdmins.Count == 0));
|
||||
var messageParams = new AHelpMessageParams(
|
||||
senderSession.Name,
|
||||
str,
|
||||
!personalChannel,
|
||||
_gameTicker.RoundDuration().ToString("hh\\:mm\\:ss"),
|
||||
_gameTicker.RunLevel,
|
||||
playedSound: playSound,
|
||||
noReceivers: nonAfkAdmins.Count == 0
|
||||
);
|
||||
_messageQueues[msg.UserId].Enqueue(GenerateAHelpMessage(messageParams));
|
||||
}
|
||||
|
||||
if (admins.Count != 0 || sendsWebhook)
|
||||
|
|
@ -532,7 +694,8 @@ namespace Content.Server.Administration.Systems
|
|||
private IList<INetChannel> GetNonAfkAdmins()
|
||||
{
|
||||
return _adminManager.ActiveAdmins
|
||||
.Where(p => (_adminManager.GetAdminData(p)?.HasFlag(AdminFlags.Adminhelp) ?? false) && !_afkManager.IsAfk(p))
|
||||
.Where(p => (_adminManager.GetAdminData(p)?.HasFlag(AdminFlags.Adminhelp) ?? false) &&
|
||||
!_afkManager.IsAfk(p))
|
||||
.Select(p => p.Channel)
|
||||
.ToList();
|
||||
}
|
||||
|
|
@ -546,25 +709,69 @@ namespace Content.Server.Administration.Systems
|
|||
.ToList();
|
||||
}
|
||||
|
||||
private static string GenerateAHelpMessage(string username, string message, bool admin, string roundTime, GameRunLevel roundState, bool playedSound, bool noReceivers = false)
|
||||
private static string GenerateAHelpMessage(AHelpMessageParams parameters)
|
||||
{
|
||||
var stringbuilder = new StringBuilder();
|
||||
|
||||
if (admin)
|
||||
if (parameters.Icon != null)
|
||||
stringbuilder.Append(parameters.Icon);
|
||||
else if (parameters.IsAdmin)
|
||||
stringbuilder.Append(":outbox_tray:");
|
||||
else if (noReceivers)
|
||||
else if (parameters.NoReceivers)
|
||||
stringbuilder.Append(":sos:");
|
||||
else
|
||||
stringbuilder.Append(":inbox_tray:");
|
||||
|
||||
if(roundTime != string.Empty && roundState == GameRunLevel.InRound)
|
||||
stringbuilder.Append($" **{roundTime}**");
|
||||
if (!playedSound)
|
||||
if (parameters.RoundTime != string.Empty && parameters.RoundState == GameRunLevel.InRound)
|
||||
stringbuilder.Append($" **{parameters.RoundTime}**");
|
||||
if (!parameters.PlayedSound)
|
||||
stringbuilder.Append(" **(S)**");
|
||||
stringbuilder.Append($" **{username}:** ");
|
||||
stringbuilder.Append(message);
|
||||
|
||||
if (parameters.Icon == null)
|
||||
stringbuilder.Append($" **{parameters.Username}:** ");
|
||||
else
|
||||
stringbuilder.Append($" **{parameters.Username}** ");
|
||||
stringbuilder.Append(parameters.Message);
|
||||
return stringbuilder.ToString();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class AHelpMessageParams
|
||||
{
|
||||
public string Username { get; set; }
|
||||
public string Message { get; set; }
|
||||
public bool IsAdmin { get; set; }
|
||||
public string RoundTime { get; set; }
|
||||
public GameRunLevel RoundState { get; set; }
|
||||
public bool PlayedSound { get; set; }
|
||||
public bool NoReceivers { get; set; }
|
||||
public string? Icon { get; set; }
|
||||
|
||||
public AHelpMessageParams(
|
||||
string username,
|
||||
string message,
|
||||
bool isAdmin,
|
||||
string roundTime,
|
||||
GameRunLevel roundState,
|
||||
bool playedSound,
|
||||
bool noReceivers = false,
|
||||
string? icon = null)
|
||||
{
|
||||
Username = username;
|
||||
Message = message;
|
||||
IsAdmin = isAdmin;
|
||||
RoundTime = roundTime;
|
||||
RoundState = roundState;
|
||||
PlayedSound = playedSound;
|
||||
NoReceivers = noReceivers;
|
||||
Icon = icon;
|
||||
}
|
||||
}
|
||||
|
||||
public enum PlayerStatusType
|
||||
{
|
||||
Connected,
|
||||
Disconnected,
|
||||
Banned,
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -390,7 +390,7 @@ public sealed partial class AntagSelectionSystem : GameRuleSystem<AntagSelection
|
|||
}
|
||||
|
||||
_mind.TransferTo(curMind.Value, antagEnt, ghostCheckOverride: true);
|
||||
_role.MindAddRoles(curMind.Value, def.MindComponents);
|
||||
_role.MindAddRoles(curMind.Value, def.MindComponents, null, true);
|
||||
ent.Comp.SelectedMinds.Add((curMind.Value, Name(player)));
|
||||
SendBriefing(session, def.Briefing);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -177,6 +177,10 @@ namespace Content.Server.Cargo.Systems
|
|||
RaiseLocalEvent(ref ev);
|
||||
ev.FulfillmentEntity ??= station.Value;
|
||||
|
||||
_idCardSystem.TryFindIdCard(player, out var idCard);
|
||||
// ReSharper disable once ConditionalAccessQualifierIsNonNullableAccordingToAPIContract
|
||||
order.SetApproverData(idCard.Comp?.FullName, idCard.Comp?.JobTitle);
|
||||
|
||||
if (!ev.Handled)
|
||||
{
|
||||
ev.FulfillmentEntity = TryFulfillOrder((station.Value, stationData), order, orderDatabase);
|
||||
|
|
@ -189,18 +193,13 @@ namespace Content.Server.Cargo.Systems
|
|||
}
|
||||
}
|
||||
|
||||
_idCardSystem.TryFindIdCard(player, out var idCard);
|
||||
// ReSharper disable once ConditionalAccessQualifierIsNonNullableAccordingToAPIContract
|
||||
order.SetApproverData(idCard.Comp?.FullName, idCard.Comp?.JobTitle);
|
||||
order.Approved = true;
|
||||
_audio.PlayPvs(component.ConfirmSound, uid);
|
||||
|
||||
var approverName = idCard.Comp?.FullName ?? Loc.GetString("access-reader-unknown-id");
|
||||
var approverJob = idCard.Comp?.JobTitle ?? Loc.GetString("access-reader-unknown-id");
|
||||
var message = Loc.GetString("cargo-console-unlock-approved-order-broadcast",
|
||||
("productName", Loc.GetString(order.ProductName)),
|
||||
("orderAmount", order.OrderQuantity),
|
||||
("approverName", approverName),
|
||||
("approverJob", approverJob),
|
||||
("approver", order.Approver ?? string.Empty),
|
||||
("cost", cost));
|
||||
_radio.SendRadioMessage(uid, message, component.AnnouncementChannel, uid, escapeMarkup: false);
|
||||
ConsolePopup(args.Actor, Loc.GetString("cargo-console-trade-station", ("destination", MetaData(ev.FulfillmentEntity.Value).EntityName)));
|
||||
|
|
@ -421,6 +420,7 @@ namespace Content.Server.Cargo.Systems
|
|||
|
||||
// Approve it now
|
||||
order.SetApproverData(dest, sender);
|
||||
order.Approved = true;
|
||||
|
||||
// Log order addition
|
||||
_adminLogger.Add(LogType.Action, LogImpact.Low,
|
||||
|
|
|
|||
|
|
@ -25,7 +25,6 @@ using Content.Shared.Interaction;
|
|||
using Content.Shared.Item;
|
||||
using Content.Shared.Movement.Events;
|
||||
using Content.Shared.Popups;
|
||||
using Content.Shared.Throwing;
|
||||
using Content.Shared.Verbs;
|
||||
using Robust.Server.Audio;
|
||||
using Robust.Server.GameObjects;
|
||||
|
|
@ -35,7 +34,6 @@ using Robust.Shared.Map.Components;
|
|||
using Robust.Shared.Physics.Components;
|
||||
using Robust.Shared.Physics.Events;
|
||||
using Robust.Shared.Player;
|
||||
using Robust.Shared.Random;
|
||||
using Robust.Shared.Utility;
|
||||
|
||||
namespace Content.Server.Disposal.Unit.EntitySystems;
|
||||
|
|
@ -331,12 +329,13 @@ public sealed class DisposalUnitSystem : SharedDisposalUnitSystem
|
|||
{
|
||||
var currentTime = GameTiming.CurTime;
|
||||
|
||||
if (!_actionBlockerSystem.CanMove(args.Entity))
|
||||
return;
|
||||
|
||||
if (!TryComp(args.Entity, out HandsComponent? hands) ||
|
||||
hands.Count == 0 ||
|
||||
currentTime < component.LastExitAttempt + ExitAttemptDelay)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
component.LastExitAttempt = currentTime;
|
||||
Remove(uid, component, args.Entity);
|
||||
|
|
|
|||
|
|
@ -4,8 +4,12 @@ using Content.Server.Humanoid;
|
|||
using Content.Shared.DoAfter;
|
||||
using Content.Shared.Humanoid;
|
||||
using Content.Shared.Humanoid.Markings;
|
||||
using Content.Shared.IdentityManagement;
|
||||
using Content.Shared.Interaction;
|
||||
using Content.Shared.Inventory;
|
||||
using Content.Shared.MagicMirror;
|
||||
using Content.Shared.Popups;
|
||||
using Content.Shared.Tag;
|
||||
using Robust.Shared.Audio.Systems;
|
||||
|
||||
namespace Content.Server.MagicMirror;
|
||||
|
|
@ -19,6 +23,9 @@ public sealed class MagicMirrorSystem : SharedMagicMirrorSystem
|
|||
[Dependency] private readonly DoAfterSystem _doAfterSystem = default!;
|
||||
[Dependency] private readonly MarkingManager _markings = default!;
|
||||
[Dependency] private readonly HumanoidAppearanceSystem _humanoid = default!;
|
||||
[Dependency] private readonly SharedPopupSystem _popup = default!;
|
||||
[Dependency] private readonly InventorySystem _inventory = default!;
|
||||
[Dependency] private readonly TagSystem _tagSystem = default!;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
|
|
@ -46,9 +53,26 @@ public sealed class MagicMirrorSystem : SharedMagicMirrorSystem
|
|||
if (component.Target is not { } target)
|
||||
return;
|
||||
|
||||
// Check if the target getting their hair altered has any clothes that hides their hair
|
||||
if (CheckHeadSlotOrClothes(message.Actor, component.Target.Value))
|
||||
{
|
||||
_popup.PopupEntity(
|
||||
component.Target == message.Actor
|
||||
? Loc.GetString("magic-mirror-blocked-by-hat-self")
|
||||
: Loc.GetString("magic-mirror-blocked-by-hat-self-target"),
|
||||
message.Actor,
|
||||
message.Actor,
|
||||
PopupType.Medium);
|
||||
return;
|
||||
}
|
||||
|
||||
_doAfterSystem.Cancel(component.DoAfter);
|
||||
component.DoAfter = null;
|
||||
|
||||
var doafterTime = component.SelectSlotTime;
|
||||
if (component.Target == message.Actor)
|
||||
doafterTime /= 3;
|
||||
|
||||
var doAfter = new MagicMirrorSelectDoAfterEvent()
|
||||
{
|
||||
Category = message.Category,
|
||||
|
|
@ -56,7 +80,7 @@ public sealed class MagicMirrorSystem : SharedMagicMirrorSystem
|
|||
Marking = message.Marking,
|
||||
};
|
||||
|
||||
_doAfterSystem.TryStartDoAfter(new DoAfterArgs(EntityManager, message.Actor, component.SelectSlotTime, doAfter, uid, target: target, used: uid)
|
||||
_doAfterSystem.TryStartDoAfter(new DoAfterArgs(EntityManager, message.Actor, doafterTime, doAfter, uid, target: target, used: uid)
|
||||
{
|
||||
DistanceThreshold = SharedInteractionSystem.InteractionRange,
|
||||
BreakOnDamage = true,
|
||||
|
|
@ -66,6 +90,15 @@ public sealed class MagicMirrorSystem : SharedMagicMirrorSystem
|
|||
},
|
||||
out var doAfterId);
|
||||
|
||||
if (component.Target == message.Actor)
|
||||
{
|
||||
_popup.PopupEntity(Loc.GetString("magic-mirror-change-slot-self"), component.Target.Value, component.Target.Value, PopupType.Medium);
|
||||
}
|
||||
else
|
||||
{
|
||||
_popup.PopupEntity(Loc.GetString("magic-mirror-change-slot-target", ("user", Identity.Name(message.Actor, EntityManager))), component.Target.Value, component.Target.Value, PopupType.Medium);
|
||||
}
|
||||
|
||||
component.DoAfter = doAfterId;
|
||||
_audio.PlayPvs(component.ChangeHairSound, uid);
|
||||
}
|
||||
|
|
@ -102,9 +135,26 @@ public sealed class MagicMirrorSystem : SharedMagicMirrorSystem
|
|||
if (component.Target is not { } target)
|
||||
return;
|
||||
|
||||
// Check if the target getting their hair altered has any clothes that hides their hair
|
||||
if (CheckHeadSlotOrClothes(message.Actor, component.Target.Value))
|
||||
{
|
||||
_popup.PopupEntity(
|
||||
component.Target == message.Actor
|
||||
? Loc.GetString("magic-mirror-blocked-by-hat-self")
|
||||
: Loc.GetString("magic-mirror-blocked-by-hat-self-target"),
|
||||
message.Actor,
|
||||
message.Actor,
|
||||
PopupType.Medium);
|
||||
return;
|
||||
}
|
||||
|
||||
_doAfterSystem.Cancel(component.DoAfter);
|
||||
component.DoAfter = null;
|
||||
|
||||
var doafterTime = component.ChangeSlotTime;
|
||||
if (component.Target == message.Actor)
|
||||
doafterTime /= 3;
|
||||
|
||||
var doAfter = new MagicMirrorChangeColorDoAfterEvent()
|
||||
{
|
||||
Category = message.Category,
|
||||
|
|
@ -112,7 +162,7 @@ public sealed class MagicMirrorSystem : SharedMagicMirrorSystem
|
|||
Colors = message.Colors,
|
||||
};
|
||||
|
||||
_doAfterSystem.TryStartDoAfter(new DoAfterArgs(EntityManager, message.Actor, component.ChangeSlotTime, doAfter, uid, target: target, used: uid)
|
||||
_doAfterSystem.TryStartDoAfter(new DoAfterArgs(EntityManager, message.Actor, doafterTime, doAfter, uid, target: target, used: uid)
|
||||
{
|
||||
BreakOnDamage = true,
|
||||
BreakOnMove = true,
|
||||
|
|
@ -121,6 +171,15 @@ public sealed class MagicMirrorSystem : SharedMagicMirrorSystem
|
|||
},
|
||||
out var doAfterId);
|
||||
|
||||
if (component.Target == message.Actor)
|
||||
{
|
||||
_popup.PopupEntity(Loc.GetString("magic-mirror-change-color-self"), component.Target.Value, component.Target.Value, PopupType.Medium);
|
||||
}
|
||||
else
|
||||
{
|
||||
_popup.PopupEntity(Loc.GetString("magic-mirror-change-color-target", ("user", Identity.Name(message.Actor, EntityManager))), component.Target.Value, component.Target.Value, PopupType.Medium);
|
||||
}
|
||||
|
||||
component.DoAfter = doAfterId;
|
||||
}
|
||||
private void OnChangeColorDoAfter(EntityUid uid, MagicMirrorComponent component, MagicMirrorChangeColorDoAfterEvent args)
|
||||
|
|
@ -156,16 +215,33 @@ public sealed class MagicMirrorSystem : SharedMagicMirrorSystem
|
|||
if (component.Target is not { } target)
|
||||
return;
|
||||
|
||||
// Check if the target getting their hair altered has any clothes that hides their hair
|
||||
if (CheckHeadSlotOrClothes(message.Actor, component.Target.Value))
|
||||
{
|
||||
_popup.PopupEntity(
|
||||
component.Target == message.Actor
|
||||
? Loc.GetString("magic-mirror-blocked-by-hat-self")
|
||||
: Loc.GetString("magic-mirror-blocked-by-hat-self-target"),
|
||||
message.Actor,
|
||||
message.Actor,
|
||||
PopupType.Medium);
|
||||
return;
|
||||
}
|
||||
|
||||
_doAfterSystem.Cancel(component.DoAfter);
|
||||
component.DoAfter = null;
|
||||
|
||||
var doafterTime = component.RemoveSlotTime;
|
||||
if (component.Target == message.Actor)
|
||||
doafterTime /= 3;
|
||||
|
||||
var doAfter = new MagicMirrorRemoveSlotDoAfterEvent()
|
||||
{
|
||||
Category = message.Category,
|
||||
Slot = message.Slot,
|
||||
};
|
||||
|
||||
_doAfterSystem.TryStartDoAfter(new DoAfterArgs(EntityManager, message.Actor, component.RemoveSlotTime, doAfter, uid, target: target, used: uid)
|
||||
_doAfterSystem.TryStartDoAfter(new DoAfterArgs(EntityManager, message.Actor, doafterTime, doAfter, uid, target: target, used: uid)
|
||||
{
|
||||
DistanceThreshold = SharedInteractionSystem.InteractionRange,
|
||||
BreakOnDamage = true,
|
||||
|
|
@ -174,6 +250,15 @@ public sealed class MagicMirrorSystem : SharedMagicMirrorSystem
|
|||
},
|
||||
out var doAfterId);
|
||||
|
||||
if (component.Target == message.Actor)
|
||||
{
|
||||
_popup.PopupEntity(Loc.GetString("magic-mirror-remove-slot-self"), component.Target.Value, component.Target.Value, PopupType.Medium);
|
||||
}
|
||||
else
|
||||
{
|
||||
_popup.PopupEntity(Loc.GetString("magic-mirror-remove-slot-target", ("user", Identity.Name(message.Actor, EntityManager))), component.Target.Value, component.Target.Value, PopupType.Medium);
|
||||
}
|
||||
|
||||
component.DoAfter = doAfterId;
|
||||
_audio.PlayPvs(component.ChangeHairSound, uid);
|
||||
}
|
||||
|
|
@ -210,15 +295,32 @@ public sealed class MagicMirrorSystem : SharedMagicMirrorSystem
|
|||
if (component.Target == null)
|
||||
return;
|
||||
|
||||
// Check if the target getting their hair altered has any clothes that hides their hair
|
||||
if (CheckHeadSlotOrClothes(message.Actor, component.Target.Value))
|
||||
{
|
||||
_popup.PopupEntity(
|
||||
component.Target == message.Actor
|
||||
? Loc.GetString("magic-mirror-blocked-by-hat-self")
|
||||
: Loc.GetString("magic-mirror-blocked-by-hat-self-target"),
|
||||
message.Actor,
|
||||
message.Actor,
|
||||
PopupType.Medium);
|
||||
return;
|
||||
}
|
||||
|
||||
_doAfterSystem.Cancel(component.DoAfter);
|
||||
component.DoAfter = null;
|
||||
|
||||
var doafterTime = component.AddSlotTime;
|
||||
if (component.Target == message.Actor)
|
||||
doafterTime /= 3;
|
||||
|
||||
var doAfter = new MagicMirrorAddSlotDoAfterEvent()
|
||||
{
|
||||
Category = message.Category,
|
||||
};
|
||||
|
||||
_doAfterSystem.TryStartDoAfter(new DoAfterArgs(EntityManager, message.Actor, component.AddSlotTime, doAfter, uid, target: component.Target.Value, used: uid)
|
||||
_doAfterSystem.TryStartDoAfter(new DoAfterArgs(EntityManager, message.Actor, doafterTime, doAfter, uid, target: component.Target.Value, used: uid)
|
||||
{
|
||||
BreakOnDamage = true,
|
||||
BreakOnMove = true,
|
||||
|
|
@ -227,6 +329,15 @@ public sealed class MagicMirrorSystem : SharedMagicMirrorSystem
|
|||
},
|
||||
out var doAfterId);
|
||||
|
||||
if (component.Target == message.Actor)
|
||||
{
|
||||
_popup.PopupEntity(Loc.GetString("magic-mirror-add-slot-self"), component.Target.Value, component.Target.Value, PopupType.Medium);
|
||||
}
|
||||
else
|
||||
{
|
||||
_popup.PopupEntity(Loc.GetString("magic-mirror-add-slot-target", ("user", Identity.Name(message.Actor, EntityManager))), component.Target.Value, component.Target.Value, PopupType.Medium);
|
||||
}
|
||||
|
||||
component.DoAfter = doAfterId;
|
||||
_audio.PlayPvs(component.ChangeHairSound, uid);
|
||||
}
|
||||
|
|
@ -265,4 +376,32 @@ public sealed class MagicMirrorSystem : SharedMagicMirrorSystem
|
|||
ent.Comp.Target = null;
|
||||
Dirty(ent);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Helper function that checks if the wearer has anything on their head
|
||||
/// Or if they have any clothes that hides their hair
|
||||
/// </summary>
|
||||
private bool CheckHeadSlotOrClothes(EntityUid user, EntityUid target)
|
||||
{
|
||||
if (TryComp<InventoryComponent>(target, out var inventoryComp))
|
||||
{
|
||||
// any hat whatsoever will block haircutting
|
||||
if (_inventory.TryGetSlotEntity(target, "head", out var hat, inventoryComp))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
// maybe there's some kind of armor that has the HidesHair tag as well, so check every slot for it
|
||||
var slots = _inventory.GetSlotEnumerator((target, inventoryComp), SlotFlags.WITHOUT_POCKET);
|
||||
while (slots.MoveNext(out var slot))
|
||||
{
|
||||
if (slot.ContainedEntity != null && _tagSystem.HasTag(slot.ContainedEntity.Value, "HidesHair"))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,4 +12,10 @@ public sealed partial class HTNCompoundPrototype : IPrototype
|
|||
|
||||
[DataField("branches", required: true)]
|
||||
public List<HTNBranch> Branches = new();
|
||||
|
||||
/// <summary>
|
||||
/// Exclude this compound task from the CompoundRecursion integration test.
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public bool AllowRecursion = false;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -63,8 +63,13 @@ public sealed class HTNPlanJob : Job<HTNPlan>
|
|||
// How many primitive tasks we've added since last record.
|
||||
var primitiveCount = 0;
|
||||
|
||||
int tasksProcessed = 0;
|
||||
|
||||
while (tasksToProcess.TryDequeue(out var currentTask))
|
||||
{
|
||||
if (tasksProcessed++ > _rootTask.MaximumTasks)
|
||||
throw new Exception("HTN Planner exceeded maximum tasks");
|
||||
|
||||
switch (currentTask)
|
||||
{
|
||||
case HTNCompoundTask compound:
|
||||
|
|
|
|||
|
|
@ -3,4 +3,10 @@ namespace Content.Server.NPC.HTN;
|
|||
[ImplicitDataDefinitionForInheritors]
|
||||
public abstract partial class HTNTask
|
||||
{
|
||||
/// <summary>
|
||||
/// Limit the amount of tasks the planner considers. Exceeding this value sleeps the NPC and throws an exception.
|
||||
/// The expected way to hit this limit is with badly written recursive tasks.
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public int MaximumTasks = 1000;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -46,6 +46,11 @@ namespace Content.Server.Power.EntitySystems
|
|||
_provQuery = GetEntityQuery<ApcPowerProviderComponent>();
|
||||
}
|
||||
|
||||
private void OnExamined(Entity<ApcPowerReceiverComponent> ent, ref ExaminedEvent args)
|
||||
{
|
||||
args.PushMarkup(GetExamineText(ent.Comp.Powered));
|
||||
}
|
||||
|
||||
private void OnGetVerbs(EntityUid uid, ApcPowerReceiverComponent component, GetVerbsEvent<Verb> args)
|
||||
{
|
||||
if (!_adminManager.HasAdminFlag(args.User, AdminFlags.Admin))
|
||||
|
|
@ -61,17 +66,6 @@ namespace Content.Server.Power.EntitySystems
|
|||
});
|
||||
}
|
||||
|
||||
///<summary>
|
||||
///Adds some markup to the examine text of whatever object is using this component to tell you if it's powered or not, even if it doesn't have an icon state to do this for you.
|
||||
///</summary>
|
||||
private void OnExamined(EntityUid uid, ApcPowerReceiverComponent component, ExaminedEvent args)
|
||||
{
|
||||
args.PushMarkup(Loc.GetString("power-receiver-component-on-examine-main",
|
||||
("stateText", Loc.GetString( component.Powered
|
||||
? "power-receiver-component-on-examine-powered"
|
||||
: "power-receiver-component-on-examine-unpowered"))));
|
||||
}
|
||||
|
||||
private void OnProviderShutdown(EntityUid uid, ApcPowerProviderComponent component, ComponentShutdown args)
|
||||
{
|
||||
foreach (var receiver in component.LinkedReceivers)
|
||||
|
|
|
|||
|
|
@ -275,7 +275,6 @@ namespace Content.Server.Preferences.Managers
|
|||
|
||||
/// <summary>
|
||||
/// Retrieves preferences for the given username from storage.
|
||||
/// Creates and saves default preferences if they are not found, then returns them.
|
||||
/// </summary>
|
||||
public PlayerPreferences GetPreferences(NetUserId userId)
|
||||
{
|
||||
|
|
@ -290,7 +289,6 @@ namespace Content.Server.Preferences.Managers
|
|||
|
||||
/// <summary>
|
||||
/// Retrieves preferences for the given username from storage or returns null.
|
||||
/// Creates and saves default preferences if they are not found, then returns them.
|
||||
/// </summary>
|
||||
public PlayerPreferences? GetPreferencesOrNull(NetUserId? userId)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ using Content.Shared.Popups;
|
|||
using Content.Shared.Resist;
|
||||
using Content.Shared.Tools.Components;
|
||||
using Content.Shared.Tools.Systems;
|
||||
using Content.Shared.ActionBlocker;
|
||||
|
||||
namespace Content.Server.Resist;
|
||||
|
||||
|
|
@ -18,6 +19,7 @@ public sealed class ResistLockerSystem : EntitySystem
|
|||
[Dependency] private readonly PopupSystem _popupSystem = default!;
|
||||
[Dependency] private readonly SharedDoAfterSystem _doAfterSystem = default!;
|
||||
[Dependency] private readonly WeldableSystem _weldable = default!;
|
||||
[Dependency] private readonly ActionBlockerSystem _actionBlocker = default!;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
|
|
@ -34,6 +36,9 @@ public sealed class ResistLockerSystem : EntitySystem
|
|||
if (!TryComp(uid, out EntityStorageComponent? storageComponent))
|
||||
return;
|
||||
|
||||
if (!_actionBlocker.CanMove(args.Entity))
|
||||
return;
|
||||
|
||||
if (TryComp<LockComponent>(uid, out var lockComponent) && lockComponent.Locked || _weldable.IsWelded(uid))
|
||||
{
|
||||
AttemptResist(args.Entity, uid, storageComponent, component);
|
||||
|
|
|
|||
|
|
@ -26,6 +26,11 @@ public interface IGridSpawnGroup
|
|||
/// </summary>
|
||||
public float MinimumDistance { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Maximum distance to spawn away from the station.
|
||||
/// </summary>
|
||||
public float MaximumDistance { get; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public ProtoId<DatasetPrototype>? NameDataset { get; }
|
||||
|
||||
|
|
@ -67,6 +72,8 @@ public sealed class DungeonSpawnGroup : IGridSpawnGroup
|
|||
/// <inheritdoc />
|
||||
public float MinimumDistance { get; }
|
||||
|
||||
public float MaximumDistance { get; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public ProtoId<DatasetPrototype>? NameDataset { get; }
|
||||
|
||||
|
|
@ -94,7 +101,11 @@ public sealed class GridSpawnGroup : IGridSpawnGroup
|
|||
{
|
||||
public List<ResPath> Paths = new();
|
||||
|
||||
/// <inheritdoc />
|
||||
public float MinimumDistance { get; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public float MaximumDistance { get; }
|
||||
public ProtoId<DatasetPrototype>? NameDataset { get; }
|
||||
public int MinCount { get; set; } = 1;
|
||||
public int MaxCount { get; set; } = 1;
|
||||
|
|
|
|||
|
|
@ -281,24 +281,24 @@ namespace Content.Server.Shuttles.Systems
|
|||
{
|
||||
if (_doorSystem.TryOpen(dockAUid, doorA))
|
||||
{
|
||||
doorA.ChangeAirtight = false;
|
||||
if (TryComp<DoorBoltComponent>(dockAUid, out var airlockA))
|
||||
{
|
||||
_doorSystem.SetBoltsDown((dockAUid, airlockA), true);
|
||||
}
|
||||
}
|
||||
doorA.ChangeAirtight = false;
|
||||
}
|
||||
|
||||
if (TryComp(dockBUid, out DoorComponent? doorB))
|
||||
{
|
||||
if (_doorSystem.TryOpen(dockBUid, doorB))
|
||||
{
|
||||
doorB.ChangeAirtight = false;
|
||||
if (TryComp<DoorBoltComponent>(dockBUid, out var airlockB))
|
||||
{
|
||||
_doorSystem.SetBoltsDown((dockBUid, airlockB), true);
|
||||
}
|
||||
}
|
||||
doorB.ChangeAirtight = false;
|
||||
}
|
||||
|
||||
if (_pathfinding.TryCreatePortal(dockAXform.Coordinates, dockBXform.Coordinates, out var handle))
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ using Content.Shared.Shuttles.Components;
|
|||
using Content.Shared.Station.Components;
|
||||
using Robust.Shared.Collections;
|
||||
using Robust.Shared.Map;
|
||||
using Robust.Shared.Map.Components;
|
||||
using Robust.Shared.Random;
|
||||
using Robust.Shared.Utility;
|
||||
|
||||
|
|
@ -86,9 +87,15 @@ public sealed partial class ShuttleSystem
|
|||
_mapManager.DeleteMap(mapId);
|
||||
}
|
||||
|
||||
private bool TryDungeonSpawn(EntityUid targetGrid, EntityUid stationUid, MapId mapId, DungeonSpawnGroup group, out EntityUid spawned)
|
||||
private bool TryDungeonSpawn(Entity<MapGridComponent?> targetGrid, EntityUid stationUid, MapId mapId, DungeonSpawnGroup group, out EntityUid spawned)
|
||||
{
|
||||
spawned = EntityUid.Invalid;
|
||||
|
||||
if (!_gridQuery.Resolve(targetGrid.Owner, ref targetGrid.Comp))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
var dungeonProtoId = _random.Pick(group.Protos);
|
||||
|
||||
if (!_protoManager.TryIndex(dungeonProtoId, out var dungeonProto))
|
||||
|
|
@ -96,11 +103,13 @@ public sealed partial class ShuttleSystem
|
|||
return false;
|
||||
}
|
||||
|
||||
var spawnCoords = new EntityCoordinates(targetGrid, Vector2.Zero);
|
||||
var targetPhysics = _physicsQuery.Comp(targetGrid);
|
||||
var spawnCoords = new EntityCoordinates(targetGrid, targetPhysics.LocalCenter);
|
||||
|
||||
if (group.MinimumDistance > 0f)
|
||||
{
|
||||
spawnCoords = spawnCoords.Offset(_random.NextVector2(group.MinimumDistance, group.MinimumDistance * 1.5f));
|
||||
var distancePadding = MathF.Max(targetGrid.Comp.LocalAABB.Width, targetGrid.Comp.LocalAABB.Height);
|
||||
spawnCoords = spawnCoords.Offset(_random.NextVector2(distancePadding + group.MinimumDistance, distancePadding + group.MaximumDistance));
|
||||
}
|
||||
|
||||
var spawnMapCoords = _transform.ToMapCoordinates(spawnCoords);
|
||||
|
|
|
|||
|
|
@ -58,12 +58,16 @@ public sealed partial class ShuttleSystem : SharedShuttleSystem
|
|||
[Dependency] private readonly ThrusterSystem _thruster = default!;
|
||||
[Dependency] private readonly UserInterfaceSystem _uiSystem = default!;
|
||||
|
||||
private EntityQuery<MapGridComponent> _gridQuery;
|
||||
|
||||
public const float TileMassMultiplier = 0.5f;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
|
||||
_gridQuery = GetEntityQuery<MapGridComponent>();
|
||||
|
||||
InitializeFTL();
|
||||
InitializeGridFills();
|
||||
InitializeIFF();
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
using Content.Server.Temperature.Systems;
|
||||
|
||||
namespace Content.Server.Atmos.Components;
|
||||
namespace Content.Server.Temperature.Components;
|
||||
|
||||
[RegisterComponent]
|
||||
[Access(typeof(TemperatureSystem))]
|
||||
|
|
@ -1,6 +1,5 @@
|
|||
using System.Linq;
|
||||
using Content.Server.Administration.Logs;
|
||||
using Content.Server.Atmos.Components;
|
||||
using Content.Server.Atmos.EntitySystems;
|
||||
using Content.Server.Body.Components;
|
||||
using Content.Server.Temperature.Components;
|
||||
|
|
|
|||
|
|
@ -10,3 +10,12 @@ public enum AccessWireActionKey : byte
|
|||
Pulsed,
|
||||
PulseCancel
|
||||
}
|
||||
|
||||
[Serializable, NetSerializable]
|
||||
public enum LogWireActionKey : byte
|
||||
{
|
||||
Key,
|
||||
Status,
|
||||
Pulsed,
|
||||
PulseCancel
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,6 +20,8 @@ namespace Content.Shared.Administration
|
|||
{
|
||||
private string? _playtimeString;
|
||||
|
||||
public bool IsPinned { get; set; }
|
||||
|
||||
public string PlaytimeString => _playtimeString ??=
|
||||
OverallPlaytime?.ToString("%d':'hh':'mm") ?? Loc.GetString("generic-unknown-title");
|
||||
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
using Content.Shared.ActionBlocker;
|
||||
using Content.Shared.Burial;
|
||||
using Content.Shared.Burial.Components;
|
||||
using Content.Shared.DoAfter;
|
||||
|
|
@ -8,7 +9,6 @@ using Content.Shared.Popups;
|
|||
using Content.Shared.Storage.Components;
|
||||
using Content.Shared.Storage.EntitySystems;
|
||||
using Robust.Shared.Audio.Systems;
|
||||
using Robust.Shared.Player;
|
||||
|
||||
namespace Content.Server.Burial.Systems;
|
||||
|
||||
|
|
@ -18,6 +18,7 @@ public sealed class BurialSystem : EntitySystem
|
|||
[Dependency] private readonly SharedEntityStorageSystem _storageSystem = default!;
|
||||
[Dependency] private readonly SharedAudioSystem _audioSystem = default!;
|
||||
[Dependency] private readonly SharedPopupSystem _popupSystem = default!;
|
||||
[Dependency] private readonly ActionBlockerSystem _actionBlocker = default!;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
|
|
@ -162,6 +163,9 @@ public sealed class BurialSystem : EntitySystem
|
|||
if (component.HandDiggingDoAfter != null)
|
||||
return;
|
||||
|
||||
if (!_actionBlocker.CanMove(args.Entity))
|
||||
return;
|
||||
|
||||
var doAfterEventArgs = new DoAfterArgs(EntityManager, args.Entity, component.DigDelay / component.DigOutByHandModifier, new GraveDiggingDoAfterEvent(), uid, target: uid)
|
||||
{
|
||||
NeedHand = false,
|
||||
|
|
|
|||
|
|
@ -48,7 +48,7 @@ namespace Content.Shared.Cargo
|
|||
// public int RequesterId;
|
||||
[DataField]
|
||||
public string Reason { get; private set; }
|
||||
public bool Approved => Approver is not null;
|
||||
public bool Approved;
|
||||
[DataField]
|
||||
public string? Approver;
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
using Content.Shared.ActionBlocker;
|
||||
using Content.Shared.Body.Systems;
|
||||
using Content.Shared.Buckle.Components;
|
||||
using Content.Shared.Climbing.Components;
|
||||
using Content.Shared.Climbing.Events;
|
||||
|
|
@ -44,6 +43,7 @@ public sealed partial class ClimbSystem : VirtualController
|
|||
private const string ClimbingFixtureName = "climb";
|
||||
private const int ClimbingCollisionGroup = (int) (CollisionGroup.TableLayer | CollisionGroup.LowImpassable);
|
||||
|
||||
private EntityQuery<ClimbableComponent> _climbableQuery;
|
||||
private EntityQuery<FixturesComponent> _fixturesQuery;
|
||||
private EntityQuery<TransformComponent> _xformQuery;
|
||||
|
||||
|
|
@ -51,6 +51,7 @@ public sealed partial class ClimbSystem : VirtualController
|
|||
{
|
||||
base.Initialize();
|
||||
|
||||
_climbableQuery = GetEntityQuery<ClimbableComponent>();
|
||||
_fixturesQuery = GetEntityQuery<FixturesComponent>();
|
||||
_xformQuery = GetEntityQuery<TransformComponent>();
|
||||
|
||||
|
|
@ -350,12 +351,39 @@ public sealed partial class ClimbSystem : VirtualController
|
|||
{
|
||||
if (args.OurFixtureId != ClimbingFixtureName
|
||||
|| !component.IsClimbing
|
||||
|| component.NextTransition != null
|
||||
|| args.OurFixture.Contacts.Count > 1)
|
||||
|| component.NextTransition != null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (args.OurFixture.Contacts.Count > 1)
|
||||
{
|
||||
foreach (var contact in args.OurFixture.Contacts.Values)
|
||||
{
|
||||
if (!contact.IsTouching)
|
||||
continue;
|
||||
|
||||
var otherEnt = contact.EntityA;
|
||||
var otherFixture = contact.FixtureA;
|
||||
var otherFixtureId = contact.FixtureAId;
|
||||
if (uid == contact.EntityA)
|
||||
{
|
||||
otherEnt = contact.EntityB;
|
||||
otherFixture = contact.FixtureB;
|
||||
otherFixtureId = contact.FixtureBId;
|
||||
}
|
||||
|
||||
if (args.OtherEntity == otherEnt && args.OtherFixtureId == otherFixtureId)
|
||||
continue;
|
||||
|
||||
if (otherFixture is { Hard: true } &&
|
||||
_climbableQuery.HasComp(otherEnt))
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var otherFixture in args.OurFixture.Contacts.Keys)
|
||||
{
|
||||
// If it's the other fixture then ignore em
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
using Content.Shared.Actions;
|
||||
using Content.Shared.Mind;
|
||||
using Content.Shared.MouseRotator;
|
||||
using Content.Shared.Movement.Components;
|
||||
using Content.Shared.Popups;
|
||||
|
|
@ -13,6 +14,7 @@ public abstract class SharedCombatModeSystem : EntitySystem
|
|||
[Dependency] private readonly INetManager _netMan = default!;
|
||||
[Dependency] private readonly SharedActionsSystem _actionsSystem = default!;
|
||||
[Dependency] private readonly SharedPopupSystem _popup = default!;
|
||||
[Dependency] private readonly SharedMindSystem _mind = default!;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
|
|
@ -82,7 +84,7 @@ public abstract class SharedCombatModeSystem : EntitySystem
|
|||
_actionsSystem.SetToggled(component.CombatToggleActionEntity, component.IsInCombatMode);
|
||||
|
||||
// Change mouse rotator comps if flag is set
|
||||
if (!component.ToggleMouseRotator || IsNpc(entity))
|
||||
if (!component.ToggleMouseRotator || IsNpc(entity) && !_mind.TryGetMind(entity, out _, out _))
|
||||
return;
|
||||
|
||||
SetMouseRotatorComponents(entity, value);
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@ using Robust.Shared.Physics.Systems;
|
|||
using Robust.Shared.Timing;
|
||||
using Robust.Shared.Audio.Systems;
|
||||
using Robust.Shared.Network;
|
||||
using Robust.Shared.Map.Components;
|
||||
|
||||
namespace Content.Shared.Doors.Systems;
|
||||
|
||||
|
|
@ -40,6 +41,8 @@ public abstract partial class SharedDoorSystem : EntitySystem
|
|||
[Dependency] private readonly AccessReaderSystem _accessReaderSystem = default!;
|
||||
[Dependency] private readonly PryingSystem _pryingSystem = default!;
|
||||
[Dependency] protected readonly SharedPopupSystem Popup = default!;
|
||||
[Dependency] private readonly SharedMapSystem _mapSystem = default!;
|
||||
|
||||
|
||||
[ValidatePrototypeId<TagPrototype>]
|
||||
public const string DoorBumpTag = "DoorBumpOpener";
|
||||
|
|
@ -555,29 +558,37 @@ public abstract partial class SharedDoorSystem : EntitySystem
|
|||
if (!Resolve(uid, ref physics))
|
||||
yield break;
|
||||
|
||||
var xform = Transform(uid);
|
||||
// Getting the world bounds from the gridUid allows us to use the version of
|
||||
// GetCollidingEntities that returns Entity<PhysicsComponent>
|
||||
if (!TryComp<MapGridComponent>(xform.GridUid, out var mapGridComp))
|
||||
yield break;
|
||||
var tileRef = _mapSystem.GetTileRef(xform.GridUid.Value, mapGridComp, xform.Coordinates);
|
||||
var doorWorldBounds = _entityLookup.GetWorldBounds(tileRef);
|
||||
|
||||
// TODO SLOTH fix electro's code.
|
||||
// ReSharper disable once InconsistentNaming
|
||||
var doorAABB = _entityLookup.GetWorldAABB(uid);
|
||||
|
||||
foreach (var otherPhysics in PhysicsSystem.GetCollidingEntities(Transform(uid).MapID, doorAABB))
|
||||
foreach (var otherPhysics in PhysicsSystem.GetCollidingEntities(Transform(uid).MapID, doorWorldBounds))
|
||||
{
|
||||
if (otherPhysics == physics)
|
||||
if (otherPhysics.Comp == physics)
|
||||
continue;
|
||||
|
||||
//TODO: Make only shutters ignore these objects upon colliding instead of all airlocks
|
||||
// Excludes Glasslayer for windows, GlassAirlockLayer for windoors, TableLayer for tables
|
||||
if (!otherPhysics.CanCollide || otherPhysics.CollisionLayer == (int)CollisionGroup.GlassLayer || otherPhysics.CollisionLayer == (int)CollisionGroup.GlassAirlockLayer || otherPhysics.CollisionLayer == (int)CollisionGroup.TableLayer)
|
||||
if (!otherPhysics.Comp.CanCollide || otherPhysics.Comp.CollisionLayer == (int) CollisionGroup.GlassLayer || otherPhysics.Comp.CollisionLayer == (int) CollisionGroup.GlassAirlockLayer || otherPhysics.Comp.CollisionLayer == (int) CollisionGroup.TableLayer)
|
||||
continue;
|
||||
|
||||
//If the colliding entity is a slippable item ignore it by the airlock
|
||||
if (otherPhysics.CollisionLayer == (int)CollisionGroup.SlipLayer && otherPhysics.CollisionMask == (int)CollisionGroup.ItemMask)
|
||||
if (otherPhysics.Comp.CollisionLayer == (int) CollisionGroup.SlipLayer && otherPhysics.Comp.CollisionMask == (int) CollisionGroup.ItemMask)
|
||||
continue;
|
||||
|
||||
//For when doors need to close over conveyor belts
|
||||
if (otherPhysics.CollisionLayer == (int) CollisionGroup.ConveyorMask)
|
||||
if (otherPhysics.Comp.CollisionLayer == (int) CollisionGroup.ConveyorMask)
|
||||
continue;
|
||||
|
||||
if ((physics.CollisionMask & otherPhysics.CollisionLayer) == 0 && (otherPhysics.CollisionMask & physics.CollisionLayer) == 0)
|
||||
if ((physics.CollisionMask & otherPhysics.Comp.CollisionLayer) == 0 && (otherPhysics.Comp.CollisionMask & physics.CollisionLayer) == 0)
|
||||
continue;
|
||||
|
||||
if (_entityLookup.GetWorldAABB(otherPhysics.Owner).IntersectPercentage(doorAABB) < IntersectPercentage)
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ namespace Content.Shared.Examine
|
|||
{
|
||||
public abstract partial class ExamineSystemShared : EntitySystem
|
||||
{
|
||||
[Dependency] private readonly OccluderSystem _occluder = default!;
|
||||
[Dependency] private readonly SharedTransformSystem _transform = default!;
|
||||
[Dependency] private readonly SharedContainerSystem _containerSystem = default!;
|
||||
[Dependency] private readonly SharedInteractionSystem _interactionSystem = default!;
|
||||
|
|
@ -182,12 +183,9 @@ namespace Content.Shared.Examine
|
|||
length = MaxRaycastRange;
|
||||
}
|
||||
|
||||
var occluderSystem = Get<OccluderSystem>();
|
||||
IoCManager.Resolve(ref entMan);
|
||||
|
||||
var ray = new Ray(origin.Position, dir.Normalized());
|
||||
var rayResults = occluderSystem
|
||||
.IntersectRayWithPredicate(origin.MapId, ray, length, state, predicate, false).ToList();
|
||||
var rayResults = _occluder
|
||||
.IntersectRayWithPredicate(origin.MapId, ray, length, state, predicate, false);
|
||||
|
||||
if (rayResults.Count == 0) return true;
|
||||
|
||||
|
|
@ -195,13 +193,13 @@ namespace Content.Shared.Examine
|
|||
|
||||
foreach (var result in rayResults)
|
||||
{
|
||||
if (!entMan.TryGetComponent(result.HitEntity, out OccluderComponent? o))
|
||||
if (!TryComp(result.HitEntity, out OccluderComponent? o))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var bBox = o.BoundingBox;
|
||||
bBox = bBox.Translated(entMan.GetComponent<TransformComponent>(result.HitEntity).WorldPosition);
|
||||
bBox = bBox.Translated(_transform.GetWorldPosition(result.HitEntity));
|
||||
|
||||
if (bBox.Contains(origin.Position) || bBox.Contains(other.Position))
|
||||
{
|
||||
|
|
@ -216,7 +214,6 @@ namespace Content.Shared.Examine
|
|||
|
||||
public bool InRangeUnOccluded(EntityUid origin, EntityUid other, float range = ExamineRange, Ignored? predicate = null, bool ignoreInsideBlocker = true)
|
||||
{
|
||||
var entMan = IoCManager.Resolve<IEntityManager>();
|
||||
var originPos = _transform.GetMapCoordinates(origin);
|
||||
var otherPos = _transform.GetMapCoordinates(other);
|
||||
|
||||
|
|
@ -225,16 +222,14 @@ namespace Content.Shared.Examine
|
|||
|
||||
public bool InRangeUnOccluded(EntityUid origin, EntityCoordinates other, float range = ExamineRange, Ignored? predicate = null, bool ignoreInsideBlocker = true)
|
||||
{
|
||||
var entMan = IoCManager.Resolve<IEntityManager>();
|
||||
var originPos = _transform.GetMapCoordinates(origin);
|
||||
var otherPos = other.ToMap(entMan, _transform);
|
||||
var otherPos = _transform.ToMapCoordinates(other);
|
||||
|
||||
return InRangeUnOccluded(originPos, otherPos, range, predicate, ignoreInsideBlocker);
|
||||
}
|
||||
|
||||
public bool InRangeUnOccluded(EntityUid origin, MapCoordinates other, float range = ExamineRange, Ignored? predicate = null, bool ignoreInsideBlocker = true)
|
||||
{
|
||||
var entMan = IoCManager.Resolve<IEntityManager>();
|
||||
var originPos = _transform.GetMapCoordinates(origin);
|
||||
|
||||
return InRangeUnOccluded(originPos, other, range, predicate, ignoreInsideBlocker);
|
||||
|
|
@ -250,11 +245,12 @@ namespace Content.Shared.Examine
|
|||
}
|
||||
|
||||
var hasDescription = false;
|
||||
var metadata = MetaData(entity);
|
||||
|
||||
//Add an entity description if one is declared
|
||||
if (!string.IsNullOrEmpty(EntityManager.GetComponent<MetaDataComponent>(entity).EntityDescription))
|
||||
if (!string.IsNullOrEmpty(metadata.EntityDescription))
|
||||
{
|
||||
message.AddText(EntityManager.GetComponent<MetaDataComponent>(entity).EntityDescription);
|
||||
message.AddText(metadata.EntityDescription);
|
||||
hasDescription = true;
|
||||
}
|
||||
|
||||
|
|
@ -356,7 +352,7 @@ namespace Content.Shared.Examine
|
|||
var totalMessage = new FormattedMessage(Message);
|
||||
parts.Sort(Comparison);
|
||||
|
||||
if (_hasDescription)
|
||||
if (_hasDescription && parts.Count > 0)
|
||||
{
|
||||
totalMessage.PushNewline();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -953,7 +953,7 @@ namespace Content.Shared.Interaction
|
|||
RaiseLocalEvent(target, interactUsingEvent, true);
|
||||
DoContactInteraction(user, used, interactUsingEvent);
|
||||
DoContactInteraction(user, target, interactUsingEvent);
|
||||
DoContactInteraction(used, target, interactUsingEvent);
|
||||
// Contact interactions are currently only used for forensics, so we don't raise used -> target
|
||||
if (interactUsingEvent.Handled)
|
||||
return;
|
||||
|
||||
|
|
@ -974,7 +974,7 @@ namespace Content.Shared.Interaction
|
|||
if (canReach)
|
||||
{
|
||||
DoContactInteraction(user, target, afterInteractEvent);
|
||||
DoContactInteraction(used, target, afterInteractEvent);
|
||||
// Contact interactions are currently only used for forensics, so we don't raise used -> target
|
||||
}
|
||||
|
||||
if (afterInteractEvent.Handled)
|
||||
|
|
@ -990,7 +990,7 @@ namespace Content.Shared.Interaction
|
|||
if (canReach)
|
||||
{
|
||||
DoContactInteraction(user, target, afterInteractUsingEvent);
|
||||
DoContactInteraction(used, target, afterInteractUsingEvent);
|
||||
// Contact interactions are currently only used for forensics, so we don't raise used -> target
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -39,6 +39,12 @@ namespace Content.Shared.Lathe
|
|||
|
||||
[DataField]
|
||||
public string? RunningState;
|
||||
|
||||
[DataField]
|
||||
public string? UnlitIdleState;
|
||||
|
||||
[DataField]
|
||||
public string? UnlitRunningState;
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
|
|
|
|||
|
|
@ -20,25 +20,25 @@ public sealed partial class MagicMirrorComponent : Component
|
|||
public EntityUid? Target;
|
||||
|
||||
/// <summary>
|
||||
/// doafter time required to add a new slot
|
||||
/// Do after time to add a new slot, adding hair to a person
|
||||
/// </summary>
|
||||
[DataField, ViewVariables(VVAccess.ReadWrite)]
|
||||
public TimeSpan AddSlotTime = TimeSpan.FromSeconds(10); // Sunrise-edit
|
||||
|
||||
/// <summary>
|
||||
/// doafter time required to remove a existing slot
|
||||
/// Do after time to remove a slot, removing hair from a person
|
||||
/// </summary>
|
||||
[DataField, ViewVariables(VVAccess.ReadWrite)]
|
||||
public TimeSpan RemoveSlotTime = TimeSpan.FromSeconds(8); // Sunrise-edit
|
||||
|
||||
/// <summary>
|
||||
/// doafter time required to change slot
|
||||
/// Do after time to change a person's hairstyle
|
||||
/// </summary>
|
||||
[DataField, ViewVariables(VVAccess.ReadWrite)]
|
||||
public TimeSpan SelectSlotTime = TimeSpan.FromSeconds(6); // Sunrise-edit
|
||||
|
||||
/// <summary>
|
||||
/// doafter time required to recolor slot
|
||||
/// Do after time to change a person's hair color
|
||||
/// </summary>
|
||||
[DataField, ViewVariables(VVAccess.ReadWrite)]
|
||||
public TimeSpan ChangeSlotTime = TimeSpan.FromSeconds(4); // Sunrise-edit
|
||||
|
|
|
|||
63
Content.Shared/Paper/EnvelopeComponent.cs
Normal file
63
Content.Shared/Paper/EnvelopeComponent.cs
Normal file
|
|
@ -0,0 +1,63 @@
|
|||
using Content.Shared.DoAfter;
|
||||
using Robust.Shared.Audio;
|
||||
using Robust.Shared.GameStates;
|
||||
using Robust.Shared.Serialization;
|
||||
|
||||
namespace Content.Shared.Paper;
|
||||
|
||||
[RegisterComponent, NetworkedComponent, AutoGenerateComponentState(true)]
|
||||
public sealed partial class EnvelopeComponent : Component
|
||||
{
|
||||
/// <summary>
|
||||
/// The current open/sealed/torn state of the envelope
|
||||
/// </summary>
|
||||
[ViewVariables, DataField, AutoNetworkedField]
|
||||
public EnvelopeState State = EnvelopeState.Open;
|
||||
|
||||
[DataField, ViewVariables]
|
||||
public string SlotId = "letter_slot";
|
||||
|
||||
/// <summary>
|
||||
/// Stores the current sealing/tearing doafter of the envelope
|
||||
/// to prevent doafter spam/prediction issues
|
||||
/// </summary>
|
||||
[DataField, ViewVariables]
|
||||
public DoAfterId? EnvelopeDoAfter;
|
||||
|
||||
/// <summary>
|
||||
/// How long it takes to seal the envelope closed
|
||||
/// </summary>
|
||||
[DataField, ViewVariables]
|
||||
public TimeSpan SealDelay = TimeSpan.FromSeconds(1);
|
||||
|
||||
/// <summary>
|
||||
/// How long it takes to tear open the envelope
|
||||
/// </summary>
|
||||
[DataField, ViewVariables]
|
||||
public TimeSpan TearDelay = TimeSpan.FromSeconds(1);
|
||||
|
||||
/// <summary>
|
||||
/// The sound to play when the envelope is sealed closed
|
||||
/// </summary>
|
||||
[DataField, ViewVariables]
|
||||
public SoundPathSpecifier? SealSound = new SoundPathSpecifier("/Audio/Effects/packetrip.ogg");
|
||||
|
||||
/// <summary>
|
||||
/// The sound to play when the envelope is torn open
|
||||
/// </summary>
|
||||
[DataField, ViewVariables]
|
||||
public SoundPathSpecifier? TearSound = new SoundPathSpecifier("/Audio/Effects/poster_broken.ogg");
|
||||
|
||||
[Serializable, NetSerializable]
|
||||
public enum EnvelopeState : byte
|
||||
{
|
||||
Open,
|
||||
Sealed,
|
||||
Torn
|
||||
}
|
||||
}
|
||||
|
||||
[Serializable, NetSerializable]
|
||||
public sealed partial class EnvelopeDoAfterEvent : SimpleDoAfterEvent
|
||||
{
|
||||
}
|
||||
108
Content.Shared/Paper/EnvelopeSystem.cs
Normal file
108
Content.Shared/Paper/EnvelopeSystem.cs
Normal file
|
|
@ -0,0 +1,108 @@
|
|||
using Content.Shared.DoAfter;
|
||||
using Content.Shared.Containers.ItemSlots;
|
||||
using Content.Shared.Verbs;
|
||||
using Robust.Shared.Audio.Systems;
|
||||
using Content.Shared.Examine;
|
||||
|
||||
namespace Content.Shared.Paper;
|
||||
|
||||
public sealed class EnvelopeSystem : EntitySystem
|
||||
{
|
||||
[Dependency] private readonly SharedDoAfterSystem _doAfterSystem = default!;
|
||||
[Dependency] private readonly SharedAudioSystem _audioSystem = default!;
|
||||
[Dependency] private readonly ItemSlotsSystem _itemSlotsSystem = default!;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
|
||||
SubscribeLocalEvent<EnvelopeComponent, ItemSlotInsertAttemptEvent>(OnInsertAttempt);
|
||||
SubscribeLocalEvent<EnvelopeComponent, ItemSlotEjectAttemptEvent>(OnEjectAttempt);
|
||||
SubscribeLocalEvent<EnvelopeComponent, GetVerbsEvent<AlternativeVerb>>(OnGetAltVerbs);
|
||||
SubscribeLocalEvent<EnvelopeComponent, EnvelopeDoAfterEvent>(OnDoAfter);
|
||||
SubscribeLocalEvent<EnvelopeComponent, ExaminedEvent>(OnExamine);
|
||||
}
|
||||
|
||||
private void OnExamine(Entity<EnvelopeComponent> ent, ref ExaminedEvent args)
|
||||
{
|
||||
if (ent.Comp.State == EnvelopeComponent.EnvelopeState.Sealed)
|
||||
{
|
||||
args.PushMarkup(Loc.GetString("envelope-sealed-examine", ("envelope", ent.Owner)));
|
||||
}
|
||||
else if (ent.Comp.State == EnvelopeComponent.EnvelopeState.Torn)
|
||||
{
|
||||
args.PushMarkup(Loc.GetString("envelope-torn-examine", ("envelope", ent.Owner)));
|
||||
}
|
||||
}
|
||||
|
||||
private void OnGetAltVerbs(Entity<EnvelopeComponent> ent, ref GetVerbsEvent<AlternativeVerb> args)
|
||||
{
|
||||
if (!args.CanAccess || !args.CanInteract || args.Hands == null)
|
||||
return;
|
||||
|
||||
if (ent.Comp.State == EnvelopeComponent.EnvelopeState.Torn)
|
||||
return;
|
||||
|
||||
var user = args.User;
|
||||
args.Verbs.Add(new AlternativeVerb()
|
||||
{
|
||||
Text = Loc.GetString(ent.Comp.State == EnvelopeComponent.EnvelopeState.Open ? "envelope-verb-seal" : "envelope-verb-tear"),
|
||||
IconEntity = GetNetEntity(ent.Owner),
|
||||
Act = () =>
|
||||
{
|
||||
TryStartDoAfter(ent, user, ent.Comp.State == EnvelopeComponent.EnvelopeState.Open ? ent.Comp.SealDelay : ent.Comp.TearDelay);
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
private void OnInsertAttempt(Entity<EnvelopeComponent> ent, ref ItemSlotInsertAttemptEvent args)
|
||||
{
|
||||
args.Cancelled |= ent.Comp.State != EnvelopeComponent.EnvelopeState.Open;
|
||||
}
|
||||
|
||||
private void OnEjectAttempt(Entity<EnvelopeComponent> ent, ref ItemSlotEjectAttemptEvent args)
|
||||
{
|
||||
args.Cancelled |= ent.Comp.State == EnvelopeComponent.EnvelopeState.Sealed;
|
||||
}
|
||||
|
||||
private void TryStartDoAfter(Entity<EnvelopeComponent> ent, EntityUid user, TimeSpan delay)
|
||||
{
|
||||
if (ent.Comp.EnvelopeDoAfter.HasValue)
|
||||
return;
|
||||
|
||||
var doAfterEventArgs = new DoAfterArgs(EntityManager, user, delay, new EnvelopeDoAfterEvent(), ent.Owner, ent.Owner)
|
||||
{
|
||||
BreakOnDamage = true,
|
||||
NeedHand = true,
|
||||
BreakOnHandChange = true,
|
||||
MovementThreshold = 0.01f,
|
||||
DistanceThreshold = 1.0f,
|
||||
};
|
||||
|
||||
if (_doAfterSystem.TryStartDoAfter(doAfterEventArgs, out var doAfterId))
|
||||
ent.Comp.EnvelopeDoAfter = doAfterId;
|
||||
}
|
||||
private void OnDoAfter(Entity<EnvelopeComponent> ent, ref EnvelopeDoAfterEvent args)
|
||||
{
|
||||
ent.Comp.EnvelopeDoAfter = null;
|
||||
|
||||
if (args.Cancelled)
|
||||
return;
|
||||
|
||||
if (ent.Comp.State == EnvelopeComponent.EnvelopeState.Open)
|
||||
{
|
||||
_audioSystem.PlayPredicted(ent.Comp.SealSound, ent.Owner, args.User);
|
||||
ent.Comp.State = EnvelopeComponent.EnvelopeState.Sealed;
|
||||
Dirty(ent.Owner, ent.Comp);
|
||||
}
|
||||
else if (ent.Comp.State == EnvelopeComponent.EnvelopeState.Sealed)
|
||||
{
|
||||
_audioSystem.PlayPredicted(ent.Comp.TearSound, ent.Owner, args.User);
|
||||
ent.Comp.State = EnvelopeComponent.EnvelopeState.Torn;
|
||||
Dirty(ent.Owner, ent.Comp);
|
||||
|
||||
if (_itemSlotsSystem.TryGetSlot(ent.Owner, ent.Comp.SlotId, out var slotComp))
|
||||
_itemSlotsSystem.TryEjectToHands(ent.Owner, slotComp, args.User);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,6 +1,15 @@
|
|||
namespace Content.Shared.Power.EntitySystems;
|
||||
using Content.Shared.Examine;
|
||||
using Content.Shared.Power.Components;
|
||||
|
||||
namespace Content.Shared.Power.EntitySystems;
|
||||
|
||||
public abstract class SharedPowerReceiverSystem : EntitySystem
|
||||
{
|
||||
|
||||
protected string GetExamineText(bool powered)
|
||||
{
|
||||
return Loc.GetString("power-receiver-component-on-examine-main",
|
||||
("stateText", Loc.GetString(powered
|
||||
? "power-receiver-component-on-examine-powered"
|
||||
: "power-receiver-component-on-examine-unpowered")));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ public interface ISalvageMod
|
|||
/// <summary>
|
||||
/// Player-friendly version describing this modifier.
|
||||
/// </summary>
|
||||
string Description { get; }
|
||||
LocId Description { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Cost for difficulty modifiers.
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ public sealed partial class SalvageAirMod : IPrototype, IBiomeSpecificMod
|
|||
|
||||
/// <inheritdoc/>
|
||||
[DataField("desc")]
|
||||
public string Description { get; private set; } = string.Empty;
|
||||
public LocId Description { get; private set; } = string.Empty;
|
||||
|
||||
/// <inheritdoc/>
|
||||
[DataField("cost")]
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ public sealed partial class SalvageBiomeModPrototype : IPrototype, ISalvageMod
|
|||
{
|
||||
[IdDataField] public string ID { get; } = default!;
|
||||
|
||||
[DataField("desc")] public string Description { get; private set; } = string.Empty;
|
||||
[DataField("desc")] public LocId Description { get; private set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// Cost for difficulty modifiers.
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ public sealed partial class SalvageDungeonModPrototype : IPrototype, IBiomeSpeci
|
|||
{
|
||||
[IdDataField] public string ID { get; } = default!;
|
||||
|
||||
[DataField("desc")] public string Description { get; private set; } = string.Empty;
|
||||
[DataField("desc")] public LocId Description { get; private set; } = string.Empty;
|
||||
|
||||
/// <inheridoc/>
|
||||
[DataField("cost")]
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ public sealed partial class SalvageLightMod : IPrototype, IBiomeSpecificMod
|
|||
{
|
||||
[IdDataField] public string ID { get; } = default!;
|
||||
|
||||
[DataField("desc")] public string Description { get; private set; } = string.Empty;
|
||||
[DataField("desc")] public LocId Description { get; private set; } = string.Empty;
|
||||
|
||||
/// <inheritdoc/>
|
||||
[DataField("cost")]
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ public sealed partial class SalvageMod : IPrototype, ISalvageMod
|
|||
{
|
||||
[IdDataField] public string ID { get; } = default!;
|
||||
|
||||
[DataField("desc")] public string Description { get; private set; } = string.Empty;
|
||||
[DataField("desc")] public LocId Description { get; private set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// Cost for difficulty modifiers.
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ public sealed partial class SalvageTemperatureMod : IPrototype, IBiomeSpecificMo
|
|||
{
|
||||
[IdDataField] public string ID { get; } = default!;
|
||||
|
||||
[DataField("desc")] public string Description { get; private set; } = string.Empty;
|
||||
[DataField("desc")] public LocId Description { get; private set; } = string.Empty;
|
||||
|
||||
/// <inheritdoc/>
|
||||
[DataField("cost")]
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ public sealed partial class SalvageWeatherMod : IPrototype, IBiomeSpecificMod
|
|||
{
|
||||
[IdDataField] public string ID { get; } = default!;
|
||||
|
||||
[DataField("desc")] public string Description { get; private set; } = string.Empty;
|
||||
[DataField("desc")] public LocId Description { get; private set; } = string.Empty;
|
||||
|
||||
/// <inheritdoc/>
|
||||
[DataField("cost")]
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ public sealed partial class SalvageFactionPrototype : IPrototype
|
|||
{
|
||||
[IdDataField] public string ID { get; } = default!;
|
||||
|
||||
[DataField("desc")] public string Description { get; private set; } = string.Empty;
|
||||
[DataField("desc")] public LocId Description { get; private set; } = string.Empty;
|
||||
|
||||
[ViewVariables(VVAccess.ReadWrite), DataField("entries", required: true)]
|
||||
public List<SalvageMobEntry> MobGroups = new();
|
||||
|
|
|
|||
|
|
@ -55,18 +55,18 @@ public abstract partial class SharedSalvageSystem : EntitySystem
|
|||
|
||||
if (air.Description != string.Empty)
|
||||
{
|
||||
mods.Add(air.Description);
|
||||
mods.Add(Loc.GetString(air.Description));
|
||||
}
|
||||
|
||||
// only show the description if there is an atmosphere since wont matter otherwise
|
||||
if (temp.Description != string.Empty && !air.Space)
|
||||
{
|
||||
mods.Add(temp.Description);
|
||||
mods.Add(Loc.GetString(temp.Description));
|
||||
}
|
||||
|
||||
if (light.Description != string.Empty)
|
||||
{
|
||||
mods.Add(light.Description);
|
||||
mods.Add(Loc.GetString(light.Description));
|
||||
}
|
||||
|
||||
var duration = TimeSpan.FromSeconds(CfgManager.GetCVar(CCVars.SalvageExpeditionDuration));
|
||||
|
|
|
|||
|
|
@ -1,7 +1,9 @@
|
|||
namespace Content.Shared.Slippery
|
||||
using Robust.Shared.GameStates;
|
||||
|
||||
namespace Content.Shared.Slippery;
|
||||
|
||||
[RegisterComponent, NetworkedComponent]
|
||||
public sealed partial class NoSlipComponent : Component
|
||||
{
|
||||
[RegisterComponent]
|
||||
public sealed partial class NoSlipComponent : Component
|
||||
{
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,16 +16,14 @@ using Content.Shared.Tools.Systems;
|
|||
using Content.Shared.Verbs;
|
||||
using Content.Shared.Wall;
|
||||
using Content.Shared.Whitelist;
|
||||
using Robust.Shared.Audio;
|
||||
using Content.Shared.ActionBlocker;
|
||||
using Robust.Shared.Audio.Systems;
|
||||
using Robust.Shared.Containers;
|
||||
using Robust.Shared.GameStates;
|
||||
using Robust.Shared.Map;
|
||||
using Robust.Shared.Network;
|
||||
using Robust.Shared.Physics;
|
||||
using Robust.Shared.Physics.Components;
|
||||
using Robust.Shared.Physics.Systems;
|
||||
using Robust.Shared.Prototypes;
|
||||
using Robust.Shared.Timing;
|
||||
using Robust.Shared.Utility;
|
||||
|
||||
|
|
@ -47,6 +45,7 @@ public abstract class SharedEntityStorageSystem : EntitySystem
|
|||
[Dependency] protected readonly SharedTransformSystem TransformSystem = default!;
|
||||
[Dependency] private readonly WeldableSystem _weldable = default!;
|
||||
[Dependency] private readonly EntityWhitelistSystem _whitelistSystem = default!;
|
||||
[Dependency] private readonly ActionBlockerSystem _actionBlocker = default!;
|
||||
|
||||
public const string ContainerName = "entity_storage";
|
||||
|
||||
|
|
@ -132,6 +131,9 @@ public abstract class SharedEntityStorageSystem : EntitySystem
|
|||
if (!HasComp<HandsComponent>(args.Entity))
|
||||
return;
|
||||
|
||||
if (!_actionBlocker.CanMove(args.Entity))
|
||||
return;
|
||||
|
||||
if (_timing.CurTime < component.NextInternalOpenAttempt)
|
||||
return;
|
||||
|
||||
|
|
@ -139,9 +141,7 @@ public abstract class SharedEntityStorageSystem : EntitySystem
|
|||
Dirty(uid, component);
|
||||
|
||||
if (component.OpenOnMove)
|
||||
{
|
||||
TryOpenStorage(args.Entity, uid);
|
||||
}
|
||||
}
|
||||
|
||||
protected void OnFoldAttempt(EntityUid uid, SharedEntityStorageComponent component, ref FoldAttemptEvent args)
|
||||
|
|
|
|||
|
|
@ -150,8 +150,11 @@ public sealed class SwapTeleporterSystem : EntitySystem
|
|||
return;
|
||||
}
|
||||
|
||||
var (teleEnt, cont) = GetTeleportingEntity((uid, xform));
|
||||
var (otherTeleEnt, otherCont) = GetTeleportingEntity((linkedEnt, Transform(linkedEnt)));
|
||||
var teleEnt = GetTeleportingEntity((uid, xform));
|
||||
var otherTeleEnt = GetTeleportingEntity((linkedEnt, Transform(linkedEnt)));
|
||||
|
||||
_container.TryGetOuterContainer(teleEnt, Transform(teleEnt), out var cont);
|
||||
_container.TryGetOuterContainer(otherTeleEnt, Transform(otherTeleEnt), out var otherCont);
|
||||
|
||||
if (otherCont != null && !_container.CanInsert(teleEnt, otherCont) ||
|
||||
cont != null && !_container.CanInsert(otherTeleEnt, cont))
|
||||
|
|
@ -195,20 +198,18 @@ public sealed class SwapTeleporterSystem : EntitySystem
|
|||
DestroyLink(linked, user); // the linked one is shown globally
|
||||
}
|
||||
|
||||
private (EntityUid, BaseContainer?) GetTeleportingEntity(Entity<TransformComponent> ent)
|
||||
private EntityUid GetTeleportingEntity(Entity<TransformComponent> ent)
|
||||
{
|
||||
var parent = ent.Comp.ParentUid;
|
||||
if (_container.TryGetOuterContainer(ent, ent, out var container))
|
||||
parent = container.Owner;
|
||||
|
||||
if (HasComp<MapGridComponent>(parent) || HasComp<MapComponent>(parent))
|
||||
return (ent, container);
|
||||
return ent;
|
||||
|
||||
if (!_xformQuery.TryGetComponent(parent, out var parentXform) || parentXform.Anchored)
|
||||
return (ent, container);
|
||||
return ent;
|
||||
|
||||
if (!TryComp<PhysicsComponent>(parent, out var body) || body.BodyType == BodyType.Static)
|
||||
return (ent, container);
|
||||
return ent;
|
||||
|
||||
return GetTeleportingEntity((parent, parentXform));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -485,7 +485,7 @@ public abstract class SharedMeleeWeaponSystem : EntitySystem
|
|||
|
||||
var weapon = GetEntity(ev.Weapon);
|
||||
|
||||
Interaction.DoContactInteraction(weapon, target);
|
||||
// We skip weapon -> target interaction, as forensics system applies DNA on hit
|
||||
Interaction.DoContactInteraction(user, weapon);
|
||||
|
||||
// If the user is using a long-range weapon, this probably shouldn't be happening? But I'll interpret melee as a
|
||||
|
|
@ -616,7 +616,7 @@ public abstract class SharedMeleeWeaponSystem : EntitySystem
|
|||
// For stuff that cares about it being attacked.
|
||||
foreach (var target in targets)
|
||||
{
|
||||
Interaction.DoContactInteraction(weapon, target);
|
||||
// We skip weapon -> target interaction, as forensics system applies DNA on hit
|
||||
|
||||
// If the user is using a long-range weapon, this probably shouldn't be happening? But I'll interpret melee as a
|
||||
// somewhat messy scuffle. See also, light attacks.
|
||||
|
|
|
|||
|
|
@ -31,8 +31,6 @@ public abstract class SharedGrapplingGunSystem : EntitySystem
|
|||
|
||||
public const string GrapplingJoint = "grappling";
|
||||
|
||||
public const float ReelRate = 2.5f;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
|
|
@ -187,7 +185,7 @@ public abstract class SharedGrapplingGunSystem : EntitySystem
|
|||
}
|
||||
|
||||
// TODO: This should be on engine.
|
||||
distance.MaxLength = MathF.Max(distance.MinLength, distance.MaxLength - ReelRate * frameTime);
|
||||
distance.MaxLength = MathF.Max(distance.MinLength, distance.MaxLength - grappling.ReelRate * frameTime);
|
||||
distance.Length = MathF.Min(distance.MaxLength, distance.Length);
|
||||
|
||||
_physics.WakeBody(joint.BodyAUid);
|
||||
|
|
|
|||
|
|
@ -8,6 +8,12 @@ namespace Content.Shared.Weapons.Ranged.Components;
|
|||
[RegisterComponent, NetworkedComponent, AutoGenerateComponentState]
|
||||
public sealed partial class GrapplingGunComponent : Component
|
||||
{
|
||||
/// <summary>
|
||||
/// Hook's reeling force and speed - the higher the number, the faster the hook rewinds.
|
||||
/// </summary>
|
||||
[DataField, AutoNetworkedField]
|
||||
public float ReelRate = 2.5f;
|
||||
|
||||
[DataField("jointId"), AutoNetworkedField]
|
||||
public string Joint = string.Empty;
|
||||
|
||||
|
|
|
|||
|
|
@ -367,5 +367,16 @@ Entries:
|
|||
id: 45
|
||||
time: '2024-07-11T05:14:01.0000000+00:00'
|
||||
url: https://github.com/space-wizards/space-station-14/pull/29896
|
||||
- author: Repo
|
||||
changes:
|
||||
- message: Added aHelp player pinning.
|
||||
type: Add
|
||||
- message: Added disconnection, reconnection, banning notice on relay and ahelp.
|
||||
type: Add
|
||||
- message: Fixed search clears on aHelp close.
|
||||
type: Fix
|
||||
id: 46
|
||||
time: '2024-07-30T08:28:32.0000000+00:00'
|
||||
url: https://github.com/space-wizards/space-station-14/pull/28639
|
||||
Name: Admin
|
||||
Order: 1
|
||||
|
|
|
|||
|
|
@ -1,202 +1,4 @@
|
|||
Entries:
|
||||
- author: MilenVolf
|
||||
changes:
|
||||
- message: Borgs now have brand new voice and walking sounds.
|
||||
type: Add
|
||||
- message: Syndicate assault borgs now have new feature to scare - manic laugher.
|
||||
type: Add
|
||||
id: 6491
|
||||
time: '2024-04-29T04:38:31.0000000+00:00'
|
||||
url: https://github.com/space-wizards/space-station-14/pull/27205
|
||||
- author: KrasnoshchekovPavel
|
||||
changes:
|
||||
- message: Fixed formatting of floating point numbers during localization
|
||||
type: Fix
|
||||
id: 6492
|
||||
time: '2024-04-29T04:52:35.0000000+00:00'
|
||||
url: https://github.com/space-wizards/space-station-14/pull/27441
|
||||
- author: mirrorcult
|
||||
changes:
|
||||
- message: Random events should now occur much more frequently
|
||||
type: Tweak
|
||||
id: 6493
|
||||
time: '2024-04-29T06:38:15.0000000+00:00'
|
||||
url: https://github.com/space-wizards/space-station-14/pull/27469
|
||||
- author: Plykiya
|
||||
changes:
|
||||
- message: Latejoin players now have a chance to roll thief.
|
||||
type: Add
|
||||
id: 6494
|
||||
time: '2024-04-29T06:38:38.0000000+00:00'
|
||||
url: https://github.com/space-wizards/space-station-14/pull/27466
|
||||
- author: ElectroJr
|
||||
changes:
|
||||
- message: Fixed actions sometimes disappearing from the hotbar when double clicking
|
||||
type: Fix
|
||||
id: 6495
|
||||
time: '2024-04-29T08:36:18.0000000+00:00'
|
||||
url: https://github.com/space-wizards/space-station-14/pull/27468
|
||||
- author: DrSmugleaf
|
||||
changes:
|
||||
- message: Fixed bullets not going exactly where you click when moving.
|
||||
type: Fix
|
||||
id: 6496
|
||||
time: '2024-04-29T13:12:30.0000000+00:00'
|
||||
url: https://github.com/space-wizards/space-station-14/pull/27484
|
||||
- author: FungiFellow
|
||||
changes:
|
||||
- message: Syndi-Cats now have a Wideswing, 80% Explosion Resist, 6/6/15 Pierce/Slash/Structural
|
||||
and step over glass shards with trained feline agility.
|
||||
type: Tweak
|
||||
id: 6497
|
||||
time: '2024-04-29T17:09:30.0000000+00:00'
|
||||
url: https://github.com/space-wizards/space-station-14/pull/27408
|
||||
- author: ShadowCommander
|
||||
changes:
|
||||
- message: Fixed microwave construction not creating a microwave on completion.
|
||||
type: Fix
|
||||
id: 6498
|
||||
time: '2024-04-30T00:19:08.0000000+00:00'
|
||||
url: https://github.com/space-wizards/space-station-14/pull/27500
|
||||
- author: lzk228
|
||||
changes:
|
||||
- message: Barozine is removed from hydroponics mutatuions.
|
||||
type: Remove
|
||||
id: 6499
|
||||
time: '2024-04-30T03:01:38.0000000+00:00'
|
||||
url: https://github.com/space-wizards/space-station-14/pull/27512
|
||||
- author: DogZeroX
|
||||
changes:
|
||||
- message: Changed the announcement of the immovable rod event.
|
||||
type: Tweak
|
||||
id: 6500
|
||||
time: '2024-04-30T04:05:14.0000000+00:00'
|
||||
url: https://github.com/space-wizards/space-station-14/pull/27515
|
||||
- author: DogZeroX
|
||||
changes:
|
||||
- message: Flares looped sound no longer have a massive range, and are much quieter.
|
||||
type: Fix
|
||||
id: 6501
|
||||
time: '2024-04-30T06:49:35.0000000+00:00'
|
||||
url: https://github.com/space-wizards/space-station-14/pull/27521
|
||||
- author: ERORR404V1
|
||||
changes:
|
||||
- message: Added chameleon projector in thief toolbox!
|
||||
type: Add
|
||||
id: 6502
|
||||
time: '2024-04-30T12:14:06.0000000+00:00'
|
||||
url: https://github.com/space-wizards/space-station-14/pull/27491
|
||||
- author: DamnFeds
|
||||
changes:
|
||||
- message: honkbot now uses a happy honk meal instead of box of hugs and clown's
|
||||
rubber stamp. Honk!
|
||||
type: Tweak
|
||||
id: 6503
|
||||
time: '2024-05-01T03:27:21.0000000+00:00'
|
||||
url: https://github.com/space-wizards/space-station-14/pull/27535
|
||||
- author: Plykiya
|
||||
changes:
|
||||
- message: Inserting telecrystals no longer announces to everyone around you that
|
||||
you inserted it.
|
||||
type: Tweak
|
||||
id: 6504
|
||||
time: '2024-05-01T15:17:47.0000000+00:00'
|
||||
url: https://github.com/space-wizards/space-station-14/pull/27585
|
||||
- author: Dezzzix
|
||||
changes:
|
||||
- message: Goldschlager empty bottle renamed to Gildlager empty bottle
|
||||
type: Tweak
|
||||
id: 6505
|
||||
time: '2024-05-01T15:24:05.0000000+00:00'
|
||||
url: https://github.com/space-wizards/space-station-14/pull/27581
|
||||
- author: FungiFellow
|
||||
changes:
|
||||
- message: Grilles now take Structural Damage
|
||||
type: Tweak
|
||||
id: 6506
|
||||
time: '2024-05-01T22:23:42.0000000+00:00'
|
||||
url: https://github.com/space-wizards/space-station-14/pull/27596
|
||||
- author: lzk228
|
||||
changes:
|
||||
- message: Immovable rod announce now happens at the end of event.
|
||||
type: Tweak
|
||||
id: 6507
|
||||
time: '2024-05-01T22:26:22.0000000+00:00'
|
||||
url: https://github.com/space-wizards/space-station-14/pull/27587
|
||||
- author: metalgearsloth
|
||||
changes:
|
||||
- message: Fix server performance dropping significantly.
|
||||
type: Fix
|
||||
id: 6508
|
||||
time: '2024-05-02T00:18:38.0000000+00:00'
|
||||
url: https://github.com/space-wizards/space-station-14/pull/27528
|
||||
- author: metalgearsloth
|
||||
changes:
|
||||
- message: Fix muzzle flash rotations.
|
||||
type: Fix
|
||||
- message: Fix large client performance drop.
|
||||
type: Fix
|
||||
id: 6509
|
||||
time: '2024-05-02T02:40:07.0000000+00:00'
|
||||
url: https://github.com/space-wizards/space-station-14/pull/27533
|
||||
- author: ElectroJr
|
||||
changes:
|
||||
- message: Fix gas analyzers not opening their UI when used in-hand.
|
||||
type: Fix
|
||||
id: 6510
|
||||
time: '2024-05-02T06:00:01.0000000+00:00'
|
||||
url: https://github.com/space-wizards/space-station-14/pull/27610
|
||||
- author: Plykiya
|
||||
changes:
|
||||
- message: Disarming a player now causes them to throw the disarmed item away from
|
||||
them.
|
||||
type: Tweak
|
||||
id: 6511
|
||||
time: '2024-05-02T12:32:47.0000000+00:00'
|
||||
url: https://github.com/space-wizards/space-station-14/pull/27589
|
||||
- author: fujiwaranao
|
||||
changes:
|
||||
- message: Renault now has additional fox noises.
|
||||
type: Add
|
||||
id: 6512
|
||||
time: '2024-05-02T12:35:11.0000000+00:00'
|
||||
url: https://github.com/space-wizards/space-station-14/pull/27578
|
||||
- author: Doc-Michael
|
||||
changes:
|
||||
- message: CMO's Lab coat is now more resistant to chemical spills and minor cuts
|
||||
type: Tweak
|
||||
id: 6513
|
||||
time: '2024-05-02T12:37:12.0000000+00:00'
|
||||
url: https://github.com/space-wizards/space-station-14/pull/27551
|
||||
- author: Vasilis
|
||||
changes:
|
||||
- message: Removed airtight flaps from the construction menu.
|
||||
type: Remove
|
||||
id: 6514
|
||||
time: '2024-05-02T14:49:54.0000000+00:00'
|
||||
url: https://github.com/space-wizards/space-station-14/pull/27619
|
||||
- author: Lamrr
|
||||
changes:
|
||||
- message: Wine and beer bottles can now be inserted into the booze dispenser.
|
||||
type: Fix
|
||||
id: 6515
|
||||
time: '2024-05-02T16:17:36.0000000+00:00'
|
||||
url: https://github.com/space-wizards/space-station-14/pull/27626
|
||||
- author: deltanedas
|
||||
changes:
|
||||
- message: "Ducky slippers now make you waddle. \U0001F986\U0001F986"
|
||||
type: Tweak
|
||||
id: 6516
|
||||
time: '2024-05-02T17:09:38.0000000+00:00'
|
||||
url: https://github.com/space-wizards/space-station-14/pull/27628
|
||||
- author: ElectroJr
|
||||
changes:
|
||||
- message: Fixed various interactions not prioritizing opening a UI. No more trying
|
||||
to eat mission critical faxes.
|
||||
type: Fix
|
||||
id: 6517
|
||||
time: '2024-05-02T23:37:21.0000000+00:00'
|
||||
url: https://github.com/space-wizards/space-station-14/pull/27631
|
||||
- author: Plykiya
|
||||
changes:
|
||||
- message: Blast grenades have had their manufacturing cost tripled.
|
||||
|
|
@ -3781,3 +3583,205 @@
|
|||
id: 6990
|
||||
time: '2024-07-27T07:27:21.0000000+00:00'
|
||||
url: https://github.com/space-wizards/space-station-14/pull/30393
|
||||
- author: BombasterDS
|
||||
changes:
|
||||
- message: Added new plant mutations for apple, sugarcane and galaxythistle
|
||||
type: Add
|
||||
id: 6991
|
||||
time: '2024-07-27T15:08:49.0000000+00:00'
|
||||
url: https://github.com/space-wizards/space-station-14/pull/28993
|
||||
- author: Spessmann
|
||||
changes:
|
||||
- message: Thief objectives for figurines and stamps now require less items
|
||||
type: Tweak
|
||||
id: 6992
|
||||
time: '2024-07-27T23:11:27.0000000+00:00'
|
||||
url: https://github.com/space-wizards/space-station-14/pull/30390
|
||||
- author: metalgearsloth
|
||||
changes:
|
||||
- message: Moved VGRoid from 1,000m away to ~500m.
|
||||
type: Tweak
|
||||
id: 6993
|
||||
time: '2024-07-28T03:14:18.0000000+00:00'
|
||||
url: https://github.com/space-wizards/space-station-14/pull/29943
|
||||
- author: lzk228
|
||||
changes:
|
||||
- message: Fixed pancakes stacks. Before it, splitting not default pancakes stacks
|
||||
would give you default pancakes.
|
||||
type: Fix
|
||||
id: 6994
|
||||
time: '2024-07-28T03:49:06.0000000+00:00'
|
||||
url: https://github.com/space-wizards/space-station-14/pull/30270
|
||||
- author: Plykiya
|
||||
changes:
|
||||
- message: Fixed the client mispredicting people slipping with their magboots turned
|
||||
on
|
||||
type: Fix
|
||||
id: 6995
|
||||
time: '2024-07-28T06:17:06.0000000+00:00'
|
||||
url: https://github.com/space-wizards/space-station-14/pull/30425
|
||||
- author: Katzenminer
|
||||
changes:
|
||||
- message: Pun and similar pets are no longer firemune
|
||||
type: Fix
|
||||
id: 6996
|
||||
time: '2024-07-28T08:32:27.0000000+00:00'
|
||||
url: https://github.com/space-wizards/space-station-14/pull/30424
|
||||
- author: lzk228
|
||||
changes:
|
||||
- message: Fixed permanent absence of the approver string in cargo invoice.
|
||||
type: Fix
|
||||
id: 6997
|
||||
time: '2024-07-29T06:19:43.0000000+00:00'
|
||||
url: https://github.com/space-wizards/space-station-14/pull/29690
|
||||
- author: JIPDawg
|
||||
changes:
|
||||
- message: F9 is correctly bound to the Round End Summary window by default now.
|
||||
type: Fix
|
||||
id: 6998
|
||||
time: '2024-07-29T06:49:28.0000000+00:00'
|
||||
url: https://github.com/space-wizards/space-station-14/pull/30438
|
||||
- author: githubuser508
|
||||
changes:
|
||||
- message: Candles crate and the ability for Cargo to order it.
|
||||
type: Add
|
||||
id: 6999
|
||||
time: '2024-07-29T08:29:27.0000000+00:00'
|
||||
url: https://github.com/space-wizards/space-station-14/pull/29736
|
||||
- author: Blackern5000
|
||||
changes:
|
||||
- message: Emergency oxygen and fire lockers now generally contain more supplies
|
||||
type: Tweak
|
||||
id: 7000
|
||||
time: '2024-07-29T09:57:04.0000000+00:00'
|
||||
url: https://github.com/space-wizards/space-station-14/pull/29230
|
||||
- author: Moomoobeef
|
||||
changes:
|
||||
- message: Added the ability to wear lizard plushies on your head!
|
||||
type: Add
|
||||
id: 7001
|
||||
time: '2024-07-29T12:52:40.0000000+00:00'
|
||||
url: https://github.com/space-wizards/space-station-14/pull/30400
|
||||
- author: TurboTrackerss14
|
||||
changes:
|
||||
- message: Reduced Kobold ghostrole chance to mirror Monkey
|
||||
type: Tweak
|
||||
id: 7002
|
||||
time: '2024-07-29T15:16:54.0000000+00:00'
|
||||
url: https://github.com/space-wizards/space-station-14/pull/30450
|
||||
- author: Ian321
|
||||
changes:
|
||||
- message: The Courser now comes with a defibrillator.
|
||||
type: Tweak
|
||||
id: 7003
|
||||
time: '2024-07-30T01:05:27.0000000+00:00'
|
||||
url: https://github.com/space-wizards/space-station-14/pull/30471
|
||||
- author: slarticodefast
|
||||
changes:
|
||||
- message: Fixed puppy Ian not counting as a thief steal target.
|
||||
type: Fix
|
||||
id: 7004
|
||||
time: '2024-07-30T01:22:17.0000000+00:00'
|
||||
url: https://github.com/space-wizards/space-station-14/pull/30474
|
||||
- author: themias
|
||||
changes:
|
||||
- message: Added envelopes to the PTech and bureaucracy crate
|
||||
type: Add
|
||||
id: 7005
|
||||
time: '2024-07-30T01:49:05.0000000+00:00'
|
||||
url: https://github.com/space-wizards/space-station-14/pull/30298
|
||||
- author: TheKittehJesus
|
||||
changes:
|
||||
- message: The recipe for chow mein, egg-fried rice, and both brownies now use liquid
|
||||
egg instead of a whole egg.
|
||||
type: Tweak
|
||||
- message: Cake batter now also requires 5u of milk
|
||||
type: Tweak
|
||||
id: 7006
|
||||
time: '2024-07-30T02:14:11.0000000+00:00'
|
||||
url: https://github.com/space-wizards/space-station-14/pull/30262
|
||||
- author: Plykiya
|
||||
changes:
|
||||
- message: Wearing something that covers your head will prevent your hair from being
|
||||
cut.
|
||||
type: Add
|
||||
- message: You now see a popup when your hair is being altered.
|
||||
type: Add
|
||||
- message: The doafter for altering other people's hair now takes seven seconds.
|
||||
type: Tweak
|
||||
id: 7007
|
||||
time: '2024-07-30T02:17:28.0000000+00:00'
|
||||
url: https://github.com/space-wizards/space-station-14/pull/30366
|
||||
- author: Cojoke-dot
|
||||
changes:
|
||||
- message: Hamlet and other ghost rolls can now spin when they enter combat mode
|
||||
type: Fix
|
||||
id: 7008
|
||||
time: '2024-07-30T02:48:28.0000000+00:00'
|
||||
url: https://github.com/space-wizards/space-station-14/pull/30478
|
||||
- author: themias
|
||||
changes:
|
||||
- message: Fixed the ACC wire not appearing in vending machine wire layouts
|
||||
type: Fix
|
||||
id: 7009
|
||||
time: '2024-07-30T03:04:17.0000000+00:00'
|
||||
url: https://github.com/space-wizards/space-station-14/pull/30453
|
||||
- author: Blackern5000
|
||||
changes:
|
||||
- message: The defibrillator has been recolored slightly
|
||||
type: Tweak
|
||||
id: 7010
|
||||
time: '2024-07-30T04:41:21.0000000+00:00'
|
||||
url: https://github.com/space-wizards/space-station-14/pull/29964
|
||||
- author: themias
|
||||
changes:
|
||||
- message: Fixed victim's fingerprints transferring onto an attacker's weapon
|
||||
type: Fix
|
||||
id: 7011
|
||||
time: '2024-07-30T08:35:30.0000000+00:00'
|
||||
url: https://github.com/space-wizards/space-station-14/pull/30257
|
||||
- author: to4no_fix
|
||||
changes:
|
||||
- message: Now engineering access is needed to interact with the particle accelerator
|
||||
type: Tweak
|
||||
id: 7012
|
||||
time: '2024-07-30T11:29:32.0000000+00:00'
|
||||
url: https://github.com/space-wizards/space-station-14/pull/30394
|
||||
- author: Cojoke-dot
|
||||
changes:
|
||||
- message: You can no longer get out of a disposal chute or container while knocked
|
||||
over by trying to walk
|
||||
type: Fix
|
||||
id: 7013
|
||||
time: '2024-07-30T13:53:44.0000000+00:00'
|
||||
url: https://github.com/space-wizards/space-station-14/pull/30391
|
||||
- author: Cojoke-dot
|
||||
changes:
|
||||
- message: QSI now swaps the top most valid container instead of QSI when placed
|
||||
in an anchored container
|
||||
type: Fix
|
||||
id: 7014
|
||||
time: '2024-07-30T14:07:35.0000000+00:00'
|
||||
url: https://github.com/space-wizards/space-station-14/pull/30241
|
||||
- author: TheShuEd
|
||||
changes:
|
||||
- message: industrial ore processor can now process diamonds
|
||||
type: Fix
|
||||
id: 7015
|
||||
time: '2024-07-30T14:41:15.0000000+00:00'
|
||||
url: https://github.com/space-wizards/space-station-14/pull/30499
|
||||
- author: PJB3005
|
||||
changes:
|
||||
- message: CLF3 is now called "chlorine trifluoride"
|
||||
type: Tweak
|
||||
id: 7016
|
||||
time: '2024-07-31T00:14:23.0000000+00:00'
|
||||
url: https://github.com/space-wizards/space-station-14/pull/30510
|
||||
- author: slarticodefast
|
||||
changes:
|
||||
- message: Fixed the mouse position when it is over a singularity distortion effect
|
||||
while zoomed in or out.
|
||||
type: Fix
|
||||
id: 7017
|
||||
time: '2024-07-31T00:14:49.0000000+00:00'
|
||||
url: https://github.com/space-wizards/space-station-14/pull/30509
|
||||
|
|
|
|||
File diff suppressed because one or more lines are too long
1
Resources/Locale/en-US/actions/actions/polymorph.ftl
Normal file
1
Resources/Locale/en-US/actions/actions/polymorph.ftl
Normal file
|
|
@ -0,0 +1 @@
|
|||
gera-transformation-popup = This action will transform you. Use it again to confirm.
|
||||
|
|
@ -16,3 +16,6 @@ admin-bwoink-play-sound = Bwoink?
|
|||
bwoink-title-none-selected = None selected
|
||||
|
||||
bwoink-system-rate-limited = System: you are sending messages too quickly.
|
||||
bwoink-system-player-disconnecting = has disconnected.
|
||||
bwoink-system-player-reconnecting = has reconnected.
|
||||
bwoink-system-player-banned = has been banned for: {$banReason}
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@ cargo-console-snip-snip = Order trimmed to capacity
|
|||
cargo-console-insufficient-funds = Insufficient funds (require {$cost})
|
||||
cargo-console-unfulfilled = No room to fulfill order
|
||||
cargo-console-trade-station = Sent to {$destination}
|
||||
cargo-console-unlock-approved-order-broadcast = [bold]{$productName} x{$orderAmount}[/bold], which cost [bold]{$cost}[/bold], was approved by [bold]{$approverName}, {$approverJob}[/bold]
|
||||
cargo-console-unlock-approved-order-broadcast = [bold]{$productName} x{$orderAmount}[/bold], which cost [bold]{$cost}[/bold], was approved by [bold]{$approver}[/bold]
|
||||
|
||||
cargo-console-paper-print-name = Order #{$orderNumber}
|
||||
cargo-console-paper-print-text =
|
||||
|
|
|
|||
|
|
@ -1,3 +1,15 @@
|
|||
magic-mirror-component-activate-user-has-no-hair = You can't have any hair!
|
||||
|
||||
magic-mirror-window-title = Magic Mirror
|
||||
magic-mirror-window-title = Magic Mirror
|
||||
magic-mirror-add-slot-self = You're giving yourself some hair.
|
||||
magic-mirror-remove-slot-self = You're removing some of your hair.
|
||||
magic-mirror-change-slot-self = You're changing your hairstyle.
|
||||
magic-mirror-change-color-self = You're changing your hair color.
|
||||
|
||||
magic-mirror-add-slot-target = Hair is being added to you by {$user}.
|
||||
magic-mirror-remove-slot-target = Your hair is being cut off by {$user}.
|
||||
magic-mirror-change-slot-target = Your hairstyle is being changed by {$user}.
|
||||
magic-mirror-change-color-target = Your hair color is being changed by {$user}.
|
||||
|
||||
magic-mirror-blocked-by-hat-self = You need to take off your hat before changing your hair.
|
||||
magic-mirror-blocked-by-hat-self-target = You try to change their hair but their clothes gets in the way.
|
||||
|
|
|
|||
|
|
@ -6,6 +6,6 @@ examine-system-cant-see-entity = You can't make out whatever that is.
|
|||
|
||||
examine-verb-name = Basic
|
||||
|
||||
examinable-anchored = It is [color=darkgreen]anchored[/color] to the floor
|
||||
examinable-anchored = It is [color=darkgreen]anchored[/color] to the floor.
|
||||
|
||||
examinable-unanchored = It is [color=darkred]unanchored[/color] from the floor
|
||||
examinable-unanchored = It is [color=darkred]unanchored[/color] from the floor.
|
||||
|
|
|
|||
11
Resources/Locale/en-US/paper/envelope.ftl
Normal file
11
Resources/Locale/en-US/paper/envelope.ftl
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
envelope-verb-seal = Seal
|
||||
envelope-verb-tear = Tear
|
||||
|
||||
envelope-letter-slot = Letter
|
||||
|
||||
envelope-sealed-examine = [color=gray]{CAPITALIZE(THE($envelope))} is sealed.[/color]
|
||||
envelope-torn-examine = [color=yellow]{CAPITALIZE(THE($envelope))} is torn and unusable![/color]
|
||||
|
||||
envelope-default-message = TO:
|
||||
|
||||
FROM:
|
||||
|
|
@ -32,3 +32,34 @@ salvage-expedition-announcement-countdown-seconds = {$duration} seconds remainin
|
|||
salvage-expedition-announcement-dungeon = Dungeon is located {$direction}.
|
||||
salvage-expedition-completed = Expedition is completed.
|
||||
salvage-expedition-reward-description = Mission completion reward
|
||||
|
||||
# Salvage biome mod
|
||||
salvage-biome-mod-caves = Caves
|
||||
salvage-biome-mod-grasslands = Grasslands
|
||||
salvage-biome-mod-snow = Snow
|
||||
salvage-biome-mod-lava = Lava
|
||||
|
||||
# Salvage mods
|
||||
salvage-light-mod-daylight = Daylight
|
||||
salvage-light-mod-evening = Evening
|
||||
salvage-light-mod-night = Night time
|
||||
|
||||
salvage-temperature-mod-room-temperature = Room temperature
|
||||
salvage-temperature-mod-hot = Hot
|
||||
salvage-temperature-mod-high-temperature = High temperature
|
||||
salvage-temperature-mod-extreme-heat = Extreme heat
|
||||
salvage-temperature-mod-cold = Cold
|
||||
salvage-temperature-mod-low-temperature = Low temperature
|
||||
salvage-temperature-mod-extreme-cold = Extreme cold
|
||||
|
||||
salvage-air-mod-no-atmosphere = No atmosphere
|
||||
salvage-air-mod-breathable-atmosphere = Breathable atmosphere
|
||||
salvage-air-mod-dangerous-atmosphere = Dangerous atmosphere
|
||||
salvage-air-mod-toxic-atmosphere = Toxic atmosphere
|
||||
salvage-air-mod-volatile-atmosphere = Volatile atmosphere
|
||||
|
||||
salvage-dungeon-mod-lava-brig = Lava Brig
|
||||
salvage-dungeon-mod-snowy-labs = Snowy labs
|
||||
salvage-dungeon-mod-experiment = Experiment
|
||||
salvage-dungeon-mod-haunted = Haunted
|
||||
salvage-dungeon-mod-mineshaft = Mineshaft
|
||||
|
|
|
|||
2
Resources/Locale/en-US/procedural/salvage-faction.ftl
Normal file
2
Resources/Locale/en-US/procedural/salvage-faction.ftl
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
salvage-faction-xenos = Xenos
|
||||
salvage-faction-carps = Carps
|
||||
|
|
@ -7,7 +7,7 @@ reagent-desc-napalm = It's just a little flammable.
|
|||
reagent-name-phlogiston = phlogiston
|
||||
reagent-desc-phlogiston = Catches you on fire and makes you ignite.
|
||||
|
||||
reagent-name-chlorine-trifluoride = CLF3
|
||||
reagent-name-chlorine-trifluoride = chlorine trifluoride
|
||||
reagent-desc-chlorine-trifluoride = You really, REALLY don't want to get this shit anywhere near you.
|
||||
|
||||
reagent-name-foaming-agent = foaming agent
|
||||
|
|
|
|||
|
|
@ -32,6 +32,8 @@ seeds-potato-name = potato
|
|||
seeds-potato-display-name = potatoes
|
||||
seeds-sugarcane-name = sugarcane
|
||||
seeds-sugarcane-display-name = sugarcanes
|
||||
seeds-papercane-name = papercane
|
||||
seeds-papercane-display-name = papercanes
|
||||
seeds-towercap-name = tower cap
|
||||
seeds-towercap-display-name = tower caps
|
||||
seeds-steelcap-name = steel cap
|
||||
|
|
@ -48,6 +50,8 @@ seeds-eggplant-name = eggplant
|
|||
seeds-eggplant-display-name = eggplants
|
||||
seeds-apple-name = apple
|
||||
seeds-apple-display-name = apple tree
|
||||
seeds-goldenapple-name = golden apple
|
||||
seeds-goldenapple-display-name = golden apple tree
|
||||
seeds-corn-name = corn
|
||||
seeds-corn-display-name = ears of corn
|
||||
seeds-onion-name = onion
|
||||
|
|
@ -88,6 +92,8 @@ seeds-ambrosiadeus-name = ambrosia deus
|
|||
seeds-ambrosiadeus-display-name = ambrosia deus
|
||||
seeds-galaxythistle-name = galaxythistle
|
||||
seeds-galaxythistle-display-name = galaxythistle
|
||||
seeds-glasstle-name = glasstle
|
||||
seeds-glasstle-display-name = glasstle
|
||||
seeds-flyamanita-name = fly amanita
|
||||
seeds-flyamanita-display-name = fly amanita
|
||||
seeds-gatfruit-name = gatfruit
|
||||
|
|
|
|||
|
|
@ -362,85 +362,96 @@ entities:
|
|||
version: 2
|
||||
data:
|
||||
tiles:
|
||||
-2,-1:
|
||||
0: 61166
|
||||
-1,-1:
|
||||
0: 65535
|
||||
0,-1:
|
||||
0: 65535
|
||||
-2,-3:
|
||||
0: 60620
|
||||
0: 8192
|
||||
1: 34944
|
||||
-2,-2:
|
||||
0: 61102
|
||||
1: 64
|
||||
1: 52936
|
||||
-2,-1:
|
||||
1: 52430
|
||||
-2,-4:
|
||||
0: 51328
|
||||
-1,-4:
|
||||
0: 57343
|
||||
1: 8192
|
||||
-1,-3:
|
||||
0: 65535
|
||||
-1,-2:
|
||||
0: 49151
|
||||
1: 16384
|
||||
0,-4:
|
||||
0: 65535
|
||||
0,-3:
|
||||
0: 65535
|
||||
0,-2:
|
||||
0: 65535
|
||||
1,-4:
|
||||
0: 12560
|
||||
1,-3:
|
||||
0: 29491
|
||||
1,-2:
|
||||
0: 30551
|
||||
1: 32
|
||||
1,-1:
|
||||
0: 30583
|
||||
0: 16512
|
||||
-2,0:
|
||||
0: 61166
|
||||
-2,1:
|
||||
0: 61102
|
||||
1: 64
|
||||
-2,2:
|
||||
0: 52300
|
||||
1: 128
|
||||
-2,3:
|
||||
0: 136
|
||||
-1,0:
|
||||
0: 65535
|
||||
-1,1:
|
||||
0: 49151
|
||||
1: 16384
|
||||
-1,2:
|
||||
0: 65535
|
||||
-1,3:
|
||||
0: 61439
|
||||
0,0:
|
||||
0: 65535
|
||||
0,1:
|
||||
0: 57343
|
||||
1: 8192
|
||||
0,2:
|
||||
0: 65535
|
||||
0,3:
|
||||
0: 32767
|
||||
1,0:
|
||||
0: 30583
|
||||
1,1:
|
||||
0: 30551
|
||||
1: 32
|
||||
1,2:
|
||||
0: 13091
|
||||
1: 16
|
||||
1,3:
|
||||
0: 17
|
||||
1: 52940
|
||||
-1,-4:
|
||||
1: 65260
|
||||
-1,-3:
|
||||
1: 65372
|
||||
-1,-2:
|
||||
1: 57297
|
||||
-1,-1:
|
||||
1: 65489
|
||||
-1,-5:
|
||||
0: 61440
|
||||
0: 4096
|
||||
-1,0:
|
||||
1: 8191
|
||||
0,-4:
|
||||
1: 63347
|
||||
0,-3:
|
||||
1: 65443
|
||||
0,-2:
|
||||
1: 49080
|
||||
0,-1:
|
||||
1: 65464
|
||||
0,0:
|
||||
1: 36863
|
||||
0,-5:
|
||||
0: 61440
|
||||
0: 32768
|
||||
1,-4:
|
||||
0: 8208
|
||||
1,-3:
|
||||
1: 4368
|
||||
0: 16384
|
||||
1,-2:
|
||||
1: 14129
|
||||
1,-1:
|
||||
1: 13111
|
||||
1,0:
|
||||
1: 14131
|
||||
-2,1:
|
||||
1: 35022
|
||||
0: 8192
|
||||
-2,2:
|
||||
1: 136
|
||||
0: 16384
|
||||
-1,1:
|
||||
1: 56829
|
||||
-1,2:
|
||||
1: 62705
|
||||
-2,3:
|
||||
0: 128
|
||||
-1,3:
|
||||
1: 3310
|
||||
0,1:
|
||||
1: 48123
|
||||
0,2:
|
||||
1: 62200
|
||||
0,3:
|
||||
1: 887
|
||||
1,1:
|
||||
1: 4407
|
||||
0: 16384
|
||||
1,2:
|
||||
1: 17
|
||||
0: 8192
|
||||
1,3:
|
||||
0: 16
|
||||
uniqueMixes:
|
||||
- volume: 2500
|
||||
immutable: True
|
||||
moles:
|
||||
- 0
|
||||
- 0
|
||||
- 0
|
||||
- 0
|
||||
- 0
|
||||
- 0
|
||||
- 0
|
||||
- 0
|
||||
- 0
|
||||
- 0
|
||||
- 0
|
||||
- 0
|
||||
- volume: 2500
|
||||
temperature: 293.15
|
||||
moles:
|
||||
|
|
@ -456,21 +467,6 @@ entities:
|
|||
- 0
|
||||
- 0
|
||||
- 0
|
||||
- volume: 2500
|
||||
temperature: 293.15
|
||||
moles:
|
||||
- 19.481253
|
||||
- 73.28662
|
||||
- 0
|
||||
- 0
|
||||
- 0
|
||||
- 0
|
||||
- 0
|
||||
- 0
|
||||
- 0
|
||||
- 0
|
||||
- 0
|
||||
- 0
|
||||
chunkSize: 4
|
||||
- type: RadiationGridResistance
|
||||
- type: GravityShake
|
||||
|
|
@ -485,8 +481,6 @@ entities:
|
|||
- type: Transform
|
||||
pos: 0.5,-12.5
|
||||
parent: 656
|
||||
- type: AtmosDevice
|
||||
joinedGrid: 656
|
||||
- proto: AirlockCommandGlassLocked
|
||||
entities:
|
||||
- uid: 601
|
||||
|
|
@ -2023,6 +2017,14 @@ entities:
|
|||
- type: Transform
|
||||
pos: 0.5,14.5
|
||||
parent: 656
|
||||
- proto: DefibrillatorCabinetFilled
|
||||
entities:
|
||||
- uid: 657
|
||||
components:
|
||||
- type: Transform
|
||||
rot: 1.5707963267948966 rad
|
||||
pos: -2.5,-6.5
|
||||
parent: 656
|
||||
- proto: ExtinguisherCabinetFilled
|
||||
entities:
|
||||
- uid: 517
|
||||
|
|
@ -2176,8 +2178,6 @@ entities:
|
|||
- type: Transform
|
||||
pos: 0.5,-11.5
|
||||
parent: 656
|
||||
- type: AtmosDevice
|
||||
joinedGrid: 656
|
||||
- proto: GasPassiveVent
|
||||
entities:
|
||||
- uid: 521
|
||||
|
|
@ -2186,8 +2186,6 @@ entities:
|
|||
rot: -1.5707963267948966 rad
|
||||
pos: -0.5,-11.5
|
||||
parent: 656
|
||||
- type: AtmosDevice
|
||||
joinedGrid: 656
|
||||
- proto: GasPipeBend
|
||||
entities:
|
||||
- uid: 523
|
||||
|
|
@ -2536,8 +2534,6 @@ entities:
|
|||
rot: 3.141592653589793 rad
|
||||
pos: 0.5,-12.5
|
||||
parent: 656
|
||||
- type: AtmosDevice
|
||||
joinedGrid: 656
|
||||
- proto: GasVentPump
|
||||
entities:
|
||||
- uid: 524
|
||||
|
|
@ -2546,72 +2542,54 @@ entities:
|
|||
rot: -1.5707963267948966 rad
|
||||
pos: -0.5,-12.5
|
||||
parent: 656
|
||||
- type: AtmosDevice
|
||||
joinedGrid: 656
|
||||
- uid: 550
|
||||
components:
|
||||
- type: Transform
|
||||
rot: 3.141592653589793 rad
|
||||
pos: 3.5,-10.5
|
||||
parent: 656
|
||||
- type: AtmosDevice
|
||||
joinedGrid: 656
|
||||
- uid: 551
|
||||
components:
|
||||
- type: Transform
|
||||
rot: 3.141592653589793 rad
|
||||
pos: -3.5,-10.5
|
||||
parent: 656
|
||||
- type: AtmosDevice
|
||||
joinedGrid: 656
|
||||
- uid: 552
|
||||
components:
|
||||
- type: Transform
|
||||
rot: 1.5707963267948966 rad
|
||||
pos: -4.5,-0.5
|
||||
parent: 656
|
||||
- type: AtmosDevice
|
||||
joinedGrid: 656
|
||||
- uid: 553
|
||||
components:
|
||||
- type: Transform
|
||||
rot: -1.5707963267948966 rad
|
||||
pos: 4.5,-0.5
|
||||
parent: 656
|
||||
- type: AtmosDevice
|
||||
joinedGrid: 656
|
||||
- uid: 573
|
||||
components:
|
||||
- type: Transform
|
||||
rot: -1.5707963267948966 rad
|
||||
pos: 2.5,11.5
|
||||
parent: 656
|
||||
- type: AtmosDevice
|
||||
joinedGrid: 656
|
||||
- uid: 574
|
||||
components:
|
||||
- type: Transform
|
||||
rot: 1.5707963267948966 rad
|
||||
pos: -2.5,11.5
|
||||
parent: 656
|
||||
- type: AtmosDevice
|
||||
joinedGrid: 656
|
||||
- uid: 580
|
||||
components:
|
||||
- type: Transform
|
||||
rot: -1.5707963267948966 rad
|
||||
pos: 4.5,8.5
|
||||
parent: 656
|
||||
- type: AtmosDevice
|
||||
joinedGrid: 656
|
||||
- uid: 589
|
||||
components:
|
||||
- type: Transform
|
||||
rot: 1.5707963267948966 rad
|
||||
pos: -4.5,8.5
|
||||
parent: 656
|
||||
- type: AtmosDevice
|
||||
joinedGrid: 656
|
||||
- proto: GeneratorBasic15kW
|
||||
entities:
|
||||
- uid: 66
|
||||
|
|
@ -3424,7 +3402,7 @@ entities:
|
|||
- type: Transform
|
||||
pos: 1.5,-15.5
|
||||
parent: 656
|
||||
- proto: soda_dispenser
|
||||
- proto: SodaDispenser
|
||||
entities:
|
||||
- uid: 166
|
||||
components:
|
||||
|
|
|
|||
|
|
@ -11876,6 +11876,8 @@ entities:
|
|||
rot: 3.141592653589793 rad
|
||||
pos: 0.5,-0.5
|
||||
parent: 7536
|
||||
- type: Door
|
||||
changeAirtight: False
|
||||
- type: Docking
|
||||
dockJointId: docking43669
|
||||
dockedWith: 7332
|
||||
|
|
@ -13198,6 +13200,8 @@ entities:
|
|||
lastSignals:
|
||||
DoorStatus: False
|
||||
DockStatus: True
|
||||
- type: Door
|
||||
changeAirtight: False
|
||||
- uid: 12584
|
||||
components:
|
||||
- type: Transform
|
||||
|
|
@ -122226,6 +122230,21 @@ entities:
|
|||
parent: 60
|
||||
- proto: SignAi
|
||||
entities:
|
||||
- uid: 16533
|
||||
components:
|
||||
- type: Transform
|
||||
pos: -101.5,16.5
|
||||
parent: 60
|
||||
- uid: 19800
|
||||
components:
|
||||
- type: Transform
|
||||
pos: -112.5,20.5
|
||||
parent: 60
|
||||
- uid: 19808
|
||||
components:
|
||||
- type: Transform
|
||||
pos: -107.5,16.5
|
||||
parent: 60
|
||||
- uid: 21237
|
||||
components:
|
||||
- type: Transform
|
||||
|
|
@ -122236,6 +122255,18 @@ entities:
|
|||
- type: Transform
|
||||
pos: -60.5,16.5
|
||||
parent: 60
|
||||
- proto: SignAiUpload
|
||||
entities:
|
||||
- uid: 21130
|
||||
components:
|
||||
- type: Transform
|
||||
pos: -110.5,6.5
|
||||
parent: 60
|
||||
- uid: 23380
|
||||
components:
|
||||
- type: Transform
|
||||
pos: -112.5,14.5
|
||||
parent: 60
|
||||
- proto: SignalButton
|
||||
entities:
|
||||
- uid: 3803
|
||||
|
|
@ -123122,11 +123153,12 @@ entities:
|
|||
- type: Transform
|
||||
pos: 2.5,-1.5
|
||||
parent: 60
|
||||
- proto: SignCanisters
|
||||
- proto: SignCans
|
||||
entities:
|
||||
- uid: 15171
|
||||
- uid: 13825
|
||||
components:
|
||||
- type: Transform
|
||||
rot: 3.141592653589793 rad
|
||||
pos: -28.5,37.5
|
||||
parent: 60
|
||||
- proto: SignCargo
|
||||
|
|
@ -123183,6 +123215,13 @@ entities:
|
|||
- type: Transform
|
||||
pos: 42.5,-25.5
|
||||
parent: 60
|
||||
- proto: SignCryo
|
||||
entities:
|
||||
- uid: 15171
|
||||
components:
|
||||
- type: Transform
|
||||
pos: -29.5,22.5
|
||||
parent: 60
|
||||
- proto: SignCryogenicsMed
|
||||
entities:
|
||||
- uid: 4111
|
||||
|
|
@ -123313,11 +123352,11 @@ entities:
|
|||
rot: 1.5707963267948966 rad
|
||||
pos: 42.49971,-21.305145
|
||||
parent: 60
|
||||
- uid: 16533
|
||||
- uid: 23381
|
||||
components:
|
||||
- type: Transform
|
||||
rot: -1.5707963267948966 rad
|
||||
pos: -29.5,22.5
|
||||
rot: 3.141592653589793 rad
|
||||
pos: -32.5,18.5
|
||||
parent: 60
|
||||
- proto: SignDirectionalDorms
|
||||
entities:
|
||||
|
|
@ -124056,6 +124095,14 @@ entities:
|
|||
- type: Transform
|
||||
pos: -109.5,20.5
|
||||
parent: 60
|
||||
- proto: SignKitchen
|
||||
entities:
|
||||
- uid: 23382
|
||||
components:
|
||||
- type: Transform
|
||||
rot: 3.141592653589793 rad
|
||||
pos: 24.5,-25.5
|
||||
parent: 60
|
||||
- proto: SignLaserMed
|
||||
entities:
|
||||
- uid: 14624
|
||||
|
|
@ -124094,6 +124141,12 @@ entities:
|
|||
- type: Transform
|
||||
pos: 3.5,-46.5
|
||||
parent: 60
|
||||
- uid: 23969
|
||||
components:
|
||||
- type: Transform
|
||||
rot: 3.141592653589793 rad
|
||||
pos: 18.5,17.5
|
||||
parent: 60
|
||||
- proto: SignMedical
|
||||
entities:
|
||||
- uid: 2632
|
||||
|
|
@ -124279,6 +124332,14 @@ entities:
|
|||
- type: Transform
|
||||
pos: -19.5,-11.5
|
||||
parent: 60
|
||||
- proto: SignRestroom
|
||||
entities:
|
||||
- uid: 23970
|
||||
components:
|
||||
- type: Transform
|
||||
rot: 3.141592653589793 rad
|
||||
pos: 18.5,11.5
|
||||
parent: 60
|
||||
- proto: SignRND
|
||||
entities:
|
||||
- uid: 7085
|
||||
|
|
@ -124537,6 +124598,14 @@ entities:
|
|||
- type: Transform
|
||||
pos: 22.5,6.5
|
||||
parent: 60
|
||||
- proto: SignTheater
|
||||
entities:
|
||||
- uid: 24271
|
||||
components:
|
||||
- type: Transform
|
||||
rot: 3.141592653589793 rad
|
||||
pos: 18.5,-20.5
|
||||
parent: 60
|
||||
- proto: SignToolStorage
|
||||
entities:
|
||||
- uid: 6315
|
||||
|
|
@ -124544,6 +124613,14 @@ entities:
|
|||
- type: Transform
|
||||
pos: 14.5,10.5
|
||||
parent: 60
|
||||
- proto: SignVault
|
||||
entities:
|
||||
- uid: 24268
|
||||
components:
|
||||
- type: Transform
|
||||
rot: 3.141592653589793 rad
|
||||
pos: 2.5,-5.5
|
||||
parent: 60
|
||||
- proto: SignVirology
|
||||
entities:
|
||||
- uid: 2969
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -166,6 +166,8 @@
|
|||
name: Morph into Geras
|
||||
description: Morphs you into a Geras - a miniature version of you which allows you to move fast, at the cost of your inventory.
|
||||
components:
|
||||
- type: ConfirmableAction
|
||||
popup: gera-transformation-popup
|
||||
- type: InstantAction
|
||||
itemIconStyle: BigAction
|
||||
useDelay: 10 # prevent spam
|
||||
|
|
|
|||
|
|
@ -84,7 +84,7 @@
|
|||
specificHeat: 40
|
||||
heatCapacityRatio: 1.3
|
||||
molarMass: 44
|
||||
color: 2887E8
|
||||
color: 8F00FF
|
||||
reagent: NitrousOxide
|
||||
pricePerMole: 1
|
||||
|
||||
|
|
|
|||
|
|
@ -198,3 +198,12 @@
|
|||
category: cargoproduct-category-name-service
|
||||
group: market
|
||||
|
||||
- type: cargoProduct
|
||||
id: ServiceCandles
|
||||
icon:
|
||||
sprite: Objects/Misc/candles.rsi
|
||||
state: candle-big
|
||||
product: CrateCandles
|
||||
cost: 500
|
||||
category: cargoproduct-category-name-service
|
||||
group: market
|
||||
|
|
|
|||
|
|
@ -432,3 +432,17 @@
|
|||
- id: DartYellow
|
||||
amount: 2
|
||||
|
||||
- type: entity
|
||||
name: envelope box
|
||||
parent: BoxCardboard
|
||||
id: BoxEnvelope
|
||||
description: A box filled with envelopes.
|
||||
components:
|
||||
- type: Sprite
|
||||
layers:
|
||||
- state: box
|
||||
- state: envelope
|
||||
- type: StorageFill
|
||||
contents:
|
||||
- id: Envelope
|
||||
amount: 9
|
||||
|
|
@ -128,6 +128,7 @@
|
|||
- id: BoxFolderRed
|
||||
- id: BoxFolderYellow
|
||||
- id: NewtonCradle
|
||||
- id: BoxEnvelope
|
||||
|
||||
- type: entity
|
||||
id: CrateServiceFaxMachine
|
||||
|
|
@ -333,3 +334,16 @@
|
|||
prob: 0.1
|
||||
- id: ShardGlassPlasma
|
||||
prob: 0.1
|
||||
|
||||
- type: entity
|
||||
id: CrateCandles
|
||||
parent: CrateGenericSteel
|
||||
name: candles crate
|
||||
description: Contains 4 boxes of candles, 2 large and 2 small. For atmosphere or something.
|
||||
components:
|
||||
- type: StorageFill
|
||||
contents:
|
||||
- id: BoxCandle
|
||||
amount: 2
|
||||
- id: BoxCandleSmall
|
||||
amount: 2
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
- type: entity
|
||||
id: ClothingShoesBootsCombatFilled
|
||||
suffix: Filled, Combat Knife
|
||||
parent:
|
||||
- ClothingShoesBootsCombat
|
||||
- ClothingShoesBootsSecFilled
|
||||
|
|
@ -38,3 +39,12 @@
|
|||
item:
|
||||
- KukriKnife
|
||||
|
||||
- type: entity
|
||||
id: ClothingShoesBootsSyndieFilled
|
||||
parent: ClothingShoesBootsCombat
|
||||
suffix: Filled, Throwing Knife
|
||||
components:
|
||||
- type: ContainerFill
|
||||
containers:
|
||||
item:
|
||||
- ThrowingKnife
|
||||
|
|
|
|||
|
|
@ -20,25 +20,27 @@
|
|||
components:
|
||||
- type: StorageFill
|
||||
contents:
|
||||
- id: ClothingOuterSuitEmergency
|
||||
- id: ClothingMaskBreath
|
||||
- id: ClothingOuterSuitEmergency
|
||||
- id: EmergencyOxygenTankFilled
|
||||
prob: 0.80
|
||||
orGroup: EmergencyTankOrRegularTank
|
||||
prob: 0.5
|
||||
orGroup: OxygenTank
|
||||
- id: OxygenTankFilled
|
||||
prob: 0.20
|
||||
orGroup: EmergencyTankOrRegularTank
|
||||
prob: 0.5
|
||||
orGroup: OxygenTank
|
||||
- id: ToolboxEmergencyFilled
|
||||
prob: 0.4
|
||||
prob: 0.5
|
||||
- id: MedkitOxygenFilled
|
||||
prob: 0.2
|
||||
- id: WeaponFlareGun
|
||||
prob: 0.05
|
||||
- id: BoxMRE
|
||||
prob: 0.1
|
||||
# Sunrise-Start
|
||||
- id: CrowbarRed
|
||||
- id: CrowbarRed
|
||||
- id: CrowbarRed
|
||||
# Sunrise-End
|
||||
|
||||
- type: entity
|
||||
id: ClosetWallEmergencyFilledRandom
|
||||
|
|
@ -47,25 +49,27 @@
|
|||
components:
|
||||
- type: StorageFill
|
||||
contents:
|
||||
- id: ClothingOuterSuitEmergency
|
||||
- id: ClothingMaskBreath
|
||||
- id: ClothingOuterSuitEmergency
|
||||
- id: EmergencyOxygenTankFilled
|
||||
prob: 0.80
|
||||
orGroup: EmergencyTankOrRegularTank
|
||||
prob: 0.5
|
||||
orGroup: OxygenTank
|
||||
- id: OxygenTankFilled
|
||||
prob: 0.20
|
||||
orGroup: EmergencyTankOrRegularTank
|
||||
prob: 0.5
|
||||
orGroup: OxygenTank
|
||||
- id: ToolboxEmergencyFilled
|
||||
prob: 0.4
|
||||
prob: 0.5
|
||||
- id: MedkitOxygenFilled
|
||||
prob: 0.2
|
||||
- id: WeaponFlareGun
|
||||
prob: 0.05
|
||||
- id: BoxMRE
|
||||
prob: 0.1
|
||||
# Sunrise-Start
|
||||
- id: CrowbarRed
|
||||
- id: CrowbarRed
|
||||
- id: CrowbarRed
|
||||
# Sunrise-End
|
||||
|
||||
- type: entity
|
||||
id: ClosetEmergencyN2FilledRandom
|
||||
|
|
@ -75,49 +79,75 @@
|
|||
- type: StorageFill
|
||||
contents:
|
||||
- id: ClothingMaskBreath
|
||||
- id: ClothingOuterSuitEmergency
|
||||
- id: EmergencyNitrogenTankFilled
|
||||
prob: 0.80
|
||||
orGroup: EmergencyTankOrRegularTank
|
||||
prob: 0.5
|
||||
orGroup: NitrogenTank
|
||||
- id: NitrogenTankFilled
|
||||
prob: 0.20
|
||||
orGroup: EmergencyTankOrRegularTank
|
||||
prob: 0.5
|
||||
orGroup: NitrogenTank
|
||||
# Sunrise-Start
|
||||
- id: CrowbarRed
|
||||
- id: CrowbarRed
|
||||
- id: CrowbarRed
|
||||
# Sunrise-End
|
||||
|
||||
- type: entity
|
||||
id: ClosetFireFilled
|
||||
parent: ClosetFire
|
||||
suffix: Filled
|
||||
components:
|
||||
- type: StorageFill
|
||||
contents:
|
||||
- id: ClothingOuterSuitFire
|
||||
- id: ClothingHeadHelmetFire
|
||||
- id: ClothingMaskGas
|
||||
- id: OxygenTankFilled
|
||||
- id: FireExtinguisher
|
||||
prob: 0.25
|
||||
- id: CrowbarRed
|
||||
- id: CrowbarRed
|
||||
- id: CrowbarRed
|
||||
- type: StorageFill
|
||||
contents:
|
||||
- id: ClothingOuterSuitFire
|
||||
- id: ClothingHeadHelmetFire
|
||||
- id: ClothingMaskGas
|
||||
- id: EmergencyOxygenTankFilled
|
||||
prob: 0.5
|
||||
orGroup: OxygenTank
|
||||
- id: OxygenTankFilled
|
||||
prob: 0.5
|
||||
orGroup: OxygenTank
|
||||
- id: CrowbarRed
|
||||
- id: FireExtinguisher
|
||||
prob: 0.98
|
||||
orGroup: FireExtinguisher
|
||||
- id: SprayBottleWater #It's just budget cut after budget cut man
|
||||
prob: 0.02
|
||||
orGroup: FireExtinguisher
|
||||
# Sunrise-Start
|
||||
- id: CrowbarRed
|
||||
- id: CrowbarRed
|
||||
- id: CrowbarRed
|
||||
# Sunrise-End
|
||||
|
||||
- type: entity
|
||||
id: ClosetWallFireFilledRandom
|
||||
parent: ClosetWallFire
|
||||
suffix: Filled
|
||||
components:
|
||||
- type: StorageFill
|
||||
contents:
|
||||
- id: ClothingOuterSuitFire
|
||||
- id: ClothingHeadHelmetFire
|
||||
- id: ClothingMaskGas
|
||||
- id: OxygenTankFilled
|
||||
- id: FireExtinguisher
|
||||
prob: 0.25
|
||||
- id: CrowbarRed
|
||||
- id: CrowbarRed
|
||||
- id: CrowbarRed
|
||||
- type: StorageFill
|
||||
contents:
|
||||
- id: ClothingOuterSuitFire
|
||||
- id: ClothingHeadHelmetFire
|
||||
- id: ClothingMaskGas
|
||||
- id: EmergencyOxygenTankFilled
|
||||
prob: 0.5
|
||||
orGroup: OxygenTank
|
||||
- id: OxygenTankFilled
|
||||
prob: 0.5
|
||||
orGroup: OxygenTank
|
||||
# Sunrise-Start
|
||||
- id: CrowbarRed
|
||||
- id: CrowbarRed
|
||||
- id: CrowbarRed
|
||||
# Sunrise-End
|
||||
- id: FireExtinguisher
|
||||
prob: 0.98
|
||||
orGroup: FireExtinguisher
|
||||
- id: SprayBottleWater #It's just budget cut after budget cut man
|
||||
prob: 0.02
|
||||
orGroup: FireExtinguisher
|
||||
|
||||
- type: entity
|
||||
id: ClosetMaintenanceFilledRandom
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@
|
|||
RubberStampApproved: 1
|
||||
RubberStampDenied: 1
|
||||
Paper: 10
|
||||
Envelope: 10
|
||||
EncryptionKeyCargo: 2
|
||||
EncryptionKeyEngineering: 2
|
||||
EncryptionKeyMedical: 2
|
||||
|
|
|
|||
|
|
@ -113,7 +113,7 @@
|
|||
modifiers:
|
||||
coefficients:
|
||||
Heat: 0.90
|
||||
Radiation: 0.001
|
||||
Radiation: 0.01
|
||||
- type: Clothing
|
||||
sprite: Clothing/OuterClothing/Suits/rad.rsi
|
||||
- type: GroupExamine
|
||||
|
|
|
|||
|
|
@ -1250,6 +1250,17 @@
|
|||
tags:
|
||||
- VimPilot
|
||||
- DoorBumpOpener
|
||||
- type: Reactive
|
||||
groups:
|
||||
Flammable: [ Touch ]
|
||||
Extinguish: [ Touch ]
|
||||
reactions:
|
||||
- reagents: [ Water, SpaceCleaner ]
|
||||
methods: [ Touch ]
|
||||
effects:
|
||||
- !type:WashCreamPieReaction
|
||||
|
||||
|
||||
|
||||
- type: entity
|
||||
name: monkey
|
||||
|
|
@ -1283,6 +1294,7 @@
|
|||
clumsySound:
|
||||
path: /Audio/Animals/monkey_scream.ogg
|
||||
|
||||
|
||||
- type: entity
|
||||
name: monkey
|
||||
id: MobBaseSyndicateMonkey
|
||||
|
|
@ -1434,7 +1446,7 @@
|
|||
- type: SentienceTarget
|
||||
flavorKind: station-event-random-sentience-flavor-kobold
|
||||
- type: GhostRole
|
||||
prob: 0.1
|
||||
prob: 0.05
|
||||
makeSentient: true
|
||||
name: ghost-role-information-kobold-name
|
||||
description: ghost-role-information-kobold-description
|
||||
|
|
|
|||
|
|
@ -100,6 +100,8 @@
|
|||
- id: FoodMeatCorgi
|
||||
amount: 2
|
||||
- id: MaterialHideCorgi
|
||||
- type: StealTarget
|
||||
stealGroup: AnimalIan
|
||||
|
||||
- type: entity
|
||||
name: Runtime
|
||||
|
|
|
|||
|
|
@ -257,14 +257,12 @@
|
|||
|
||||
- type: entity
|
||||
name: blueberry pancake
|
||||
parent: FoodBakedBase
|
||||
parent: FoodBakedPancake
|
||||
id: FoodBakedPancakeBb
|
||||
description: A fluffy and delicious blueberry pancake.
|
||||
components:
|
||||
- type: Stack
|
||||
stackType: Pancake
|
||||
count: 1
|
||||
composite: true
|
||||
stackType: PancakeBb
|
||||
layerStates:
|
||||
- pancakesbb1
|
||||
- pancakesbb2
|
||||
|
|
@ -281,7 +279,6 @@
|
|||
- state: pancakesbb3
|
||||
map: ["pancakesbb3"]
|
||||
visible: false
|
||||
- type: Appearance
|
||||
- type: Tag
|
||||
tags:
|
||||
- Pancake
|
||||
|
|
@ -289,14 +286,12 @@
|
|||
|
||||
- type: entity
|
||||
name: chocolate chip pancake
|
||||
parent: FoodBakedBase
|
||||
parent: FoodBakedPancake
|
||||
id: FoodBakedPancakeCc
|
||||
description: A fluffy and delicious chocolate chip pancake.
|
||||
components:
|
||||
- type: Stack
|
||||
stackType: Pancake
|
||||
count: 1
|
||||
composite: true
|
||||
stackType: PancakeCc
|
||||
layerStates:
|
||||
- pancakescc1
|
||||
- pancakescc2
|
||||
|
|
@ -313,7 +308,6 @@
|
|||
- state: pancakescc3
|
||||
map: ["pancakescc3"]
|
||||
visible: false
|
||||
- type: Appearance
|
||||
- type: SolutionContainerManager
|
||||
solutions:
|
||||
food:
|
||||
|
|
@ -323,9 +317,6 @@
|
|||
Quantity: 5
|
||||
- ReagentId: Theobromine
|
||||
Quantity: 1
|
||||
- type: Tag
|
||||
tags:
|
||||
- Pancake
|
||||
|
||||
- type: entity
|
||||
name: waffles
|
||||
|
|
|
|||
|
|
@ -95,6 +95,21 @@
|
|||
- type: Produce
|
||||
seedId: sugarcane
|
||||
|
||||
- type: entity
|
||||
name: papercane roll
|
||||
description: Why do we even need to grow paper?
|
||||
id: Papercane
|
||||
parent: ProduceBase
|
||||
components:
|
||||
- type: Sprite
|
||||
sprite: Objects/Specific/Hydroponics/papercane.rsi
|
||||
- type: SolutionContainerManager
|
||||
- type: Produce
|
||||
seedId: papercane
|
||||
- type: Log
|
||||
spawnedPrototype: SheetPaper1
|
||||
spawnCount: 2
|
||||
|
||||
- type: entity
|
||||
parent: FoodProduceBase
|
||||
id: FoodLaughinPeaPod
|
||||
|
|
@ -869,6 +884,42 @@
|
|||
tags:
|
||||
- Fruit
|
||||
|
||||
- type: entity
|
||||
name: golden apple
|
||||
parent: FoodProduceBase
|
||||
id: FoodGoldenApple
|
||||
description: It should be shaped like a cube, shouldn't it?
|
||||
components:
|
||||
- type: FlavorProfile
|
||||
flavors:
|
||||
- apple
|
||||
- metallic
|
||||
- type: SolutionContainerManager
|
||||
solutions:
|
||||
food:
|
||||
maxVol: 30
|
||||
reagents:
|
||||
- ReagentId: Nutriment
|
||||
Quantity: 10
|
||||
- ReagentId: Vitamin
|
||||
Quantity: 4
|
||||
- ReagentId: DoctorsDelight
|
||||
Quantity: 13
|
||||
- type: Sprite
|
||||
sprite: Objects/Specific/Hydroponics/golden_apple.rsi
|
||||
- type: Produce
|
||||
seedId: goldenApple
|
||||
- type: Extractable
|
||||
juiceSolution:
|
||||
reagents:
|
||||
- ReagentId: JuiceApple
|
||||
Quantity: 10
|
||||
- ReagentId: Gold
|
||||
Quantity: 10
|
||||
- type: Tag
|
||||
tags:
|
||||
- Fruit
|
||||
|
||||
- type: entity
|
||||
name: cocoa pod
|
||||
parent: FoodProduceBase
|
||||
|
|
@ -1411,6 +1462,71 @@
|
|||
- Galaxythistle
|
||||
- Fruit # Probably?
|
||||
|
||||
- type: entity
|
||||
name: glasstle
|
||||
parent: FoodProduceBase
|
||||
id: FoodGlasstle
|
||||
description: A fragile crystal plant with lot of spiky thorns.
|
||||
components:
|
||||
- type: Item
|
||||
size: Small
|
||||
sprite: Objects/Specific/Hydroponics/glasstle.rsi
|
||||
heldPrefix: produce
|
||||
- type: FlavorProfile
|
||||
flavors:
|
||||
- sharp
|
||||
- type: SolutionContainerManager
|
||||
solutions:
|
||||
food:
|
||||
maxVol: 15
|
||||
reagents:
|
||||
- ReagentId: Razorium
|
||||
Quantity: 15
|
||||
- type: Sprite
|
||||
sprite: Objects/Specific/Hydroponics/glasstle.rsi
|
||||
- type: Produce
|
||||
seedId: glasstle
|
||||
- type: Extractable
|
||||
grindableSolutionName: food
|
||||
- type: Damageable
|
||||
damageContainer: Inorganic
|
||||
- type: ToolRefinable
|
||||
refineResult:
|
||||
- id: SheetGlass1
|
||||
- type: Destructible
|
||||
thresholds:
|
||||
- trigger:
|
||||
!type:DamageTrigger
|
||||
damage: 10
|
||||
behaviors:
|
||||
- !type:PlaySoundBehavior
|
||||
sound:
|
||||
collection: GlassBreak
|
||||
params:
|
||||
volume: -4
|
||||
- !type:SpawnEntitiesBehavior
|
||||
spawn:
|
||||
ShardGlass:
|
||||
min: 1
|
||||
max: 1
|
||||
- !type:DoActsBehavior
|
||||
acts: [ "Destruction" ]
|
||||
- type: DamageOnHit
|
||||
damage:
|
||||
types:
|
||||
Blunt: 10
|
||||
- type: MeleeWeapon
|
||||
wideAnimationRotation: 60
|
||||
damage:
|
||||
types:
|
||||
Slash: 15
|
||||
soundHit:
|
||||
path: /Audio/Weapons/bladeslice.ogg
|
||||
- type: Tag
|
||||
tags:
|
||||
- Galaxythistle
|
||||
|
||||
|
||||
- type: entity
|
||||
name: fly amanita
|
||||
parent: FoodProduceBase
|
||||
|
|
|
|||
|
|
@ -301,6 +301,12 @@
|
|||
Quantity: 10
|
||||
- ReagentId: JuiceThatMakesYouWeh
|
||||
Quantity: 10
|
||||
- type: Clothing
|
||||
quickEquip: false
|
||||
sprite: Objects/Fun/toys.rsi
|
||||
equippedPrefix: lizard
|
||||
slots:
|
||||
- HEAD
|
||||
|
||||
- type: entity
|
||||
parent: PlushieLizard
|
||||
|
|
|
|||
|
|
@ -568,3 +568,81 @@
|
|||
Blunt: 10
|
||||
- type: StealTarget
|
||||
stealGroup: BoxFolderQmClipboard
|
||||
|
||||
- type: entity
|
||||
name: envelope
|
||||
parent: BaseItem
|
||||
id: Envelope
|
||||
description: 'A small envelope for keeping prying eyes off of your sensitive documents.'
|
||||
components:
|
||||
- type: Sprite
|
||||
sprite: Objects/Misc/bureaucracy.rsi
|
||||
layers:
|
||||
- state: envelope_open
|
||||
map: ["enum.EnvelopeVisualLayers.Open"]
|
||||
- state: envelope_closed
|
||||
map: ["enum.EnvelopeVisualLayers.Sealed"]
|
||||
visible: false
|
||||
- state: envelope_torn
|
||||
map: ["enum.EnvelopeVisualLayers.Torn"]
|
||||
visible: false
|
||||
- state: paper_stamp-generic
|
||||
map: ["enum.PaperVisualLayers.Stamp"]
|
||||
visible: false
|
||||
- type: Paper
|
||||
escapeFormatting: false
|
||||
content: envelope-default-message
|
||||
- type: PaperVisuals
|
||||
headerImagePath: "/Textures/Interface/Paper/paper_heading_postage_stamp.svg.96dpi.png"
|
||||
headerMargin: 216.0, 0.0, 0.0, 0.0
|
||||
contentMargin: 0.0, 0.0, 0.0, 0.0
|
||||
maxWritableArea: 368.0, 256.0
|
||||
- type: Envelope
|
||||
- type: ContainerContainer
|
||||
containers:
|
||||
letter_slot: !type:ContainerSlot
|
||||
- type: ItemSlots
|
||||
slots:
|
||||
letter_slot:
|
||||
name: envelope-letter-slot
|
||||
insertSound: /Audio/Effects/packetrip.ogg
|
||||
ejectSound: /Audio/Effects/packetrip.ogg
|
||||
whitelist:
|
||||
tags:
|
||||
- Paper
|
||||
- type: ActivatableUI
|
||||
key: enum.PaperUiKey.Key
|
||||
requireHands: false
|
||||
- type: UserInterface
|
||||
interfaces:
|
||||
enum.PaperUiKey.Key:
|
||||
type: PaperBoundUserInterface
|
||||
- type: Item
|
||||
size: Tiny
|
||||
- type: Tag
|
||||
tags:
|
||||
- Trash
|
||||
- Document
|
||||
#- type: Appearance, hide stamp marks until we have some kind of displacement
|
||||
- type: Flammable
|
||||
fireSpread: true
|
||||
canResistFire: false
|
||||
alwaysCombustible: true
|
||||
canExtinguish: true
|
||||
damage:
|
||||
types:
|
||||
Heat: 1
|
||||
- type: FireVisuals
|
||||
sprite: Effects/fire.rsi
|
||||
normalState: fire
|
||||
- type: Damageable
|
||||
damageModifierSet: Wood
|
||||
- type: Destructible
|
||||
thresholds:
|
||||
- trigger:
|
||||
!type:DamageTrigger
|
||||
damage: 15
|
||||
behaviors:
|
||||
- !type:EmptyAllContainersBehaviour
|
||||
- !type:DoActsBehavior
|
||||
acts: [ "Destruction" ]
|
||||
|
|
@ -163,6 +163,16 @@
|
|||
- type: Sprite
|
||||
sprite: Objects/Specific/Hydroponics/sugarcane.rsi
|
||||
|
||||
- type: entity
|
||||
parent: SeedBase
|
||||
name: packet of papercane seeds
|
||||
id: PapercaneSeeds
|
||||
components:
|
||||
- type: Seed
|
||||
seedId: papercane
|
||||
- type: Sprite
|
||||
sprite: Objects/Specific/Hydroponics/papercane.rsi
|
||||
|
||||
- type: entity
|
||||
parent: SeedBase
|
||||
name: packet of tower cap spores
|
||||
|
|
@ -243,6 +253,16 @@
|
|||
- type: Sprite
|
||||
sprite: Objects/Specific/Hydroponics/apple.rsi
|
||||
|
||||
- type: entity
|
||||
parent: SeedBase
|
||||
name: packet of golden apple seeds
|
||||
id: GoldenAppleSeeds
|
||||
components:
|
||||
- type: Seed
|
||||
seedId: goldenApple
|
||||
- type: Sprite
|
||||
sprite: Objects/Specific/Hydroponics/golden_apple.rsi
|
||||
|
||||
- type: entity
|
||||
parent: SeedBase
|
||||
name: packet of corn seeds
|
||||
|
|
@ -427,6 +447,17 @@
|
|||
- type: Sprite
|
||||
sprite: Objects/Specific/Hydroponics/galaxythistle.rsi
|
||||
|
||||
- type: entity
|
||||
parent: SeedBase
|
||||
name: packet of glasstle seeds
|
||||
description: "Scars of gloomy nights."
|
||||
id: GlasstleSeeds
|
||||
components:
|
||||
- type: Seed
|
||||
seedId: glasstle
|
||||
- type: Sprite
|
||||
sprite: Objects/Specific/Hydroponics/glasstle.rsi
|
||||
|
||||
- type: entity
|
||||
parent: SeedBase
|
||||
name: packet of fly amanita spores
|
||||
|
|
|
|||
|
|
@ -76,9 +76,6 @@
|
|||
components:
|
||||
- type: Sprite
|
||||
sprite: Objects/Weapons/Guns/Pistols/viper.rsi
|
||||
availableModes:
|
||||
- FullAuto
|
||||
- SemiAuto
|
||||
- type: ItemSlots
|
||||
slots:
|
||||
gun_magazine:
|
||||
|
|
|
|||
|
|
@ -62,12 +62,7 @@
|
|||
- /Maps/_Sunrise/Shuttles/security.yml # Sunrise-edit
|
||||
nameGrid: false
|
||||
# Слишком большая нагрузка ради 3 человек
|
||||
# ruins: !type:GridSpawnGroup
|
||||
# hide: true
|
||||
# nameGrid: true
|
||||
# minCount: 2
|
||||
# maxCount: 2
|
||||
# stationGrid: false
|
||||
# security: !type:GridSpawnGroup
|
||||
# paths:
|
||||
# - /Maps/Ruins/chunked_tcomms.yml
|
||||
# - /Maps/Ruins/biodome_satellite.yml
|
||||
|
|
@ -80,7 +75,8 @@
|
|||
# - /Maps/Ruins/whiteship_bluespacejumper.yml
|
||||
# Ебейшие лаги и куча гридов
|
||||
# vgroid: !type:DungeonSpawnGroup
|
||||
# minimumDistance: 1000
|
||||
# minimumDistance: 400
|
||||
# maximumDistance: 450
|
||||
# nameDataset: names_borer
|
||||
# stationGrid: false
|
||||
# addComponents:
|
||||
|
|
|
|||
|
|
@ -37,6 +37,17 @@
|
|||
- Chemist
|
||||
- type: StealTarget
|
||||
stealGroup: ChemDispenser
|
||||
- type: Fixtures
|
||||
fixtures:
|
||||
fix1:
|
||||
shape:
|
||||
!type:PhysShapeAabb
|
||||
bounds: "-0.25, -0.4, 0.25, 0.4"
|
||||
density: 190
|
||||
mask:
|
||||
- MachineMask
|
||||
layer:
|
||||
- MachineLayer
|
||||
|
||||
- type: entity
|
||||
id: ChemDispenserEmpty
|
||||
|
|
|
|||
|
|
@ -115,6 +115,8 @@
|
|||
- type: Lathe
|
||||
idleState: icon
|
||||
runningState: building
|
||||
unlitIdleState: unlit
|
||||
unlitRunningState: unlit-building
|
||||
staticRecipes:
|
||||
- Wirecutter
|
||||
- Igniter
|
||||
|
|
@ -270,6 +272,8 @@
|
|||
- type: Lathe
|
||||
idleState: icon
|
||||
runningState: building
|
||||
unlitIdleState: unlit
|
||||
unlitRunningState: unlit-building
|
||||
staticRecipes:
|
||||
- LargeBeaker
|
||||
- Dropper
|
||||
|
|
@ -1237,6 +1241,7 @@
|
|||
- IngotGold30
|
||||
- IngotSilver30
|
||||
- MaterialBananium10
|
||||
- MaterialDiamond
|
||||
|
||||
- type: entity
|
||||
parent: BaseLathe
|
||||
|
|
|
|||
|
|
@ -150,6 +150,8 @@
|
|||
suffix: keg
|
||||
description: You probably shouldn't stick around to see if this is armed. It has a tap on the side.
|
||||
components:
|
||||
- type: Transform
|
||||
anchored: false
|
||||
- type: NukeLabel
|
||||
- type: Sprite
|
||||
sprite: Objects/Devices/nuke.rsi
|
||||
|
|
@ -183,11 +185,11 @@
|
|||
shape:
|
||||
!type:PhysShapeCircle
|
||||
radius: 0.45
|
||||
density: 80
|
||||
density: 255
|
||||
mask:
|
||||
- TabletopMachineMask
|
||||
- MachineMask
|
||||
layer:
|
||||
- TabletopMachineLayer
|
||||
- WallLayer
|
||||
- type: SolutionContainerManager
|
||||
solutions:
|
||||
tank:
|
||||
|
|
|
|||
|
|
@ -25,6 +25,8 @@
|
|||
- type: Wires
|
||||
boardName: wires-board-name-pa
|
||||
layoutId: ParticleAccelerator
|
||||
- type: AccessReader
|
||||
access: [["Engineering"]]
|
||||
|
||||
# Unfinished
|
||||
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Reference in a new issue