Merge remote-tracking branch 'upstream/master' into upstream-sync

This commit is contained in:
Arthur 2022-03-02 02:12:36 +03:00
commit 41398c1749
210 changed files with 130274 additions and 45251 deletions

View file

@ -176,8 +176,12 @@ namespace Content.Client.Atmos.EntitySystems
var frameCount = FrameCounter[i];
Timer[i] += frameTime;
if (!(Timer[i] >= delays[frameCount])) continue;
Timer[i] = 0f;
var time = delays[frameCount];
if (Timer[i] < time)
continue;
Timer[i] -= time;
FrameCounter[i] = (frameCount + 1) % Frames[i].Length;
}
@ -188,8 +192,10 @@ namespace Content.Client.Atmos.EntitySystems
var frameCount = FireFrameCounter[i];
FireTimer[i] += frameTime;
if (!(FireTimer[i] >= delays[frameCount])) continue;
FireTimer[i] = 0f;
var time = delays[frameCount];
if (FireTimer[i] < time) continue;
FireTimer[i] -= time;
FireFrameCounter[i] = (frameCount + 1) % FireFrames[i].Length;
}
}

View file

@ -8,7 +8,7 @@ namespace Content.Client.Atmos.Visualizers
public sealed class PressurePumpVisualizer : EnabledAtmosDeviceVisualizer
{
protected override object LayerMap => Layers.Enabled;
protected override Enum DataKey => PressurePumpVisuals.Enabled;
protected override Enum DataKey => PumpVisuals.Enabled;
enum Layers : byte
{

View file

@ -72,30 +72,4 @@ namespace Content.Client.Commands
EntitySystem.Get<PopupSystem>().PopupCursor(message);
}
}
internal sealed class MappingCommand : IConsoleCommand
{
public string Command => "mapping";
public string Description => "Creates and teleports you to a new uninitialized map for mapping.";
public string Help => $"Usage: {Command} <mapname> / {Command} <id> <mapname>";
public void Execute(IConsoleShell shell, string argStr, string[] args)
{
if (args.Length == 0)
{
shell.WriteLine(Help);
return;
}
#if DEBUG
shell.WriteError("WARNING: The client is using a debug build. You are risking losing your changes.");
#endif
shell.ConsoleHost.RegisteredCommands["togglelight"].Execute(shell, string.Empty, Array.Empty<string>());
shell.ConsoleHost.RegisteredCommands["showsubfloorforever"].Execute(shell, string.Empty, Array.Empty<string>());
shell.ConsoleHost.RegisteredCommands["showmarkers"].Execute(shell, string.Empty, Array.Empty<string>());
shell.RemoteExecuteCommand(argStr);
}
}
}

View file

@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">
<Import Project="..\RobustToolbox\MSBuild\Robust.Properties.targets" />
<PropertyGroup>
<!-- Work around https://github.com/dotnet/project-system/issues/4314 -->
@ -26,5 +26,4 @@
<Import Project="..\RobustToolbox\MSBuild\XamlIL.targets" />
<Import Project="..\RobustToolbox\MSBuild\Robust.Analyzers.targets" />
</Project>

View file

@ -1,12 +1,9 @@
using System;
using System.Collections.Generic;
using Content.Client.Outline;
using Content.Client.Viewport;
using Content.Shared.ActionBlocker;
using Content.Shared.DragDrop;
using Content.Shared.Interaction;
using Content.Shared.Interaction.Events;
using Content.Shared.Interaction.Helpers;
using Content.Shared.Popups;
using JetBrains.Annotations;
using Robust.Client.GameObjects;
@ -14,13 +11,8 @@ using Robust.Client.Graphics;
using Robust.Client.Input;
using Robust.Client.Player;
using Robust.Client.State;
using Robust.Shared.GameObjects;
using Robust.Shared.Input;
using Robust.Shared.Input.Binding;
using Robust.Shared.IoC;
using Robust.Shared.Localization;
using Robust.Shared.Log;
using Robust.Shared.Maths;
using Robust.Shared.Prototypes;
using Robust.Shared.Utility;
using DrawDepth = Content.Shared.DrawDepth.DrawDepth;
@ -237,13 +229,11 @@ namespace Content.Client.DragDrop
if (_dragShadow == default)
return false;
EntityManager.GetComponent<TransformComponent>(_dragShadow).WorldPosition = mousePos.Position;
_targetRecheckTime += frameTime;
if (_targetRecheckTime > TargetRecheckInterval)
{
HighlightTargets();
_targetRecheckTime = 0;
_targetRecheckTime -= TargetRecheckInterval;
}
return true;
@ -464,7 +454,20 @@ namespace Content.Client.DragDrop
public override void Update(float frameTime)
{
base.Update(frameTime);
_dragDropHelper.Update(frameTime);
}
public override void FrameUpdate(float frameTime)
{
base.FrameUpdate(frameTime);
// Update position every frame to make it smooth.
if (_dragDropHelper.IsDragging)
{
var mousePos = _eyeManager.ScreenToMap(_inputManager.MouseScreenPosition);
Transform(_dragShadow).WorldPosition = mousePos.Position;
}
}
}
}

View file

@ -1,4 +1,4 @@
<DefaultWindow xmlns="https://spacestation14.io"
<DefaultWindow xmlns="https://spacestation14.io"
xmlns:tabs="clr-namespace:Content.Client.EscapeMenu.UI.Tabs"
Title="{Loc 'ui-options-title'}"
MinSize="800 450">
@ -6,5 +6,6 @@
<tabs:GraphicsTab />
<tabs:KeyRebindTab />
<tabs:AudioTab />
<tabs:NetworkTab/>
</TabContainer>
</DefaultWindow>

View file

@ -1,4 +1,4 @@
using Robust.Client.AutoGenerated;
using Robust.Client.AutoGenerated;
using Robust.Client.UserInterface.CustomControls;
using Robust.Client.UserInterface.XAML;
using Robust.Shared.IoC;
@ -17,6 +17,7 @@ namespace Content.Client.EscapeMenu.UI
Tabs.SetTabTitle(0, Loc.GetString("ui-options-tab-graphics"));
Tabs.SetTabTitle(1, Loc.GetString("ui-options-tab-controls"));
Tabs.SetTabTitle(2, Loc.GetString("ui-options-tab-audio"));
Tabs.SetTabTitle(3, Loc.GetString("ui-options-tab-network"));
}
}
}

View file

@ -0,0 +1,39 @@
<Control xmlns="https://spacestation14.io"
xmlns:hudUi="clr-namespace:Content.Client.HUD.UI"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="Content.Client.EscapeMenu.UI.Tabs.NetworkTab">
<BoxContainer Orientation="Vertical">
<BoxContainer Orientation="Vertical" Margin="8 8 8 8" VerticalExpand="True">
<BoxContainer Orientation="Horizontal" Margin="5 0 0 0">
<Label Text="{Loc 'ui-options-net-interp-ratio'}" />
<Control MinSize="8 0" />
<Slider Name="NetInterpRatioSlider"
MinValue="0"
MaxValue="6"
HorizontalExpand="True"
MinSize="80 0"
Rounded="True" />
<Control MinSize="8 0" />
<Label Name="NetInterpRatioLabel" MinSize="48 0" Align="Right" />
<Control MinSize="4 0"/>
</BoxContainer>
</BoxContainer>
<hudUi:StripeBack HasBottomEdge="False" HasMargins="False">
<BoxContainer Orientation="Horizontal"
Align="End"
HorizontalExpand="True"
VerticalExpand="True">
<Button Name="ResetButton"
Text="{Loc 'ui-options-reset-all'}"
StyleClasses="Caution"
HorizontalExpand="True"
HorizontalAlignment="Right" />
<Control MinSize="2 0" />
<Button Name="ApplyButton"
Text="{Loc 'ui-options-apply'}"
TextAlign="Center"
HorizontalAlignment="Right" />
</BoxContainer>
</hudUi:StripeBack>
</BoxContainer>
</Control>

View file

@ -0,0 +1,72 @@
using System;
using Content.Shared.CCVar;
using Robust.Client.AutoGenerated;
using Robust.Client.Graphics;
using Robust.Client.UserInterface;
using Robust.Client.UserInterface.Controls;
using Robust.Client.UserInterface.XAML;
using Robust.Shared;
using Robust.Shared.Maths;
using Robust.Shared.Configuration;
using Robust.Shared.IoC;
using Robust.Shared.Localization;
namespace Content.Client.EscapeMenu.UI.Tabs
{
[GenerateTypedNameReferences]
public sealed partial class NetworkTab : Control
{
[Dependency] private readonly IConfigurationManager _cfg = default!;
public NetworkTab()
{
RobustXamlLoader.Load(this);
IoCManager.InjectDependencies(this);
ApplyButton.OnPressed += OnApplyButtonPressed;
ResetButton.OnPressed += OnResetButtonPressed;
NetInterpRatioSlider.OnValueChanged += OnNetInterpRatioSliderChanged;
Reset();
}
protected override void Dispose(bool disposing)
{
ApplyButton.OnPressed -= OnApplyButtonPressed;
ResetButton.OnPressed -= OnResetButtonPressed;
NetInterpRatioSlider.OnValueChanged -= OnNetInterpRatioSliderChanged;
base.Dispose(disposing);
}
private void OnNetInterpRatioSliderChanged(Robust.Client.UserInterface.Controls.Range range)
{
UpdateChanges();
}
private void OnApplyButtonPressed(BaseButton.ButtonEventArgs args)
{
_cfg.SetCVar(CVars.NetInterpRatio, (int) NetInterpRatioSlider.Value);
_cfg.SaveToFile();
UpdateChanges();
}
private void OnResetButtonPressed(BaseButton.ButtonEventArgs args)
{
Reset();
}
private void Reset()
{
NetInterpRatioSlider.Value = _cfg.GetCVar(CVars.NetInterpRatio);
UpdateChanges();
}
private void UpdateChanges()
{
var isEverythingSame = NetInterpRatioSlider.Value == _cfg.GetCVar(CVars.NetInterpRatio);
ApplyButton.Disabled = isEverythingSame;
ResetButton.Disabled = isEverythingSame;
NetInterpRatioLabel.Text = NetInterpRatioSlider.Value.ToString();
}
}
}

View file

@ -10,12 +10,32 @@ namespace Content.Server.Actions
public sealed class ActionsSystem : SharedActionsSystem
{
[Dependency] private readonly IChatManager _chatMan = default!;
[Dependency] private readonly MetaDataSystem _metaSystem = default!;
public override void Initialize()
{
base.Initialize();
SubscribeLocalEvent<ActionsComponent, PlayerAttachedEvent>(OnPlayerAttached);
SubscribeLocalEvent<ActionsComponent, ComponentStartup>(OnStartup);
SubscribeLocalEvent<ActionsComponent, ComponentShutdown>(OnShutdown);
SubscribeLocalEvent<ActionsComponent, MetaFlagRemoveAttemptEvent>(OnMetaFlagRemoval);
}
private void OnMetaFlagRemoval(EntityUid uid, ActionsComponent component, ref MetaFlagRemoveAttemptEvent args)
{
if (component.LifeStage == ComponentLifeStage.Running)
args.Cancelled = true;
}
private void OnStartup(EntityUid uid, ActionsComponent component, ComponentStartup args)
{
_metaSystem.AddFlag(uid, MetaDataFlags.EntitySpecific);
}
private void OnShutdown(EntityUid uid, ActionsComponent component, ComponentShutdown args)
{
_metaSystem.RemoveFlag(uid, MetaDataFlags.EntitySpecific);
}
private void OnPlayerAttached(EntityUid uid, ActionsComponent component, PlayerAttachedEvent args)

View file

@ -108,6 +108,7 @@ public sealed partial class AdminLogSystem : SharedAdminLogSystem
}
SubscribeLocalEvent<RoundStartingEvent>(RoundStarting);
SubscribeLocalEvent<GameRunLevelChangedEvent>(RunLevelChanged);
}
public override async void Shutdown()
@ -181,7 +182,7 @@ public sealed partial class AdminLogSystem : SharedAdminLogSystem
private async Task SaveLogs()
{
_accumulatedFrameTime = 0;
_accumulatedFrameTime = 0f;
// TODO ADMIN LOGS array pool
var copy = new List<QueuedLog>(_logQueue.Count + _preRoundLogQueue.Count);
@ -232,14 +233,21 @@ public sealed partial class AdminLogSystem : SharedAdminLogSystem
private void RoundStarting(RoundStartingEvent ev)
{
Interlocked.Exchange(ref _currentLogId, 0);
CacheNewRound();
}
if (_metricsEnabled)
private void RunLevelChanged(GameRunLevelChangedEvent ev)
{
if (ev.New == GameRunLevel.PreRoundLobby)
{
PreRoundQueueCapReached.Set(0);
QueueCapReached.Set(0);
LogsSent.Set(0);
Interlocked.Exchange(ref _currentLogId, 0);
if (_metricsEnabled)
{
PreRoundQueueCapReached.Set(0);
QueueCapReached.Set(0);
LogsSent.Set(0);
}
}
}

View file

@ -37,25 +37,28 @@ namespace Content.Server.Animals.Systems
{
udder.AccumulatedFrameTime += frameTime;
if (udder.AccumulatedFrameTime < udder.UpdateRate)
continue;
// Actually there is food digestion so no problem with instant reagent generation "OnFeed"
if (EntityManager.TryGetComponent<HungerComponent?>(udder.Owner, out var hunger))
while (udder.AccumulatedFrameTime > udder.UpdateRate)
{
hunger.HungerThresholds.TryGetValue(HungerThreshold.Peckish, out var targetThreshold);
udder.AccumulatedFrameTime -= udder.UpdateRate;
// Is there enough nutrition to produce reagent?
if (hunger.CurrentHunger < targetThreshold)
// Actually there is food digestion so no problem with instant reagent generation "OnFeed"
if (EntityManager.TryGetComponent<HungerComponent?>(udder.Owner, out var hunger))
{
hunger.HungerThresholds.TryGetValue(HungerThreshold.Peckish, out var targetThreshold);
// Is there enough nutrition to produce reagent?
if (hunger.CurrentHunger < targetThreshold)
continue;
}
if (!_solutionContainerSystem.TryGetSolution(udder.Owner, udder.TargetSolutionName,
out var solution))
continue;
//TODO: toxins from bloodstream !?
_solutionContainerSystem.TryAddReagent(udder.Owner, solution, udder.ReagentId,
udder.QuantityPerUpdate, out var accepted);
}
if (!_solutionContainerSystem.TryGetSolution(udder.Owner, udder.TargetSolutionName, out var solution))
continue;
//TODO: toxins from bloodstream !?
_solutionContainerSystem.TryAddReagent(udder.Owner, solution, udder.ReagentId, udder.QuantityPerUpdate, out var accepted);
udder.AccumulatedFrameTime = 0;
}
}

View file

@ -1,7 +1,4 @@
using Content.Shared.Atmos;
using Robust.Shared.GameObjects;
using Robust.Shared.Serialization.Manager.Attributes;
using Robust.Shared.ViewVariables;
namespace Content.Server.Atmos.Piping.Binary.Components
{
@ -28,6 +25,7 @@ namespace Content.Server.Atmos.Piping.Binary.Components
public string OutletName { get; set; } = "outlet";
[ViewVariables(VVAccess.ReadWrite)]
[DataField("targetPressure")]
public float TargetPressure { get; set; } = Atmospherics.OneAtmosphere;
}
}

View file

@ -1,7 +1,4 @@
using Content.Shared.Atmos;
using Robust.Shared.GameObjects;
using Robust.Shared.Serialization.Manager.Attributes;
using Robust.Shared.ViewVariables;
namespace Content.Server.Atmos.Piping.Binary.Components
{
@ -20,6 +17,14 @@ namespace Content.Server.Atmos.Piping.Binary.Components
public string OutletName { get; set; } = "outlet";
[ViewVariables(VVAccess.ReadWrite)]
[DataField("targetPressure")]
public float TargetPressure { get; set; } = Atmospherics.OneAtmosphere;
/// <summary>
/// Max pressure of the target gas (NOT relative to source).
/// </summary>
[ViewVariables(VVAccess.ReadWrite)]
[DataField("maxTargetPressure")]
public float MaxTargetPressure = Atmospherics.MaxOutputPressure;
}
}

View file

@ -1,7 +1,4 @@
using Content.Shared.Atmos;
using Robust.Shared.GameObjects;
using Robust.Shared.Serialization.Manager.Attributes;
using Robust.Shared.ViewVariables;
namespace Content.Server.Atmos.Piping.Binary.Components
{
@ -23,8 +20,13 @@ namespace Content.Server.Atmos.Piping.Binary.Components
public string OutletName { get; set; } = "outlet";
[ViewVariables(VVAccess.ReadWrite)]
[DataField("transferRate")]
public float TransferRate { get; set; } = Atmospherics.MaxTransferRate;
[ViewVariables(VVAccess.ReadWrite)]
[DataField("maxTransferRate")]
public float MaxTransferRate { get; set; } = Atmospherics.MaxTransferRate;
[DataField("leakRatio")]
public float LeakRatio { get; set; } = 0.1f;
@ -32,9 +34,9 @@ namespace Content.Server.Atmos.Piping.Binary.Components
public float LowerThreshold { get; set; } = 0.01f;
[DataField("higherThreshold")]
public float HigherThreshold { get; set; } = 9000f;
public float HigherThreshold { get; set; } = 2 * Atmospherics.MaxOutputPressure;
[DataField("overclockThreshold")]
public float OverclockThreshold { get; set; } = 1000f;
public float OverclockThreshold { get; set; } = 1000;
}
}

View file

@ -14,10 +14,6 @@ using Content.Shared.Interaction;
using Content.Shared.Popups;
using JetBrains.Annotations;
using Robust.Server.GameObjects;
using Robust.Shared.GameObjects;
using Robust.Shared.IoC;
using Robust.Shared.Localization;
using Robust.Shared.Maths;
namespace Content.Server.Atmos.Piping.Binary.EntitySystems
{
@ -62,7 +58,7 @@ namespace Content.Server.Atmos.Piping.Binary.EntitySystems
|| !nodeContainer.TryGetNode(pump.InletName, out PipeNode? inlet)
|| !nodeContainer.TryGetNode(pump.OutletName, out PipeNode? outlet))
{
appearance?.SetData(PressurePumpVisuals.Enabled, false);
appearance?.SetData(PumpVisuals.Enabled, false);
return;
}
@ -70,13 +66,13 @@ namespace Content.Server.Atmos.Piping.Binary.EntitySystems
if (MathHelper.CloseToPercent(pump.TargetPressure, outputStartingPressure))
{
appearance?.SetData(PressurePumpVisuals.Enabled, false);
appearance?.SetData(PumpVisuals.Enabled, false);
return; // No need to pump gas if target has been reached.
}
if (inlet.Air.TotalMoles > 0 && inlet.Air.Temperature > 0)
{
appearance?.SetData(PressurePumpVisuals.Enabled, true);
appearance?.SetData(PumpVisuals.Enabled, true);
// We calculate the necessary moles to transfer using our good ol' friend PV=nRT.
var pressureDelta = pump.TargetPressure - outputStartingPressure;
@ -91,7 +87,7 @@ namespace Content.Server.Atmos.Piping.Binary.EntitySystems
{
if (EntityManager.TryGetComponent(uid, out AppearanceComponent? appearance))
{
appearance.SetData(PressurePumpVisuals.Enabled, false);
appearance.SetData(PumpVisuals.Enabled, false);
}
}

View file

@ -1,11 +1,10 @@
using System;
using Content.Server.Administration.Logs;
using Content.Server.Atmos.EntitySystems;
using Content.Server.Atmos.Piping.Binary.Components;
using Content.Server.Atmos.Piping.Components;
using Content.Server.NodeContainer;
using Content.Server.NodeContainer.Nodes;
using Content.Shared.Atmos;
using Content.Shared.Atmos.Piping;
using Content.Shared.Atmos.Piping.Binary.Components;
using Content.Shared.Database;
using Content.Shared.Examine;
@ -13,9 +12,6 @@ using Content.Shared.Interaction;
using Content.Shared.Popups;
using JetBrains.Annotations;
using Robust.Server.GameObjects;
using Robust.Shared.GameObjects;
using Robust.Shared.IoC;
using Robust.Shared.Localization;
using Robust.Shared.Timing;
namespace Content.Server.Atmos.Piping.Binary.EntitySystems
@ -54,18 +50,17 @@ namespace Content.Server.Atmos.Piping.Binary.EntitySystems
private void OnVolumePumpUpdated(EntityUid uid, GasVolumePumpComponent pump, AtmosDeviceUpdateEvent args)
{
if (!pump.Enabled)
return;
TryComp(uid, out AppearanceComponent? appearance);
if (!EntityManager.TryGetComponent(uid, out NodeContainerComponent? nodeContainer))
return;
if (!EntityManager.TryGetComponent(uid, out AtmosDeviceComponent? device))
return;
if (!nodeContainer.TryGetNode(pump.InletName, out PipeNode? inlet)
if (!pump.Enabled
|| !TryComp(uid, out NodeContainerComponent? nodeContainer)
|| !TryComp(uid, out AtmosDeviceComponent? device)
|| !nodeContainer.TryGetNode(pump.InletName, out PipeNode? inlet)
|| !nodeContainer.TryGetNode(pump.OutletName, out PipeNode? outlet))
{
appearance?.SetData(PumpVisuals.Enabled, false);
return;
}
var inputStartingPressure = inlet.Air.Pressure;
var outputStartingPressure = outlet.Air.Pressure;
@ -78,6 +73,8 @@ namespace Content.Server.Atmos.Piping.Binary.EntitySystems
if ((outputStartingPressure - inputStartingPressure > pump.OverclockThreshold) && pump.Overclocked)
return;
appearance?.SetData(PumpVisuals.Enabled, true);
// We multiply the transfer rate in L/s by the seconds passed since the last process to get the liters.
var transferRatio = (float)(pump.TransferRate * (_gameTiming.CurTime - device.LastProcess).TotalSeconds) / inlet.Air.Volume;
@ -126,7 +123,7 @@ namespace Content.Server.Atmos.Piping.Binary.EntitySystems
private void OnTransferRateChangeMessage(EntityUid uid, GasVolumePumpComponent pump, GasVolumePumpChangeTransferRateMessage args)
{
pump.TransferRate = Math.Clamp(args.TransferRate, 0f, Atmospherics.MaxTransferRate);
pump.TransferRate = Math.Clamp(args.TransferRate, 0f, pump.MaxTransferRate);
_adminLogSystem.Add(LogType.AtmosVolumeChanged, LogImpact.Medium,
$"{ToPrettyString(args.Session.AttachedEntity!.Value):player} set the transfer rate on {ToPrettyString(uid):device} to {args.TransferRate}");
DirtyUI(uid, pump);

View file

@ -1,9 +1,4 @@
using System;
using Content.Server.Atmos.Piping.Trinary.EntitySystems;
using Content.Shared.Atmos;
using Robust.Shared.GameObjects;
using Robust.Shared.Serialization.Manager.Attributes;
using Robust.Shared.ViewVariables;
namespace Content.Server.Atmos.Piping.Trinary.Components
{
@ -26,8 +21,13 @@ namespace Content.Server.Atmos.Piping.Trinary.Components
public string OutletName { get; set; } = "outlet";
[ViewVariables(VVAccess.ReadWrite)]
[DataField("transferRate")]
public float TransferRate { get; set; } = Atmospherics.MaxTransferRate;
[DataField("maxTransferRate")]
public float MaxTransferRate { get; set; } = Atmospherics.MaxTransferRate;
[ViewVariables(VVAccess.ReadWrite)]
public Gas? FilteredGas { get; set; }
}

View file

@ -23,8 +23,13 @@ namespace Content.Server.Atmos.Piping.Trinary.Components
public string OutletName = "outlet";
[ViewVariables(VVAccess.ReadWrite)]
[DataField("targetPressure")]
public float TargetPressure = Atmospherics.OneAtmosphere;
[ViewVariables(VVAccess.ReadWrite)]
[DataField("maxTargetPressure")]
public float MaxTargetPressure = Atmospherics.MaxOutputPressure;
[ViewVariables(VVAccess.ReadWrite)]
[DataField("inletOneConcentration")]
public float InletOneConcentration = 0.5f;

View file

@ -138,7 +138,7 @@ namespace Content.Server.Atmos.Piping.Trinary.EntitySystems
private void OnTransferRateChangeMessage(EntityUid uid, GasFilterComponent filter, GasFilterChangeRateMessage args)
{
filter.TransferRate = Math.Clamp(args.Rate, 0f, Atmospherics.MaxTransferRate);
filter.TransferRate = Math.Clamp(args.Rate, 0f, filter.MaxTransferRate);
_adminLogSystem.Add(LogType.AtmosVolumeChanged, LogImpact.Medium,
$"{ToPrettyString(args.Session.AttachedEntity!.Value):player} set the transfer rate on {ToPrettyString(uid):device} to {args.Rate}");
DirtyUI(uid, filter);

View file

@ -173,7 +173,7 @@ namespace Content.Server.Atmos.Piping.Trinary.EntitySystems
private void OnOutputPressureChangeMessage(EntityUid uid, GasMixerComponent mixer, GasMixerChangeOutputPressureMessage args)
{
mixer.TargetPressure = Math.Clamp(args.Pressure, 0f, Atmospherics.MaxOutputPressure);
mixer.TargetPressure = Math.Clamp(args.Pressure, 0f, mixer.MaxTargetPressure);
_adminLogSystem.Add(LogType.AtmosPressureChanged, LogImpact.Medium,
$"{ToPrettyString(args.Session.AttachedEntity!.Value):player} set the pressure on {ToPrettyString(uid):device} to {args.Pressure}kPa");
DirtyUI(uid, mixer);

View file

@ -1,10 +1,10 @@
using Robust.Shared.GameObjects;
using Robust.Shared.Serialization.Manager.Attributes;
using Robust.Shared.ViewVariables;
using Content.Server.Atmos.Piping.Unary.EntitySystems;
using Content.Shared.Atmos;
namespace Content.Server.Atmos.Piping.Unary.Components
{
[RegisterComponent]
[Friend(typeof(GasOutletInjectorSystem))]
public sealed class GasOutletInjectorComponent : Component
{
@ -14,12 +14,26 @@ namespace Content.Server.Atmos.Piping.Unary.Components
[ViewVariables(VVAccess.ReadWrite)]
public bool Injecting { get; set; } = false;
/// <summary>
/// Target volume to transfer. If <see cref="WideNet"/> is enabled, actual transfer rate will be much higher.
/// </summary>
[ViewVariables(VVAccess.ReadWrite)]
public float VolumeRate { get; set; } = 50f;
public float TransferRate
{
get => _transferRate;
set => _transferRate = Math.Clamp(value, 0f, MaxTransferRate);
}
private float _transferRate = 50;
[ViewVariables(VVAccess.ReadWrite)]
[DataField("maxTransferRate")]
public float MaxTransferRate = Atmospherics.MaxTransferRate;
[DataField("maxPressure")]
public float MaxPressure { get; set; } = 2 * Atmospherics.MaxOutputPressure;
[DataField("inlet")]
public string InletName { get; set; } = "pipe";
// TODO ATMOS: Inject method.
}
}

View file

@ -1,9 +1,5 @@
using System;
using Content.Shared.Atmos;
using Content.Shared.Atmos.Piping.Unary.Components;
using Robust.Shared.GameObjects;
using Robust.Shared.Serialization.Manager.Attributes;
using Robust.Shared.ViewVariables;
namespace Content.Server.Atmos.Piping.Unary.Components
{
@ -24,17 +20,57 @@ namespace Content.Server.Atmos.Piping.Unary.Components
public string InletName { get; set; } = "pipe";
[ViewVariables(VVAccess.ReadWrite)]
[DataField("pumpDirection")]
public VentPumpDirection PumpDirection { get; set; } = VentPumpDirection.Releasing;
[ViewVariables(VVAccess.ReadWrite)]
[DataField("pressureChecks")]
public VentPressureBound PressureChecks { get; set; } = VentPressureBound.ExternalBound;
[ViewVariables(VVAccess.ReadWrite)]
[DataField("externalPressureBound")]
public float ExternalPressureBound { get; set; } = Atmospherics.OneAtmosphere;
public float ExternalPressureBound
{
get => _externalPressureBound;
set
{
_externalPressureBound = Math.Clamp(value, 0, MaxPressure);
}
}
private float _externalPressureBound = Atmospherics.OneAtmosphere;
[ViewVariables(VVAccess.ReadWrite)]
public float InternalPressureBound { get; set; } = 0f;
[DataField("internalPressureBound")]
public float InternalPressureBound
{
get => _internalPressureBound;
set
{
_internalPressureBound = Math.Clamp(value, 0, MaxPressure);
}
}
private float _internalPressureBound = 0;
/// <summary>
/// Max pressure of the target gas (NOT relative to source).
/// </summary>
[ViewVariables(VVAccess.ReadWrite)]
[DataField("maxPressure")]
public float MaxPressure = Atmospherics.MaxOutputPressure;
/// <summary>
/// Pressure pump speed in kPa/s. Determines how much gas is moved.
/// </summary>
/// <remarks>
/// The pump will attempt to modify the destination's final pressure by this quantity every second. If this
/// is too high, and the vent is connected to a large pipe-net, then someone can nearly instantly flood a
/// room with gas.
/// </remarks>
[ViewVariables(VVAccess.ReadWrite)]
[DataField("targetPressureChange")]
public float TargetPressureChange = Atmospherics.OneAtmosphere;
public GasVentPumpData ToAirAlarmData()
{

View file

@ -1,14 +1,12 @@
using System.Collections.Generic;
using System.Linq;
using Content.Server.Atmos.Piping.Unary.EntitySystems;
using Content.Shared.Atmos;
using Content.Shared.Atmos.Piping.Unary.Components;
using Robust.Shared.GameObjects;
using Robust.Shared.Serialization.Manager.Attributes;
using Robust.Shared.ViewVariables;
namespace Content.Server.Atmos.Piping.Unary.Components
{
[RegisterComponent]
[Friend(typeof(GasVentScrubberSystem))]
public sealed class GasVentScrubberComponent : Component
{
[ViewVariables(VVAccess.ReadWrite)]
@ -30,8 +28,28 @@ namespace Content.Server.Atmos.Piping.Unary.Components
[ViewVariables(VVAccess.ReadWrite)]
public ScrubberPumpDirection PumpDirection { get; set; } = ScrubberPumpDirection.Scrubbing;
/// <summary>
/// Target volume to transfer. If <see cref="WideNet"/> is enabled, actual transfer rate will be much higher.
/// </summary>
[ViewVariables(VVAccess.ReadWrite)]
public float VolumeRate { get; set; } = 200f;
public float TransferRate
{
get => _transferRate;
set => _transferRate = Math.Clamp(value, 0f, MaxTransferRate);
}
private float _transferRate = Atmospherics.MaxTransferRate;
[ViewVariables(VVAccess.ReadWrite)]
[DataField("maxTransferRate")]
public float MaxTransferRate = Atmospherics.MaxTransferRate;
/// <summary>
/// As pressure difference approaches this number, the effective volume rate may be smaller than <see
/// cref="TransferRate"/>
/// </summary>
[DataField("maxPressure")]
public float MaxPressure = Atmospherics.MaxOutputPressure;
[ViewVariables(VVAccess.ReadWrite)]
public bool WideNet { get; set; } = false;
@ -46,7 +64,7 @@ namespace Content.Server.Atmos.Piping.Unary.Components
Dirty = IsDirty,
FilterGases = FilterGases,
PumpDirection = PumpDirection,
VolumeRate = VolumeRate,
VolumeRate = TransferRate,
WideNet = WideNet
};
}
@ -56,7 +74,7 @@ namespace Content.Server.Atmos.Piping.Unary.Components
Enabled = data.Enabled;
IsDirty = data.Dirty;
PumpDirection = (ScrubberPumpDirection) data.PumpDirection!;
VolumeRate = (float) data.VolumeRate!;
TransferRate = (float) data.VolumeRate!;
WideNet = data.WideNet;
if (!data.FilterGases!.SequenceEqual(FilterGases))

View file

@ -3,10 +3,8 @@ using Content.Server.Atmos.Piping.Components;
using Content.Server.Atmos.Piping.Unary.Components;
using Content.Server.NodeContainer;
using Content.Server.NodeContainer.Nodes;
using Content.Shared.Atmos;
using JetBrains.Annotations;
using Robust.Shared.GameObjects;
using Robust.Shared.IoC;
using Robust.Shared.Timing;
namespace Content.Server.Atmos.Piping.Unary.EntitySystems
{
@ -14,6 +12,7 @@ namespace Content.Server.Atmos.Piping.Unary.EntitySystems
public sealed class GasOutletInjectorSystem : EntitySystem
{
[Dependency] private readonly AtmosphereSystem _atmosphereSystem = default!;
[Dependency] private readonly IGameTiming _gameTiming = default!;
public override void Initialize()
{
@ -32,6 +31,9 @@ namespace Content.Server.Atmos.Piping.Unary.EntitySystems
if (!EntityManager.TryGetComponent(uid, out NodeContainerComponent? nodeContainer))
return;
if (!TryComp(uid, out AtmosDeviceComponent? device))
return;
if (!nodeContainer.TryGetNode(injector.InletName, out PipeNode? inlet))
return;
@ -40,14 +42,14 @@ namespace Content.Server.Atmos.Piping.Unary.EntitySystems
if (environment == null)
return;
if (inlet.Air.Temperature > 0)
{
var transferMoles = inlet.Air.Pressure * injector.VolumeRate / (inlet.Air.Temperature * Atmospherics.R);
if (inlet.Air.Temperature < 0)
return;
var removed = inlet.Air.Remove(transferMoles);
var timeDelta = (float) (_gameTiming.CurTime - device.LastProcess).TotalSeconds;
var ratio = MathF.Min(1f, timeDelta * injector.TransferRate / inlet.Air.Volume);
var removed = inlet.Air.RemoveRatio(ratio);
_atmosphereSystem.Merge(environment, removed);
}
_atmosphereSystem.Merge(environment, removed);
}
}
}

View file

@ -1,4 +1,3 @@
using System;
using Content.Server.Atmos.EntitySystems;
using Content.Server.Atmos.Monitor.Components;
using Content.Server.Atmos.Monitor.Systems;
@ -12,12 +11,10 @@ using Content.Server.NodeContainer.Nodes;
using Content.Server.Power.Components;
using Content.Shared.Atmos;
using Content.Shared.Atmos.Monitor;
using Content.Shared.Atmos.Monitor.Components;
using Content.Shared.Atmos.Piping.Unary.Components;
using Content.Shared.Atmos.Visuals;
using JetBrains.Annotations;
using Robust.Shared.GameObjects;
using Robust.Shared.IoC;
using Robust.Shared.Timing;
namespace Content.Server.Atmos.Piping.Unary.EntitySystems
{
@ -26,6 +23,7 @@ namespace Content.Server.Atmos.Piping.Unary.EntitySystems
{
[Dependency] private readonly AtmosphereSystem _atmosphereSystem = default!;
[Dependency] private readonly DeviceNetworkSystem _deviceNetSystem = default!;
[Dependency] private readonly IGameTiming _gameTiming = default!;
public override void Initialize()
{
@ -49,7 +47,8 @@ namespace Content.Server.Atmos.Piping.Unary.EntitySystems
}
if (!vent.Enabled
|| !EntityManager.TryGetComponent(uid, out NodeContainerComponent? nodeContainer)
|| !TryComp(uid, out AtmosDeviceComponent? device)
|| !TryComp(uid, out NodeContainerComponent? nodeContainer)
|| !nodeContainer.TryGetNode(vent.InletName, out PipeNode? pipe))
{
appearance?.SetData(VentPumpVisuals.State, VentPumpState.Off);
@ -65,43 +64,71 @@ namespace Content.Server.Atmos.Piping.Unary.EntitySystems
return;
}
if (vent.PumpDirection == VentPumpDirection.Releasing)
var timeDelta = (_gameTiming.CurTime - device.LastProcess).TotalSeconds;
var pressureDelta = (float) timeDelta * vent.TargetPressureChange;
if (vent.PumpDirection == VentPumpDirection.Releasing && pipe.Air.Pressure > 0)
{
appearance?.SetData(VentPumpVisuals.State, VentPumpState.Out);
var pressureDelta = 10000f;
if (environment.Pressure > vent.MaxPressure)
return;
if ((vent.PressureChecks & VentPressureBound.ExternalBound) != 0)
pressureDelta = MathF.Min(pressureDelta, vent.ExternalPressureBound - environment.Pressure);
if (pressureDelta <= 0)
return;
// how many moles to transfer to change external pressure by pressureDelta
// (ignoring temperature differences because I am lazy)
var transferMoles = pressureDelta * environment.Volume / (pipe.Air.Temperature * Atmospherics.R);
// limit transferMoles so the source doesn't go below its bound.
if ((vent.PressureChecks & VentPressureBound.InternalBound) != 0)
pressureDelta = MathF.Min(pressureDelta, pipe.Air.Pressure - vent.InternalPressureBound);
if (pressureDelta > 0 && pipe.Air.Temperature > 0)
{
var transferMoles = pressureDelta * environment.Volume / (pipe.Air.Temperature * Atmospherics.R);
var internalDelta = pipe.Air.Pressure - vent.InternalPressureBound;
_atmosphereSystem.Merge(environment, pipe.Air.Remove(transferMoles));
if (internalDelta <= 0)
return;
var maxTransfer = internalDelta * pipe.Air.Volume / (pipe.Air.Temperature * Atmospherics.R);
transferMoles = MathF.Min(transferMoles, maxTransfer);
}
_atmosphereSystem.Merge(environment, pipe.Air.Remove(transferMoles));
}
else if (vent.PumpDirection == VentPumpDirection.Siphoning && environment.Pressure > 0)
{
appearance?.SetData(VentPumpVisuals.State, VentPumpState.In);
var ourMultiplier = pipe.Air.Volume / (environment.Temperature * Atmospherics.R);
var molesDelta = 10000f * ourMultiplier;
if ((vent.PressureChecks & VentPressureBound.ExternalBound) != 0)
molesDelta = MathF.Min(molesDelta,
(environment.Pressure - vent.ExternalPressureBound) * environment.Volume /
(environment.Temperature * Atmospherics.R));
if (pipe.Air.Pressure > vent.MaxPressure)
return;
if ((vent.PressureChecks & VentPressureBound.InternalBound) != 0)
molesDelta = MathF.Min(molesDelta, (vent.InternalPressureBound - pipe.Air.Pressure) * ourMultiplier);
pressureDelta = MathF.Min(pressureDelta, vent.InternalPressureBound - pipe.Air.Pressure);
if (molesDelta > 0)
if (pressureDelta <= 0)
return;
// how many moles to transfer to change internal pressure by pressureDelta
// (ignoring temperature differences because I am lazy)
var transferMoles = pressureDelta * pipe.Air.Volume / (environment.Temperature * Atmospherics.R);
// limit transferMoles so the source doesn't go below its bound.
if ((vent.PressureChecks & VentPressureBound.ExternalBound) != 0)
{
var removed = environment.Remove(molesDelta);
_atmosphereSystem.Merge(pipe.Air, removed);
var externalDelta = environment.Pressure - vent.ExternalPressureBound;
if (externalDelta <= 0)
return;
var maxTransfer = externalDelta * environment.Volume / (environment.Temperature * Atmospherics.R);
transferMoles = MathF.Min(transferMoles, maxTransfer);
}
_atmosphereSystem.Merge(pipe.Air, environment.Remove(transferMoles));
}
}

View file

@ -15,15 +15,14 @@ using Content.Shared.Atmos.Piping.Unary.Visuals;
using Content.Shared.Atmos.Monitor;
using Content.Shared.Atmos.Piping.Unary.Components;
using JetBrains.Annotations;
using Robust.Shared.GameObjects;
using Robust.Shared.IoC;
using Robust.Shared.Maths;
using Robust.Shared.Timing;
namespace Content.Server.Atmos.Piping.Unary.EntitySystems
{
[UsedImplicitly]
public sealed class GasVentScrubberSystem : EntitySystem
{
[Dependency] private readonly IGameTiming _gameTiming = default!;
[Dependency] private readonly AtmosphereSystem _atmosphereSystem = default!;
[Dependency] private readonly DeviceNetworkSystem _deviceNetSystem = default!;
@ -36,7 +35,6 @@ namespace Content.Server.Atmos.Piping.Unary.EntitySystems
SubscribeLocalEvent<GasVentScrubberComponent, AtmosMonitorAlarmEvent>(OnAtmosAlarm);
SubscribeLocalEvent<GasVentScrubberComponent, PowerChangedEvent>(OnPowerChanged);
SubscribeLocalEvent<GasVentScrubberComponent, PacketSentEvent>(OnPacketRecv);
}
private void OnVentScrubberUpdated(EntityUid uid, GasVentScrubberComponent scrubber, AtmosDeviceUpdateEvent args)
@ -49,6 +47,11 @@ namespace Content.Server.Atmos.Piping.Unary.EntitySystems
return;
}
if (!TryComp(uid, out AtmosDeviceComponent? device))
return;
var timeDelta = (float) (_gameTiming.CurTime - device.LastProcess).TotalSeconds;
if (!scrubber.Enabled
|| !EntityManager.TryGetComponent(uid, out NodeContainerComponent? nodeContainer)
|| !nodeContainer.TryGetNode(scrubber.OutletName, out PipeNode? outlet))
@ -59,14 +62,14 @@ namespace Content.Server.Atmos.Piping.Unary.EntitySystems
var environment = _atmosphereSystem.GetTileMixture(EntityManager.GetComponent<TransformComponent>(scrubber.Owner).Coordinates, true);
Scrub(_atmosphereSystem, scrubber, appearance, environment, outlet);
Scrub(timeDelta, scrubber, appearance, environment, outlet);
if (!scrubber.WideNet) return;
// Scrub adjacent tiles too.
foreach (var adjacent in _atmosphereSystem.GetAdjacentTileMixtures(EntityManager.GetComponent<TransformComponent>(scrubber.Owner).Coordinates, false, true))
{
Scrub(_atmosphereSystem, scrubber, null, adjacent, outlet);
Scrub(timeDelta, scrubber, null, adjacent, outlet);
}
}
@ -78,7 +81,7 @@ namespace Content.Server.Atmos.Piping.Unary.EntitySystems
}
}
private void Scrub(AtmosphereSystem atmosphereSystem, GasVentScrubberComponent scrubber, AppearanceComponent? appearance, GasMixture? tile, PipeNode outlet)
private void Scrub(float timeDelta, GasVentScrubberComponent scrubber, AppearanceComponent? appearance, GasMixture? tile, PipeNode outlet)
{
// Cannot scrub if tile is null or air-blocked.
if (tile == null
@ -88,29 +91,26 @@ namespace Content.Server.Atmos.Piping.Unary.EntitySystems
return;
}
// Take a gas sample.
var ratio = MathF.Min(1f, timeDelta * scrubber.TransferRate / tile.Volume);
var removed = tile.RemoveRatio(ratio);
// Nothing left to remove from the tile.
if (MathHelper.CloseToPercent(removed.TotalMoles, 0f))
return;
if (scrubber.PumpDirection == ScrubberPumpDirection.Scrubbing)
{
appearance?.SetData(ScrubberVisuals.State, scrubber.WideNet ? ScrubberState.WideScrub : ScrubberState.Scrub);
var transferMoles = MathF.Min(1f, scrubber.VolumeRate / tile.Volume) * tile.TotalMoles;
// Take a gas sample.
var removed = tile.Remove(transferMoles);
// Nothing left to remove from the tile.
if (MathHelper.CloseToPercent(removed.TotalMoles, 0f))
return;
atmosphereSystem.ScrubInto(removed, outlet.Air, scrubber.FilterGases);
_atmosphereSystem.ScrubInto(removed, outlet.Air, scrubber.FilterGases);
// Remix the gases.
atmosphereSystem.Merge(tile, removed);
_atmosphereSystem.Merge(tile, removed);
}
else if (scrubber.PumpDirection == ScrubberPumpDirection.Siphoning)
{
appearance?.SetData(ScrubberVisuals.State, ScrubberState.Siphon);
var transferMoles = tile.TotalMoles * (scrubber.VolumeRate / tile.Volume);
var removed = tile.Remove(transferMoles);
_atmosphereSystem.Merge(outlet.Air, removed);
}

View file

@ -72,7 +72,7 @@ namespace Content.Server.Botany.Systems
if (_timer < 3f)
return;
_timer = 0f;
_timer -= 3f;
foreach (var plantHolder in EntityManager.EntityQuery<PlantHolderComponent>())
{

View file

@ -109,19 +109,19 @@ namespace Content.Server.Chat.Managers
DispatchServerAnnouncement(Loc.GetString(val ? "chat-manager-admin-ooc-chat-enabled-message" : "chat-manager-admin-ooc-chat-disabled-message"));
}
public void DispatchServerAnnouncement(string message)
public void DispatchServerAnnouncement(string message, Color? colorOverride = null)
{
var messageWrap = Loc.GetString("chat-manager-server-wrap-message");
NetMessageToAll(ChatChannel.Server, message, messageWrap);
NetMessageToAll(ChatChannel.Server, message, messageWrap, colorOverride);
Logger.InfoS("SERVER", message);
_logs.Add(LogType.Chat, LogImpact.Low, $"Server announcement: {message}");
}
public void DispatchStationAnnouncement(string message, string sender = "Central Command", bool playDefaultSound = true)
public void DispatchStationAnnouncement(string message, string sender = "Central Command", bool playDefaultSound = true, Color? colorOverride = null)
{
var messageWrap = Loc.GetString("chat-manager-sender-announcement-wrap-message", ("sender", sender));
NetMessageToAll(ChatChannel.Radio, message, messageWrap);
NetMessageToAll(ChatChannel.Radio, message, messageWrap, colorOverride);
if (playDefaultSound)
{
SoundSystem.Play(Filter.Broadcast(), "/Audio/Announcements/announce.ogg", AudioParams.Default.WithVolume(-2f));
@ -596,12 +596,16 @@ namespace Content.Server.Chat.Managers
_netManager.ServerSendMessage(msg, client);
}
public void NetMessageToAll(ChatChannel channel, string message, string messageWrap)
public void NetMessageToAll(ChatChannel channel, string message, string messageWrap, Color? colorOverride = null)
{
var msg = _netManager.CreateNetMessage<MsgChatMessage>();
msg.Channel = channel;
msg.Message = message;
msg.MessageWrap = messageWrap;
if (colorOverride != null)
{
msg.MessageColorOverride = colorOverride.Value;
}
_netManager.ServerSendToAll(msg);
}

View file

@ -12,7 +12,9 @@ namespace Content.Server.Chat.Managers
/// <summary>
/// Dispatch a server announcement to every connected player.
/// </summary>
void DispatchServerAnnouncement(string message);
/// <param name="message"></param>
/// <param name="colorOverride">Override the color of the message being sent.</param>
void DispatchServerAnnouncement(string message, Color? colorOverride = null);
/// <summary>
/// Station announcement to every player
@ -20,7 +22,8 @@ namespace Content.Server.Chat.Managers
/// <param name="message"></param>
/// <param name="sender"></param>
/// <param name="playDefaultSound">If the default 'PA' sound should be played.</param>
void DispatchStationAnnouncement(string message, string sender = "CentComm", bool playDefaultSound = true);
/// <param name="colorOverride">Override the color of the message being sent.</param>
void DispatchStationAnnouncement(string message, string sender = "CentComm", bool playDefaultSound = true, Color? colorOverride = null);
void DispatchServerMessage(IPlayerSession player, string message);

View file

@ -3,6 +3,7 @@ using Content.Server.Chemistry.Components;
using Content.Server.Chemistry.EntitySystems;
using Content.Server.Coordinates.Helpers;
using Content.Shared.Audio;
using Content.Shared.Chemistry.Components;
using Content.Shared.Chemistry.Reagent;
using Content.Shared.Database;
using Content.Shared.Sound;

View file

@ -1,7 +1,14 @@
using Content.Server.Chemistry.Components;
using Content.Server.Coordinates.Helpers;
using Content.Shared.Audio;
using Content.Shared.Chemistry.Components;
using Content.Shared.Sound;
using JetBrains.Annotations;
using Robust.Shared.Audio;
using Robust.Shared.GameObjects;
using Robust.Shared.IoC;
using Robust.Shared.Map;
using Robust.Shared.Player;
using Robust.Shared.Serialization.Manager.Attributes;
namespace Content.Server.Chemistry.ReactionEffects
@ -14,5 +21,27 @@ namespace Content.Server.Chemistry.ReactionEffects
{
return IoCManager.Resolve<IEntityManager>().GetComponentOrNull<FoamSolutionAreaEffectComponent>(entity);
}
public static void SpawnFoam(string entityPrototype, EntityCoordinates coords, Solution? contents, int amount, float duration, float spreadDelay,
float removeDelay, SoundSpecifier sound, IEntityManager? entityManager = null)
{
entityManager ??= IoCManager.Resolve<IEntityManager>();
var ent = entityManager.SpawnEntity(entityPrototype, coords.SnapToGrid());
var areaEffectComponent = entityManager.GetComponentOrNull<FoamSolutionAreaEffectComponent>(ent);
if (areaEffectComponent == null)
{
Logger.Error("Couldn't get AreaEffectComponent from " + entityPrototype);
IoCManager.Resolve<IEntityManager>().QueueDeleteEntity(ent);
return;
}
if (contents != null)
areaEffectComponent.TryAddSolution(contents);
areaEffectComponent.Start(amount, duration, spreadDelay, removeDelay);
SoundSystem.Play(Filter.Pvs(ent), sound.GetSound(), ent, AudioHelpers.WithVariation(0.125f));
}
}
}

View file

@ -109,7 +109,7 @@ namespace Content.Server.Communications
}
message += $"\nSent by {author}";
_chatManager.DispatchStationAnnouncement(message, "Communications Console");
_chatManager.DispatchStationAnnouncement(message, "Communications Console", colorOverride: Color.Gold);
break;
}
}

View file

@ -1,14 +1,16 @@
using Robust.Shared.GameObjects;
using Robust.Shared.Serialization.Manager.Attributes;
using Robust.Shared.ViewVariables;
using Robust.Shared.Prototypes;
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype;
namespace Content.Server.Construction.Components
{
/// <summary>
/// Used for construction graphs in building computers.
/// </summary>
[RegisterComponent]
public sealed class ComputerBoardComponent : Component
{
[ViewVariables]
[DataField("prototype")]
[DataField("prototype", customTypeSerializer:typeof(PrototypeIdSerializer<EntityPrototype>))]
public string? Prototype { get; private set; }
}
}

View file

@ -25,7 +25,7 @@ namespace Content.Server.Dice
base.Initialize();
SubscribeLocalEvent<DiceComponent, ComponentInit>(OnComponentInit);
SubscribeLocalEvent<DiceComponent, ActivateInWorldEvent>(OnActivate);
SubscribeLocalEvent<DiceComponent, UseInHandEvent>(OnUseInHand);
SubscribeLocalEvent<DiceComponent, LandEvent>(OnLand);
SubscribeLocalEvent<DiceComponent, ExaminedEvent>(OnExamined);
}
@ -36,8 +36,11 @@ namespace Content.Server.Dice
component.CurrentSide = component.Sides;
}
private void OnActivate(EntityUid uid, DiceComponent component, ActivateInWorldEvent args)
private void OnUseInHand(EntityUid uid, DiceComponent component, UseInHandEvent args)
{
if (args.Handled) return;
args.Handled = true;
Roll(uid, component);
}

View file

@ -1,21 +1,15 @@
using System;
using System.Collections.Generic;
using Content.Server.Flash.Components;
using Content.Server.Stunnable;
using Content.Server.Weapon.Melee;
using Content.Shared.Examine;
using Content.Shared.Flash;
using Content.Shared.Interaction;
using Content.Shared.Interaction.Helpers;
using Content.Shared.Inventory;
using Content.Shared.Physics;
using Content.Shared.Popups;
using Content.Shared.Sound;
using Robust.Server.GameObjects;
using Robust.Shared.Audio;
using Robust.Shared.GameObjects;
using Robust.Shared.IoC;
using Robust.Shared.Localization;
using Robust.Shared.Player;
using Robust.Shared.Timing;
using InventoryComponent = Content.Shared.Inventory.InventoryComponent;
@ -28,18 +22,40 @@ namespace Content.Server.Flash
[Dependency] private readonly IGameTiming _gameTiming = default!;
[Dependency] private readonly StunSystem _stunSystem = default!;
[Dependency] private readonly InventorySystem _inventorySystem = default!;
[Dependency] private readonly MetaDataSystem _metaSystem = default!;
[Dependency] private readonly SharedInteractionSystem _interactionSystem = default!;
public override void Initialize()
{
base.Initialize();
SubscribeLocalEvent<FlashComponent, MeleeHitEvent>(OnFlashMeleeHit);
SubscribeLocalEvent<FlashComponent, MeleeInteractEvent>(OnFlashMeleeInteract);
SubscribeLocalEvent<FlashComponent, UseInHandEvent>(OnFlashUseInHand);
SubscribeLocalEvent<FlashComponent, ExaminedEvent>(OnFlashExamined);
SubscribeLocalEvent<InventoryComponent, FlashAttemptEvent>(OnInventoryFlashAttempt);
SubscribeLocalEvent<FlashImmunityComponent, FlashAttemptEvent>(OnFlashImmunityFlashAttempt);
SubscribeLocalEvent<FlashableComponent, ComponentStartup>(OnFlashableStartup);
SubscribeLocalEvent<FlashableComponent, ComponentShutdown>(OnFlashableShutdown);
SubscribeLocalEvent<FlashableComponent, MetaFlagRemoveAttemptEvent>(OnMetaFlagRemoval);
}
private void OnMetaFlagRemoval(EntityUid uid, FlashableComponent component, ref MetaFlagRemoveAttemptEvent args)
{
if (component.LifeStage == ComponentLifeStage.Running)
args.Cancelled = true;
}
private void OnFlashableStartup(EntityUid uid, FlashableComponent component, ComponentStartup args)
{
_metaSystem.AddFlag(uid, MetaDataFlags.EntitySpecific);
}
private void OnFlashableShutdown(EntityUid uid, FlashableComponent component, ComponentShutdown args)
{
_metaSystem.RemoveFlag(uid, MetaDataFlags.EntitySpecific);
}
private void OnFlashMeleeHit(EntityUid uid, FlashComponent comp, MeleeHitEvent args)

View file

@ -1,15 +1,10 @@
using System.Collections.Generic;
using Content.Server.Administration;
using Content.Server.Roles;
using Content.Server.Station;
using Content.Shared.Administration;
using Content.Shared.GameTicking;
using Content.Shared.Roles;
using Content.Shared.Station;
using Robust.Server.Player;
using Robust.Shared.Console;
using Robust.Shared.GameObjects;
using Robust.Shared.IoC;
using Robust.Shared.Localization;
using Robust.Shared.Prototypes;
namespace Content.Server.GameTicking.Commands
@ -45,8 +40,9 @@ namespace Content.Server.GameTicking.Commands
var ticker = EntitySystem.Get<GameTicker>();
var stationSystem = EntitySystem.Get<StationSystem>();
if (!ticker.PlayersInLobby.ContainsKey(player))
if (!ticker.PlayersInLobby.ContainsKey(player) || ticker.PlayersInLobby[player] == LobbyPlayerStatus.Observer)
{
Logger.InfoS("security", $"{player.Name} ({player.UserId}) attempted to latejoin while in-game.");
shell.WriteError($"{player.Name} is not in the lobby. This incident will be reported.");
return;
}

View file

@ -1,16 +1,11 @@
// ReSharper disable once RedundantUsingDirective
// Used to warn the player in big red letters in debug mode
using System.Linq;
using Content.Server.Administration;
using Content.Shared.Administration;
using Robust.Server.Player;
using Robust.Shared.Console;
using Robust.Shared.GameObjects;
using Robust.Shared.IoC;
using Robust.Shared.Map;
using Robust.Shared.Prototypes;
using Robust.Shared.Timing;
using Robust.Shared.Utility;
namespace Content.Server.GameTicking.Commands
@ -22,14 +17,19 @@ namespace Content.Server.GameTicking.Commands
public string Command => "mapping";
public string Description => "Creates and teleports you to a new uninitialized map for mapping.";
public string Help => $"Usage: {Command} <mapname> / {Command} <id> <mapname>";
public string Help => $"Usage: {Command} <MapID> <Path>";
public void Execute(IConsoleShell shell, string argStr, string[] args)
{
var player = shell.Player as IPlayerSession;
if (player == null)
if (shell.Player is not IPlayerSession player)
{
shell.WriteLine("Only players can use this command");
shell.WriteError("Only players can use this command");
return;
}
if (args.Length > 2)
{
shell.WriteLine(Help);
return;
}
@ -38,60 +38,62 @@ namespace Content.Server.GameTicking.Commands
#endif
var mapManager = IoCManager.Resolve<IMapManager>();
int mapId;
string mapName;
MapId mapId;
switch (args.Length)
// Get the map ID to use
if (args.Length is 1 or 2)
{
case 1:
if (player.AttachedEntity == null)
{
shell.WriteError("The map name argument cannot be omitted if you have no entity.");
return;
}
mapId = (int) mapManager.NextMapId();
mapName = args[0];
break;
case 2:
if (!int.TryParse(args[0], out var id))
{
shell.WriteError($"{args[0]} is not a valid integer.");
return;
}
mapId = id;
mapName = args[1];
break;
default:
shell.WriteLine(Help);
if (!int.TryParse(args[0], out var id))
{
shell.WriteError($"{args[0]} is not a valid integer.");
return;
}
mapId = new MapId(id);
if (mapManager.MapExists(mapId))
{
shell.WriteError($"Map {mapId} already exists");
return;
}
}
else
{
mapId = mapManager.NextMapId();
}
// loadmap checks for this on its own but we want to avoid running our other commands.
if (mapManager.MapExists(new MapId(mapId)))
DebugTools.Assert(args.Length <= 2);
// either load a map or create a new one.
if (args.Length <= 1)
shell.ExecuteCommand($"addmap {mapId} false");
else
shell.ExecuteCommand($"loadmap {mapId} \"{CommandParsing.Escape(args[1])}\"");
// was the map actually created?
if (!mapManager.MapExists(mapId))
{
shell.WriteError($"Map {mapId} already exists");
shell.WriteError($"An error occurred when creating the new map.");
return;
}
shell.ExecuteCommand("sudo cvar events.enabled false");
shell.ExecuteCommand($"loadmap {mapId} \"{CommandParsing.Escape(mapName)}\" true");
if (player.AttachedEntity is {Valid: true} playerEntity &&
// map successfully created. run misc helpful mapping commands
if (player.AttachedEntity is { Valid: true } playerEntity &&
_entities.GetComponent<MetaDataComponent>(playerEntity).EntityPrototype?.ID != "AdminObserver")
{
shell.ExecuteCommand("aghost");
}
shell.ExecuteCommand("sudo cvar events.enabled false");
shell.ExecuteCommand($"tp 0 0 {mapId}");
shell.RemoteExecuteCommand("showmarkers");
shell.RemoteExecuteCommand("togglelight");
shell.RemoteExecuteCommand("showsubfloorforever");
mapManager.SetMapPaused(mapId, true);
var newGrid = mapManager.GetAllGrids().OrderByDescending(g => (int) g.Index).First();
mapManager.SetMapPaused(newGrid.ParentMapId, true);
shell.WriteLine($"Created unloaded map from file {mapName} with id {mapId}. Use \"savebp {newGrid.Index} foo.yml\" to save the new grid as a map.");
if (args.Length == 2)
shell.WriteLine($"Created uninitialized map from file {args[1]} with id {mapId}.");
else
shell.WriteLine($"Created a new uninitialized map with id {mapId}.");
}
}
}

View file

@ -24,6 +24,7 @@ namespace Content.Server.Ghost.Components
Icon = new SpriteSpecifier.Texture(new ResourcePath("Interface/Actions/scream.png")),
Name = "action-name-boo",
Description = "action-description-boo",
CheckCanInteract = false,
Event = new BooActionEvent(),
};
}

View file

@ -6,6 +6,7 @@ using Content.Shared.Interaction;
using Content.Shared.MobState.Components;
using Content.Shared.Nutrition.Components;
using Content.Shared.Popups;
using Content.Shared.Verbs;
using Robust.Shared.Player;
namespace Content.Server.Kitchen.EntitySystems;
@ -22,32 +23,45 @@ public sealed class SharpSystem : EntitySystem
SubscribeLocalEvent<SharpComponent, AfterInteractEvent>(OnAfterInteract);
SubscribeLocalEvent<SharpButcherDoafterComplete>(OnDoafterComplete);
SubscribeLocalEvent<SharpButcherDoafterCancelled>(OnDoafterCancelled);
SubscribeLocalEvent<SharedButcherableComponent, GetVerbsEvent<InteractionVerb>>(OnGetInteractionVerbs);
}
private void OnAfterInteract(EntityUid uid, SharpComponent component, AfterInteractEvent args)
{
if (args.Target is null || !TryComp<SharedButcherableComponent>(args.Target, out var butcher))
if (args.Target is null || !args.CanReach)
return;
TryStartButcherDoafter(uid, args.Target.Value, args.User);
}
private void TryStartButcherDoafter(EntityUid knife, EntityUid target, EntityUid user)
{
if (!TryComp<SharedButcherableComponent>(target, out var butcher))
return;
if (!TryComp<SharpComponent>(knife, out var sharp))
return;
if (butcher.Type != ButcheringType.Knife)
return;
if (TryComp<MobStateComponent>(args.Target, out var mobState) && !mobState.IsDead())
if (TryComp<MobStateComponent>(target, out var mobState) && !mobState.IsDead())
return;
if (!component.Butchering.Add(args.Target.Value))
if (!sharp.Butchering.Add(target))
return;
var doAfter =
new DoAfterEventArgs(args.User, component.ButcherDelayModifier * butcher.ButcherDelay, default, args.Target)
new DoAfterEventArgs(user, sharp.ButcherDelayModifier * butcher.ButcherDelay, default, target)
{
BreakOnTargetMove = true,
BreakOnUserMove = true,
BreakOnDamage = true,
BreakOnStun = true,
NeedHand = true,
BroadcastFinishedEvent = new SharpButcherDoafterComplete { User = args.User, Entity = args.Target.Value, Sharp = uid },
BroadcastCancelledEvent = new SharpButcherDoafterCancelled { Entity = args.Target.Value, Sharp = uid }
BroadcastFinishedEvent = new SharpButcherDoafterComplete { User = user, Entity = target, Sharp = knife },
BroadcastCancelledEvent = new SharpButcherDoafterCancelled { Entity = target, Sharp = knife }
};
_doAfterSystem.DoAfter(doAfter);
@ -89,6 +103,42 @@ public sealed class SharpSystem : EntitySystem
sharp.Butchering.Remove(ev.Entity);
}
private void OnGetInteractionVerbs(EntityUid uid, SharedButcherableComponent component, GetVerbsEvent<InteractionVerb> args)
{
if (component.Type != ButcheringType.Knife)
return;
bool disabled = false;
string? message = null;
if (TryComp<MobStateComponent>(uid, out var state) && !state.IsDead())
{
disabled = true;
message = Loc.GetString("butcherable-mob-isnt-dead");
}
if (args.Using is null || !TryComp<SharpComponent>(args.Using, out var sharp))
{
disabled = true;
message = Loc.GetString("butcherable-need-knife");
}
InteractionVerb verb = new()
{
Act = () =>
{
if (!disabled)
TryStartButcherDoafter(args.Using!.Value, args.Target, args.User);
},
Message = message,
Disabled = disabled,
IconTexture = "/Textures/Interface/VerbIcons/cutlery.svg.192dpi.png",
Text = Loc.GetString("butcherable-verb-name"),
};
args.Verbs.Add(verb);
}
}
public sealed class SharpButcherDoafterComplete : EntityEventArgs

View file

@ -1,6 +1,7 @@
using System.Threading;
using Content.Shared.Damage;
using Content.Shared.Damage.Prototypes;
using Content.Shared.Sound;
using Robust.Shared.GameObjects;
using Robust.Shared.Serialization.Manager.Attributes;
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype;
@ -42,5 +43,17 @@ namespace Content.Server.Medical.Components
public float Delay = 3f;
public CancellationTokenSource? CancelToken = null;
/// <summary>
/// Sound played on healing begin
/// </summary>
[DataField("healingBeginSound")]
public SoundSpecifier? HealingBeginSound = null;
/// <summary>
/// Sound played on healing end
/// </summary>
[DataField("healingEndSound")]
public SoundSpecifier? HealingEndSound = null;
}
}

View file

@ -4,12 +4,13 @@ using Content.Server.Body.Systems;
using Content.Server.DoAfter;
using Content.Server.Medical.Components;
using Content.Server.Stack;
using Content.Shared.ActionBlocker;
using Content.Shared.Audio;
using Content.Shared.Damage;
using Content.Shared.Database;
using Content.Shared.Interaction;
using Content.Shared.Interaction.Helpers;
using Content.Shared.Stacks;
using Robust.Shared.Audio;
using Robust.Shared.Player;
namespace Content.Server.Medical;
@ -56,6 +57,11 @@ public sealed class HealingSystem : EntitySystem
_logs.Add(LogType.Healed, $"{EntityManager.ToPrettyString(args.User):user} healed {EntityManager.ToPrettyString(uid):target} for {healed.Total:damage} damage");
else
_logs.Add(LogType.Healed, $"{EntityManager.ToPrettyString(args.User):user} healed themselves for {healed.Total:damage} damage");
if (args.Component.HealingEndSound != null)
{
SoundSystem.Play(Filter.Pvs(uid, entityManager:EntityManager), args.Component.HealingEndSound.GetSound(), uid, AudioHelpers.WithVariation(0.125f).WithVolume(-5f));
}
}
private static void OnHealingCancelled(HealingCancelledEvent ev)
@ -68,7 +74,7 @@ public sealed class HealingSystem : EntitySystem
if (args.Handled) return;
args.Handled = true;
Heal(args.User, args.User, component);
Heal(uid, args.User, args.User, component);
}
private void OnHealingAfterInteract(EntityUid uid, HealingComponent component, AfterInteractEvent args)
@ -76,10 +82,10 @@ public sealed class HealingSystem : EntitySystem
if (args.Handled || !args.CanReach || args.Target == null) return;
args.Handled = true;
Heal(args.User, args.Target.Value, component);
Heal(uid, args.User, args.Target.Value, component);
}
private void Heal(EntityUid user, EntityUid target, HealingComponent component)
private void Heal(EntityUid uid, EntityUid user, EntityUid target, HealingComponent component)
{
if (component.CancelToken != null)
{
@ -105,6 +111,11 @@ public sealed class HealingSystem : EntitySystem
component.CancelToken = new CancellationTokenSource();
if (component.HealingBeginSound != null)
{
SoundSystem.Play(Filter.Pvs(uid, entityManager:EntityManager), component.HealingBeginSound.GetSound(), uid, AudioHelpers.WithVariation(0.125f).WithVolume(-5f));
}
_doAfter.DoAfter(new DoAfterEventArgs(user, component.Delay, component.CancelToken.Token, target)
{
BreakOnUserMove = true,

View file

@ -335,7 +335,7 @@ namespace Content.Server.Nuke
var announcement = Loc.GetString("nuke-component-announcement-armed",
("time", (int) component.RemainingTime));
var sender = Loc.GetString("nuke-component-announcement-sender");
_chat.DispatchStationAnnouncement(announcement, sender, false);
_chat.DispatchStationAnnouncement(announcement, sender, false, Color.Red);
// todo: move it to announcements system
SoundSystem.Play(Filter.Broadcast(), component.ArmSound.GetSound());

View file

@ -259,6 +259,7 @@ namespace Content.Server.Nutrition.EntitySystems
{
TryFeed(uid, ev.User, component);
},
IconTexture = "/Textures/Interface/VerbIcons/cutlery.svg.192dpi.png",
Text = Loc.GetString("food-system-verb-eat"),
Priority = -1
};

View file

@ -19,7 +19,8 @@ namespace Content.Server.Nutrition.EntitySystems
{
comp.OnUpdate(_accumulatedFrameTime);
}
_accumulatedFrameTime = 0;
_accumulatedFrameTime -= 1;
}
}
}

View file

@ -57,11 +57,7 @@ namespace Content.Server.Power.EntitySystems
if (access == null || _accessReader.IsAllowed(access, args.Session.AttachedEntity.Value))
{
component.MainBreakerEnabled = !component.MainBreakerEnabled;
Comp<PowerNetworkBatteryComponent>(uid).CanDischarge = component.MainBreakerEnabled;
UpdateUIState(uid, component);
SoundSystem.Play(Filter.Pvs(uid), component.OnReceiveMessageSound.GetSound(), uid, AudioParams.Default.WithVolume(-2f));
ApcToggleBreaker(uid, component);
}
else
{
@ -70,6 +66,18 @@ namespace Content.Server.Power.EntitySystems
}
}
public void ApcToggleBreaker(EntityUid uid, ApcComponent? apc = null, PowerNetworkBatteryComponent? battery = null)
{
if (!Resolve(uid, ref apc, ref battery))
return;
apc.MainBreakerEnabled = !apc.MainBreakerEnabled;
battery.CanDischarge = apc.MainBreakerEnabled;
UpdateUIState(uid, apc);
SoundSystem.Play(Filter.Pvs(uid), apc.OnReceiveMessageSound.GetSound(), uid, AudioParams.Default.WithVolume(-2f));
}
private void OnEmagged(EntityUid uid, ApcComponent comp, GotEmaggedEvent args)
{
if(!comp.Emagged)

View file

@ -84,7 +84,7 @@ namespace Content.Server.RoundEnd
_adminLog.Add(LogType.ShuttleCalled, LogImpact.High, $"Shuttle called");
}
_chatManager.DispatchStationAnnouncement(Loc.GetString("round-end-system-shuttle-called-announcement",("minutes", countdownTime.Minutes)), Loc.GetString("Station"), false);
_chatManager.DispatchStationAnnouncement(Loc.GetString("round-end-system-shuttle-called-announcement",("minutes", countdownTime.Minutes)), Loc.GetString("Station"), false, Color.Gold);
SoundSystem.Play(Filter.Broadcast(), "/Audio/Announcements/shuttlecalled.ogg");

View file

@ -294,9 +294,9 @@ namespace Content.Server.Salvage
return true;
}
private void Report(string messageKey) =>
_chatManager.DispatchStationAnnouncement(Loc.GetString(messageKey), Loc.GetString("salvage-system-announcement-source"));
_chatManager.DispatchStationAnnouncement(Loc.GetString(messageKey), Loc.GetString("salvage-system-announcement-source"), colorOverride: Color.Orange);
private void Report(string messageKey, params (string, object)[] args) =>
_chatManager.DispatchStationAnnouncement(Loc.GetString(messageKey, args), Loc.GetString("salvage-system-announcement-source"));
_chatManager.DispatchStationAnnouncement(Loc.GetString(messageKey, args), Loc.GetString("salvage-system-announcement-source"), colorOverride: Color.Orange);
private void Transition(SalvageMagnetComponent magnet, TimeSpan currentTime)
{

View file

@ -0,0 +1,40 @@
using System.Linq;
using Content.Server.Power.Components;
using Content.Server.Power.EntitySystems;
using JetBrains.Annotations;
using Robust.Shared.Random;
namespace Content.Server.StationEvents.Events;
[UsedImplicitly]
public sealed class BreakerFlip : StationEvent
{
[Dependency] private readonly IEntityManager _entityManager = default!;
[Dependency] private readonly IRobustRandom _random = default!;
public override string Name => "BreakerFlip";
public override string? StartAnnouncement =>
Loc.GetString("station-event-breaker-flip-announcement", ("data", Loc.GetString(Loc.GetString($"random-sentience-event-data-{_random.Next(1, 6)}"))));
public override float Weight => WeightNormal;
protected override float EndAfter => 1.0f;
public override int? MaxOccurrences => 5;
public override int MinimumPlayers => 15;
public override void Startup()
{
base.Startup();
var apcSys = EntitySystem.Get<ApcSystem>();
var allApcs = _entityManager.EntityQuery<ApcComponent>().ToList();
var toDisable = Math.Min(_random.Next(3, 7), allApcs.Count);
if (toDisable == 0)
return;
_random.Shuffle(allApcs);
for (var i = 0; i < toDisable; i++)
{
apcSys.ApcToggleBreaker(allApcs[i].Owner, allApcs[i]);
}
}
}

View file

@ -4,6 +4,7 @@ using JetBrains.Annotations;
using Robust.Shared.Audio;
using Robust.Shared.Player;
using Robust.Shared.Random;
using Robust.Shared.Utility;
using Timer = Robust.Shared.Timing.Timer;
namespace Content.Server.StationEvents.Events
@ -11,6 +12,9 @@ namespace Content.Server.StationEvents.Events
[UsedImplicitly]
public sealed class PowerGridCheck : StationEvent
{
[Dependency] private readonly IEntityManager _entityManager = default!;
[Dependency] private readonly IRobustRandom _random = default!;
public override string Name => "PowerGridCheck";
public override float Weight => WeightNormal;
public override int? MaxOccurrences => 3;
@ -25,6 +29,13 @@ namespace Content.Server.StationEvents.Events
private CancellationTokenSource? _announceCancelToken;
private readonly List<EntityUid> _powered = new();
private readonly List<EntityUid> _unpowered = new();
private const float SecondsUntilOff = 30.0f;
private int _numberPerSecond = 0;
private float UpdateRate => 1.0f / _numberPerSecond;
private float _frameTimeAccumulator = 0.0f;
public override void Announce()
{
@ -34,26 +45,53 @@ namespace Content.Server.StationEvents.Events
public override void Startup()
{
var entityManager = IoCManager.Resolve<IEntityManager>();
foreach (var component in entityManager.EntityQuery<ApcPowerReceiverComponent>(true))
foreach (var component in _entityManager.EntityQuery<ApcPowerReceiverComponent>(true))
{
component.PowerDisabled = true;
_powered.Add(component.Owner);
if (!component.PowerDisabled)
_powered.Add(component.Owner);
}
_random.Shuffle(_powered);
_numberPerSecond = Math.Max(1, (int)(_powered.Count / SecondsUntilOff)); // Number of APCs to turn off every second. At least one.
base.Startup();
}
public override void Update(float frameTime)
{
base.Update(frameTime);
_frameTimeAccumulator += frameTime;
var updates = 0;
if (_frameTimeAccumulator > UpdateRate)
{
updates = (int) (_frameTimeAccumulator / UpdateRate);
_frameTimeAccumulator -= UpdateRate * updates;
}
for (var i = 0; i < updates; i++)
{
if (_powered.Count == 0)
break;
var selected = _powered.Pop();
if (_entityManager.Deleted(selected)) continue;
if (_entityManager.TryGetComponent<ApcPowerReceiverComponent>(selected, out var powerReceiverComponent))
{
powerReceiverComponent.PowerDisabled = true;
}
_unpowered.Add(selected);
}
}
public override void Shutdown()
{
var entMan = IoCManager.Resolve<IEntityManager>();
foreach (var entity in _powered)
foreach (var entity in _unpowered)
{
if (entMan.Deleted(entity)) continue;
if (_entityManager.Deleted(entity)) continue;
if (entMan.TryGetComponent(entity, out ApcPowerReceiverComponent? powerReceiverComponent))
if (_entityManager.TryGetComponent(entity, out ApcPowerReceiverComponent? powerReceiverComponent))
{
powerReceiverComponent.PowerDisabled = false;
}
@ -66,7 +104,7 @@ namespace Content.Server.StationEvents.Events
{
SoundSystem.Play(Filter.Broadcast(), "/Audio/Announcements/power_on.ogg", AudioParams);
}, _announceCancelToken.Token);
_powered.Clear();
_unpowered.Clear();
base.Shutdown();
}

View file

@ -132,7 +132,7 @@ namespace Content.Server.StationEvents.Events
if (StartAnnouncement != null)
{
var chatManager = IoCManager.Resolve<IChatManager>();
chatManager.DispatchStationAnnouncement(StartAnnouncement, playDefaultSound: false);
chatManager.DispatchStationAnnouncement(StartAnnouncement, playDefaultSound: false, colorOverride: Color.Gold);
}
if (StartAudio != null)
@ -155,7 +155,7 @@ namespace Content.Server.StationEvents.Events
if (EndAnnouncement != null)
{
var chatManager = IoCManager.Resolve<IChatManager>();
chatManager.DispatchStationAnnouncement(EndAnnouncement, playDefaultSound: false);
chatManager.DispatchStationAnnouncement(EndAnnouncement, playDefaultSound: false, colorOverride: Color.Gold);
}
if (EndAudio != null)

View file

@ -0,0 +1,78 @@
using System.Linq;
using Content.Server.Atmos.Piping.Unary.Components;
using Content.Server.Chemistry.ReactionEffects;
using Content.Shared.Chemistry.Components;
using Content.Shared.Chemistry.Reagent;
using Content.Shared.Sound;
using JetBrains.Annotations;
using Robust.Shared.Map;
using Robust.Shared.Prototypes;
using Robust.Shared.Random;
using Robust.Shared.Utility;
namespace Content.Server.StationEvents.Events;
[UsedImplicitly]
public sealed class VentClog : StationEvent
{
[Dependency] private readonly IRobustRandom _random = default!;
[Dependency] private readonly IEntityManager _entityManager = default!;
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
public override string Name => "VentClog";
public override string? StartAnnouncement =>
Loc.GetString("station-event-vent-clog-start-announcement");
public override string? StartAudio => "/Audio/Announcements/bloblarm.ogg";
public override int EarliestStart => 15;
public override int MinimumPlayers => 15;
public override float Weight => WeightLow;
public override int? MaxOccurrences => 2;
// Give players time to reach cover.
protected override float StartAfter => 50f;
protected override float EndAfter => 51.0f; // This can, surprisingly, cause the event to end before it starts.
public readonly IReadOnlyList<string> SafeishVentChemicals = new[]
{
"Water", "Iron", "Oxygen", "Tritium", "Plasma", "SulfuricAcid", "Blood", "SpaceDrugs", "SpaceCleaner", "Flour",
"Nutriment", "Sugar", "SpaceLube", "Ethanol", "Mercury", "Ephedrine", "WeldingFuel"
};
public override void Startup()
{
base.Startup();
// TODO: "safe random" for chems. Right now this includes admin chemicals.
var allReagents = _prototypeManager.EnumeratePrototypes<ReagentPrototype>()
.Where(x => !x.Abstract)
.Select(x => x.ID).ToList();
// This is gross, but not much can be done until event refactor, which needs Dynamic.
var sound = new SoundPathSpecifier("/Audio/Effects/extinguish.ogg");
foreach (var (_, transform) in _entityManager.EntityQuery<GasVentPumpComponent, TransformComponent>())
{
var solution = new Solution();
if (_random.Prob(0.05f))
{
solution.AddReagent(_random.Pick(allReagents), 100);
}
else
{
solution.AddReagent(_random.Pick(SafeishVentChemicals), 100);
}
FoamAreaReactionEffect.SpawnFoam("Foam", transform.Coordinates, solution, _random.Next(2, 6), 20, 1,
1, sound, _entityManager);
}
}
}

View file

@ -263,12 +263,12 @@ namespace Content.Shared.Atmos
#region Pipes
/// <summary>
/// The pressure pumps and powered equipment max out at, in kPa.
/// The default pressure at which pumps and powered equipment max out at, in kPa.
/// </summary>
public const float MaxOutputPressure = 4500;
/// <summary>
/// The maximum speed powered equipment can work at, in L/s.
/// The default maximum speed powered equipment can work at, in L/s.
/// </summary>
public const float MaxTransferRate = 200;

View file

@ -28,7 +28,7 @@ namespace Content.Shared.Atmos.Piping
}
[Serializable, NetSerializable]
public enum PressurePumpVisuals : byte
public enum PumpVisuals : byte
{
Enabled,
}

View file

@ -73,5 +73,6 @@ namespace Content.Shared.Atmos.Piping.Unary.Components
NoBound = 0,
InternalBound = 1,
ExternalBound = 2,
Both = 3,
}
}

View file

@ -28,6 +28,7 @@ namespace Content.Shared.DoAfter
public CancelledDoAfterMessage(EntityUid uid, byte id)
{
Uid = uid;
ID = id;
}
}

View file

@ -8,7 +8,7 @@ namespace Content.Shared.Light.Component
public abstract class SharedHandheldLightComponent : Robust.Shared.GameObjects.Component
{
[DataField("toggleAction", required: true)]
public InstantAction ToggleAction = default!;
public InstantAction ToggleAction = new();
public const int StatusLevels = 6;

Binary file not shown.

Binary file not shown.

Binary file not shown.

View file

@ -0,0 +1,10 @@
The following sounds were used from freesound:
herbertboland - heavyskirtmovement.wav - CC BY 3.0
vinrax - cloth-sounds.mp3 - CC BY-NC 3.0
lordvanye - skintouching.wav - CC0 1.0
Additional sound effects from https://www.zapsplat.com
foley-cloth-denim-rip-003.mp3 -
zapsplat_food_bottle_golden_syrup_cap_open_then_close.mp3

Binary file not shown.

Binary file not shown.

View file

@ -1,120 +1,4 @@
Entries:
- author: mirrorcult
changes:
- {message: 'Chemicals metabolizing in the body now last twice as long, meaning
most medicines and poisons will have a greater effect over a longer timespan.',
type: Tweak}
id: 630
time: '2021-11-22T08:45:21.0000000+00:00'
- author: mirrorcult
changes:
- {message: 'People sprayed/coming into contact with any alcoholic drink can now
be lit on fire, rather than just ethanol.', type: Tweak}
id: 631
time: '2021-11-22T09:17:35.0000000+00:00'
- author: DrSmugleaf
changes:
- {message: Admin logs., type: Add}
id: 632
time: '2021-11-22T17:49:26.0000000+00:00'
- author: 20kdc
changes:
- {message: It is no longer possible to start pulling people while in cuffs., type: Fix}
id: 633
time: '2021-11-22T19:31:12.0000000+00:00'
- author: moony
changes:
- {message: Admins no longer have to turn events back on every time the server restarts,
type: Add}
id: 634
time: '2021-11-22T22:33:30.0000000+00:00'
- author: 20kdc
changes:
- {message: Announcements from Central Command are now properly serenaded., type: Fix}
id: 635
time: '2021-11-22T22:34:48.0000000+00:00'
- author: 20kdc
changes:
- {message: You are no longer interrupted by damage during prying a firelock or
airlock., type: Tweak}
id: 636
time: '2021-11-23T00:34:57.0000000+00:00'
- author: mirrorcult
changes:
- {message: 'Added carpetium, a chemical that creates carpets whenever it touches
a tile either through spills, sprays, or foam. It''s created using Space Drugs
and Fiber.', type: Add}
- {message: You can now grind up jumpsuits and shoes into Fiber. TOTALLY unrelated
to the last changelog entry, type: Add}
id: 637
time: '2021-11-23T01:01:51.0000000+00:00'
- author: metalgearsloth
changes:
- {message: Removed meth., type: Remove}
- {message: Added desoxyephedrine., type: Add}
id: 638
time: '2021-11-23T04:39:59.0000000+00:00'
- author: metalgearsloth
changes:
- {message: Thrusters now have examine text, type: Add}
id: 639
time: '2021-11-23T06:44:08.0000000+00:00'
- author: mirrorcult
changes:
- {message: Admins are now fully knowledgeable of every potassium/water bomb you
make., type: Add}
id: 640
time: '2021-11-23T06:51:43.0000000+00:00'
- author: mirrorcult
changes:
- {message: 'Added epinephrine, an emergency medical chemical that reduces stun
times slightly and heals people that are in critical health. Everyone starts
with a medipen containing it in their survival box--beware of overdoses.', type: Add}
id: 641
time: '2021-11-23T06:51:52.0000000+00:00'
- author: Mith-randalf
changes:
- {message: Added the warden's favourite jacket., type: Add}
id: 642
time: '2021-11-23T11:12:20.0000000+00:00'
- author: ElectroJr
changes:
- {message: 'Mopping now picks up slightly more reagents, and cleaning vomit should
be easier.', type: Tweak}
id: 643
time: '2021-11-23T17:14:46.0000000+00:00'
- author: metalgearsloth
changes:
- {message: Pried tiles now have a random rotation applied, type: Tweak}
id: 644
time: '2021-11-23T17:15:49.0000000+00:00'
- author: mirrorcult
changes:
- {message: Smoke spam no longer crashes the server., type: Fix}
id: 645
time: '2021-11-23T19:35:50.472421+00:00'
- author: Clyybber
changes:
- {message: Reworked how dropping items by slipping works., type: Tweak}
id: 646
time: '2021-11-23T23:38:39.0000000+00:00'
- author: 20kdc
changes:
- {message: Disposals should no longer be capable of sending employees through walls
when they're not supposed to be., type: Fix}
id: 647
time: '2021-11-23T23:38:46.0000000+00:00'
- author: ElectroJr
changes:
- {message: You can now directly swap beakers in chemistry machines. No more swap-hands
> eject > swap-hands> insert., type: Tweak}
id: 648
time: '2021-11-24T07:03:08.0000000+00:00'
- author: moonheart08
changes:
- {message: The lobby timer is now (much) longer., type: Tweak}
id: 649
time: '2021-11-24T09:52:07.0000000+00:00'
- author: 20kdc
changes:
- {message: Solar control console works again, type: Fix}
@ -2995,3 +2879,120 @@ Entries:
- {message: Added handheld GPS devices which can be found in the autolathe, type: Add}
id: 1129
time: '2022-02-26T05:59:20.0000000+00:00'
- author: Zymem
changes:
- {message: Drinks should now have sprites, type: Fix}
id: 1130
time: '2022-02-27T01:26:45.0000000+00:00'
- author: ElectroJr
changes:
- {message: 'Fixed two action bugs: ghost boo not working, and powered-flashlight
toggling affecting all flashlights.', type: Fix}
id: 1131
time: '2022-02-27T03:02:39.0000000+00:00'
- author: moony
changes:
- {message: Introduced two more events., type: Add}
id: 1132
time: '2022-02-27T03:04:01.0000000+00:00'
- author: moony
changes:
- {message: 'Power grid check no longer shuts off all power instantly, and instead
does so over about 30 seconds.', type: Tweak}
id: 1133
time: '2022-02-27T07:01:39.0000000+00:00'
- author: Peptide90
changes:
- {message: 'Adds a bunch of new carpets, grass and shuttle flooring for mappers.
Keep an eye out for updates to your favorite maps!', type: Add}
id: 1134
time: '2022-02-27T07:01:48.0000000+00:00'
- author: Peptide90
changes:
- {message: Added the fire helmet! Heat resistant goodness for your head that looks
cool AND has a light!, type: Add}
id: 1135
time: '2022-02-27T07:02:07.0000000+00:00'
- author: Peptide90
changes:
- {message: 'Pillar V5.1 - bug fixes and reinforced more walls, departments, offices
and substations.', type: Add}
id: 1136
time: '2022-02-27T07:02:15.0000000+00:00'
- author: Peptide90
changes:
- {message: 'All electronics, machine and computer boards now have updated names,
descriptions and in some cases sprites.', type: Fix}
- {message: SMES construction is now fixed., type: Fix}
- {message: There's now computer boards for all computers on the station...some
still don't do anything., type: Add}
id: 1137
time: '2022-02-27T13:46:27.0000000+00:00'
- author: Zumorica
changes:
- {message: Suspicion no longer shows up in gamemode votes., type: Remove}
id: 1138
time: '2022-02-27T18:03:08.0000000+00:00'
- author: Peptide90
changes:
- {message: 'Added boxes of trashbags, flares and all magazine types.', type: Add}
id: 1139
time: '2022-02-27T19:56:27.0000000+00:00'
- author: Zyme
changes:
- {message: Monkeys now understand the concept of hats, type: Add}
id: 1140
time: '2022-02-27T19:56:36.0000000+00:00'
- author: ElectroJr
changes:
- {message: 'The /mapping command syntax has changed. The filename now comes before
the Id, and a new blank map is created by providing no arguments.', type: Tweak}
id: 1141
time: '2022-02-28T01:21:15.0000000+00:00'
- author: DogZeroX
changes:
- {message: Animal's blood now variate depending on their size, type: Tweak}
id: 1142
time: '2022-02-28T01:23:45.0000000+00:00'
- author: metalgearsloth
changes:
- {message: Lowered ghost movement speed., type: Tweak}
id: 1143
time: '2022-02-28T15:14:17.0000000+00:00'
- author: Emisse
changes:
- {message: 'A brand new station, moose station.', type: Add}
id: 1144
time: '2022-03-01T02:16:46.0000000+00:00'
- author: ElectroJr
changes:
- {message: 'Fixed being able to push some entities (computers, canisters, plants)
through walls and doors.', type: Fix}
id: 1145
time: '2022-03-01T02:18:20.0000000+00:00'
- author: mirrorcult
changes:
- {message: Added a new medium-sized salvage., type: Add}
id: 1146
time: '2022-03-01T02:18:31.0000000+00:00'
- author: Zumorica
changes:
- {message: Map votes during the pre-round period actually affect the chosen map
on round start., type: Tweak}
id: 1147
time: '2022-03-01T02:20:21.0000000+00:00'
- author: mirrorcult
changes:
- {message: Gauze can now be crafted using cloth., type: Add}
- {message: 'You can now gain cloth by butchering clothing items like jumpsuits,
shoes, or cloaks.', type: Tweak}
- {message: 'Fiber reagent is now gained by grinding cloth, not the individual clothing
items.', type: Tweak}
id: 1148
time: '2022-03-01T03:38:39.0000000+00:00'
- author: HoofedEar
changes:
- {message: Certain station announcements have been given a splash of color in chat.,
type: Add}
id: 1149
time: '2022-03-01T13:21:29.0000000+00:00'

View file

@ -4,6 +4,7 @@ ui-options-title = Game Options
ui-options-tab-graphics = Graphics
ui-options-tab-controls = Controls
ui-options-tab-audio = Audio
ui-options-tab-network = Network
ui-options-apply = Apply
ui-options-reset-all = Reset All
@ -148,3 +149,7 @@ ui-options-function-loadout6 = Hotbar Loadout 6
ui-options-function-loadout7 = Hotbar Loadout 7
ui-options-function-loadout8 = Hotbar Loadout 8
ui-options-function-loadout9 = Hotbar Loadout 9
## Network menu
ui-options-net-interp-ratio = Network Smoothing

View file

@ -18,7 +18,7 @@ petting-success-reptile = You pet {THE($target)} on {POSS-ADJ($target)} scaly li
petting-success-sloth = You pet {THE($target)} on {POSS-ADJ($target)} slow moving head.
petting-success-space-cat = You pet {THE($target)} on {POSS-ADJ($target)} glass domed head.
petting-success-tarantula = You pet {THE($target)} on {POSS-ADJ($target)} hairy little head.
petting-success-holo = You pet {THE($target)} on {POSS-ADJ($target)} metallic spiky head.
petting-failure-generic = You reach out to pet {THE($target)}, but {SUBJECT($target)} {CONJUGATE-BE($target)} aloof towards you.
@ -29,6 +29,7 @@ petting-failure-goat = You reach out to pet {THE($target)}, but {SUBJECT($target
petting-failure-goose = You reach out to pet {THE($target)}, but {SUBJECT($target)} {CONJUGATE-BE($target)} too horrible!
petting-failure-possum = You reach out to pet {THE($target)}, but are met with hisses and snarls!
petting-failure-sloth = You reach out to pet {THE($target)}, but {SUBJECT($target)} somehow dodge with ludicrous speed!
petting-failure-holo = You reach out to pet {THE($target)}, but {POSS-ADJ($target)} spikes almost impale your hand!
## Knocking on windows

View file

@ -1 +1,4 @@
butcherable-knife-butchered-success = You butcher { THE($target) } with { THE($knife) }.
butcherable-need-knife = Need something sharp.
butcherable-mob-isnt-dead = Needs to be dead.
butcherable-verb-name = Butcher

View file

@ -0,0 +1 @@
station-event-breaker-flip-announcement = Based on { $data }, we have opted to disable specific APCs to avoid damage to equipment. Please contact the engineering department to re-enable them.

View file

@ -0,0 +1 @@
station-event-vent-clog-start-announcement = The scrubbers network is experiencing a backpressure surge. Some ejection of contents may occur.

File diff suppressed because it is too large Load diff

81536
Resources/Maps/moose.yml Normal file

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,207 @@
# ---- Library Salvage Fills ----
- type: entity
name: demonomicon
parent: BookBase
id: BookDemonomicon
description: 'Who knows what dark spells may be contained in these horrid pages?'
components:
- type: Sprite
sprite: Objects/Misc/books.rsi
layers:
- state: book_demonomicon
- type: entity
name: demonomicon
parent: BookDemonomicon
id: BookDemonomiconRandom
suffix: random
components:
- type: RandomSpawner
prototypes:
- BookDemonomicon1
- BookDemonomicon2
- BookDemonomicon3
offset: 0.1
- type: entity
parent: BookDemonomicon
id: BookDemonomicon1
abstract: true
suffix: 1
components:
- type: Paper
content: |
How To Summon a Demon
- by J.G. Wizgerald
1. todo finish writing demon summoning guide
- type: entity
parent: BookDemonomicon
id: BookDemonomicon2
abstract: true
suffix: 2
components:
- type: Paper
content: |
How To Summon a Lemon
- by J.G. Wizgerald
1. todo finish writing lemon summoning guide
2. WAit. Typo. Oh shit. Sorry guys
- type: entity
parent: BookDemonomicon
id: BookDemonomicon3
abstract: true
suffix: 3
components:
- type: Paper
content: |
Cool Demon Names I Found
- by Ms. Mossrock
Abraxas
Nephilim
Baal
Leviathan
Gary
Moloch
Scylla
Phenex
- type: entity
name: pharmaceutical manuscript
parent: BookBase
id: BookChemistryInsane
suffix: library salvage
description: 'You can tell whoever wrote this was off the desoxy HARD.'
components:
- type: Sprite
sprite: Objects/Misc/books.rsi
layers:
- state: book_chemistry
- type: Paper
content: |
IGOR CHEMISTRY GUIDE TO CHEMISTRY
TITLE: GUIDE TO CHEMISTRY
ABSTRACT: GUIDE TO CHEMISTRY
SECTION: WISE WORDS OF IGOR CHEMISTRY
MY NUMBER ONE TIP. IS TO ALWAYS HAVE FUN. YOU NEVER KNOW WHEN IT'LL ALL END.
SO JUST KEEP AT IT!!
MY NUMBER TWO TIP. I JUST CAN'T STOP FUCKING GRINDING UP JUMPSUITS. MY "COLLEAGUES" (agents) KEEP YELLING AT ME
TO STOP AND THAT 'itll come out of our paychecks' BUT THE STUFF IS SO GOOD. I'M LIKE AN INTERIOR DECORATION GENIUS.
SAXOPHONES AND BATTERIES TAKE MY MIND OFF OF IT BUT I'M ALWAYS BACK TO THE JUMPSUITS. HOO WEE.
MY NUMBER THREE TIP. THANK YOU FOR READING!! IGOR CHEMISTRY
CONCLUSION: IGOR CHEMISTRY
- type: entity
name: botanical textbook
parent: BookBase
id: BookBotanicalTextbook
suffix: library salvage
description: 'Only a couple pages are left.'
components:
- type: Sprite
sprite: Objects/Misc/books.rsi
layers:
- state: book_hydroponics_pod_people
- type: Paper
content: |
** Applications of Botanical Specimens Found In Nanotrasen Territories **
Many plants, when ground, yield useful chemicals. S. (spessmens) papaver and S. aloe vera
are known for their basic healing properties.
S. lucidum, or lingzhi, is known for its potent ability to save those near death from toxins. Eating too much
is known to cause adverse effects.
S. amanita, a powerfully poisonous specimen (Rest In Peace Sir Alacaster), and S. galactica, a
seemingly ordinary antitoxin, appear to have some sort of relation to eachother.
Some research is being done on combinations of the medicinal plants discussed, and they may prove fruitful.
----
- penned by James Alacaster and Golzuk Amaranth
- type: entity
parent: BookBase
id: BookGnominomicon
name: gnominomicon
suffix: library salvage
description: You don't like the look of this. Looks
components:
- type: Sprite
sprite: Objects/Misc/books.rsi
layers:
- state: book5
- type: Paper
content: |
All Hail Our Gnome King
He who is the grand cartographer who placed our kind into the world of the Island!
He who loves those with the largest of Hats!
Struck down by the evildoers who cannot appreciate our kind!
Our revenge will be dealt in full! He will Rise once more! hee Hoo!
- type: entity
parent: BookBase
id: BookFishing
name: Tales from the Fishbowl
suffix: library salvage
description: This book sucks.
components:
- type: Sprite
sprite: Objects/Misc/books.rsi
layers:
- state: book_fish
- type: Paper
content: |
When I grow up, I want to be one of the harvesters of the space sea!
I think before my days are done I want to catch the fabled space fish!
I'm like a little rat sailing the seas of cheese! The bastards come to end me but I am as sly as a cat and as lucky as they come!
Press the <L BUMPER> and <R TRIGGER> to activate the fishing minigame.
- Sgt. John Baker Aclopoly
- type: entity
parent: BookBase
id: BookDetective
name: Strokgraeth Holmes, Dwarf Detective
suffix: library salvage
description: Exciting! Invigorating! This author died after his book career failed.
components:
- type: Sprite
sprite: Objects/Misc/books.rsi
layers:
- state: book_detective
- type: Paper
content: |
CHAPTER 1: SMALL ADVENTURES IN A BIG STATION
This station is filled with crime and grime...
I was shooting hoops down on Bagel when I heard a cry and a laser shot. I walked under the table nearby to hide, but there wasn't a second shot.
Outside, the engineerin chief got blasted by two Syndies hooked up with some fierce contraband. There wasn't enough of him for an open casket funeral.
Things always go wild here.. I'll never look at clowns the same.
The question is.. Who did it?
# ---- End Library Salvage Fills ----

View file

@ -0,0 +1,699 @@
# ClRifle
- type: entity
name: box of .25 caseless magazines
parent: BoxCardboard
id: BoxMagazineClRiflePistol
description: A box full of .25 caseless magazines.
components:
- type: StorageFill
contents:
- id: MagazineClRifleBase
amount: 6
- type: Sprite
layers:
- state: box
- type: entity
name: box of .25 caseless (high-velocity) magazines
parent: BoxCardboard
id: BoxMagazineClRiflePistolHV
description: A box full of .25 caseless high-velocity magazines.
components:
- type: StorageFill
contents:
- id: MagazineClRiflePistolHV
amount: 6
- type: Sprite
layers:
- state: box
- type: entity
name: box of .25 caseless (practice) magazines
parent: BoxCardboard
id: BoxMagazineClRiflePistolPractice
description: A box full of .25 caseless practice magazines.
components:
- type: StorageFill
contents:
- id: MagazineClRiflePistolPractice
amount: 6
- type: Sprite
layers:
- state: box
- type: entity
name: box of .25 caseless (rubber) magazines
parent: BoxCardboard
id: BoxMagazineClRifleRubber
description: A box full of
components:
- type: StorageFill
contents:
- id: MagazineClRifleRubber
amount: 6
- type: Sprite
layers:
- state: box
# LRifle
- type: entity
name: box of .30 rifle magazines
parent: BoxCardboard
id: BoxMagazineLRifle
description: A box full of .30 rifle magazines.
components:
- type: StorageFill
contents:
- id: MagazineLRifle
amount: 6
- type: Sprite
layers:
- state: box
- type: entity
name: box of .30 rifle (high-velocity) magazines
parent: BoxCardboard
id: BoxMagazineLRifleHV
description: A box full of .30 rifle (high-velocity) magazines.
components:
- type: StorageFill
contents:
- id: MagazineLRifleHV
amount: 6
- type: Sprite
layers:
- state: box
- type: entity
name: box of .30 rifle (practice) magazines
parent: BoxCardboard
id: BoxMagazineLRiflePractice
description: A box full of .30 rifle (practice) magazines.
components:
- type: StorageFill
contents:
- id: MagazineLRiflePractice
amount: 6
- type: Sprite
layers:
- state: box
- type: entity
name: box of .30 rifle (rubber) magazines
parent: BoxCardboard
id: BoxMagazineLRifleRubber
description: A box full of .30 rifle (practice) magazines.
components:
- type: StorageFill
contents:
- id: MagazineLRifleRubber
amount: 6
- type: Sprite
layers:
- state: box
# Magnum
- type: entity
name: box of .40 Lamia magazines
parent: BoxCardboard
id: BoxMagazineMagnum
description: A box full of .40 Lamia magazines.
components:
- type: StorageFill
contents:
- id: MagazineMagnum
amount: 6
- type: Sprite
layers:
- state: box
- type: entity
name: box of .40 Lamia (flash) magazines.
parent: BoxCardboard
id: BoxMagazineMagnumFlash
description: A box full of .40 Lamia (flash) magazines.
components:
- type: StorageFill
contents:
- id: MagazineMagnumFlash
amount: 6
- type: Sprite
layers:
- state: box
- type: entity
name: box of .40 Lamia (high-velocity) magazines
parent: BoxCardboard
id: BoxMagazineMagnumHV
description: A box full of .40 Lamia (high-velocity) magazines.
components:
- type: StorageFill
contents:
- id: MagazineMagnumHV
amount: 6
- type: Sprite
layers:
- state: box
- type: entity
name: box of .40 Lamia (practice) magazines
parent: BoxCardboard
id: BoxMagazineMagnumPractice
description: A box full of .40 Lamia (practice) magazines.
components:
- type: StorageFill
contents:
- id: MagazineMagnumPractice
amount: 6
- type: Sprite
layers:
- state: box
- type: entity
name: box of .40 Drozd magazines
parent: BoxCardboard
id: BoxMagazineMagnumSmg
description: A box full of .40 Drozd magazines.
components:
- type: StorageFill
contents:
- id: MagazineMagnumSmg
amount: 6
- type: Sprite
layers:
- state: box
- type: entity
name: box of .40 Drozd (high-velocity) magazines
parent: BoxCardboard
id: BoxMagazineMagnumSmgHV
description: A box full of .40 Drozd (high-velocity) magazines.
components:
- type: StorageFill
contents:
- id: MagazineMagnumSmgHV
amount: 6
- type: Sprite
layers:
- state: box
- type: entity
name: box of .40 Drozd (practice) magazines
parent: BoxCardboard
id: BoxMagazineMagnumSmgPractice
description: A box full of .40 Drozd (practice) magazines.
components:
- type: StorageFill
contents:
- id: MagazineMagnumSmgPractice
amount: 6
- type: Sprite
layers:
- state: box
- type: entity
name: box of .40 Drozd (rubber) magazines
parent: BoxCardboard
id: BoxMagazineMagnumSmgRubber
description: A box full of .40 Drozd (rubber) magazines.
components:
- type: StorageFill
contents:
- id: MagazineMagnumSmgRubber
amount: 6
- type: Sprite
layers:
- state: box
# Pistol
- type: entity
name: box of WT550 .35 auto magazines
parent: BoxCardboard
id: BoxMagazinePistolSmgTopMounted
description: A box full of WT550 .35 auto magazines.
components:
- type: StorageFill
contents:
- id: MagazinePistolSmgTopMounted
amount: 6
- type: Sprite
layers:
- state: box
- type: entity
name: box of Calico .35 auto magazines
parent: BoxCardboard
id: BoxMagazinePistolCalicoTopMounted
description: A box full of Calico .35 auto magazines.
components:
- type: StorageFill
contents:
- id: MagazinePistolCalicoTopMounted
amount: 6
- type: Sprite
layers:
- state: box
- type: entity
name: box of pistol .35 auto magazines
parent: BoxCardboard
id: BoxMagazinePistol
description: A box full of pistol .35 auto magazines.
components:
- type: StorageFill
contents:
- id: MagazinePistol
amount: 6
- type: Sprite
layers:
- state: box
- type: entity
name: box of pistol .35 auto (flash) magazines
parent: BoxCardboard
id: BoxMagazinePistolFlash
description: A box full of pistol .35 auto (flash) magazines.
components:
- type: StorageFill
contents:
- id: MagazinePistolFlash
amount: 6
- type: Sprite
layers:
- state: box
- type: entity
name: box of pistol .35 auto (high-velocity) magazines
parent: BoxCardboard
id: BoxMagazinePistolHV
description: A box full of pistol .35 auto (high-velocity) magazines.
components:
- type: StorageFill
contents:
- id: MagazinePistolHV
amount: 6
- type: Sprite
layers:
- state: box
- type: entity
name: box of pistol .35 auto (practice) magazines
parent: BoxCardboard
id: BoxMagazinePistolPractice
description: A box full of magazines.
components:
- type: StorageFill
contents:
- id: MagazinePistolPractice
amount: 6
- type: Sprite
layers:
- state: box
- type: entity
name: box of pistol .35 auto (rubber) magazines
parent: BoxCardboard
id: BoxMagazinePistolRubber
description: A box full of pistol .35 auto (rubber) magazines.
components:
- type: StorageFill
contents:
- id: MagazinePistolRubber
amount: 6
- type: Sprite
layers:
- state: box
- type: entity
name: box of machine pistol .35 auto magazines
parent: BoxCardboard
id: BoxMagazineHCPistol
description: A box full of machine pistol .35 auto magazines.
components:
- type: StorageFill
contents:
- id: MagazineHCPistol
amount: 6
- type: Sprite
layers:
- state: box
- type: entity
name: box of machine pistol .35 auto (high-velocity) magazines
parent: BoxCardboard
id: BoxMagazineHCPistolHV
description: A box full of machine pistol .35 auto (high-velocity) magazines.
components:
- type: StorageFill
contents:
- id: MagazineHCPistolHV
amount: 6
- type: Sprite
layers:
- state: box
- type: entity
name: box of machine pistol .35 auto (practice) magazines
parent: BoxCardboard
id: BoxMagazineHCPistolPractice
description: A box full of machine pistol .35 auto (practice) magazines.
components:
- type: StorageFill
contents:
- id: MagazineHCPistolPractice
amount: 6
- type: Sprite
layers:
- state: box
- type: entity
name: box of machine pistol .35 auto (rubber) magazines
parent: BoxCardboard
id: BoxMagazineHCPistolRubber
description: A box full of machine pistol .35 auto (rubber) magazines.
components:
- type: StorageFill
contents:
- id: MagazineHCPistolRubber
amount: 6
- type: Sprite
layers:
- state: box
- type: entity
name: box of SMG .35 auto magazines
parent: BoxCardboard
id: BoxMagazinePistolSmg
description: A box full of SMG .35 auto magazines.
components:
- type: StorageFill
contents:
- id: MagazinePistolSmg
amount: 6
- type: Sprite
layers:
- state: box
- type: entity
name: box of SMG .35 auto (flash) magazines
parent: BoxCardboard
id: BoxMagazinePistolSmgFlash
description: A box full of SMG .35 auto (flash) magazines.
components:
- type: StorageFill
contents:
- id: MagazinePistolSmgFlash
amount: 6
- type: Sprite
layers:
- state: box
- type: entity
name: box of SMG .35 auto (high-velocity) magazines
parent: BoxCardboard
id: BoxMagazinePistolSmgHV
description: A box full of SMG .35 auto (high-velocity) magazines.
components:
- type: StorageFill
contents:
- id: MagazinePistolSmgHV
amount: 6
- type: Sprite
layers:
- state: box
- type: entity
name: box of SMG .35 auto (practice) magazines
parent: BoxCardboard
id: BoxMagazinePistolSmgPractice
description: A box full of SMG .35 auto (practice) magazines.
components:
- type: StorageFill
contents:
- id: MagazinePistolSmgPractice
amount: 6
- type: Sprite
layers:
- state: box
- type: entity
name: box of SMG .35 auto (rubber) magazines
parent: BoxCardboard
id: BoxMagazinePistolSmgRubber
description: A box full of SMG .35 auto (rubber) magazines.
components:
- type: StorageFill
contents:
- id: MagazinePistolSmgRubber
amount: 6
- type: Sprite
layers:
- state: box
# Shotgun
- type: entity
name: box of (.50 pellet) ammo drums
parent: BoxCardboard
id: BoxMagazineShotgun
description: A box full of (.50 pellet) ammo drums.
components:
- type: StorageFill
contents:
- id: MagazineShotgun
amount: 6
- type: Sprite
layers:
- state: box
- type: entity
name: box of (.50 beanbag) ammo drums
parent: BoxCardboard
id: BoxMagazineShotgunBeanbag
description: A box full of (.50 beanbag) ammo drums.
components:
- type: StorageFill
contents:
- id: MagazineShotgunBeanbag
amount: 6
- type: Sprite
layers:
- state: box
- type: entity
name: box of (.50 slug) ammo drums
parent: BoxCardboard
id: BoxMagazineShotgunSlug
description: A box full of (.50 slug) ammo drums.
components:
- type: StorageFill
contents:
- id: MagazineShotgunSlug
amount: 6
- type: Sprite
layers:
- state: box
- type: entity
name: box of (.50 incendiary) ammo drums
parent: BoxCardboard
id: BoxMagazineShotgunIncendiary
description: A box full of (.50 incendiary) ammo drums.
components:
- type: StorageFill
contents:
- id: MagazineShotgunIncendiary
amount: 6
- type: Sprite
layers:
- state: box
- type: entity
name: box of shotgun beanbag cartridges
parent: BoxCardboard
id: BoxBeanbag
description: A box full of beanbag shots, designed for riot shotguns.
components:
- type: StorageFill
contents:
- id: ShellShotgunBeanbag
amount: 6
- type: Sprite
layers:
- state: boxwide
- state: shellbeanbag
- type: entity
name: box of shotgun lethal cartridges
parent: BoxCardboard
id: BoxLethalshot
description: A box full of lethal pellet shots, designed for riot shotguns.
components:
- type: StorageFill
contents:
- id: ShellShotgun
amount: 6
- type: Sprite
layers:
- state: boxwide
- state: shelllethal
- type: entity
name: box of shotgun slug cartridges
parent: BoxCardboard
id: BoxShotgunSlug
description: A box full of shotgun slugs, designed for riot shotguns.
components:
- type: StorageFill
contents:
- id: ShellShotgunSlug
amount: 6
- type: Sprite
layers:
- state: boxwide
- state: shellslug
- type: entity
name: box of shotgun flare cartridges
parent: BoxCardboard
id: BoxShotgunFlare
description: A box full of shotgun flare cartridges, designed for riot shotguns.
components:
- type: StorageFill
contents:
- id: ShellShotgunFlare
amount: 6
- type: Sprite
layers:
- state: boxwide
- state: shellflare
- type: entity
name: box of shotgun flash cartridges
parent: BoxCardboard
id: BoxShotgunFlash
description: A box full of shotgun flash cartridges, designed for riot shotguns.
components:
- type: StorageFill
contents:
- id: ShellShotgunFlash
amount: 6
- type: Sprite
layers:
- state: boxwide
- state: shellflash
- type: entity
name: box of shotgun incendiary cartridges
parent: BoxCardboard
id: BoxShotgunIncendiary
description: A box full of shotgun incendiary cartridges, designed for riot shotguns.
components:
- type: StorageFill
contents:
- id: ShellShotgunIncendiary
amount: 6
- type: Sprite
layers:
- state: boxwide
- state: shellincendiary
- type: entity
name: box of shotgun practice cartridges
parent: BoxCardboard
id: BoxShotgunPractice
description: A box full of shotgun practice cartridges, designed for riot shotguns.
components:
- type: StorageFill
contents:
- id: ShellShotgunPractice
amount: 6
- type: Sprite
layers:
- state: boxwide
- state: shellpractice
- type: entity
name: box of tranquilizer cartridges
parent: BoxCardboard
id: BoxShellTranquilizer
description: A box full of tranquilizer cartridges, designed for riot shotguns.
components:
- type: StorageFill
contents:
- id: ShellTranquilizer
amount: 6
- type: Sprite
layers:
- state: boxwide
- state: shellslug
# SRifle
- type: entity
name: box of .20 rifle magazines
parent: BoxCardboard
id: BoxMagazineSRifle
description: A box full of .20 rifle magazines.
components:
- type: StorageFill
contents:
- id: MagazineSRifle
amount: 6
- type: Sprite
layers:
- state: box
- type: entity
name: box of .20 rifle (flash) magazines
parent: BoxCardboard
id: BoxMagazineSRifleFlash
description: A box full of .20 rifle (flash) magazines.
components:
- type: StorageFill
contents:
- id: MagazineSRifleFlash
amount: 6
- type: Sprite
layers:
- state: box
- type: entity
name: box of .20 rifle (high-velocity) magazines
parent: BoxCardboard
id: BoxMagazineSRifleHV
description: A box full of .20 rifle (high-velocity) magazines.
components:
- type: StorageFill
contents:
- id: MagazineSRifleHV
amount: 6
- type: Sprite
layers:
- state: box
- type: entity
name: box of .20 rifle (practice) magazines
parent: BoxCardboard
id: BoxMagazineSRiflePractice
description: A box full of .20 rifle (practice) magazines.
components:
- type: StorageFill
contents:
- id: MagazineSRiflePractice
amount: 6
- type: Sprite
layers:
- state: box
- type: entity
name: box of .20 rifle (rubber) magazines
parent: BoxCardboard
id: BoxMagazineSRifleRubber
description: A box full of .20 rifle (rubber) magazines.
components:
- type: StorageFill
contents:
- id: MagazineSRifleRubber
amount: 6
- type: Sprite
layers:
- state: box

View file

@ -177,3 +177,38 @@
layers:
- state: box
- state: writing
- type: entity
name: flare box
parent: BoxCardboard
id: BoxFlare
description: A box of flares. Party time.
components:
- type: StorageFill
contents:
- id: Flare
amount: 6
- type: Sprite
layers:
- state: box
- state: writing
- type: entity
name: trashbag box
parent: BoxCardboard
id: BoxTrashbag
description: A box of trashbags. Happy janitor noises.
components:
- type: StorageFill
contents:
- id: TrashBag
amount: 6
- type: Storage
capacity: 800
whitelist:
tags:
- TrashBag
- type: Sprite
layers:
- state: box
- state: writing

View file

@ -56,32 +56,4 @@
- type: Sprite
layers:
- state: box_security
- state: ziptie
- type: entity
name: box of beanbag shots
parent: BoxCardboard
id: BoxBeanbag
description: A box full of beanbag shots, designed for riot shotguns.
components:
- type: StorageFill
contents:
- id: ShellShotgunBeanbag
amount: 6
- type: Sprite
layers:
- state: box_beanbag
- type: entity
name: box of lethal shots
parent: BoxCardboard
id: BoxLethalshot
description: A box full of lethal shots, designed for riot shotguns.
components:
- type: StorageFill
contents:
- id: ShellShotgunBase
amount: 6
- type: Sprite
layers:
- state: box_lethalshot
- state: ziptie

View file

@ -38,6 +38,8 @@
prob: 0.75
- id: ClothingMaskGas
prob: 0.75
- id: ClothingHeadHelmetFire
prob: 0.75
- type: entity
id: ClosetMaintenanceFilledRandom

View file

@ -96,7 +96,7 @@
- CryostasisBeaker
- Dropper
- Syringe
- KitchenReagentGrinderMachineCircuitboard
- ReagentGrinderMachineCircuitboard
- PillCanister
- type: technology

View file

@ -10,3 +10,5 @@
ClothingUniformJumpskirtEngineering: 3
ClothingShoesColorBlack: 3
ClothingHeadsetEngineering: 2
ClothingOuterSuitFire: 2
ClothingHeadHelmetFire: 2

View file

@ -157,3 +157,20 @@
- type: Clothing
sprite: Clothing/Head/Helmets/wizardhelm.rsi
- type: IngestionBlocker
- type: entity
parent: ClothingHeadHardsuitWithLightBase # hardsuitlight base for light and protection
id: ClothingHeadHelmetFire
name: fire helmet
description: An atmos techs best friend. Provides some heat resistance and looks cool.
components:
- type: Sprite
sprite: Clothing/Head/Helmets/firehelmet.rsi
- type: Clothing
sprite: Clothing/Head/Helmets/firehelmet.rsi
- type: IngestionBlocker
- type: PowerCellSlot
cellSlot:
startingItem: PowerCellSmallHigh
- type: TemperatureProtection
coefficient: 0.01

View file

@ -10,3 +10,7 @@
- neck
- type: Sprite
state: icon
- type: Butcherable
butcheringType: Knife
spawned: MaterialCloth1
pieces: 2

View file

@ -8,8 +8,7 @@
- FEET
- type: Sprite
state: icon
- type: Extractable
juiceSolution:
reagents:
- ReagentId: Fiber
Quantity: 5
- type: Butcherable
butcheringType: Knife
spawned: MaterialCloth1
pieces: 1

View file

@ -20,11 +20,10 @@
Slots: [innerclothing]
EquipSound:
path: /Audio/Items/jumpsuit_equip.ogg
- type: Extractable
juiceSolution:
reagents:
- ReagentId: Fiber
Quantity: 10
- type: Butcherable
butcheringType: Knife
spawned: MaterialCloth1
pieces: 3
- type: entity
abstract: true
@ -38,8 +37,7 @@
femaleMask: UniformTop
EquipSound:
path: /Audio/Items/jumpsuit_equip.ogg
- type: Extractable
juiceSolution:
reagents:
- ReagentId: Fiber
Quantity: 5
- type: Butcherable
butcheringType: Knife
spawned: MaterialCloth1
pieces: 3

View file

@ -48,6 +48,7 @@
name: Salvage Mob Spawner
id: SalvageMobSpawner
parent: MarkerBase
suffix: 25
components:
- type: Sprite
layers:
@ -65,3 +66,20 @@
chance: 0.25
offset: 0.2
- type: entity
id: SalvageMobSpawner75
parent: SalvageMobSpawner
suffix: 75
components:
- type: RandomSpawner
prototypes:
- MobCarp
- MobCarp
- MobCarp
- MobCarp
- MobCarp
- PlushieCarp
- DehydratedSpaceCarp
chance: 0.75
offset: 0.2

View file

@ -44,6 +44,8 @@
interactFailureString: petting-failure-bat
- type: SentienceTarget
flavorKind: organic
- type: Bloodstream
bloodMaxVolume: 50
- type: entity
name: bee
@ -90,6 +92,8 @@
- type: Tag
tags:
- Bee
- type: Bloodstream
bloodMaxVolume: 0.1
- type: entity
name: bee
@ -112,6 +116,9 @@
- type: AiFactionTag
factions:
- SimpleHostile
- type: Bloodstream
bloodMaxVolume: 0.1
- type: entity
name: chicken
@ -140,6 +147,8 @@
interactFailureString: petting-failure-generic
interactSuccessSound:
path: /Audio/Animals/chicken_cluck_happy.ogg
- type: Bloodstream
bloodMaxVolume: 100
- type: entity
name: mallard duck #Quack
@ -168,6 +177,8 @@
interactFailureString: petting-failure-generic
interactSuccessSound:
path: /Audio/Animals/duck_quack_happy.ogg
- type: Bloodstream
bloodMaxVolume: 100
- type: entity
name: white duck #Quack
@ -196,6 +207,8 @@
interactFailureString: petting-failure-generic
interactSuccessSound:
path: /Audio/Animals/duck_quack_happy.ogg
- type: Bloodstream
bloodMaxVolume: 100
- type: entity
name: brown duck #Quack
@ -224,6 +237,8 @@
interactFailureString: petting-failure-generic
interactSuccessSound:
path: /Audio/Animals/duck_quack_happy.ogg
- type: Bloodstream
bloodMaxVolume: 100
- type: entity
name: butterfly
@ -274,6 +289,8 @@
normal: butterfly
crit: dead
dead: dead
- type: Bloodstream
bloodMaxVolume: 0.1
- type: entity
name: cow
@ -329,6 +346,7 @@
interactSuccessString: petting-success-soft-floofy
interactFailureString: petting-failure-generic
- type: entity
name: crab
parent: SimpleMobBase
@ -368,6 +386,8 @@
successChance: 0.5
interactSuccessString: petting-success-crab
interactFailureString: petting-failure-crab
- type: Bloodstream
bloodMaxVolume: 50
- type: entity
name: goat
@ -436,6 +456,8 @@
successChance: 0.1 # Yeah, good luck with that.
interactSuccessString: petting-success-goose
interactFailureString: petting-failure-goose
- type: Bloodstream
bloodMaxVolume: 100
- type: entity
name: gorilla
@ -471,6 +493,8 @@
- type: Butcherable
spawned: FoodMeat
pieces: 4
- type: Bloodstream
bloodMaxVolume: 300
- type: entity
name: kangaroo
@ -550,6 +574,13 @@
group: Monkey
- type: SentienceTarget
flavorKind: primate
- type: Inventory
templateId: head
- type: Strippable
- type: UserInterface
interfaces:
- key: enum.StrippingUiKey.Key
type: StrippableBoundUserInterface
- type: Sprite
drawdepth: Mobs
layers:
@ -634,6 +665,8 @@
reagents:
- ReagentId: Nutriment
Quantity: 5
- ReagentId: Blood
Quantity: 50
- type: Butcherable
spawned: FoodMeat
pieces: 1
@ -652,6 +685,8 @@
disarmAction:
enabled: false
autoPopulate: false
- type: Bloodstream
bloodMaxVolume: 50
- type: entity
@ -672,6 +707,9 @@
normal: mouse-1
crit: dead-1
dead: splat-1
- type: Bloodstream
bloodMaxVolume: 50
- type: entity
parent: MobMouse
@ -691,10 +729,12 @@
normal: mouse-2
crit: dead-2
dead: splat-2
- type: Bloodstream
bloodMaxVolume: 50
- type: entity
name: lizard
name: lizard #Weh
parent: SimpleMobBase
id: MobLizard
description: I think it's lost.
@ -734,6 +774,8 @@
successChance: 0.3
interactSuccessString: petting-success-reptile
interactFailureString: petting-failure-generic
- type: Bloodstream
bloodMaxVolume: 50
- type: entity
name: frog
@ -776,6 +818,8 @@
successChance: 0.6
interactSuccessString: petting-success-frog
interactFailureString: petting-failure-generic
- type: Bloodstream
bloodMaxVolume: 50
# Would be cool to have some functionality for the parrot to be able to sit on stuff
- type: entity
@ -819,6 +863,8 @@
successChance: 0.6
interactSuccessString: petting-success-bird
interactFailureString: petting-failure-generic
- type: Bloodstream
bloodMaxVolume: 50
- type: entity
name: penguin
@ -900,6 +946,8 @@
successChance: 0.6
interactSuccessString: petting-success-reptile
interactFailureString: petting-failure-generic
- type: Bloodstream
bloodMaxVolume: 50
# Code unique spider prototypes or combine them all into one spider and get a
# random sprite state when you spawn it.

View file

@ -45,6 +45,13 @@
- type: Butcherable
spawned: FoodMeat # TODO: CrapMeat or FishMeat # - 2022-02-17 LMAO crap meat
pieces: 2
- type: UnarmedCombat
range: 1.5
arcwidth: 0
arc: bite
damage:
groups:
Brute: 20
- type: entity
name: magicarp

View file

@ -182,3 +182,6 @@
heatDamage:
types:
Heat : 1 #per second, scales with temperature & other constants
- type: Bloodstream
bloodMaxVolume: 150

View file

@ -14,6 +14,9 @@
- type: CombatMode
- type: Actions
- type: PlayerInputMover
- type: MovementSpeedModifier
baseSprintSpeed: 12
baseWalkSpeed: 8
- type: Physics
bodyType: Kinematic
status: InAir

View file

@ -69,5 +69,9 @@
Blunt: 22
- type: Actions
- type: Guardian
- type: InteractionPopup
interactSuccessString: petting-success-holo
interactFailureString: petting-failure-holo
successChance: 0.7
- type: NameIdentifier
group: Holoparasite

View file

@ -42,6 +42,6 @@
- state: animated
shader: unshaded
- type: MovementSpeedModifier
baseSprintSpeed: 14
baseWalkSpeed: 7
baseSprintSpeed: 8
baseWalkSpeed: 5
- type: MovementIgnoreGravity

View file

@ -77,7 +77,7 @@
- type: NameIdentifier
group: Drone
- type: Inventory
templateId: drone
templateId: head
- type: Strippable
- type: UserInterface
interfaces:

View file

@ -14,7 +14,6 @@
- type: Drink
- type: Sprite
state: icon
netsync: false
- type: Spillable
solution: drink
- type: UserInterface

View file

@ -1,9 +1,8 @@
# TODO: Add descriptions (3)
- type: entity
- type: entity
id: MachineParticleAcceleratorEndCapCircuitboard
parent: BaseMachineCircuitboard
name: PA End Cap
name: PA end cap board
description: A machine board for a particle accelerator end cap
components:
- type: MachineBoard
prototype: ParticleAcceleratorEndCapUnfinished
@ -14,7 +13,8 @@
- type: entity
id: MachineParticleAcceleratorFuelChamberCircuitboard
parent: BaseMachineCircuitboard
name: PA Fuel Chamber
name: PA fuel chamber board
description: A machine board for a particle accelerator fuel chamber
components:
- type: MachineBoard
prototype: ParticleAcceleratorFuelChamberUnfinished
@ -30,7 +30,8 @@
- type: entity
id: MachineParticleAcceleratorPowerBoxCircuitboard
parent: BaseMachineCircuitboard
name: PA Power Box
name: PA power box board
description: A machine board for a particle accelerator power box
components:
- type: MachineBoard
prototype: ParticleAcceleratorPowerBoxUnfinished
@ -43,7 +44,8 @@
- type: entity
id: MachineParticleAcceleratorEmitterLeftCircuitboard
parent: BaseMachineCircuitboard
name: PA Emitter Left
name: PA emitter left board
description: A machine board for a particle accelerator left emitter
components:
- type: MachineBoard
prototype: ParticleAcceleratorEmitterLeftUnfinished
@ -54,7 +56,8 @@
- type: entity
id: MachineParticleAcceleratorEmitterCenterCircuitboard
parent: BaseMachineCircuitboard
name: PA Emitter Center
name: PA emitter center board
description: A machine board for a particle accelerator center emitter
components:
- type: MachineBoard
prototype: ParticleAcceleratorEmitterCenterUnfinished
@ -65,7 +68,8 @@
- type: entity
id: MachineParticleAcceleratorEmitterRightCircuitboard
parent: BaseMachineCircuitboard
name: PA Emitter Right
name: PA emitter right board
description: A machine board for a particle accelerator right emitter
components:
- type: MachineBoard
prototype: ParticleAcceleratorEmitterRightUnfinished

View file

@ -1,9 +1,8 @@
# TODO: Add descriptions (3)
- type: entity
- type: entity
id: AutolatheMachineCircuitboard
parent: BaseMachineCircuitboard
name: Autolathe (Machine Board)
name: autolathe machine board
description: A machine printed circuit board for an autolathe
components:
- type: MachineBoard
prototype: Autolathe
@ -16,7 +15,8 @@
- type: entity
id: ProtolatheMachineCircuitboard
parent: BaseMachineCircuitboard
name: Protolathe (Machine Board)
name: protolathe machine board
description: A machine printed circuit board for a protolathe
components:
- type: MachineBoard
prototype: Protolathe
@ -83,7 +83,8 @@
- type: entity
id: CloningPodMachineCircuitboard
parent: BaseMachineCircuitboard
name: Cloning Pod (Machine Board)
name: cloning pod machine board
description: A machine printed circuit board for a cloning pod
components:
- type: MachineBoard
prototype: CloningPod
@ -97,7 +98,8 @@
- type: entity
id: MedicalScannerMachineCircuitboard
parent: BaseMachineCircuitboard
name: Medical Scanner (Machine Board)
name: medical scanner machine board
description: A machine printed circuit board for a medical scanner
components:
- type: MachineBoard
prototype: MedicalScanner
@ -112,7 +114,8 @@
- type: entity
id: ChemMasterMachineCircuitboard
parent: BaseMachineCircuitboard
name: Chem Master (Machine Board)
name: ChemMaster 4000 machine board
description: A machine printed circuit board for a ChemMaster 4000
components:
- type: MachineBoard
prototype: chem_master
@ -129,7 +132,8 @@
- type: entity
id: ChemDispenserMachineCircuitboard
parent: BaseMachineCircuitboard
name: Chem Dispenser (Machine Board)
name: chem dispenser machine board
description: A machine printed circuit board for a chem dispenser
components:
- type: MachineBoard
prototype: chem_dispenser
@ -143,7 +147,8 @@
- type: entity
id: HydroponicsTrayMachineCircuitboard
parent: BaseMachineCircuitboard
name: Hydroponics Tray (Machine Board)
name: hydroponics tray machine board
description: A machine printed circuit board for a hydroponics tray
components:
- type: MachineBoard
prototype: hydroponicsTray
@ -164,20 +169,22 @@
- type: entity
id: SMESMachineCircuitboard
parent: BaseMachineCircuitboard
name: SMES (Machine Board)
name: SMES machine board
description: A machine printed circuit board for a SMES
components:
- type: Sprite
sprite: Objects/Misc/module.rsi
state: power_mod
- type: MachineBoard
prototype: BaseSmes
prototype: BaseSMES
requirements:
Capacitor: 10
- type: entity
id: SubstationMachineCircuitboard
parent: BaseMachineCircuitboard
name: Substation (Machine Board)
name: substation machine board
description: A machine printed circuit board for a substation
components:
- type: MachineBoard
prototype: BaseSubstation
@ -224,9 +231,10 @@
- type: entity
id: KitchenReagentGrinderMachineCircuitboard #unsure why the reagent grinder has 'kitchen' in the id name when multiple departments use it but that's for another time
id: ReagentGrinderMachineCircuitboard
parent: BaseMachineCircuitboard
name: Reagent Grinder (Machine Board)
name: reagent grinder machine board
description: A machine printed circuit board for a reagent grinder
components:
- type: MachineBoard
prototype: KitchenReagentGrinder

View file

@ -1,20 +1,55 @@
# TODO: Add descriptions (10)
- type: entity
parent: BaseItem
id: BaseComputerCircuitboard
name: circuit board
name: computer board
abstract: true
components:
- type: ComputerBoard
- type: Sprite
sprite: Objects/Misc/module.rsi
state: id_mod
state: cpuboard
- type: entity
parent: BaseComputerCircuitboard
id: AlertsComputerCircuitboard
name: alerts computer board
description: A computer printed circuit board for an alerts computer
components:
- type: ComputerBoard
prototype: ComputerAlert
- type: entity
parent: BaseComputerCircuitboard
id: PowerComputerCircuitboard
name: power monitoring computer board
description: A computer printed circuit board for a power monitoring computer
components:
- type: ComputerBoard
prototype: ComputerPowerMonitoring
- type: entity
parent: BaseComputerCircuitboard
id: MedicalRecordsComputerCircuitboard
name: medical records computer board
description: A computer printed circuit board for a medical records computer
components:
- type: ComputerBoard
prototype: ComputerMedicalRecords
- type: entity
parent: BaseComputerCircuitboard
id: CriminalRecordsComputerCircuitboard
name: criminal records computer board
description: A computer printed circuit board for a criminal records computer
components:
- type: ComputerBoard
prototype: ComputerCriminalRecords
- type: entity
parent: BaseComputerCircuitboard
id: SupplyComputerCircuitboard
name: supply board
name: supply ordering computer board
description: A computer printed circuit board for a supply ordering console
components:
- type: ComputerBoard
prototype: ComputerSupplyOrdering
@ -22,7 +57,8 @@
- type: entity
parent: BaseComputerCircuitboard
id: SupplyRequestComputerCircuitboard
name: supply request board
name: supply request computer board
description: A computer printed circuit board for a supply request console
components:
- type: ComputerBoard
prototype: ComputerSupplyRequest
@ -31,6 +67,7 @@
parent: BaseComputerCircuitboard
id: ResearchComputerCircuitboard
name: R&D computer board
description: A computer printed circuit board for a R&D console
components:
- type: ComputerBoard
prototype: ComputerResearchAndDevelopment
@ -38,7 +75,8 @@
- type: entity
parent: BaseComputerCircuitboard
id: CrewMonitoringComputerCircuitboard
name: crew monitoring console board
name: crew monitoring computer board
description: A computer printed circuit board for a crew monitoring console
components:
- type: ComputerBoard
prototype: ComputerCrewMonitoring
@ -46,7 +84,8 @@
- type: entity
parent: BaseComputerCircuitboard
id: IDComputerCircuitboard
name: ID card terminal board
name: ID card computer board
description: A computer printed circuit board for an ID card console
components:
- type: ComputerBoard
prototype: ComputerId
@ -55,6 +94,7 @@
parent: BaseComputerCircuitboard
id: BodyScannerComputerCircuitboard
name: body scanner computer board
description: A computer printed circuit board for a body scanner console
components:
- type: ComputerBoard
prototype: computerBodyScanner
@ -63,6 +103,7 @@
parent: BaseComputerCircuitboard
id: CommsComputerCircuitboard
name: communications computer board
description: A computer printed circuit board for a communications console
components:
- type: ComputerBoard
prototype: ComputerComms
@ -79,6 +120,7 @@
parent: BaseComputerCircuitboard
id: SolarControlComputerCircuitboard
name: solar control computer board
description: A computer printed circuit board for a solar control console
components:
- type: ComputerBoard
prototype: ComputerSolarControl
@ -87,6 +129,7 @@
parent: BaseComputerCircuitboard
id: SpaceVillainArcadeComputerCircuitboard
name: space villain arcade board
description: A computer printed circuit board for a space villain arcade cabinet
components:
- type: ComputerBoard
prototype: SpaceVillainArcade
@ -95,6 +138,7 @@
parent: BaseComputerCircuitboard
id: BlockGameArcadeComputerCircuitboard
name: block game arcade board
description: A computer printed circuit board for a block game arcade cabinet
components:
- type: ComputerBoard
prototype: BlockGameArcade
@ -102,8 +146,8 @@
- type: entity
parent: BaseComputerCircuitboard
id: ParticleAcceleratorComputerCircuitboard
name: PA control box
suffix: Circuit Board
name: PA control box computer board
description: A computer printed circuit board for a particle accelerator control box
components:
- type: ComputerBoard
prototype: ParticleAcceleratorControlBoxUnfinished
@ -111,7 +155,8 @@
- type: entity
parent: BaseComputerCircuitboard
id: ShuttleConsoleCircuitboard
name: Shuttle Console Board
name: shuttle console board
description: A computer printed circuit board for a shuttle console
components:
- type: ComputerBoard
prototype: ComputerShuttle
@ -120,6 +165,7 @@
parent: BaseComputerCircuitboard
id: SyndicateShuttleConsoleCircuitboard
name: syndicate shuttle console board
description: A computer printed circuit board for a syndicate shuttle console
components:
- type: ComputerBoard
prototype: ComputerShuttleSyndie

View file

@ -2,7 +2,7 @@
id: APCElectronics
parent: BaseItem
name: APC electronics
description: Circuit used in APC construction.
description: An electronics board used in APC construction.
components:
- type: Sprite
sprite: Objects/Misc/module.rsi

View file

@ -2,6 +2,7 @@
id: AirAlarmElectronics
parent: BaseItem
name: air alarm electronics
description: An electronics board used in air alarms
components:
- type: Tag
tags:
@ -14,10 +15,11 @@
id: FireAlarmElectronics
parent: BaseItem
name: fire alarm electronics
description: An electronics board used in fire alarms
components:
- type: Tag
tags:
- FireAlarmElectronics
- type: Sprite
sprite: Objects/Misc/module.rsi
state: door_electronics
state: airalarm_electronics

View file

@ -2,6 +2,7 @@
id: DoorElectronics
parent: BaseItem
name: door electronics
description: An electronics board used in doors and airlocks
components:
- type: Tag
tags:

View file

@ -2,7 +2,7 @@
id: FirelockElectronics
parent: BaseItem
name: firelock electronics
description: Advanced circuit board used to detect differences in pressure, temperature and gas concentrations between the two sides of the door.
description: An electronics board used to detect differences in pressure, temperature and gas concentrations between the two sides of the door.
components:
- type: Tag
tags:

Some files were not shown because too many files have changed in this diff Show more