diff --git a/Content.Client/Atmos/Consoles/AtmosAlarmEntryContainer.xaml b/Content.Client/Atmos/Consoles/AtmosAlarmEntryContainer.xaml
new file mode 100644
index 0000000000..96f136abf0
--- /dev/null
+++ b/Content.Client/Atmos/Consoles/AtmosAlarmEntryContainer.xaml
@@ -0,0 +1,81 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Content.Client/Atmos/Consoles/AtmosAlarmEntryContainer.xaml.cs b/Content.Client/Atmos/Consoles/AtmosAlarmEntryContainer.xaml.cs
new file mode 100644
index 0000000000..b0d0365ef6
--- /dev/null
+++ b/Content.Client/Atmos/Consoles/AtmosAlarmEntryContainer.xaml.cs
@@ -0,0 +1,215 @@
+using Content.Client.Stylesheets;
+using Content.Shared.Atmos;
+using Content.Shared.Atmos.Components;
+using Content.Shared.Atmos.Monitor;
+using Content.Shared.FixedPoint;
+using Content.Shared.Temperature;
+using Robust.Client.AutoGenerated;
+using Robust.Client.Graphics;
+using Robust.Client.ResourceManagement;
+using Robust.Client.UserInterface.Controls;
+using Robust.Client.UserInterface.XAML;
+using Robust.Shared.Map;
+using System.Linq;
+
+namespace Content.Client.Atmos.Consoles;
+
+[GenerateTypedNameReferences]
+public sealed partial class AtmosAlarmEntryContainer : BoxContainer
+{
+ public NetEntity NetEntity;
+ public EntityCoordinates? Coordinates;
+
+ private readonly IEntityManager _entManager;
+ private readonly IResourceCache _cache;
+
+ private Dictionary _alarmStrings = new Dictionary()
+ {
+ [AtmosAlarmType.Invalid] = "atmos-alerts-window-invalid-state",
+ [AtmosAlarmType.Normal] = "atmos-alerts-window-normal-state",
+ [AtmosAlarmType.Warning] = "atmos-alerts-window-warning-state",
+ [AtmosAlarmType.Danger] = "atmos-alerts-window-danger-state",
+ };
+
+ private Dictionary _gasShorthands = new Dictionary()
+ {
+ [Gas.Ammonia] = "NH₃",
+ [Gas.CarbonDioxide] = "CO₂",
+ [Gas.Frezon] = "F",
+ [Gas.Nitrogen] = "N₂",
+ [Gas.NitrousOxide] = "N₂O",
+ [Gas.Oxygen] = "O₂",
+ [Gas.Plasma] = "P",
+ [Gas.Tritium] = "T",
+ [Gas.WaterVapor] = "H₂O",
+ };
+
+ public AtmosAlarmEntryContainer(NetEntity uid, EntityCoordinates? coordinates)
+ {
+ RobustXamlLoader.Load(this);
+
+ _entManager = IoCManager.Resolve();
+ _cache = IoCManager.Resolve();
+
+ NetEntity = uid;
+ Coordinates = coordinates;
+
+ // Load fonts
+ var headerFont = new VectorFont(_cache.GetResource("/Fonts/NotoSans/NotoSans-Bold.ttf"), 11);
+ var normalFont = new VectorFont(_cache.GetResource("/Fonts/NotoSansDisplay/NotoSansDisplay-Regular.ttf"), 11);
+ var smallFont = new VectorFont(_cache.GetResource("/Fonts/NotoSans/NotoSans-Regular.ttf"), 10);
+
+ // Set fonts
+ TemperatureHeaderLabel.FontOverride = headerFont;
+ PressureHeaderLabel.FontOverride = headerFont;
+ OxygenationHeaderLabel.FontOverride = headerFont;
+ GasesHeaderLabel.FontOverride = headerFont;
+
+ TemperatureLabel.FontOverride = normalFont;
+ PressureLabel.FontOverride = normalFont;
+ OxygenationLabel.FontOverride = normalFont;
+
+ NoDataLabel.FontOverride = headerFont;
+
+ SilenceCheckBox.Label.FontOverride = smallFont;
+ SilenceCheckBox.Label.FontColorOverride = Color.DarkGray;
+ }
+
+ public void UpdateEntry(AtmosAlertsComputerEntry entry, bool isFocus, AtmosAlertsFocusDeviceData? focusData = null)
+ {
+ NetEntity = entry.NetEntity;
+ Coordinates = _entManager.GetCoordinates(entry.Coordinates);
+
+ // Load fonts
+ var normalFont = new VectorFont(_cache.GetResource("/Fonts/NotoSansDisplay/NotoSansDisplay-Regular.ttf"), 11);
+
+ // Update alarm state
+ if (!_alarmStrings.TryGetValue(entry.AlarmState, out var alarmString))
+ alarmString = "atmos-alerts-window-invalid-state";
+
+ AlarmStateLabel.Text = Loc.GetString(alarmString);
+ AlarmStateLabel.FontColorOverride = GetAlarmStateColor(entry.AlarmState);
+
+ // Update alarm name
+ AlarmNameLabel.Text = Loc.GetString("atmos-alerts-window-alarm-label", ("name", entry.EntityName), ("address", entry.Address));
+
+ // Focus updates
+ FocusContainer.Visible = isFocus;
+
+ if (isFocus)
+ SetAsFocus();
+ else
+ RemoveAsFocus();
+
+ if (isFocus && entry.Group == AtmosAlertsComputerGroup.AirAlarm)
+ {
+ MainDataContainer.Visible = (entry.AlarmState != AtmosAlarmType.Invalid);
+ NoDataLabel.Visible = (entry.AlarmState == AtmosAlarmType.Invalid);
+
+ if (focusData != null)
+ {
+ // Update temperature
+ var tempK = (FixedPoint2)focusData.Value.TemperatureData.Item1;
+ var tempC = (FixedPoint2)TemperatureHelpers.KelvinToCelsius(tempK.Float());
+
+ TemperatureLabel.Text = Loc.GetString("atmos-alerts-window-temperature-value", ("valueInC", tempC), ("valueInK", tempK));
+ TemperatureLabel.FontColorOverride = GetAlarmStateColor(focusData.Value.TemperatureData.Item2);
+
+ // Update pressure
+ PressureLabel.Text = Loc.GetString("atmos-alerts-window-pressure-value", ("value", (FixedPoint2)focusData.Value.PressureData.Item1));
+ PressureLabel.FontColorOverride = GetAlarmStateColor(focusData.Value.PressureData.Item2);
+
+ // Update oxygenation
+ var oxygenPercent = (FixedPoint2)0f;
+ var oxygenAlert = AtmosAlarmType.Invalid;
+
+ if (focusData.Value.GasData.TryGetValue(Gas.Oxygen, out var oxygenData))
+ {
+ oxygenPercent = oxygenData.Item2 * 100f;
+ oxygenAlert = oxygenData.Item3;
+ }
+
+ OxygenationLabel.Text = Loc.GetString("atmos-alerts-window-oxygenation-value", ("value", oxygenPercent));
+ OxygenationLabel.FontColorOverride = GetAlarmStateColor(oxygenAlert);
+
+ // Update other present gases
+ GasGridContainer.RemoveAllChildren();
+
+ var gasData = focusData.Value.GasData.Where(g => g.Key != Gas.Oxygen);
+
+ if (gasData.Count() == 0)
+ {
+ // No other gases
+ var gasLabel = new Label()
+ {
+ Text = Loc.GetString("atmos-alerts-window-other-gases-value-nil"),
+ FontOverride = normalFont,
+ FontColorOverride = StyleNano.DisabledFore,
+ HorizontalAlignment = HAlignment.Center,
+ VerticalAlignment = VAlignment.Center,
+ HorizontalExpand = true,
+ Margin = new Thickness(0, 2, 0, 0),
+ SetHeight = 24f,
+ };
+
+ GasGridContainer.AddChild(gasLabel);
+ }
+
+ else
+ {
+ // Add an entry for each gas
+ foreach ((var gas, (var mol, var percent, var alert)) in gasData)
+ {
+ var gasPercent = (FixedPoint2)0f;
+ gasPercent = percent * 100f;
+
+ if (!_gasShorthands.TryGetValue(gas, out var gasShorthand))
+ gasShorthand = "X";
+
+ var gasLabel = new Label()
+ {
+ Text = Loc.GetString("atmos-alerts-window-other-gases-value", ("shorthand", gasShorthand), ("value", gasPercent)),
+ FontOverride = normalFont,
+ FontColorOverride = GetAlarmStateColor(alert),
+ HorizontalAlignment = HAlignment.Center,
+ VerticalAlignment = VAlignment.Center,
+ HorizontalExpand = true,
+ Margin = new Thickness(0, 2, 0, 0),
+ SetHeight = 24f,
+ };
+
+ GasGridContainer.AddChild(gasLabel);
+ }
+ }
+ }
+ }
+ }
+
+ public void SetAsFocus()
+ {
+ FocusButton.AddStyleClass(StyleNano.StyleClassButtonColorGreen);
+ ArrowTexture.TexturePath = "/Textures/Interface/Nano/inverted_triangle.svg.png";
+ }
+
+ public void RemoveAsFocus()
+ {
+ FocusButton.RemoveStyleClass(StyleNano.StyleClassButtonColorGreen);
+ ArrowTexture.TexturePath = "/Textures/Interface/Nano/triangle_right.png";
+ FocusContainer.Visible = false;
+ }
+
+ private Color GetAlarmStateColor(AtmosAlarmType alarmType)
+ {
+ switch (alarmType)
+ {
+ case AtmosAlarmType.Normal:
+ return StyleNano.GoodGreenFore;
+ case AtmosAlarmType.Warning:
+ return StyleNano.ConcerningOrangeFore;
+ case AtmosAlarmType.Danger:
+ return StyleNano.DangerousRedFore;
+ }
+
+ return StyleNano.DisabledFore;
+ }
+}
\ No newline at end of file
diff --git a/Content.Client/Atmos/Consoles/AtmosAlertsComputerBoundUserInterface.cs b/Content.Client/Atmos/Consoles/AtmosAlertsComputerBoundUserInterface.cs
new file mode 100644
index 0000000000..08cae979b9
--- /dev/null
+++ b/Content.Client/Atmos/Consoles/AtmosAlertsComputerBoundUserInterface.cs
@@ -0,0 +1,52 @@
+using Content.Shared.Atmos.Components;
+
+namespace Content.Client.Atmos.Consoles;
+
+public sealed class AtmosAlertsComputerBoundUserInterface : BoundUserInterface
+{
+ [ViewVariables]
+ private AtmosAlertsComputerWindow? _menu;
+
+ public AtmosAlertsComputerBoundUserInterface(EntityUid owner, Enum uiKey) : base(owner, uiKey) { }
+
+ protected override void Open()
+ {
+ _menu = new AtmosAlertsComputerWindow(this, Owner);
+ _menu.OpenCentered();
+ _menu.OnClose += Close;
+
+ EntMan.TryGetComponent(Owner, out var xform);
+ }
+
+ protected override void UpdateState(BoundUserInterfaceState state)
+ {
+ base.UpdateState(state);
+
+ var castState = (AtmosAlertsComputerBoundInterfaceState) state;
+
+ if (castState == null)
+ return;
+
+ EntMan.TryGetComponent(Owner, out var xform);
+ _menu?.UpdateUI(xform?.Coordinates, castState.AirAlarms, castState.FireAlarms, castState.FocusData);
+ }
+
+ public void SendFocusChangeMessage(NetEntity? netEntity)
+ {
+ SendMessage(new AtmosAlertsComputerFocusChangeMessage(netEntity));
+ }
+
+ public void SendDeviceSilencedMessage(NetEntity netEntity, bool silenceDevice)
+ {
+ SendMessage(new AtmosAlertsComputerDeviceSilencedMessage(netEntity, silenceDevice));
+ }
+
+ protected override void Dispose(bool disposing)
+ {
+ base.Dispose(disposing);
+ if (!disposing)
+ return;
+
+ _menu?.Dispose();
+ }
+}
diff --git a/Content.Client/Atmos/Consoles/AtmosAlertsComputerWindow.xaml b/Content.Client/Atmos/Consoles/AtmosAlertsComputerWindow.xaml
new file mode 100644
index 0000000000..8824a776ee
--- /dev/null
+++ b/Content.Client/Atmos/Consoles/AtmosAlertsComputerWindow.xaml
@@ -0,0 +1,108 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Content.Client/Atmos/Consoles/AtmosAlertsComputerWindow.xaml.cs b/Content.Client/Atmos/Consoles/AtmosAlertsComputerWindow.xaml.cs
new file mode 100644
index 0000000000..a55321833c
--- /dev/null
+++ b/Content.Client/Atmos/Consoles/AtmosAlertsComputerWindow.xaml.cs
@@ -0,0 +1,550 @@
+using Content.Client.Message;
+using Content.Client.Pinpointer.UI;
+using Content.Client.Stylesheets;
+using Content.Client.UserInterface.Controls;
+using Content.Shared.Atmos.Components;
+using Content.Shared.Atmos.Monitor;
+using Content.Shared.Pinpointer;
+using Robust.Client.AutoGenerated;
+using Robust.Client.GameObjects;
+using Robust.Client.UserInterface;
+using Robust.Client.UserInterface.Controls;
+using Robust.Client.UserInterface.XAML;
+using Robust.Shared.Map;
+using Robust.Shared.Timing;
+using Robust.Shared.Utility;
+using Robust.Shared.ContentPack;
+using Robust.Shared.Prototypes;
+using System.Diagnostics.CodeAnalysis;
+using System.Linq;
+
+namespace Content.Client.Atmos.Consoles;
+
+[GenerateTypedNameReferences]
+public sealed partial class AtmosAlertsComputerWindow : FancyWindow
+{
+ private readonly IEntityManager _entManager;
+ private readonly SpriteSystem _spriteSystem;
+
+ private EntityUid? _owner;
+ private NetEntity? _trackedEntity;
+
+ private AtmosAlertsComputerEntry[]? _airAlarms = null;
+ private AtmosAlertsComputerEntry[]? _fireAlarms = null;
+ private IEnumerable? _allAlarms = null;
+
+ private IEnumerable? _activeAlarms = null;
+ private Dictionary _deviceSilencingProgress = new();
+
+ public event Action? SendFocusChangeMessageAction;
+ public event Action? SendDeviceSilencedMessageAction;
+
+ private bool _autoScrollActive = false;
+ private bool _autoScrollAwaitsUpdate = false;
+
+ private const float SilencingDuration = 2.5f;
+
+ public AtmosAlertsComputerWindow(AtmosAlertsComputerBoundUserInterface userInterface, EntityUid? owner)
+ {
+ RobustXamlLoader.Load(this);
+ _entManager = IoCManager.Resolve();
+ _spriteSystem = _entManager.System();
+
+ // Pass the owner to nav map
+ _owner = owner;
+ NavMap.Owner = _owner;
+
+ // Set nav map colors
+ NavMap.WallColor = new Color(64, 64, 64);
+ NavMap.TileColor = Color.DimGray * NavMap.WallColor;
+
+ // Set nav map grid uid
+ var stationName = Loc.GetString("atmos-alerts-window-unknown-location");
+
+ if (_entManager.TryGetComponent(owner, out var xform))
+ {
+ NavMap.MapUid = xform.GridUid;
+
+ // Assign station name
+ if (_entManager.TryGetComponent(xform.GridUid, out var stationMetaData))
+ stationName = stationMetaData.EntityName;
+
+ var msg = new FormattedMessage();
+ msg.AddMarkup(Loc.GetString("atmos-alerts-window-station-name", ("stationName", stationName)));
+
+ StationName.SetMessage(msg);
+ }
+
+ else
+ {
+ StationName.SetMessage(stationName);
+ NavMap.Visible = false;
+ }
+
+ // Set trackable entity selected action
+ NavMap.TrackedEntitySelectedAction += SetTrackedEntityFromNavMap;
+
+ // Update nav map
+ NavMap.ForceNavMapUpdate();
+
+ // Set tab container headers
+ MasterTabContainer.SetTabTitle(0, Loc.GetString("atmos-alerts-window-tab-no-alerts"));
+ MasterTabContainer.SetTabTitle(1, Loc.GetString("atmos-alerts-window-tab-air-alarms"));
+ MasterTabContainer.SetTabTitle(2, Loc.GetString("atmos-alerts-window-tab-fire-alarms"));
+
+ // Set UI toggles
+ ShowInactiveAlarms.OnToggled += _ => OnShowAlarmsToggled(ShowInactiveAlarms, AtmosAlarmType.Invalid);
+ ShowNormalAlarms.OnToggled += _ => OnShowAlarmsToggled(ShowNormalAlarms, AtmosAlarmType.Normal);
+ ShowWarningAlarms.OnToggled += _ => OnShowAlarmsToggled(ShowWarningAlarms, AtmosAlarmType.Warning);
+ ShowDangerAlarms.OnToggled += _ => OnShowAlarmsToggled(ShowDangerAlarms, AtmosAlarmType.Danger);
+
+ // Set atmos monitoring message action
+ SendFocusChangeMessageAction += userInterface.SendFocusChangeMessage;
+ SendDeviceSilencedMessageAction += userInterface.SendDeviceSilencedMessage;
+ }
+
+ #region Toggle handling
+
+ private void OnShowAlarmsToggled(CheckBox toggle, AtmosAlarmType toggledAlarmState)
+ {
+ if (_owner == null)
+ return;
+
+ if (!_entManager.TryGetComponent(_owner.Value, out var console))
+ return;
+
+ foreach (var device in console.AtmosDevices)
+ {
+ var alarmState = GetAlarmState(device.NetEntity);
+
+ if (toggledAlarmState != alarmState)
+ continue;
+
+ if (toggle.Pressed)
+ AddTrackedEntityToNavMap(device, alarmState);
+
+ else
+ NavMap.TrackedEntities.Remove(device.NetEntity);
+ }
+ }
+
+ private void OnSilenceAlertsToggled(NetEntity netEntity, bool toggleState)
+ {
+ if (!_entManager.TryGetComponent(_owner, out var console))
+ return;
+
+ if (toggleState)
+ _deviceSilencingProgress[netEntity] = SilencingDuration;
+
+ else
+ _deviceSilencingProgress.Remove(netEntity);
+
+ foreach (AtmosAlarmEntryContainer entryContainer in AlertsTable.Children)
+ {
+ if (entryContainer.NetEntity == netEntity)
+ entryContainer.SilenceAlarmProgressBar.Visible = toggleState;
+ }
+
+ SendDeviceSilencedMessageAction?.Invoke(netEntity, toggleState);
+ }
+
+ #endregion
+
+ public void UpdateUI(EntityCoordinates? consoleCoords, AtmosAlertsComputerEntry[] airAlarms, AtmosAlertsComputerEntry[] fireAlarms, AtmosAlertsFocusDeviceData? focusData)
+ {
+ if (_owner == null)
+ return;
+
+ if (!_entManager.TryGetComponent(_owner.Value, out var console))
+ return;
+
+ if (_trackedEntity != focusData?.NetEntity)
+ {
+ SendFocusChangeMessageAction?.Invoke(_trackedEntity);
+ focusData = null;
+ }
+
+ // Retain alarm data for use inbetween updates
+ _airAlarms = airAlarms;
+ _fireAlarms = fireAlarms;
+ _allAlarms = airAlarms.Concat(fireAlarms);
+
+ var silenced = console.SilencedDevices;
+
+ _activeAlarms = _allAlarms.Where(x => x.AlarmState > AtmosAlarmType.Normal &&
+ (!silenced.Contains(x.NetEntity) || _deviceSilencingProgress.ContainsKey(x.NetEntity)));
+
+ // Reset nav map data
+ NavMap.TrackedCoordinates.Clear();
+ NavMap.TrackedEntities.Clear();
+
+ // Add tracked entities to the nav map
+ foreach (var device in console.AtmosDevices)
+ {
+ if (!NavMap.Visible)
+ continue;
+
+ var alarmState = GetAlarmState(device.NetEntity);
+
+ if (_trackedEntity != device.NetEntity)
+ {
+ // Skip air alarms if the appropriate overlay is off
+ if (!ShowInactiveAlarms.Pressed && alarmState == AtmosAlarmType.Invalid)
+ continue;
+
+ if (!ShowNormalAlarms.Pressed && alarmState == AtmosAlarmType.Normal)
+ continue;
+
+ if (!ShowWarningAlarms.Pressed && alarmState == AtmosAlarmType.Warning)
+ continue;
+
+ if (!ShowDangerAlarms.Pressed && alarmState == AtmosAlarmType.Danger)
+ continue;
+ }
+
+ AddTrackedEntityToNavMap(device, alarmState);
+ }
+
+ // Show the monitor location
+ var consoleUid = _entManager.GetNetEntity(_owner);
+
+ if (consoleCoords != null && consoleUid != null)
+ {
+ var texture = _spriteSystem.Frame0(new SpriteSpecifier.Texture(new ResPath("/Textures/Interface/NavMap/beveled_circle.png")));
+ var blip = new NavMapBlip(consoleCoords.Value, texture, Color.Cyan, true, false);
+ NavMap.TrackedEntities[consoleUid.Value] = blip;
+ }
+
+ // Update the nav map
+ NavMap.ForceNavMapUpdate();
+
+ // Clear excess children from the tables
+ var activeAlarmCount = _activeAlarms.Count();
+
+ while (AlertsTable.ChildCount > activeAlarmCount)
+ AlertsTable.RemoveChild(AlertsTable.GetChild(AlertsTable.ChildCount - 1));
+
+ while (AirAlarmsTable.ChildCount > airAlarms.Length)
+ AirAlarmsTable.RemoveChild(AirAlarmsTable.GetChild(AirAlarmsTable.ChildCount - 1));
+
+ while (FireAlarmsTable.ChildCount > fireAlarms.Length)
+ FireAlarmsTable.RemoveChild(FireAlarmsTable.GetChild(FireAlarmsTable.ChildCount - 1));
+
+ // Update all entries in each table
+ for (int index = 0; index < _activeAlarms.Count(); index++)
+ {
+ var entry = _activeAlarms.ElementAt(index);
+ UpdateUIEntry(entry, index, AlertsTable, console, focusData);
+ }
+
+ for (int index = 0; index < airAlarms.Count(); index++)
+ {
+ var entry = airAlarms.ElementAt(index);
+ UpdateUIEntry(entry, index, AirAlarmsTable, console, focusData);
+ }
+
+ for (int index = 0; index < fireAlarms.Count(); index++)
+ {
+ var entry = fireAlarms.ElementAt(index);
+ UpdateUIEntry(entry, index, FireAlarmsTable, console, focusData);
+ }
+
+ // If no alerts are active, display a message
+ if (MasterTabContainer.CurrentTab == 0 && activeAlarmCount == 0)
+ {
+ var label = new RichTextLabel()
+ {
+ HorizontalExpand = true,
+ VerticalExpand = true,
+ HorizontalAlignment = HAlignment.Center,
+ VerticalAlignment = VAlignment.Center,
+ };
+
+ label.SetMarkup(Loc.GetString("atmos-alerts-window-no-active-alerts", ("color", StyleNano.GoodGreenFore.ToHexNoAlpha())));
+
+ AlertsTable.AddChild(label);
+ }
+
+ // Update the alerts tab with the number of active alerts
+ if (activeAlarmCount == 0)
+ MasterTabContainer.SetTabTitle(0, Loc.GetString("atmos-alerts-window-tab-no-alerts"));
+
+ else
+ MasterTabContainer.SetTabTitle(0, Loc.GetString("atmos-alerts-window-tab-alerts", ("value", activeAlarmCount)));
+
+ // Auto-scroll re-enable
+ if (_autoScrollAwaitsUpdate)
+ {
+ _autoScrollActive = true;
+ _autoScrollAwaitsUpdate = false;
+ }
+ }
+
+ private void AddTrackedEntityToNavMap(AtmosAlertsDeviceNavMapData metaData, AtmosAlarmType alarmState)
+ {
+ var data = GetBlipTexture(alarmState);
+
+ if (data == null)
+ return;
+
+ var texture = data.Value.Item1;
+ var color = data.Value.Item2;
+ var coords = _entManager.GetCoordinates(metaData.NetCoordinates);
+
+ if (_trackedEntity != null && _trackedEntity != metaData.NetEntity)
+ color *= Color.DimGray;
+
+ var selectable = true;
+ var blip = new NavMapBlip(coords, _spriteSystem.Frame0(texture), color, _trackedEntity == metaData.NetEntity, selectable);
+
+ NavMap.TrackedEntities[metaData.NetEntity] = blip;
+ }
+
+ private void UpdateUIEntry(AtmosAlertsComputerEntry entry, int index, Control table, AtmosAlertsComputerComponent console, AtmosAlertsFocusDeviceData? focusData = null)
+ {
+ // Make new UI entry if required
+ if (index >= table.ChildCount)
+ {
+ var newEntryContainer = new AtmosAlarmEntryContainer(entry.NetEntity, _entManager.GetCoordinates(entry.Coordinates));
+
+ // On click
+ newEntryContainer.FocusButton.OnButtonUp += args =>
+ {
+ if (_trackedEntity == newEntryContainer.NetEntity)
+ {
+ _trackedEntity = null;
+ }
+
+ else
+ {
+ _trackedEntity = newEntryContainer.NetEntity;
+
+ if (newEntryContainer.Coordinates != null)
+ NavMap.CenterToCoordinates(newEntryContainer.Coordinates.Value);
+ }
+
+ // Send message to console that the focus has changed
+ SendFocusChangeMessageAction?.Invoke(_trackedEntity);
+
+ // Update affected UI elements across all tables
+ UpdateConsoleTable(console, AlertsTable, _trackedEntity);
+ UpdateConsoleTable(console, AirAlarmsTable, _trackedEntity);
+ UpdateConsoleTable(console, FireAlarmsTable, _trackedEntity);
+ };
+
+ // On toggling the silence check box
+ newEntryContainer.SilenceCheckBox.OnToggled += _ => OnSilenceAlertsToggled(newEntryContainer.NetEntity, newEntryContainer.SilenceCheckBox.Pressed);
+
+ // Add the entry to the current table
+ table.AddChild(newEntryContainer);
+ }
+
+ // Update values and UI elements
+ var tableChild = table.GetChild(index);
+
+ if (tableChild is not AtmosAlarmEntryContainer)
+ {
+ table.RemoveChild(tableChild);
+ UpdateUIEntry(entry, index, table, console, focusData);
+
+ return;
+ }
+
+ var entryContainer = (AtmosAlarmEntryContainer)tableChild;
+
+ entryContainer.UpdateEntry(entry, entry.NetEntity == _trackedEntity, focusData);
+
+ if (_trackedEntity != entry.NetEntity)
+ {
+ var silenced = console.SilencedDevices;
+ entryContainer.SilenceCheckBox.Pressed = (silenced.Contains(entry.NetEntity) || _deviceSilencingProgress.ContainsKey(entry.NetEntity));
+ }
+
+ entryContainer.SilenceAlarmProgressBar.Visible = (table == AlertsTable && _deviceSilencingProgress.ContainsKey(entry.NetEntity));
+ }
+
+ private void UpdateConsoleTable(AtmosAlertsComputerComponent console, Control table, NetEntity? currTrackedEntity)
+ {
+ foreach (var tableChild in table.Children)
+ {
+ if (tableChild is not AtmosAlarmEntryContainer)
+ continue;
+
+ var entryContainer = (AtmosAlarmEntryContainer)tableChild;
+
+ if (entryContainer.NetEntity != currTrackedEntity)
+ entryContainer.RemoveAsFocus();
+
+ else if (entryContainer.NetEntity == currTrackedEntity)
+ entryContainer.SetAsFocus();
+ }
+ }
+
+ private void SetTrackedEntityFromNavMap(NetEntity? netEntity)
+ {
+ if (netEntity == null)
+ return;
+
+ if (!_entManager.TryGetComponent(_owner, out var console))
+ return;
+
+ _trackedEntity = netEntity;
+
+ if (netEntity != null)
+ {
+ // Tab switching
+ if (MasterTabContainer.CurrentTab != 0 || _activeAlarms?.Any(x => x.NetEntity == netEntity) == false)
+ {
+ var device = console.AtmosDevices.FirstOrNull(x => x.NetEntity == netEntity);
+
+ switch (device?.Group)
+ {
+ case AtmosAlertsComputerGroup.AirAlarm:
+ MasterTabContainer.CurrentTab = 1; break;
+ case AtmosAlertsComputerGroup.FireAlarm:
+ MasterTabContainer.CurrentTab = 2; break;
+ }
+ }
+
+ // Get the scroll position of the selected entity on the selected button the UI
+ ActivateAutoScrollToFocus();
+ }
+
+ // Send message to console that the focus has changed
+ SendFocusChangeMessageAction?.Invoke(_trackedEntity);
+ }
+
+ protected override void FrameUpdate(FrameEventArgs args)
+ {
+ AutoScrollToFocus();
+
+ // Device silencing update
+ foreach ((var device, var remainingTime) in _deviceSilencingProgress)
+ {
+ var t = remainingTime - args.DeltaSeconds;
+
+ if (t <= 0)
+ {
+ _deviceSilencingProgress.Remove(device);
+
+ if (device == _trackedEntity)
+ _trackedEntity = null;
+ }
+
+ else
+ _deviceSilencingProgress[device] = t;
+ }
+ }
+
+ private void ActivateAutoScrollToFocus()
+ {
+ _autoScrollActive = false;
+ _autoScrollAwaitsUpdate = true;
+ }
+
+ private void AutoScrollToFocus()
+ {
+ if (!_autoScrollActive)
+ return;
+
+ var scroll = MasterTabContainer.Children.ElementAt(MasterTabContainer.CurrentTab) as ScrollContainer;
+ if (scroll == null)
+ return;
+
+ if (!TryGetVerticalScrollbar(scroll, out var vScrollbar))
+ return;
+
+ if (!TryGetNextScrollPosition(out float? nextScrollPosition))
+ return;
+
+ vScrollbar.ValueTarget = nextScrollPosition.Value;
+
+ if (MathHelper.CloseToPercent(vScrollbar.Value, vScrollbar.ValueTarget))
+ _autoScrollActive = false;
+ }
+
+ private bool TryGetVerticalScrollbar(ScrollContainer scroll, [NotNullWhen(true)] out VScrollBar? vScrollBar)
+ {
+ vScrollBar = null;
+
+ foreach (var child in scroll.Children)
+ {
+ if (child is not VScrollBar)
+ continue;
+
+ var castChild = child as VScrollBar;
+
+ if (castChild != null)
+ {
+ vScrollBar = castChild;
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ private bool TryGetNextScrollPosition([NotNullWhen(true)] out float? nextScrollPosition)
+ {
+ nextScrollPosition = null;
+
+ var scroll = MasterTabContainer.Children.ElementAt(MasterTabContainer.CurrentTab) as ScrollContainer;
+ if (scroll == null)
+ return false;
+
+ var container = scroll.Children.ElementAt(0) as BoxContainer;
+ if (container == null || container.Children.Count() == 0)
+ return false;
+
+ // Exit if the heights of the children haven't been initialized yet
+ if (!container.Children.Any(x => x.Height > 0))
+ return false;
+
+ nextScrollPosition = 0;
+
+ foreach (var control in container.Children)
+ {
+ if (control == null || control is not AtmosAlarmEntryContainer)
+ continue;
+
+ if (((AtmosAlarmEntryContainer)control).NetEntity == _trackedEntity)
+ return true;
+
+ nextScrollPosition += control.Height;
+ }
+
+ // Failed to find control
+ nextScrollPosition = null;
+
+ return false;
+ }
+
+ private AtmosAlarmType GetAlarmState(NetEntity netEntity)
+ {
+ var alarmState = _allAlarms?.FirstOrNull(x => x.NetEntity == netEntity)?.AlarmState;
+
+ if (alarmState == null)
+ return AtmosAlarmType.Invalid;
+
+ return alarmState.Value;
+ }
+
+ private (SpriteSpecifier.Texture, Color)? GetBlipTexture(AtmosAlarmType alarmState)
+ {
+ (SpriteSpecifier.Texture, Color)? output = null;
+
+ switch (alarmState)
+ {
+ case AtmosAlarmType.Invalid:
+ output = (new SpriteSpecifier.Texture(new ResPath("/Textures/Interface/NavMap/beveled_circle.png")), StyleNano.DisabledFore); break;
+ case AtmosAlarmType.Normal:
+ output = (new SpriteSpecifier.Texture(new ResPath("/Textures/Interface/NavMap/beveled_circle.png")), Color.LimeGreen); break;
+ case AtmosAlarmType.Warning:
+ output = (new SpriteSpecifier.Texture(new ResPath("/Textures/Interface/NavMap/beveled_triangle.png")), new Color(255, 182, 72)); break;
+ case AtmosAlarmType.Danger:
+ output = (new SpriteSpecifier.Texture(new ResPath("/Textures/Interface/NavMap/beveled_square.png")), new Color(255, 67, 67)); break;
+ }
+
+ return output;
+ }
+}
\ No newline at end of file
diff --git a/Content.Server/Administration/Commands/SetOutfitCommand.cs b/Content.Server/Administration/Commands/SetOutfitCommand.cs
index 1231228651..e19c5b72fa 100644
--- a/Content.Server/Administration/Commands/SetOutfitCommand.cs
+++ b/Content.Server/Administration/Commands/SetOutfitCommand.cs
@@ -14,6 +14,7 @@
using Robust.Shared.Prototypes;
using Content.Server.Silicon.IPC;
using Content.Shared.Radio.Components;
+using Content.Shared.Cluwne;
namespace Content.Server.Administration.Commands
{
@@ -129,6 +130,8 @@ public static bool SetOutfit(EntityUid target, string gear, IEntityManager entit
}
}
+ if (entityManager.HasComponent(target))
+ return true; //Fuck it, nuclear option for not Cluwning an IPC because that causes a crash that SOMEHOW ignores null checks.
if (entityManager.HasComponent(target))
{
var encryption = new InternalEncryptionKeySpawner();
diff --git a/Content.Server/Atmos/Consoles/AtmosAlertsComputerSystem.cs b/Content.Server/Atmos/Consoles/AtmosAlertsComputerSystem.cs
new file mode 100644
index 0000000000..758fde88f1
--- /dev/null
+++ b/Content.Server/Atmos/Consoles/AtmosAlertsComputerSystem.cs
@@ -0,0 +1,356 @@
+using Content.Server.Atmos.Monitor.Components;
+using Content.Server.DeviceNetwork.Components;
+using Content.Server.Power.Components;
+using Content.Shared.Atmos;
+using Content.Shared.Atmos.Components;
+using Content.Shared.Atmos.Consoles;
+using Content.Shared.Atmos.Monitor;
+using Content.Shared.Atmos.Monitor.Components;
+using Content.Shared.Pinpointer;
+using Robust.Server.GameObjects;
+using Robust.Shared.Map.Components;
+using Robust.Shared.Player;
+using Robust.Shared.ContentPack;
+using Robust.Shared.Prototypes;
+using System.Diagnostics.CodeAnalysis;
+using System.Linq;
+using Content.Shared.Access.Components;
+using Content.Shared.Database;
+using Content.Shared.NameIdentifier;
+using Content.Shared.Stacks;
+using JetBrains.Annotations;
+using Robust.Shared.Utility;
+
+namespace Content.Server.Atmos.Monitor.Systems;
+
+public sealed class AtmosAlertsComputerSystem : SharedAtmosAlertsComputerSystem
+{
+ [Dependency] private readonly UserInterfaceSystem _uiSystem = default!;
+ [Dependency] private readonly AirAlarmSystem _airAlarmSystem = default!;
+ [Dependency] private readonly AtmosDeviceNetworkSystem _atmosDevNet = default!;
+ [Dependency] private readonly SharedAppearanceSystem _appearance = default!;
+
+ private const float UpdateTime = 1.0f;
+
+ // Note: this data does not need to be saved
+ private float _updateTimer = 1.0f;
+
+ public override void Initialize()
+ {
+ base.Initialize();
+
+ // Console events
+ SubscribeLocalEvent(OnConsoleInit);
+ SubscribeLocalEvent(OnConsoleParentChanged);
+ SubscribeLocalEvent(OnFocusChangedMessage);
+
+ // Grid events
+ SubscribeLocalEvent(OnGridSplit);
+ SubscribeLocalEvent(OnDeviceAnchorChanged);
+ }
+
+ #region Event handling
+
+ private void OnConsoleInit(EntityUid uid, AtmosAlertsComputerComponent component, ComponentInit args)
+ {
+ InitalizeConsole(uid, component);
+ }
+
+ private void OnConsoleParentChanged(EntityUid uid, AtmosAlertsComputerComponent component, EntParentChangedMessage args)
+ {
+ InitalizeConsole(uid, component);
+ }
+
+ private void OnFocusChangedMessage(EntityUid uid, AtmosAlertsComputerComponent component, AtmosAlertsComputerFocusChangeMessage args)
+ {
+ component.FocusDevice = args.FocusDevice;
+ }
+
+ private void OnGridSplit(ref GridSplitEvent args)
+ {
+ // Collect grids
+ var allGrids = args.NewGrids.ToList();
+
+ if (!allGrids.Contains(args.Grid))
+ allGrids.Add(args.Grid);
+
+ // Update atmos monitoring consoles that stand upon an updated grid
+ var query = AllEntityQuery();
+ while (query.MoveNext(out var ent, out var entConsole, out var entXform))
+ {
+ if (entXform.GridUid == null)
+ continue;
+
+ if (!allGrids.Contains(entXform.GridUid.Value))
+ continue;
+
+ InitalizeConsole(ent, entConsole);
+ }
+ }
+
+ private void OnDeviceAnchorChanged(EntityUid uid, AtmosAlertsDeviceComponent component, AnchorStateChangedEvent args)
+ {
+ var xform = Transform(uid);
+ var gridUid = xform.GridUid;
+
+ if (gridUid == null)
+ return;
+
+ if (!TryGetAtmosDeviceNavMapData(uid, component, xform, gridUid.Value, out var data))
+ return;
+
+ var netEntity = EntityManager.GetNetEntity(uid);
+
+ var query = AllEntityQuery();
+ while (query.MoveNext(out var ent, out var entConsole, out var entXform))
+ {
+ if (gridUid != entXform.GridUid)
+ continue;
+
+ if (args.Anchored)
+ entConsole.AtmosDevices.Add(data.Value);
+
+ else if (!args.Anchored)
+ entConsole.AtmosDevices.RemoveWhere(x => x.NetEntity == netEntity);
+ }
+ }
+
+ #endregion
+
+ public override void Update(float frameTime)
+ {
+ base.Update(frameTime);
+
+ _updateTimer += frameTime;
+
+ if (_updateTimer >= UpdateTime)
+ {
+ _updateTimer -= UpdateTime;
+
+ // Keep a list of UI entries for each gridUid, in case multiple consoles stand on the same grid
+ var airAlarmEntriesForEachGrid = new Dictionary();
+ var fireAlarmEntriesForEachGrid = new Dictionary();
+
+ var query = AllEntityQuery();
+ while (query.MoveNext(out var ent, out var entConsole, out var entXform))
+ {
+ if (entXform?.GridUid == null)
+ continue;
+
+ // Make a list of alarm state data for all the air and fire alarms on the grid
+ if (!airAlarmEntriesForEachGrid.TryGetValue(entXform.GridUid.Value, out var airAlarmEntries))
+ {
+ airAlarmEntries = GetAlarmStateData(entXform.GridUid.Value, AtmosAlertsComputerGroup.AirAlarm).ToArray();
+ airAlarmEntriesForEachGrid[entXform.GridUid.Value] = airAlarmEntries;
+ }
+
+ if (!fireAlarmEntriesForEachGrid.TryGetValue(entXform.GridUid.Value, out var fireAlarmEntries))
+ {
+ fireAlarmEntries = GetAlarmStateData(entXform.GridUid.Value, AtmosAlertsComputerGroup.FireAlarm).ToArray();
+ fireAlarmEntriesForEachGrid[entXform.GridUid.Value] = fireAlarmEntries;
+ }
+
+ // Determine the highest level of alert for the console (based on non-silenced alarms)
+ var highestAlert = AtmosAlarmType.Invalid;
+
+ foreach (var entry in airAlarmEntries)
+ {
+ if (entry.AlarmState > highestAlert && !entConsole.SilencedDevices.Contains(entry.NetEntity))
+ highestAlert = entry.AlarmState;
+ }
+
+ foreach (var entry in fireAlarmEntries)
+ {
+ if (entry.AlarmState > highestAlert && !entConsole.SilencedDevices.Contains(entry.NetEntity))
+ highestAlert = entry.AlarmState;
+ }
+
+ // Update the appearance of the console based on the highest recorded level of alert
+ if (TryComp(ent, out var entAppearance))
+ _appearance.SetData(ent, AtmosAlertsComputerVisuals.ComputerLayerScreen, (int) highestAlert, entAppearance);
+
+ // If the console UI is open, send UI data to each subscribed session
+ UpdateUIState(ent, airAlarmEntries, fireAlarmEntries, entConsole, entXform);
+ }
+ }
+ }
+
+ public void UpdateUIState
+ (EntityUid uid,
+ AtmosAlertsComputerEntry[] airAlarmStateData,
+ AtmosAlertsComputerEntry[] fireAlarmStateData,
+ AtmosAlertsComputerComponent component,
+ TransformComponent xform)
+ {
+ if (!_uiSystem.IsUiOpen(uid, AtmosAlertsComputerUiKey.Key))
+ return;
+
+ var gridUid = xform.GridUid!.Value;
+
+ if (!HasComp(gridUid))
+ return;
+
+ // The grid must have a NavMapComponent to visualize the map in the UI
+ EnsureComp(gridUid);
+
+ // Gathering remaining data to be send to the client
+ var focusAlarmData = GetFocusAlarmData(uid, GetEntity(component.FocusDevice), gridUid);
+
+ // Set the UI state
+ _uiSystem.TrySetUiState(uid, AtmosAlertsComputerUiKey.Key,
+ new AtmosAlertsComputerBoundInterfaceState(airAlarmStateData, fireAlarmStateData, focusAlarmData));
+ }
+
+ private List GetAlarmStateData(EntityUid gridUid, AtmosAlertsComputerGroup group)
+ {
+ var alarmStateData = new List();
+
+ var queryAlarms = AllEntityQuery();
+ while (queryAlarms.MoveNext(out var ent, out var entDevice, out var entAtmosAlarmable, out var entDeviceNetwork, out var entXform))
+ {
+ if (entXform.GridUid != gridUid)
+ continue;
+
+ if (!entXform.Anchored)
+ continue;
+
+ if (entDevice.Group != group)
+ continue;
+
+ // If emagged, change the alarm type to normal
+ var alarmState = (entAtmosAlarmable.LastAlarmState == AtmosAlarmType.Emagged) ? AtmosAlarmType.Normal : entAtmosAlarmable.LastAlarmState;
+
+ // Unpowered alarms can't sound
+ if (TryComp(ent, out var entAPCPower) && !entAPCPower.Powered)
+ alarmState = AtmosAlarmType.Invalid;
+
+ var entry = new AtmosAlertsComputerEntry
+ (GetNetEntity(ent),
+ GetNetCoordinates(entXform.Coordinates),
+ entDevice.Group,
+ alarmState,
+ MetaData(ent).EntityName,
+ entDeviceNetwork.Address);
+
+ alarmStateData.Add(entry);
+ }
+
+ return alarmStateData;
+ }
+
+ private AtmosAlertsFocusDeviceData? GetFocusAlarmData(EntityUid uid, EntityUid? focusDevice, EntityUid gridUid)
+ {
+ if (focusDevice == null)
+ return null;
+
+ var focusDeviceXform = Transform(focusDevice.Value);
+
+ if (!focusDeviceXform.Anchored ||
+ focusDeviceXform.GridUid != gridUid ||
+ !TryComp(focusDevice.Value, out var focusDeviceAirAlarm))
+ {
+ return null;
+ }
+
+ // Force update the sensors attached to the alarm
+ if (!_uiSystem.IsUiOpen(focusDevice.Value, SharedAirAlarmInterfaceKey.Key))
+ {
+ _atmosDevNet.Register(focusDevice.Value, null);
+ _atmosDevNet.Sync(focusDevice.Value, null);
+
+ foreach ((var address, var _) in focusDeviceAirAlarm.SensorData)
+ _atmosDevNet.Register(uid, null);
+ }
+
+ // Get the sensor data
+ var temperatureData = (_airAlarmSystem.CalculateTemperatureAverage(focusDeviceAirAlarm), AtmosAlarmType.Normal);
+ var pressureData = (_airAlarmSystem.CalculatePressureAverage(focusDeviceAirAlarm), AtmosAlarmType.Normal);
+ var gasData = new Dictionary();
+
+ foreach ((var address, var sensorData) in focusDeviceAirAlarm.SensorData)
+ {
+ if (sensorData.TemperatureThreshold.CheckThreshold(sensorData.Temperature, out var temperatureState) &&
+ (int) temperatureState > (int) temperatureData.Item2)
+ {
+ temperatureData = (temperatureData.Item1, temperatureState);
+ }
+
+ if (sensorData.PressureThreshold.CheckThreshold(sensorData.Pressure, out var pressureState) &&
+ (int) pressureState > (int) pressureData.Item2)
+ {
+ pressureData = (pressureData.Item1, pressureState);
+ }
+
+ if (focusDeviceAirAlarm.SensorData.Sum(g => g.Value.TotalMoles) > 1e-8)
+ {
+ foreach ((var gas, var threshold) in sensorData.GasThresholds)
+ {
+ if (!gasData.ContainsKey(gas))
+ {
+ float mol = _airAlarmSystem.CalculateGasMolarConcentrationAverage(focusDeviceAirAlarm, gas, out var percentage);
+
+ if (mol < 1e-8)
+ continue;
+
+ gasData[gas] = (mol, percentage, AtmosAlarmType.Normal);
+ }
+
+ if (threshold.CheckThreshold(gasData[gas].Item2, out var gasState) &&
+ (int) gasState > (int) gasData[gas].Item3)
+ {
+ gasData[gas] = (gasData[gas].Item1, gasData[gas].Item2, gasState);
+ }
+ }
+ }
+ }
+
+ return new AtmosAlertsFocusDeviceData(GetNetEntity(focusDevice.Value), temperatureData, pressureData, gasData);
+ }
+
+ private HashSet GetAllAtmosDeviceNavMapData(EntityUid gridUid)
+ {
+ var atmosDeviceNavMapData = new HashSet();
+
+ var query = AllEntityQuery();
+ while (query.MoveNext(out var ent, out var entComponent, out var entXform))
+ {
+ if (TryGetAtmosDeviceNavMapData(ent, entComponent, entXform, gridUid, out var data))
+ atmosDeviceNavMapData.Add(data.Value);
+ }
+
+ return atmosDeviceNavMapData;
+ }
+
+ private bool TryGetAtmosDeviceNavMapData
+ (EntityUid uid,
+ AtmosAlertsDeviceComponent component,
+ TransformComponent xform,
+ EntityUid gridUid,
+ [NotNullWhen(true)] out AtmosAlertsDeviceNavMapData? output)
+ {
+ output = null;
+
+ if (xform.GridUid != gridUid)
+ return false;
+
+ if (!xform.Anchored)
+ return false;
+
+ output = new AtmosAlertsDeviceNavMapData(GetNetEntity(uid), GetNetCoordinates(xform.Coordinates), component.Group);
+
+ return true;
+ }
+
+ private void InitalizeConsole(EntityUid uid, AtmosAlertsComputerComponent component)
+ {
+ var xform = Transform(uid);
+
+ if (xform.GridUid == null)
+ return;
+
+ var grid = xform.GridUid.Value;
+ component.AtmosDevices = GetAllAtmosDeviceNavMapData(grid);
+
+ Dirty(uid, component);
+ }
+}
diff --git a/Content.Server/Atmos/Monitor/Systems/AirAlarmSystem.cs b/Content.Server/Atmos/Monitor/Systems/AirAlarmSystem.cs
index 2922d0796a..240f21ad42 100644
--- a/Content.Server/Atmos/Monitor/Systems/AirAlarmSystem.cs
+++ b/Content.Server/Atmos/Monitor/Systems/AirAlarmSystem.cs
@@ -593,6 +593,21 @@ public float CalculateTemperatureAverage(AirAlarmComponent alarm)
: 0f;
}
+ public float CalculateGasMolarConcentrationAverage(AirAlarmComponent alarm, Gas gas, out float percentage)
+ {
+ percentage = 0f;
+
+ var data = alarm.SensorData.Values.SelectMany(v => v.Gases.Where(g => g.Key == gas));
+
+ if (data.Count() == 0)
+ return 0f;
+
+ var averageMol = data.Select(kvp => kvp.Value).Average();
+ percentage = data.Select(kvp => kvp.Value).Sum() / alarm.SensorData.Values.Select(v => v.TotalMoles).Sum();
+
+ return averageMol;
+ }
+
public void UpdateUI(EntityUid uid, AirAlarmComponent? alarm = null, DeviceNetworkComponent? devNet = null, AtmosAlarmableComponent? alarmable = null)
{
if (!Resolve(uid, ref alarm, ref devNet, ref alarmable))
diff --git a/Content.Server/NPC/Components/NPCJukeComponent.cs b/Content.Server/NPC/Components/NPCJukeComponent.cs
index 2c4136c24b..768feeca6f 100644
--- a/Content.Server/NPC/Components/NPCJukeComponent.cs
+++ b/Content.Server/NPC/Components/NPCJukeComponent.cs
@@ -1,4 +1,3 @@
-using Content.Server.NPC.HTN.PrimitiveTasks.Operators.Combat;
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom;
namespace Content.Server.NPC.Components;
@@ -6,17 +5,20 @@ namespace Content.Server.NPC.Components;
[RegisterComponent, AutoGenerateComponentPause]
public sealed partial class NPCJukeComponent : Component
{
- [DataField("jukeType")]
+ [DataField]
public JukeType JukeType = JukeType.Away;
- [DataField("jukeDuration")]
+ [DataField]
public float JukeDuration = 0.5f;
- [DataField("nextJuke", customTypeSerializer:typeof(TimeOffsetSerializer))]
+ [DataField]
+ public float JukeCooldown = 3f;
+
+ [DataField(customTypeSerializer: typeof(TimeOffsetSerializer))]
[AutoPausedField]
public TimeSpan NextJuke;
- [DataField("targetTile")]
+ [DataField]
public Vector2i? TargetTile;
}
diff --git a/Content.Server/NPC/HTN/PrimitiveTasks/Operators/Combat/JukeOperator.cs b/Content.Server/NPC/HTN/PrimitiveTasks/Operators/Combat/JukeOperator.cs
index 02a3b08510..68029f5a4c 100644
--- a/Content.Server/NPC/HTN/PrimitiveTasks/Operators/Combat/JukeOperator.cs
+++ b/Content.Server/NPC/HTN/PrimitiveTasks/Operators/Combat/JukeOperator.cs
@@ -6,17 +6,31 @@ public sealed partial class JukeOperator : HTNOperator, IHtnConditionalShutdown
{
[Dependency] private readonly IEntityManager _entManager = default!;
- [DataField("jukeType")]
+ [DataField]
public JukeType JukeType = JukeType.AdjacentTile;
- [DataField("shutdownState")]
+ [DataField]
public HTNPlanState ShutdownState { get; private set; } = HTNPlanState.PlanFinished;
+ ///
+ /// Controls how long(in seconds) the NPC will move while juking.
+ ///
+ [DataField]
+ public float JukeDuration = 0.5f;
+
+ ///
+ /// Controls how often (in seconds) an NPC will try to juke.
+ ///
+ [DataField]
+ public float JukeCooldown = 3f;
+
public override void Startup(NPCBlackboard blackboard)
{
base.Startup(blackboard);
var juke = _entManager.EnsureComponent(blackboard.GetValue(NPCBlackboard.Owner));
juke.JukeType = JukeType;
+ juke.JukeDuration = JukeDuration;
+ juke.JukeCooldown = JukeCooldown;
}
public override HTNOperatorStatus Update(NPCBlackboard blackboard, float frameTime)
diff --git a/Content.Server/NPC/Systems/NPCJukeSystem.cs b/Content.Server/NPC/Systems/NPCJukeSystem.cs
index da9fa1f761..5a724762ef 100644
--- a/Content.Server/NPC/Systems/NPCJukeSystem.cs
+++ b/Content.Server/NPC/Systems/NPCJukeSystem.cs
@@ -3,6 +3,7 @@
using Content.Server.NPC.Events;
using Content.Server.NPC.HTN.PrimitiveTasks.Operators.Combat;
using Content.Server.Weapons.Melee;
+using Content.Shared.Coordinates.Helpers;
using Content.Shared.NPC;
using Content.Shared.Weapons.Melee;
using Robust.Shared.Collections;
@@ -38,22 +39,19 @@ public override void Initialize()
private void OnJukeSteering(EntityUid uid, NPCJukeComponent component, ref NPCSteeringEvent args)
{
- if (component.JukeType == JukeType.AdjacentTile)
+ if (_timing.CurTime < component.NextJuke)
{
- if (_npcRangedQuery.TryGetComponent(uid, out var ranged) &&
- ranged.Status == CombatStatus.NotInSight)
- {
- component.TargetTile = null;
- return;
- }
+ component.TargetTile = null;
+ return;
+ }
- if (_timing.CurTime < component.NextJuke)
- {
- component.TargetTile = null;
- return;
- }
+ component.NextJuke = _timing.CurTime + TimeSpan.FromSeconds(component.JukeCooldown);
- if (!TryComp(args.Transform.GridUid, out var grid))
+ if (component.JukeType == JukeType.AdjacentTile)
+ {
+ if (_npcRangedQuery.TryGetComponent(uid, out var ranged)
+ && ranged.Status is CombatStatus.NotInSight
+ || !TryComp(args.Transform.GridUid, out var grid))
{
component.TargetTile = null;
return;
@@ -107,12 +105,11 @@ private void OnJukeSteering(EntityUid uid, NPCJukeComponent component, ref NPCSt
var elapsed = _timing.CurTime - component.NextJuke;
- // Finished juke, reset timer.
- if (elapsed.TotalSeconds > component.JukeDuration ||
- currentTile == component.TargetTile)
+ // Finished juke.
+ if (elapsed.TotalSeconds > component.JukeDuration
+ || currentTile == component.TargetTile)
{
component.TargetTile = null;
- component.NextJuke = _timing.CurTime + TimeSpan.FromSeconds(component.JukeDuration);
return;
}
@@ -155,9 +152,7 @@ private void OnJukeSteering(EntityUid uid, NPCJukeComponent component, ref NPCSt
var obstacleDirection = _transform.GetWorldPosition(melee.Target) - args.WorldPosition;
if (obstacleDirection == Vector2.Zero)
- {
obstacleDirection = _random.NextVector2();
- }
// If they're moving away then pursue anyway.
// If just hit then always back up a bit.
diff --git a/Content.Server/Nyanotrasen/Objectives/Components/BecomePsionicConditionComponent.cs b/Content.Server/Nyanotrasen/Objectives/Components/BecomePsionicConditionComponent.cs
deleted file mode 100644
index 3b677bab2d..0000000000
--- a/Content.Server/Nyanotrasen/Objectives/Components/BecomePsionicConditionComponent.cs
+++ /dev/null
@@ -1,11 +0,0 @@
-using Content.Server.Objectives.Systems;
-
-namespace Content.Server.Objectives.Components;
-
-///
-/// Requires that the player dies to be complete.
-///
-[RegisterComponent, Access(typeof(BecomePsionicConditionSystem))]
-public sealed partial class BecomePsionicConditionComponent : Component
-{
-}
\ No newline at end of file
diff --git a/Content.Server/Nyanotrasen/Objectives/Systems/BecomePsionicConditionSystem.cs b/Content.Server/Nyanotrasen/Objectives/Systems/BecomePsionicConditionSystem.cs
deleted file mode 100644
index d090c320a4..0000000000
--- a/Content.Server/Nyanotrasen/Objectives/Systems/BecomePsionicConditionSystem.cs
+++ /dev/null
@@ -1,32 +0,0 @@
-using Content.Shared.Abilities.Psionics;
-using Content.Server.Objectives.Components;
-using Content.Shared.Mind;
-using Content.Shared.Objectives.Components;
-
-namespace Content.Server.Objectives.Systems
-{
- public sealed class BecomePsionicConditionSystem : EntitySystem
- {
- private EntityQuery _metaQuery;
-
- public override void Initialize()
- {
- base.Initialize();
-
- SubscribeLocalEvent(OnGetProgress);
- }
-
- private void OnGetProgress(EntityUid uid, BecomePsionicConditionComponent comp, ref ObjectiveGetProgressEvent args)
- {
- args.Progress = GetProgress(args.Mind);
- }
-
- private float GetProgress(MindComponent mind)
- {
- var entMan = IoCManager.Resolve();
- if (HasComp(mind.CurrentEntity))
- return 1;
- return 0;
- }
- }
-}
diff --git a/Content.Server/RandomMetadata/RandomMetadataSystem.cs b/Content.Server/RandomMetadata/RandomMetadataSystem.cs
index 3a80230ce5..d2453b0083 100644
--- a/Content.Server/RandomMetadata/RandomMetadataSystem.cs
+++ b/Content.Server/RandomMetadata/RandomMetadataSystem.cs
@@ -48,9 +48,15 @@ public string GetRandomFromSegments(List segments, string? separator)
foreach (var segment in segments)
{
if (_prototype.TryIndex(segment, out var proto))
- outputSegments.Add(Loc.GetString(_random.Pick(proto.Values)));
+ {
+ var random = _random.Pick(proto.Values);
+ if (Loc.TryGetString(random, out var localizedSegment))
+ outputSegments.Add(localizedSegment);
+ else
+ outputSegments.Add(random);
+ }
else if (Loc.TryGetString(segment, out var localizedSegment))
- outputSegments.Add(Loc.GetString(segment));
+ outputSegments.Add(localizedSegment);
else
outputSegments.Add(segment);
}
diff --git a/Content.Server/Traits/Assorted/ForeignerTraitComponent.cs b/Content.Server/Traits/Assorted/ForeignerTraitComponent.cs
index 756f44e742..a35972f1c8 100644
--- a/Content.Server/Traits/Assorted/ForeignerTraitComponent.cs
+++ b/Content.Server/Traits/Assorted/ForeignerTraitComponent.cs
@@ -13,7 +13,7 @@ public sealed partial class ForeignerTraitComponent : Component
{
///
/// The "base" language that is to be removed and substituted with a translator.
- /// By default, equals to the fallback language, which is GalacticCommon.
+ /// By default, equals to the fallback language, which is TauCetiBasic.
///
[DataField]
public ProtoId BaseLanguage = SharedLanguageSystem.FallbackLanguagePrototype;
diff --git a/Content.Shared/Atmos/Consoles/Components/AtmosAlertsComputerComponent.cs b/Content.Shared/Atmos/Consoles/Components/AtmosAlertsComputerComponent.cs
new file mode 100644
index 0000000000..d64c8907af
--- /dev/null
+++ b/Content.Shared/Atmos/Consoles/Components/AtmosAlertsComputerComponent.cs
@@ -0,0 +1,235 @@
+using Content.Shared.Atmos.Consoles;
+using Content.Shared.Atmos.Monitor;
+using Robust.Shared.GameStates;
+using Robust.Shared.Map;
+using Robust.Shared.Serialization;
+
+namespace Content.Shared.Atmos.Components;
+
+[RegisterComponent, NetworkedComponent, AutoGenerateComponentState]
+[Access(typeof(SharedAtmosAlertsComputerSystem))]
+public sealed partial class AtmosAlertsComputerComponent : Component
+{
+ ///
+ /// The current entity of interest (selected via the console UI)
+ ///
+ [ViewVariables]
+ public NetEntity? FocusDevice;
+
+ ///
+ /// A list of all the atmos devices that will be used to populate the nav map
+ ///
+ [ViewVariables, AutoNetworkedField]
+ public HashSet AtmosDevices = new();
+
+ ///
+ /// A list of all the air alarms that have had their alerts silenced on this particular console
+ ///
+ [ViewVariables, AutoNetworkedField]
+ public HashSet SilencedDevices = new();
+}
+
+[Serializable, NetSerializable]
+public struct AtmosAlertsDeviceNavMapData
+{
+ ///
+ /// The entity in question
+ ///
+ public NetEntity NetEntity;
+
+ ///
+ /// Location of the entity
+ ///
+ public NetCoordinates NetCoordinates;
+
+ ///
+ /// Used to determine what map icons to use
+ ///
+ public AtmosAlertsComputerGroup Group;
+
+ ///
+ /// Populate the atmos monitoring console nav map with a single entity
+ ///
+ public AtmosAlertsDeviceNavMapData(NetEntity netEntity, NetCoordinates netCoordinates, AtmosAlertsComputerGroup group)
+ {
+ NetEntity = netEntity;
+ NetCoordinates = netCoordinates;
+ Group = group;
+ }
+}
+
+[Serializable, NetSerializable]
+public struct AtmosAlertsFocusDeviceData
+{
+ ///
+ /// Focus entity
+ ///
+ public NetEntity NetEntity;
+
+ ///
+ /// Temperature (K) and related alert state
+ ///
+ public (float, AtmosAlarmType) TemperatureData;
+
+ ///
+ /// Pressure (kPA) and related alert state
+ ///
+ public (float, AtmosAlarmType) PressureData;
+
+ ///
+ /// Moles, percentage, and related alert state, for all detected gases
+ ///
+ public Dictionary GasData;
+
+ ///
+ /// Populates the atmos monitoring console focus entry with atmospheric data
+ ///
+ public AtmosAlertsFocusDeviceData
+ (NetEntity netEntity,
+ (float, AtmosAlarmType) temperatureData,
+ (float, AtmosAlarmType) pressureData,
+ Dictionary gasData)
+ {
+ NetEntity = netEntity;
+ TemperatureData = temperatureData;
+ PressureData = pressureData;
+ GasData = gasData;
+ }
+}
+
+[Serializable, NetSerializable]
+public sealed class AtmosAlertsComputerBoundInterfaceState : BoundUserInterfaceState
+{
+ ///
+ /// A list of all air alarms
+ ///
+ public AtmosAlertsComputerEntry[] AirAlarms;
+
+ ///
+ /// A list of all fire alarms
+ ///
+ public AtmosAlertsComputerEntry[] FireAlarms;
+
+ ///
+ /// Data for the UI focus (if applicable)
+ ///
+ public AtmosAlertsFocusDeviceData? FocusData;
+
+ ///
+ /// Sends data from the server to the client to populate the atmos monitoring console UI
+ ///
+ public AtmosAlertsComputerBoundInterfaceState(AtmosAlertsComputerEntry[] airAlarms, AtmosAlertsComputerEntry[] fireAlarms, AtmosAlertsFocusDeviceData? focusData)
+ {
+ AirAlarms = airAlarms;
+ FireAlarms = fireAlarms;
+ FocusData = focusData;
+ }
+}
+
+[Serializable, NetSerializable]
+public struct AtmosAlertsComputerEntry
+{
+ ///
+ /// The entity in question
+ ///
+ public NetEntity NetEntity;
+
+ ///
+ /// Location of the entity
+ ///
+ public NetCoordinates Coordinates;
+
+ ///
+ /// The type of entity
+ ///
+ public AtmosAlertsComputerGroup Group;
+
+ ///
+ /// Current alarm state
+ ///
+ public AtmosAlarmType AlarmState;
+
+ ///
+ /// Localised device name
+ ///
+ public string EntityName;
+
+ ///
+ /// Device network address
+ ///
+ public string Address;
+
+ ///
+ /// Used to populate the atmos monitoring console UI with data from a single air alarm
+ ///
+ public AtmosAlertsComputerEntry
+ (NetEntity entity,
+ NetCoordinates coordinates,
+ AtmosAlertsComputerGroup group,
+ AtmosAlarmType alarmState,
+ string entityName,
+ string address)
+ {
+ NetEntity = entity;
+ Coordinates = coordinates;
+ Group = group;
+ AlarmState = alarmState;
+ EntityName = entityName;
+ Address = address;
+ }
+}
+
+[Serializable, NetSerializable]
+public sealed class AtmosAlertsComputerFocusChangeMessage : BoundUserInterfaceMessage
+{
+ public NetEntity? FocusDevice;
+
+ ///
+ /// Used to inform the server that the specified focus for the atmos monitoring console has been changed by the client
+ ///
+ public AtmosAlertsComputerFocusChangeMessage(NetEntity? focusDevice)
+ {
+ FocusDevice = focusDevice;
+ }
+}
+
+[Serializable, NetSerializable]
+public sealed class AtmosAlertsComputerDeviceSilencedMessage : BoundUserInterfaceMessage
+{
+ public NetEntity AtmosDevice;
+ public bool SilenceDevice = true;
+
+ ///
+ /// Used to inform the server that the client has silenced alerts from the specified device to this atmos monitoring console
+ ///
+ public AtmosAlertsComputerDeviceSilencedMessage(NetEntity atmosDevice, bool silenceDevice = true)
+ {
+ AtmosDevice = atmosDevice;
+ SilenceDevice = silenceDevice;
+ }
+}
+
+///
+/// List of all the different atmos device groups
+///
+public enum AtmosAlertsComputerGroup
+{
+ Invalid,
+ AirAlarm,
+ FireAlarm,
+}
+
+[NetSerializable, Serializable]
+public enum AtmosAlertsComputerVisuals
+{
+ ComputerLayerScreen,
+}
+
+///
+/// UI key associated with the atmos monitoring console
+///
+[Serializable, NetSerializable]
+public enum AtmosAlertsComputerUiKey
+{
+ Key
+}
diff --git a/Content.Shared/Atmos/Consoles/Components/AtmosAlertsDeviceComponent.cs b/Content.Shared/Atmos/Consoles/Components/AtmosAlertsDeviceComponent.cs
new file mode 100644
index 0000000000..881d60b084
--- /dev/null
+++ b/Content.Shared/Atmos/Consoles/Components/AtmosAlertsDeviceComponent.cs
@@ -0,0 +1,14 @@
+using Robust.Shared.GameStates;
+
+namespace Content.Shared.Atmos.Components;
+
+[RegisterComponent, NetworkedComponent]
+[Access([])]
+public sealed partial class AtmosAlertsDeviceComponent : Component
+{
+ ///
+ /// The group that the entity belongs to
+ ///
+ [DataField, ViewVariables]
+ public AtmosAlertsComputerGroup Group;
+}
diff --git a/Content.Shared/Atmos/Consoles/SharedAtmosAlertsComputerSystem.cs b/Content.Shared/Atmos/Consoles/SharedAtmosAlertsComputerSystem.cs
new file mode 100644
index 0000000000..7e2b2b0467
--- /dev/null
+++ b/Content.Shared/Atmos/Consoles/SharedAtmosAlertsComputerSystem.cs
@@ -0,0 +1,24 @@
+using Content.Shared.Atmos.Components;
+
+namespace Content.Shared.Atmos.Consoles;
+
+public abstract partial class SharedAtmosAlertsComputerSystem : EntitySystem
+{
+ public override void Initialize()
+ {
+ base.Initialize();
+
+ SubscribeLocalEvent(OnDeviceSilencedMessage);
+ }
+
+ private void OnDeviceSilencedMessage(EntityUid uid, AtmosAlertsComputerComponent component, AtmosAlertsComputerDeviceSilencedMessage args)
+ {
+ if (args.SilenceDevice)
+ component.SilencedDevices.Add(args.AtmosDevice);
+
+ else
+ component.SilencedDevices.Remove(args.AtmosDevice);
+
+ Dirty(uid, component);
+ }
+}
diff --git a/Content.Shared/Language/Systems/SharedLanguageSystem.cs b/Content.Shared/Language/Systems/SharedLanguageSystem.cs
index 0a03086ebe..d9e882147c 100644
--- a/Content.Shared/Language/Systems/SharedLanguageSystem.cs
+++ b/Content.Shared/Language/Systems/SharedLanguageSystem.cs
@@ -10,7 +10,7 @@ public abstract class SharedLanguageSystem : EntitySystem
/// The language used as a fallback in cases where an entity suddenly becomes a language speaker (e.g. the usage of make-sentient)
///
[ValidatePrototypeId]
- public static readonly string FallbackLanguagePrototype = "GalacticCommon";
+ public static readonly string FallbackLanguagePrototype = "TauCetiBasic";
///
/// The language whose speakers are assumed to understand and speak every language. Should never be added directly.
diff --git a/Content.Shared/Movement/Pulling/Components/PullableComponent.cs b/Content.Shared/Movement/Pulling/Components/PullableComponent.cs
index db889e7e3b..01ce0efaae 100644
--- a/Content.Shared/Movement/Pulling/Components/PullableComponent.cs
+++ b/Content.Shared/Movement/Pulling/Components/PullableComponent.cs
@@ -36,4 +36,11 @@ public sealed partial class PullableComponent : Component
[Access(typeof(Systems.PullingSystem), Other = AccessPermissions.ReadExecute)]
[AutoNetworkedField, DataField]
public bool PrevFixedRotation;
+
+ ///
+ /// Whether the entity is currently being actively pushed by the puller.
+ /// If true, the entity will be able to enter disposals upon colliding with them, and the like.
+ ///
+ [DataField, AutoNetworkedField]
+ public bool BeingActivelyPushed = false;
}
diff --git a/Content.Shared/Movement/Pulling/Components/PullerComponent.cs b/Content.Shared/Movement/Pulling/Components/PullerComponent.cs
index 1fc9b731bd..c13baa28ef 100644
--- a/Content.Shared/Movement/Pulling/Components/PullerComponent.cs
+++ b/Content.Shared/Movement/Pulling/Components/PullerComponent.cs
@@ -1,5 +1,6 @@
using Content.Shared.Movement.Pulling.Systems;
using Robust.Shared.GameStates;
+using Robust.Shared.Map;
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom;
namespace Content.Shared.Movement.Pulling.Components;
@@ -11,16 +12,17 @@ namespace Content.Shared.Movement.Pulling.Components;
[Access(typeof(PullingSystem))]
public sealed partial class PullerComponent : Component
{
- // My raiding guild
///
- /// Next time the puller can throw what is being pulled.
- /// Used to avoid spamming it for infinite spin + velocity.
+ /// Next time the puller change where they are pulling the target towards.
///
[DataField(customTypeSerializer: typeof(TimeOffsetSerializer)), AutoNetworkedField]
- public TimeSpan NextThrow;
+ public TimeSpan NextPushTargetChange;
+
+ [DataField, AutoNetworkedField]
+ public TimeSpan NextPushStop;
[DataField]
- public TimeSpan ThrowCooldown = TimeSpan.FromSeconds(1);
+ public TimeSpan PushChangeCooldown = TimeSpan.FromSeconds(0.1f), PushDuration = TimeSpan.FromSeconds(2f);
// Before changing how this is updated, please see SharedPullerSystem.RefreshMovementSpeed
public float WalkSpeedModifier => Pulling == default ? 1.0f : 0.95f;
@@ -28,14 +30,38 @@ public sealed partial class PullerComponent : Component
public float SprintSpeedModifier => Pulling == default ? 1.0f : 0.95f;
///
- /// Entity currently being pulled if applicable.
+ /// Entity currently being pulled/pushed if applicable.
///
[AutoNetworkedField, DataField]
public EntityUid? Pulling;
+ ///
+ /// The position the entity is currently being pulled towards.
+ ///
+ [AutoNetworkedField, DataField]
+ public EntityCoordinates? PushingTowards;
+
///
/// Does this entity need hands to be able to pull something?
///
[DataField]
public bool NeedsHands = true;
+
+ ///
+ /// The maximum acceleration of pushing, in meters per second squared.
+ ///
+ [DataField]
+ public float PushAcceleration = 0.3f;
+
+ ///
+ /// The maximum speed to which the pulled entity may be accelerated relative to the push direction, in meters per second.
+ ///
+ [DataField]
+ public float MaxPushSpeed = 1.2f;
+
+ ///
+ /// The maximum distance between the puller and the point towards which the puller may attempt to pull it, in meters.
+ ///
+ [DataField]
+ public float MaxPushRange = 2f;
}
diff --git a/Content.Shared/Movement/Pulling/Systems/PullingSystem.cs b/Content.Shared/Movement/Pulling/Systems/PullingSystem.cs
index 3c265d5a02..e6acabc33c 100644
--- a/Content.Shared/Movement/Pulling/Systems/PullingSystem.cs
+++ b/Content.Shared/Movement/Pulling/Systems/PullingSystem.cs
@@ -8,16 +8,19 @@
using Content.Shared.Hands.EntitySystems;
using Content.Shared.Input;
using Content.Shared.Interaction;
+using Content.Shared.Movement.Components;
using Content.Shared.Movement.Events;
using Content.Shared.Movement.Pulling.Components;
using Content.Shared.Movement.Pulling.Events;
using Content.Shared.Movement.Systems;
+using Content.Shared.Projectiles;
using Content.Shared.Pulling.Events;
using Content.Shared.Throwing;
using Content.Shared.Verbs;
using Robust.Shared.Containers;
using Robust.Shared.Input.Binding;
using Robust.Shared.Map;
+using Robust.Shared.Network;
using Robust.Shared.Physics;
using Robust.Shared.Physics.Components;
using Robust.Shared.Physics.Events;
@@ -34,6 +37,7 @@ public sealed class PullingSystem : EntitySystem
{
[Dependency] private readonly IGameTiming _timing = default!;
[Dependency] private readonly ISharedAdminLogManager _adminLogger = default!;
+ [Dependency] private readonly INetManager _net = default!;
[Dependency] private readonly ActionBlockerSystem _blocker = default!;
[Dependency] private readonly AlertsSystem _alertsSystem = default!;
[Dependency] private readonly MovementSpeedModifierSystem _modifierSystem = default!;
@@ -43,7 +47,7 @@ public sealed class PullingSystem : EntitySystem
[Dependency] private readonly SharedInteractionSystem _interaction = default!;
[Dependency] private readonly SharedPhysicsSystem _physics = default!;
[Dependency] private readonly SharedTransformSystem _xformSys = default!;
- [Dependency] private readonly ThrowingSystem _throwing = default!;
+ [Dependency] private readonly ThrownItemSystem _thrownItem = default!;
public override void Initialize()
{
@@ -57,7 +61,9 @@ public override void Initialize()
SubscribeLocalEvent(OnJointRemoved);
SubscribeLocalEvent>(AddPullVerbs);
SubscribeLocalEvent(OnPullableContainerInsert);
+ SubscribeLocalEvent(OnPullableCollide);
+ SubscribeLocalEvent(OnPullerMoveInput);
SubscribeLocalEvent(OnPullerContainerInsert);
SubscribeLocalEvent(OnPullerUnpaused);
SubscribeLocalEvent(OnVirtualItemDeleted);
@@ -69,6 +75,86 @@ public override void Initialize()
.Register();
}
+ public override void Shutdown()
+ {
+ base.Shutdown();
+ CommandBinds.Unregister();
+ }
+
+ public override void Update(float frameTime)
+ {
+ if (_net.IsClient) // Client cannot predict this
+ return;
+
+ var query = EntityQueryEnumerator();
+ while (query.MoveNext(out var puller, out var pullerComp, out var pullerPhysics, out var pullerXForm))
+ {
+ // If not pulling, reset the pushing cooldowns and exit
+ if (pullerComp.Pulling is not { } pulled || !TryComp(pulled, out var pulledComp))
+ {
+ pullerComp.PushingTowards = null;
+ pullerComp.NextPushTargetChange = TimeSpan.Zero;
+ continue;
+ }
+
+ pulledComp.BeingActivelyPushed = false; // Temporarily set to false; if the checks below pass, it will be set to true again
+
+ // If pulling but the pullee is invalid or is on a different map, stop pulling
+ var pulledXForm = Transform(pulled);
+ if (!TryComp(pulled, out var pulledPhysics)
+ || pulledPhysics.BodyType == BodyType.Static
+ || pulledXForm.MapUid != pullerXForm.MapUid)
+ {
+ StopPulling(pulled, pulledComp);
+ continue;
+ }
+
+ if (pullerComp.PushingTowards is null)
+ continue;
+
+ // If pushing but the target position is invalid, or the push action has expired or finished, stop pushing
+ if (pullerComp.NextPushStop < _timing.CurTime
+ || !(pullerComp.PushingTowards.Value.ToMap(EntityManager, _xformSys) is var pushCoordinates)
+ || pushCoordinates.MapId != pulledXForm.MapID)
+ {
+ pullerComp.PushingTowards = null;
+ pullerComp.NextPushTargetChange = TimeSpan.Zero;
+ continue;
+ }
+
+ // Actual force calculation. All the Vector2's below are in map coordinates.
+ var desiredDeltaPos = pushCoordinates.Position - Transform(pulled).Coordinates.ToMapPos(EntityManager, _xformSys);
+ if (desiredDeltaPos.LengthSquared() < 0.1f)
+ {
+ pullerComp.PushingTowards = null;
+ continue;
+ }
+
+ var velocityAndDirectionAngle = new Angle(pulledPhysics.LinearVelocity) - new Angle(desiredDeltaPos);
+ var currentRelativeSpeed = pulledPhysics.LinearVelocity.Length() * (float) Math.Cos(velocityAndDirectionAngle.Theta);
+ var desiredAcceleration = MathF.Max(0f, pullerComp.MaxPushSpeed - currentRelativeSpeed);
+
+ var desiredImpulse = pulledPhysics.Mass * desiredDeltaPos;
+ var maxSourceImpulse = MathF.Min(pullerComp.PushAcceleration, desiredAcceleration) * pullerPhysics.Mass;
+ var actualImpulse = desiredImpulse.LengthSquared() > maxSourceImpulse * maxSourceImpulse ? desiredDeltaPos.Normalized() * maxSourceImpulse : desiredImpulse;
+
+ // Ideally we'd want to apply forces instead of impulses, however...
+ // We cannot use ApplyForce here because it will be cleared on the next physics substep which will render it ultimately useless
+ // The alternative is to run this function on every physics substep, but that is way too expensive for such a minor system
+ _physics.ApplyLinearImpulse(pulled, actualImpulse);
+ _physics.ApplyLinearImpulse(puller, -actualImpulse);
+ pulledComp.BeingActivelyPushed = true;
+ }
+ query.Dispose();
+ }
+
+ private void OnPullerMoveInput(EntityUid uid, PullerComponent component, ref MoveInputEvent args)
+ {
+ // Stop pushing
+ component.PushingTowards = null;
+ component.NextPushStop = TimeSpan.Zero;
+ }
+
private void OnPullerContainerInsert(Entity ent, ref EntGotInsertedIntoContainerMessage args)
{
if (ent.Comp.Pulling == null) return;
@@ -84,15 +170,26 @@ private void OnPullableContainerInsert(Entity ent, ref EntGot
TryStopPull(ent.Owner, ent.Comp);
}
- public override void Shutdown()
+ private void OnPullableCollide(Entity ent, ref StartCollideEvent args)
{
- base.Shutdown();
- CommandBinds.Unregister();
+ if (!ent.Comp.BeingActivelyPushed || args.OtherEntity == ent.Comp.Puller)
+ return;
+
+ // This component isn't actually needed anywhere besides the thrownitemsyste`m itself, so we just fake it
+ var fakeThrown = new ThrownItemComponent()
+ {
+ Owner = ent.Owner,
+ Animate = false,
+ Landed = false,
+ PlayLandSound = false,
+ Thrower = ent.Comp.Puller
+ };
+ _thrownItem.ThrowCollideInteraction(fakeThrown, ent, args.OtherEntity);
}
private void OnPullerUnpaused(EntityUid uid, PullerComponent component, ref EntityUnpausedEvent args)
{
- component.NextThrow += args.PausedTime;
+ component.NextPushTargetChange += args.PausedTime;
}
private void OnVirtualItemDeleted(EntityUid uid, PullerComponent component, VirtualItemDeletedEvent args)
@@ -234,31 +331,22 @@ public bool IsPulled(EntityUid uid, PullableComponent? component = null)
private bool OnRequestMovePulledObject(ICommonSession? session, EntityCoordinates coords, EntityUid uid)
{
- if (session?.AttachedEntity is not { } player ||
- !player.IsValid())
- {
- return false;
- }
-
- if (!TryComp(player, out var pullerComp))
+ if (session?.AttachedEntity is not { } player
+ || !player.IsValid()
+ || !TryComp(player, out var pullerComp))
return false;
var pulled = pullerComp.Pulling;
-
- if (!HasComp(pulled))
- return false;
-
- if (_containerSystem.IsEntityInContainer(player))
+ if (!HasComp(pulled)
+ || _containerSystem.IsEntityInContainer(player)
+ || _timing.CurTime < pullerComp.NextPushTargetChange)
return false;
- // Cooldown buddy
- if (_timing.CurTime < pullerComp.NextThrow)
- return false;
-
- pullerComp.NextThrow = _timing.CurTime + pullerComp.ThrowCooldown;
+ pullerComp.NextPushTargetChange = _timing.CurTime + pullerComp.PushChangeCooldown;
+ pullerComp.NextPushStop = _timing.CurTime + pullerComp.PushDuration;
// Cap the distance
- const float range = 2f;
+ var range = pullerComp.MaxPushRange;
var fromUserCoords = coords.WithEntityId(player, EntityManager);
var userCoords = new EntityCoordinates(player, Vector2.Zero);
@@ -268,8 +356,9 @@ private bool OnRequestMovePulledObject(ICommonSession? session, EntityCoordinate
fromUserCoords = userCoords.Offset(userDirection.Normalized() * range);
}
+ pullerComp.PushingTowards = fromUserCoords;
Dirty(player, pullerComp);
- _throwing.TryThrow(pulled.Value, fromUserCoords, user: player, strength: 4f, animated: false, recoil: false, playSound: false, doSpin: false);
+
return false;
}
diff --git a/Resources/Changelog/Changelog.yml b/Resources/Changelog/Changelog.yml
index 10df4525ab..f4bc13c117 100644
--- a/Resources/Changelog/Changelog.yml
+++ b/Resources/Changelog/Changelog.yml
@@ -6520,3 +6520,59 @@ Entries:
id: 6376
time: '2024-09-20T19:34:46.0000000+00:00'
url: https://github.com/Simple-Station/Einstein-Engines/pull/938
+- author: VMSolidus
+ changes:
+ - type: Tweak
+ message: >-
+ JukeOperator now allows for JukeDuration and JukeCooldown arguments.
+ JukeCooldown is a new feature where enemies must wait an amount of time
+ in seconds equal to the JukeCooldown, before they are allowed to attempt
+ to dodge a melee attack.
+ - type: Tweak
+ message: >-
+ By default, NPCs will only attempt to dodge attacks once every 5
+ seconds.
+ - type: Fix
+ message: >-
+ JukeOperator now performs extremely expensive math 5000 times less
+ often. EXIT CONDITIONS PEOPLE!
+ id: 6377
+ time: '2024-09-20T20:05:31.0000000+00:00'
+ url: https://github.com/Simple-Station/Einstein-Engines/pull/935
+- author: VMSolidus
+ changes:
+ - type: Add
+ message: >-
+ All "Long-arms", Rifles, Light Machine Guns, Shotguns, now require
+ wielding to use.
+ id: 6378
+ time: '2024-09-20T20:35:43.0000000+00:00'
+ url: https://github.com/Simple-Station/Einstein-Engines/pull/913
+- author: zelezniciar
+ changes:
+ - type: Add
+ message: Added Atmospheric Alerts Computer
+ id: 6379
+ time: '2024-09-20T21:46:38.0000000+00:00'
+ url: https://github.com/Simple-Station/Einstein-Engines/pull/922
+- author: VMSolidus
+ changes:
+ - type: Add
+ message: 'A basic Languages menu has been added into the Traits tab. '
+ - type: Add
+ message: >-
+ Tau-Ceti Basic, Tradeband, Freespeak, Elyran Standard, Sol Common, and
+ Sign Language have been added to the Languages tab.
+ id: 6380
+ time: '2024-09-20T21:46:47.0000000+00:00'
+ url: https://github.com/Simple-Station/Einstein-Engines/pull/936
+- author: VMSolidus
+ changes:
+ - type: Remove
+ message: >-
+ Removed the "Become Psionic" traitor objective. It was literally
+ impossible to fail if you took the Latent Psychic trait, and literally
+ impossible to greentext if you didn't.
+ id: 6381
+ time: '2024-09-20T21:47:16.0000000+00:00'
+ url: https://github.com/Simple-Station/Einstein-Engines/pull/940
diff --git a/Resources/Changelog/ChangelogLPP.yml b/Resources/Changelog/ChangelogLPP.yml
index 4b7f00e52f..e1e5e490cc 100644
--- a/Resources/Changelog/ChangelogLPP.yml
+++ b/Resources/Changelog/ChangelogLPP.yml
@@ -586,3 +586,23 @@ Entries:
id: 57
time: '2024-09-20T15:32:35.0000000+00:00'
url: https://github.com/Lost-Paradise-Project/Lost-Paradise/pull/168
+- author: Kest
+ changes:
+ - type: Tweak
+ message: C4Low был заменён на пробивной заряд
+ - type: Remove
+ message: C4Low был удалён из игры
+ - type: Remove
+ message: Дубликат штурмового молота был удалён из игры
+ id: 58
+ time: '2024-09-21T16:25:13.0000000+00:00'
+ url: https://github.com/Lost-Paradise-Project/Lost-Paradise/pull/175
+- author: IAmLePacko
+ changes:
+ - type: Tweak
+ message: Изменены параметры появления режимов.
+ - type: Tweak
+ message: 'Изменено: Вор потерял пацифизм в угоду РП и логики.'
+ id: 59
+ time: '2024-09-21T16:25:24.0000000+00:00'
+ url: https://github.com/Lost-Paradise-Project/Lost-Paradise/pull/174
diff --git a/Resources/Credits/GitHub.txt b/Resources/Credits/GitHub.txt
index 1a2d582a05..22e7aef8a9 100644
--- a/Resources/Credits/GitHub.txt
+++ b/Resources/Credits/GitHub.txt
@@ -1 +1 @@
-0x6273, 2013HORSEMEATSCANDAL, 20kdc, 21Melkuu, 4dplanner, 612git, 778b, Ablankmann, Acruid, actioninja, adamsong, Admiral-Obvious-001, Adrian16199, Aerocrux, Aexxie, africalimedrop, Agoichi, Ahion, AJCM-git, AjexRose, Alekshhh, AlexMorgan3817, AlmondFlour, AlphaQwerty, Altoids1, amylizzle, ancientpower, angelofallars, ArchPigeon, Arendian, arimah, Arteben, AruMoon, as334, AsikKEsel, asperger-sind, aspiringLich, avghdev, AzzyIsNotHere, BananaFlambe, BasedUser, beck-thompson, BGare, BingoJohnson-zz, BismarckShuffle, Bixkitts, Blackern5000, Blazeror, BlueHNT, Boaz1111, BobdaBiscuit, brainfood1183, BramvanZijp, Brandon-Huu, Bribrooo, Bright0, brndd, BubblegumBlue, BYONDFuckery, c4llv07e, CaasGit, CakeQ, CaptainSqrBeard, Carbonhell, Carolyn3114, CatTheSystem, Centronias, chairbender, Charlese2, Cheackraze, cheesePizza2, Chief-Engineer, chromiumboy, Chronophylos, clorl, Clyybber, CodedCrow, ColdAutumnRain, Colin-Tel, collinlunn, ComicIronic, coolmankid12345, corentt, crazybrain23, creadth, CrigCrag, Crotalus, CrudeWax, CrzyPotato, Cyberboss, d34d10cc, Daemon, daerSeebaer, dahnte, dakamakat, dakimasu, DamianX, DangerRevolution, daniel-cr, Darkenson, DawBla, dch-GH, Deahaka, DEATHB4DEFEAT, DeathCamel58, deathride58, DebugOk, Decappi, Deeeeja, deepdarkdepths, Delete69, deltanedas, DeltaV-Bot, DerbyX, DoctorBeard, DogZeroX, dontbetank, dootythefrooty, Doru991, DoubleRiceEddiedd, DrMelon, DrSmugleaf, drteaspoon420, DTanxxx, DubiousDoggo, Duddino, Dutch-VanDerLinde, Easypoller, eclips_e, EdenTheLiznerd, EEASAS, Efruit, ElectroSR, elthundercloud, Emisse, EmoGarbage404, Endecc, enumerate0, eoineoineoin, ERORR404V1, Errant-4, estacaoespacialpirata, Evgencheg, exincore, exp111, Fahasor, FairlySadPanda, Fansana, ficcialfaint, Fildrance, FillerVK, Fishfish458, Flareguy, FluffiestFloof, FluidRock, FoLoKe, fooberticus, Fortune117, FoxxoTrystan, freeman2651, Froffy025, Fromoriss, FungiFellow, GalacticChimp, gbasood, Geekyhobo, geraeumig, Git-Nivrak, github-actions[bot], gituhabu, gluesniffler, GNF54, Golinth, GoodWheatley, graevy, GreyMario, Guess-My-Name, gusxyz, h3half, Hanzdegloker, Hardly3D, harikattar, HerCoyote23, HoofedEar, Hoolny, hord-brayden, hubismal, Hugal31, Huxellberger, iacore, IamVelcroboy, icekot8, igorsaux, ike709, Illiux, Ilya246, IlyaElDunaev, Injazz, Insineer, Interrobang01, IProduceWidgets, ItsMeThom, Jackal298, Jackrost, jamessimo, janekvap, JerryImMouse, Jessetriesagain, jessicamaybe, Jezithyr, jicksaw, JiimBob, JoeHammad1844, JohnGinnane, johnku1, joshepvodka, jproads, Jrpl, juliangiebel, JustArt1m, JustCone14, JustinTrotter, KaiShibaa, kalane15, kalanosh, Kelrak, kerisargit, keronshb, KIBORG04, Killerqu00, KingFroozy, kira-er, Kit0vras, KittenColony, Ko4ergaPunk, komunre, koteq, Krunklehorn, kxvvv, Lamrr, LankLTE, lapatison, Leander-0, leonardo-dabepis, LetterN, Level10Cybermancer, lever1209, liltenhead, LittleBuilderJane, Lomcastar, LordCarve, LordEclipse, LovelyLophi, Lukasz825700516, lunarcomets, luringens, lvvova1, lzimann, lzk228, MACMAN2003, Macoron, MagnusCrowe, ManelNavola, Matz05, MehimoNemo, MeltedPixel, MemeProof, Menshin, Mervill, metalgearsloth, mhamsterr, MilenVolf, Minty642, Mirino97, mirrorcult, misandrie, MishaUnity, MisterMecky, Mith-randalf, Mnemotechnician, Moneyl, Moomoobeef, moony, Morb0, Mr0maks, musicmanvr, Myakot, Myctai, N3X15, Nairodian, Naive817, namespace-Memory, NickPowers43, nikthechampiongr, Nimfar11, Nirnael, nmajask, nok-ko, notafet, notquitehadouken, noudoit, noverd, nuke-haus, NULL882, nyeogmi, OCOtheOmega, OctoRocket, OldDanceJacket, onoira, osjarw, Owai-Seek, pali6, Pangogie, patrikturi, PaulRitter, Peptide90, peptron1, Phantom-Lily, PHCodes, PixelTheKermit, PJB3005, Plykiya, pofitlo, pointer-to-null, PolterTzi, PoorMansDreams, potato1234x, ProfanedBane, PrPleGoo, ps3moira, Pspritechologist, Psychpsyo, psykzz, PuroSlavKing, quatre, QuietlyWhisper, qwerltaz, Radosvik, Radrark, Rainbeon, Rainfey, Rane, ravage123321, rbertoche, Redict, RedlineTriad, RednoWCirabrab, RemberBM, RemieRichards, RemTim, rene-descartes2021, RiceMar1244, RieBi, Rinkashikachi, Rockdtben, rolfero, rosieposieeee, Saakra, Samsterious, SaphireLattice, ScalyChimp, scrato, Scribbles0, Serkket, ShadowCommander, Shadowtheprotogen546, ShatteredSwords, SignalWalker, SimpleStation14, Simyon264, Sirionaut, siyengar04, Skarletto, Skrauz, Skyedra, SlamBamActionman, slarticodefast, Slava0135, SleepyScarecrow, Snowni, snowsignal, SonicHDC, SoulSloth, SpaceManiac, SpeltIncorrectyl, spoogemonster, ssdaniel24, stalengd, Stealthbomber16, stellar-novas, StrawberryMoses, superjj18, SweptWasTaken, Szunti, TadJohnson00, takemysoult, TaralGit, Tayrtahn, tday93, TekuNut, TemporalOroboros, tentekal, tgrkzus, thatrandomcanadianguy, TheArturZh, theashtronaut, thedraccx, themias, Theomund, theOperand, TheShuEd, TimrodDX, Titian3, tkdrg, Tmanzxd, tmtmtl30, TokenStyle, tom-leys, tomasalves8, Tomeno, Tornado-Technology, tosatur, Tryded, TsjipTsjip, Tunguso4ka, TurboTrackerss14, Tyler-IN, Tyzemol, UbaserB, UKNOWH, UnicornOnLSD, Uriende, UristMcDorf, Vaaankas, Varen, VasilisThePikachu, veliebm, Veritius, Vermidia, Verslebas, VigersRay, Visne, VMSolidus, volundr-, Voomra, Vordenburg, vulppine, wafehling, WarMechanic, waylon531, weaversam8, whateverusername0, Willhelm53, Winkarst-cpu, wixoaGit, WlarusFromDaSpace, wrexbe, xRiriq, yathxyz, Ygg01, YotaXP, YuriyKiss, zach-hill, Zandario, Zap527, Zealith-Gamer, ZelteHonor, zerorulez, zionnBE, zlodo, ZNixian, ZoldorfTheWizard, Zumorica, Zymem
+0x6273, 2013HORSEMEATSCANDAL, 20kdc, 21Melkuu, 4dplanner, 612git, 778b, Ablankmann, Acruid, actioninja, adamsong, Admiral-Obvious-001, Adrian16199, Aerocrux, Aexxie, africalimedrop, Agoichi, Ahion, AJCM-git, AjexRose, Alekshhh, AlexMorgan3817, AlmondFlour, AlphaQwerty, Altoids1, amylizzle, ancientpower, angelofallars, ArchPigeon, Arendian, arimah, Arteben, AruMoon, as334, AsikKEsel, asperger-sind, aspiringLich, avghdev, AzzyIsNotHere, BananaFlambe, BasedUser, beck-thompson, BGare, BingoJohnson-zz, BismarckShuffle, Bixkitts, Blackern5000, Blazeror, BlueHNT, Boaz1111, BobdaBiscuit, brainfood1183, BramvanZijp, Brandon-Huu, Bribrooo, Bright0, brndd, BubblegumBlue, BYONDFuckery, c4llv07e, CaasGit, CakeQ, CaptainSqrBeard, Carbonhell, Carolyn3114, CatTheSystem, Centronias, chairbender, Charlese2, Cheackraze, cheesePizza2, Chief-Engineer, chromiumboy, Chronophylos, CilliePaint, clorl, Clyybber, CodedCrow, ColdAutumnRain, Colin-Tel, collinlunn, ComicIronic, coolmankid12345, corentt, crazybrain23, creadth, CrigCrag, Crotalus, CrudeWax, CrzyPotato, Cyberboss, d34d10cc, Daemon, daerSeebaer, dahnte, dakamakat, dakimasu, DamianX, DangerRevolution, daniel-cr, Darkenson, DawBla, dch-GH, Deahaka, DEATHB4DEFEAT, DeathCamel58, deathride58, DebugOk, Decappi, Deeeeja, deepdarkdepths, Delete69, deltanedas, DeltaV-Bot, DerbyX, DoctorBeard, DogZeroX, dontbetank, dootythefrooty, Doru991, DoubleRiceEddiedd, DrMelon, DrSmugleaf, drteaspoon420, DTanxxx, DubiousDoggo, Duddino, Dutch-VanDerLinde, Easypoller, eclips_e, EdenTheLiznerd, EEASAS, Efruit, ElectroSR, elthundercloud, Emisse, EmoGarbage404, Endecc, enumerate0, eoineoineoin, ERORR404V1, Errant-4, estacaoespacialpirata, Evgencheg, exincore, exp111, Fahasor, FairlySadPanda, Fansana, ficcialfaint, Fildrance, FillerVK, Fishfish458, Flareguy, FluffiestFloof, FluidRock, FoLoKe, fooberticus, Fortune117, FoxxoTrystan, freeman2651, Froffy025, Fromoriss, FungiFellow, GalacticChimp, gbasood, Geekyhobo, geraeumig, Git-Nivrak, github-actions[bot], gituhabu, gluesniffler, GNF54, Golinth, GoodWheatley, graevy, GreyMario, Guess-My-Name, gusxyz, h3half, Hanzdegloker, Hardly3D, harikattar, HerCoyote23, HoofedEar, Hoolny, hord-brayden, hubismal, Hugal31, Huxellberger, iacore, IamVelcroboy, icekot8, igorsaux, ike709, Illiux, Ilya246, IlyaElDunaev, Injazz, Insineer, Interrobang01, IProduceWidgets, ItsMeThom, Jackal298, Jackrost, jamessimo, janekvap, JerryImMouse, Jessetriesagain, jessicamaybe, Jezithyr, jicksaw, JiimBob, JoeHammad1844, JohnGinnane, johnku1, joshepvodka, jproads, Jrpl, juliangiebel, JustArt1m, JustCone14, JustinTrotter, KaiShibaa, kalane15, kalanosh, Kelrak, kerisargit, keronshb, KIBORG04, Killerqu00, KingFroozy, kira-er, Kit0vras, KittenColony, Ko4ergaPunk, komunre, koteq, Krunklehorn, kxvvv, Lamrr, LankLTE, lapatison, Leander-0, leonardo-dabepis, LetterN, Level10Cybermancer, lever1209, liltenhead, LittleBuilderJane, Lomcastar, LordCarve, LordEclipse, LovelyLophi, Lukasz825700516, lunarcomets, luringens, lvvova1, lzimann, lzk228, MACMAN2003, Macoron, MagnusCrowe, ManelNavola, Matz05, MehimoNemo, MeltedPixel, MemeProof, Menshin, Mervill, metalgearsloth, mhamsterr, MilenVolf, Minty642, Mirino97, mirrorcult, misandrie, MishaUnity, MisterMecky, Mith-randalf, Mnemotechnician, Moneyl, Moomoobeef, moony, Morb0, Mr0maks, musicmanvr, Myakot, Myctai, N3X15, Nairodian, Naive817, namespace-Memory, NickPowers43, nikthechampiongr, Nimfar11, Nirnael, nmajask, nok-ko, notafet, notquitehadouken, noudoit, nuke-haus, NULL882, nyeogmi, OCOtheOmega, OctoRocket, OldDanceJacket, onoira, osjarw, Owai-Seek, pali6, Pangogie, patrikturi, PaulRitter, Peptide90, peptron1, Phantom-Lily, PHCodes, PixelTheKermit, PJB3005, Plykiya, pofitlo, pointer-to-null, PolterTzi, PoorMansDreams, potato1234x, ProfanedBane, PrPleGoo, ps3moira, Pspritechologist, Psychpsyo, psykzz, PuroSlavKing, quatre, QuietlyWhisper, qwerltaz, Radosvik, Radrark, Rainbeon, Rainfey, Rane, ravage123321, rbertoche, Redict, RedlineTriad, RednoWCirabrab, RemberBM, RemieRichards, RemTim, rene-descartes2021, RiceMar1244, RieBi, Rinkashikachi, Rockdtben, rolfero, rosieposieeee, Saakra, Samsterious, SaphireLattice, ScalyChimp, scrato, Scribbles0, Serkket, ShadowCommander, Shadowtheprotogen546, ShatteredSwords, SignalWalker, SimpleStation14, Simyon264, Sirionaut, siyengar04, Skarletto, Skrauz, Skyedra, SlamBamActionman, slarticodefast, Slava0135, SleepyScarecrow, Snowni, snowsignal, SonicHDC, SoulSloth, SpaceManiac, SpeltIncorrectyl, spoogemonster, ssdaniel24, stalengd, Stealthbomber16, stellar-novas, StrawberryMoses, superjj18, SweptWasTaken, Szunti, TadJohnson00, takemysoult, TaralGit, Tayrtahn, tday93, TekuNut, TemporalOroboros, tentekal, tgrkzus, thatrandomcanadianguy, TheArturZh, theashtronaut, thedraccx, themias, Theomund, theOperand, TheShuEd, TimrodDX, Titian3, tkdrg, Tmanzxd, tmtmtl30, TokenStyle, tom-leys, tomasalves8, Tomeno, Tornado-Technology, tosatur, Tryded, TsjipTsjip, Tunguso4ka, TurboTrackerss14, Tyler-IN, Tyzemol, UbaserB, UKNOWH, UnicornOnLSD, Uriende, UristMcDorf, Vaaankas, Varen, VasilisThePikachu, veliebm, Veritius, Vermidia, Verslebas, VigersRay, Visne, VMSolidus, volundr-, Voomra, Vordenburg, vulppine, wafehling, WarMechanic, waylon531, weaversam8, whateverusername0, Willhelm53, Winkarst-cpu, wixoaGit, WlarusFromDaSpace, wrexbe, xRiriq, yathxyz, Ygg01, YotaXP, YuriyKiss, zach-hill, Zandario, Zap527, Zealith-Gamer, ZelteHonor, zerorulez, zionnBE, ZNixian, ZoldorfTheWizard, Zumorica, Zymem
diff --git a/Resources/Locale/en-US/atmos/atmos-alerts-console.ftl b/Resources/Locale/en-US/atmos/atmos-alerts-console.ftl
new file mode 100644
index 0000000000..a1640c5e9d
--- /dev/null
+++ b/Resources/Locale/en-US/atmos/atmos-alerts-console.ftl
@@ -0,0 +1,35 @@
+atmos-alerts-window-title = Atmospheric Alerts Computer
+atmos-alerts-window-station-name = [color=white][font size=14]{$stationName}[/font][/color]
+atmos-alerts-window-unknown-location = Unknown location
+
+atmos-alerts-window-tab-no-alerts = Alerts
+atmos-alerts-window-tab-alerts = Alerts ({$value})
+atmos-alerts-window-tab-air-alarms = Air alarms
+atmos-alerts-window-tab-fire-alarms = Fire alarms
+
+atmos-alerts-window-alarm-label = {CAPITALIZE($name)} ({$address})
+atmos-alerts-window-temperature-label = Temperature
+atmos-alerts-window-temperature-value = {$valueInC} °C ({$valueInK} K)
+atmos-alerts-window-pressure-label = Pressure
+atmos-alerts-window-pressure-value = {$value} kPa
+atmos-alerts-window-oxygenation-label = Oxygenation
+atmos-alerts-window-oxygenation-value = {$value}%
+atmos-alerts-window-other-gases-label = Other present gases
+atmos-alerts-window-other-gases-value = {$shorthand} ({$value}%)
+atmos-alerts-window-other-gases-value-nil = None
+atmos-alerts-window-silence-alerts = Silence alerts from this alarm
+
+atmos-alerts-window-label-alert-types = Alert levels:
+atmos-alerts-window-normal-state = Normal
+atmos-alerts-window-warning-state = Warning
+atmos-alerts-window-danger-state = Danger!
+atmos-alerts-window-invalid-state = Inactive
+
+atmos-alerts-window-no-active-alerts = [font size=16][color=white]No active alerts -[/color] [color={$color}]situation normal[/color][/font]
+atmos-alerts-window-no-data-available = No data available
+atmos-alerts-window-alerts-being-silenced = Silencing alerts...
+
+atmos-alerts-window-toggle-overlays = Toggle alarm display
+
+atmos-alerts-window-flavor-left = Contact an atmospheric technician for assistance
+atmos-alerts-window-flavor-right = v1.8
\ No newline at end of file
diff --git a/Resources/Locale/en-US/language/commands.ftl b/Resources/Locale/en-US/language/commands.ftl
index 65959e3f28..ccbe2570c9 100644
--- a/Resources/Locale/en-US/language/commands.ftl
+++ b/Resources/Locale/en-US/language/commands.ftl
@@ -2,10 +2,10 @@ command-list-langs-desc = List languages your current entity can speak at the cu
command-list-langs-help = Usage: {$command}
command-saylang-desc = Send a message in a specific language. To choose a language, you can use either the name of the language, or its position in the list of languages.
-command-saylang-help = Usage: {$command} . Example: {$command} GalacticCommon "Hello World!". Example: {$command} 1 "Hello World!"
+command-saylang-help = Usage: {$command} . Example: {$command} TauCetiBasic "Hello World!". Example: {$command} 1 "Hello World!"
command-language-select-desc = Select the currently spoken language of your entity. You can use either the name of the language, or its position in the list of languages.
-command-language-select-help = Usage: {$command} . Example: {$command} 1. Example: {$command} GalacticCommon
+command-language-select-help = Usage: {$command} . Example: {$command} 1. Example: {$command} TauCetiBasic
command-language-spoken = Spoken:
command-language-understood = Understood:
@@ -18,14 +18,14 @@ command-language-invalid-language = The language {$id} does not exist or you can
# toolshed
command-description-language-add = Adds a new language to the piped entity. The two last arguments indicate whether it should be spoken/understood. Example: 'self language:add "Canilunzt" true true'
-command-description-language-rm = Removes a language from the piped entity. Works similarly to language:add. Example: 'self language:rm "GalacticCommon" true true'.
+command-description-language-rm = Removes a language from the piped entity. Works similarly to language:add. Example: 'self language:rm "TauCetiBasic" true true'.
command-description-language-lsspoken = Lists all languages the entity can speak. Example: 'self language:lsspoken'
command-description-language-lsunderstood = Lists all languages the entity can understand. Example: 'self language:lssunderstood'
command-description-translator-addlang = Adds a new target language to the piped translator entity. See language:add for details.
command-description-translator-rmlang = Removes a target language from the piped translator entity. See language:rm for details.
-command-description-translator-addrequired = Adds a new required language to the piped translator entity. Example: 'ent 1234 translator:addrequired "GalacticCommon"'
-command-description-translator-rmrequired = Removes a required language from the piped translator entity. Example: 'ent 1234 translator:rmrequired "GalacticCommon"'
+command-description-translator-addrequired = Adds a new required language to the piped translator entity. Example: 'ent 1234 translator:addrequired "TauCetiBasic"'
+command-description-translator-rmrequired = Removes a required language from the piped translator entity. Example: 'ent 1234 translator:rmrequired "TauCetiBasic"'
command-description-translator-lsspoken = Lists all spoken languages for the piped translator entity. Example: 'ent 1234 translator:lsspoken'
command-description-translator-lsunderstood = Lists all understood languages for the piped translator entity. Example: 'ent 1234 translator:lssunderstood'
command-description-translator-lsrequired = Lists all required languages for the piped translator entity. Example: 'ent 1234 translator:lsrequired'
diff --git a/Resources/Locale/en-US/language/languages.ftl b/Resources/Locale/en-US/language/languages.ftl
index 68dc80f51d..7ad66d1aab 100644
--- a/Resources/Locale/en-US/language/languages.ftl
+++ b/Resources/Locale/en-US/language/languages.ftl
@@ -1,9 +1,6 @@
language-Universal-name = Universal
language-Universal-description = What are you?
-language-GalacticCommon-name = Galactic common
-language-GalacticCommon-description = The standard Galatic language, most commonly used for inter-species communications and legal work.
-
language-Bubblish-name = Bubblish
language-Bubblish-description = The language of Slimes. Being a mixture of bubbling noises and pops it's very difficult to speak for humans without the use of mechanical aids.
@@ -17,10 +14,37 @@ language-Draconic-name = Draconic
language-Draconic-description = The common language of lizard-people, composed of sibilant hisses and rattles.
language-SolCommon-name = Sol common
-language-SolCommon-description = The language common to species from the Sol System.
+language-SolCommon-description =
+ With its roots in Mandarin Chinese - Common evolved as the official language of the Sol Alliance - with officials working to tie it together with a common tongue.
+ It's spoken by state officials - taught in schools - and spoken by those who either feel a sense of national pride in the Alliance or otherwise fell sway to the culture.
+
+language-TauCetiBasic-name = Tau-Ceti Basic
+language-TauCetiBasic-description =
+ A spiritual successor of Esperanto, established in 2404 in Tau Ceti by Ceti intellectuals.
+ Its unique, fully customized alphabet and structure allow it to be spoken even by most alien species.
+ It's the official language of Tau Ceti and has growing traction in diplomatic circles and Universalists across human space.
+
+language-Tradeband-name = Tradeband
+language-Tradeband-description =
+ Descended from latin and romance languages of old Earth - Tradeband remains the main tongue of the upper class of humanity.
+ The language sounds elegant and well structured to most ears. It remains in popular use with traders - diplomats - and those seeking to hold onto a piece of a romantic past.
+
+language-Freespeak-name = Freespeak
+language-Freespeak-description =
+ A language of renegades and frontiersmen descending from various languages from Earth-- like Hindi,
+ combined into a multi-rooted jumble that sounds incoherent or even barbarian to non-native speakers.
+ This language is the only common cultural identity for humans in the frontier. Speaking this language in itself boldly declares the speaker a free spirit.
+ It is often called 'Gutter' by Alliance citizens.
+
+language-Elyran-name = Elyran Standard
+language-Elyran-description =
+ Elyran Standard is the official tongue of the Republic of Elyra. Constructed using elements of Farsi - Arabic - and Turkish.
+ Influence from all three of these languages can be seen throughout its grammar and vocabulary.
language-Canilunzt-name = Canilunzt
-language-Canilunzt-description = The guttural language spoken and utilized by the inhabitants of the Vazzend system, composed of growls, barks, yaps, and heavy utilization of ears and tail movements. Vulpkanin speak this language with ease.
+language-Canilunzt-description =
+ The guttural language spoken and utilized by the inhabitants of the Vazzend system,
+ composed of growls, barks, yaps, and heavy utilization of ears and tail movements. Vulpkanin speak this language with ease.
language-Moffic-name = Moffic
language-Moffic-description = The language of the mothpeople borders on complete unintelligibility.
@@ -28,8 +52,8 @@ language-Moffic-description = The language of the mothpeople borders on complete
language-RobotTalk-name = RobotTalk
language-RobotTalk-description = A language consisting of harsh binary chirps, whistles, hisses, and whines. Organic tongues cannot speak it without aid from special translators.
-language-Sign-name = Galactic Sign Language
-language-Sign-description = GSL for short, this sign language is prevalent among mute and deaf people.
+language-Sign-name = Tau-Ceti Basic Sign Language
+language-Sign-description = TCB-SL for short, this sign language is prevalent among mute and deaf people.
language-Cat-name = Cat
language-Cat-description = Meow
diff --git a/Resources/Locale/en-US/loadouts/itemgroups.ftl b/Resources/Locale/en-US/loadouts/itemgroups.ftl
index 29aca3ddb9..97fcfa6984 100644
--- a/Resources/Locale/en-US/loadouts/itemgroups.ftl
+++ b/Resources/Locale/en-US/loadouts/itemgroups.ftl
@@ -64,3 +64,7 @@ character-item-group-LoadoutBartenderWeapon = Bartender Weapon
# Service - Musician
character-item-group-LoadoutMusicianInstruments = Musician Instruments
+
+# Traits - Languages
+character-item-group-TraitsLanguagesBasic = Basic Languages
+character-item-group-TraitsAccents = Accents
\ No newline at end of file
diff --git a/Resources/Locale/en-US/traits/categories.ftl b/Resources/Locale/en-US/traits/categories.ftl
index 56f0adeb47..2bd4b7ba49 100644
--- a/Resources/Locale/en-US/traits/categories.ftl
+++ b/Resources/Locale/en-US/traits/categories.ftl
@@ -5,4 +5,7 @@ trait-category-Auditory = Auditory
trait-category-Mental = Mental
trait-category-Physical = Physical
trait-category-Speech = Speech
-trait-category-Visual = Visual
+trait-category-TraitsSpeechUncategorized = Uncategorized
+trait-category-TraitsSpeechAccents = Accents
+trait-category-TraitsSpeechLanguages = Languages
+trait-category-Visual = Visual
\ No newline at end of file
diff --git a/Resources/Locale/en-US/traits/traits.ftl b/Resources/Locale/en-US/traits/traits.ftl
index b034f69b9e..4db6055e46 100644
--- a/Resources/Locale/en-US/traits/traits.ftl
+++ b/Resources/Locale/en-US/traits/traits.ftl
@@ -152,9 +152,30 @@ trait-description-Lethargy =
trait-name-SignLanguage = Sign Language
trait-description-SignLanguage =
- You can understand and use Galactic Sign Language (GSL).
+ You can understand and use Tau-Ceti Basic Sign Language (TCB-SL).
If you are mute for any reason, you can still communicate with sign language.
+trait-name-SolCommon = Sol Common
+trait-description-SolCommon =
+ With its roots in Mandarin Chinese - Common evolved as the official language of the Sol Alliance - with officials working to tie it together with a common tongue.
+ It's spoken by state officials - taught in schools - and spoken by those who either feel a sense of national pride in the Alliance or otherwise fell sway to the culture.
+
+trait-name-Tradeband = Tradeband
+trait-description-Tradeband =
+ Descended from latin and romance languages of old Earth - Tradeband remains the main tongue of the upper class of humanity.
+ The language sounds elegant and well structured to most ears. It remains in popular use with traders - diplomats - and those seeking to hold onto a piece of a romantic past.
+
+trait-name-Freespeak = Freespeak (Gutter)
+trait-description-Freespeak =
+ A language of renegades and frontiersmen descending from various languages from Earth like Hindi combined into a multi-rooted jumble that sounds incoherent or even barbarian to non-native speakers.
+ This language is the only common cultural identity for humans in the frontier. Speaking this language in itself boldly declares the speaker a free spirit.
+ Often called 'Gutter' by Alliance citizens.
+
+trait-name-Elyran = Elyran Standard
+trait-description-Elyran =
+ Elyran Standard is the official tongue of the Republic of Elyra.
+ Constructed using elements of Farsi - Arabic - and Turkish - influence from all three of these languages can be seen throughout its grammar and vocabulary.
+
trait-name-Voracious = Voracious
trait-description-Voracious =
Nothing gets between you and your food.
diff --git a/Resources/Locale/ru-RU/_LostParadise/prototypes/entities/clothing/shoes/misc.ftl b/Resources/Locale/ru-RU/_LostParadise/prototypes/entities/clothing/shoes/misc.ftl
deleted file mode 100644
index e69de29bb2..0000000000
diff --git a/Resources/Locale/ru-RU/_LostParadise/prototypes/entities/mobs/player/ipc.ftl b/Resources/Locale/ru-RU/_LostParadise/prototypes/entities/mobs/player/ipc.ftl
index ae4814a56b..24d924f607 100644
--- a/Resources/Locale/ru-RU/_LostParadise/prototypes/entities/mobs/player/ipc.ftl
+++ b/Resources/Locale/ru-RU/_LostParadise/prototypes/entities/mobs/player/ipc.ftl
@@ -1,5 +1,4 @@
ent-MobIpc = Урист МакПозитроник
.desc = Позитронный мозг в металлическом теле.
-ent-MobIPCDummy = Урист МакПозитроник
- .desc = Манекен позитронного мозга в металлическом теле.
+
ipc-board-name = системный блок КПБ
diff --git a/Resources/Locale/ru-RU/_LostParadise/update20.ftl b/Resources/Locale/ru-RU/_LostParadise/update20.ftl
index ce91e2f05f..4eb4c369c0 100644
--- a/Resources/Locale/ru-RU/_LostParadise/update20.ftl
+++ b/Resources/Locale/ru-RU/_LostParadise/update20.ftl
@@ -35,8 +35,6 @@ ent-LPParbitermask = Трофейная маска
.desc = Трофейная маска одного из известных охотников. От неё так и веет отчаянием
ent-LPPBrasMat = Раздатчик бюстгальтеров
.desc = Раздатчик, что дополняет образ пользователя и делает его неотразимым!
-ent-LPPC4Low = C4Low
- .desc = Взрывпакет предназначенный для быстрого выламывания шлюзов или стен, но его взрыв довольно слабый в плане радиуса. Виднеется этикетка (ставьте прямо на объект)
ent-LPPCargodrobeVard = Раздатчик продвинутой одежды снабжения
.desc = Красивая одежда для персонала снабжения!
ent-LPPClothingMaskGasIIC = Противогаз Delta
diff --git a/Resources/Locale/ru-RU/accent/italian.ftl b/Resources/Locale/ru-RU/accent/italian.ftl
index b1c25f8397..5245f28e9d 100644
--- a/Resources/Locale/ru-RU/accent/italian.ftl
+++ b/Resources/Locale/ru-RU/accent/italian.ftl
@@ -1,7 +1,6 @@
# This should probably use the same prefix system as the mobster accent.
# For the record, these do not work right now - even when uncommented.
-
# accent-italian-prefix-1 = Ravioli, ravioli, give me the formuoli!
# accent-italian-prefix-2 = Mamma-mia!
# accent-italian-prefix-3 = Mamma-mia! That's a spicy meat-ball!
diff --git a/Resources/Locale/ru-RU/actions/actions/actions-commands.ftl b/Resources/Locale/ru-RU/actions/actions/actions-commands.ftl
index fed57d1c1a..8a6d41203c 100644
--- a/Resources/Locale/ru-RU/actions/actions/actions-commands.ftl
+++ b/Resources/Locale/ru-RU/actions/actions/actions-commands.ftl
@@ -1,6 +1,5 @@
## Actions Commands loc
-
## Upgradeaction command loc
upgradeaction-command-need-one-argument = upgradeaction needs at least one argument, the action entity uid. The second optional argument is a specified level.
diff --git a/Resources/Locale/ru-RU/atmos/air-alarm-ui.ftl b/Resources/Locale/ru-RU/atmos/air-alarm-ui.ftl
index 67482f4d42..0278f62114 100644
--- a/Resources/Locale/ru-RU/atmos/air-alarm-ui.ftl
+++ b/Resources/Locale/ru-RU/atmos/air-alarm-ui.ftl
@@ -1,6 +1,5 @@
# UI
-
## Window
air-alarm-ui-access-denied = Недостаточный уровень доступа!
@@ -31,7 +30,6 @@ air-alarm-ui-mode-none = Нет
## Widgets
-
### General
air-alarm-ui-widget-enable = Включено
diff --git a/Resources/Locale/ru-RU/atmos/atmos-alerts-console.ftl b/Resources/Locale/ru-RU/atmos/atmos-alerts-console.ftl
new file mode 100644
index 0000000000..01cb6f8aeb
--- /dev/null
+++ b/Resources/Locale/ru-RU/atmos/atmos-alerts-console.ftl
@@ -0,0 +1,35 @@
+atmos-alerts-window-title = Компьютер Атмосферных Оповещений
+atmos-alerts-window-station-name = [color=white][font size=14]{$stationName}[/font][/color]
+atmos-alerts-window-unknown-location = Неизвестное местоположение
+
+atmos-alerts-window-tab-no-alerts = Оповещения
+atmos-alerts-window-tab-alerts = Оповещений: ({$value})
+atmos-alerts-window-tab-air-alarms = Сигналы воздушной тревоги
+atmos-alerts-window-tab-fire-alarms = Пожарные сигналы
+
+atmos-alerts-window-alarm-label = {CAPITALIZE($name)} ({$address})
+atmos-alerts-window-temperature-label = Температура
+atmos-alerts-window-temperature-value = {$valueInC} °C ({$valueInK} K)
+atmos-alerts-window-pressure-label = Давление
+atmos-alerts-window-pressure-value = {$value} кПа
+atmos-alerts-window-oxygenation-label = Уровень кислорода
+atmos-alerts-window-oxygenation-value = {$value}%
+atmos-alerts-window-other-gases-label = Присутствующие газы
+atmos-alerts-window-other-gases-value = {$shorthand} ({$value}%)
+atmos-alerts-window-other-gases-value-nil = Нет
+atmos-alerts-window-silence-alerts = Отключить оповещения от этого датчика
+
+atmos-alerts-window-label-alert-types = Уровни тревоги:
+atmos-alerts-window-normal-state = Нормально
+atmos-alerts-window-warning-state = Предупреждение
+atmos-alerts-window-danger-state = Опасность!
+atmos-alerts-window-invalid-state = Неактивно
+
+atmos-alerts-window-no-active-alerts = [font size=16][color=white]Нет активных оповещений -[/color] [color={$color}]ситуация нормальная[/color][/font]
+atmos-alerts-window-no-data-available = Данные недоступны
+atmos-alerts-window-alerts-being-silenced = Отключение оповещений...
+
+atmos-alerts-window-toggle-overlays = Переключить отображение сигналов тревоги
+
+atmos-alerts-window-flavor-left = Обратитесь к технику по атмосфере за помощью
+atmos-alerts-window-flavor-right = v1.8
diff --git a/Resources/Locale/ru-RU/atmos/gas-canister-component.ftl b/Resources/Locale/ru-RU/atmos/gas-canister-component.ftl
index 99c0ad00b9..772d1d1a92 100644
--- a/Resources/Locale/ru-RU/atmos/gas-canister-component.ftl
+++ b/Resources/Locale/ru-RU/atmos/gas-canister-component.ftl
@@ -1,6 +1,5 @@
## UI
-
# Bound Interface
gas-canister-bound-user-interface-title = Газовый баллон
diff --git a/Resources/Locale/ru-RU/barsign/barsign-component.ftl b/Resources/Locale/ru-RU/barsign/barsign-component.ftl
index d3a39835c4..3cd12f7f84 100644
--- a/Resources/Locale/ru-RU/barsign/barsign-component.ftl
+++ b/Resources/Locale/ru-RU/barsign/barsign-component.ftl
@@ -4,7 +4,6 @@ barsign-ui-set-label = Выбрать вывеску:
# Bar signs prototypes
-
## The Harmbaton
barsign-prototype-name-harmbaton = Хармбатон
diff --git a/Resources/Locale/ru-RU/climbing/glass-table-component.ftl b/Resources/Locale/ru-RU/climbing/glass-table-component.ftl
index e22123a969..5056cc13de 100644
--- a/Resources/Locale/ru-RU/climbing/glass-table-component.ftl
+++ b/Resources/Locale/ru-RU/climbing/glass-table-component.ftl
@@ -1,6 +1,5 @@
### Tables which take damage when a user is dragged onto them
-
## Showed to users other than the climber
glass-table-shattered-others = { CAPITALIZE($table) } ломается под весом { $climber }!
diff --git a/Resources/Locale/ru-RU/corvax/join-playtime/join-playtime-reason.ftl b/Resources/Locale/ru-RU/corvax/join-playtime/join-playtime-reason.ftl
deleted file mode 100644
index e69de29bb2..0000000000
diff --git a/Resources/Locale/ru-RU/corvax/paper/books-lore.ftl b/Resources/Locale/ru-RU/corvax/paper/books-lore.ftl
index 6571b59c7f..d591b1957f 100644
--- a/Resources/Locale/ru-RU/corvax/paper/books-lore.ftl
+++ b/Resources/Locale/ru-RU/corvax/paper/books-lore.ftl
@@ -3,53 +3,42 @@ book-expensive-crystal-contents =
Чистые кристаллы космеция встречаются крайне-крайне-крайне редко и стоят целое состояние. Чаще всего встречаются кристаллы сложного состава, а именно космеций с оксидом меди(II), космеций с оксидом кремния и железом. Блюспейс кристаллы имеют сингонию, которая более нигде не встречается. Анизотропные. Имеют одно кристаллографическое направление, по которому происходит наиболее быстрая обработка, в частности раскол, слом и крошение.
Также известно, что космеций обладает карбидообразующими свойствами.
-
В природе встречается и иная форма природных кристаллов космеция, а именно космеций с примесью оксида алюминия и хрома.
Данный тип кристаллов образовывается в зонах активности аномалий, после действия редспейс разломов, а также на астероидах и обломках, претерпевших контакт с редспейс-пространством.
Они также анизотропны, и обладают такой же незнакомой земным материалам сингонией, но при этом имеют целых два направления удобного слома.
-
Истинный потенциал Блюспейс кристалла проявляется в его связанной работой с твёрдой плазмой. Плазма при распаде выделяет колоссальное количество энергии, которую способен поглотить и сохранить космеций. Далее он сможет постепенно отдавать эту энергию в специальные устройства. Но истинной уникальностью является то, что блюспейс кристалл способен стать основой для мощного квантового осциллятора, способного взаимодействовать напрямую с волнами вероятности де Бройля.
Этот эффект используется в модулях БС скачков для двигателей космических кораблей.
Отдельными свойствами выделяются кристаллы, измельчённые в мелкодисперсный порошок.
При взаимодействия такого порошка с углеродными материалами происходит образование карбида космеция. Данный материал приводит к невероятному квантово-механическому явлению: Неопределённость Гейзенберга, указывающая на сильную неточность координат, начинает играть определяющую роль и невероятно усиливается, ибо предмет, созданный с использованием карбида космеция теряет чёткие внутренние границы, при относительной стабильности внешних. Таким образом можно создавать, скажем, рюкзаки или мензурки, чей внутренний объём сильно превышает объём внешний.
Качество данных уникальных свойств тем выше, чем ниже примесей в кристалле. При этом у космеция с примесью оксида меди самые худшие свойства, а у чистого космеция самые лучшие.
-
Космеций также способен через неопределённость Гейзенберга влиять на волны вероятности де Бройля. Но в отличии от блюспейс кристаллов, редспейс не выборочно либо изменяют пространство, либо проводят колебания квантовых волн, а делают это одновременно.
Таким образом при накоплении в редспейс кристалле энергии, открывается возможность колебания волн вероятности для мгновенного перемещения некого объекта к кристаллу из более-менее конкретной выбранной точки. При этом данное действие способно разрушить кристалл, распылив его атомы в произвольной области пространства.
Из-за этой, по факту, телепортации редспейс кристаллы прозвали телепортационными кристаллами, или же телекристаллами.
book-clones-contents =
По началу отношение к клонированию и к самим клонам было крайне отрицательным, немало людей страдали бионализмом (страх перед клонированными людьми). Они отказывались признавать клонов не то, что за личностей, а за живых существ как таковых. Некоторые принимали их за расходный материал, другие – за чудовищное надругательство над законами природы. Впоследствии это выливалось в гонения клонов, их убийствами и погромами их жилищ. Большими проблемами также стали вопросы о юридических правах клонов, их интеграции в общество, осмысления этичности самого процесса клонирования.
-
Апофеозом всего этого стал “Туртельский Кризис” []Данные удалены[] года, когда несколько десятков клонов начали забастовку на малой научной станции под названием “Туртель”, находившейся на орбите Марса и занимавшейся секретными разработками компании NanoTrasen (именно поэтому на ней было довольно большое количество клонов-экипажа), работа станции была саботирована, а всему не клонированному персоналу было предложено эвакуироваться с неё. После того как все желающие эвакуировались, были и те, кто не являясь клонами, решили всё-таки остаться на станции тем самым выказав поддержку идеям клонов. Клоны и им сочувствующие смогли настроить аппаратуру станции на одну известную медиа-частоту и обратились по ней со своими требованиями, главным из которых было – предоставления всем клонам на территориях ОПЗ и объектах NanoTrasen равных с обычными гуманоидами прав. В результате долгих и не очень продуктивных переговоров, NanoTrasen не нашла ничего лучше, чем послать на станцию отряд зачистки, прибыв на место они устроили настоящую кровавую баню и когда уже подходили к мостику, были взорваны вместе со всей станцией одним из клонов-инженеров, который смог активировать ядерную боеголовку. Когда все произошедшие стало достоянием широкой публики репутации и активам NanoTrasen был нанесен огромный удар, а на многих планетах и станциях прошли митинги и забастовки в поддержку клонов. Массовые беспорядки нарастали, а СМИ лишь ещё больше подливали масло в огонь, так что ОПЗ приняла “Хартию Прав Клонов” и потребовала того же от NanoTrasen, что последние поспешили и сделать.
-
Примерно в те же времена был основан “Комитет по защите прав клонов” (КЗПК), который и по сей день занимается защитой прав клонов и предоставлением им юридических услуг.
book-dam-contents =
Получение энергии из антиматерии – дело не хитрое, но опасное. Оно основано на эффекте взаимной аннигиляции материи и антиматерии при соприкосновении. При этом вся масса материи и антиматерии преобразуется в чистейшую световую энергию, то есть формирует мощнейшую фотонную вспышку.
-
Контейнеры с топливом представляют собой магнитные ловушки, где граммы антиматерии парят в полном вакууме, не соприкасаясь со стенками контейнера.
-
Двигатель Антиматерии состоят из ядер и стенок. Ядра являются реакционными камерами, где соприкасаются материя и антиматерия. Для простоты используют Гелий и Антигелий. В ядрах установлены мощнейшие преобразователи, способные улавливать как световую, так и тепловую энергию. Стенки ДАМ выполнены из взрывостойкой, сверхпрочной, плохо проводящей тепло композитов и покрытий с парамагнитными свойствами.
-
Важнейшей частью ДАМ является его контроллер. Это сложное устройство состоит из набора трубок и магнитных бесконтактных транспортёров, которые призваны безопасно и дозированно перенести антиматерию в ядро. Также на контроллере присутствует консоль, показывающая количество оставшегося топлива по показанию сверхточных весов, и система настройки впрыска. Двух условных единиц антиматерии хватает для полной работоспособности одного ядра ДАМ. При этом если превысить это значение, то преобразователи энергии начнут нагреваться и перегреваться. Со временим тепло может проникнуть в камеры с гелием. Увеличение давления выше критической точки спровоцирует нарушение целостности ДАМ, это выведет из строя магнитные системы, под действием гравитации или иных внешних сил антиматерия коснётся любого вещества в помещении и спровоцирует бесконтрольный уничтожающий взрыв.
book-faks-contents =
Схема работы Факса проста. Оператор пишет текст на бумаге нужного стандартного формата, ставит печать и отправляет в приёмное окно устройства. В области приёма располагается подвижная планка, перемещающаяся вдоль листа. На планке закреплён распределитель излучения, а над ним находится несколько источников фиолетового лазера низкой энергии. Фиолетовый лазер был выбран по причине наиболее благоприятного выполнения критерия Релея и повышения разрешающей способности. Распределитель превращает гауссовы пучки лазера в лазерную линию, которая проходит по всему листу. Помимо распределителя в нижней части планки располагаются датчики оптического излучения. Лучи света отражаются от бумаги и чернил и попадают в датчики. Датчики анализируют отражённые лучи и записывают в память факса показания, что и является сканированием текста. Особенность представляет место для печатей, ибо печати глав используют не стандартные чернила, а чернила с определённым процентом примеси вполне конкретных металлических и жидко-органических добавок. Поэтому у факсов присутствует система Рентгеновской фотоэлектронной спектроскопии, для определения процентного атомного состава с поверхности печати. Все проценты также заносятся в память.
Все данные в памяти проходят процедуру шифрования, а затем разбиваются на два потока данных по особому алгоритму, после чего оба потока получают код протокола разбиение на потоки данных, проходят процедуру расчёта и присваивания кода исправления ошибок и скремблирования, также каждому потоку данных прибавляется кодированный адрес станции и адрес конкретного факса на станции. Наконец эти потоки данных при помощи метода импульсного биполярного кодирования отправляются по системе дальней связи в пункт назначения. Все антенны дальней связи принимают сообщение с факса и считывают адрес станции, сравнивают со своим адресом и отбраковывают пакеты данных, если он не подходит, или принимают всю остальную посылку, если адрес совпадает. Далее специально выделенный ретранслятор отфильтровывает адрес станции и начинает рассылку на все факсы станции. Приёмное устройство факсов в свою очередь аналогичным образом производит сравнение адреса факса.
-
Целевой факс получает оба потока данных одновременно и извлекает их из частот методом анализа амплитуд, затем дескремблирует оба потока данных, производит анализ кода исправления ошибок и исправляет ошибки. После система факса по полученному коду разбиения на потоки восстанавливает из двух потоков единый пакет данных, который затем декодируется и анализируется печатной системой факса.
-
Печатная система раздельно анализирует данные текста и данные снятые с области для печатей. На электрофотографический цилиндр при помощи коротрона наносится электрический заряд. Далее идёт облучение фиолетовым лазером участков, где должна остаться белая область (область без текста). Из-за действия света заряд в облучённых участках стекает. Далее ЭФЦ обсыпается заряженным цветным тонером, а потом к нему прижимается бумага, формируя таким образом отпечатанное изображение. После чего цилиндр очищается от воздействия заряда и от остатков печатного тоника.
-
Нечто аналогичное происходит и с печатью собственно печатей оригинала. Но факс использует обычные цветной тоник, но при этом использует пометку об соответствии пришедших закодированных данных состава оригинальной печати или несоответствия, по которым член командования может понять оригинальное ли ему пришло письмо или фальшивое.
book-famalis-contents =
Семья Дилли Джонсона
@@ -58,87 +47,72 @@ book-famalis-contents =
Во внешнем мире джони известны как опасные налётчики. Они грабят торговые суда, совершают атаки на чиновников, банки, биржи, хранилища денег, драгоценностей, музеи. Они славятся своей вероломностью, быстрой расправой, а также молниеносными налётами «через парадный вход». При этом они же известны как явные пижоны, любители моды и стиля. Их фирменной визитной карточной является длинное пальто, плащ или тренч, со знаком Семьи на спине – Устаревшей латинской буквой «D», лентой патронов вокруг и одной красной розой, продетой через букву.
-
Клан Сава
Внутри государства савы занимаются охраной важных шишек, чиновников, управленцев, а также всех, кто наймёт их услуги. Это профессиональные телохранители. Также они ведают утилизацией и переработкой мусора. «Мусорная» мафия вызывает смех только у тех, кто ничего в этом не смыслит. Услуги вывоза мусора являются платными, самостоятельно утилизировать или перерабатывать не дадут крупные братки-савы, а при скоплении невыброшенного мусора гражданину будет попросту невозможно жить. А также его соседи вызовут джони, для урегулирования вопроса, которые церемониться не станут. Помимо мусора савы утилизируют самые разные вещи за сходную договорную цену. Так что все знают, что если что-то или кто-то пропал бесследно, то вполне вероятно его останки находятся где-то у сав. Таким образом вся вторсырьевая продукция также является продуктом работы заводов клана Сава.
Во всей галактике савы – это пираты, налётчики, грабители торговых судов, а также крупная мафия в области рэкета, похищений и запугиваний. Их услуги порой применяются для «протаскивания» нужных законов посредством «общения» с несогласными политиками, а также для уборки неугодных, лидеров оппозиций. Порой с помощью них даже подавляют мятежи, но пока они не наняты, они являются жуткой головной болью для логистов и охранно-сопровождающих ведомств.
-
Союз «Клевер»
Клеверы чаще внутри стороны занимают сразу четыре ниши, а именно они владеют крупными юридическими бюро, они управляют планетарными и космическими тюрьмами, они владеют половиной планетарных дорог и третью космических торговых путей, а также они являются организацией государственной безопасности. Благодаря тому, что лучшие Адвокаты работают на них или являются членами их Семьи, Союз «Клевер» часто может толковать законы в свою пользу, получая существенную выгоду. Владение частными тюрьмами позволяет взымать плату с планет и государств, чей преступник содержиться в тюрьме. В случае отказа или превышения срока оплаты, преступник выходит на волю и возвращается в родные края. Клеверы же не звери, готовы предоставить практически нищему билетик до родины, но увы… содержание обходится «так» дорого! При этом важно понимать, что перемещение по дорогам и космическим путям Клевера – дело платное, но оплата сугубо добровольная. Вы по доброй воле можете заплатить или отправиться другим путём. При этом пути клеверов самые защищённые и скоростные с отлично развитой инфраструктурой (тоже доход!) и прекрасным состоянием. Помимо этого, клеверы выступают как контрразведка и занимаются расследованиями, связанными со шпионажем, саботажем, похищениями, убийствами и т.п. направленными от других государств.
В остальной галактике клеверы – это лучшие независимые эксперты в области юриспруденции и политологии. За деньги они способны перевернуть практически любое дело с ног на голову и вывернуть своего Адвоката-оппонента наизнанку. Также их знают, как отличных трассовладельцев в пространстве Братства и, местами, за его приделами. Для правоохранительных органов клеверы становятся прекрасным способом убрать особо опасных заключённых как можно дальше от себя и больше их не видеть, а вот разведывательные управления лютой ненавистью не любят эту Семью.
-
Организация «Ворбакс»
Ворбаки или же ворбы выполняют роль тайной полиции государства, а также им принадлежат текстильные фабрики и плантации по всему сектору. Они шьют одежду и продают её. Вполне легальный бизнес. Также они владеют сетью гостиниц и кафе. Как ни странно, но магазины ткани, одежды, пошивочные мастерские, гостиницы и кафе становятся для них отличными источниками информации, а также прекрасным способом перемещения и внедрения своих агентов. Они занимаются преследованием и устранением опасных для Собрания Семей, для Дона и для их Семьи членов общества, репортёров, беглых шпионов, оппозиционеров, бунтовщиков, революционеров. А также осуществляют шпионаж, разведку и саботажи на территории других государств.
Контрразведывательные управления и организации госбезопасности разных стран тратят достаточно много средств и усилий, борясь с ворбаками. При этом в тот же момент миллионы граждан по всей галактике знает компанию ткани и удобной одежды «Ворбакс Текст», небольшие кафе «Ворбачная» и сеть дешёвых, но уютных трёхзвёздочных гостиниц «Тенистый Домик»
-
Семья Глазиуса Мора
Внутри государства многие очень не любят членов семьи Глазиуса Мора. «Глаза», как их называют вызывают огромное количество трат. Глаза занимаются контролем качества, экологическим аудитом, налоговыми сборами, выявлением всяческих нарушений, а также трудовыми и всякими разными другими инспекциями. Само собой, они прекрасные профессионалы и крайне быстро находят несоответствия. А так как именно они в своё время «протащили» ряд законов о стандартах производства, то имеют право сообщить о нарушениях джони или клеверам. Чтобы избежать неприятного общения с этими господами, владельцы предприятий платят глазам немалые суммы, а те взамен не только не докладывают правоохранителям, но ещё и за отдельную плату составляют подробные инструкции, как исправить недочёты.
За пределами Братства глаза известны как опасные мошенники, воры, шпионы, кляузники, а ещё как успешные торговцы, игроки на бирже. Кроме того они оказывают услуги независимого аудита, консультации перед гос.проверками. Порой их нанимают даже в качестве кризис-менеджеров в некоторые филиалы компаний.
-
Семья Фенарио
Семья Фенарио владеет казино, игорными домами, клубами эротического содержания, дорогими отелями, а также производством и продажей алкоголя. Все эти места приносят отличную прибыль, кроме того, позволяют собирать весомый компромат на различные грязные выходки очень разных людей с целью последующего шантажа. Помимо прочего на счётчике у Семьи стоят должники, которым приходится отрабатывать проценты самыми разными способами. Но при этом главы Семей Фенарио славятся своей щедростью! Порой они списывают долги своих должников, рождая тем самым кучу благодарных, а от того затем и преданных ему людей. также они вносят пожертвования на образование и благотворительность, также устанавливая дружеские связи, создавая преданность или сажая некоторые заведения и организации на денежную иглу. Кроме того, благодаря огромным денежным запасам Семья спонсирует научные лаборатории, проводящие исследования вне рамок морали.
В большом мире Семья Фенарио известна, как династия промышленников в области хорошего алкоголя. Дорогие вина, коньяк, портвейн, джин, ром, пиво и многое другое. Также они почитаются за известных меценатов и щедрых благотворителях. Они имеют во владении несколько известных на всю галактику крупных отелей и пару легальных казино. Знакомство с ними охотно заводят представители политической элиты всех стран, кроме СССП. Впрочем, у органов государственной безопасности порой возникают подозрение, что ряд чиновников и политиков находится у Фенарио на долговом счету или на коротком поводке компромата. Но доказательства собрать пока не удаётся.
-
Фонд Мола Гола
Граждане Межпланетарного братства могут, конечно, опасаться джони, сав или ворбаков, но членов Фонда они воистину боятся. Они похищают всех представителей разумных существ во всех уголках галактики, а затем делают из них рабов. Рабы продаются в самые разные безымянные места, где затем до самой смерти в нечеловеческих условиях вкалывают на полях, плантациях. Промышленных теплицах, шахтах, штольнях, рудниках, на заводах, фабриках и в цехах. Они теряют имена, имущество, родных, друзей, а всю личность им заменяет номер, отпечатанный на груди. Таким образом Фонд становится промышленным сердцем и одновременно рабовладельческим гигантом.
-
Семья Синий Камень
Областью деятельности Семьи являются курительные смеси, кальянные заправки и наркотики. Самые разные, всех мастей. Массовые, авторские. В любом объёме. Регулярные запросы на наркотики от подсаженных на иглу обеспечивают стабильный доход, а распространения курева всех мастей позволяет легализовать точки сбыта в других системах. В галактике эта Семья известна под именем «Синекаменный табак». Мелкая компания, продающая табачные изделия. Она не попадает в поле зрения правоохранителей и умудряется тихонько распространять длинные сети дистрибуции наркотиков.
-
Союз Границ
Название граничников говорит само за себя. Он взымает таможенную пошлину с ввозимых товаров. Проверяет на список запряжённых вещей. также управляют потоками контрабанды и занимаются защитой космического пространства и наёмным сопровождением в космосе. Сети контрабанды распространяются далеко за пределы сектора Арабеллы. Правоохранители всех стран стараются обрубать головы этой гидры, но Семья находит новые пути. При этом наёмные боевые корабли сопровождения граничников считаются элитными наёмными отрядами, которые пользуются популярностью у многих логистов всех корпораций и стран.
book-grav-contents =
Генераторы гравитации отличаются лишь мощностью, но в сути их работы лежат выдающиеся патенты НТ по работе с антиматерией и, в частности, с антиполем. В привычной механике мы привыкли, что объект с существенной массой создаёт в пространстве гравитационное искажение по законам Ньютона, из-за которого все объекты начинают к нему стремиться.
-
Генератор же гравитации представляет собой невероятное сочетание уникальной по своей природе плазмы с антиматерией. При облучении плазмы антигелием формируется не обычная фотонная вспышка, а вспышка гравитационного антиполя (оно же «поле искусственной гравитации»). Все тела, попадающие в действие антиполя начинают воспроизводить гравитационное искажение, не меняя свою стандартную массу, а формируя мнимую гравитационную массу. Таким образом у всего в поле действия генератора гравитации увеличивается ньютоновское притяжение друг к другу, не используя центробежное вращение, как в космических кораблях тысячелетней давности.
-
Незначительным побочным эффектом является формирование отрицательной мнимой массы у самого генератора, из-за чего его может переносить один человек, ибо генератор очень лёгкий.
book-halifat-contents =
Духовная составляющая
-
Шахада
Является первым и наиболее важным символом веры. «Свидетельствую, что нет божества достойного поклонения кроме Аллаха и ещё свидетельствую, что Мухаммад — посланник Аллаха». Является необходимой формулой для признания себя правоверным. Отдельно стоит отметить, что в понимании ражулитов нет принципиальной разницы между понятиями «Бог», «Создатель», «Вселенский перводвигатель», «Объект поклонения». Попытка разделить эти понятия может быть встречена абсолютно глухим непониманием. Шахада может быть использована религиозными деятелями или истинно правоверными, как дополнительный аргумент при свидетельствовании или доказательстве чего-либо другому лицу, если произносящий шахаду не лукавит, не пытается врать, утаить факты, а полностью уверен в том, что доказывает.
-
Намаз
Является обязательным столпом для истинно правоверных и религиозных деятелей. Это ежедневный цикл молитв, который состоит двукратной утренней молитвы (фадж), четырёхкратной полуденной (зухр), четырёхкратной предвечерней (аср), трёхкратной вечерней (магриб) и четырёхкратной ночной (иша). Молитвы должны быть принесены с условием выполнения определённых правил.
-
Саум
Необходимость совершать воздержание в течение священного месяца Рамодана, который отсчитывается по лунному (по Земле) исламскому календарю. Именно в этот месяц пророк Мухаммад получил с небес Коран. В ходе воздержания правоверным запрещается есть пищу от момента наступления утренней молитвы и до вечерней молитвы. Считается, что временем начала поста и утренней молитвы можно назвать тот момент, когда на улице при естественном свете получиться отличить белую нить от чёрной. В случае если пост был нарушен по уважительной причине, вроде тяжёлой болезни, ражулит должен восполнить пропущенный день одним днём поста или отдать нуждающимся пищу, эквивалентную по стоимости 3,3 кг муки. Позволяется отдавать муку, мясо, яйца, хлеб, овощи или фрукты. Если же причина была неуважительной, то есть воплощала недержание и слабость воли ражулита, то он будет обязан со следующего лунного месяца начать личный пост на 60 дней под присмотром священнослужителя или накормить досыта 60 бедняков.
-
Закят
Выплата налогов Духовному собранию и в государственную казну всеми дееспособными, самостоятельными, взрослыми ражулитами. При этом пятая часть денег, идущих к Духовному собранию, идёт на развитие проектов и поддержку самого собрания, а остальные 80% идут на поддержку нуждающихся, коих достаточно особенно в пограничных регионах, где идут военные действия. Кроме нищих и обездоленных, деньги идут для выкупания должников или рабов мусульман у других государств или корпораций, также на помощь в погашении долга тем ражулитам, что взяли в долг у мечети или Духовного собрания на организацию богоугодного дела. Среди прочего эти деньги идут в поддержку джихада и на развитие общей инфраструктуры государства для разного рода путников.
-
Хадж
Священное паломничество. «Пророка Мухаммеда спросили - „Какое дело является наилучшим?“ Он ответил - „Вера в Аллаха и Его посланника“. Его спросили - „А после этого?“ Он ответил - „Борьба на пути Аллаха“. Его снова спросили - „А после этого?“ Он ответил - „Безупречный хадж“». Из-за веяний истории и времени до современных последователей Неоислама не дошли точные знания о том, как древние мусульмане совершали хадж. А потому Духовным Собранием было решено разделить хадж на три категории, а именно
@@ -149,49 +123,38 @@ book-halifat-contents =
3) Ражулитам малого достатка предписывается совершить хадж на своей планете до святыни, которую установил имам Духовного собрания при колонизации.
-
-
Земная составляющая
-
Ограниченная монархия
Халиф никогда не должен иметь полностью безраздельную власть. Его решения должны обсуждать и осуждаться, если они направлены на личную выгоду, а не на благо государства. А потому лидеры Министерств могут устроить голосование за наложения вета на приказ Халифа. При этом от Совета философии выступает два диалектических лидера.
-
Национализм
Не должно быть различий, которые могут пошатнуть, устои страны. А потому гражданское и этническое должны быть отождествлены. Если кто-то хочет стать ражулитом, гражданином, то он должен отбросить свои культурные, расовые или кланово-национальные устои или привести их под образец устоев государства.
-
Народность
Нужно максимально преодолевать все возможные классовые расслоения, приводя их лишь к необходимому минимуму. Это устанавливает равенство каждого ражулита перед законом, вне зависимости от его рода деятельности, достатка или положения. И нищий, и Халиф должны быть подсудны одинаково.
-
Лациизм
Установление преимущественно светского характера государства. Недопускания религиозного права в государственную судебную систему. А также не полное подчинение образования религиозным канонам.
-
Этатизм
Построение экономической системы, при которой государство будет играть лидирующую роль, что могло бы привести к национализации промышленных предприятий, банков, транспортных систем и прочего. Осуществление этого могло происходить как через реквизицию, так и через конфискацию.
-
Революционность
Недопускание полумер. Если уж выкупать предприятие, то не долу владения, а целиком. Если уж отказываться от расовых устоев, то полностью. При этом с опорой на просвещение, прогресс и реформацию.
book-redspace-contents =
Считается, что редспейс в общем случае невозможно полностью рационализировать и понять. Учёные и исследователи потратили многие годы и многие тысячи жизней на исследование этого пространства, а узнали практически ничего. Тем не менее в данный момент существует научная теория, являющаяся доминирующей в научном мире. Согласно данной теории Редспейс является категорически иным видом пространства. Когда учёные заходят в тупик при своих суждениях, они пытаются сделать шаг в другую сторону и найти вдохновение в другой сфере. В данном случае идеи существования других миров, множественных вселенных или даже астрал из оккультизма вкупе с вероятностным характером квантовой механики навели на мысль, что вполне может существовать иной вид пространства. Редспейс.
-
Итак, по большому счёту Редспейс – это тоже евклидово пространство, как и наше, но при этом, если единичный отрезок в нашем пространстве можно назначить один орт конкретной бесконечно малой длины (или варьируемой малой длины под конкретную задачу), то в пространстве Редспейс ортом выступает функция или же оператор, притом для каждого орта задаётся своя функция. Таким образом каждая точка пространства задаётся не просто координатами и сочетанием нескольких функций. Это было бы сложно, но возможно предсказать, если бы Редспейс, как и наше привычное пространство, имел всего три координатные оси, но различные эксперименты дают основания предположить, что у него куда больше осей, что позволяет внести его в класс предгильбертовых.
-
Учёные могут лишь предполагать количество осей и орты-операторы, которые по ним отложены. Тем не менее уже есть определённые идеи описания процессов данного пространства. Каждая точка является сочетанием операторов квантовой вероятности, импульса, координаты и понятия существования. Неотъемлемым элементом динамики подобных пространств является оператор эволюции. Он воплощает в себе вариант изменения пространства.
-
По вышеизложенным причинам любой объект находящийся в Редспейсе и живущий (существующий) по его законам способен мгновенно поменять свой импульс в определённых пределах с определённой вероятность, совершить мгновенное перемещение с определённой вероятностью, пропасть совсем с определённой вероятность или неожиданно восстановить себя во времени с определённой вероятностью. При этом используемый оператор вероятности оказывается чётным относительно времени, то есть при подстановки отрицательного времени в расчёт (то есть время идущее назад) оказывает, что вероятность всё ещё есть и вполне положительная из-за несходящейся системы и из-за практически повсеместно положительного определённого скалярного произведения векторов различных осей. Таким образом в Редспейсе может восстановиться нечто, существовавшее очень много лет и тысяч лет назад. И наоборот.
book-ships-contents =
(S - Sigma) МКК – маленькие космические корабли.
@@ -204,7 +167,6 @@ book-ships-contents =
3) Персональные МКК. Не превышают пары метров в длину и рассчитаны на перевозку от двух, до пятнадцати гражданских лиц.
-
К военным МКК относят корабли, несущие на себе какое-либо вооружение. Они имеют следующие назначения.
1) Истребитель – Разведчик (ИР). Такие МКК используют для разведки и сбора информации. Они очень маневренны и быстры, но практически не несут на себе какого-либо вооружения и брони.
@@ -213,8 +175,6 @@ book-ships-contents =
3) Истребитель – Бомбардировщик (ИБ). ИБ – это более крупный собрат простого истребителя, он менее манёвренный, при этом он имеет улучшенное бронирование, а также несёт на себе пару мощных боеголовок, способных нанести серьёзный вред крупным судам.
-
-
(T – Teta) СКК – средние космические корабли.
К гражданским СКК относятся.
@@ -223,7 +183,6 @@ book-ships-contents =
2) Космические грузовые корабли, танкеры. Используются для перевозки огромного объёма грузов на очень дальние расстояния.
-
К военным ССК относятся.
1) Фрегаты. Данный тип кораблей слабо вооружён и не способен оказать достойное сопротивление кораблям своего класса. Зачастую он используется для сопровождения некрупных конвоев или в составе крупных боевых групп, в качестве корабля ПВО – ПРО.
@@ -232,16 +191,12 @@ book-ships-contents =
3) Эсминец. Данный тип кораблей считается универсальным и несёт на себе оружие, которое считается самым сильным в своём классе кораблей. Зачастую появляться в составе средних боевых соединений и выполняет роль ударного корабля.
-
-
(O – Omicron) СККК – Среднекрупные космические корабли.
1)Лёгкий крейсер. Это более подвижная и более слабо вооружённая версия простых крейсеров. Предназначенная для сопровождения и охранения более крупных судов, либо же для патрулирования в составе небольшой боевой группы.
2) Авианесущий крейсер. Данный тип кораблей представляет собой небольшие авианосцы несущие на себе некрупные боевые группы. Предназначен для прикрытия более крупных судов.
-
-
(G – Gamma) ККК – Крупный космический корабль.
1) Тяжёлый авианесущий крейсер. Данный тип представляет собой универсальные корабли, предназначенные в основном для уничтожения авианосцев всех классов. Несут авиакрыло равное по численности авиакрылу лёгкого авианосца, и в дополнение к нему многоцелевые или противокорабельные ракеты.
@@ -250,8 +205,6 @@ book-ships-contents =
3) Монитор артиллерийский. Данный тип кораблей является ещё более урезанным вариантом линкоров, по существу являющимся подвижным аналогам орбитальных артиллерийских платформ. Отличаются весьма низкой мобильностью, но компенсирующий это высокой огневой мощью.
-
-
(B – Beta) ТКК – Тяжёлые космические корабли.
1) Линкор. Линкоры — это наиболее мощные артиллерийские корабли, хорошо бронированы, но не слишком подвижны. Предназначены для уничтожения кораблей всех классов, орбитальных сооружений и орбитальной бомбардировке поверхности планет.
@@ -262,14 +215,10 @@ book-ships-contents =
4) Десантный авианосец. Это разновидность тяжелых авианосцев, предназначенная для базирования и десантирования пехотных соединений. Обычно несколько превосходят по габаритам тяжёлые авианосцы.
-
-
(A – Alpha) СТКК – Сверхтяжёлые боевые корабли.
Единственным представителем кораблей данного класса является Дредноут. Дредноут или «суперлинкор». Дредноуты — это самые большие корабли, совмещающие в себе мощь линкора и способности тяжелого авианосца. Обычно в составе всего космического флота одной страны, находится не более двух таких кораблей, поскольку даже постройка одного такого корабля считается сверх затратной, а уж их содержание может обходится в не меньшую сумму, чем затраты на содержание какой-нибудь около столичной планеты.
-
-
ОКК – Особые космические корабли.
1) Исследовательские космические корабли, дальнего действия. Используются для изучения ещё неизученных секторов космоса. Запаса хода, как и полезной нагрузки им хватает на несколько лет. Также они оснащены полноценными лабораториями и иногда несут на себе мелкое вооружение.
@@ -278,16 +227,12 @@ book-ships-contents =
book-zp-contents =
Базовая криптовалюта начисляется за каждую минуту пребывания сотрудника на смене. Учитывается каждая полная минута, все секунды в зачёт не идут. Базовая сумма начисления умножается на коэффициент, который зависит от типа договора, должности сотрудника, назначении станции и цели станции. В случае применения санкции к отделу, коэффициент всех сотрудников отдела отдела признается равным единице.
-
Формула расчета заработной платы за 1 смену -- ЗП = БС х min х Кд х Кр х Кнс х Кцс х Кп х Кш Обнулением или отменой коэффициента признается приравнивание коэффициента к единице. Базовая ставка равна 10 единицам.
-
Коэффициенты по договорам -- Бессрочный– 1,5 Долгосрочный – 1,3 Среднесрочный - 1,1 Краткосрочный – 1,05
-
Коэффициенты по рождению -- Родился на территории ОПЗ – 1,05 Родился на территории корпорации – 1,10 Родился на иных территориях - 1,0
-
Коэффициенты по назначении станции:
Административная станция – 2,0;
Бизнес станция – 1,6;
@@ -298,13 +243,11 @@ book-zp-contents =
Оборонная станция – 1,7;
Транспортная станция – 1,0.
-
Коэффициенты по цели станции:
Отдел напрямую занимается целью станции – 1,5;
Отдел косвенно связан с целью станции – 1,25;
Отдел не занимается целью станции – 1,0.
-
Коэффициенты по профессиям
Повар -- 1
@@ -343,7 +286,6 @@ book-zp-contents =
Интерн -- 1
-
Офицер СБ -- 1.1
Врач -- 1.1
@@ -352,26 +294,22 @@ book-zp-contents =
Психолог -- 1.1
-
Химик -- 1.2
Утилизатор -- 1.2
Атмосферный техник -- 1.2
-
медицинский офицер -- 1.3
Детектив -- 1.3
Учёный -- 1.3
-
Глава персонала -- 1.4
Квартирмейстер -- 1.4
-
Смотритель -- 1.5
Ведущий врач -- 1.5
@@ -382,7 +320,6 @@ book-zp-contents =
Ведущий учёный -- 1.5
-
Старший инженер -- 1.8
Научный Директор -- 1.8
@@ -391,10 +328,8 @@ book-zp-contents =
Глава Службы Безопасности -- 1.8
-
Капитан -- 2.5
-
Коэффициенты штрафов
Нахождение в заключении – 0. Отчет о времени заключения составляет смотритель.
@@ -406,22 +341,18 @@ book-zp-contents =
Гибель на станции или при исполнении должностных обязанностей – 0,2. Факт формируется после окончания смены.
Отстранение от должности и нарушение СРП. При отстранении от должности или нарушении СРП все коэффициенты замораживаются до отдельного разбирательства после окончания смены. По итогам разбирательства итоговая заработная плата рассчитывается отдельно.
-
Гибель
В случае гибели сотрудника и невозможности клонирования его заработная плата выплачивается ближайшим родственникам. Если таковых нет, удерживается в пользу корпорации. В случае возможности клонирования, коэффициент гибели признается равным 0,5. Страхование жизни и здоровья. Во время пребывания на станции каждый сотрудник и посетитель имеет право безвозмездного использования результатами труда других сотрудников станции и находящимися в раздатчиках ценностями (активами, продуктами, товарами). При получении инвалидности по итогу смены, компания назначает выплату на установку замены потерянной сотрудником конечности. По достижению старости компания выплачивает пенсионное вознаграждение - Ежемесячно 30% от среднемесячной заработной платы не работающим пенсионерам; ежемесячно 10% от среднемесячной заработной платы в дополнение к их заработной плате. Среднемесячная заработная плата рассчитывается, как сумма заработной платы за весь период работы, разделенная на количество полных месяцев работы на корпорацию.
-
Прибыль станции
Из результата деятельности станции на конец смены (результат/прибыль работы отдела снабжения) станция удерживает 75%. Квартирмейстер получает 3% от прибыли станции вне зависимости от участия в доставке грузов. Остальная часть распределяется в виде премии между сотрудниками станции, сформировавшими доход. Например, Атмосферный техник создал газ, грузчик отнес его в отдел снабжения, оба делят доход между собой. Второй пример - Утилизаторы притащили на станцию двигатели с обломка, которые были проданы. Утилизаторы делят доход между собой.
-
Растраты
Растратами признаются любое нецелевое использование средств, предоставленных корпорацией. Например, строительство космической техники в то время, когда цель – исследование артефактов. При таком использовании средств станции, виновный лишается всех коэффициентов выше единицы, а результат его деятельности признается собственностью корпорации. В любых нестандартных ситуациях специальная комиссия назначает дополнительные штрафные санкции.
-
Дополнительное премирование
Награждение медалью добавляет 50% к итоговой заработной плате. Быстрое окончание смены добавляет 50% к заработной плате руководителей отделов. Центральное командование корпорации может по своему усмотрению назначить дополнительную премию по итогам смены.
@@ -430,7 +361,6 @@ book-ussp-contents =
Важнейшим управляющим законодательным органом СССП является Политическое бюро Социалистической Партии Союзных планет. В него входят граждане, достигшие наибольшего политического и партийного влияния в составе партии. Обычно в Политбюро входят не очень много членов. В разное время их число колебалось от 5-и до 16-ти. На данный момент в него входят 9 членов. Тартышников А.П. Морроу Д.В., Огнева А.В., Р.Р. Старшинов, Пламя Коллективизма, Вариван’Зен, Пульт Валливс, Ровкуд Красноусая, Укар’вар Дари.
-
Президиум и Советы
Первые отцы революции боялись, что в будущем найдутся индивидуумы, которые, преисполнившись хитростью, будут делать вид, что верны идеалам коммунизма, а на деле проникнут в верха власти, узурпируют её и отбросят страну назад от идеалов коммунизма. Они не могли придумать, как не пустить таких «товарищей» во власть. Однако, было найдено решение, как их полномочия возможно ограничить.
@@ -439,14 +369,12 @@ book-ussp-contents =
Президиум занимается обсуждением законопроектов, выдвигаемых Политбюро, созданием списка замечаний, просьб по уточнению. Кроме того, Президиум имеет право вето на ввод какого-либо распоряжения или закона Политбюро. В возможностях Президиума есть право на собственную разработку законов и постановлений, которые также могут быть запрещены или исправлены.
-
Народные секретариаты и Генеральный Секретарь
Для создания дополнительной объединяющей граждан силы изначально формировался культ личности Генерального Секретаря, члена Политбюро, выбранного в качестве главы государства «первого среди равных» и одобренного Президиумом. Он должен был стать особой фигурой, сочетающей в себе лицо законодательной власти от Президиума, Политбюро и исполнительной власти Секретариатов. На данный момент роль генсека исполняет Р.Р. Старшинов.
Исполнительная власть, коей управлял и контролировал генсек, была сосредоточена в двенадцати народных секретариатах, которыми руководят нарсеки (народные секретари). Секретариаты осуществляют свою власть через комитеты разного уровня - Сисисполкомы, Планисполкомы, Горисполкомы и Райисполкомы (Системные, планетарные, городские и районные исполнительные комитеты соответсвенно). Комитеты занимаются местным надзором за исполнением всех постановлений и законодательной базы государства в районах своего действия. Очень часто разные комитеты размещаются в одном здании, которое граждане чаще всего так и зовут — Исполкомом. Как правило, милиция, прокуратура и ВГБ базируются в отдельных зданиях.
-
Суды и главное управление красных комиссаров
Судебная система СССП делится на две ветви - Суды гражданских дел и Главное Управление Красных Комиссаров (ГУКК).
@@ -472,7 +400,6 @@ book-mirt-contents =
book-gior-contents =
ГИОР (Галактическая Инициатива Объединённых Рас) – это исполнительный комитет межрасового надгосударственного общения, сформированный ОПЗ, после обнаружения первых инопланетных рас (Унатхов, Дворфов и Ниан), идейно ГИОР пришла на замену ООН, организации, некогда созданной на земле. По сути, целью ГИОР является урегулирование разнообразных конфликтов в галактике, собрание её участниц на заседаниях, которые проводятся раз в 5 лет, выдвижение каких, либо резолюций, а также контроль за соблюдением принятых законов.
-
Сама ГИОР как-бы разделена ещё на 4 организации, которые отвечают за урегулирование конкретных ситуаций.
Галактическая Инициатива Объединённых Рас и Межрасового Урегулирования (ГИОРиМУ)
@@ -483,13 +410,10 @@ book-gior-contents =
Совет Безопасности Галактической Инициативы Объединённых Рас (СовБезГИОР)
-
1) Галактическая Инициатива Объединённых Рас и Межрасового Урегулирования (ГИОРиМУ), является достаточно старым формированием, и именно она изначально и носила название ГИОР, и только позже, после формирования других государств она была переименована в ГИОРиМУ. Целью данной организации является урегулирование вопросов касаемых межрасового общения, а также отслеживание за соблюдением ОПРС (Общие Права Разумных Существ), важным уточнением будет то, что при нарушении ОПРС каким-либо государством или корпорацией, эту ситуацию будет рассматривать Всегалактический Суд Разумных Существ.
-
В состав данной организации входят все расы галактики, интересы которых представляют их представители. От каждой расы может выдвигаться несколько представителей, и их число зависит от численности самой расы (1 представитель на 10 миллиардов представителей этой расы). Из-за того, что точное число представителей какой-либо расы подчитать достаточно сложно, общим решением принято округлять число представителей в меньшую сторону. Также важным уточнением будет, что ГИОРиМУ является надгосударственным формированием, а значит, что представители рас могут являться гражданами разных государств.
-
В состав ГИОРиМУ входят.
Люди – порядка 71 представителей
@@ -512,10 +436,8 @@ book-gior-contents =
Вульпканины – порядка 60 представителей
-
2) Галактическая Инициатива Объединённых Рас и Государственного Урегулирования (ГИОРиГУ), появилась после обнаружения ОПЗ Империи Миртана, а также после откола СССП и СНК от ОПЗ. Целью ГИОРиГУ является урегулирование всех межгосударственных вопросов, также ГИОРиГУ обладает контингентом оранжевых касок (OH – Orange Helmets), которые занимаются поддержанием галактического порядка, путём принудительных мер и действий. Также на заседаниях ГИОРиГУ, могут подписываться пакты, которые обязательны к исполнению всеми государствами, подписавшими оные. От каждого из государств в ГИОРиГУ выступает по одному представителю.
-
В состав ГИОРиГУ входят.
ОПЗ (Объединённое Правительство Земли)
@@ -534,17 +456,14 @@ book-gior-contents =
Халифатский Божественный Конгломерат
-
В качестве наблюдателей в ГИОР находятся.
Империя Миртана
Корпорации Большой Пятёрки
-
3) Галактическая Инициатива Объединённых Рас и Корпоративного Урегулирования (ГИОРиКУ), была создана относительно недавно в 2781 году, в ответ на разрешение, выданное правительством ОПЗ, корпорациям на освоение регионов фронтира. Занимается контролем за исполнением принятых резолюций и соглашений, а также подписанием новых. При этом ГИОРиКУ имеет огромную когорту своих представителей, которые постоянно находятся в разъездах по всей галактике и занимаются отслеживанием нарушений.
-
4) Совет Безопасности Галактической Инициативы Объединённых Рас (СовБезГИОР), самая «молодая» организация в составе ГИОР. Занимается тем, что отслеживает всевозможные угрозы галактике, а также старается их предотвратить. Самой первой и на данный момент единственной задачей является отслеживание ситуации с ксеноморфами, а также всевозможная поддержка государств, которые занимаются урегулированием данной проблемы. Постоянными членами СовБезГИОР) являются ОПЗ и Империя Миртана (не смотря на статус наблюдателя в заседаниях самой ГИОРиГУ, с недавних пор Империя Миртана обладает особым правовым статусов в СовБезГИОР из-за того, что именно она является щитом галактики от угрозы ксеноморфов).
Также в состав СовБезГИОР входят все остальные государства и организации, которые входят в ГИОРиГУ
@@ -615,62 +534,50 @@ book-vitz-contents =
Два лёгких космических судна сделанных на манер истребителей-Разведчиков ОПЗ (машина класса «Комар» по документам Vitezstvi), но с облегчённой бронёй, большей скоростью и более слабыми орудиями. Пара состоит из ведущего и ведомого. Предназначена для скрытной авиаразведки. Часто авиапары посылают на простые задания и ставят в них новичков, чтобы они освоились перед настоящими опасными делами.
-
2) Истребительная авиапара
Два лёгких космических судна сделанных на манер истребителей-перехватчиков ОПЗ (машина класса «Лилия» по документам Vitezstvi). Пара состоит из ведущего и ведомого. Предназначена для патрулирования и охраны. Часто в пару к опытному ведущему-ветерану ставят ведомого-юнца, чтобы быстрей обучить его.
-
3) Истребительное звено
Пять лёгких машин, аналогичных используемых в соответствующей авиапаре. Подразделение включает в себя командира звена и четырёх ведомых. Предназначена для охраны транспортных судов, для поддержки бомбардировочных соединений, а также для изматывающих налётов на сухопутные силы. В звеньях служат уже полноценные состоявшиеся лётчики-истребители.
-
4) Разведывательное звено
Четыре машины, аналогичные используемым в соответствующей паре. Чаще всего разведчики равны друг другу по званию и среди них не выделяют командира, а лишь ответственного за задание. Данное подразделение предназначено для проведения разведки в зоне боевых действий, где всегда можно попасть под обстрел и погибнуть, а потому в этих звеньях служат лишь опытные пилоты, чья выживаемость всегда на высоте.
-
5) Легкобомбардировочное звено
Шесть машин, аналогичных по строению истребителям-бомбардировщикам ОПЗ (машина класса «Чарли» по документам Vitezstvi). В звено входят командир звена, зам.командира звена и четыре ведомых. Подразделение предназначено для атаки на крупные суда, для штурмовки планетарных сил, для уничтожения планетарных объектов, для отвлечения внимания ПВО и истребителей. Сюда поступают уже набравшиеся опыта в авиапарах истребители. Они быстро проходят курс обучения на бомбардировщика, стремительно приноравливаются к новому делу и сразу готовы к бою.
-
6) Тяжелобомбардировочное звено
Три машины, созданные на базе истребителей-бомбардировщиков ОПЗ. У них укреплена броня, увеличен размер и количество перевозимого бомбового вооружения, а также увеличена огневая мощь (машина класса «Барон» по документам Vitezstvi). При этом сильно страдает скорость и манёвренность. Подразделение не имеет командира, только ответственного за задание. Используется для поражения крупных судов, разрешения линий планетарных обороны, а также объектов производства, инфраструктуры или военных объектов. В эти подразделения идут служить только самые смелые пилоты-бомбардировщики, ибо полёт в медленной машине во многом зависит от качества стрелков и поддержки.
-
7) Истребительная эскадрилья
Состоит из трёх истребительных звеньев (15 машин «Лилия»). Предназначена для защиты караванов, крупных судов, а также для перехвата бомбардировщиков и для достижения превосходства в воздухе.
-
8) Разведывательная эскадрилья
Состоит из трёх разведывательных авиапар и двух разведывательных звеньев (14 машин «Комар»). Предназначена для проведения полного комплекса разведывательных мероприятий в зоне боевых действий.
-
9) Легкобомбардировочная эскадрилья
Состоит из трёх легкобомбардировочных звеньев (18 машин «Чарли»). Предназначена для ковровых бомбардировок, для массивных авиаударов, для уничтожения боевого порядка крупных судов в космосе.
-
10) Тяжелобомбардировочная эскадрилья
Состоит из трёх тяжелобомбардировочных звеньев (9 машин «Барон»). Предназначены для крупномасштабной стратегической бомбардировки на крупные планетарные объекты, а также для уничтожения купных космических судов.
-
11) Истребительный авиаполк
Состоит из одной разведывательной эскадрильи, пяти истребительных, а также ещё одного отдельного разведывательного звена и одного отдельного истребительного звена (всего 98 машин, из которых 18 «Комаров» и 80 «Лилий»). Предназначены для подавления и уничтожения всего малого летательного в зоне действия полка.
-
12) Бомбардировочный авиаполк
Состоит из одной разведывательной эскадрильи, одной истребительной, трёх легкобомбардировочных и двух тяжелобомбардировочных (всего 101 машина, из которых 14 «Комаров», 15 «Лилий», 54 «Чарли» и 18 «Баронов»). Предназначены для уничтожения планетарных линий фронта, а также для поражения крупных флотов.
-
13) Специальный авиаполк
Такие авиаполки формируют под требования командира авиаполка. В них встречаются всевозможные вариации, которые становятся необходимостью при применении определённых тактик или при необходимости следовать определённому сценарию сражений.
@@ -687,7 +594,6 @@ book-gefest-contents =
Как оказалось, на фронтире есть не только плазма, но множество артефактов, оставленные некогда великой цивилизацией, изучением которых занимаются другие корпорации.
-
По прибытии на фронтир Гефест начал разворачиваться, и активно начал строить маленькие колонии-поселения. Все дома были построены из специальных модульных блоков, части которых помещаются в стандартные грузовые контейнеры. Некоторые сооружения представляют из себя сломанные шаттлы, пострадавшие в результате работы. Все колонии выполняют строго определенную работу - добычу ресурсов, выращивание пищи, производство лекарств и удобрений. Такая система была введена для того, чтобы поселения изначально не были самодостаточными и зависели от других колоний и центрального управления. Однако, во всех колониях должен быть пункт охраны и хотя бы один врач и мэр. Количество колонистов на один населенный пункт не превышает сотни.
С течением времени начали появляться новые жители-колонисты, которые были вынуждены работать на Гефест, у них просто не было выбора и средств на то чтобы выбраться с фронтира. Через несколько поколений среди молодежи стали появляться анти-корпоративные настроения основанные на желании выбраться из этого корпоративного рабства.
@@ -796,27 +702,22 @@ book-saibasan-contents =
Заводы представляют собой крупные автоматические почти что конвейерные линии. Автоматически происходит всё - подготовка подложек, нанесение резистов, экспонирование, эпитаксия, металлизация и многое другое. Из-за этого все этапы производства находятся в чистых зонах, и им требуются сложные системы очистных сооружений. Таким образом большая часть заводского персонала – это инженеры тех. обеспечения коммуникаций, а также инженеры выходного контроля.
-
Дизайн центры
Как правило — это небольшие офисы, расположенные в самых разных местах. В них работают инженеры-проектировщики схемотехники. Они занимаются разработкой схем по заказам различных предприятий и государств. Проектировка происходит, как полностью сквозная, с созданием полностью своей уникальной микросхемы, так и использующая готовые технологические шаблоны одной из имеющихся сборочных линий.
-
Технологически лаборатории
Данных лабораторий не много. В них учёные-материаловеды и инженеры-технологи проводят исследования и эксперименты над различными параметрами и показателями, варьируя их и добиваясь куда лучших результатов характеристик! (на самом деле они достигают главной истины любого технолога - «Не ТРОГАЙ, МАТЬ ТВОЮ, НАСТРОЙКИ, А ТО Я ТЕБЕ БОШКУ РАЗНЕСУ!»
-
Административное отделение
В это отделение входят бухгалтерия, директорат корпорации. Тут же отдел приёма заказов, подразделение спикеров и, как ни странно, информационная безопасность, которая на самом деле напрямую связана с директоратом.
-
Взаимодействие с обществом
Ни у кого не было уверенности, что дочерняя компания корпорации Cybersun Industries, сможет быть чем-то помимо вспомогательного подразделения, созданного для уменьшения расходов на электронику. Но в итоге это, хоть и дочерняя, но крупная компания-производитель электроники, известная по всей изведанной Галактике. Приборы с чипами Saibasan – это гарантия качества и надёжности.
-
Активы корпорации
По большому счёту Saibasan обеспечивает электроникой (по примерноым расчётам) 4 сектора Фронтира, 2 сектора ОПЗ, 2 сектора Умпорской Федерации и 1 Сектор СНК. Посему у корпорации 45 заводов, 121 дизайн-центр, 9 технологических лабораторий и 10 административных отделений, одно из которых главное.
book-unath-ptone-contents =
@@ -826,7 +727,6 @@ book-unath-ptone-contents =
При менее формальном общении с семьей, друзьями и подчиненными, унатхи могут быть крайне тактильными. Для более хрупко сложенных рас, объятия, толчки и хлопки по телу могут быть чересчур сильными, и не каждому будет приятно ощущение когтей на коже. Ассимилируясь в общество, где мало сородичей, унатхи отучаются от подобных привычек, а вот навещая Моргха Унатх, путешественнику стоит приготовиться к такому отношению.
-
Одежда и Украшения
Традиционная одежда унатхов обычно крайне открытая, с менее строгими стандартами пристойности, чем людская. Текстура материала играет меньшую роль, чем цвет, а в застёжках ценится прочность. Богатая одежда, в противоречие стандарту, очень тёплая и основана на большом количестве замысловато перекрывающих друг друга слоёв. В местах с прохладным климатом, тёплая одежда наслаждается значительно более утилитарным отношением и резко контрастирует с тропическими аналогами своей обыденностью.
@@ -849,7 +749,6 @@ book-unath-ptwo-contents =
С распространением ТрансЛита, к доступной людям части унатхского наследия присоединились кино и литература. Среди рассказываемых унатхами историй выделяется много отличных от человеческих архетипов. Одним из них являются ссен'гха — мореплаватели времён Золотого Века Морей, исследователи, послы, шпионы. Рассказами об их приключениях изобилует как литература унатхской современности, так и популярная культура. Человеческому наблюдателю будет удобно думать о ссен'гха, как об унатхских аналогах рыцарей или ковбоев — в той роли, которую они играют в культурном сознании общества.
-
Война и Мир
По окончании Последней Войны в обществе унатхов одно из лидирующих мест заняли антимилитаризм и пацифизм. Всем было ясно одно — подобное не должно повториться никогда. Многие участники Кшеса Д’тхун, федерации-предшественника Унатхской Автономии, начали уменьшать свои армии, полагаясь на сеть тесных торговых и дипломатических связей для урегулирования конфликтов. С раннего возраста унатхам объясняли ужасы войны, и обучали способам решать конфликты без насилия. Молодым унатхам и унати показывали, что сотни лет мира привели к совместному процветанию, и поэтому у каждого разумного существа есть моральная обязанность не допустить войны. Такая практика сохранилась с незначительными изменениями до наших дней, но полтысячи лет назад ее популярность пошатнулась.
@@ -886,7 +785,6 @@ book-scaf-contents =
3) Внешний слой. Он исполняет больше эстетическую функцию. Он скрывает внутренние неровности, трубки и крепления. Кроме того, именно на этот слой наносится краска, которая позволяет разделять EVA скафандры по типам - тюремный, аварийный и т.д.
-
Скафандры специалистов по работе в открытом космосе
Следующие итерацией развития скафандров после достижения пределов серией EVA стала разработка принципиально новой серии скафандров. И первым в серии стал скафандр для работы в открытом космосе. Это было совершенно необходимо для строительство новых космических объектов прямо в космосе, для проведения диагностики внешних покровов космических объектов, а также для прочих работ. Скафандр конструировали таким образом, чтобы погасить большую часть вероятных рисков космоса. Из-за этого скафандр насчитывал четыре слоя
@@ -909,7 +807,6 @@ book-mbsone-contents =
В результате повторного эксперимента новый шаттл снова пропал. Стало ясно, что это не ошибка и началась новая «эпоха» скрупулёзных тестов, которые не давали результатов. Но через год, к радости инженеров, второй потерянный шаттл вернулся. Записи «черного ящика» показали, что взаимодействие БС-модуля двигателей с волнами квантовой вероятности повлияли также и на вероятностные процессы в электронике шаттла и особенно в модуле «Маяк-01», что привело не к точной настройке, а к большей нестабильности, что усугубило проблему.
-
Суперкомпьютер «Маяк-02»
Выяснилось, что для таких задач никакого модуля не хватит. В любом случае размещение его на шаттле приводит к плачевным последствиям. Постепенно улучшая систему и наращивая расчётную мощность, увеличивая надёжность и добавляя системы, препятствующие искажению вероятностных волн, инженеры превратили модуль в целый суперкомпьютер «Маяк-02».
@@ -928,7 +825,6 @@ book-mbsone-contents =
Провал эксперимента подал идею создания отправляемого спутника-маяка.
-
Спутник «Маяк-03»
На помощь пришли промышленные квантовые компьютеры. Они позволили упростить вычисления, производимые суперкомпьютером, хотя и делали их куда менее точными. При этом новый модуль требовал на много меньше энергии, был сложен в производстве, но, как ни странно, сравнительно дешёвым.
@@ -945,19 +841,16 @@ book-mbstwo-contents =
Следующая итерация, «Маяк-05», получила сложный вычислительный модуль. Который был на самом деле переработанным модулем «Маяк-01», но с технологиями квантовой электроники. Новый модуль позволил «вытягивать» шаттлы из Блюспейс пространства на некотором небольшом расстоянии от себя (с погрешностью).
-
Установка «Маяк-06»
Определённая кульминация серии маяков стала, когда было решено объединить суперкомпьютер «Маяк-02», который переработали, сделав дешевле, быстрей и энергоэффективней, спутник «Маяк-03» и искажатель «Маяк-05». В результате вышла крупная и дорогая установка «Маяк-06», которая давала возможность вычислять прыжки для нескольких шаттлов, а также принимать прилетающие шаттлы и делать всё так, чтобы многие потоки шаттлов между собой не врезались. Это наиболее современная система, устанавливаемая на космических объектах, станциях, верфях, портах.
-
Искажатель «Маяк-07»
На данный момент это последняя разработанная итерация технологии. Это громадная и крайне мощная версия искажателя «Маяк-05», совмещённая с переработанным суперкомпьютером. Особенностью его является то, что она «вытягивает» объекты не в радиусе, а вытянутой полосе. Это позволило создать установку, способную реализовывать таможенный контроль на границе секторов, заставляя все шаттлы перемещаться к таможенно-пограничной станции.
Особенностью выступает то, что на длину полосы «вытягивания» влияют самые разны параметры, а потому порой она сокращается или удлиняется. Это даёт некоторое пространство для реализации возможностей различных челноков, подпольных организаций, террористов, контрабандистов и товарищей с чёрного рынка.
-
Искажатель «Маяк-08»
Искажать «Маяк-04» имел и иной путь развития, нежели выведение судов из БС пространства к самому маяку на некоторое расстояние. Новая модель была оснащена куда более скромным расчётным модулем, менее чувствительными сканерами, но большей мощностью. Кто-то с иронией считал, что такая модель только и способна, что вытягивать к себе линкоры. Остальным объектам просто не хватило бы энергии, чтобы быть точно замеченными. Но идея изобретателей была не в этом. Данный маяк был способен притягивать к себе высокоэнергетические объекты. То есть субстанции. Которые и без БС-модуля имели огромный отклик в пространстве энергий. Например, сбежавшие из-под контроля сингулярности. Таким образом «Маяк-08» стал серьёзным ответом всем тем обществам, которые ежегодно и ежемесячно твердили об отказе в использовании сингулярных двигателей по причине существования вероятности аварии с их побегом и дальнейшим прилётом непойми куда и созданием ещё большей аварии. Теперь сингулярности можно было ловить.
@@ -966,32 +859,26 @@ book-implants-contents =
Во время решения ряда проблем, связанного с секретностью, доступом и безопасностью руководство пришло к выводу, что в конкретных частных, но порой регулярно встречающихся ситуациях ни в коем случае нельзя полагаться ни на какое снаряжение. И причина этому весьма проста - снаряжение можно снять. То есть в спешке, по небрежности или под воздействием злого умысла сотрудник может утерять нечто важное. Чтобы преодолеть эту сложность руководство NT учредило грант на создание подкожных имплантов, способных хоть в малой степени заменить некоторые виды снаряжения.
-
Имплант трекера
Данный имплант устанавливается в грудную клетку неподалёку от сердца. Сердце является мышцей, которая постоянно пребывает в движении. А от того постоянно генерирует поверхностное напряжение, которого хватает на поддержание работы импланта. Помимо системы зарядки от мышцы имплант имеет антенну-передатчик, которая при каждом движении сердечной мышцы генерирует сигнал. Сигнал достигает антенн системы внутренней связи объекта НТ, а затем АЛУ (Арифметическо-Логическое устройство) при помощи Фурье-преобразований устанавливает положение импланта и передаёт данные на сервер. Таким образом трекер – это система локального позиционирования, но под кожей. Было бы глупо, если бы при остановке сердца от, скажем, инфаркта или прочих неприятных ситуаций имплант вышел из строя. А потому в него встроек небольшой аккумулятор, продолжающий работу импланта после тревожного использования.
-
Имплант света
Имплант света представляет собой небольшой, но достаточно мощный светодиодный фонарик на аккумуляторе, и устанавливается в руку. Очевидной проблемой может стать подзарядка аккумулятора, но решение подсказали древние фонарики тысячелетней давности с рычажной подзарядкой. Но в случае импланта рычагом для подзарядки являются мышцы. Носитель может совершить несложные движения рукой и подзарядить батарею своего фонарика, что делает имплант крайне полезным и долговечным.
-
Имплант грустного тромбона
Имплант устанавливается в район диафрагмы. Имеет в себе небольшой аккумулятор, сторожевой таймер, небольшой чип логики и динамик. При дыхании происходит периодическое расширение и сужение диафрагмы, что совершенно не влияет на имплант. Если же диафрагма перестаёт, то начинается отсчёт секунд на сторожевом таймере. Если время превышает среднее максимальное время задержки дыхания, то сторожевой таймер переполняется и активирует чип, заставляя динамик издать грустный тревожный звук.
-
Имплант водокодера
Встраивается в горло. Имплант включает в себя матрицу подвижных наночастиц, которые способные перестаиваться, «нарастая» и изменяя параметры голосовых связок из-за чего они начинают звучать иначе. Для регулировки требуется итерационное взаимодействие с подкожными регуляторами частоты и тембра. А именно требуется повернуть регулятор и тут же что-то произнести, дабы проверить звучание.
-
Имплант хонк
И кто-то же придумал идею, что ряду сотрудников понадобится, возможно, издать громкий предупреждающий звук в ситуации, когда, скажем, коридор заполнен стоящими сотрудниками, мешающими пройти. Для этого был разработан имплант он, работающий аналогично импланту света. Четырёх-шести сгибаний руки хватит, чтобы зарядить батарею импланта и издать громкий предупреждающий звук.
-
Mindshield (майндшилд или имплант защиты разума) – имплант защиты разработки корпорации NanoTrasen, позволяющий нивелировать гипнотическое или психологическое воздействие на носителя.
Имплант представляет из себя вычислительный чип, микросканер ЭЭГ и сложную сеть искусственный нейронов, а также чип, создающий искусственное увеличение лояльности к корпорации NanoTrasen. Имплант является сложным в производстве, поэтому даже не весь состав станции удостоен быть носителем данного импланта, впрочем, со временем долгих исследований и модификаций, учёным удалось добиться того, что устанавливать его стало сравнительно просто любому обученному врачу при помощи имплантера стандартного образца. Использование искусственных нейронов позволяет как сканировать активность лобной доли головного мозга, выявляя гипноз или психологическое воздействие, так и стимулировать лобную кору, чтобы вывести мозг в нормальное состояние и избавиться от гипноза или психологического воздействия. Данный имплант постоянно сканирует лобную долю носителя, точно соотносит отклонения от нормы, достигая точности нивелирования гипноза или психологического воздействия на 99%. Работает, если воздействие на носителя протекает малое количество времени, иначе действия гипноза входит в нормальное состояние мозга, перестраивая структура мозга, чьи нейронные сети постоянно видоизменяются, и вывести носителя в первоначальное состояние используя имплант невозможно.
diff --git a/Resources/Locale/ru-RU/deltav/interaction/interaction-popup-component.ftl b/Resources/Locale/ru-RU/deltav/interaction/interaction-popup-component.ftl
index 82ef324f73..ccf1d2051a 100644
--- a/Resources/Locale/ru-RU/deltav/interaction/interaction-popup-component.ftl
+++ b/Resources/Locale/ru-RU/deltav/interaction/interaction-popup-component.ftl
@@ -1,6 +1,5 @@
### Interaction Popup component
-
## Petting animals
petting-success-nukie-mouse = Вы гладите { THE($target) } по { POSS-ADJ($target) } маленькая кроваво-красная мышиная головка синдиката.
diff --git a/Resources/Locale/ru-RU/deltav/prototypes/catalog/cargo/cargo-food.ftl b/Resources/Locale/ru-RU/deltav/prototypes/catalog/cargo/cargo-food.ftl
index c121c2100f..c6ed924004 100644
--- a/Resources/Locale/ru-RU/deltav/prototypes/catalog/cargo/cargo-food.ftl
+++ b/Resources/Locale/ru-RU/deltav/prototypes/catalog/cargo/cargo-food.ftl
@@ -1,5 +1,4 @@
-ent-FoodCrateKvassTank = { ent-CrateFoodKvassTank }
- .desc = { ent-CrateFoodKvassTank.desc }
+
ent-FoodDonkpocketSavory = { ent-CrateFoodDonkpocketSavory }
.desc = { ent-CrateFoodDonkpocketSavory.desc }
ent-FoodDonkpocketSweet = { ent-CrateFoodDonkpocketSweet }
diff --git a/Resources/Locale/ru-RU/flavors/flavor-profiles.ftl b/Resources/Locale/ru-RU/flavors/flavor-profiles.ftl
index 50ed96a54e..86262cf77b 100644
--- a/Resources/Locale/ru-RU/flavors/flavor-profiles.ftl
+++ b/Resources/Locale/ru-RU/flavors/flavor-profiles.ftl
@@ -264,7 +264,6 @@ flavor-complex-pilk = как сладкое молоко
# Medicine/chemical-specific flavors.
-
## Generic flavors.
flavor-complex-medicine = как лекарство
diff --git a/Resources/Locale/ru-RU/gravity/gravity-generator-component.ftl b/Resources/Locale/ru-RU/gravity/gravity-generator-component.ftl
index 22190b51ea..48e571d333 100644
--- a/Resources/Locale/ru-RU/gravity/gravity-generator-component.ftl
+++ b/Resources/Locale/ru-RU/gravity/gravity-generator-component.ftl
@@ -1,6 +1,5 @@
### Gravity Generator
-
## UI
gravity-generator-window-title = Генератор гравитации
diff --git a/Resources/Locale/ru-RU/info/info-window.ftl b/Resources/Locale/ru-RU/info/info-window.ftl
index 4d45a42bde..722956d5da 100644
--- a/Resources/Locale/ru-RU/info/info-window.ftl
+++ b/Resources/Locale/ru-RU/info/info-window.ftl
@@ -1,6 +1,5 @@
### Info Window
-
## General stuff
ui-info-title = Информация
diff --git a/Resources/Locale/ru-RU/interaction/interaction-popup-component.ftl b/Resources/Locale/ru-RU/interaction/interaction-popup-component.ftl
index 13a6b73115..3a91272284 100644
--- a/Resources/Locale/ru-RU/interaction/interaction-popup-component.ftl
+++ b/Resources/Locale/ru-RU/interaction/interaction-popup-component.ftl
@@ -1,6 +1,5 @@
### Interaction Popup component
-
## Petting animals
petting-success-generic = Вы гладите { $target } по голове.
diff --git a/Resources/Locale/ru-RU/interaction/verbs/noop.ftl b/Resources/Locale/ru-RU/interaction/verbs/noop.ftl
index 73b6b4703c..76c1ae97e2 100644
--- a/Resources/Locale/ru-RU/interaction/verbs/noop.ftl
+++ b/Resources/Locale/ru-RU/interaction/verbs/noop.ftl
@@ -21,8 +21,8 @@ interaction-PetAnimal-success-others-popup = { interaction-Pet-success-others-po
interaction-KnockOn-name = Постучать
interaction-KnockOn-description = Постучите по цели, чтобы привлечь к себе внимание.
interaction-KnockOn-success-self-popup = Вы постучали по { THE($target) }.
-interaction-KnockOn-success-target-popup = { THE($user) } стучит по вам.
-interaction-KnockOn-success-others-popup = { THE($user) } стучит то { THE($target) }.
+interaction-KnockOn-success-target-popup = { THE($user) } стучит по тебе.
+interaction-KnockOn-success-others-popup = { THE($user) } стучит по { THE($target) }.
interaction-Rattle-name = Трясти
interaction-Rattle-success-self-popup = Вы трясёте { THE($target) }.
interaction-Rattle-success-target-popup = { THE($user) } трясёт вас.
diff --git a/Resources/Locale/ru-RU/language/commands.ftl b/Resources/Locale/ru-RU/language/commands.ftl
index 67d0517e0e..7c01700d65 100644
--- a/Resources/Locale/ru-RU/language/commands.ftl
+++ b/Resources/Locale/ru-RU/language/commands.ftl
@@ -1,28 +1,34 @@
command-list-langs-desc = Перечислите языки, на которых сущность может говорить.
command-list-langs-help = Исп: { $command }
+
command-saylang-desc = Отправьте сообщение на определенном языке. Чтобы выбрать язык, вы можете использовать либо название языка, либо его позицию в списке языков.
-command-saylang-help = Исп: { $command } <имя языка> <текст>. Пример: { $command } GalacticCommon "Привет мир!". Пример: { $command } 1 "Привет мир!"
+command-saylang-help = Исп: { $command } <имя языка> <текст>. Пример: { $command } TauCetiBasic "Привет мир!". Пример: { $command } 1 "Привет мир!"
+
command-language-select-desc = Выберите язык, на котором в данный момент будет говорить существо. Вы можете использовать либо название языка, либо его позицию в списке языков.
-command-language-select-help = Исп: { $command } <имя языка>. Пример: { $command } GalacticCommon
+command-language-select-help = Исп: { $command } <имя языка>. Пример: { $command } TauCetiBasic
+
command-language-spoken = Говорит:
command-language-understood = Понимает:
command-language-current-entry = { $id }. { $language } - { $name } (текущий)
command-language-entry = { $id }. { $language } - { $name }
+
command-language-invalid-number = Номер языка должен быть между 0 и { $total }. Ну либо используйте имя языка.
command-language-invalid-language = Язык { $id } не существует или им нельзя говорить.
# toolshed
command-description-language-add = Добавляет новый язык к сущности. Два последних аргумента указывают, сможет ли она его произносить/понимать. Пример: 'self language:add "Canilunzt" true true'
-command-description-language-rm = Удаляет язык из передаваемого объекта. Работает аналогично language:add. Пример: 'self language:rm "GalacticCommon" true true'.
+command-description-language-rm = Удаляет язык из передаваемого объекта. Работает аналогично language:add. Пример: 'self language:rm "TauCetiBasic" true true'.
command-description-language-lsspoken = Выводит список всех языков, на которых может говорить объект. Пример: 'self language:lsspoken'
command-description-language-lsunderstood = Содержит список всех языков, которые может понимать сущность. Пример: 'self language:lssunderstood'
+
command-description-translator-addlang = Добавляет язык переводчику. Смотрите language:add для деталей.
command-description-translator-rmlang = Удаляет целевой язык из переводчика. Смотрите language:rm для деталей.
-command-description-translator-addrequired = Добавляет новый необходимый язык к переводчику. Пример: 'ent 1234 translator:addrequired "GalacticCommon"'
-command-description-translator-rmrequired = Удаляет необходимый язык из переводчика. Пример: 'ent 1234 translator:rmrequired "GalacticCommon"'
+command-description-translator-addrequired = Добавляет новый необходимый язык к переводчику. Пример: 'ent 1234 translator:addrequired "TauCetiBasic"'
+command-description-translator-rmrequired = Удаляет необходимый язык из переводчика. Пример: 'ent 1234 translator:rmrequired "TauCetiBasic"'
command-description-translator-lsspoken = Выводит список всех языков на которых говорит переводчик. Пример: 'ent 1234 translator:lsspoken'
command-description-translator-lsunderstood = Выводит список всех понятных языков для переводчика. Пример: 'ent 1234 translator:lssunderstood'
command-description-translator-lsrequired = Выводит список всех необходимых языков для переводчика. Пример: 'ent 1234 translator:lsrequired'
+
command-language-error-this-will-not-work = Не сработает.
command-language-error-not-a-translator = Сущность { $entity } не переводчик.
diff --git a/Resources/Locale/ru-RU/language/languages.ftl b/Resources/Locale/ru-RU/language/languages.ftl
index 9a200b6f81..56a4212fad 100644
--- a/Resources/Locale/ru-RU/language/languages.ftl
+++ b/Resources/Locale/ru-RU/language/languages.ftl
@@ -1,52 +1,97 @@
language-Universal-name = Универсальный
language-Universal-description = Что ты такое?
-language-GalacticCommon-name = Общегалактический
-language-GalacticCommon-description = Обычно используется для межвидового общения и официальных целей.
+
language-Bubblish-name = Пузырчатый
language-Bubblish-description = Язык слаймолюдов. Это смесь булькающих звуков и хлюпов. Человеку очень трудно говорить без механической помощи.
+
language-RootSpeak-name = Песнь корней
language-RootSpeak-description = Странный шелестящий язык, на котором говорят дионы.
+
language-Nekomimetic-name = Некоязык
language-Nekomimetic-description = Для стороннего наблюдателя этот язык представляет собой непонятную смесь ломаного японского. Для фелинидов он каким-то образом понятен.
+
language-Draconic-name = Синта'унати
language-Draconic-description = Общий язык унатхов с преобладающими шипящими звуками.
+
language-SolCommon-name = Солнечный язык
-language-SolCommon-description = Общий язык, на котором говорят обитатели солнечной системы.
+language-SolCommon-description =
+ Общий язык Солнечного Альянса берёт свои корни из мандаринского диалекта китайского языка и эволюционировал как официальный язык Солнечного Альянса, при этом чиновники стремились объединить его в единый общий язык.
+ На нём говорят государственные служащие, его преподают в школах, и его используют те, кто либо испытывает чувство национальной гордости за Альянс, либо оказался под влиянием его культуры.
+
+language-TauCetiBasic-name = Общегалактический
+language-TauCetiBasic-description = Духовный преемник эсперанто, созданный в 2404 году в системе Тау Кита её интеллектуалами.
+ Его уникальный, полностью настроенный алфавит и структура позволяют говорить на нем даже большинству инопланетных видов.
+ Это официальный язык Тау Кита, который набирает все большую популярность в дипломатических кругах и среди универсалистов по всему человеческому пространству.
+
+language-Tradeband-name = Торговый язык
+language-Tradeband-description =
+ Происходящий от латинских и романских языков старой Земли, Торговый остается основным языком высшего класса человечества.
+ Язык звучит элегантно и хорошо структурированно для большинства ушей. Он по-прежнему популярен среди торговцев, дипломатов и тех, кто стремится сохранить частичку романтического прошлого.
+
+language-Freespeak-name = Свободная речь
+language-Freespeak-description =
+ Язык ренегатов и пограничников, происходящий от различных языков Земли, таких как хинди, объединенных в многокорневую мешанину, которая звучит несвязно или даже варварски для неносителей языка.
+ Этот язык является единственной общей культурной идентичностью для людей на границе. Само по себе владение этим языком смело заявляет о свободном духе говорящего.
+ Граждане Альянса часто называют его Уличным языком.
+
+trait-name-Elyran = Элиранский язык
+language-Elyran-description =
+ Стандартный Элиранский — это официальный язык Республики Элира. Он был создан на основе элементов фарси, арабского и турецкого языков.
+ Влияние всех трёх этих языков прослеживается в его грамматике и словарном составе.
+
language-Canilunzt-name = Канилунц
language-Canilunzt-description = Гортанный язык, на котором говорят и используют обитатели системы Ваззенда, состоящий из рычания, лая, тявканья и интенсивного использования движений ушей и хвоста, вулпканины говорят на этом языке с легкостью.
+
language-Moffic-name = Мольный
language-Moffic-description = Язык народа мотыльков граничит с полной неразборчивостью.
+
language-RobotTalk-name = Робоязык
language-RobotTalk-description = Язык, состоящий из резких бинарных звуков - чириканья, свиста, шипения и завывания. Органические языки не могут говорить на нем без помощи специальных переводчиков.
+
language-Sign-name = Галактический язык жестов
language-Sign-description = Этот язык жестов распространен среди немых и глухих людей.
+
language-Cat-name = Кот
language-Cat-description = Мяу
+
language-Dog-name = Собака
language-Dog-description = Гав!
+
language-Fox-name = Лиса
language-Fox-description = Япиии!
+
language-Xeno-name = Ксено
language-Xeno-description = СССССССССССССР!
+
language-Monkey-name = Мартышка
language-Monkey-description = уаааааак!
+
language-Mouse-name = Мышка
language-Mouse-description = Сквик!
+
language-Chicken-name = Курица
language-Chicken-description = Курлык ёпта!
+
language-Duck-name = Курица
language-Duck-description = Кудах!
+
language-Cow-name = Корова
language-Cow-description = Муууу!
+
language-Sheep-name = Овца
language-Sheep-description = Бееее!
+
language-Kangaroo-name = Кенгуру
language-Kangaroo-description = Чуууу!
+
language-Pig-name = Свинья
language-Pig-description = Хрю!
+
language-Crab-name = Краб
language-Crab-description = Клик!
+
language-Kobold-name = Кобольды
language-Kobold-description = Хиссс!
+
language-Hissing-name = Шипящий
language-Hissing-description = Хисс!
diff --git a/Resources/Locale/ru-RU/loadouts/itemgroups.ftl b/Resources/Locale/ru-RU/loadouts/itemgroups.ftl
index 8b07a6aaf8..c1acc8cda5 100644
--- a/Resources/Locale/ru-RU/loadouts/itemgroups.ftl
+++ b/Resources/Locale/ru-RU/loadouts/itemgroups.ftl
@@ -8,6 +8,7 @@ character-item-group-LoadoutNeck = Гражданская Одежда На Ше
character-item-group-LoadoutOuter = Гражданская Верхняя Одежда
character-item-group-LoadoutShoes = Гражданская Обувь
character-item-group-LoadoutUniformsCivilian = Гражданская Униформа
+
# Generic - Items
character-item-group-LoadoutAirTank = Аварийные Баллоны С Воздухом
character-item-group-LoadoutLighters = Зажигалки
@@ -15,15 +16,18 @@ character-item-group-LoadoutInstrumentsAny = Музыкальные Инстру
character-item-group-LoadoutSmokes = Табачное
character-item-group-LoadoutBoxKits = Наборы Для Выживания
character-item-group-LoadoutWritables = Канцелярия
+
# Cargo
character-item-group-LoadoutNeckCargo = Одежда На Шею Отдела Снабжения
character-item-group-LoadoutOuterCargo = Верхняя Одежда Отдела Снабжения
character-item-group-LoadoutShoesCargo = Обувь Отдела Снабжения
+
# Engineering
character-item-group-LoadoutEyesEngineering = Очки Инженерного Отдела
character-item-group-LoadoutHeadEngineering = Головные Уборы Инженерного Отдела
character-item-group-LoadoutOuterEngineering = Верхняя Одежда Инженерного Отдела
character-item-group-LoadoutUniformsEngineering = Униформа Инженерного Отдела
+
# Medical
character-item-group-LoadoutEyesMedical = Очки Медицинского Отдела
character-item-group-LoadoutGlovesMedical = Перчатки Медицинского отдела
@@ -32,6 +36,7 @@ character-item-group-LoadoutNeckMedical = Одежда На Шею Медици
character-item-group-LoadoutOuterMedical = Верхняя Одежда Медицинского Отдела
character-item-group-LoadoutShoesMedical = Обувь Медицинского Отдела
character-item-group-LoadoutUniformsMedical = Униформа Медицинского Отдела
+
# Security
character-item-group-LoadoutBeltSecurity = Ремни Отдела Службы Безопасности
character-item-group-LoadoutEquipmentSecurity = Снаряжение Отдела Службы Безопасности
@@ -43,6 +48,7 @@ character-item-group-LoadoutNeckSecurity = Одежда На Шею Отдела
character-item-group-LoadoutOuterSecurity = Верхняя Одежда Отдела Службы Безопасности
character-item-group-LoadoutShoesSecurity = Обувь Отдела Службы Безопасности
character-item-group-LoadoutUniformsSecurity = Униформа Отдела Службы Безопасности
+
# Service
character-item-group-LoadoutEquipmentService = Снаряжение Сервиса
character-item-group-LoadoutMaskService = Маски Сервиса
@@ -50,9 +56,15 @@ character-item-group-LoadoutNeckService = Одежда На Шею Сервис
character-item-group-LoadoutOuterService = Верхняя Одежда Сервиса
character-item-group-LoadoutShoesService = Обувь Сервиса
character-item-group-LoadoutUniformsService = Униформа Сервиса
+
# Service - Bartender
character-item-group-LoadoutBartenderAmmo = Аммуниция Бармена
character-item-group-LoadoutBartenderOuterwear = Верхняя Одежда Бармена
character-item-group-LoadoutBartenderWeapon = Оружие Бармена
+
# Service - Musician
character-item-group-LoadoutMusicianInstruments = Музыкальные Инструменты
+
+# Traits - Languages
+character-item-group-TraitsLanguagesBasic = Основные языки
+character-item-group-TraitsAccents = Акценты
diff --git a/Resources/Locale/ru-RU/loadouts/neck.ftl b/Resources/Locale/ru-RU/loadouts/neck.ftl
deleted file mode 100644
index e69de29bb2..0000000000
diff --git a/Resources/Locale/ru-RU/pda/Ringer/ringer-component.ftl b/Resources/Locale/ru-RU/pda/Ringer/ringer-component.ftl
index a461cbd795..b0cd8a95bc 100644
--- a/Resources/Locale/ru-RU/pda/Ringer/ringer-component.ftl
+++ b/Resources/Locale/ru-RU/pda/Ringer/ringer-component.ftl
@@ -1,6 +1,5 @@
### UI
-
# For the PDA Ringer screen
comp-ringer-vibration-popup = Ваш КПК вибрирует
diff --git a/Resources/Locale/ru-RU/robust-toolbox/commands.ftl b/Resources/Locale/ru-RU/robust-toolbox/commands.ftl
index 3f0fc6778c..1259d33e34 100644
--- a/Resources/Locale/ru-RU/robust-toolbox/commands.ftl
+++ b/Resources/Locale/ru-RU/robust-toolbox/commands.ftl
@@ -1,6 +1,5 @@
### Localization for engine console commands
-
## generic command errors
cmd-invalid-arg-number-error = Недопустимое число аргументов.
@@ -172,7 +171,6 @@ cmd-hint-savebp-id =
## 'flushcookies' command
-
# Примечание: команда flushcookies взята из Robust.Client.WebView, её нет в коде основного движка.
cmd-flushcookies-desc = Сброс хранилища CEF-cookie на диск
diff --git a/Resources/Locale/ru-RU/shell.ftl b/Resources/Locale/ru-RU/shell.ftl
index 1c2169249e..82b1ded855 100644
--- a/Resources/Locale/ru-RU/shell.ftl
+++ b/Resources/Locale/ru-RU/shell.ftl
@@ -1,6 +1,5 @@
### for technical and/or system messages
-
## General
shell-server-cannot = Сервер не может выполнить это.
diff --git a/Resources/Locale/ru-RU/shuttles/emergency.ftl b/Resources/Locale/ru-RU/shuttles/emergency.ftl
index 598fc029c9..f11256dc03 100644
--- a/Resources/Locale/ru-RU/shuttles/emergency.ftl
+++ b/Resources/Locale/ru-RU/shuttles/emergency.ftl
@@ -1,6 +1,5 @@
# Commands
-
## Delay shuttle round end
emergency-shuttle-command-round-desc = Останавливает таймер окончания раунда, когда эвакуационный шаттл покидает гиперпространство.
diff --git a/Resources/Locale/ru-RU/ss14-ru/prototypes/deltav/body/organs/vulpkanin.ftl b/Resources/Locale/ru-RU/ss14-ru/prototypes/deltav/body/organs/vulpkanin.ftl
index 0ceb733b42..8b13789179 100644
--- a/Resources/Locale/ru-RU/ss14-ru/prototypes/deltav/body/organs/vulpkanin.ftl
+++ b/Resources/Locale/ru-RU/ss14-ru/prototypes/deltav/body/organs/vulpkanin.ftl
@@ -1,2 +1 @@
-ent-OrganVulpkaninStomach = { ent-OrganAnimalStomach }
- .desc = { ent-OrganAnimalStomach.desc }
+
diff --git a/Resources/Locale/ru-RU/ss14-ru/prototypes/deltav/catalog/fills/backpacks/startergear/backpack.ftl b/Resources/Locale/ru-RU/ss14-ru/prototypes/deltav/catalog/fills/backpacks/startergear/backpack.ftl
index 299b7bcd92..86a9ba38ae 100644
--- a/Resources/Locale/ru-RU/ss14-ru/prototypes/deltav/catalog/fills/backpacks/startergear/backpack.ftl
+++ b/Resources/Locale/ru-RU/ss14-ru/prototypes/deltav/catalog/fills/backpacks/startergear/backpack.ftl
@@ -3,7 +3,6 @@ ent-ClothingBackpackMafiaFilled = { ent-ClothingBackpackSatchelLeather }
.desc = { ent-ClothingBackpackSatchelLeather.desc }
ent-ClothingBackpackParamedicFilledDV = { ent-ClothingBackpackMedical }
.desc = { ent-ClothingBackpackMedical.desc }
-ent-ClothingBackpackPsychologistFilled = { ent-ClothingBackpackMedical }
- .desc = { ent-ClothingBackpackMedical.desc }
+
ent-ClothingBackpackLawyerFilled = { ent-ClothingBackpack }
.desc = { ent-ClothingBackpack.desc }
diff --git a/Resources/Locale/ru-RU/ss14-ru/prototypes/deltav/catalog/fills/backpacks/startergear/duffelbag.ftl b/Resources/Locale/ru-RU/ss14-ru/prototypes/deltav/catalog/fills/backpacks/startergear/duffelbag.ftl
index 20e14626e6..2009854e71 100644
--- a/Resources/Locale/ru-RU/ss14-ru/prototypes/deltav/catalog/fills/backpacks/startergear/duffelbag.ftl
+++ b/Resources/Locale/ru-RU/ss14-ru/prototypes/deltav/catalog/fills/backpacks/startergear/duffelbag.ftl
@@ -1,6 +1,5 @@
ent-ClothingBackpackDuffelParamedicFilledDV = { ent-ClothingBackpackDuffelMedical }
.desc = { ent-ClothingBackpackDuffelMedical.desc }
-ent-ClothingBackpackDuffelPsychologistFilled = { ent-ClothingBackpackDuffelMedical }
- .desc = { ent-ClothingBackpackDuffelMedical.desc }
+
ent-ClothingBackpackDuffelLawyerFilled = { ent-ClothingBackpackDuffel }
.desc = { ent-ClothingBackpackDuffel.desc }
diff --git a/Resources/Locale/ru-RU/ss14-ru/prototypes/deltav/catalog/fills/backpacks/startergear/satchel.ftl b/Resources/Locale/ru-RU/ss14-ru/prototypes/deltav/catalog/fills/backpacks/startergear/satchel.ftl
index 057311deff..4e395685f7 100644
--- a/Resources/Locale/ru-RU/ss14-ru/prototypes/deltav/catalog/fills/backpacks/startergear/satchel.ftl
+++ b/Resources/Locale/ru-RU/ss14-ru/prototypes/deltav/catalog/fills/backpacks/startergear/satchel.ftl
@@ -1,6 +1,5 @@
ent-ClothingBackpackSatchelParamedicFilledDV = { ent-ClothingBackpackSatchelMedical }
.desc = { ent-ClothingBackpackSatchelMedical.desc }
-ent-ClothingBackpackSatchelPsychologistFilled = { ent-ClothingBackpackSatchelMedical }
- .desc = { ent-ClothingBackpackSatchelMedical.desc }
+
ent-ClothingBackpackSatchelLawyerFilled = { ent-ClothingBackpackSatchel }
.desc = { ent-ClothingBackpackSatchel.desc }
diff --git a/Resources/Locale/ru-RU/ss14-ru/prototypes/deltav/catalog/fills/crates/armory.ftl b/Resources/Locale/ru-RU/ss14-ru/prototypes/deltav/catalog/fills/crates/armory.ftl
index 4834d7b064..139597f9cb 100644
--- a/Resources/Locale/ru-RU/ss14-ru/prototypes/deltav/catalog/fills/crates/armory.ftl
+++ b/Resources/Locale/ru-RU/ss14-ru/prototypes/deltav/catalog/fills/crates/armory.ftl
@@ -1,10 +1,2 @@
-ent-CrateArmoryGrand = { ent-CrateWeaponSecure }
- .desc = { ent-CrateWeaponSecure.desc }
-ent-CrateArmoryUniversal = { ent-CrateWeaponSecure }
- .desc = { ent-CrateWeaponSecure.desc }
-ent-CrateArmoryAdjutant = { ent-CrateWeaponSecure }
- .desc = { ent-CrateWeaponSecure.desc }
-ent-CrateArmoryEnergyGun = { ent-CrateWeaponSecure }
- .desc = { ent-CrateWeaponSecure.desc }
-ent-CrateArmoryEnergyGunMini = { ent-CrateWeaponSecure }
- .desc = { ent-CrateWeaponSecure.desc }
+
+
diff --git a/Resources/Locale/ru-RU/ss14-ru/prototypes/deltav/catalog/fills/crates/food.ftl b/Resources/Locale/ru-RU/ss14-ru/prototypes/deltav/catalog/fills/crates/food.ftl
index 6360a3a93c..139597f9cb 100644
--- a/Resources/Locale/ru-RU/ss14-ru/prototypes/deltav/catalog/fills/crates/food.ftl
+++ b/Resources/Locale/ru-RU/ss14-ru/prototypes/deltav/catalog/fills/crates/food.ftl
@@ -1,4 +1,2 @@
-ent-CrateFoodDonkpocketSavory = { ent-CratePlastic }
- .desc = { ent-CratePlastic.desc }
-ent-CrateFoodDonkpocketSweet = { ent-CratePlastic }
- .desc = { ent-CratePlastic.desc }
+
+
diff --git a/Resources/Locale/ru-RU/ss14-ru/prototypes/deltav/catalog/fills/crates/npc.ftl b/Resources/Locale/ru-RU/ss14-ru/prototypes/deltav/catalog/fills/crates/npc.ftl
index f73531dce1..8b13789179 100644
--- a/Resources/Locale/ru-RU/ss14-ru/prototypes/deltav/catalog/fills/crates/npc.ftl
+++ b/Resources/Locale/ru-RU/ss14-ru/prototypes/deltav/catalog/fills/crates/npc.ftl
@@ -1,2 +1 @@
-ent-CrateNPCSecDog = { ent-CrateLivestock }
- .desc = { ent-CrateLivestock.desc }
+
diff --git a/Resources/Locale/ru-RU/ss14-ru/prototypes/deltav/catalog/fills/crates/vending.ftl b/Resources/Locale/ru-RU/ss14-ru/prototypes/deltav/catalog/fills/crates/vending.ftl
index 4b1aa26b38..8b13789179 100644
--- a/Resources/Locale/ru-RU/ss14-ru/prototypes/deltav/catalog/fills/crates/vending.ftl
+++ b/Resources/Locale/ru-RU/ss14-ru/prototypes/deltav/catalog/fills/crates/vending.ftl
@@ -1,2 +1 @@
-ent-CrateVendingMachineRestockPrideFilled = { ent-CratePlastic }
- .desc = { ent-CratePlastic.desc }
+
diff --git a/Resources/Locale/ru-RU/ss14-ru/prototypes/deltav/entities/mobs/player/vulpkanin.ftl b/Resources/Locale/ru-RU/ss14-ru/prototypes/deltav/entities/mobs/player/vulpkanin.ftl
index c91bc8b9d2..8b13789179 100644
--- a/Resources/Locale/ru-RU/ss14-ru/prototypes/deltav/entities/mobs/player/vulpkanin.ftl
+++ b/Resources/Locale/ru-RU/ss14-ru/prototypes/deltav/entities/mobs/player/vulpkanin.ftl
@@ -1,2 +1 @@
-ent-MobVulpkanin = Урист МакВульп
- .desc = { ent-BaseMobVulpkanin.desc }
+
diff --git a/Resources/Locale/ru-RU/ss14-ru/prototypes/deltav/entities/objects/consumable/drinks/drinks.ftl b/Resources/Locale/ru-RU/ss14-ru/prototypes/deltav/entities/objects/consumable/drinks/drinks.ftl
index ae8451bc43..bff9a984ed 100644
--- a/Resources/Locale/ru-RU/ss14-ru/prototypes/deltav/entities/objects/consumable/drinks/drinks.ftl
+++ b/Resources/Locale/ru-RU/ss14-ru/prototypes/deltav/entities/objects/consumable/drinks/drinks.ftl
@@ -10,15 +10,11 @@ ent-DrinkLemonDropGlass = { ent-DrinkGlass }
ent-DrinkGreenGrassGlass = { ent-DrinkGlass }
.desc = Необычно зелёный коктейль приправленный льдом, долькой лемона и трубочкой для питья.
.suffix = зелёная травка
-ent-DrinkDaiquiriGlass = { ent-DrinkGlass }
- .desc = Ром, лайм и сладкий сироп. Вкусно!
- .suffix = классический дайкири
+
ent-DrinkArsonistsBrewGlass = { ent-DrinkGlass }
.desc = Ничего обычного в том, что он дымится.. или светится.. Всё в норме.
.suffix = отвар поджигателя
-ent-DrinkKvassGlass = { ent-DrinkGlass }
- .desc = Вкусный освежающий напиток с нотками социализма.
- .suffix = квас
+
ent-DrinkMothamphetamineGlass = { ent-DrinkGlass }
.desc = На удивление газированный напиток.. От него веет аурой хаоса.
.suffix = метамфетамин
diff --git a/Resources/Locale/ru-RU/ss14-ru/prototypes/deltav/entities/objects/misc/rubber_stamp.ftl b/Resources/Locale/ru-RU/ss14-ru/prototypes/deltav/entities/objects/misc/rubber_stamp.ftl
index d093694741..444e0de5a8 100644
--- a/Resources/Locale/ru-RU/ss14-ru/prototypes/deltav/entities/objects/misc/rubber_stamp.ftl
+++ b/Resources/Locale/ru-RU/ss14-ru/prototypes/deltav/entities/objects/misc/rubber_stamp.ftl
@@ -1,6 +1,4 @@
-ent-RubberStampPsychologist = печать психолога
- .suffix = НЕ МАППИТЬ
- .desc = { ent-RubberStampBase.desc }
+
ent-RubberStampLawyer = печать адвоката
.suffix = НЕ МАППИТЬ
.desc = { ent-RubberStampBase.desc }
diff --git a/Resources/Locale/ru-RU/ss14-ru/prototypes/deltav/entities/structures/storage/tanks/tanks.ftl b/Resources/Locale/ru-RU/ss14-ru/prototypes/deltav/entities/structures/storage/tanks/tanks.ftl
index 99950853b2..139597f9cb 100644
--- a/Resources/Locale/ru-RU/ss14-ru/prototypes/deltav/entities/structures/storage/tanks/tanks.ftl
+++ b/Resources/Locale/ru-RU/ss14-ru/prototypes/deltav/entities/structures/storage/tanks/tanks.ftl
@@ -1,6 +1,2 @@
-ent-KvassTank = { ent-StorageTank }
- .suffix = Пустая
- .desc = { ent-StorageTank.desc }
-ent-KvassTankFull = { ent-KvassTank }
- .suffix = Full
- .desc = { ent-KvassTank.desc }
+
+
diff --git a/Resources/Locale/ru-RU/ss14-ru/prototypes/entities/clothing/outerclothing/softsuits.ftl b/Resources/Locale/ru-RU/ss14-ru/prototypes/entities/clothing/outerclothing/softsuits.ftl
index 3a5af76baf..54e4013aa6 100644
--- a/Resources/Locale/ru-RU/ss14-ru/prototypes/entities/clothing/outerclothing/softsuits.ftl
+++ b/Resources/Locale/ru-RU/ss14-ru/prototypes/entities/clothing/outerclothing/softsuits.ftl
@@ -11,5 +11,4 @@ ent-ClothingOuterHardsuitEVAPrisoner = тюремный скафандр EVA
.desc = Лёгкий космический скафандр, способный защитить заключённого от космического вакуума во время аварийной ситуации.
ent-ClothingOuterHardsuitAncientEVA = пустотный скафандр NTSRA
.desc = Древний космический скафандр, разработанный по заказу Центкома подразделением NTSRA - агентством космических исследований Nanotrasen. Он изготовлен с особой тщательностью, обеспечивая большую мобильность, чем большинство современных космических костюмов.
-ent-ClothingOuterHardsuitVoidParamed = пустотный скафандр полевого врача
- .desc = Пустотный скафандр, предназначенный для парамедиков.
+
diff --git a/Resources/Locale/ru-RU/ss14-ru/prototypes/entities/mobs/player/base.ftl b/Resources/Locale/ru-RU/ss14-ru/prototypes/entities/mobs/player/base.ftl
deleted file mode 100644
index e69de29bb2..0000000000
diff --git a/Resources/Locale/ru-RU/ss14-ru/prototypes/entities/objects/consumable/food/injectable_base.ftl b/Resources/Locale/ru-RU/ss14-ru/prototypes/entities/objects/consumable/food/injectable_base.ftl
deleted file mode 100644
index e69de29bb2..0000000000
diff --git a/Resources/Locale/ru-RU/ss14-ru/prototypes/entities/objects/misc/rubber_stamp.ftl b/Resources/Locale/ru-RU/ss14-ru/prototypes/entities/objects/misc/rubber_stamp.ftl
index 27698cb1cb..b28b268e3f 100644
--- a/Resources/Locale/ru-RU/ss14-ru/prototypes/entities/objects/misc/rubber_stamp.ftl
+++ b/Resources/Locale/ru-RU/ss14-ru/prototypes/entities/objects/misc/rubber_stamp.ftl
@@ -11,9 +11,7 @@ ent-RubberStampCentcom = печать Центком
ent-RubberStampChaplain = печать священника
.suffix = НЕ МАППИТЬ
.desc = { ent-RubberStampBase.desc }
-ent-RubberStampLawyer = печать адвоката
- .suffix = НЕ МАППИТЬ
- .desc = { ent-RubberStampBase.desc }
+
ent-RubberStampClown = печать клоуна
.suffix = НЕ МАППИТЬ
.desc = { ent-RubberStampBase.desc }
diff --git a/Resources/Locale/ru-RU/ss14-ru/prototypes/entities/objects/weapons/guns/ammunition/cartridges/base_cartridge.ftl b/Resources/Locale/ru-RU/ss14-ru/prototypes/entities/objects/weapons/guns/ammunition/cartridges/base_cartridge.ftl
index 3a32e7e40c..8b13789179 100644
--- a/Resources/Locale/ru-RU/ss14-ru/prototypes/entities/objects/weapons/guns/ammunition/cartridges/base_cartridge.ftl
+++ b/Resources/Locale/ru-RU/ss14-ru/prototypes/entities/objects/weapons/guns/ammunition/cartridges/base_cartridge.ftl
@@ -1,2 +1 @@
-ent-BaseCartridge = { ent-BaseItem }
- .desc = { ent-BaseItem.desc }
+
diff --git a/Resources/Locale/ru-RU/ss14-ru/prototypes/entities/objects/weapons/guns/snipers/snipers.ftl b/Resources/Locale/ru-RU/ss14-ru/prototypes/entities/objects/weapons/guns/snipers/snipers.ftl
index 197a47b657..9a27e07252 100644
--- a/Resources/Locale/ru-RU/ss14-ru/prototypes/entities/objects/weapons/guns/snipers/snipers.ftl
+++ b/Resources/Locale/ru-RU/ss14-ru/prototypes/entities/objects/weapons/guns/snipers/snipers.ftl
@@ -12,3 +12,6 @@ ent-WeaponPistolFlintlock = кремнёвый пистолет
ent-Musket = мушкет
.desc = Это должно было оказаться в музее задолго до твоего рождения. Использует патроны калибра .60 крупнокалиберный.
.suffix = Винтовка
+ent-WeaponSniperMosinRubber = { ent-WeaponSniperMosin }
+ .desc = { ent-WeaponSniperMosin.desc }
+ .suffix = Винтовка, Не летальный
diff --git a/Resources/Locale/ru-RU/ss14-ru/prototypes/entities/structures/machines/nuke.ftl b/Resources/Locale/ru-RU/ss14-ru/prototypes/entities/structures/machines/nuke.ftl
index 585b37733e..139597f9cb 100644
--- a/Resources/Locale/ru-RU/ss14-ru/prototypes/entities/structures/machines/nuke.ftl
+++ b/Resources/Locale/ru-RU/ss14-ru/prototypes/entities/structures/machines/nuke.ftl
@@ -1,8 +1,2 @@
-ent-NuclearBomb = ядерная боеголовка
- .desc = Вам, вероятно, не стоит оставаться здесь, чтобы проверить, запущена ли она.
-ent-NuclearBombUnanchored = { ent-NuclearBomb }
- .suffix = незакрепленный
- .desc = { ent-NuclearBomb.desc }
-ent-NuclearBombKeg = ядерная боеголовка
- .desc = Вам, вероятно, не стоит оставаться здесь, чтобы проверить, запущена ли она. Сбоку имеется кран.
- .suffix = кег
+
+
diff --git a/Resources/Locale/ru-RU/ss14-ru/prototypes/nyanotrasen/catalog/fills/crates/epistemics.ftl b/Resources/Locale/ru-RU/ss14-ru/prototypes/nyanotrasen/catalog/fills/crates/epistemics.ftl
index c9a8863969..8b13789179 100644
--- a/Resources/Locale/ru-RU/ss14-ru/prototypes/nyanotrasen/catalog/fills/crates/epistemics.ftl
+++ b/Resources/Locale/ru-RU/ss14-ru/prototypes/nyanotrasen/catalog/fills/crates/epistemics.ftl
@@ -1,2 +1 @@
-ent-CrateHolyWaterKit = { ent-CrateScienceSecure }
- .desc = { ent-CrateScienceSecure.desc }
+
diff --git a/Resources/Locale/ru-RU/ss14-ru/prototypes/nyanotrasen/catalog/fills/crates/syndicate.ftl b/Resources/Locale/ru-RU/ss14-ru/prototypes/nyanotrasen/catalog/fills/crates/syndicate.ftl
index 4cebf1da44..8b13789179 100644
--- a/Resources/Locale/ru-RU/ss14-ru/prototypes/nyanotrasen/catalog/fills/crates/syndicate.ftl
+++ b/Resources/Locale/ru-RU/ss14-ru/prototypes/nyanotrasen/catalog/fills/crates/syndicate.ftl
@@ -1,2 +1 @@
-ent-CrateSyndicateSamurai = { ent-CrateSyndicate }
- .desc = { ent-CrateSyndicate.desc }
+
diff --git a/Resources/Locale/ru-RU/ss14-ru/prototypes/nyanotrasen/entities/clothing/head/hardsuit-helmets.ftl b/Resources/Locale/ru-RU/ss14-ru/prototypes/nyanotrasen/entities/clothing/head/hardsuit-helmets.ftl
index e03b743f4c..139597f9cb 100644
--- a/Resources/Locale/ru-RU/ss14-ru/prototypes/nyanotrasen/entities/clothing/head/hardsuit-helmets.ftl
+++ b/Resources/Locale/ru-RU/ss14-ru/prototypes/nyanotrasen/entities/clothing/head/hardsuit-helmets.ftl
@@ -1,8 +1,2 @@
-ent-ClothingHeadHelmetHardsuitMystagogue = шлем скафандра научного директора
- .desc = Легкий шлем-скафандр, оснащенный первой в галактике псионической системой пропуска.
-ent-ClothingHeadHelmetHardsuitSyndieReverseEngineered = Боевой защитный шлем SA-123
- .desc = Усовершенствованный шлем скафандра, предназначенный для работы в специальных операциях.
-ent-ClothingHeadHelmetHardsuitJuggernautReverseEngineered = Боевой защитный шлем SA-127
- .desc = Штурмовой шлем-скафандр из сверхсекретного полупрозрачного полимера.
-ent-ClothingHeadHelmetHardsuitERTCentcomm = Защитный шлем скафандра ЦентКом
- .desc = { ent-ClothingHeadHelmetHardsuitERTLeader.desc }
+
+
diff --git a/Resources/Locale/ru-RU/ss14-ru/prototypes/nyanotrasen/entities/clothing/outerclothing/hardsuits.ftl b/Resources/Locale/ru-RU/ss14-ru/prototypes/nyanotrasen/entities/clothing/outerclothing/hardsuits.ftl
index 1ddb55fbc2..139597f9cb 100644
--- a/Resources/Locale/ru-RU/ss14-ru/prototypes/nyanotrasen/entities/clothing/outerclothing/hardsuits.ftl
+++ b/Resources/Locale/ru-RU/ss14-ru/prototypes/nyanotrasen/entities/clothing/outerclothing/hardsuits.ftl
@@ -1,10 +1,2 @@
-ent-ClothingOuterHardsuitMystagogue = скафандр Научного Директора
- .desc = Легкий защитный костюм, оснащенный шлемом с первой в галактике псионической системой пропуска.
-ent-ClothingOuterHardsuitSyndieReverseEngineered = боевой скафандр SA-122
- .suffix = перепрограммирован
- .desc = { ent-ClothingOuterHardsuitSyndie.desc }
-ent-ClothingOuterHardsuitJuggernautReverseEngineered = боевой скафандр SA-126
- .desc = Костюм, изготовленный отделом специальных закупок Nanotrasen, отличается повышенной эластичностью.
- .suffix = перепрограммирован
-ent-ClothingOuterHardsuitERTCentcomm = Скафандр ЦентКом
- .desc = { ent-ClothingOuterHardsuitERTLeader.desc }
+
+
diff --git a/Resources/Locale/ru-RU/ss14-ru/prototypes/nyanotrasen/entities/mobs/npcs/mutants.ftl b/Resources/Locale/ru-RU/ss14-ru/prototypes/nyanotrasen/entities/mobs/npcs/mutants.ftl
index 1f4a7e15a5..13350a41ed 100644
--- a/Resources/Locale/ru-RU/ss14-ru/prototypes/nyanotrasen/entities/mobs/npcs/mutants.ftl
+++ b/Resources/Locale/ru-RU/ss14-ru/prototypes/nyanotrasen/entities/mobs/npcs/mutants.ftl
@@ -5,5 +5,4 @@ ent-MobGiantSpiderVampire = онейрофаг
ent-MobGiantSpiderVampireAngry = онейрофаг
.suffix = Злой
.desc = { ent-MobGiantSpiderVampire.desc }
-ent-MobMouseCancer = раковая мышь
- .desc = О, Привет, Сиви..
+
diff --git a/Resources/Locale/ru-RU/ss14-ru/prototypes/nyanotrasen/entities/objects/consumable/drinks/drinks.ftl b/Resources/Locale/ru-RU/ss14-ru/prototypes/nyanotrasen/entities/objects/consumable/drinks/drinks.ftl
index fc88ccdf43..52e0da2aec 100644
--- a/Resources/Locale/ru-RU/ss14-ru/prototypes/nyanotrasen/entities/objects/consumable/drinks/drinks.ftl
+++ b/Resources/Locale/ru-RU/ss14-ru/prototypes/nyanotrasen/entities/objects/consumable/drinks/drinks.ftl
@@ -1,6 +1,4 @@
-ent-DrinkSakeGlass = { ent-DrinkGlass }
- .desc = Алкоголь приготовленный из риса.
- .suffix = саке
+
ent-DrinkOrangeCreamiceGlass = { ent-DrinkGlass }
.desc = Апельсиново, кремово, божественно.
.suffix = апельсиновый кремовик
diff --git a/Resources/Locale/ru-RU/ss14-ru/prototypes/nyanotrasen/entities/objects/consumable/drinks/drinks_bottles.ftl b/Resources/Locale/ru-RU/ss14-ru/prototypes/nyanotrasen/entities/objects/consumable/drinks/drinks_bottles.ftl
index 4b6ce828bb..ab710ad406 100644
--- a/Resources/Locale/ru-RU/ss14-ru/prototypes/nyanotrasen/entities/objects/consumable/drinks/drinks_bottles.ftl
+++ b/Resources/Locale/ru-RU/ss14-ru/prototypes/nyanotrasen/entities/objects/consumable/drinks/drinks_bottles.ftl
@@ -1,5 +1,4 @@
-ent-DrinkSakeBottleFull = бутылка саке
- .desc = Пойло для истинных самураев.
+
ent-DrinkSojuBottleFull = бутылка соджу
.desc = Это как саке, но в этот раз вы реально хотите напиться.
ent-DrinkTokkuri = токкури
diff --git a/Resources/Locale/ru-RU/ss14-ru/prototypes/nyanotrasen/entities/objects/weapons/melee/knives.ftl b/Resources/Locale/ru-RU/ss14-ru/prototypes/nyanotrasen/entities/objects/weapons/melee/knives.ftl
index 57d50df64e..8b13789179 100644
--- a/Resources/Locale/ru-RU/ss14-ru/prototypes/nyanotrasen/entities/objects/weapons/melee/knives.ftl
+++ b/Resources/Locale/ru-RU/ss14-ru/prototypes/nyanotrasen/entities/objects/weapons/melee/knives.ftl
@@ -1,2 +1 @@
-ent-AntiPsychicKnife = анти-психический нож
- .desc = Специальный нож для убийства психических существ.
+
diff --git a/Resources/Locale/ru-RU/ss14-ru/prototypes/nyanotrasen/entities/structures/machines/metempsychoticMachine.ftl b/Resources/Locale/ru-RU/ss14-ru/prototypes/nyanotrasen/entities/structures/machines/metempsychoticMachine.ftl
index 4540ea88b9..8b13789179 100644
--- a/Resources/Locale/ru-RU/ss14-ru/prototypes/nyanotrasen/entities/structures/machines/metempsychoticMachine.ftl
+++ b/Resources/Locale/ru-RU/ss14-ru/prototypes/nyanotrasen/entities/structures/machines/metempsychoticMachine.ftl
@@ -1,2 +1 @@
-ent-MetempsychoticMachine = машина для метампсихоза
- .desc = Перемещает душу из старого тела в нынешнее.
+
diff --git a/Resources/Locale/ru-RU/ss14-ru/prototypes/nyanotrasen/entities/structures/walls/walls.ftl b/Resources/Locale/ru-RU/ss14-ru/prototypes/nyanotrasen/entities/structures/walls/walls.ftl
index 98ecd2b20f..39a82ff404 100644
--- a/Resources/Locale/ru-RU/ss14-ru/prototypes/nyanotrasen/entities/structures/walls/walls.ftl
+++ b/Resources/Locale/ru-RU/ss14-ru/prototypes/nyanotrasen/entities/structures/walls/walls.ftl
@@ -1,6 +1,4 @@
-ent-WallShuttleInterior = стена шаттла
- .suffix = Интерьер
- .desc = { ent-WallSolid.desc }
+
ent-WallPaper = бумажная стена
.desc = Помогает изолироваться от страшных криков из додзё.
ent-WallDrywall = гипсокартоновая стена
diff --git a/Resources/Locale/ru-RU/traits/categories.ftl b/Resources/Locale/ru-RU/traits/categories.ftl
index fd5a9d3a22..d019442074 100644
--- a/Resources/Locale/ru-RU/traits/categories.ftl
+++ b/Resources/Locale/ru-RU/traits/categories.ftl
@@ -5,4 +5,7 @@ trait-category-Auditory = Слуховые
trait-category-Mental = Ментальные
trait-category-Physical = Психические
trait-category-Speech = Разговорные
+trait-category-TraitsSpeechUncategorized = Несортированные
+trait-category-TraitsSpeechAccents = Акценты
+trait-category-TraitsSpeechLanguages = Языки
trait-category-Visual = Визуальные
diff --git a/Resources/Locale/ru-RU/traits/traits.ftl b/Resources/Locale/ru-RU/traits/traits.ftl
index 22ca3e018b..5f3cfb7c62 100644
--- a/Resources/Locale/ru-RU/traits/traits.ftl
+++ b/Resources/Locale/ru-RU/traits/traits.ftl
@@ -1,197 +1,274 @@
trait-name-Blindness = Слепота
trait-description-Blindness = Вы совершенно слепы и не можете видеть дальше нескольких метров перед собой.
trait-examined-Blindness = [color=lightblue]{ CAPITALIZE(POSS-ADJ($target)) } глаза остекленелые и расфокусированные. Не похоже, что { SUBJECT($target) } может хорошо вас видеть, если может вообще.[/color]
+
trait-name-Narcolepsy = Нарколепсия
trait-description-Narcolepsy = Вас одолевают приступы сонливости
+
trait-name-Pacifist = Пацифист
trait-description-Pacifist = Вы не можете атаковать или причинить вред живым существам.
+
trait-name-SelfAware = Самосознание
trait-description-SelfAware =
Вы обладаете острой интуицией своего тела и чувств.
Вы можете точно оценить тяжесть своих ран и ожогов, как анализатор здоровья,
и можете определить, есть ли у вас повреждения от токсинов или потери воздуха.
+
trait-name-LightweightDrunk = Быстрое опьянение
trait-description-LightweightDrunk = Алкоголь оказывает на вас более сильное воздействие
+
trait-name-HeavyweightDrunk = Толерантность к алкоголю
-trait-description-HeavyweightDrunk = Алкоголь боится тебя.
+trait-description-HeavyweightDrunk =
+ Алкоголь боится тебя.
+
trait-name-LiquorLifeline = Спасательный круг для ликера
trait-description-LiquorLifeline =
Забудьте о враче — просто зайдите в бар и получите свой "рецепт на этанол"!
Когда вы пьёте, лечите [color=red]Механические[/color], [color=orange]Термические[/color], [color=orange]Электрические[/color], и [color=orange]Обморожение[/color], смотря на сколько вы пьяны.
Вы также получаете преимущества [color=lightblue]Толерантности к алкоголю[/color].
+
trait-name-Muted = Немой
trait-description-Muted = Вы не можете говорить
+
trait-name-BloodDeficiency = Дефицит крови
trait-description-BloodDeficiency =
Ваше тело теряет больше крови, чем может восполнить.
Со временем вы теряете кровь, и если не лечиться, вы в конечном итоге умрете от потери крови.
+
trait-name-Hemophilia = Гемофилия
trait-description-Hemophilia =
Способность вашего организма образовывать тромбы нарушена.
Вы истекаете кровью в два раза дольше, у вас легкие синяки, и вы получаете на 10% больше дробящего урона.
+
trait-name-Paracusia = Паракузия
trait-description-Paracusia = Вы слышите звуки, которых на самом деле нет
+
trait-name-PirateAccent = Пиратский акцент
trait-description-PirateAccent = Ты не можешь перестать говорить как пират!
+
trait-name-Accentless = Без акцента
trait-description-Accentless = У вас нет того акцента, который обычно бывает у представителей вашего вида.
+
trait-name-FrontalLisp = Сигматизм
trait-description-FrontalLisp = У ваф имеютшя проблемы ш произношением.
+
trait-name-Stutter = Социофобия
trait-description-Stutter = Вы испытываете тревожность, когда говорите, что приводит к заиканию.
+
trait-name-Snoring = Храп
trait-description-Snoring = Вы храпите во время сна.
+
trait-name-CPRTraining = Обученный СЛР
trait-description-CPRTraining =
В какой-то момент вашей жизни вы прошли обучение тому, как выполнять СЛР.
Эта черта автоматически бесплатно предоставляется врачам и предназначена для немедицинских персонажей.
+
trait-name-NormalVisionHarpy = Модификация трихромата
trait-description-NormalVisionHarpy = Ваши глаза были модифицированы с помощью передовой медицины, чтобы видеть стандартные цвета: красный, зеленый и синий.
+
trait-name-Southern = Южный протяжный говор
trait-description-Southern = У тебя другая манера говорить. (Работает только на английском)
+
trait-name-NormalVision = Модификация трихромата
trait-description-NormalVision = Ваши глаза были изменены с помощью передовых медицинских технологий, чтобы они могли видеть стандартные цвета - красный, зеленый и синий.
+
trait-name-Thieving = Бывалый вор
trait-description-Thieving =
У вас ловкие руки, и вы талантливо умеете убеждать людей в том, что у них есть вещи.
Вы можете распознавать спрятанные в карман предметы, красть их тише и на 33% быстрее.
+
trait-name-ForeignerLight = Унесённый ядерным взрывом (Легкое)
trait-description-ForeignerLight =
Вам трудно выучить основной язык этой станции, и поэтому вы не можете на нем говорить. Однако вы можете понимать, что другие говорят на этом языке.
Чтобы помочь вам преодолеть это препятствие, у вас есть переводчик, который поможет вам говорить на основном языке этой станции.
+
trait-name-Foreigner = Унесённый ядерным взрывом
trait-description-Foreigner =
По той или иной причине вы не говорите на основном языке станции.
Вместо этого вам выдан переводчик, которым можете пользоваться только вы.
+
trait-name-Saturnine = Мрачный
trait-description-Saturnine = Вы от природы суровы и угрюмый человек. Ваше настроение постоянно ухудшается.
+
trait-name-Sanguine = Оптимистичный
trait-description-Sanguine = Вы от природы оптимистичны и жизнерадостны! Ваше настроение постоянно повышается в разы.
+
trait-name-WillToLive = Воля К Жизни
trait-description-WillToLive =
У вас необычайно сильная "воля к жизни", и вы будете сопротивляться смерти сильнее, чем другие.
ваш порог урона, при котором вы становитесь мертвым, увеличен на 10 пунктов.
+
trait-name-WillToDie = Воля к Смерти
trait-description-WillToDie =
У вас необычайно слабая "воля к жизни", и вы будете умирать от ранений раньше, чем другие.
ваш порог урона, при котором вы становитесь мертвым, снижен на 15 пунктов.
+
trait-name-Tenacity = Упорство
trait-description-Tenacity =
Будь то благодаря упорству, силе воли или тонким бионическим усилениям, вы становитесь выносливее других.
Ваш порог получения критического урона увеличен на 5 пунктов.
+
trait-name-GlassJaw = Стеклянная челюсть
trait-description-GlassJaw =
Ваше тело более хрупкое, чем у других, что приводит к большему урону критическими травмами
Ваш порог получения критического урона снижен на 10 пунктов.
+
trait-name-HighAdrenaline = Высокий уровень адреналина
trait-description-HighAdrenaline =
В силу естественных причин, генетических или бионических особенностей, у вас более мощная надпочечниковая железа.
При ранении ваши атаки в ближнем бою наносят на 10% больше урона, в дополнение к естественным бонусам от адреналина.
Стандартные адреналиновые бонусы к урону в ближнем бою увеличиваются на 20%.
+
trait-name-AdrenalDysfunction = Дисфункция надпочечников
trait-description-AdrenalDysfunction =
Ваши надпочечники полностью выведены из строя или, возможно, полностью отсутствуют.
При ранении ваши атаки в ближнем бою не получают бонус.
Стандартные бонусы от адреналина к урону в ближнем бою увеличиваются на 20%.
+
trait-name-Masochism = Мазохизм
trait-description-Masochism =
Получая удовольствие от собственной боли, вы не испытываете такой скованности, как другие.
Вы игнорируете первые 10% урона выносливости при атаках в ближнем бою.
+
trait-name-LowPainTolerance = Низкая переносимость боли
trait-description-LowPainTolerance =
Ваша переносимость боли намного ниже средней, а ее воздействие более подавляюще.
При получении урона выносливости ваш урон в ближнем бою уменьшается еще на 15%.
+
trait-name-MartialArtist = Мастер боевых искусств
trait-description-MartialArtist =
Вы прошли подготовку по рукопашному бою, будь то на кулаках, ногах или когтях.
Ваши кулаки бьют дальше и наносят на 50% больше урона.
Это не относится ни к какому виду ручного оружия, а только к оружию, с которым вы родились.
+
trait-name-Vigor = Сила
trait-description-Vigor =
Ваша выносливость повышается благодаря целеустремленности, физической подготовке или бионическим усилениям.
Ваша выносливость увеличивается на 10 пунктов.
+
trait-name-Lethargy = Летаргия
trait-description-Lethargy =
Вы устаете быстрее других, что делает вас более уязвимым к переутомлению.
Ваша выносливость снижена на 15 пунктов.
+
trait-name-SignLanguage = Язык жестов
trait-description-SignLanguage =
Вы можете понимать и использовать галактический язык жестов.
Если вы по какой-либо причине не можете говорить, вы все равно можете общаться с помощью языка жестов.
+
+trait-name-SolCommon = Общий язык Солнечного Альянса
+trait-description-SolCommon =
+ Общий язык Солнечного Альянса берёт свои корни из мандаринского диалекта китайского языка и эволюционировал как официальный язык Солнечного Альянса, при этом чиновники стремились объединить его в единый общий язык.
+ На нём говорят государственные служащие, его преподают в школах, и его используют те, кто либо испытывает чувство национальной гордости за Альянс, либо оказался под влиянием его культуры.
+
+trait-name-Tradeband = Торговый язык
+trait-description-Tradeband =
+ Происходящий от латинских и романских языков старой Земли, Торговый остается основным языком высшего класса человечества.
+ Язык звучит элегантно и хорошо структурированно для большинства ушей. Он по-прежнему популярен среди торговцев, дипломатов и тех, кто стремится сохранить частичку романтического прошлого.
+
+trait-name-Freespeak = Свободная речь (Уличный)
+trait-description-Freespeak =
+ Язык ренегатов и пограничников, происходящий от различных языков Земли, таких как хинди, объединенных в многокорневую мешанину, которая звучит несвязно или даже варварски для неносителей языка.
+ Этот язык является единственной общей культурной идентичностью для людей на границе. Само по себе владение этим языком смело заявляет о свободном духе говорящего.
+ Граждане Альянса часто называют его Уличным.
+
+trait-name-Elyran = Элиранский язык
+trait-description-Elyran =
+ Стандартный Элиранский — это официальный язык Республики Элира. Он был создан на основе элементов фарси, арабского и турецкого языков.
+ Влияние всех трёх этих языков прослеживается в его грамматике и словарном составе.
+
trait-name-Voracious = Прожорливый
trait-description-Voracious =
Ничто не встанет между вами и вашей едой.
Вы будете потреблять еду и напитки в два раза быстрее, чем обычно.
+
trait-name-ParkourTraining = Тренировка по паркуру
trait-description-ParkourTraining =
Паркур - это ваше хобби, стиль жизни или профессиональная тренировка.
Вы становитесь быстрее в лазании, ползании, лежании и вставании.
+
trait-name-Sluggish = Вялый
trait-description-Sluggish =
Вы ориентируетесь в мире медленнее, чем другие, возможно, из-за состояния здоровья, гиподинамии или возраста.
Вы двигаетесь медленнее, и вам требуется больше времени, чтобы подняться, лечь и встать с постели.
+
trait-name-SnailPaced = Черепашьим шагом
trait-description-SnailPaced =
Вы передвигаетесь со скоростью улитки, возможно, из-за состояния здоровья, нарушения подвижности или возраста.
Вы двигаетесь значительно медленнее, и вам требуется гораздо больше времени, чтобы подняться, лечь и встать.
+
trait-name-LightStep = Легкий шаг
trait-description-LightStep = Вы двигаетесь легким шагом, делая свои шаги тише.
+
trait-name-Swashbuckler = Фехтовальщик
trait-description-Swashbuckler =
Вы являетесь экспертом в фехтовании, владея мечами, ножами и другими видами клинков с непревзойденным мастерством.
Ваш бонус за удар ножом в ближнем бою увеличен до 35%, но бонус за удар тупым предметом в ближнем бою снижен до 20%.
+
trait-name-Spearmaster = Мастер копья
trait-description-Spearmaster =
Вы превосходно владеете копьями, используя их как продолжение своего тела.
Ваш бонус к прокалыванию в ближнем бою увеличен до 35%, но бонус к нанесению ударов тупым предметом в ближнем бою снижен до 20%.
+
trait-name-WeaponsGeneralist = Специалист по оружию
trait-description-WeaponsGeneralist =
Вы мастер на все руки в обращении с оружием ближнего боя, что позволяет вам быть универсальным в своем арсенале.
Ваш бонус к урону в ближнем бою за все виды грубого урона составляет 25%.
+
trait-name-Singer = Певец
trait-description-Singer = Вы, естественно, способны петь своим голосом простые мелодии.
+
trait-name-LatentPsychic = Скрытый экстрасенс
trait-description-LatentPsychic =
Ваш разум и душа открыты ноосфере, что позволяет использовать телепатию.
Таким образом, вы имеете право на потенциальное получение экстрасенсорных способностей.
Вполне возможно, что за вами охотятся потусторонние силы, поэтому подумайте о том, чтобы сохранить свои способности в секрете.
+
trait-name-PsionicInsulation = Изменение формы сигнала
trait-description-PsionicInsulation =
Вы - автомат из плоти и крови, оживляемый нейротрансмиттерами. Внутри вашего черепа находится полуторакилограммовый мешок мяса, дающий вам разум. Согласно современной теории познания, вы даже не существо с правами.
Из хороших новостей то, что вы невосприимчивы к большинству положительных и отрицательных воздействий экстрасенсорных способностей.
У этого заболевания могут быть и другие, неизвестные последствия.
+
trait-name-NaturalTelepath = Врождённая телепатия
trait-description-NaturalTelepath =
Как одарённый с рождения, вы способны к быстрому телепатическому общению, независимо от того
обладаете ли вы какими-либо заметными экстрасенсорными способностями. Это дает все те же преимущества и
недостатки, что и экстрасенс, за исключением того, что вы гарантированно начнете с телепатической связью.
Вы все еще можете обрести способности, так же, как и обычный экстрасенс.
+
trait-name-TrapAvoider = Избегатель ловушек
trait-description-TrapAvoider =
Вы обладаете сверхъестественным чутьем на ловушки и будете неосознанно избегать их.
Вы никогда не сможете их активировать.
+
trait-name-AnomalousPositronics = Аномальная позитроника
trait-description-AnomalousPositronics =
Будь то преднамеренный дизайн от производителя, модификации на черном рынке или случайное упущение,
вашему позитронному мозгу не хватает стандартной псионической изоляции. Как существо, у которого, как можно утверждать, есть душа,
это, в более широком смысле, означает, что вы можете подвергаться влиянию Ноосферы.
+
trait-name-Photophobia = Светобоязнь
trait-description-Photophobia =
Ваши глаза чрезвычайно чувствительны к яркому свету.
В результате вы можете быть ослеплены на больший срок, чем другие, когда подвергаетесь воздействию внезапных вспышек света.
Кроме того, ваши глаза с большей вероятностью могут пострадать от вспышек.
+
trait-name-Clumsy = Неуклюжий
trait-description-Clumsy =
У вас серьезный дефицит зрительно-моторной координации, что приводит к неспособности делать некоторые вещи, которые другие воспринимали бы как должное.
Любое оружие, которое вы попытаетесь использовать, скорее всего, повредит вам, чем другим. Вы не сможете взобраться на какой-либо объект, не поранившись.
+
trait-name-Small = Низкий
trait-description-Small =
Вы намного меньше обычного человека и можете забираться в места, в которые другие обычно не помещаются, например в спортивные сумки.
Эта черта никоим образом не изменяет размер вашего персонажа, она просто требует, чтобы ваш персонаж был размером не более стандартного Феленида.
+
trait-name-TemperatureTolerance = Температурная терпимость
trait-description-TemperatureTolerance =
Вы хорошо переносите более низкие температуры. Вы можете длительное время находиться в условиях, температура которых немного ниже точки замерзания, например, внутри кухонной морозилки,
или на залитом солнцем склоне горы, где находится знаменитая ледниковая станция.
+
trait-name-Talons = Колющие Когти
trait-description-Talons =
Кончики ваших пальцев были заменены колющими когтями.
@@ -199,6 +276,7 @@ trait-description-Talons =
или даже выдвижные когти из твердого пластика, встроенные в протез конечности.
Ваши атаки в ближнем бою без оружия наносят колющий урон вместо стандартного для вашей расы урона.
Это не влияет на урон, наносимый в любой форме вооруженного ближнего боя.
+
trait-name-Claws = Режущие Когти
trait-description-Claws =
Кончики ваших пальцев были заменены острыми когтями.
@@ -206,12 +284,14 @@ trait-description-Claws =
или даже выдвижные когти из твердого пластика, встроенные в протез конечности.
Ваши атаки в ближнем бою без оружия наносят режущий урон вместо стандартного для вашей расы урона.
Это не влияет на урон, наносимый в любой форме вооруженного ближнего боя.
+
trait-name-NaturalWeaponRemoval = Удаление природного оружия
trait-description-NaturalWeaponRemoval =
Любое "природное оружие", с которым обычно рождается ваш вид, было удалено хирургическим путем.
Это могло быть сделано для того, чтобы лучше вписаться в земные космические станции, или в качестве косметического решения.
В результате ваши атаки без оружия наносят тупой урон вместо стандартного для вашего вида урона.
Это не влияет на урон, наносимый в любой форме вооруженного ближнего боя.
+
trait-name-StrikingCalluses = Поразительные мозоли
trait-description-StrikingCalluses =
Культовое усовершенствование, широко распространенное в мире кибернетических боевых искусств.
@@ -220,10 +300,12 @@ trait-description-StrikingCalluses =
Владельцы протезов или бионических конечностей вместо этого будут иметь твердую пластиковую оболочку на костяшках пальцев.
Эти улучшения увеличивают ваш урон от удара без оружия на 1 базовое очко, но не дают
любые преимущества в любой форме вооруженного ближнего боя.
+
trait-name-Spinarette = Бионические Фильеры
trait-description-Spinarette =
Этот орган, выращенный в пробирке, отмеченный торговой маркой и запатентованный корпорацией Cybersun, позиционируется как сугубо утилитарное усовершенствование, и продается в клиниках по всему известному миру. Он состоит из узелка, который традиционно
имплантированный прямо под запястьем, он впитывает липиды организма и превращается в натуральный шелк.. Небольшое отверстие
на ладони позволяет пользователю "раскручивать" эту нить. Пользователям этого усовершенствования обычно требуется в два раза больше пищи, чем обычному солнечному человеку, из-за высокой метаболической стоимости искусственного шелководства.
+
trait-name-AddictionNicotine = Никотиновая зависимость
trait-description-AddictionNicotine = У вас зависимость от никотина, и вам понадобятся частые перекуры, чтобы сохранить свой рассудок.
diff --git a/Resources/Locale/ru-RU/ui/transfer-amount.ftl b/Resources/Locale/ru-RU/ui/transfer-amount.ftl
index 2b786d323d..4864b4deb3 100644
--- a/Resources/Locale/ru-RU/ui/transfer-amount.ftl
+++ b/Resources/Locale/ru-RU/ui/transfer-amount.ftl
@@ -1,6 +1,5 @@
### Loc for the transfer amount eui window
-
## Title
ui-transfer-amount-title = Изменить перемещаемое количество
diff --git a/Resources/Locale/ru-RU/verbs/invoke-verb-command.ftl b/Resources/Locale/ru-RU/verbs/invoke-verb-command.ftl
index b748505059..e8d06c3ae5 100644
--- a/Resources/Locale/ru-RU/verbs/invoke-verb-command.ftl
+++ b/Resources/Locale/ru-RU/verbs/invoke-verb-command.ftl
@@ -1,6 +1,5 @@
### Localization used for the invoke verb command.
-
# Mostly help + error messages.
invoke-verb-command-description = Вызывает verb с заданным именем на сущности, с сущностью игрока
diff --git a/Resources/Locale/ru-RU/verbs/list-verbs-command.ftl b/Resources/Locale/ru-RU/verbs/list-verbs-command.ftl
index fc2330408f..7811b4b3e5 100644
--- a/Resources/Locale/ru-RU/verbs/list-verbs-command.ftl
+++ b/Resources/Locale/ru-RU/verbs/list-verbs-command.ftl
@@ -1,6 +1,5 @@
### Localization used for the list verbs command.
-
# Mostly help + error messages.
list-verbs-command-description = Перечисляет все verbs, которые игрок может использовать на данной сущности.
diff --git a/Resources/Locale/ru-RU/voting/vote-commands.ftl b/Resources/Locale/ru-RU/voting/vote-commands.ftl
index 1d333f82a5..f2e9067437 100644
--- a/Resources/Locale/ru-RU/voting/vote-commands.ftl
+++ b/Resources/Locale/ru-RU/voting/vote-commands.ftl
@@ -1,6 +1,5 @@
### Voting system related console commands
-
## 'createvote' command
cmd-createvote-desc = Создаёт голосование
diff --git a/Resources/Migrations/LostParadiseMigrations.yml b/Resources/Migrations/LostParadiseMigrations.yml
index 9c9a8bc8e8..caf116ad61 100644
--- a/Resources/Migrations/LostParadiseMigrations.yml
+++ b/Resources/Migrations/LostParadiseMigrations.yml
@@ -19,3 +19,5 @@ LPPFlagPoleSYND: null
LPPLockerElectricalSuppliesSynFilled: null
LPPRusUnder: null
PlastitaniumPwindow: WindowReinforcedDirectional
+LPPC4Low: BreachingCharge
+LPPHammer: SecBreachingHammer
diff --git a/Resources/Prototypes/Catalog/VendingMachines/Inventories/sec.yml b/Resources/Prototypes/Catalog/VendingMachines/Inventories/sec.yml
index b490dff9e0..97247659dd 100644
--- a/Resources/Prototypes/Catalog/VendingMachines/Inventories/sec.yml
+++ b/Resources/Prototypes/Catalog/VendingMachines/Inventories/sec.yml
@@ -24,7 +24,7 @@
ClothingOuterArmorPlateCarrier: 2 # DeltaV - moved body armour from SecDrobe to SecTech
ClothingOuterArmorDuraVest: 2
ClothingHeadHelmetBasic: 2 # DeltaV - added helmets to the SecTech. Another line of defense between the tide and your grey matter.
- # BreachingCharge: 8
+ BreachingCharge: 8
LPPWeaponEnergyGunSoleil: 2 #LPP
LPPTelebaton: 3 #LPP
# security officers need to follow a diet regimen!
diff --git a/Resources/Prototypes/CharacterItemGroups/languageGroups.yml b/Resources/Prototypes/CharacterItemGroups/languageGroups.yml
new file mode 100644
index 0000000000..244792e4c6
--- /dev/null
+++ b/Resources/Prototypes/CharacterItemGroups/languageGroups.yml
@@ -0,0 +1,31 @@
+- type: characterItemGroup
+ id: TraitsLanguagesBasic
+ maxItems: 1
+ items:
+ - type: trait
+ id: SignLanguage
+ - type: trait
+ id: SolCommon
+ - type: trait
+ id: Tradeband
+ - type: trait
+ id: Freespeak
+ - type: trait
+ id: Elyran
+
+- type: characterItemGroup
+ id: TraitsAccents
+ maxItems: 1
+ items:
+ - type: trait
+ id: FrontalLisp
+ - type: trait
+ id: Stutter
+ - type: trait
+ id: PirateAccent
+ - type: trait
+ id: Accentless
+ - type: trait
+ id: Southern
+ - type: trait
+ id: ScottishAccent
\ No newline at end of file
diff --git a/Resources/Prototypes/DeltaV/Entities/Mobs/NPCs/animals.yml b/Resources/Prototypes/DeltaV/Entities/Mobs/NPCs/animals.yml
index 6e81306722..9ea26b7a2f 100644
--- a/Resources/Prototypes/DeltaV/Entities/Mobs/NPCs/animals.yml
+++ b/Resources/Prototypes/DeltaV/Entities/Mobs/NPCs/animals.yml
@@ -184,4 +184,4 @@
- Dog
understands:
- Dog
- - GalacticCommon
+ - TauCetiBasic
diff --git a/Resources/Prototypes/DeltaV/Entities/Mobs/NPCs/familiars.yml b/Resources/Prototypes/DeltaV/Entities/Mobs/NPCs/familiars.yml
index 364907ff9c..4d3d139e8e 100644
--- a/Resources/Prototypes/DeltaV/Entities/Mobs/NPCs/familiars.yml
+++ b/Resources/Prototypes/DeltaV/Entities/Mobs/NPCs/familiars.yml
@@ -111,9 +111,9 @@
- NanoTrasen
- type: LanguageKnowledge
speaks:
- - GalacticCommon
+ - TauCetiBasic
understands:
- - GalacticCommon
+ - TauCetiBasic
- type: GhostTakeoverAvailable
- type: GhostRole
makeSentient: true
diff --git a/Resources/Prototypes/DeltaV/Entities/Mobs/NPCs/nukiemouse.yml b/Resources/Prototypes/DeltaV/Entities/Mobs/NPCs/nukiemouse.yml
index 8968f0e77a..59c7fe2b21 100644
--- a/Resources/Prototypes/DeltaV/Entities/Mobs/NPCs/nukiemouse.yml
+++ b/Resources/Prototypes/DeltaV/Entities/Mobs/NPCs/nukiemouse.yml
@@ -101,7 +101,7 @@
- Mouse
understands:
- Mouse
- - GalacticCommon
+ - TauCetiBasic
- type: Tag
tags:
- VimPilot
diff --git a/Resources/Prototypes/DeltaV/Entities/Mobs/Species/vulpkanin.yml b/Resources/Prototypes/DeltaV/Entities/Mobs/Species/vulpkanin.yml
index fde82ecb6c..73bafd4631 100644
--- a/Resources/Prototypes/DeltaV/Entities/Mobs/Species/vulpkanin.yml
+++ b/Resources/Prototypes/DeltaV/Entities/Mobs/Species/vulpkanin.yml
@@ -115,10 +115,10 @@
- type: Wagging
- type: LanguageKnowledge
speaks:
- - GalacticCommon
+ - TauCetiBasic
- Canilunzt
understands:
- - GalacticCommon
+ - TauCetiBasic
- Canilunzt
- type: ConsumeDelayModifier
foodDelayMultiplier: 0.5
diff --git a/Resources/Prototypes/DeltaV/GameRules/events.yml b/Resources/Prototypes/DeltaV/GameRules/events.yml
index a3fb69cf73..16ecb05283 100644
--- a/Resources/Prototypes/DeltaV/GameRules/events.yml
+++ b/Resources/Prototypes/DeltaV/GameRules/events.yml
@@ -38,7 +38,7 @@
- type: StationEvent
startAnnouncement: true
reoccurrenceDelay: 12
- minimumPlayers: 1
+ minimumPlayers: 5
- type: VentCrittersRule
entries:
- id: MobXeno
@@ -78,8 +78,8 @@
noSpawn: true
components:
- type: StationEvent
- weight: 7.5
- minimumPlayers: 10
+ weight: 8.5
+ minimumPlayers: 40
maxOccurrences: 1
duration: 1
- type: PirateRadioSpawnRule
diff --git a/Resources/Prototypes/DeltaV/Traits/neutral.yml b/Resources/Prototypes/DeltaV/Traits/neutral.yml
index e63367b7ef..b3251f8835 100644
--- a/Resources/Prototypes/DeltaV/Traits/neutral.yml
+++ b/Resources/Prototypes/DeltaV/Traits/neutral.yml
@@ -1,6 +1,9 @@
#- type: trait
# id: ScottishAccent
-# category: Speech
+# category: TraitsSpeechAccents
# points: 0
+# requirements:
+# - !type:CharacterItemGroupRequirement
+# group: TraitsAccents
# components:
# - type: ScottishAccent
diff --git a/Resources/Prototypes/Entities/Mobs/Cyborgs/base_borg_chassis.yml b/Resources/Prototypes/Entities/Mobs/Cyborgs/base_borg_chassis.yml
index cbc2ae65c0..9d522a5b20 100644
--- a/Resources/Prototypes/Entities/Mobs/Cyborgs/base_borg_chassis.yml
+++ b/Resources/Prototypes/Entities/Mobs/Cyborgs/base_borg_chassis.yml
@@ -218,10 +218,10 @@
- Normal
- type: LanguageKnowledge
speaks:
- - GalacticCommon
+ - TauCetiBasic
- RobotTalk
understands:
- - GalacticCommon
+ - TauCetiBasic
- RobotTalk
- type: PsionicInsulation
diff --git a/Resources/Prototypes/Entities/Mobs/NPCs/animals.yml b/Resources/Prototypes/Entities/Mobs/NPCs/animals.yml
index 3e6160bd8f..536c9156f6 100644
--- a/Resources/Prototypes/Entities/Mobs/NPCs/animals.yml
+++ b/Resources/Prototypes/Entities/Mobs/NPCs/animals.yml
@@ -1370,7 +1370,7 @@
understands:
- Monkey
- Kobold
- - GalacticCommon
+ - TauCetiBasic
- type: NpcFactionMember
factions:
- Syndicate
@@ -2002,9 +2002,9 @@
bloodMaxVolume: 50
- type: LanguageKnowledge
speaks:
- - GalacticCommon
+ - TauCetiBasic
understands:
- - GalacticCommon
+ - TauCetiBasic
- type: entity
name: penguin
@@ -2271,7 +2271,7 @@
- Xeno
understands:
- Xeno
- - GalacticCommon
+ - TauCetiBasic
- type: InteractionPopup
successChance: 0.5
interactSuccessString: petting-success-tarantula
@@ -2904,7 +2904,7 @@
- Cat
understands:
- Cat
- - GalacticCommon
+ - TauCetiBasic
- type: entity
name: space cat
@@ -3451,7 +3451,7 @@
speaks:
- RootSpeak
understands:
- - GalacticCommon
+ - TauCetiBasic
- RootSpeak
- type: entity
diff --git a/Resources/Prototypes/Entities/Mobs/NPCs/dogs.yml b/Resources/Prototypes/Entities/Mobs/NPCs/dogs.yml
index 22da758372..2bcd377626 100644
--- a/Resources/Prototypes/Entities/Mobs/NPCs/dogs.yml
+++ b/Resources/Prototypes/Entities/Mobs/NPCs/dogs.yml
@@ -89,7 +89,7 @@
- Dog
understands:
- Dog
- - GalacticCommon
+ - TauCetiBasic
- type: entity
parent: MobPibble
diff --git a/Resources/Prototypes/Entities/Mobs/NPCs/pets.yml b/Resources/Prototypes/Entities/Mobs/NPCs/pets.yml
index 9237276f78..e6fc10e7f6 100644
--- a/Resources/Prototypes/Entities/Mobs/NPCs/pets.yml
+++ b/Resources/Prototypes/Entities/Mobs/NPCs/pets.yml
@@ -40,7 +40,7 @@
speaks:
- Dog
understands:
- - GalacticCommon
+ - TauCetiBasic
- Dog
- type: entity
@@ -131,7 +131,7 @@
speaks:
- Cat
understands:
- - GalacticCommon
+ - TauCetiBasic
- Cat
- type: entity
@@ -155,7 +155,7 @@
speaks:
- Cat
understands:
- - GalacticCommon
+ - TauCetiBasic
- Cat
- type: entity
@@ -310,7 +310,7 @@
speaks:
- Dog
understands:
- - GalacticCommon
+ - TauCetiBasic
- Dog
- type: InteractionPopup
successChance: 0.5
@@ -415,7 +415,7 @@
speaks:
- Dog
understands:
- - GalacticCommon
+ - TauCetiBasic
- Dog
- type: InteractionPopup
successChance: 0.7
@@ -582,7 +582,7 @@
speaks:
- Fox
understands:
- - GalacticCommon
+ - TauCetiBasic
- Fox
- type: entity
@@ -635,7 +635,7 @@
speaks:
- Mouse
understands:
- - GalacticCommon
+ - TauCetiBasic
- Mouse
- type: entity
@@ -815,7 +815,7 @@
speaks:
- Bubblish
understands:
- - GalacticCommon
+ - TauCetiBasic
- Bubblish
- type: entity
@@ -855,7 +855,7 @@
speaks:
- Monkey
understands:
- - GalacticCommon
+ - TauCetiBasic
- Monkey
- Kobold
@@ -889,5 +889,5 @@
speaks:
- Crab
understands:
- - GalacticCommon
+ - TauCetiBasic
- Crab
diff --git a/Resources/Prototypes/Entities/Mobs/NPCs/regalrat.yml b/Resources/Prototypes/Entities/Mobs/NPCs/regalrat.yml
index 129484420d..45eda02eaa 100644
--- a/Resources/Prototypes/Entities/Mobs/NPCs/regalrat.yml
+++ b/Resources/Prototypes/Entities/Mobs/NPCs/regalrat.yml
@@ -122,10 +122,10 @@
voice: Astral
- type: LanguageKnowledge
speaks:
- - GalacticCommon
+ - TauCetiBasic
- Mouse
understands:
- - GalacticCommon
+ - TauCetiBasic
- Mouse
- type: entity
@@ -303,7 +303,7 @@
speaks:
- Mouse
understands:
- - GalacticCommon
+ - TauCetiBasic
- Mouse
- type: FireVisuals
sprite: Mobs/Effects/onfire.rsi
diff --git a/Resources/Prototypes/Entities/Mobs/NPCs/silicon.yml b/Resources/Prototypes/Entities/Mobs/NPCs/silicon.yml
index ff322e8dea..c02a1a2db0 100644
--- a/Resources/Prototypes/Entities/Mobs/NPCs/silicon.yml
+++ b/Resources/Prototypes/Entities/Mobs/NPCs/silicon.yml
@@ -111,10 +111,10 @@
- type: PsionicInsulation
- type: LanguageKnowledge #для ТТС
speaks:
- - GalacticCommon
+ - TauCetiBasic
- RobotTalk
understands:
- - GalacticCommon
+ - TauCetiBasic
- RobotTalk
- type: entity
diff --git a/Resources/Prototypes/Entities/Mobs/NPCs/xeno.yml b/Resources/Prototypes/Entities/Mobs/NPCs/xeno.yml
index 39a88267fb..71a4bbffab 100644
--- a/Resources/Prototypes/Entities/Mobs/NPCs/xeno.yml
+++ b/Resources/Prototypes/Entities/Mobs/NPCs/xeno.yml
@@ -248,10 +248,10 @@
- DoorBumpOpener
- type: LanguageKnowledge
speaks:
- - GalacticCommon
+ - TauCetiBasic
- Xeno
understands:
- - GalacticCommon
+ - TauCetiBasic
- Xeno
- type: entity
diff --git a/Resources/Prototypes/Entities/Mobs/Player/admin_ghost.yml b/Resources/Prototypes/Entities/Mobs/Player/admin_ghost.yml
index 6c9ec2049f..e0300fa503 100644
--- a/Resources/Prototypes/Entities/Mobs/Player/admin_ghost.yml
+++ b/Resources/Prototypes/Entities/Mobs/Player/admin_ghost.yml
@@ -25,6 +25,8 @@
- type: GhostHearing
- type: Hands
- type: Puller
+ pushAcceleration: 1000000 # Will still be capped in max speed
+ maxPushRange: 20
- type: CombatMode
- type: Physics
ignorePaused: true
diff --git a/Resources/Prototypes/Entities/Mobs/Player/ipc.yml b/Resources/Prototypes/Entities/Mobs/Player/ipc.yml
index a28cf7a8d6..e416146d9b 100644
--- a/Resources/Prototypes/Entities/Mobs/Player/ipc.yml
+++ b/Resources/Prototypes/Entities/Mobs/Player/ipc.yml
@@ -113,10 +113,10 @@
- MobLayer
- type: LanguageKnowledge
speaks:
- - GalacticCommon
+ - TauCetiBasic
- RobotTalk
understands:
- - GalacticCommon
+ - TauCetiBasic
- RobotTalk
- type: WeldingHealable
- type: PsionicInsulation
diff --git a/Resources/Prototypes/Entities/Mobs/Species/base.yml b/Resources/Prototypes/Entities/Mobs/Species/base.yml
index 3256470a7e..fdaab86876 100644
--- a/Resources/Prototypes/Entities/Mobs/Species/base.yml
+++ b/Resources/Prototypes/Entities/Mobs/Species/base.yml
@@ -221,9 +221,9 @@
- type: CanEscapeInventory # Carrying system from nyanotrasen.
- type: LanguageKnowledge # This is here so even if species doesn't have a defined language, they at least speak GC
speaks:
- - GalacticCommon
+ - TauCetiBasic
understands:
- - GalacticCommon
+ - TauCetiBasic
- type: Tag
tags:
- CanPilot
diff --git a/Resources/Prototypes/Entities/Mobs/Species/diona.yml b/Resources/Prototypes/Entities/Mobs/Species/diona.yml
index 5c8873451b..5b64551146 100644
--- a/Resources/Prototypes/Entities/Mobs/Species/diona.yml
+++ b/Resources/Prototypes/Entities/Mobs/Species/diona.yml
@@ -104,10 +104,10 @@
- Dead
- type: LanguageKnowledge
speaks:
- - GalacticCommon
+ - TauCetiBasic
- RootSpeak
understands:
- - GalacticCommon
+ - TauCetiBasic
- RootSpeak
- type: TraitSpeedModifier
sprintModifier: 0.75
diff --git a/Resources/Prototypes/Entities/Mobs/Species/dwarf.yml b/Resources/Prototypes/Entities/Mobs/Species/dwarf.yml
index d2f075383a..938a100aee 100644
--- a/Resources/Prototypes/Entities/Mobs/Species/dwarf.yml
+++ b/Resources/Prototypes/Entities/Mobs/Species/dwarf.yml
@@ -53,10 +53,10 @@
speechSounds: Bass
- type: LanguageKnowledge
speaks:
- - GalacticCommon
+ - TauCetiBasic
- SolCommon
understands:
- - GalacticCommon
+ - TauCetiBasic
- SolCommon
- type: LightweightDrunk
boozeStrengthMultiplier: 0.5
diff --git a/Resources/Prototypes/Entities/Mobs/Species/harpy.yml b/Resources/Prototypes/Entities/Mobs/Species/harpy.yml
index 8882da868b..8d657d3532 100644
--- a/Resources/Prototypes/Entities/Mobs/Species/harpy.yml
+++ b/Resources/Prototypes/Entities/Mobs/Species/harpy.yml
@@ -117,11 +117,11 @@
- ShoesRequiredStepTriggerImmune
- type: LanguageKnowledge
speaks:
- - GalacticCommon
- - SolCommon
+ - TauCetiBasic
+ - Tradeband
understands:
- - GalacticCommon
- - SolCommon
+ - TauCetiBasic
+ - Tradeband
- type: StepTriggerImmune
whitelist:
types:
diff --git a/Resources/Prototypes/Entities/Mobs/Species/human.yml b/Resources/Prototypes/Entities/Mobs/Species/human.yml
index 06de920aaf..169c77b67d 100644
--- a/Resources/Prototypes/Entities/Mobs/Species/human.yml
+++ b/Resources/Prototypes/Entities/Mobs/Species/human.yml
@@ -18,10 +18,10 @@
amount: 5
- type: LanguageKnowledge
speaks:
- - GalacticCommon
+ - TauCetiBasic
- SolCommon
understands:
- - GalacticCommon
+ - TauCetiBasic
- SolCommon
- type: entity
diff --git a/Resources/Prototypes/Entities/Mobs/Species/moth.yml b/Resources/Prototypes/Entities/Mobs/Species/moth.yml
index b6cca2b5f4..3bda264328 100644
--- a/Resources/Prototypes/Entities/Mobs/Species/moth.yml
+++ b/Resources/Prototypes/Entities/Mobs/Species/moth.yml
@@ -25,10 +25,10 @@
speechVerb: Moth
- type: LanguageKnowledge
speaks:
- - GalacticCommon
+ - TauCetiBasic
- Moffic
understands:
- - GalacticCommon
+ - TauCetiBasic
- Moffic
- type: TypingIndicator
proto: moth
diff --git a/Resources/Prototypes/Entities/Mobs/Species/reptilian.yml b/Resources/Prototypes/Entities/Mobs/Species/reptilian.yml
index 7cd347fd41..8368e90b5d 100644
--- a/Resources/Prototypes/Entities/Mobs/Species/reptilian.yml
+++ b/Resources/Prototypes/Entities/Mobs/Species/reptilian.yml
@@ -67,10 +67,10 @@
- DoorBumpOpener
- type: LanguageKnowledge
speaks:
- - GalacticCommon
+ - TauCetiBasic
- Draconic
understands:
- - GalacticCommon
+ - TauCetiBasic
- Draconic
- type: entity
diff --git a/Resources/Prototypes/Entities/Mobs/Species/slime.yml b/Resources/Prototypes/Entities/Mobs/Species/slime.yml
index c10e68b2bb..cfc243c155 100644
--- a/Resources/Prototypes/Entities/Mobs/Species/slime.yml
+++ b/Resources/Prototypes/Entities/Mobs/Species/slime.yml
@@ -76,10 +76,10 @@
maxSaturation: 15
- type: LanguageKnowledge
speaks:
- - GalacticCommon
+ - TauCetiBasic
- Bubblish
understands:
- - GalacticCommon
+ - TauCetiBasic
- Bubblish
- type: entity
diff --git a/Resources/Prototypes/Entities/Objects/Devices/Circuitboards/computer.yml b/Resources/Prototypes/Entities/Objects/Devices/Circuitboards/computer.yml
index 1210f302fc..35a941e759 100644
--- a/Resources/Prototypes/Entities/Objects/Devices/Circuitboards/computer.yml
+++ b/Resources/Prototypes/Entities/Objects/Devices/Circuitboards/computer.yml
@@ -21,8 +21,8 @@
- type: entity
parent: BaseComputerCircuitboard
id: AlertsComputerCircuitboard
- name: alerts computer board
- description: A computer printed circuit board for an alerts computer.
+ name: atmospheric alerts computer board
+ description: A computer printed circuit board for an atmospheric alerts computer.
components:
- type: ComputerBoard
prototype: ComputerAlert
diff --git a/Resources/Prototypes/Entities/Objects/Devices/translator_implants.yml b/Resources/Prototypes/Entities/Objects/Devices/translator_implants.yml
index da42b2774b..d430f5ea5d 100644
--- a/Resources/Prototypes/Entities/Objects/Devices/translator_implants.yml
+++ b/Resources/Prototypes/Entities/Objects/Devices/translator_implants.yml
@@ -1,26 +1,26 @@
- type: entity
parent: BaseSubdermalImplant
- id: BasicGalacticCommonTranslatorImplant
+ id: BasicTauCetiBasicTranslatorImplant
name: basic common translator implant
description: Provides your illiterate friends the ability to understand the common galactic tongue.
noSpawn: true
components:
- type: TranslatorImplant
understood:
- - GalacticCommon
+ - TauCetiBasic
- type: entity
parent: BaseSubdermalImplant
- id: GalacticCommonTranslatorImplant
+ id: TauCetiBasicTranslatorImplant
name: advanced common translator implant
description: A more advanced version of the translator implant, teaches your illiterate friends the ability to both speak and understand the galactic tongue!
noSpawn: true
components:
- type: TranslatorImplant
understood:
- - GalacticCommon
+ - TauCetiBasic
spoken:
- - GalacticCommon
+ - TauCetiBasic
- type: entity
parent: BaseSubdermalImplant
@@ -35,7 +35,7 @@
spoken:
- Bubblish
requires:
- - GalacticCommon
+ - TauCetiBasic
- type: entity
parent: BaseSubdermalImplant
@@ -50,7 +50,7 @@
spoken:
- Nekomimetic
requires:
- - GalacticCommon
+ - TauCetiBasic
- type: entity
parent: BaseSubdermalImplant
@@ -65,7 +65,7 @@
spoken:
- Draconic
requires:
- - GalacticCommon
+ - TauCetiBasic
- type: entity
parent: BaseSubdermalImplant
@@ -80,7 +80,7 @@
spoken:
- Canilunzt
requires:
- - GalacticCommon
+ - TauCetiBasic
- type: entity
parent: BaseSubdermalImplant
@@ -95,7 +95,7 @@
spoken:
- SolCommon
requires:
- - GalacticCommon
+ - TauCetiBasic
- type: entity
parent: BaseSubdermalImplant
@@ -110,7 +110,7 @@
spoken:
- RootSpeak
requires:
- - GalacticCommon
+ - TauCetiBasic
- type: entity
parent: BaseSubdermalImplant
@@ -125,4 +125,4 @@
spoken:
- Moffic
requires:
- - GalacticCommon
+ - TauCetiBasic
diff --git a/Resources/Prototypes/Entities/Objects/Devices/translators.yml b/Resources/Prototypes/Entities/Objects/Devices/translators.yml
index 6aa7947c82..4a14e37156 100644
--- a/Resources/Prototypes/Entities/Objects/Devices/translators.yml
+++ b/Resources/Prototypes/Entities/Objects/Devices/translators.yml
@@ -67,13 +67,13 @@
components:
- type: HandheldTranslator
spoken:
- - GalacticCommon
+ - TauCetiBasic
- Canilunzt
understood:
- - GalacticCommon
+ - TauCetiBasic
- Canilunzt
requires:
- - GalacticCommon
+ - TauCetiBasic
- Canilunzt
- type: entity
@@ -84,13 +84,13 @@
components:
- type: HandheldTranslator
spoken:
- - GalacticCommon
+ - TauCetiBasic
- Bubblish
understood:
- - GalacticCommon
+ - TauCetiBasic
- Bubblish
requires:
- - GalacticCommon
+ - TauCetiBasic
- Bubblish
- type: entity
@@ -101,13 +101,13 @@
components:
- type: HandheldTranslator
spoken:
- - GalacticCommon
+ - TauCetiBasic
- Nekomimetic
understood:
- - GalacticCommon
+ - TauCetiBasic
- Nekomimetic
requires:
- - GalacticCommon
+ - TauCetiBasic
- Nekomimetic
- type: entity
@@ -118,13 +118,13 @@
components:
- type: HandheldTranslator
spoken:
- - GalacticCommon
+ - TauCetiBasic
- Draconic
understood:
- - GalacticCommon
+ - TauCetiBasic
- Draconic
requires:
- - GalacticCommon
+ - TauCetiBasic
- Draconic
- type: entity
@@ -135,13 +135,13 @@
components:
- type: HandheldTranslator
spoken:
- - GalacticCommon
+ - TauCetiBasic
- SolCommon
understood:
- - GalacticCommon
+ - TauCetiBasic
- SolCommon
requires:
- - GalacticCommon
+ - TauCetiBasic
- SolCommon
- type: entity
@@ -152,13 +152,13 @@
components:
- type: HandheldTranslator
spoken:
- - GalacticCommon
+ - TauCetiBasic
- RootSpeak
understood:
- - GalacticCommon
+ - TauCetiBasic
- RootSpeak
requires:
- - GalacticCommon
+ - TauCetiBasic
- RootSpeak
- type: entity
@@ -169,13 +169,13 @@
components:
- type: HandheldTranslator
spoken:
- - GalacticCommon
+ - TauCetiBasic
- Moffic
understood:
- - GalacticCommon
+ - TauCetiBasic
- Moffic
requires:
- - GalacticCommon
+ - TauCetiBasic
- Moffic
- type: entity
@@ -186,13 +186,13 @@
components:
- type: HandheldTranslator
spoken:
- - GalacticCommon
+ - TauCetiBasic
- Xeno
understood:
- - GalacticCommon
+ - TauCetiBasic
- Xeno
requires:
- - GalacticCommon
+ - TauCetiBasic
- type: entity
id: AnimalTranslator
@@ -217,5 +217,5 @@
- Kobold
- Hissing
requires:
- - GalacticCommon
+ - TauCetiBasic
setLanguageOnInteract: false
diff --git a/Resources/Prototypes/Entities/Objects/Misc/translator_implanters.yml b/Resources/Prototypes/Entities/Objects/Misc/translator_implanters.yml
index 8b5b262ff8..92e21e5140 100644
--- a/Resources/Prototypes/Entities/Objects/Misc/translator_implanters.yml
+++ b/Resources/Prototypes/Entities/Objects/Misc/translator_implanters.yml
@@ -10,7 +10,7 @@
name: basic common translator implanter
components:
- type: Implanter
- implant: BasicGalacticCommonTranslatorImplant
+ implant: BasicTauCetiBasicTranslatorImplant
- type: entity
id: AdvancedGalaticCommonTranslatorImplanter
@@ -18,7 +18,7 @@
name: advanced common translator implanter
components:
- type: Implanter
- implant: GalacticCommonTranslatorImplant
+ implant: TauCetiBasicTranslatorImplant
- type: entity
id: BubblishTranslatorImplanter
diff --git a/Resources/Prototypes/Entities/Objects/Weapons/Guns/LMGs/lmgs.yml b/Resources/Prototypes/Entities/Objects/Weapons/Guns/LMGs/lmgs.yml
index 49b2eeaada..a721f254c8 100644
--- a/Resources/Prototypes/Entities/Objects/Weapons/Guns/LMGs/lmgs.yml
+++ b/Resources/Prototypes/Entities/Objects/Weapons/Guns/LMGs/lmgs.yml
@@ -14,6 +14,7 @@
slots:
- Back
- type: Wieldable
+ - type: GunRequiresWield
- type: GunWieldBonus
minAngle: -20
maxAngle: -20
diff --git a/Resources/Prototypes/Entities/Objects/Weapons/Guns/Rifles/rifles.yml b/Resources/Prototypes/Entities/Objects/Weapons/Guns/Rifles/rifles.yml
index c55b2b6b09..2e7265a2c7 100644
--- a/Resources/Prototypes/Entities/Objects/Weapons/Guns/Rifles/rifles.yml
+++ b/Resources/Prototypes/Entities/Objects/Weapons/Guns/Rifles/rifles.yml
@@ -14,6 +14,8 @@
slots:
- Back
- suitStorage
+ - type: Wieldable
+ - type: GunRequiresWield
- type: AmmoCounter
- type: Gun
fireRate: 5
diff --git a/Resources/Prototypes/Entities/Objects/Weapons/Guns/Shotguns/shotguns.yml b/Resources/Prototypes/Entities/Objects/Weapons/Guns/Shotguns/shotguns.yml
index 52b05b6d60..d1635f4979 100644
--- a/Resources/Prototypes/Entities/Objects/Weapons/Guns/Shotguns/shotguns.yml
+++ b/Resources/Prototypes/Entities/Objects/Weapons/Guns/Shotguns/shotguns.yml
@@ -77,6 +77,8 @@
soundEmpty:
path: /Audio/Weapons/Guns/Empty/empty.ogg
fireOnDropChance: 0.3
+ - type: Wieldable
+ - type: GunRequiresWield
- type: ItemSlots
slots:
gun_magazine:
@@ -118,6 +120,8 @@
- type: Gun
fireRate: 2
fireOnDropChance: 0.5
+ - type: Wieldable
+ - type: GunRequiresWield
- type: BallisticAmmoProvider
capacity: 2
- type: Construction
@@ -146,6 +150,8 @@
- type: Clothing
sprite: DeltaV/Objects/Weapons/Guns/Shotguns/enforcer.rsi # Delta-V
- type: BallisticAmmoProvider
+ - type: Wieldable
+ - type: GunRequiresWield
- type: entity
parent: WeaponShotgunEnforcer
@@ -176,6 +182,8 @@
- type: Tag
tags:
- WeaponShotgunKammerer
+ - type: Wieldable
+ - type: GunRequiresWield
- type: entity
name: sawn-off shotgun
@@ -260,6 +268,8 @@
capacity: 1
- type: StaticPrice
price: 0
+ - type: Wieldable
+ - type: GunRequiresWield
- type: entity
name: improvised shotgun
diff --git a/Resources/Prototypes/Entities/Objects/Weapons/Guns/Snipers/snipers.yml b/Resources/Prototypes/Entities/Objects/Weapons/Guns/Snipers/snipers.yml
index cd003daf22..31dea1b7ab 100644
--- a/Resources/Prototypes/Entities/Objects/Weapons/Guns/Snipers/snipers.yml
+++ b/Resources/Prototypes/Entities/Objects/Weapons/Guns/Snipers/snipers.yml
@@ -18,6 +18,8 @@
- Back
- suitStorage
- type: AmmoCounter
+ - type: Wieldable
+ - type: GunRequiresWield
- type: Gun
fireRate: 0.75
selectedMode: SemiAuto
diff --git a/Resources/Prototypes/Entities/Stations/base.yml b/Resources/Prototypes/Entities/Stations/base.yml
index 0bf0f7f915..ab65c8b991 100644
--- a/Resources/Prototypes/Entities/Stations/base.yml
+++ b/Resources/Prototypes/Entities/Stations/base.yml
@@ -93,8 +93,8 @@
ruins:
hide: true
nameGrid: true
- minCount: 2
- maxCount: 2
+ minCount: 1
+ maxCount: 1
stationGrid: false
paths:
- /Maps/Ruins/DeltaV/biodome_satellite.yml #Delta V - Move to DV folder
@@ -153,4 +153,4 @@
id: BaseStationAllEventsEligible
abstract: true
components:
- - type: StationEventEligible # For when someone makes this more granular in the future.
\ No newline at end of file
+ - type: StationEventEligible # For when someone makes this more granular in the future.
diff --git a/Resources/Prototypes/Entities/Structures/Machines/Computers/base_structurecomputers.yml b/Resources/Prototypes/Entities/Structures/Machines/Computers/base_structurecomputers.yml
index b7ea7c6f6c..9468ecd452 100644
--- a/Resources/Prototypes/Entities/Structures/Machines/Computers/base_structurecomputers.yml
+++ b/Resources/Prototypes/Entities/Structures/Machines/Computers/base_structurecomputers.yml
@@ -62,11 +62,11 @@
priority: 1
- type: RequireProjectileTarget
- type: LanguageSpeaker
- currentLanguage: GalacticCommon
+ currentLanguage: TauCetiBasic
- type: LanguageKnowledge
speaks:
- - GalacticCommon
+ - TauCetiBasic
- RobotTalk
understands:
- - GalacticCommon
+ - TauCetiBasic
- RobotTalk
diff --git a/Resources/Prototypes/Entities/Structures/Machines/Computers/computers.yml b/Resources/Prototypes/Entities/Structures/Machines/Computers/computers.yml
index c3c6ec4c29..86a3db9b5a 100644
--- a/Resources/Prototypes/Entities/Structures/Machines/Computers/computers.yml
+++ b/Resources/Prototypes/Entities/Structures/Machines/Computers/computers.yml
@@ -1,8 +1,8 @@
- type: entity
parent: BaseComputer
id: ComputerAlert
- name: alerts computer
- description: Used to access the station's automated alert system.
+ name: atmospheric alerts computer
+ description: Used to access the station's automated atmospheric alert system.
components:
- type: Computer
board: AlertsComputerCircuitboard
@@ -13,9 +13,33 @@
- map: ["computerLayerKeyboard"]
state: generic_keyboard
- map: ["computerLayerScreen"]
- state: alert-2
+ state: alert-0
- map: ["computerLayerKeys"]
state: atmos_key
+ - type: GenericVisualizer
+ visuals:
+ enum.ComputerVisuals.Powered:
+ computerLayerScreen:
+ True: { visible: true, shader: unshaded }
+ False: { visible: false }
+ computerLayerKeys:
+ True: { visible: true, shader: unshaded }
+ False: { visible: true, shader: shaded }
+ enum.AtmosAlertsComputerVisuals.ComputerLayerScreen:
+ computerLayerScreen:
+ 0: { state: alert-0 }
+ 1: { state: alert-0 }
+ 2: { state: alert-1 }
+ 3: { state: alert-2 }
+ 4: { state: alert-2 }
+ - type: AtmosAlertsComputer
+ - type: ActivatableUI
+ singleUser: true
+ key: enum.AtmosAlertsComputerUiKey.Key
+ - type: UserInterface
+ interfaces:
+ - key: enum.AtmosAlertsComputerUiKey.Key
+ type: AtmosAlertsComputerBoundUserInterface
- type: entity
parent: BaseComputer
diff --git a/Resources/Prototypes/Entities/Structures/Machines/lathe.yml b/Resources/Prototypes/Entities/Structures/Machines/lathe.yml
index 0c8031c6f8..b2a1a92105 100644
--- a/Resources/Prototypes/Entities/Structures/Machines/lathe.yml
+++ b/Resources/Prototypes/Entities/Structures/Machines/lathe.yml
@@ -718,7 +718,6 @@
idleState: icon
runningState: icon
staticRecipes:
- - LPPC4Low
- ClothingEyesHudSecurity
- CombatKnife
- Flash
diff --git a/Resources/Prototypes/Entities/Structures/Machines/vending_machines.yml b/Resources/Prototypes/Entities/Structures/Machines/vending_machines.yml
index 02cdd80af3..f3f68660b2 100644
--- a/Resources/Prototypes/Entities/Structures/Machines/vending_machines.yml
+++ b/Resources/Prototypes/Entities/Structures/Machines/vending_machines.yml
@@ -105,10 +105,10 @@
- type: WiresVisuals
- type: LanguageKnowledge
speaks:
- - GalacticCommon
+ - TauCetiBasic
- RobotTalk
understands:
- - GalacticCommon
+ - TauCetiBasic
- RobotTalk
- type: VendingMachine
soundVend: /Audio/SimpleStation14/Machines/machine_vend.ogg
diff --git a/Resources/Prototypes/Entities/Structures/Specific/oracle.yml b/Resources/Prototypes/Entities/Structures/Specific/oracle.yml
index 2161c6d80d..1e3b9a5b7e 100644
--- a/Resources/Prototypes/Entities/Structures/Specific/oracle.yml
+++ b/Resources/Prototypes/Entities/Structures/Specific/oracle.yml
@@ -68,12 +68,12 @@
components:
- Item
- type: LanguageSpeaker
- currentLanguage: GalacticCommon
+ currentLanguage: TauCetiBasic
- type: LanguageKnowledge
speaks:
- - GalacticCommon
+ - TauCetiBasic
understands:
- - GalacticCommon
+ - TauCetiBasic
- type: weightedRandomEntity
diff --git a/Resources/Prototypes/Entities/Structures/Wallmounts/air_alarm.yml b/Resources/Prototypes/Entities/Structures/Wallmounts/air_alarm.yml
index 62f2000593..70e204f694 100644
--- a/Resources/Prototypes/Entities/Structures/Wallmounts/air_alarm.yml
+++ b/Resources/Prototypes/Entities/Structures/Wallmounts/air_alarm.yml
@@ -53,6 +53,8 @@
- AirAlarm
- type: AtmosDevice
- type: AirAlarm
+ - type: AtmosAlertsDevice
+ group: AirAlarm
- type: Clickable
- type: InteractionOutline
- type: UserInterface
diff --git a/Resources/Prototypes/Entities/Structures/Wallmounts/fire_alarm.yml b/Resources/Prototypes/Entities/Structures/Wallmounts/fire_alarm.yml
index 05988fbc21..c39adcde3b 100644
--- a/Resources/Prototypes/Entities/Structures/Wallmounts/fire_alarm.yml
+++ b/Resources/Prototypes/Entities/Structures/Wallmounts/fire_alarm.yml
@@ -42,6 +42,8 @@
- type: Clickable
- type: InteractionOutline
- type: FireAlarm
+ - type: AtmosAlertsDevice
+ group: FireAlarm
- type: ContainerFill
containers:
board: [ FireAlarmElectronics ]
diff --git a/Resources/Prototypes/GameRules/cargo_gifts.yml b/Resources/Prototypes/GameRules/cargo_gifts.yml
index 799805272d..546f60ccfd 100644
--- a/Resources/Prototypes/GameRules/cargo_gifts.yml
+++ b/Resources/Prototypes/GameRules/cargo_gifts.yml
@@ -46,7 +46,7 @@
- type: StationEvent
weight: 4
startDelay: 10
- duration: 240
+ duration: 180
earliestStart: 30
minimumPlayers: 10
- type: CargoGiftsRule
@@ -67,11 +67,11 @@
noSpawn: true
components:
- type: StationEvent
- weight: 4
+ weight: 5
startDelay: 10
duration: 120
- minimumPlayers: 40
- earliestStart: 30
+ minimumPlayers: 30
+ earliestStart: 45
- type: CargoGiftsRule
description: cargo-gift-vending
sender: cargo-gift-default-sender
@@ -90,7 +90,7 @@
noSpawn: true
components:
- type: StationEvent
- weight: 8
+ weight: 6
startDelay: 10
duration: 120
minimumPlayers: 30
diff --git a/Resources/Prototypes/GameRules/events.yml b/Resources/Prototypes/GameRules/events.yml
index 66a8f6ada8..713c00efcc 100644
--- a/Resources/Prototypes/GameRules/events.yml
+++ b/Resources/Prototypes/GameRules/events.yml
@@ -29,8 +29,8 @@
components:
- type: StationEvent
weight: 1
- maxOccurrences: 4 # Very annoying, makes containers unusable
- earliestStart: 1
+ maxOccurrences: 5 # Very annoying, makes containers unusable
+ earliestStart: 15
reoccurrenceDelay: 15
duration: 1
- type: BluespaceLockerRule
@@ -43,7 +43,7 @@
- type: StationEvent
weight: 10
duration: 1
- minimumPlayers: 7
+ minimumPlayers: 10
reoccurrenceDelay: 5
- type: BreakerFlipRule
@@ -54,8 +54,8 @@
components:
- type: StationEvent
startAnnouncement: true
- minimumPlayers: 25
- weight: 5
+ minimumPlayers: 35
+ weight: 4
duration: 1
reoccurrenceDelay: 5
- type: BureaucraticErrorRule
@@ -67,8 +67,8 @@
components:
- type: StationEvent
startAnnouncement: true
- minimumPlayers: 15
- weight: 5
+ minimumPlayers: 30
+ weight: 4
duration: 1
reoccurrenceDelay: 5
- type: ClericalErrorRule
@@ -79,9 +79,9 @@
noSpawn: true
components:
- type: StationEvent
- weight: 10
+ weight: 9
duration: 1
- minimumPlayers: 15
+ minimumPlayers: 20
reoccurrenceDelay: 25
- type: RandomEntityStorageSpawnRule
prototype: MobSkeletonCloset
@@ -96,7 +96,7 @@
duration: 1
earliestStart: 45
reoccurrenceDelay: 60
- minimumPlayers: 20
+ minimumPlayers: 35
- type: RandomSpawnRule
prototype: SpawnPointGhostDragon
@@ -110,7 +110,7 @@
duration: 1
earliestStart: 45
reoccurrenceDelay: 45
- minimumPlayers: 20
+ minimumPlayers: 25
- type: NinjaSpawnRule
# TODO there's already a glimmer revenant rule. One of them might be broken.
@@ -133,7 +133,7 @@
noSpawn: true
components:
- type: StationEvent
- weight: 10
+ weight: 9
duration: 1
reoccurrenceDelay: 4 # Please no 10 false alarms in a row.
- type: FalseAlarmRule
@@ -175,8 +175,8 @@
- type: StationEvent
earliestStart: 30
reoccurrenceDelay: 5
- weight: 7.5
- minimumPlayers: 7 #Enough to hopefully have at least one engineering guy
+ weight: 7
+ minimumPlayers: 15 #Enough to hopefully have at least one engineering guy
startAnnouncement: true
endAnnouncement: true
duration: null #ending is handled by MeteorSwarmRule
@@ -267,7 +267,7 @@
noSpawn: true
components:
- type: StationEvent
- weight: 5
+ weight: 4
duration: 1
reoccurrenceDelay: 10
maxOccurrences: 3 # Annoying and rarely if ever interesting
@@ -339,7 +339,7 @@
startDelay: 10
earliestStart: 20
reoccurrenceDelay: 12
- minimumPlayers: 15
+ minimumPlayers: 20
weight: 5
duration: 60
- type: VentCrittersRule
@@ -361,7 +361,7 @@
startDelay: 10
earliestStart: 20
reoccurrenceDelay: 15
- minimumPlayers: 15
+ minimumPlayers: 20
weight: 5
duration: 60
- type: VentCrittersRule
@@ -376,7 +376,7 @@
noSpawn: true
components:
- type: StationEvent
- minimumPlayers: 1
+ minimumPlayers: 7
- type: VentCrittersRule
entries:
- id: MobAdultSlimesBlueAngry
@@ -392,7 +392,7 @@
noSpawn: true
components:
- type: StationEvent
- minimumPlayers: 1
+ minimumPlayers: 7
- type: VentCrittersRule
entries:
- id: MobGiantSpiderAngry
@@ -423,9 +423,9 @@
- type: StationEvent
id: VentCritters
earliestStart: 15
- minimumPlayers: 15
+ minimumPlayers: 25
weight: 4
- duration: 60
+ duration: 45
- type: VentCrittersRule
entries:
- id: MobGiantSpiderVampireAngry
@@ -439,7 +439,7 @@
- type: StationEvent
earliestStart: 60
reoccurrenceDelay: 60
- minimumPlayers: 15
+ minimumPlayers: 25
weight: 2
duration: 1
- type: ZombieRule
@@ -474,7 +474,7 @@
- type: StationEvent
earliestStart: 60
weight: 3
- minimumPlayers: 15
+ minimumPlayers: 25
reoccurrenceDelay: 45
duration: 1
- type: LoadMapRule
@@ -547,9 +547,9 @@
noSpawn: true
components:
- type: StationEvent
- earliestStart: 0
+ earliestStart: 10
reoccurrenceDelay: 5
minimumPlayers: 20
- weight: 5
+ weight: 4
- type: MobReplacementRule
numberToReplace: 1
diff --git a/Resources/Prototypes/GameRules/midround.yml b/Resources/Prototypes/GameRules/midround.yml
index bb870f6007..d8d44ffbde 100644
--- a/Resources/Prototypes/GameRules/midround.yml
+++ b/Resources/Prototypes/GameRules/midround.yml
@@ -40,12 +40,10 @@
maxRange:
min: 1
max: 3
- playerRatio: 1
+ playerRatio: 10
allowNonHumans: true
multiAntagSetting: All
startingGear: ThiefGear
- components:
- - type: Pacified
mindComponents:
- type: ThiefRole
prototype: Thief
diff --git a/Resources/Prototypes/Language/Species-Specific/diona.yml b/Resources/Prototypes/Language/Species-Specific/diona.yml
new file mode 100644
index 0000000000..52c7741457
--- /dev/null
+++ b/Resources/Prototypes/Language/Species-Specific/diona.yml
@@ -0,0 +1,18 @@
+# Spoken by dionas.
+# TODO: Replace this with a much better language.
+- type: language
+ id: RootSpeak
+ speech:
+ color: "#ce5e14dd"
+ fontId: Noganas
+ obfuscation:
+ !type:SyllableObfuscation
+ minSyllables: 1
+ maxSyllables: 5
+ replacement:
+ - хс
+ - зт
+ - кр
+ - ст
+ - ш
+ - шш
diff --git a/Resources/Prototypes/Language/Species-Specific/moth.yml b/Resources/Prototypes/Language/Species-Specific/moth.yml
new file mode 100644
index 0000000000..341ebf714c
--- /dev/null
+++ b/Resources/Prototypes/Language/Species-Specific/moth.yml
@@ -0,0 +1,69 @@
+# Spoken by moths.
+# TODO: Replace this with a much better language.
+- type: language
+ id: Moffic
+ speech:
+ color: "#c7df2edd"
+ fontId: Copperplate
+ obfuscation:
+ !type:SyllableObfuscation
+ minSyllables: 2 # Replacements are really short
+ maxSyllables: 4
+ replacement:
+ - ар
+ - и
+ - гар
+ - сек
+ - мо
+ - фф
+ - ок
+ - гж
+ - оё
+ - га
+ - ла
+ - ле
+ - лит
+ - югг
+ - ван
+ - дарр
+ - наэ
+ - мёт
+ - идд
+ - хво
+ - йа
+ - па
+ - хэн
+ - за
+ - ан
+ - дет
+ - атт
+ - на
+ - гё
+ - бпа
+ - инт
+ - тук
+ - ом
+ - нар
+ - тва
+ - ма
+ - даг
+ - сйа
+ - вии
+ - вуо
+ - эил
+ - тун
+ - кайт
+ - тэх
+ - ва
+ - хэи
+ - хуо
+ - суо
+ - АААААААА
+ - тен
+ - йа
+ - хеу
+ - сту
+ - ухр
+ - укр
+ - ви
+ - хён
diff --git a/Resources/Prototypes/Language/Species-Specific/nekomimetic.yml b/Resources/Prototypes/Language/Species-Specific/nekomimetic.yml
new file mode 100644
index 0000000000..9e24b31922
--- /dev/null
+++ b/Resources/Prototypes/Language/Species-Specific/nekomimetic.yml
@@ -0,0 +1,60 @@
+# A mess of broken Japanese, spoken by Felinds and Oni
+# TODO: Replace this with a much better language.
+- type: language
+ id: Nekomimetic
+ speech:
+ color: "#df57aaee"
+ fontId: Manga
+ obfuscation:
+ !type:SyllableObfuscation
+ minSyllables: 1
+ maxSyllables: 3 # May be too long even, we'll see.
+ replacement:
+ - неко
+ - нян
+ - мими
+ - ми
+ - мофу
+ - фува
+ - кьяя
+ - кавай
+ - пока
+ - муня
+ - пуни
+ - мунью
+ - уфуфу
+ - ича
+ - доки
+ - кьюн
+ - кусу
+ - ня
+ - няя
+ - десу
+ - кис
+ - ама
+ - чуу
+ - бака
+ - хево
+ - буп
+ - гато
+ - кит
+ - сюн
+ - йори
+ - соу
+ - бака
+ - чан
+ - сан
+ - кун
+ - махо
+ - йатта
+ - сукки
+ - усаги
+ - домо
+ - ори
+ - ува
+ - заазаа
+ - шику
+ - пуру
+ - ира
+ - хето
+ - етто
diff --git a/Resources/Prototypes/Language/Species-Specific/reptilian.yml b/Resources/Prototypes/Language/Species-Specific/reptilian.yml
new file mode 100644
index 0000000000..077648c304
--- /dev/null
+++ b/Resources/Prototypes/Language/Species-Specific/reptilian.yml
@@ -0,0 +1,95 @@
+# Spoken by the Lizard race.
+# TODO: Replace this with a much better language.
+- type: language
+ id: Draconic
+ speech:
+ color: "#2aca2add"
+ obfuscation:
+ !type:SyllableObfuscation
+ minSyllables: 2
+ maxSyllables: 4
+ replacement:
+ - за
+ - аз
+ - зе
+ - ез
+ - зи
+ - из
+ - зо
+ - оз
+ - зу
+ - уз
+ - зс
+ - сз
+ - ха
+ - ах
+ - хе
+ - ех
+ - хи
+ - их
+ - хо
+ - ох
+ - ху
+ - ух
+ - хс
+ - сш
+ - ла
+ - ал
+ - ле
+ - ел
+ - ли
+ - ил
+ - ло
+ - ол
+ - лу
+ - ул
+ - лс
+ - сл
+ - ка
+ - ак
+ - ке
+ - ек
+ - ки
+ - ик
+ - ко
+ - ок
+ - ку
+ - ук
+ - кс
+ - ск
+ - са
+ - ас
+ - се
+ - ес
+ - си
+ - ис
+ - со
+ - ос
+ - су
+ - ус
+ - сс
+ - сс
+ - ра
+ - ар
+ - ре
+ - ер
+ - ри
+ - ир
+ - ро
+ - ор
+ - ру
+ - ур
+ - рс
+ - ср
+ - аа
+ - а
+ - ее
+ - е
+ - ии
+ - и
+ - оо
+ - о
+ - уу
+ - у
+ - сс
+ - с
diff --git a/Resources/Prototypes/Language/Species-Specific/slimeperson.yml b/Resources/Prototypes/Language/Species-Specific/slimeperson.yml
new file mode 100644
index 0000000000..d980f58c30
--- /dev/null
+++ b/Resources/Prototypes/Language/Species-Specific/slimeperson.yml
@@ -0,0 +1,26 @@
+# Spoken by slimes.
+# TODO: Replace this with a much better language.
+- type: language
+ id: Bubblish
+ speech:
+ color: "#00a3e2dd"
+ fontId: RubikBubbles
+ obfuscation:
+ !type:SyllableObfuscation
+ minSyllables: 1
+ maxSyllables: 3
+ replacement:
+ - блоб
+ - плоп
+ - поп
+ - боп
+ - бооп
+ - блюм
+ - бабл-бламп
+ - блаааамп
+ - блаби
+ - блюмс
+ - блип
+ - бульк
+ - буль
+ - були
diff --git a/Resources/Prototypes/Language/Species-Specific/vulpkanin.yml b/Resources/Prototypes/Language/Species-Specific/vulpkanin.yml
new file mode 100644
index 0000000000..104777691b
--- /dev/null
+++ b/Resources/Prototypes/Language/Species-Specific/vulpkanin.yml
@@ -0,0 +1,47 @@
+# Spoken by the Vulpkanin race.
+# TODO: Replace this with a much better language.
+- type: language
+ id: Canilunzt
+ speech:
+ color: "#d69b3dcc"
+ obfuscation:
+ !type:SyllableObfuscation
+ minSyllables: 1
+ maxSyllables: 4
+ replacement:
+ - рур
+ - йа
+ - цен
+ - равр
+ - ваф
+ - кьюк
+ - тек
+ - кват
+ - ук
+ - ву
+ - вух
+ - тах
+ - тч
+ - щз
+ - ауч
+ - ист
+ - еин
+ - енчт
+ - звисшч
+ - тут
+ - мир
+ - во
+ - бис
+ - ес
+ - вор
+ - ник
+ - гро
+ - енем
+ - зандт
+ - джс
+ - пруно # no porno
+ - йифф
+ - ищт
+ - фа
+ - ва
+ - вульф
diff --git a/Resources/Prototypes/Language/Standard/elyran.yml b/Resources/Prototypes/Language/Standard/elyran.yml
new file mode 100644
index 0000000000..9348c43fa4
--- /dev/null
+++ b/Resources/Prototypes/Language/Standard/elyran.yml
@@ -0,0 +1,86 @@
+- type: language
+ id: Elyran
+ speech:
+ color: "#8282fbaa"
+ obfuscation:
+ !type:SyllableObfuscation
+ minSyllables: 1
+ maxSyllables: 4
+ replacement:
+ - аф
+ - ыф
+ - ба
+ - та
+ - за
+ - ид
+ - джим
+ - ха
+ - кха
+ - дал
+ - дхл
+ - ра
+ - зеу
+ - зен
+ - ум
+ - шн
+ - сид
+ - ад
+ - та
+ - за
+ - айн
+ - гха
+ - зир
+ - йин
+ - фа
+ - каф
+ - иам
+ - мим
+ - ал
+ - джа
+ - нон
+ - йа
+ - вав
+ - я
+ - йем
+ - зах
+ - хмл
+ - кс
+ - ини
+ - да
+ - кз
+ - ига
+ - их
+ - ля
+ - ульф
+ - кзе
+ - айв
+ - сит
+ - ах
+ - аарах
+ - джалаа
+ - сирт
+ - курт
+ - турк
+ - уст
+ - ирк
+ - кир
+ - мир
+ - ач
+ - оглу
+ - болу
+ - шек
+ - ше
+ - гоз
+ - миа
+ - ейжан
+ - хааз
+ - кйук
+ - тааб
+ - шанха
+ - ан
+ - саа
+ - сей
+ - ань
+ - ё
+ - я
+ - емь
diff --git a/Resources/Prototypes/Language/Standard/freespeak.yml b/Resources/Prototypes/Language/Standard/freespeak.yml
new file mode 100644
index 0000000000..c8c4fe6c1b
--- /dev/null
+++ b/Resources/Prototypes/Language/Standard/freespeak.yml
@@ -0,0 +1,259 @@
+- type: language
+ id: Freespeak
+ speech:
+ color: "#597d35"
+ obfuscation:
+ !type:SyllableObfuscation
+ minSyllables: 1
+ maxSyllables: 3
+ replacement:
+ - а
+ - аан
+ - аас
+ - аб
+ - аба
+ - ад
+ - аие
+ - афт
+ - аг
+ - аи
+ - айзе
+ - ак
+ - акие
+ - акй
+ - ар
+ - ата
+ - аур
+ - аус
+ - ба
+ - баат
+ - бащ
+ - бад
+ - бахе
+ - банд
+ - бе
+ - бен
+ - бер
+ - бхаа
+ - бху
+ - бра
+ - бурт
+ - кап
+ - сер
+ - ч
+ - ча
+ - чаар
+ - чале
+ - чало
+ - чил
+ - ком
+ - да
+ - даа
+ - дааж
+ - дат
+ - де
+ - дие
+ - дхаа
+ - ди
+ - дае
+ - дик
+ - дин
+ - диз
+ - до
+ - доз
+ - дош
+ - дюрх
+ - иер
+ - ек
+ - ер
+ - ес
+ - фал
+ - фанг
+ - фра
+ - фан
+ - га
+ - ган
+ - гао
+ - гие
+ - гиет
+ - герн
+ - гир
+ - гон
+ - грен
+ - гри
+ - гу
+ - гуда
+ - ха
+ - хаа
+ - хаи
+ - хаин
+ - хар
+ - хат
+ - хе
+ - хие
+ - хиер
+ - хект
+ - хеу
+ - хит
+ - хн
+ - хо
+ - хуа
+ - хук
+ - хул
+ - ич
+ - иг
+ - ин
+ - исч
+ - джа
+ - джаа
+ - джад
+ - джан
+ - джао
+ - джар
+ - джас
+ - джие
+ - джияо
+ - джин
+ - джинг
+ - ун
+ - ка
+ - каха
+ - кана
+ - кар
+ - кара
+ - каро
+ - ке
+ - кие
+ - келн
+ - кха
+ - кхада
+ - кхе
+ - кхи
+ - ко
+ - куо
+ - ку
+ - ла
+ - лаа
+ - лаат
+ - лад
+ - лада
+ - лана
+ - лане
+ - ле
+ - лие
+ - лейден
+ - лейс
+ - лен
+ - лай
+ - ло
+ - маа
+ - маан
+ - мод
+ - мост
+ - мудж
+ - мудже
+ - мукт
+ - на
+ - найя
+ - не
+ - ние
+ - нет
+ - нета
+ - нир
+ - нка
+ - уон
+ - уоп
+ - па
+ - паа
+ - пет
+ - фен
+ - фот
+ - пи
+ - пло
+ - про
+ - кйие
+ - ра
+ - раа
+ - рахе
+ - рахо
+ - ран
+ - рана
+ - рар
+ - ре
+ - ри
+ - рйие
+ - рин
+ - ро
+ - рона
+ - рош
+ - ртив
+ - саа
+ - саал
+ - саат
+ - сан
+ - санту
+ - сщ
+ - се
+ - сен
+ - ш
+ - ша
+ - шие
+ - ши
+ - шн
+ - шт
+ - шуо
+ - сощ
+ - сол
+ - соо
+ - сса
+ - стер
+ - сук
+ - сур
+ - та
+ - таан
+ - так
+ - така
+ - тал
+ - тан
+ - тар
+ - тен
+ - тенд
+ - тх
+ - тхо
+ - тили
+ - то
+ - тон
+ - тр
+ - ту
+ - тум
+ - тун
+ - удаа
+ - угр
+ - унге
+ - ут
+ - ва
+ - ваа
+ - ваад
+ - ваиб
+ - ве
+ - вен
+ - вер
+ - ви
+ - вис
+ - вол
+ - уик
+ - ву
+ - вут
+ - кси
+ - ксйао
+ - йа
+ - йах
+ - йон
+ - йу
+ - зас
+ - зе
+ - зу
+ - зи
+ - зо
+ - зорн
+ - зт
diff --git a/Resources/Prototypes/Language/Standard/solcommon.yml b/Resources/Prototypes/Language/Standard/solcommon.yml
new file mode 100644
index 0000000000..7d704df0c4
--- /dev/null
+++ b/Resources/Prototypes/Language/Standard/solcommon.yml
@@ -0,0 +1,33 @@
+- type: language
+ id: SolCommon
+ speech:
+ color: "#8282fbaa"
+ obfuscation:
+ !type:SyllableObfuscation
+ minSyllables: 1
+ maxSyllables: 4
+ replacement:
+ - тао
+ - ши
+ - тзу
+ - йи
+ - ком
+ - би
+ - ис
+ - я
+ - оп
+ - ви
+ - эд
+ - лек
+ - мо
+ - кле
+ - те
+ - дис
+ - ее
+ - ку
+ - кле
+ - вае
+ - лой
+ - пой
+ - хау
+ - тсе
diff --git a/Resources/Prototypes/Language/Standard/taucetibasic.yml b/Resources/Prototypes/Language/Standard/taucetibasic.yml
new file mode 100644
index 0000000000..72deef40e0
--- /dev/null
+++ b/Resources/Prototypes/Language/Standard/taucetibasic.yml
@@ -0,0 +1,31 @@
+# The "Default Language" other than Universal.
+- type: language
+ id: TauCetiBasic
+ obfuscation:
+ !type:SyllableObfuscation
+ minSyllables: 1
+ maxSyllables: 3
+ replacement:
+ - Бла
+ - Бла
+ - Бла
+ - динг-донг
+ - динг
+ - донг
+ - жиббер-жаббер
+ - жуббр
+ - бле
+ - зиппти
+ - зуп
+ - виббл
+ - воббл
+ - виггл
+ - яда
+ - мех
+ - нех
+ - брэ
+ - буэ
+ - бам
+ - звен
+ - дун
+ - блон
diff --git a/Resources/Prototypes/Language/Standard/tradeband.yml b/Resources/Prototypes/Language/Standard/tradeband.yml
new file mode 100644
index 0000000000..5784f2fc56
--- /dev/null
+++ b/Resources/Prototypes/Language/Standard/tradeband.yml
@@ -0,0 +1,258 @@
+- type: language
+ id: Tradeband
+ speech:
+ color: "#597d35"
+ obfuscation:
+ !type:SyllableObfuscation
+ minSyllables: 1
+ maxSyllables: 3
+ replacement:
+ - а
+ - акк
+ - аи
+ - ал
+ - али
+ - ам
+ - ама
+ - ами
+ - амо
+ - ан
+ - анг
+ - арме
+ - аве
+ - ба
+ - баи
+ - бар
+ - бат
+ - би
+ - блийе
+ - брис
+ - ка
+ - кан
+ - кант
+ - кар
+ - каре
+ - ке
+ - ки
+ - кис
+ - кит
+ - кла
+ - ко
+ - кул
+ - кур
+ - курт
+ - да
+ - дам
+ - данс
+ - де
+ - ди
+ - диер
+ - дим
+ - динс
+ - дорм
+ - ду
+ - дуро
+ - е
+ - ейокс
+ - йек
+ - екто
+ - йес
+ - его
+ - ел
+ - ен
+ - ент
+ - ер
+ - ере
+ - ерес
+ - ери
+ - еро
+ - ес
+ - ет
+ - екс
+ - фар
+ - фи
+ - фик
+ - файн
+ - фол
+ - фолл
+ - фри
+ - фро
+ - ген
+ - гил
+ - го
+ - гран
+ - хаб
+ - хо
+ - хук
+ - иа
+ - иам
+ - ибус
+ - идор
+ - ие
+ - иенс
+ - иер
+ - иеур
+ - иис
+ - ил
+ - ин
+ - ине
+ - инт
+ - ир
+ - ис
+ - исе
+ - ит
+ - итт
+ - жар
+ - же
+ - жо
+ - жор
+ - ла
+ - лар
+ - лав
+ - ле
+ - лиес
+ - лер
+ - лес
+ - ли
+ - либ
+ - лйе
+ - ло
+ - лу
+ - ма
+ - ман
+ - ману
+ - мар
+ - мари
+ - мас
+ - ме
+ - меа
+ - мие
+ - мейжо
+ - мен
+ - мес
+ - меум
+ - меус
+ - ми
+ - мйер
+ - мин
+ - мине
+ - мит
+ - мо
+ - мои
+ - мон
+ - монс
+ - морс
+ - моу
+ - мул
+ - на
+ - нам
+ - нэ
+ - неэ
+ - нент
+ - нес
+ - ни
+ - нит
+ - ном
+ - ну
+ - нум
+ - о
+ - ок
+ - окк
+ - ожйа
+ - ом
+ - омни
+ - ор
+ - ори
+ - оро
+ - ос
+ - оу
+ - оуб
+ - па
+ - пар
+ - парс
+ - пас
+ - плу
+ - плув
+ - по
+ - пол
+ - пос
+ - поу
+ - поус
+ - пре
+ - пу
+ - пуг
+ - пус
+ - кйе
+ - кйи
+ - ре
+ - ри
+ - рик
+ - рига
+ - рито
+ - ро
+ - ром
+ - са
+ - сал
+ - се
+ - сер
+ - серс
+ - сес
+ - сим
+ - сион
+ - со
+ - сол
+ - сом
+ - соу
+ - спер
+ - ссе
+ - сте
+ - су
+ - суис
+ - сул
+ - сур
+ - та
+ - тар
+ - те
+ - тийау
+ - тем
+ - темп
+ - тен
+ - тене
+ - тес
+ - ти
+ - тибус
+ - тйен
+ - тйон
+ - то
+ - тол
+ - тон
+ - тонс
+ - тоут
+ - тра
+ - траи
+ - тре
+ - троу
+ - туо
+ - тус
+ - тут
+ - уес
+ - уи
+ - ул
+ - ум
+ - ун
+ - упа
+ - ус
+ - ут
+ - укс
+ - ва
+ - ваил
+ - ве
+ - вен
+ - вени
+ - ви
+ - вйам
+ - вие
+ - во
+ - кзус
+ - за
+ - зйо
diff --git a/Resources/Prototypes/Language/animal.yml b/Resources/Prototypes/Language/animal.yml
new file mode 100644
index 0000000000..526207c5a9
--- /dev/null
+++ b/Resources/Prototypes/Language/animal.yml
@@ -0,0 +1,188 @@
+# Languages spoken by various critters.
+- type: language
+ id: Cat
+ obfuscation:
+ !type:SyllableObfuscation
+ minSyllables: 1
+ maxSyllables: 2
+ replacement:
+ - мурр
+ - мяу
+ - пурр
+ - мррмяу
+
+- type: language
+ id: Dog
+ obfuscation:
+ !type:SyllableObfuscation
+ minSyllables: 1
+ maxSyllables: 2
+ replacement:
+ - вуф
+ - гаф
+ - рруф
+ - рраф
+ - ррар
+ - гррар
+
+- type: language
+ id: Fox
+ obfuscation:
+ !type:SyllableObfuscation
+ minSyllables: 1
+ maxSyllables: 2
+ replacement:
+ - руфф
+ - рафф
+ - фрь
+ - гарр
+ - йип
+ - йап
+ - мьяах
+
+- type: language
+ id: Xeno
+ obfuscation:
+ !type:SyllableObfuscation
+ minSyllables: 1
+ maxSyllables: 8 # I was crazy once
+ replacement:
+ - С
+ - Р
+
+- type: language
+ id: Monkey
+ obfuscation:
+ !type:SyllableObfuscation
+ minSyllables: 1
+ maxSyllables: 8 # They locked me in a room...
+ replacement:
+ - у
+ - а
+
+- type: language
+ id: Mouse
+ obfuscation:
+ !type:SyllableObfuscation
+ minSyllables: 2
+ maxSyllables: 3
+ replacement:
+ - ску
+ - иик
+ - пи
+ - еп
+ - чуу
+ - ии
+ - фии
+ - хи
+
+- type: language
+ id: Chicken
+ obfuscation:
+ !type:SyllableObfuscation
+ minSyllables: 1
+ maxSyllables: 3
+ replacement:
+ - ку
+ - кудах
+ - тах
+
+- type: language
+ id: Duck
+ obfuscation:
+ !type:SyllableObfuscation
+ minSyllables: 1
+ maxSyllables: 3
+ replacement:
+ - кр
+ - як
+ - кряк
+
+- type: language
+ id: Cow
+ obfuscation:
+ !type:SyllableObfuscation
+ minSyllables: 1
+ maxSyllables: 3
+ replacement:
+ - му
+ - мууу
+
+- type: language
+ id: Sheep
+ obfuscation:
+ !type:SyllableObfuscation
+ minSyllables: 1
+ maxSyllables: 3
+ replacement:
+ - беее
+ - бее
+ - ее
+
+- type: language
+ id: Kangaroo
+ obfuscation:
+ !type:SyllableObfuscation
+ minSyllables: 1
+ maxSyllables: 3
+ replacement:
+ - шре
+ - ак
+ - чууу
+ - чооо
+
+- type: language
+ id: Pig
+ obfuscation:
+ !type:SyllableObfuscation
+ minSyllables: 1
+ maxSyllables: 3
+ replacement:
+ - хрю # Please someone come up with something better
+ - Йонкь
+
+- type: language
+ id: Crab
+ obfuscation:
+ !type:SyllableObfuscation
+ minSyllables: 1
+ maxSyllables: 3
+ replacement:
+ - клик
+ - клак
+ - ти
+ - пи
+ - тык
+ - кл
+ - ик
+
+- type: language
+ id: Kobold
+ obfuscation:
+ !type:SyllableObfuscation
+ minSyllables: 2
+ maxSyllables: 4
+ replacement:
+ - йифф
+ - ски
+ - гар
+ - грр
+ - ар
+ - скрик
+ - эт
+ - горнк
+ - хисс
+ - сс
+ - ии
+
+- type: language
+ id: Hissing
+ obfuscation:
+ !type:SyllableObfuscation
+ minSyllables: 2
+ maxSyllables: 4
+ replacement:
+ - хсс
+ - хисс
+ - сс
+ - исс
diff --git a/Resources/Prototypes/Language/genericlanguages.yml b/Resources/Prototypes/Language/genericlanguages.yml
new file mode 100644
index 0000000000..ebbadf9ba7
--- /dev/null
+++ b/Resources/Prototypes/Language/genericlanguages.yml
@@ -0,0 +1,47 @@
+# The universal language. This is technically used as a fallback for simulating the pre-languages
+# style of Chat, and is not normally accessible by players. It is however used by characters
+# with the Xenoglossy psionic power, as well as Ghosts, and AGhosts.
+- type: language
+ id: Universal
+ obfuscation:
+ !type:ReplacementObfuscation
+ replacement:
+ - "*непонятно*" # Never actually used
+
+# Used by Robots.
+# TODO: Replace this with much better languages. Yes, robots can have languages.
+- type: language
+ id: RobotTalk
+ speech:
+ fontId: Monospace
+ obfuscation:
+ !type:SyllableObfuscation
+ minSyllables: 1
+ maxSyllables: 10 # Crazy
+ replacement:
+ - 0
+ - 1
+
+# Example of a sign language. Used by the Sign Language trait.
+- type: language
+ id: Sign
+ speech:
+ allowRadio: false
+ requireSpeech: false
+ color: "#dddddd"
+ messageWrapOverrides:
+ Speak: chat-sign-language-message-wrap
+ Whisper: chat-sign-language-whisper-wrap
+ speechVerbOverrides:
+ - chat-speech-verb-sign-1
+ - chat-speech-verb-sign-2
+ - chat-speech-verb-sign-3
+ obfuscation:
+ !type:ReplacementObfuscation
+ replacement:
+ - что-то
+ - машет вам
+ - будто танцует
+ - криво показывает вам что-то
+ - указывает куда-то
+ - непонятливо крутит пальцами
diff --git a/Resources/Prototypes/Language/languages.yml b/Resources/Prototypes/Language/languages.yml
deleted file mode 100644
index 1ba533edd9..0000000000
--- a/Resources/Prototypes/Language/languages.yml
+++ /dev/null
@@ -1,583 +0,0 @@
-# The universal language, assumed if the entity has a UniversalLanguageSpeakerComponent.
-# Do not use otherwise. Making an entity explicitly understand/speak this language will NOT have the desired effect.
-- type: language
- id: Universal
- obfuscation:
- !type:ReplacementObfuscation
- replacement:
- - "*непонятно*" # Never actually used
-
-# The common galactic tongue.
-- type: language
- id: GalacticCommon
- obfuscation:
- !type:SyllableObfuscation
- minSyllables: 1
- maxSyllables: 3
- replacement:
- - Бла
- - Бла
- - Бла
- - динг-донг
- - динг
- - донг
- - жиббер-жаббер
- - жуббр
- - бле
- - зиппти
- - зуп
- - виббл
- - воббл
- - виггл
- - яда
- - мех
- - нех
- - брэ
- - буэ
- - бам
-
-# Spoken by slimes.
-- type: language
- id: Bubblish
- obfuscation:
- !type:SyllableObfuscation
- minSyllables: 1
- maxSyllables: 3
- replacement:
- - блоб
- - плоп
- - поп
- - боп
- - бооп
- - блюм
- - бабл-бламп
- - блаааамп
- - блаби
- - блюмс
- - блип
- - бульк
- - буль
- - були
-
-# Spoken by moths.
-- type: language
- id: Moffic
- obfuscation:
- !type:SyllableObfuscation
- minSyllables: 2 # Replacements are really short
- maxSyllables: 4
- replacement:
- - ар
- - и
- - гар
- - сек
- - мо
- - фф
- - ок
- - гж
- - оё
- - га
- - ла
- - ле
- - лит
- - югг
- - ван
- - дарр
- - наэ
- - мёт
- - идд
- - хво
- - йа
- - па
- - хэн
- - за
- - ан
- - дет
- - атт
- - на
- - гё
- - бпа
- - инт
- - тук
- - ом
- - нар
- - тва
- - ма
- - даг
- - сйа
- - вии
- - вуо
- - эил
- - тун
- - кайт
- - тэх
- - ва
- - хэи
- - хуо
- - суо
- - АААААААА
- - тен
- - йа
- - хеу
- - сту
- - ухр
- - укр
- - ви
- - хён
-
-# Spoken by dionas.
-- type: language
- id: RootSpeak
- obfuscation:
- !type:SyllableObfuscation
- minSyllables: 1
- maxSyllables: 5
- replacement:
- - хс
- - зт
- - кр
- - ст
- - ш
- - шш
-
-# A mess of broken Japanese, spoken by Felinds and Oni
-- type: language
- id: Nekomimetic
- obfuscation:
- !type:SyllableObfuscation
- minSyllables: 1
- maxSyllables: 3 # May be too long even, we'll see.
- replacement:
- - неко
- - нян
- - мими
- - ми
- - мофу
- - фува
- - кьяя
- - кавай
- - пока
- - муня
- - пуни
- - мунью
- - уфуфу
- - ича
- - доки
- - кьюн
- - кусу
- - ня
- - няя
- - десу
- - кис
- - ама
- - чуу
- - бака
- - хево
- - буп
- - гато
- - кит
- - сюн
- - йори
- - соу
- - бака
- - чан
- - сан
- - кун
- - махо
- - йатта
- - сукки
- - усаги
- - домо
- - ори
- - ува
- - заазаа
- - шику
- - пуру
- - ира
- - хето
- - етто
-
-# Spoken by the Lizard race.
-- type: language
- id: Draconic
- obfuscation:
- !type:SyllableObfuscation
- minSyllables: 2
- maxSyllables: 4
- replacement:
- - за
- - аз
- - зе
- - ез
- - зи
- - из
- - зо
- - оз
- - зу
- - уз
- - зс
- - сз
- - ха
- - ах
- - хе
- - ех
- - хи
- - их
- - хо
- - ох
- - ху
- - ух
- - хс
- - сш
- - ла
- - ал
- - ле
- - ел
- - ли
- - ил
- - ло
- - ол
- - лу
- - ул
- - лс
- - сл
- - ка
- - ак
- - ке
- - ек
- - ки
- - ик
- - ко
- - ок
- - ку
- - ук
- - кс
- - ск
- - са
- - ас
- - се
- - ес
- - си
- - ис
- - со
- - ос
- - су
- - ус
- - сс
- - сс
- - ра
- - ар
- - ре
- - ер
- - ри
- - ир
- - ро
- - ор
- - ру
- - ур
- - рс
- - ср
- - аа
- - а
- - ее
- - е
- - ии
- - и
- - оо
- - о
- - уу
- - у
- - сс
- - с
-
-# Spoken by the Vulpkanin race.
-- type: language
- id: Canilunzt
- obfuscation:
- !type:SyllableObfuscation
- minSyllables: 1
- maxSyllables: 4
- replacement:
- - рур
- - йа
- - цен
- - равр
- - ваф
- - кьюк
- - тек
- - кват
- - ук
- - ву
- - вух
- - тах
- - тч
- - щз
- - ауч
- - ист
- - еин
- - енчт
- - звисшч
- - тут
- - мир
- - во
- - бис
- - ес
- - вор
- - ник
- - гро
- - енем
- - зандт
- - джс
- - ПОРНО
- - йифф
- - ищт
- - фа
- - ва
- - вульф
-
-# The common language of the Sol system.
-- type: language
- id: SolCommon
- obfuscation:
- !type:SyllableObfuscation
- minSyllables: 1
- maxSyllables: 4
- replacement:
- - тао
- - ши
- - тзу
- - йи
- - ком
- - би
- - ис
- - я
- - оп
- - ви
- - эд
- - лек
- - мо
- - кле
- - те
- - дис
- - ее
-
-- type: language
- id: RobotTalk
- obfuscation:
- !type:SyllableObfuscation
- minSyllables: 1
- maxSyllables: 10 # Crazy
- replacement:
- - 0
- - 1
-
-# Languages spoken by various critters.
-- type: language
- id: Cat
- obfuscation:
- !type:SyllableObfuscation
- minSyllables: 1
- maxSyllables: 2
- replacement:
- - мурр
- - мяу
- - пурр
- - мррмяу
-
-- type: language
- id: Dog
- obfuscation:
- !type:SyllableObfuscation
- minSyllables: 1
- maxSyllables: 2
- replacement:
- - вуф
- - гаф
- - рруф
- - рраф
- - ррар
- - гррар
-
-- type: language
- id: Fox
- obfuscation:
- !type:SyllableObfuscation
- minSyllables: 1
- maxSyllables: 2
- replacement:
- - руфф
- - рафф
- - гарр
- - йип
- - йап
- - мьяах
-
-- type: language
- id: Xeno
- obfuscation:
- !type:SyllableObfuscation
- minSyllables: 1
- maxSyllables: 8 # I was crazy once
- replacement:
- - С
- - Р
-
-- type: language
- id: Monkey
- obfuscation:
- !type:SyllableObfuscation
- minSyllables: 1
- maxSyllables: 8 # They locked me in a room...
- replacement:
- - у
- - а
-
-- type: language
- id: Mouse
- obfuscation:
- !type:SyllableObfuscation
- minSyllables: 2
- maxSyllables: 3
- replacement:
- - ску
- - иик
- - пи
- - еп
- - чуу
- - ии
- - фии
- - хи
-
-- type: language
- id: Chicken
- obfuscation:
- !type:SyllableObfuscation
- minSyllables: 1
- maxSyllables: 3
- replacement:
- - ку
- - кудах
- - тах
-
-- type: language
- id: Duck
- obfuscation:
- !type:SyllableObfuscation
- minSyllables: 1
- maxSyllables: 3
- replacement:
- - кр
- - як
- - кряк
-
-- type: language
- id: Cow
- obfuscation:
- !type:SyllableObfuscation
- minSyllables: 1
- maxSyllables: 3
- replacement:
- - му
- - мууу
-
-- type: language
- id: Sheep
- obfuscation:
- !type:SyllableObfuscation
- minSyllables: 1
- maxSyllables: 3
- replacement:
- - беее
- - бее
- - ее
-
-- type: language
- id: Kangaroo
- obfuscation:
- !type:SyllableObfuscation
- minSyllables: 1
- maxSyllables: 3
- replacement:
- - шре
- - ак
- - чууу
- - чооо
-
-- type: language
- id: Pig
- obfuscation:
- !type:SyllableObfuscation
- minSyllables: 1
- maxSyllables: 3
- replacement:
- - хрю # Please someone come up with something better
- - Йонкь
-
-- type: language
- id: Crab
- obfuscation:
- !type:SyllableObfuscation
- minSyllables: 1
- maxSyllables: 3
- replacement:
- - клик
- - клак
- - ти
- - пи
- - тык
- - кл
- - ик
-
-- type: language
- id: Kobold
- obfuscation:
- !type:SyllableObfuscation
- minSyllables: 2
- maxSyllables: 4
- replacement:
- - йифф
- - ски
- - гар
- - грр
- - ар
- - скрик
- - эт
- - горнк
- - хисс
- - сс
- - ии
-
-- type: language
- id: Hissing
- obfuscation:
- !type:SyllableObfuscation
- minSyllables: 2
- maxSyllables: 4
- replacement:
- - хсс
- - хисс
- - сс
- - исс
-
-# Example of a sign language. Not currently used anyhow.
-- type: language
- id: Sign
- speech:
- allowRadio: false
- requireSpeech: false
- messageWrapOverrides:
- Speak: chat-sign-language-message-wrap
- Whisper: chat-sign-language-whisper-wrap
- speechVerbOverrides:
- - chat-speech-verb-sign-1
- - chat-speech-verb-sign-2
- - chat-speech-verb-sign-3
- obfuscation:
- !type:ReplacementObfuscation
- replacement:
- - что-то
- - машет вам
- - будто танцует
- - криво показывает вам что-то
- - указывает куда-то
- - непонятливо крутит пальцами
diff --git a/Resources/Prototypes/Nyanotrasen/Entities/Mobs/Species/Oni.yml b/Resources/Prototypes/Nyanotrasen/Entities/Mobs/Species/Oni.yml
index c1655287fd..da723e7c43 100644
--- a/Resources/Prototypes/Nyanotrasen/Entities/Mobs/Species/Oni.yml
+++ b/Resources/Prototypes/Nyanotrasen/Entities/Mobs/Species/Oni.yml
@@ -40,10 +40,10 @@
proto: oni
- type: LanguageKnowledge
speaks:
- - GalacticCommon
+ - TauCetiBasic
- Nekomimetic
understands:
- - GalacticCommon
+ - TauCetiBasic
- Nekomimetic
- type: entity
diff --git a/Resources/Prototypes/Nyanotrasen/Entities/Mobs/Species/felinid.yml b/Resources/Prototypes/Nyanotrasen/Entities/Mobs/Species/felinid.yml
index 3594356674..66cce3a265 100644
--- a/Resources/Prototypes/Nyanotrasen/Entities/Mobs/Species/felinid.yml
+++ b/Resources/Prototypes/Nyanotrasen/Entities/Mobs/Species/felinid.yml
@@ -73,12 +73,10 @@
- DoorBumpOpener
- type: LanguageKnowledge
speaks:
- - GalacticCommon
- - SolCommon
+ - TauCetiBasic
- Nekomimetic
understands:
- - GalacticCommon
- - SolCommon
+ - TauCetiBasic
- Nekomimetic
- type: Thieving
ignoreStripHidden: true
diff --git a/Resources/Prototypes/Nyanotrasen/Entities/Structures/Research/sophicscribe.yml b/Resources/Prototypes/Nyanotrasen/Entities/Structures/Research/sophicscribe.yml
index 533cf31499..511262d318 100644
--- a/Resources/Prototypes/Nyanotrasen/Entities/Structures/Research/sophicscribe.yml
+++ b/Resources/Prototypes/Nyanotrasen/Entities/Structures/Research/sophicscribe.yml
@@ -49,9 +49,9 @@
guides:
- Psionics
- type: LanguageSpeaker
- currentLanguage: GalacticCommon
+ currentLanguage: TauCetiBasic
- type: LanguageKnowledge
speaks:
- - GalacticCommon
+ - TauCetiBasic
understands:
- - GalacticCommon
+ - TauCetiBasic
diff --git a/Resources/Prototypes/Nyanotrasen/GameRules/events.yml b/Resources/Prototypes/Nyanotrasen/GameRules/events.yml
index 524bf4d4b7..0e905c0b9e 100644
--- a/Resources/Prototypes/Nyanotrasen/GameRules/events.yml
+++ b/Resources/Prototypes/Nyanotrasen/GameRules/events.yml
@@ -48,7 +48,7 @@
components:
- type: StationEvent
# Favor glimmer events just a little more than regular events.
- weight: 12
+ weight: 11
- type: GlimmerEvent
## Glimmer events
@@ -84,7 +84,7 @@
noSpawn: true
components:
- type: GlimmerEvent
- minimumGlimmer: 550
+ minimumGlimmer: 600
maximumGlimmer: 1000
- type: NoosphericFryRule
@@ -94,7 +94,7 @@
noSpawn: true
components:
- type: GlimmerEvent
- minimumGlimmer: 590
+ minimumGlimmer: 650
maximumGlimmer: 1000
glimmerBurnLower: 18
glimmerBurnUpper: 40
@@ -106,7 +106,7 @@
noSpawn: true
components:
- type: GlimmerEvent
- minimumGlimmer: 900
+ minimumGlimmer: 850
glimmerBurnLower: 350
glimmerBurnUpper: 450 # Unless epistemics badly f-d up, this will restore the glimmer balance for a while.
- type: MassMindSwapRule
@@ -147,8 +147,8 @@
reoccurrenceDelay: 15
minimumPlayers: 10
- type: GlimmerEvent
- minimumGlimmer: 500
- maximumGlimmer: 900
+ minimumGlimmer: 400
+ maximumGlimmer: 800
report: glimmer-event-report-signatures
- type: GlimmerRandomSentienceRule
@@ -158,7 +158,7 @@
noSpawn: true
components:
- type: GlimmerEvent
- minimumGlimmer: 700
+ minimumGlimmer: 650
maximumGlimmer: 900
report: glimmer-event-report-signatures
- type: GlimmerRevenantRule
diff --git a/Resources/Prototypes/Nyanotrasen/Objectives/traitor.yml b/Resources/Prototypes/Nyanotrasen/Objectives/traitor.yml
index 53910a54a9..e6e497003d 100644
--- a/Resources/Prototypes/Nyanotrasen/Objectives/traitor.yml
+++ b/Resources/Prototypes/Nyanotrasen/Objectives/traitor.yml
@@ -9,29 +9,6 @@
stealGroup: AntiPsychicKnife
owner: job-name-mantis
-- type: entity
- id: BecomePsionicObjective
- parent: BaseTraitorObjective
- name: Become psionic
- description: We need you to acquire psionics and keep them until your mission is complete.
- noSpawn: true
- components:
- - type: NotJobsRequirement
- jobs:
- - Mime
- - ForensicMantis
- - type: Objective
- difficulty: 2.5
- #unique: false
- icon:
- sprite: Nyanotrasen/Icons/psi.rsi
- state: psi
- - type: ObjectiveBlacklistRequirement
- blacklist:
- components:
- - BecomeGolemCondition
- - type: BecomePsionicCondition
-
#- type: entity
# id: BecomeGolemObjective
# parent: BaseTraitorObjective
diff --git a/Resources/Prototypes/Objectives/objectiveGroups.yml b/Resources/Prototypes/Objectives/objectiveGroups.yml
index 263494f798..6929d1e1a4 100644
--- a/Resources/Prototypes/Objectives/objectiveGroups.yml
+++ b/Resources/Prototypes/Objectives/objectiveGroups.yml
@@ -40,8 +40,6 @@
EscapeShuttleObjective: 1
# DieObjective: 0.05 # DeltaV - Disable the lrp objective aka murderbone justification
#HijackShuttleObjective: 0.02
- BecomePsionicObjective: 1 # Nyanotrasen - Become Psionic objective, see Resources/Prototypes/Nyanotrasen/Objectives/traitor.yml
- #BecomeGolemObjective: 0.5 # Nyanotrasen - Become a golem objective, see Resources/Prototypes/Nyanotrasen/Objectives/traitor.yml
- type: weightedRandom
id: TraitorObjectiveGroupSocial
diff --git a/Resources/Prototypes/Traits/categories.yml b/Resources/Prototypes/Traits/categories.yml
index e413706bfa..fcd89d5bbe 100644
--- a/Resources/Prototypes/Traits/categories.yml
+++ b/Resources/Prototypes/Traits/categories.yml
@@ -19,7 +19,24 @@
- type: traitCategory
id: Speech
root: true
+ subCategories:
+ - TraitsSpeechUncategorized
+ - TraitsSpeechAccents
+ - TraitsSpeechLanguages
+
+- type: traitCategory
+ id: TraitsSpeechUncategorized
+
+- type: traitCategory
+ id: TraitsSpeechAccents
+
+- type: traitCategory
+ id: TraitsSpeechLanguages
- type: traitCategory
id: Visual
root: true
+
+- type: traitCategory
+ id: Language
+ root: true
\ No newline at end of file
diff --git a/Resources/Prototypes/Traits/disabilities.yml b/Resources/Prototypes/Traits/disabilities.yml
index e3afa57ed4..289790b149 100644
--- a/Resources/Prototypes/Traits/disabilities.yml
+++ b/Resources/Prototypes/Traits/disabilities.yml
@@ -51,7 +51,7 @@
- type: trait
id: Muted
- category: Speech
+ category: Mental
points: 4
requirements:
- !type:CharacterJobRequirement
@@ -77,7 +77,7 @@
- type: trait
id: FrontalLisp
- category: Speech
+ category: TraitsSpeechAccents
requirements:
- !type:CharacterJobRequirement
inverted: true
@@ -88,10 +88,8 @@
inverted: true
species:
- IPC
- - !type:CharacterTraitRequirement
- inverted: true
- traits:
- - Muted
+ - !type:CharacterItemGroupRequirement
+ group: TraitsAccents
components:
- type: FrontalLisp
diff --git a/Resources/Prototypes/Traits/inconveniences.yml b/Resources/Prototypes/Traits/inconveniences.yml
index 7044e8f5d8..f15dd708b7 100644
--- a/Resources/Prototypes/Traits/inconveniences.yml
+++ b/Resources/Prototypes/Traits/inconveniences.yml
@@ -23,13 +23,15 @@
- type: trait
id: Stutter
- category: Mental
+ category: TraitsSpeechAccents
requirements:
- !type:CharacterJobRequirement
inverted: true
jobs:
- Borg
- MedicalBorg
+ - !type:CharacterItemGroupRequirement
+ group: TraitsAccents
components:
- type: StutteringAccent
matchRandomProb: 0.1
@@ -39,7 +41,7 @@
- type: trait
id: ForeignerLight
- category: Mental
+ category: TraitsSpeechLanguages
points: 2
requirements:
- !type:CharacterTraitRequirement
@@ -54,7 +56,7 @@
- type: trait
id: Foreigner
- category: Mental
+ category: TraitsSpeechLanguages
points: 4
requirements: # TODO: Add a requirement to know at least 1 non-gc language
- !type:CharacterTraitRequirement
diff --git a/Resources/Prototypes/Traits/languages.yml b/Resources/Prototypes/Traits/languages.yml
new file mode 100644
index 0000000000..5fc1f3bb91
--- /dev/null
+++ b/Resources/Prototypes/Traits/languages.yml
@@ -0,0 +1,67 @@
+- type: trait
+ id: SignLanguage
+ category: TraitsSpeechLanguages
+ points: 0
+ requirements:
+ - !type:CharacterItemGroupRequirement
+ group: TraitsLanguagesBasic
+ languagesSpoken:
+ - Sign
+ languagesUnderstood:
+ - Sign
+
+- type: trait
+ id: SolCommon
+ category: TraitsSpeechLanguages
+ points: 0
+ requirements:
+ - !type:CharacterItemGroupRequirement
+ group: TraitsLanguagesBasic
+ - !type:CharacterSpeciesRequirement
+ inverted: true
+ species:
+ - Human
+ languagesSpoken:
+ - SolCommon
+ languagesUnderstood:
+ - SolCommon
+
+- type: trait
+ id: Tradeband
+ category: TraitsSpeechLanguages
+ points: 0
+ requirements:
+ - !type:CharacterItemGroupRequirement
+ group: TraitsLanguagesBasic
+ - !type:CharacterSpeciesRequirement
+ inverted: true
+ species:
+ - Harpy
+ languagesSpoken:
+ - Tradeband
+ languagesUnderstood:
+ - Tradeband
+
+- type: trait
+ id: Freespeak
+ category: TraitsSpeechLanguages
+ points: 0
+ requirements:
+ - !type:CharacterItemGroupRequirement
+ group: TraitsLanguagesBasic
+ languagesSpoken:
+ - Freespeak
+ languagesUnderstood:
+ - Freespeak
+
+- type: trait
+ id: Elyran
+ category: TraitsSpeechLanguages
+ points: 0
+ requirements:
+ - !type:CharacterItemGroupRequirement
+ group: TraitsLanguagesBasic
+ languagesSpoken:
+ - Elyran
+ languagesUnderstood:
+ - Elyran
\ No newline at end of file
diff --git a/Resources/Prototypes/Traits/neutral.yml b/Resources/Prototypes/Traits/neutral.yml
index c7fa8d914e..ad41569f7f 100644
--- a/Resources/Prototypes/Traits/neutral.yml
+++ b/Resources/Prototypes/Traits/neutral.yml
@@ -1,28 +1,24 @@
- type: trait
id: PirateAccent
- category: Speech
+ category: TraitsSpeechAccents
requirements:
- - !type:CharacterTraitRequirement
- inverted: true
- traits:
- - Muted
+ - !type:CharacterItemGroupRequirement
+ group: TraitsAccents
components:
- type: PirateAccent
- type: trait
id: Accentless
- category: Speech
- points: -2
+ category: TraitsSpeechAccents
+ points: -1
requirements:
- !type:CharacterJobRequirement
inverted: true
jobs:
- Borg
- MedicalBorg
- - !type:CharacterTraitRequirement
- inverted: true
- traits:
- - Muted
+ - !type:CharacterItemGroupRequirement
+ group: TraitsAccents
components:
- type: Accentless
removes:
@@ -33,7 +29,10 @@
#- type: trait
# id: Southern
-# category: Speech
+# category: TraitsSpeechAccents
+# requirements:
+# - !type:CharacterItemGroupRequirement
+# group: TraitsAccents
# components:
# - type: SouthernAccent
@@ -98,4 +97,4 @@
species:
- IPC
moodEffects:
- - NicotineWithdrawal
\ No newline at end of file
+ - NicotineWithdrawal
diff --git a/Resources/Prototypes/Traits/physical.yml b/Resources/Prototypes/Traits/physical.yml
index 9111b68763..8f34cf084c 100644
--- a/Resources/Prototypes/Traits/physical.yml
+++ b/Resources/Prototypes/Traits/physical.yml
@@ -395,6 +395,7 @@
species:
- Arachnid
- Arachne
+ - IPC
components:
- type: Sericulture
action: ActionSericulture
diff --git a/Resources/Prototypes/Traits/skills.yml b/Resources/Prototypes/Traits/skills.yml
index f1f133d0f8..99ca0ed875 100644
--- a/Resources/Prototypes/Traits/skills.yml
+++ b/Resources/Prototypes/Traits/skills.yml
@@ -103,15 +103,6 @@
- Borg
- MedicalBorg
-- type: trait
- id: SignLanguage
- category: Visual
- points: -2
- languagesSpoken:
- - Sign
- languagesUnderstood:
- - Sign
-
- type: trait
id: Voracious
category: Physical
@@ -280,7 +271,7 @@
- type: trait
id: TrapAvoider
category: Physical
- points: -6
+ points: -4
components:
- type: StepTriggerImmune
whitelist:
diff --git a/Resources/Prototypes/_LostParadise/Catalog/Fills/Lockers/security.yml b/Resources/Prototypes/_LostParadise/Catalog/Fills/Lockers/security.yml
index fa03f5fa65..72502896d0 100644
--- a/Resources/Prototypes/_LostParadise/Catalog/Fills/Lockers/security.yml
+++ b/Resources/Prototypes/_LostParadise/Catalog/Fills/Lockers/security.yml
@@ -14,7 +14,7 @@
- id: ToolboxMechanicalFilled
- id: ClothingHandsGlovesCombat
- id: LPPClothingOuterHardsuitSecurityEng
- - id: LPPC4Low
- - id: LPPHammer
+ - id: BreachingCharge
+ - id: SecBreachingHammer
- id: RCD
- id: RCDAmmo
diff --git a/Resources/Prototypes/_LostParadise/Catalog/Hos_catalog.yml b/Resources/Prototypes/_LostParadise/Catalog/Hos_catalog.yml
index 42a5e74880..2e9fb345e8 100644
--- a/Resources/Prototypes/_LostParadise/Catalog/Hos_catalog.yml
+++ b/Resources/Prototypes/_LostParadise/Catalog/Hos_catalog.yml
@@ -1191,7 +1191,7 @@
id: LPPHosCatalogHammer
name: штурмовой молот
description: Молот предназначенный для быстрого проникновения сквозь стены, шлюзы, а также для крушения чьих то черепов. Он явно более робастный, чем обычные молоты.
- productEntity: LPPHammer
+ productEntity: SecBreachingHammer
cost:
LPPCentcoin: 5
categories:
@@ -1221,7 +1221,7 @@
id: LPPHosC4Low
name: Слабая C4
description: Взрывпакет предназначенный для быстрого выламывания шлюзов или стен, но его взрыв довольно слабый в плане радиуса. Виднеется этикетка (ставьте прямо на объект).
- productEntity: LPPC4Low
+ productEntity: BreachingCharge
cost:
LPPCentcoin: 1
categories:
diff --git a/Resources/Prototypes/_LostParadise/Catalog/cburn_defence_catalog.yml b/Resources/Prototypes/_LostParadise/Catalog/cburn_defence_catalog.yml
index 8192d6f892..e552e36b54 100644
--- a/Resources/Prototypes/_LostParadise/Catalog/cburn_defence_catalog.yml
+++ b/Resources/Prototypes/_LostParadise/Catalog/cburn_defence_catalog.yml
@@ -306,7 +306,7 @@
# id: LPPCBURNCatalogEngineeringHammer
# name: cburn-catalog-engineering-hammer-name
# description: cburn-catalog-engineering-hammer-desc
-# productEntity: LPPHammer
+# productEntity: SecBreachingHammer
# cost:
# Telecrystal: 5
# categories:
diff --git a/Resources/Prototypes/_LostParadise/Catalog/delta_catalog.yml b/Resources/Prototypes/_LostParadise/Catalog/delta_catalog.yml
index bd6d061b09..04582760b6 100644
--- a/Resources/Prototypes/_LostParadise/Catalog/delta_catalog.yml
+++ b/Resources/Prototypes/_LostParadise/Catalog/delta_catalog.yml
@@ -659,7 +659,7 @@
# id: LPPDeltaCatalogEngineeringHammer
# name: delta-catalog-engineering-hammer-name
# description: delta-catalog-engineering-hammer-desc
-# productEntity: LPPHammer
+# productEntity: SecBreachingHammer
# cost:
# Telecrystal: 3
# categories:
diff --git a/Resources/Prototypes/_LostParadise/Catalog/ert_catalog.yml b/Resources/Prototypes/_LostParadise/Catalog/ert_catalog.yml
index 3a8a6ffb79..9e9c36d000 100644
--- a/Resources/Prototypes/_LostParadise/Catalog/ert_catalog.yml
+++ b/Resources/Prototypes/_LostParadise/Catalog/ert_catalog.yml
@@ -657,7 +657,7 @@
# id: LPPERTCatalogEngineeringHammer
# name: ert-catalog-engineering-hammer-name
# description: ert-catalog-engineering-hammer-desc
-# productEntity: LPPHammer
+# productEntity: SecBreachingHammer
# cost:
# Telecrystal: 5
# categories:
diff --git a/Resources/Prototypes/_LostParadise/Entities/Mobs/Cryborgs/base_borg.yml b/Resources/Prototypes/_LostParadise/Entities/Mobs/Cryborgs/base_borg.yml
index e8506541cd..53cdb25658 100644
--- a/Resources/Prototypes/_LostParadise/Entities/Mobs/Cryborgs/base_borg.yml
+++ b/Resources/Prototypes/_LostParadise/Entities/Mobs/Cryborgs/base_borg.yml
@@ -205,10 +205,10 @@
voice: Vally
- type: LanguageKnowledge
speaks:
- - GalacticCommon
+ - TauCetiBasic
- RobotTalk
understands:
- - GalacticCommon
+ - TauCetiBasic
- RobotTalk
- Canilunzt
- LPPSikTaj
diff --git a/Resources/Prototypes/_LostParadise/Entities/Mobs/Species/Shark/Entities/Mobs/Species/Shark.yml b/Resources/Prototypes/_LostParadise/Entities/Mobs/Species/Shark/Entities/Mobs/Species/Shark.yml
index 1c3792805f..259481ace3 100644
--- a/Resources/Prototypes/_LostParadise/Entities/Mobs/Species/Shark/Entities/Mobs/Species/Shark.yml
+++ b/Resources/Prototypes/_LostParadise/Entities/Mobs/Species/Shark/Entities/Mobs/Species/Shark.yml
@@ -61,9 +61,9 @@
speciesId: shark
- type: LanguageKnowledge
speaks:
- - GalacticCommon
+ - TauCetiBasic
understands:
- - GalacticCommon
+ - TauCetiBasic
# # - type: EmotePanel
# race: Shark
#- type: Carriable
diff --git a/Resources/Prototypes/_LostParadise/Entities/Mobs/Species/Tajaran/Entities/Mobs/Species/Tajaran.yml b/Resources/Prototypes/_LostParadise/Entities/Mobs/Species/Tajaran/Entities/Mobs/Species/Tajaran.yml
index 2fe2de7a09..38df39e4dc 100644
--- a/Resources/Prototypes/_LostParadise/Entities/Mobs/Species/Tajaran/Entities/Mobs/Species/Tajaran.yml
+++ b/Resources/Prototypes/_LostParadise/Entities/Mobs/Species/Tajaran/Entities/Mobs/Species/Tajaran.yml
@@ -60,10 +60,10 @@
# race: Tajar
- type: LanguageKnowledge
speaks:
- - GalacticCommon
+ - TauCetiBasic
- LPPSikTaj
understands:
- - GalacticCommon
+ - TauCetiBasic
- LPPSikTaj
- type: entity
diff --git a/Resources/Prototypes/_LostParadise/Entities/Mobs/Species/base.yml b/Resources/Prototypes/_LostParadise/Entities/Mobs/Species/base.yml
index 04ed8499de..e01c23f905 100644
--- a/Resources/Prototypes/_LostParadise/Entities/Mobs/Species/base.yml
+++ b/Resources/Prototypes/_LostParadise/Entities/Mobs/Species/base.yml
@@ -50,7 +50,7 @@
active: False
- type: LanguageKnowledge
understands:
- - GalacticCommon
+ - TauCetiBasic
# Used for mobs that have health and can take damage.
- type: entity
diff --git a/Resources/Prototypes/_LostParadise/Entities/Objects/Weapons/Bombs/C4Low.yml b/Resources/Prototypes/_LostParadise/Entities/Objects/Weapons/Bombs/C4Low.yml
deleted file mode 100644
index 8c5ef20d09..0000000000
--- a/Resources/Prototypes/_LostParadise/Entities/Objects/Weapons/Bombs/C4Low.yml
+++ /dev/null
@@ -1,30 +0,0 @@
-- type: entity
- name: C4Low
- description: Взрывпакет предназначенный для быстрого выламывания шлюзов или стен, но его взрыв довольно слабый в плане радиуса. Виднеется этикетка (ставьте прямо на объект)
- parent: BasePlasticExplosive
- id: LPPC4Low
- components:
- - type: Sprite
- sprite: _LostParadise/Objects/Weapons/Bombs/C4Low.rsi
- state: icon
- - type: OnUseTimerTrigger
- delay: 5
- delayOptions: [5, 10, 15, 20]
- initialBeepDelay: 0
- beepSound:
- path: /Audio/Effects/Cargo/buzz_two.ogg
- params:
- volume: -6
- startOnStick: false
- canToggleStartOnStick: true
- - type: TriggerOnSignal
- - type: DeviceLinkSink
- ports:
- - Trigger
- - type: Explosive
- explosionType: DemolitionCharge
- totalIntensity: 10
- intensitySlope: 10
- maxIntensity: 10
- canCreateVacuum: false
- - type: ExplodeOnTrigger
diff --git a/Resources/Prototypes/_LostParadise/Entities/Objects/Weapons/Melee/hammer.yml b/Resources/Prototypes/_LostParadise/Entities/Objects/Weapons/Melee/hammer.yml
deleted file mode 100644
index 424c030ebd..0000000000
--- a/Resources/Prototypes/_LostParadise/Entities/Objects/Weapons/Melee/hammer.yml
+++ /dev/null
@@ -1,34 +0,0 @@
-- type: entity
- id: LPPHammer
- parent: BaseItem
- name: штурмовой молот
- description: Молот предназначенный для быстрого проникновения сквозь стены, шлюзы, а также для крушения чьих то черепов
- components:
- - type: Tag
- tags:
- - LPPHammer
- - type: Sprite
- sprite: _LostParadise/Objects/Weapons/Melee/LPPHammer.rsi
- state: icon
- - type: Item
- size: Huge
- - type: MeleeWeapon
- attackRate: 0.75
- range: 1.70
- damage:
- types:
- Blunt: 10
- Structural: 30
- bluntStaminaDamageFactor: 1.50
- - type: Wieldable
- - type: IncreaseDamageOnWield
- damage:
- types:
- Blunt: 10
- Structural: 80
- - type: ToolTileCompatible
- - type: Clothing
- sprite: _LostParadise/Objects/Weapons/Melee/LPPHammer.rsi
- quickEquip: false
- slots:
- - back
diff --git a/Resources/Prototypes/_LostParadise/Entities/Structures/Wallmounts/HammerCabinet.yml b/Resources/Prototypes/_LostParadise/Entities/Structures/Wallmounts/HammerCabinet.yml
index 88fb631350..aca2c318bf 100644
--- a/Resources/Prototypes/_LostParadise/Entities/Structures/Wallmounts/HammerCabinet.yml
+++ b/Resources/Prototypes/_LostParadise/Entities/Structures/Wallmounts/HammerCabinet.yml
@@ -94,7 +94,7 @@
# ejectOnInteract: true
# whitelist:
# tags:
-# - LPPHammer
+# - SecBreachingHammer
# - type: Lock
# - type: AccessReader
# access: [["Engineering"], ["Salvage"], ["Security"]]
@@ -107,4 +107,4 @@
# - type: ContainerFill
# containers:
# ItemCabinet:
-# - LPPHammer
+# - SecBreachingHammer
diff --git a/Resources/Prototypes/_LostParadise/PersonalGhost/AngelDust/angel_dust.yml b/Resources/Prototypes/_LostParadise/PersonalGhost/AngelDust/angel_dust.yml
index 2b761de42d..951a14bf92 100644
--- a/Resources/Prototypes/_LostParadise/PersonalGhost/AngelDust/angel_dust.yml
+++ b/Resources/Prototypes/_LostParadise/PersonalGhost/AngelDust/angel_dust.yml
@@ -62,13 +62,13 @@
# - type: IntrinsicRadioReceiver
# - type: LanguageSpeaker
# speaks:
- # - GalacticCommon
+ # - TauCetiBasic
# - LPPCanilunzt
# - LPPElfLang
# - LPPSolCommon
# - LPPDev
# understands:
- # - GalacticCommon
+ # - TauCetiBasic
# - LPPCanilunzt
# - LPPSikTaj
# - LPPCintaTaj
diff --git a/Resources/Prototypes/_LostParadise/PersonalGhost/AngelDust/angel_dust_ghost.yml b/Resources/Prototypes/_LostParadise/PersonalGhost/AngelDust/angel_dust_ghost.yml
index 338473f90c..dc8a8ad8db 100644
--- a/Resources/Prototypes/_LostParadise/PersonalGhost/AngelDust/angel_dust_ghost.yml
+++ b/Resources/Prototypes/_LostParadise/PersonalGhost/AngelDust/angel_dust_ghost.yml
@@ -49,13 +49,13 @@
# toggleAction: ActionAGhostShowCrewMonitoring
# - type: LanguageSpeaker
# speaks:
- # - GalacticCommon
+ # - TauCetiBasic
# - LPPCanilunzt
# - LPPElfLang
# - LPPSolCommon
# - LPPDev
# understands:
- # - GalacticCommon
+ # - TauCetiBasic
# - LPPCanilunzt
# - LPPSikTaj
# - LPPCintaTaj
diff --git a/Resources/Prototypes/_LostParadise/Recipes/Lathes/security.yml b/Resources/Prototypes/_LostParadise/Recipes/Lathes/security.yml
index 37af37a2a2..d12fa4b19f 100644
--- a/Resources/Prototypes/_LostParadise/Recipes/Lathes/security.yml
+++ b/Resources/Prototypes/_LostParadise/Recipes/Lathes/security.yml
@@ -102,11 +102,3 @@
completetime: 5
materials:
Steel: 1150
-
-- type: latheRecipe
- id: LPPC4Low
- result: LPPC4Low
- completetime: 10
- materials:
- Plastic: 375
- Plasma: 375
diff --git a/Resources/Prototypes/_LostParadise/Roles/Jobs/Security/SecEng.yml b/Resources/Prototypes/_LostParadise/Roles/Jobs/Security/SecEng.yml
index c414931ddc..9fc49be316 100644
--- a/Resources/Prototypes/_LostParadise/Roles/Jobs/Security/SecEng.yml
+++ b/Resources/Prototypes/_LostParadise/Roles/Jobs/Security/SecEng.yml
@@ -46,4 +46,4 @@
back:
- SheetSteel10
- SheetGlass10
- - LPPC4Low
+ - BreachingCharge
diff --git a/Resources/Prototypes/_LostParadise/Traits/languages.yml b/Resources/Prototypes/_LostParadise/Traits/languages.yml
index bf3aa4a098..a30fa91ac6 100644
--- a/Resources/Prototypes/_LostParadise/Traits/languages.yml
+++ b/Resources/Prototypes/_LostParadise/Traits/languages.yml
@@ -1,6 +1,6 @@
- type: trait
id: ElfLanguage
- category: Speech
+ category: TraitsSpeechLanguages
points: 0
languagesSpoken:
- ElfLang
@@ -11,17 +11,12 @@
inverted: false
species:
- Human
- - !type:CharacterTraitRequirement
- inverted: true
- traits:
- - DwarfLanguage
- - ForeignerLight
- - Foreigner
- - SignLanguage
+ - !type:CharacterItemGroupRequirement
+ group: TraitsLanguagesBasic
- type: trait
id: DwarfLanguage
- category: Speech
+ category: TraitsSpeechLanguages
points: 0
languagesSpoken:
- DwarfLang
@@ -32,10 +27,5 @@
inverted: false
species:
- Human
- - !type:CharacterTraitRequirement
- inverted: true
- traits:
- - ElfLanguage
- - ForeignerLight
- - Foreigner
- - SignLanguage
+ - !type:CharacterItemGroupRequirement
+ group: TraitsLanguagesBasic
diff --git a/Resources/Prototypes/_LostParadise/tags.yml b/Resources/Prototypes/_LostParadise/tags.yml
index 717b38926a..24e708c1a2 100644
--- a/Resources/Prototypes/_LostParadise/tags.yml
+++ b/Resources/Prototypes/_LostParadise/tags.yml
@@ -143,8 +143,6 @@
- type: Tag
id: LPPDrinkBottleAlko
-- type: Tag
- id: LPPHammer
# [Обоема для M41-A]
- type: Tag
diff --git a/Resources/Textures/Interface/AtmosMonitoring/status_bg.png b/Resources/Textures/Interface/AtmosMonitoring/status_bg.png
new file mode 100644
index 0000000000..165a9b9d9f
Binary files /dev/null and b/Resources/Textures/Interface/AtmosMonitoring/status_bg.png differ
diff --git a/Tools/corvax/1.py b/Tools/corvax/1.py
new file mode 100644
index 0000000000..edd0f5a356
--- /dev/null
+++ b/Tools/corvax/1.py
@@ -0,0 +1,61 @@
+import os
+import logging
+from datetime import datetime
+
+def find_top_level_dir(start_dir):
+ marker_file = 'SpaceStation14.sln'
+ current_dir = start_dir
+ while True:
+ if marker_file in os.listdir(current_dir):
+ return current_dir
+ parent_dir = os.path.dirname(current_dir)
+ if parent_dir == current_dir:
+ print(f"Не удалось найти {marker_file} начиная с {start_dir}")
+ exit(-1)
+ current_dir = parent_dir
+def setup_logging():
+ log_filename = f"cleanup_{datetime.now().strftime('%Y%m%d_%H%M%S')}.log"
+ logging.basicConfig(filename=log_filename, level=logging.INFO,
+ format='%(asctime)s - %(levelname)s - %(message)s')
+ console = logging.StreamHandler()
+ console.setLevel(logging.INFO)
+ logging.getLogger('').addHandler(console)
+ return log_filename
+
+def remove_empty_files_and_folders(path):
+ removed_files = 0
+ removed_folders = 0
+
+ for root, dirs, files in os.walk(path, topdown=False):
+ # Удаление пустых файлов
+ for file in files:
+ file_path = os.path.join(root, file)
+ if os.path.getsize(file_path) == 0:
+ try:
+ os.remove(file_path)
+ logging.info(f"Удален пустой файл: {file_path}")
+ removed_files += 1
+ except Exception as e:
+ logging.error(f"Ошибка при удалении файла {file_path}: {str(e)}")
+
+ # Удаление пустых папок
+ if not os.listdir(root):
+ try:
+ os.rmdir(root)
+ logging.info(f"Удалена пустая папка: {root}")
+ removed_folders += 1
+ except Exception as e:
+ logging.error(f"Ошибка при удалении папки {root}: {str(e)}")
+
+ return removed_files, removed_folders
+
+if __name__ == "__main__":
+ script_dir = os.path.dirname(os.path.abspath(__file__))
+ main_folder = find_top_level_dir(script_dir)
+ root_dir = os.path.join(main_folder, "Resources\\Locale\\ru-RU")
+ log_file = setup_logging()
+
+ logging.info(f"Начало очистки в директории: {root_dir}")
+ files_removed, folders_removed = remove_empty_files_and_folders(root_dir)
+ logging.info(f"Очистка завершена. Удалено файлов: {files_removed}, удалено папок: {folders_removed}")
+ print(f"Лог операций сохранен в файл: {log_file}")
diff --git a/Tools/corvax/clean_ftl.py b/Tools/corvax/clean_ftl.py
new file mode 100644
index 0000000000..daea65b4bc
--- /dev/null
+++ b/Tools/corvax/clean_ftl.py
@@ -0,0 +1,119 @@
+import os
+import re
+import chardet
+from datetime import datetime
+
+def find_top_level_dir(start_dir):
+ marker_file = 'SpaceStation14.sln'
+ current_dir = start_dir
+ while True:
+ if marker_file in os.listdir(current_dir):
+ return current_dir
+ parent_dir = os.path.dirname(current_dir)
+ if parent_dir == current_dir:
+ print(f"Не удалось найти {marker_file} начиная с {start_dir}")
+ exit(-1)
+ current_dir = parent_dir
+def find_ftl_files(root_dir):
+ ftl_files = []
+ for root, dirs, files in os.walk(root_dir):
+ for file in files:
+ if file.endswith('.ftl'):
+ ftl_files.append(os.path.join(root, file))
+ return ftl_files
+
+def detect_encoding(file_path):
+ with open(file_path, 'rb') as file:
+ raw_data = file.read()
+ return chardet.detect(raw_data)['encoding']
+
+def parse_ent_blocks(file_path):
+ try:
+ encoding = detect_encoding(file_path)
+ with open(file_path, 'r', encoding=encoding) as file:
+ content = file.read()
+ except UnicodeDecodeError:
+ print(f"Ошибка при чтении файла {file_path}. Попытка чтения в UTF-8.")
+ try:
+ with open(file_path, 'r', encoding='utf-8') as file:
+ content = file.read()
+ except UnicodeDecodeError:
+ print(f"Не удалось прочитать файл {file_path}. Пропускаем.")
+ return {}
+
+ ent_blocks = {}
+ current_ent = None
+ current_block = []
+
+ for line in content.split('\n'):
+ if line.startswith('ent-'):
+ if current_ent:
+ ent_blocks[current_ent] = '\n'.join(current_block)
+ current_ent = line.split('=')[0].strip()
+ current_block = [line]
+ elif current_ent and (line.strip().startswith('.desc') or line.strip().startswith('.suffix')):
+ current_block.append(line)
+ elif line.strip() == '':
+ if current_ent:
+ ent_blocks[current_ent] = '\n'.join(current_block)
+ current_ent = None
+ current_block = []
+ else:
+ if current_ent:
+ ent_blocks[current_ent] = '\n'.join(current_block)
+ current_ent = None
+ current_block = []
+
+ if current_ent:
+ ent_blocks[current_ent] = '\n'.join(current_block)
+
+ return ent_blocks
+
+def remove_duplicates(root_dir):
+ ftl_files = find_ftl_files(root_dir)
+ all_ents = {}
+ removed_duplicates = []
+
+ for file_path in ftl_files:
+ ent_blocks = parse_ent_blocks(file_path)
+ for ent, block in ent_blocks.items():
+ if ent not in all_ents:
+ all_ents[ent] = (file_path, block)
+
+ for file_path in ftl_files:
+ try:
+ encoding = detect_encoding(file_path)
+ with open(file_path, 'r', encoding=encoding) as file:
+ content = file.read()
+
+ ent_blocks = parse_ent_blocks(file_path)
+ for ent, block in ent_blocks.items():
+ if all_ents[ent][0] != file_path:
+ content = content.replace(block, '')
+ removed_duplicates.append((ent, file_path, block))
+
+ content = re.sub(r'\n{3,}', '\n\n', content)
+
+ with open(file_path, 'w', encoding=encoding) as file:
+ file.write(content)
+ except Exception as e:
+ print(f"Ошибка при обработке файла {file_path}: {str(e)}")
+
+ # Сохранение лога удаленных дубликатов
+ log_filename = f"removed_duplicates_{datetime.now().strftime('%Y%m%d_%H%M%S')}.log"
+ with open(log_filename, 'w', encoding='utf-8') as log_file:
+ for ent, file_path, block in removed_duplicates:
+ log_file.write(f"Удален дубликат: {ent}\n")
+ log_file.write(f"Файл: {file_path}\n")
+ log_file.write("Содержимое:\n")
+ log_file.write(block)
+ log_file.write("\n\n")
+
+ print(f"Обработка завершена. Проверено файлов: {len(ftl_files)}")
+ print(f"Лог удаленных дубликатов сохранен в файл: {log_filename}")
+
+if __name__ == "__main__":
+ script_dir = os.path.dirname(os.path.abspath(__file__))
+ main_folder = find_top_level_dir(script_dir)
+ root_dir = os.path.join(main_folder, "Resources\\Locale\\ru-RU")
+ remove_duplicates(root_dir)