Merge branch 'master' into races
This commit is contained in:
@@ -9,20 +9,20 @@ namespace Content.Client.Access;
|
||||
|
||||
public sealed class AccessOverlay : Overlay
|
||||
{
|
||||
private const string TextFontPath = "/Fonts/NotoSans/NotoSans-Regular.ttf";
|
||||
private const int TextFontSize = 12;
|
||||
|
||||
private readonly IEntityManager _entityManager;
|
||||
private readonly EntityLookupSystem _lookup;
|
||||
private readonly SharedTransformSystem _xform;
|
||||
private readonly SharedTransformSystem _transformSystem;
|
||||
private readonly Font _font;
|
||||
|
||||
public override OverlaySpace Space => OverlaySpace.ScreenSpace;
|
||||
|
||||
public AccessOverlay(IEntityManager entManager, IResourceCache cache, EntityLookupSystem lookup, SharedTransformSystem xform)
|
||||
public AccessOverlay(IEntityManager entityManager, IResourceCache resourceCache, SharedTransformSystem transformSystem)
|
||||
{
|
||||
_entityManager = entManager;
|
||||
_lookup = lookup;
|
||||
_xform = xform;
|
||||
|
||||
_font = cache.GetFont("/Fonts/NotoSans/NotoSans-Regular.ttf", 12);
|
||||
_entityManager = entityManager;
|
||||
_transformSystem = transformSystem;
|
||||
_font = resourceCache.GetFont(TextFontPath, TextFontSize);
|
||||
}
|
||||
|
||||
protected override void Draw(in OverlayDrawArgs args)
|
||||
@@ -30,52 +30,65 @@ public sealed class AccessOverlay : Overlay
|
||||
if (args.ViewportControl == null)
|
||||
return;
|
||||
|
||||
var readerQuery = _entityManager.GetEntityQuery<AccessReaderComponent>();
|
||||
var xformQuery = _entityManager.GetEntityQuery<TransformComponent>();
|
||||
|
||||
foreach (var ent in _lookup.GetEntitiesIntersecting(args.MapId, args.WorldAABB,
|
||||
LookupFlags.Static | LookupFlags.Approximate))
|
||||
var textBuffer = new StringBuilder();
|
||||
var query = _entityManager.EntityQueryEnumerator<AccessReaderComponent, TransformComponent>();
|
||||
while (query.MoveNext(out var uid, out var accessReader, out var transform))
|
||||
{
|
||||
if (!readerQuery.TryGetComponent(ent, out var reader) ||
|
||||
!xformQuery.TryGetComponent(ent, out var xform))
|
||||
textBuffer.Clear();
|
||||
|
||||
var entityName = _entityManager.ToPrettyString(uid);
|
||||
textBuffer.AppendLine(entityName.Prototype);
|
||||
textBuffer.Append("UID: ");
|
||||
textBuffer.Append(entityName.Uid.Id);
|
||||
textBuffer.Append(", NUID: ");
|
||||
textBuffer.Append(entityName.Nuid.Id);
|
||||
textBuffer.AppendLine();
|
||||
|
||||
if (!accessReader.Enabled)
|
||||
{
|
||||
textBuffer.AppendLine("-Disabled");
|
||||
continue;
|
||||
}
|
||||
|
||||
var text = new StringBuilder();
|
||||
var index = 0;
|
||||
var a = $"{_entityManager.ToPrettyString(ent)}";
|
||||
text.Append(a);
|
||||
|
||||
foreach (var list in reader.AccessLists)
|
||||
if (accessReader.AccessLists.Count > 0)
|
||||
{
|
||||
a = $"Tag {index}";
|
||||
text.AppendLine(a);
|
||||
|
||||
foreach (var entry in list)
|
||||
var groupNumber = 0;
|
||||
foreach (var accessList in accessReader.AccessLists)
|
||||
{
|
||||
a = $"- {entry}";
|
||||
text.AppendLine(a);
|
||||
groupNumber++;
|
||||
foreach (var entry in accessList)
|
||||
{
|
||||
textBuffer.Append("+Set ");
|
||||
textBuffer.Append(groupNumber);
|
||||
textBuffer.Append(": ");
|
||||
textBuffer.Append(entry.Id);
|
||||
textBuffer.AppendLine();
|
||||
}
|
||||
}
|
||||
|
||||
index++;
|
||||
}
|
||||
|
||||
string textStr;
|
||||
|
||||
if (text.Length >= 2)
|
||||
{
|
||||
textStr = text.ToString();
|
||||
textStr = textStr[..^2];
|
||||
}
|
||||
else
|
||||
{
|
||||
textStr = "";
|
||||
textBuffer.AppendLine("+Unrestricted");
|
||||
}
|
||||
|
||||
var screenPos = args.ViewportControl.WorldToScreen(_xform.GetWorldPosition(xform));
|
||||
foreach (var key in accessReader.AccessKeys)
|
||||
{
|
||||
textBuffer.Append("+Key ");
|
||||
textBuffer.Append(key.OriginStation);
|
||||
textBuffer.Append(": ");
|
||||
textBuffer.Append(key.Id);
|
||||
textBuffer.AppendLine();
|
||||
}
|
||||
|
||||
args.ScreenHandle.DrawString(_font, screenPos, textStr, Color.Gold);
|
||||
foreach (var tag in accessReader.DenyTags)
|
||||
{
|
||||
textBuffer.Append("-Tag ");
|
||||
textBuffer.AppendLine(tag.Id);
|
||||
}
|
||||
|
||||
var accessInfoText = textBuffer.ToString();
|
||||
var screenPos = args.ViewportControl.WorldToScreen(_transformSystem.GetWorldPosition(transform));
|
||||
args.ScreenHandle.DrawString(_font, screenPos, accessInfoText, Color.Gold);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,8 +7,16 @@ namespace Content.Client.Access.Commands;
|
||||
public sealed class ShowAccessReadersCommand : IConsoleCommand
|
||||
{
|
||||
public string Command => "showaccessreaders";
|
||||
public string Description => "Shows all access readers in the viewport";
|
||||
public string Help => $"{Command}";
|
||||
|
||||
public string Description => "Toggles showing access reader permissions on the map";
|
||||
public string Help => """
|
||||
Overlay Info:
|
||||
-Disabled | The access reader is disabled
|
||||
+Unrestricted | The access reader has no restrictions
|
||||
+Set [Index]: [Tag Name]| A tag in an access set (accessor needs all tags in the set to be allowed by the set)
|
||||
+Key [StationUid]: [StationRecordKeyId] | A StationRecordKey that is allowed
|
||||
-Tag [Tag Name] | A tag that is not allowed (takes priority over other allows)
|
||||
""";
|
||||
public void Execute(IConsoleShell shell, string argStr, string[] args)
|
||||
{
|
||||
var collection = IoCManager.Instance;
|
||||
@@ -26,10 +34,9 @@ public sealed class ShowAccessReadersCommand : IConsoleCommand
|
||||
|
||||
var entManager = collection.Resolve<IEntityManager>();
|
||||
var cache = collection.Resolve<IResourceCache>();
|
||||
var lookup = entManager.System<EntityLookupSystem>();
|
||||
var xform = entManager.System<SharedTransformSystem>();
|
||||
|
||||
overlay.AddOverlay(new AccessOverlay(entManager, cache, lookup, xform));
|
||||
overlay.AddOverlay(new AccessOverlay(entManager, cache, xform));
|
||||
shell.WriteLine($"Set access reader debug overlay to true");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,6 +27,11 @@ public sealed class CargoBountyConsoleBoundUserInterface : BoundUserInterface
|
||||
SendMessage(new BountyPrintLabelMessage(id));
|
||||
};
|
||||
|
||||
_menu.OnSkipButtonPressed += id =>
|
||||
{
|
||||
SendMessage(new BountySkipMessage(id));
|
||||
};
|
||||
|
||||
_menu.OpenCentered();
|
||||
}
|
||||
|
||||
@@ -37,7 +42,7 @@ public sealed class CargoBountyConsoleBoundUserInterface : BoundUserInterface
|
||||
if (message is not CargoBountyConsoleState state)
|
||||
return;
|
||||
|
||||
_menu?.UpdateEntries(state.Bounties);
|
||||
_menu?.UpdateEntries(state.Bounties, state.UntilNextSkip);
|
||||
}
|
||||
|
||||
protected override void Dispose(bool disposing)
|
||||
|
||||
@@ -13,7 +13,18 @@
|
||||
</BoxContainer>
|
||||
<Control MinWidth="10"/>
|
||||
<BoxContainer Orientation="Vertical" MinWidth="120">
|
||||
<Button Name="PrintButton" Text="{Loc 'bounty-console-label-button-text'}" HorizontalExpand="False" HorizontalAlignment="Right"/>
|
||||
<BoxContainer Orientation="Horizontal" MinWidth="120">
|
||||
<Button Name="PrintButton"
|
||||
Text="{Loc 'bounty-console-label-button-text'}"
|
||||
HorizontalExpand="False"
|
||||
HorizontalAlignment="Right"
|
||||
StyleClasses="OpenRight"/>
|
||||
<Button Name="SkipButton"
|
||||
Text="{Loc 'bounty-console-skip-button-text'}"
|
||||
HorizontalExpand="False"
|
||||
HorizontalAlignment="Right"
|
||||
StyleClasses="OpenLeft"/>
|
||||
</BoxContainer>
|
||||
<RichTextLabel Name="IdLabel" HorizontalAlignment="Right" Margin="0 0 5 0"/>
|
||||
</BoxContainer>
|
||||
</BoxContainer>
|
||||
|
||||
@@ -1,11 +1,13 @@
|
||||
using Content.Client.Message;
|
||||
using Content.Shared.Cargo;
|
||||
using Content.Shared.Cargo.Prototypes;
|
||||
using Content.Shared.Random;
|
||||
using Robust.Client.AutoGenerated;
|
||||
using Robust.Client.UserInterface.Controls;
|
||||
using Robust.Client.UserInterface.XAML;
|
||||
using Robust.Shared.Prototypes;
|
||||
using Robust.Shared.Timing;
|
||||
using Serilog;
|
||||
|
||||
namespace Content.Client.Cargo.UI;
|
||||
|
||||
@@ -14,15 +16,19 @@ public sealed partial class BountyEntry : BoxContainer
|
||||
{
|
||||
[Dependency] private readonly IPrototypeManager _prototype = default!;
|
||||
|
||||
public Action? OnButtonPressed;
|
||||
public Action? OnLabelButtonPressed;
|
||||
public Action? OnSkipButtonPressed;
|
||||
|
||||
public TimeSpan EndTime;
|
||||
public TimeSpan UntilNextSkip;
|
||||
|
||||
public BountyEntry(CargoBountyData bounty)
|
||||
public BountyEntry(CargoBountyData bounty, TimeSpan untilNextSkip)
|
||||
{
|
||||
RobustXamlLoader.Load(this);
|
||||
IoCManager.InjectDependencies(this);
|
||||
|
||||
UntilNextSkip = untilNextSkip;
|
||||
|
||||
if (!_prototype.TryIndex<CargoBountyPrototype>(bounty.Bounty, out var bountyPrototype))
|
||||
return;
|
||||
|
||||
@@ -38,6 +44,27 @@ public sealed partial class BountyEntry : BoxContainer
|
||||
DescriptionLabel.SetMarkup(Loc.GetString("bounty-console-description-label", ("description", Loc.GetString(bountyPrototype.Description))));
|
||||
IdLabel.SetMarkup(Loc.GetString("bounty-console-id-label", ("id", bounty.Id)));
|
||||
|
||||
PrintButton.OnPressed += _ => OnButtonPressed?.Invoke();
|
||||
PrintButton.OnPressed += _ => OnLabelButtonPressed?.Invoke();
|
||||
SkipButton.OnPressed += _ => OnSkipButtonPressed?.Invoke();
|
||||
}
|
||||
|
||||
private void UpdateSkipButton(float deltaSeconds)
|
||||
{
|
||||
UntilNextSkip -= TimeSpan.FromSeconds(deltaSeconds);
|
||||
if (UntilNextSkip > TimeSpan.Zero)
|
||||
{
|
||||
SkipButton.Label.Text = UntilNextSkip.ToString("mm\\:ss");
|
||||
SkipButton.Disabled = true;
|
||||
return;
|
||||
}
|
||||
|
||||
SkipButton.Label.Text = Loc.GetString("bounty-console-skip-button-text");
|
||||
SkipButton.Disabled = false;
|
||||
}
|
||||
|
||||
protected override void FrameUpdate(FrameEventArgs args)
|
||||
{
|
||||
base.FrameUpdate(args);
|
||||
UpdateSkipButton(args.DeltaSeconds);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,19 +10,21 @@ namespace Content.Client.Cargo.UI;
|
||||
public sealed partial class CargoBountyMenu : FancyWindow
|
||||
{
|
||||
public Action<string>? OnLabelButtonPressed;
|
||||
public Action<string>? OnSkipButtonPressed;
|
||||
|
||||
public CargoBountyMenu()
|
||||
{
|
||||
RobustXamlLoader.Load(this);
|
||||
}
|
||||
|
||||
public void UpdateEntries(List<CargoBountyData> bounties)
|
||||
public void UpdateEntries(List<CargoBountyData> bounties, TimeSpan untilNextSkip)
|
||||
{
|
||||
BountyEntriesContainer.Children.Clear();
|
||||
foreach (var b in bounties)
|
||||
{
|
||||
var entry = new BountyEntry(b);
|
||||
entry.OnButtonPressed += () => OnLabelButtonPressed?.Invoke(b.Id);
|
||||
var entry = new BountyEntry(b, untilNextSkip);
|
||||
entry.OnLabelButtonPressed += () => OnLabelButtonPressed?.Invoke(b.Id);
|
||||
entry.OnSkipButtonPressed += () => OnSkipButtonPressed?.Invoke(b.Id);
|
||||
|
||||
BountyEntriesContainer.AddChild(entry);
|
||||
}
|
||||
|
||||
@@ -104,41 +104,12 @@ public sealed partial class LatheMenu : DefaultWindow
|
||||
RecipeList.Children.Clear();
|
||||
foreach (var prototype in sortedRecipesToShow)
|
||||
{
|
||||
StringBuilder sb = new();
|
||||
var first = true;
|
||||
foreach (var (id, amount) in prototype.RequiredMaterials)
|
||||
{
|
||||
if (!_prototypeManager.TryIndex<MaterialPrototype>(id, out var proto))
|
||||
continue;
|
||||
|
||||
if (first)
|
||||
first = false;
|
||||
else
|
||||
sb.Append('\n');
|
||||
|
||||
var adjustedAmount = SharedLatheSystem.AdjustMaterial(amount, prototype.ApplyMaterialDiscount, component.MaterialUseMultiplier);
|
||||
var sheetVolume = _materialStorage.GetSheetVolume(proto);
|
||||
|
||||
var unit = Loc.GetString(proto.Unit);
|
||||
// rounded in locale not here
|
||||
var sheets = adjustedAmount / (float) sheetVolume;
|
||||
var amountText = Loc.GetString("lathe-menu-material-amount", ("amount", sheets), ("unit", unit));
|
||||
var name = Loc.GetString(proto.Name);
|
||||
sb.Append(Loc.GetString("lathe-menu-tooltip-display", ("material", name), ("amount", amountText)));
|
||||
}
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(prototype.Description))
|
||||
{
|
||||
sb.Append('\n');
|
||||
sb.Append(Loc.GetString("lathe-menu-description-display", ("description", prototype.Description)));
|
||||
}
|
||||
|
||||
var icon = prototype.Icon == null
|
||||
? _spriteSystem.GetPrototypeIcon(prototype.Result).Default
|
||||
: _spriteSystem.Frame0(prototype.Icon);
|
||||
var canProduce = _lathe.CanProduce(_owner, prototype, quantity);
|
||||
|
||||
var control = new RecipeControl(prototype, sb.ToString(), canProduce, icon);
|
||||
var control = new RecipeControl(prototype, () => GenerateTooltipText(prototype), canProduce, icon);
|
||||
control.OnButtonPressed += s =>
|
||||
{
|
||||
if (!int.TryParse(AmountLineEdit.Text, out var amount) || amount <= 0)
|
||||
@@ -149,6 +120,51 @@ public sealed partial class LatheMenu : DefaultWindow
|
||||
}
|
||||
}
|
||||
|
||||
private string GenerateTooltipText(LatheRecipePrototype prototype)
|
||||
{
|
||||
StringBuilder sb = new();
|
||||
|
||||
foreach (var (id, amount) in prototype.RequiredMaterials)
|
||||
{
|
||||
if (!_prototypeManager.TryIndex<MaterialPrototype>(id, out var proto))
|
||||
continue;
|
||||
|
||||
var adjustedAmount = SharedLatheSystem.AdjustMaterial(amount, prototype.ApplyMaterialDiscount, _entityManager.GetComponent<LatheComponent>(_owner).MaterialUseMultiplier);
|
||||
var sheetVolume = _materialStorage.GetSheetVolume(proto);
|
||||
|
||||
var unit = Loc.GetString(proto.Unit);
|
||||
var sheets = adjustedAmount / (float) sheetVolume;
|
||||
|
||||
var availableAmount = _materialStorage.GetMaterialAmount(_owner, id);
|
||||
var missingAmount = Math.Max(0, adjustedAmount - availableAmount);
|
||||
var missingSheets = missingAmount / (float) sheetVolume;
|
||||
|
||||
var name = Loc.GetString(proto.Name);
|
||||
|
||||
string tooltipText;
|
||||
if (missingSheets > 0)
|
||||
{
|
||||
tooltipText = Loc.GetString("lathe-menu-material-amount-missing", ("amount", sheets), ("missingAmount", missingSheets), ("unit", unit), ("material", name));
|
||||
}
|
||||
else
|
||||
{
|
||||
var amountText = Loc.GetString("lathe-menu-material-amount", ("amount", sheets), ("unit", unit));
|
||||
tooltipText = Loc.GetString("lathe-menu-tooltip-display", ("material", name), ("amount", amountText));
|
||||
}
|
||||
|
||||
sb.AppendLine(tooltipText);
|
||||
}
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(prototype.Description))
|
||||
sb.AppendLine(Loc.GetString("lathe-menu-description-display", ("description", prototype.Description)));
|
||||
|
||||
// Remove last newline
|
||||
if (sb.Length > 0)
|
||||
sb.Remove(sb.Length - 1, 1);
|
||||
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
public void UpdateCategories()
|
||||
{
|
||||
var currentCategories = new List<ProtoId<LatheCategoryPrototype>>();
|
||||
|
||||
@@ -11,17 +11,16 @@ namespace Content.Client.Lathe.UI;
|
||||
public sealed partial class RecipeControl : Control
|
||||
{
|
||||
public Action<string>? OnButtonPressed;
|
||||
public Func<string> TooltipTextSupplier;
|
||||
|
||||
public string TooltipText;
|
||||
|
||||
public RecipeControl(LatheRecipePrototype recipe, string tooltip, bool canProduce, Texture? texture = null)
|
||||
public RecipeControl(LatheRecipePrototype recipe, Func<string> tooltipTextSupplier, bool canProduce, Texture? texture = null)
|
||||
{
|
||||
RobustXamlLoader.Load(this);
|
||||
|
||||
RecipeName.Text = recipe.Name;
|
||||
RecipeTexture.Texture = texture;
|
||||
Button.Disabled = !canProduce;
|
||||
TooltipText = tooltip;
|
||||
TooltipTextSupplier = tooltipTextSupplier;
|
||||
Button.TooltipSupplier = SupplyTooltip;
|
||||
|
||||
Button.OnPressed += (_) =>
|
||||
@@ -32,6 +31,6 @@ public sealed partial class RecipeControl : Control
|
||||
|
||||
private Control? SupplyTooltip(Control sender)
|
||||
{
|
||||
return new RecipeTooltip(TooltipText);
|
||||
return new RecipeTooltip(TooltipTextSupplier());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -210,9 +210,9 @@ public sealed partial class CrewMonitoringWindow : FancyWindow
|
||||
specifier = new SpriteSpecifier.Rsi(new ResPath("Interface/Alerts/human_crew_monitoring.rsi"), "dead");
|
||||
}
|
||||
|
||||
else if (sensor.TotalDamage != null)
|
||||
else if (sensor.DamagePercentage != null)
|
||||
{
|
||||
var index = MathF.Round(4f * (sensor.TotalDamage.Value / 100f));
|
||||
var index = MathF.Round(4f * sensor.DamagePercentage.Value);
|
||||
|
||||
if (index >= 5)
|
||||
specifier = new SpriteSpecifier.Rsi(new ResPath("Interface/Alerts/human_crew_monitoring.rsi"), "critical");
|
||||
|
||||
@@ -49,6 +49,7 @@
|
||||
<Label Text="{Loc 'ui-options-general-speech'}"
|
||||
FontColorOverride="{xNamespace:Static s:StyleNano.NanoGold}"
|
||||
StyleClasses="LabelKeyText"/>
|
||||
<CheckBox Name="ShowOocPatronColor" Text="{Loc 'ui-options-show-ooc-patron-color'}" />
|
||||
<CheckBox Name="ShowLoocAboveHeadCheckBox" Text="{Loc 'ui-options-show-looc-on-head'}" />
|
||||
<CheckBox Name="FancySpeechBubblesCheckBox" Text="{Loc 'ui-options-fancy-speech'}" />
|
||||
<CheckBox Name="FancyNameBackgroundsCheckBox" Text="{Loc 'ui-options-fancy-name-background'}" />
|
||||
|
||||
@@ -3,11 +3,14 @@ using Content.Client.UserInterface.Screens;
|
||||
using Content.Shared.CCVar;
|
||||
using Content.Shared.HUD;
|
||||
using Robust.Client.AutoGenerated;
|
||||
using Robust.Client.Player;
|
||||
using Robust.Client.UserInterface;
|
||||
using Robust.Client.UserInterface.Controls;
|
||||
using Robust.Client.UserInterface.XAML;
|
||||
using Robust.Shared;
|
||||
using Robust.Shared.Configuration;
|
||||
using Robust.Shared.Network;
|
||||
using Robust.Shared.Player;
|
||||
using Robust.Shared.Prototypes;
|
||||
using Range = Robust.Client.UserInterface.Controls.Range;
|
||||
|
||||
@@ -16,6 +19,7 @@ namespace Content.Client.Options.UI.Tabs
|
||||
[GenerateTypedNameReferences]
|
||||
public sealed partial class MiscTab : Control
|
||||
{
|
||||
[Dependency] private readonly IPlayerManager _playerManager = default!;
|
||||
[Dependency] private readonly IConfigurationManager _cfg = default!;
|
||||
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
|
||||
|
||||
@@ -55,8 +59,11 @@ namespace Content.Client.Options.UI.Tabs
|
||||
UpdateApplyButton();
|
||||
};
|
||||
|
||||
ShowOocPatronColor.Visible = _playerManager.LocalSession?.Channel.UserData.PatronTier is { } patron;
|
||||
|
||||
HudThemeOption.OnItemSelected += OnHudThemeChanged;
|
||||
DiscordRich.OnToggled += OnCheckBoxToggled;
|
||||
ShowOocPatronColor.OnToggled += OnCheckBoxToggled;
|
||||
ShowLoocAboveHeadCheckBox.OnToggled += OnCheckBoxToggled;
|
||||
ShowHeldItemCheckBox.OnToggled += OnCheckBoxToggled;
|
||||
ShowCombatModeIndicatorsCheckBox.OnToggled += OnCheckBoxToggled;
|
||||
@@ -73,6 +80,7 @@ namespace Content.Client.Options.UI.Tabs
|
||||
|
||||
HudThemeOption.SelectId(_hudThemeIdToIndex.GetValueOrDefault(_cfg.GetCVar(CVars.InterfaceTheme), 0));
|
||||
DiscordRich.Pressed = _cfg.GetCVar(CVars.DiscordEnabled);
|
||||
ShowOocPatronColor.Pressed = _cfg.GetCVar(CCVars.ShowOocPatronColor);
|
||||
ShowLoocAboveHeadCheckBox.Pressed = _cfg.GetCVar(CCVars.LoocAboveHeadShow);
|
||||
ShowHeldItemCheckBox.Pressed = _cfg.GetCVar(CCVars.HudHeldItemShow);
|
||||
ShowCombatModeIndicatorsCheckBox.Pressed = _cfg.GetCVar(CCVars.CombatModeIndicatorsPointShow);
|
||||
@@ -130,6 +138,7 @@ namespace Content.Client.Options.UI.Tabs
|
||||
_cfg.SetCVar(CCVars.HudHeldItemShow, ShowHeldItemCheckBox.Pressed);
|
||||
_cfg.SetCVar(CCVars.CombatModeIndicatorsPointShow, ShowCombatModeIndicatorsCheckBox.Pressed);
|
||||
_cfg.SetCVar(CCVars.OpaqueStorageWindow, OpaqueStorageWindowCheckBox.Pressed);
|
||||
_cfg.SetCVar(CCVars.ShowOocPatronColor, ShowOocPatronColor.Pressed);
|
||||
_cfg.SetCVar(CCVars.LoocAboveHeadShow, ShowLoocAboveHeadCheckBox.Pressed);
|
||||
_cfg.SetCVar(CCVars.ChatEnableFancyBubbles, FancySpeechBubblesCheckBox.Pressed);
|
||||
_cfg.SetCVar(CCVars.ChatFancyNameBackground, FancyNameBackgroundsCheckBox.Pressed);
|
||||
@@ -158,6 +167,7 @@ namespace Content.Client.Options.UI.Tabs
|
||||
var isShowHeldItemSame = ShowHeldItemCheckBox.Pressed == _cfg.GetCVar(CCVars.HudHeldItemShow);
|
||||
var isCombatModeIndicatorsSame = ShowCombatModeIndicatorsCheckBox.Pressed == _cfg.GetCVar(CCVars.CombatModeIndicatorsPointShow);
|
||||
var isOpaqueStorageWindow = OpaqueStorageWindowCheckBox.Pressed == _cfg.GetCVar(CCVars.OpaqueStorageWindow);
|
||||
var isOocPatronColorShowSame = ShowOocPatronColor.Pressed == _cfg.GetCVar(CCVars.ShowOocPatronColor);
|
||||
var isLoocShowSame = ShowLoocAboveHeadCheckBox.Pressed == _cfg.GetCVar(CCVars.LoocAboveHeadShow);
|
||||
var isFancyChatSame = FancySpeechBubblesCheckBox.Pressed == _cfg.GetCVar(CCVars.ChatEnableFancyBubbles);
|
||||
var isFancyBackgroundSame = FancyNameBackgroundsCheckBox.Pressed == _cfg.GetCVar(CCVars.ChatFancyNameBackground);
|
||||
@@ -175,6 +185,7 @@ namespace Content.Client.Options.UI.Tabs
|
||||
isShowHeldItemSame &&
|
||||
isCombatModeIndicatorsSame &&
|
||||
isOpaqueStorageWindow &&
|
||||
isOocPatronColorShowSame &&
|
||||
isLoocShowSame &&
|
||||
isFancyChatSame &&
|
||||
isFancyBackgroundSame &&
|
||||
|
||||
@@ -19,7 +19,6 @@ namespace Content.Client.Overlays;
|
||||
/// </summary>
|
||||
public sealed class EntityHealthBarOverlay : Overlay
|
||||
{
|
||||
[Dependency] private readonly IPrototypeManager _prototype = default!;
|
||||
private readonly IEntityManager _entManager;
|
||||
private readonly SharedTransformSystem _transform;
|
||||
private readonly MobStateSystem _mobStateSystem;
|
||||
@@ -27,17 +26,14 @@ public sealed class EntityHealthBarOverlay : Overlay
|
||||
private readonly ProgressColorSystem _progressColor;
|
||||
public override OverlaySpace Space => OverlaySpace.WorldSpaceBelowFOV;
|
||||
public HashSet<string> DamageContainers = new();
|
||||
private readonly ShaderInstance _shader;
|
||||
|
||||
public EntityHealthBarOverlay(IEntityManager entManager)
|
||||
{
|
||||
IoCManager.InjectDependencies(this);
|
||||
_entManager = entManager;
|
||||
_transform = _entManager.System<SharedTransformSystem>();
|
||||
_mobStateSystem = _entManager.System<MobStateSystem>();
|
||||
_mobThresholdSystem = _entManager.System<MobThresholdSystem>();
|
||||
_progressColor = _entManager.System<ProgressColorSystem>();
|
||||
_shader = _prototype.Index<ShaderPrototype>("unshaded").Instance();
|
||||
}
|
||||
|
||||
protected override void Draw(in OverlayDrawArgs args)
|
||||
@@ -50,8 +46,6 @@ public sealed class EntityHealthBarOverlay : Overlay
|
||||
var scaleMatrix = Matrix3.CreateScale(new Vector2(scale, scale));
|
||||
var rotationMatrix = Matrix3.CreateRotation(-rotation);
|
||||
|
||||
handle.UseShader(_shader);
|
||||
|
||||
var query = _entManager.AllEntityQueryEnumerator<MobThresholdsComponent, MobStateComponent, DamageableComponent, SpriteComponent>();
|
||||
while (query.MoveNext(out var uid,
|
||||
out var mobThresholdsComponent,
|
||||
@@ -122,7 +116,6 @@ public sealed class EntityHealthBarOverlay : Overlay
|
||||
handle.DrawRect(pixelDarken, Black.WithAlpha(128));
|
||||
}
|
||||
|
||||
handle.UseShader(null);
|
||||
handle.SetTransform(Matrix3.Identity);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
using Content.Client.UserInterface.Controls;
|
||||
using Content.Shared.Popups;
|
||||
using Content.Shared.RCD;
|
||||
using Content.Shared.RCD.Components;
|
||||
using Robust.Client.AutoGenerated;
|
||||
using Robust.Client.GameObjects;
|
||||
using Robust.Client.Player;
|
||||
using Robust.Client.UserInterface;
|
||||
using Robust.Client.UserInterface.Controls;
|
||||
using Robust.Client.UserInterface.XAML;
|
||||
@@ -16,17 +18,24 @@ public sealed partial class RCDMenu : RadialMenu
|
||||
{
|
||||
[Dependency] private readonly EntityManager _entManager = default!;
|
||||
[Dependency] private readonly IPrototypeManager _protoManager = default!;
|
||||
[Dependency] private readonly IPlayerManager _playerManager = default!;
|
||||
|
||||
private readonly SpriteSystem _spriteSystem;
|
||||
private readonly SharedPopupSystem _popup;
|
||||
|
||||
public event Action<ProtoId<RCDPrototype>>? SendRCDSystemMessageAction;
|
||||
|
||||
private EntityUid _owner;
|
||||
|
||||
public RCDMenu(EntityUid owner, RCDMenuBoundUserInterface bui)
|
||||
{
|
||||
IoCManager.InjectDependencies(this);
|
||||
RobustXamlLoader.Load(this);
|
||||
|
||||
_spriteSystem = _entManager.System<SpriteSystem>();
|
||||
_popup = _entManager.System<SharedPopupSystem>();
|
||||
|
||||
_owner = owner;
|
||||
|
||||
// Find the main radial container
|
||||
var main = FindControl<RadialContainer>("Main");
|
||||
@@ -51,14 +60,21 @@ public sealed partial class RCDMenu : RadialMenu
|
||||
if (parent == null)
|
||||
continue;
|
||||
|
||||
var name = Loc.GetString(proto.SetName);
|
||||
name = char.ToUpper(name[0]) + name.Remove(0, 1);
|
||||
var tooltip = Loc.GetString(proto.SetName);
|
||||
|
||||
if ((proto.Mode == RcdMode.ConstructTile || proto.Mode == RcdMode.ConstructObject) &&
|
||||
proto.Prototype != null && _protoManager.TryIndex(proto.Prototype, out var entProto))
|
||||
{
|
||||
tooltip = Loc.GetString(entProto.Name);
|
||||
}
|
||||
|
||||
tooltip = char.ToUpper(tooltip[0]) + tooltip.Remove(0, 1);
|
||||
|
||||
var button = new RCDMenuButton()
|
||||
{
|
||||
StyleClasses = { "RadialMenuButton" },
|
||||
SetSize = new Vector2(64f, 64f),
|
||||
ToolTip = name,
|
||||
ToolTip = tooltip,
|
||||
ProtoId = protoId,
|
||||
};
|
||||
|
||||
@@ -120,6 +136,27 @@ public sealed partial class RCDMenu : RadialMenu
|
||||
castChild.OnButtonUp += _ =>
|
||||
{
|
||||
SendRCDSystemMessageAction?.Invoke(castChild.ProtoId);
|
||||
|
||||
if (_playerManager.LocalSession?.AttachedEntity != null &&
|
||||
_protoManager.TryIndex(castChild.ProtoId, out var proto))
|
||||
{
|
||||
var msg = Loc.GetString("rcd-component-change-mode", ("mode", Loc.GetString(proto.SetName)));
|
||||
|
||||
if (proto.Mode == RcdMode.ConstructTile || proto.Mode == RcdMode.ConstructObject)
|
||||
{
|
||||
var name = Loc.GetString(proto.SetName);
|
||||
|
||||
if (proto.Prototype != null &&
|
||||
_protoManager.TryIndex(proto.Prototype, out var entProto))
|
||||
name = entProto.Name;
|
||||
|
||||
msg = Loc.GetString("rcd-component-change-build-mode", ("name", name));
|
||||
}
|
||||
|
||||
// Popup message
|
||||
_popup.PopupClient(msg, _owner, _playerManager.LocalSession.AttachedEntity);
|
||||
}
|
||||
|
||||
Close();
|
||||
};
|
||||
}
|
||||
|
||||
@@ -3,9 +3,9 @@ using Content.Shared.StatusIcon.Components;
|
||||
using Robust.Client.GameObjects;
|
||||
using Robust.Client.Graphics;
|
||||
using Robust.Shared.Enums;
|
||||
using System.Numerics;
|
||||
using Robust.Shared.Prototypes;
|
||||
using Robust.Shared.Timing;
|
||||
using System.Numerics;
|
||||
|
||||
namespace Content.Client.StatusIcon;
|
||||
|
||||
@@ -18,7 +18,7 @@ public sealed class StatusIconOverlay : Overlay
|
||||
private readonly SpriteSystem _sprite;
|
||||
private readonly TransformSystem _transform;
|
||||
private readonly StatusIconSystem _statusIcon;
|
||||
private readonly ShaderInstance _shader;
|
||||
private readonly ShaderInstance _unshadedShader;
|
||||
|
||||
public override OverlaySpace Space => OverlaySpace.WorldSpaceBelowFOV;
|
||||
|
||||
@@ -29,7 +29,7 @@ public sealed class StatusIconOverlay : Overlay
|
||||
_sprite = _entity.System<SpriteSystem>();
|
||||
_transform = _entity.System<TransformSystem>();
|
||||
_statusIcon = _entity.System<StatusIconSystem>();
|
||||
_shader = _prototype.Index<ShaderPrototype>("unshaded").Instance();
|
||||
_unshadedShader = _prototype.Index<ShaderPrototype>("unshaded").Instance();
|
||||
}
|
||||
|
||||
protected override void Draw(in OverlayDrawArgs args)
|
||||
@@ -42,8 +42,6 @@ public sealed class StatusIconOverlay : Overlay
|
||||
var scaleMatrix = Matrix3.CreateScale(new Vector2(1, 1));
|
||||
var rotationMatrix = Matrix3.CreateRotation(-eyeRot);
|
||||
|
||||
handle.UseShader(_shader);
|
||||
|
||||
var query = _entity.AllEntityQueryEnumerator<StatusIconComponent, SpriteComponent, TransformComponent, MetaDataComponent>();
|
||||
while (query.MoveNext(out var uid, out var comp, out var sprite, out var xform, out var meta))
|
||||
{
|
||||
@@ -111,11 +109,16 @@ public sealed class StatusIconOverlay : Overlay
|
||||
|
||||
}
|
||||
|
||||
if (proto.IsShaded)
|
||||
handle.UseShader(null);
|
||||
else
|
||||
handle.UseShader(_unshadedShader);
|
||||
|
||||
var position = new Vector2(xOffset, yOffset);
|
||||
handle.DrawTexture(texture, position);
|
||||
}
|
||||
}
|
||||
|
||||
handle.UseShader(null);
|
||||
handle.UseShader(null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,4 +18,7 @@ public enum WeaponArcAnimation : byte
|
||||
None,
|
||||
Thrust,
|
||||
Slash,
|
||||
//CrystallPunk Melee upgrade
|
||||
CPSlash,
|
||||
CPThrust
|
||||
}
|
||||
|
||||
@@ -42,6 +42,9 @@ public sealed partial class MeleeWeaponSystem
|
||||
return;
|
||||
}
|
||||
|
||||
var length = 1f; //CrystallPunk Melee upgrade
|
||||
var offset = -1f; //CrystallPunk Melee upgrade
|
||||
|
||||
var spriteRotation = Angle.Zero;
|
||||
if (arcComponent.Animation != WeaponArcAnimation.None
|
||||
&& TryComp(weapon, out MeleeWeaponComponent? meleeWeaponComponent))
|
||||
@@ -54,6 +57,9 @@ public sealed partial class MeleeWeaponSystem
|
||||
|
||||
if (meleeWeaponComponent.SwingLeft)
|
||||
angle *= -1;
|
||||
|
||||
length = meleeWeaponComponent.CPAnimationLength; //CrystallPunk Melee upgrade
|
||||
offset = meleeWeaponComponent.CPAnimationOffset; //CrystallPunk Melee upgrade
|
||||
}
|
||||
sprite.NoRotation = true;
|
||||
sprite.Rotation = localPos.ToWorldAngle();
|
||||
@@ -84,6 +90,20 @@ public sealed partial class MeleeWeaponSystem
|
||||
if (arcComponent.Fadeout)
|
||||
_animation.Play(animationUid, GetFadeAnimation(sprite, 0f, 0.15f), FadeAnimationKey);
|
||||
break;
|
||||
//CrystallPunk MeleeUpgrade
|
||||
case WeaponArcAnimation.CPSlash:
|
||||
_animation.Play(animationUid, CPGetSlashAnimation(sprite, angle, spriteRotation, length, offset), SlashAnimationKey);
|
||||
TransformSystem.SetParent(animationUid, xform, user, userXform);
|
||||
if (arcComponent.Fadeout)
|
||||
_animation.Play(animationUid, GetFadeAnimation(sprite, length * 0.5f, length + 0.15f), FadeAnimationKey);
|
||||
break;
|
||||
case WeaponArcAnimation.CPThrust:
|
||||
_animation.Play(animationUid, CPGetThrustAnimation(sprite, -offset, spriteRotation, length), ThrustAnimationKey);
|
||||
TransformSystem.SetParent(animationUid, xform, user, userXform);
|
||||
if (arcComponent.Fadeout)
|
||||
_animation.Play(animationUid, GetFadeAnimation(sprite, 0f, 0.15f), FadeAnimationKey);
|
||||
break;
|
||||
//CrystallPunk MeleeUpgrade end
|
||||
}
|
||||
}
|
||||
|
||||
@@ -184,7 +204,7 @@ public sealed partial class MeleeWeaponSystem
|
||||
/// </summary>
|
||||
private Animation GetLungeAnimation(Vector2 direction)
|
||||
{
|
||||
const float length = 0.1f;
|
||||
const float length = 0.2f; // 0.1 original, CrystallPunk update
|
||||
|
||||
return new Animation
|
||||
{
|
||||
@@ -198,11 +218,86 @@ public sealed partial class MeleeWeaponSystem
|
||||
InterpolationMode = AnimationInterpolationMode.Linear,
|
||||
KeyFrames =
|
||||
{
|
||||
new AnimationTrackProperty.KeyFrame(direction.Normalized() * 0.15f, 0f),
|
||||
new AnimationTrackProperty.KeyFrame(Vector2.Zero, length)
|
||||
new AnimationTrackProperty.KeyFrame(Vector2.Zero, 0f), //CrystallPunk MeleeUpgrade
|
||||
new AnimationTrackProperty.KeyFrame(direction.Normalized() * 0.15f, length*0.4f), //CrystallPunk MeleeUpgrade
|
||||
new AnimationTrackProperty.KeyFrame(Vector2.Zero, length*0.8f) //CrystallPunk MeleeUpgrade
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
//CrystallPunk MeleeUpgrade start
|
||||
private Animation CPGetSlashAnimation(SpriteComponent sprite, Angle arc, Angle spriteRotation, float length, float offset = -1f)
|
||||
{
|
||||
var startRotation = sprite.Rotation + (arc * 0.5f);
|
||||
var endRotation = sprite.Rotation - (arc * 0.5f);
|
||||
|
||||
var startRotationOffset = startRotation.RotateVec(new Vector2(0f, offset));
|
||||
var endRotationOffset = endRotation.RotateVec(new Vector2(0f, offset));
|
||||
|
||||
startRotation += spriteRotation;
|
||||
endRotation += spriteRotation;
|
||||
sprite.NoRotation = true;
|
||||
|
||||
return new Animation()
|
||||
{
|
||||
Length = TimeSpan.FromSeconds(length + 0.05f),
|
||||
AnimationTracks =
|
||||
{
|
||||
new AnimationTrackComponentProperty()
|
||||
{
|
||||
ComponentType = typeof(SpriteComponent),
|
||||
Property = nameof(SpriteComponent.Rotation),
|
||||
KeyFrames =
|
||||
{
|
||||
new AnimationTrackProperty.KeyFrame(Angle.Lerp(startRotation,endRotation,0.0f), length * 0.0f),
|
||||
new AnimationTrackProperty.KeyFrame(Angle.Lerp(startRotation,endRotation,1.0f), length * 0.6f),
|
||||
new AnimationTrackProperty.KeyFrame(Angle.Lerp(startRotation,endRotation,0.8f), length * 1.0f),
|
||||
}
|
||||
},
|
||||
new AnimationTrackComponentProperty()
|
||||
{
|
||||
ComponentType = typeof(SpriteComponent),
|
||||
Property = nameof(SpriteComponent.Offset),
|
||||
KeyFrames =
|
||||
{
|
||||
new AnimationTrackProperty.KeyFrame(Vector2.Lerp(startRotationOffset,endRotationOffset,0.0f), length * 0.0f),
|
||||
new AnimationTrackProperty.KeyFrame(Vector2.Lerp(startRotationOffset,endRotationOffset,1.0f), length * 0.6f),
|
||||
new AnimationTrackProperty.KeyFrame(Vector2.Lerp(startRotationOffset,endRotationOffset,0.8f), length * 1.0f),
|
||||
}
|
||||
},
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private Animation CPGetThrustAnimation(SpriteComponent sprite, float distance, Angle spriteRotation, float length)
|
||||
{
|
||||
var startOffset = sprite.Rotation.RotateVec(new Vector2(0f, -distance / 5f));
|
||||
var endOffset = sprite.Rotation.RotateVec(new Vector2(0f, -distance));
|
||||
|
||||
sprite.Rotation += spriteRotation;
|
||||
|
||||
return new Animation()
|
||||
{
|
||||
Length = TimeSpan.FromSeconds(length),
|
||||
AnimationTracks =
|
||||
{
|
||||
new AnimationTrackComponentProperty()
|
||||
{
|
||||
ComponentType = typeof(SpriteComponent),
|
||||
Property = nameof(SpriteComponent.Offset),
|
||||
KeyFrames =
|
||||
{
|
||||
new AnimationTrackProperty.KeyFrame(Vector2.Lerp(startOffset, endOffset, 0f), length * 0f),
|
||||
new AnimationTrackProperty.KeyFrame(Vector2.Lerp(startOffset, endOffset, 1f), length * 0.5f),
|
||||
new AnimationTrackProperty.KeyFrame(Vector2.Lerp(startOffset, endOffset, 0.9f), length * 0.8f),
|
||||
}
|
||||
},
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
//CrystallPunk MeleeUpgrade end
|
||||
|
||||
}
|
||||
|
||||
@@ -56,7 +56,7 @@ public sealed class CraftingTests : InteractionTest
|
||||
|
||||
// Player's hands should be full of the remaining rods, except those dropped during the failed crafting attempt.
|
||||
// Spear and left over stacks should be on the floor.
|
||||
await AssertEntityLookup((Rod, 2), (Cable, 8), (ShardGlass, 2), (Spear, 1));
|
||||
await AssertEntityLookup((Rod, 2), (Cable, 7), (ShardGlass, 2), (Spear, 1));
|
||||
}
|
||||
|
||||
// The following is wrapped in an if DEBUG. This is because of cursed state handling bugs. Tests don't (de)serialize
|
||||
@@ -100,7 +100,7 @@ public sealed class CraftingTests : InteractionTest
|
||||
Assert.That(sys.IsEntityInContainer(rods), Is.False);
|
||||
Assert.That(sys.IsEntityInContainer(wires), Is.False);
|
||||
Assert.That(rodStack, Has.Count.EqualTo(8));
|
||||
Assert.That(wireStack, Has.Count.EqualTo(8));
|
||||
Assert.That(wireStack, Has.Count.EqualTo(7));
|
||||
|
||||
await FindEntity(Spear, shouldSucceed: false);
|
||||
});
|
||||
|
||||
@@ -14,7 +14,7 @@ namespace Content.Server.Audio;
|
||||
public sealed class ContentAudioSystem : SharedContentAudioSystem
|
||||
{
|
||||
[ValidatePrototypeId<SoundCollectionPrototype>]
|
||||
private const string LobbyMusicCollection = "LobbyMusic";
|
||||
private const string LobbyMusicCollection = "CPLobbyMusic";
|
||||
|
||||
[Dependency] private readonly AudioSystem _serverAudio = default!;
|
||||
[Dependency] private readonly IRobustRandom _robustRandom = default!;
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using Content.Shared.Cargo;
|
||||
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom;
|
||||
|
||||
namespace Content.Server.Cargo.Components;
|
||||
|
||||
@@ -32,4 +33,16 @@ public sealed partial class StationCargoBountyDatabaseComponent : Component
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public HashSet<string> CheckedBounties = new();
|
||||
|
||||
/// <summary>
|
||||
/// The time at which players will be able to skip the next bounty.
|
||||
/// </summary>
|
||||
[DataField(customTypeSerializer: typeof(TimeOffsetSerializer))]
|
||||
public TimeSpan NextSkipTime = TimeSpan.Zero;
|
||||
|
||||
/// <summary>
|
||||
/// The time between skipping bounties.
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public TimeSpan SkipDelay = TimeSpan.FromMinutes(15);
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@ using Content.Server.Cargo.Components;
|
||||
using Content.Server.Labels;
|
||||
using Content.Server.NameIdentifier;
|
||||
using Content.Server.Paper;
|
||||
using Content.Server.Station.Systems;
|
||||
using Content.Shared.Access.Components;
|
||||
using Content.Shared.Cargo;
|
||||
using Content.Shared.Cargo.Components;
|
||||
using Content.Shared.Cargo.Prototypes;
|
||||
@@ -35,6 +35,7 @@ public sealed partial class CargoSystem
|
||||
{
|
||||
SubscribeLocalEvent<CargoBountyConsoleComponent, BoundUIOpenedEvent>(OnBountyConsoleOpened);
|
||||
SubscribeLocalEvent<CargoBountyConsoleComponent, BountyPrintLabelMessage>(OnPrintLabelMessage);
|
||||
SubscribeLocalEvent<CargoBountyConsoleComponent, BountySkipMessage>(OnSkipBountyMessage);
|
||||
SubscribeLocalEvent<CargoBountyLabelComponent, PriceCalculationEvent>(OnGetBountyPrice);
|
||||
SubscribeLocalEvent<EntitySoldEvent>(OnSold);
|
||||
SubscribeLocalEvent<StationCargoBountyDatabaseComponent, MapInitEvent>(OnMapInit);
|
||||
@@ -50,7 +51,8 @@ public sealed partial class CargoSystem
|
||||
!TryComp<StationCargoBountyDatabaseComponent>(station, out var bountyDb))
|
||||
return;
|
||||
|
||||
_uiSystem.TrySetUiState(uid, CargoConsoleUiKey.Bounty, new CargoBountyConsoleState(bountyDb.Bounties));
|
||||
var untilNextSkip = bountyDb.NextSkipTime - _timing.CurTime;
|
||||
_uiSystem.TrySetUiState(uid, CargoConsoleUiKey.Bounty, new CargoBountyConsoleState(bountyDb.Bounties, untilNextSkip));
|
||||
}
|
||||
|
||||
private void OnPrintLabelMessage(EntityUid uid, CargoBountyConsoleComponent component, BountyPrintLabelMessage args)
|
||||
@@ -70,6 +72,37 @@ public sealed partial class CargoSystem
|
||||
_audio.PlayPvs(component.PrintSound, uid);
|
||||
}
|
||||
|
||||
private void OnSkipBountyMessage(EntityUid uid, CargoBountyConsoleComponent component, BountySkipMessage args)
|
||||
{
|
||||
if (_station.GetOwningStation(uid) is not { } station || !TryComp<StationCargoBountyDatabaseComponent>(station, out var db))
|
||||
return;
|
||||
|
||||
if (_timing.CurTime < db.NextSkipTime)
|
||||
return;
|
||||
|
||||
if (!TryGetBountyFromId(station, args.BountyId, out var bounty))
|
||||
return;
|
||||
|
||||
if (args.Session.AttachedEntity is not { Valid: true } mob)
|
||||
return;
|
||||
|
||||
if (TryComp<AccessReaderComponent>(uid, out var accessReaderComponent) &&
|
||||
!_accessReaderSystem.IsAllowed(mob, uid, accessReaderComponent))
|
||||
{
|
||||
_audio.PlayPvs(component.DenySound, uid);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!TryRemoveBounty(station, bounty.Value))
|
||||
return;
|
||||
|
||||
FillBountyDatabase(station);
|
||||
db.NextSkipTime = _timing.CurTime + db.SkipDelay;
|
||||
var untilNextSkip = db.NextSkipTime - _timing.CurTime;
|
||||
_uiSystem.TrySetUiState(uid, CargoConsoleUiKey.Bounty, new CargoBountyConsoleState(db.Bounties, untilNextSkip));
|
||||
_audio.PlayPvs(component.SkipSound, uid);
|
||||
}
|
||||
|
||||
public void SetupBountyLabel(EntityUid uid, EntityUid stationId, CargoBountyData bounty, PaperComponent? paper = null, CargoBountyLabelComponent? label = null)
|
||||
{
|
||||
if (!Resolve(uid, ref paper, ref label) || !_protoMan.TryIndex<CargoBountyPrototype>(bounty.Bounty, out var prototype))
|
||||
@@ -431,7 +464,8 @@ public sealed partial class CargoSystem
|
||||
!TryComp<StationCargoBountyDatabaseComponent>(station, out var db))
|
||||
continue;
|
||||
|
||||
_uiSystem.TrySetUiState(uid, CargoConsoleUiKey.Bounty, new CargoBountyConsoleState(db.Bounties), ui: ui);
|
||||
var untilNextSkip = db.NextSkipTime - _timing.CurTime;
|
||||
_uiSystem.TrySetUiState(uid, CargoConsoleUiKey.Bounty, new CargoBountyConsoleState(db.Bounties, untilNextSkip), ui: ui);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -244,8 +244,7 @@ namespace Content.Server.Chat.Managers
|
||||
var prefs = _preferencesManager.GetPreferences(player.UserId);
|
||||
colorOverride = prefs.AdminOOCColor;
|
||||
}
|
||||
if (player.Channel.UserData.PatronTier is { } patron &&
|
||||
PatronOocColors.TryGetValue(patron, out var patronColor))
|
||||
if ( _netConfigManager.GetClientCVar(player.Channel, CCVars.ShowOocPatronColor) && player.Channel.UserData.PatronTier is { } patron && PatronOocColors.TryGetValue(patron, out var patronColor))
|
||||
{
|
||||
wrappedMessage = Loc.GetString("chat-manager-send-ooc-patron-wrap-message", ("patronColor", patronColor),("playerName", player.Name), ("message", FormattedMessage.EscapeText(message)));
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using System.Collections.Immutable;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text.Json.Nodes;
|
||||
using System.Threading.Tasks;
|
||||
using Content.Server.Database;
|
||||
@@ -10,6 +11,7 @@ using Content.Shared.Players.PlayTimeTracking;
|
||||
using Robust.Server.Player;
|
||||
using Robust.Shared.Configuration;
|
||||
using Robust.Shared.Network;
|
||||
using Robust.Shared.Timing;
|
||||
|
||||
|
||||
namespace Content.Server.Connection
|
||||
@@ -17,6 +19,18 @@ namespace Content.Server.Connection
|
||||
public interface IConnectionManager
|
||||
{
|
||||
void Initialize();
|
||||
|
||||
/// <summary>
|
||||
/// Temporarily allow a user to bypass regular connection requirements.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The specified user will be allowed to bypass regular player cap,
|
||||
/// whitelist and panic bunker restrictions for <paramref name="duration"/>.
|
||||
/// Bans are not bypassed.
|
||||
/// </remarks>
|
||||
/// <param name="user">The user to give a temporary bypass.</param>
|
||||
/// <param name="duration">How long the bypass should last for.</param>
|
||||
void AddTemporaryConnectBypass(NetUserId user, TimeSpan duration);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -31,15 +45,31 @@ namespace Content.Server.Connection
|
||||
[Dependency] private readonly IConfigurationManager _cfg = default!;
|
||||
[Dependency] private readonly ILocalizationManager _loc = default!;
|
||||
[Dependency] private readonly ServerDbEntryManager _serverDbEntry = default!;
|
||||
[Dependency] private readonly IGameTiming _gameTiming = default!;
|
||||
[Dependency] private readonly ILogManager _logManager = default!;
|
||||
|
||||
private readonly Dictionary<NetUserId, TimeSpan> _temporaryBypasses = [];
|
||||
private ISawmill _sawmill = default!;
|
||||
|
||||
public void Initialize()
|
||||
{
|
||||
_sawmill = _logManager.GetSawmill("connections");
|
||||
|
||||
_netMgr.Connecting += NetMgrOnConnecting;
|
||||
_netMgr.AssignUserIdCallback = AssignUserIdCallback;
|
||||
// Approval-based IP bans disabled because they don't play well with Happy Eyeballs.
|
||||
// _netMgr.HandleApprovalCallback = HandleApproval;
|
||||
}
|
||||
|
||||
public void AddTemporaryConnectBypass(NetUserId user, TimeSpan duration)
|
||||
{
|
||||
ref var time = ref CollectionsMarshal.GetValueRefOrAddDefault(_temporaryBypasses, user, out _);
|
||||
var newTime = _gameTiming.RealTime + duration;
|
||||
// Make sure we only update the time if we wouldn't shrink it.
|
||||
if (newTime > time)
|
||||
time = newTime;
|
||||
}
|
||||
|
||||
/*
|
||||
private async Task<NetApproval> HandleApproval(NetApprovalEventArgs eventArgs)
|
||||
{
|
||||
@@ -109,6 +139,20 @@ namespace Content.Server.Connection
|
||||
hwId = null;
|
||||
}
|
||||
|
||||
var bans = await _db.GetServerBansAsync(addr, userId, hwId, includeUnbanned: false);
|
||||
if (bans.Count > 0)
|
||||
{
|
||||
var firstBan = bans[0];
|
||||
var message = firstBan.FormatBanMessage(_cfg, _loc);
|
||||
return (ConnectionDenyReason.Ban, message, bans);
|
||||
}
|
||||
|
||||
if (HasTemporaryBypass(userId))
|
||||
{
|
||||
_sawmill.Verbose("User {UserId} has temporary bypass, skipping further connection checks", userId);
|
||||
return null;
|
||||
}
|
||||
|
||||
var adminData = await _dbManager.GetAdminDataForAsync(e.UserId);
|
||||
|
||||
if (_cfg.GetCVar(CCVars.PanicBunkerEnabled) && adminData == null)
|
||||
@@ -167,14 +211,6 @@ namespace Content.Server.Connection
|
||||
return (ConnectionDenyReason.Full, Loc.GetString("soft-player-cap-full"), null);
|
||||
}
|
||||
|
||||
var bans = await _db.GetServerBansAsync(addr, userId, hwId, includeUnbanned: false);
|
||||
if (bans.Count > 0)
|
||||
{
|
||||
var firstBan = bans[0];
|
||||
var message = firstBan.FormatBanMessage(_cfg, _loc);
|
||||
return (ConnectionDenyReason.Ban, message, bans);
|
||||
}
|
||||
|
||||
if (_cfg.GetCVar(CCVars.WhitelistEnabled))
|
||||
{
|
||||
var min = _cfg.GetCVar(CCVars.WhitelistMinPlayers);
|
||||
@@ -195,6 +231,11 @@ namespace Content.Server.Connection
|
||||
return null;
|
||||
}
|
||||
|
||||
private bool HasTemporaryBypass(NetUserId user)
|
||||
{
|
||||
return _temporaryBypasses.TryGetValue(user, out var time) && time > _gameTiming.RealTime;
|
||||
}
|
||||
|
||||
private async Task<NetUserId?> AssignUserIdCallback(string name)
|
||||
{
|
||||
if (!_cfg.GetCVar(CCVars.GamePersistGuests))
|
||||
|
||||
60
Content.Server/Connection/GrantConnectBypassCommand.cs
Normal file
60
Content.Server/Connection/GrantConnectBypassCommand.cs
Normal file
@@ -0,0 +1,60 @@
|
||||
using Content.Server.Administration;
|
||||
using Content.Shared.Administration;
|
||||
using Robust.Shared.Console;
|
||||
|
||||
namespace Content.Server.Connection;
|
||||
|
||||
[AdminCommand(AdminFlags.Admin)]
|
||||
public sealed class GrantConnectBypassCommand : LocalizedCommands
|
||||
{
|
||||
private static readonly TimeSpan DefaultDuration = TimeSpan.FromHours(1);
|
||||
|
||||
[Dependency] private readonly IPlayerLocator _playerLocator = default!;
|
||||
[Dependency] private readonly IConnectionManager _connectionManager = default!;
|
||||
|
||||
public override string Command => "grant_connect_bypass";
|
||||
|
||||
public override async void Execute(IConsoleShell shell, string argStr, string[] args)
|
||||
{
|
||||
if (args.Length is not (1 or 2))
|
||||
{
|
||||
shell.WriteError(Loc.GetString("cmd-grant_connect_bypass-invalid-args"));
|
||||
return;
|
||||
}
|
||||
|
||||
var argPlayer = args[0];
|
||||
var info = await _playerLocator.LookupIdByNameOrIdAsync(argPlayer);
|
||||
if (info == null)
|
||||
{
|
||||
shell.WriteError(Loc.GetString("cmd-grant_connect_bypass-unknown-user", ("user", argPlayer)));
|
||||
return;
|
||||
}
|
||||
|
||||
var duration = DefaultDuration;
|
||||
if (args.Length > 1)
|
||||
{
|
||||
var argDuration = args[2];
|
||||
if (!uint.TryParse(argDuration, out var minutes))
|
||||
{
|
||||
shell.WriteLine(Loc.GetString("cmd-grant_connect_bypass-invalid-duration", ("duration", argDuration)));
|
||||
return;
|
||||
}
|
||||
|
||||
duration = TimeSpan.FromMinutes(minutes);
|
||||
}
|
||||
|
||||
_connectionManager.AddTemporaryConnectBypass(info.UserId, duration);
|
||||
shell.WriteLine(Loc.GetString("cmd-grant_connect_bypass-success", ("user", argPlayer)));
|
||||
}
|
||||
|
||||
public override CompletionResult GetCompletion(IConsoleShell shell, string[] args)
|
||||
{
|
||||
if (args.Length == 1)
|
||||
return CompletionResult.FromHint(Loc.GetString("cmd-grant_connect_bypass-arg-user"));
|
||||
|
||||
if (args.Length == 2)
|
||||
return CompletionResult.FromHint(Loc.GetString("cmd-grant_connect_bypass-arg-duration"));
|
||||
|
||||
return CompletionResult.Empty;
|
||||
}
|
||||
}
|
||||
@@ -5,6 +5,11 @@ namespace Content.Server.Damage.Components;
|
||||
[RegisterComponent, Access(typeof(DamagePopupSystem))]
|
||||
public sealed partial class DamagePopupComponent : Component
|
||||
{
|
||||
/// <summary>
|
||||
/// Bool that will be used to determine if the popup type can be changed with a left click.
|
||||
/// </summary>
|
||||
[DataField("allowTypeChange")] [ViewVariables(VVAccess.ReadWrite)]
|
||||
public bool AllowTypeChange = false;
|
||||
/// <summary>
|
||||
/// Enum that will be used to determine the type of damage popup displayed.
|
||||
/// </summary>
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
using System.Linq;
|
||||
using Content.Server.Damage.Components;
|
||||
using Content.Server.Popups;
|
||||
using Content.Shared.Damage;
|
||||
using Robust.Shared.Player;
|
||||
using Content.Shared.Interaction;
|
||||
|
||||
namespace Content.Server.Damage.Systems;
|
||||
|
||||
@@ -13,6 +14,7 @@ public sealed class DamagePopupSystem : EntitySystem
|
||||
{
|
||||
base.Initialize();
|
||||
SubscribeLocalEvent<DamagePopupComponent, DamageChangedEvent>(OnDamageChange);
|
||||
SubscribeLocalEvent<DamagePopupComponent, InteractHandEvent>(OnInteractHand);
|
||||
}
|
||||
|
||||
private void OnDamageChange(EntityUid uid, DamagePopupComponent component, DamageChangedEvent args)
|
||||
@@ -33,4 +35,20 @@ public sealed class DamagePopupSystem : EntitySystem
|
||||
_popupSystem.PopupEntity(msg, uid);
|
||||
}
|
||||
}
|
||||
|
||||
private void OnInteractHand(EntityUid uid, DamagePopupComponent component, InteractHandEvent args)
|
||||
{
|
||||
if (component.AllowTypeChange)
|
||||
{
|
||||
if (component.Type == Enum.GetValues(typeof(DamagePopupType)).Cast<DamagePopupType>().Last())
|
||||
{
|
||||
component.Type = Enum.GetValues(typeof(DamagePopupType)).Cast<DamagePopupType>().First();
|
||||
}
|
||||
else
|
||||
{
|
||||
component.Type = (DamagePopupType) (int) component.Type + 1;
|
||||
}
|
||||
_popupSystem.PopupEntity("Target set to type: " + component.Type.ToString(), uid);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -299,7 +299,12 @@ public sealed class DisposalUnitSystem : SharedDisposalUnitSystem
|
||||
var canInsert = CanInsert(uid, component, args.Thrown);
|
||||
var randDouble = _robustRandom.NextDouble();
|
||||
|
||||
if (!canInsert || randDouble > 0.75)
|
||||
if (!canInsert)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (randDouble > 0.75)
|
||||
{
|
||||
_audioSystem.PlayPvs(component.MissSound, uid);
|
||||
|
||||
|
||||
@@ -143,6 +143,9 @@ public sealed partial class PuddleSystem
|
||||
if (Openable.IsClosed(entity.Owner))
|
||||
return;
|
||||
|
||||
if (!entity.Comp.SpillWhenThrown)
|
||||
return;
|
||||
|
||||
if (args.User != null)
|
||||
{
|
||||
_adminLogger.Add(LogType.Landed,
|
||||
|
||||
@@ -217,7 +217,8 @@ namespace Content.Server.GameTicking
|
||||
Loc.GetString(
|
||||
"latejoin-arrival-announcement",
|
||||
("character", MetaData(mob).EntityName),
|
||||
("job", CultureInfo.CurrentCulture.TextInfo.ToTitleCase(jobName))
|
||||
("job", CultureInfo.CurrentCulture.TextInfo.ToTitleCase(jobName)),
|
||||
("gender", character.Gender) // CrystallPunk-LastnameGender
|
||||
), Loc.GetString("latejoin-arrival-sender"),
|
||||
playDefaultSound: false);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
using Content.Shared.Whitelist;
|
||||
|
||||
namespace Content.Server.GameTicking.Rules.VariationPass.Components;
|
||||
|
||||
/// <summary>
|
||||
/// Handles cutting a random wire on random devices around the station.
|
||||
/// </summary>
|
||||
[RegisterComponent]
|
||||
public sealed partial class CutWireVariationPassComponent : Component
|
||||
{
|
||||
/// <summary>
|
||||
/// Blacklist of hackable entities that should not be chosen to
|
||||
/// have wires cut.
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public EntityWhitelist Blacklist = new();
|
||||
|
||||
/// <summary>
|
||||
/// Chance for an individual wire to be cut.
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public float WireCutChance = 0.05f;
|
||||
|
||||
/// <summary>
|
||||
/// Maximum number of wires that can be cut stationwide.
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public int MaxWiresCut = 10;
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
using Content.Server.GameTicking.Rules.VariationPass.Components;
|
||||
using Content.Server.Wires;
|
||||
using Robust.Shared.Random;
|
||||
|
||||
namespace Content.Server.GameTicking.Rules.VariationPass;
|
||||
|
||||
/// <summary>
|
||||
/// Handles cutting a random wire on random devices around the station.
|
||||
/// This system identifies target devices and adds <see cref="CutWireOnMapInitComponent"/> to them.
|
||||
/// The actual wire cutting is handled by <see cref="CutWireOnMapInitSystem"/>.
|
||||
/// </summary>
|
||||
public sealed class CutWireVariationPassSystem : VariationPassSystem<CutWireVariationPassComponent>
|
||||
{
|
||||
protected override void ApplyVariation(Entity<CutWireVariationPassComponent> ent, ref StationVariationPassEvent args)
|
||||
{
|
||||
var wiresCut = 0;
|
||||
var query = AllEntityQuery<WiresComponent, TransformComponent>();
|
||||
while (query.MoveNext(out var uid, out _, out var transform))
|
||||
{
|
||||
// Ignore if not part of the station
|
||||
if (!IsMemberOfStation((uid, transform), ref args))
|
||||
continue;
|
||||
|
||||
// Check against blacklist
|
||||
if (ent.Comp.Blacklist.IsValid(uid))
|
||||
continue;
|
||||
|
||||
if (Random.Prob(ent.Comp.WireCutChance))
|
||||
{
|
||||
EnsureComp<CutWireOnMapInitComponent>(uid);
|
||||
wiresCut++;
|
||||
|
||||
// Limit max wires cut
|
||||
if (wiresCut >= ent.Comp.MaxWiresCut)
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -249,7 +249,7 @@ public sealed class ZombieRuleSystem : GameRuleSystem<ZombieRuleComponent>
|
||||
_playerManager.Sessions,
|
||||
component.PatientZeroPrototypeId,
|
||||
includeAllJobs: false,
|
||||
customExcludeCondition: player => HasComp<ZombieImmuneComponent>(player) || HasComp<InitialInfectedExemptComponent>(player)
|
||||
customExcludeCondition: player => HasComp<ZombieImmuneComponent>(player) || HasComp<InitialInfectedExemptComponent>(player)
|
||||
);
|
||||
|
||||
//And get all players, excluding ZombieImmune and roles with CanBeAntag = False - to fill any leftover initial infected slots
|
||||
@@ -259,7 +259,7 @@ public sealed class ZombieRuleSystem : GameRuleSystem<ZombieRuleComponent>
|
||||
acceptableAntags: Shared.Antag.AntagAcceptability.All,
|
||||
includeAllJobs: false ,
|
||||
ignorePreferences: true,
|
||||
customExcludeCondition: HasComp<ZombieImmuneComponent>
|
||||
customExcludeCondition: HasComp<ZombieImmuneComponent>
|
||||
);
|
||||
|
||||
//If there are no players to choose, abort
|
||||
@@ -293,6 +293,7 @@ public sealed class ZombieRuleSystem : GameRuleSystem<ZombieRuleComponent>
|
||||
|
||||
//Add the role to the mind silently (to avoid repeating job assignment)
|
||||
_roles.MindAddRole(mind, new InitialInfectedRoleComponent { PrototypeId = component.PatientZeroPrototypeId }, silent: true);
|
||||
EnsureComp<InitialInfectedComponent>(entity);
|
||||
|
||||
//Add the zombie components and grace period
|
||||
var pending = EnsureComp<PendingZombieComponent>(entity);
|
||||
|
||||
@@ -1,36 +1,23 @@
|
||||
using Content.Shared.Examine;
|
||||
using Content.Shared.Humanoid;
|
||||
using Content.Shared.Humanoid.Markings;
|
||||
using Content.Shared.Humanoid.Prototypes;
|
||||
using Content.Shared.IdentityManagement;
|
||||
using Content.Shared.Preferences;
|
||||
using Content.Shared.Verbs;
|
||||
using Robust.Shared.GameObjects.Components.Localization;
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
namespace Content.Server.Humanoid;
|
||||
|
||||
public sealed partial class HumanoidAppearanceSystem : SharedHumanoidAppearanceSystem
|
||||
{
|
||||
[Dependency] private readonly MarkingManager _markingManager = default!;
|
||||
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
|
||||
SubscribeLocalEvent<HumanoidAppearanceComponent, HumanoidMarkingModifierMarkingSetMessage>(OnMarkingsSet);
|
||||
SubscribeLocalEvent<HumanoidAppearanceComponent, HumanoidMarkingModifierBaseLayersSetMessage>(OnBaseLayersSet);
|
||||
SubscribeLocalEvent<HumanoidAppearanceComponent, GetVerbsEvent<Verb>>(OnVerbsRequest);
|
||||
SubscribeLocalEvent<HumanoidAppearanceComponent, ExaminedEvent>(OnExamined);
|
||||
}
|
||||
|
||||
private void OnExamined(EntityUid uid, HumanoidAppearanceComponent component, ExaminedEvent args)
|
||||
{
|
||||
var identity = Identity.Entity(uid, EntityManager);
|
||||
var species = GetSpeciesRepresentation(component.Species).ToLower();
|
||||
var age = GetAgeRepresentation(component.Species, component.Age);
|
||||
|
||||
args.PushText(Loc.GetString("humanoid-appearance-component-examine", ("user", identity), ("age", age), ("species", species)));
|
||||
}
|
||||
|
||||
// this was done enough times that it only made sense to do it here
|
||||
@@ -164,42 +151,4 @@ public sealed partial class HumanoidAppearanceSystem : SharedHumanoidAppearanceS
|
||||
|
||||
Dirty(uid, humanoid);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Takes ID of the species prototype, returns UI-friendly name of the species.
|
||||
/// </summary>
|
||||
public string GetSpeciesRepresentation(string speciesId)
|
||||
{
|
||||
if (_prototypeManager.TryIndex<SpeciesPrototype>(speciesId, out var species))
|
||||
{
|
||||
return Loc.GetString(species.Name);
|
||||
}
|
||||
else
|
||||
{
|
||||
return Loc.GetString("humanoid-appearance-component-unknown-species");
|
||||
}
|
||||
}
|
||||
|
||||
public string GetAgeRepresentation(string species, int age)
|
||||
{
|
||||
_prototypeManager.TryIndex<SpeciesPrototype>(species, out var speciesPrototype);
|
||||
|
||||
if (speciesPrototype == null)
|
||||
{
|
||||
Log.Error("Tried to get age representation of species that couldn't be indexed: " + species);
|
||||
return Loc.GetString("identity-age-young");
|
||||
}
|
||||
|
||||
if (age < speciesPrototype.YoungAge)
|
||||
{
|
||||
return Loc.GetString("identity-age-young");
|
||||
}
|
||||
|
||||
if (age < speciesPrototype.OldAge)
|
||||
{
|
||||
return Loc.GetString("identity-age-middle-aged");
|
||||
}
|
||||
|
||||
return Loc.GetString("identity-age-old");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -49,6 +49,12 @@ public sealed class HealthAnalyzerSystem : EntitySystem
|
||||
if (component.ScannedEntity is not {} patient)
|
||||
continue;
|
||||
|
||||
if (Deleted(patient))
|
||||
{
|
||||
StopAnalyzingEntity((uid, component), patient);
|
||||
continue;
|
||||
}
|
||||
|
||||
component.NextUpdate = _timing.CurTime + component.UpdateInterval;
|
||||
|
||||
//Get distance between health analyzer and the scanned entity
|
||||
|
||||
@@ -33,6 +33,7 @@ public sealed class SuitSensorSystem : EntitySystem
|
||||
[Dependency] private readonly SharedTransformSystem _transform = default!;
|
||||
[Dependency] private readonly StationSystem _stationSystem = default!;
|
||||
[Dependency] private readonly SingletonDeviceNetServerSystem _singletonServerSystem = default!;
|
||||
[Dependency] private readonly MobThresholdSystem _mobThresholdSystem = default!;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
@@ -344,6 +345,11 @@ public sealed class SuitSensorSystem : EntitySystem
|
||||
if (TryComp<DamageableComponent>(sensor.User.Value, out var damageable))
|
||||
totalDamage = damageable.TotalDamage.Int();
|
||||
|
||||
// Get mob total damage crit threshold
|
||||
int? totalDamageThreshold = null;
|
||||
if (_mobThresholdSystem.TryGetThresholdForState(sensor.User.Value, Shared.Mobs.MobState.Critical, out var critThreshold))
|
||||
totalDamageThreshold = critThreshold.Value.Int();
|
||||
|
||||
// finally, form suit sensor status
|
||||
var status = new SuitSensorStatus(GetNetEntity(uid), userName, userJob, userJobIcon, userJobDepartments);
|
||||
switch (sensor.Mode)
|
||||
@@ -354,10 +360,12 @@ public sealed class SuitSensorSystem : EntitySystem
|
||||
case SuitSensorMode.SensorVitals:
|
||||
status.IsAlive = isAlive;
|
||||
status.TotalDamage = totalDamage;
|
||||
status.TotalDamageThreshold = totalDamageThreshold;
|
||||
break;
|
||||
case SuitSensorMode.SensorCords:
|
||||
status.IsAlive = isAlive;
|
||||
status.TotalDamage = totalDamage;
|
||||
status.TotalDamageThreshold = totalDamageThreshold;
|
||||
EntityCoordinates coordinates;
|
||||
var xformQuery = GetEntityQuery<TransformComponent>();
|
||||
|
||||
@@ -402,6 +410,8 @@ public sealed class SuitSensorSystem : EntitySystem
|
||||
|
||||
if (status.TotalDamage != null)
|
||||
payload.Add(SuitSensorConstants.NET_TOTAL_DAMAGE, status.TotalDamage);
|
||||
if (status.TotalDamageThreshold != null)
|
||||
payload.Add(SuitSensorConstants.NET_TOTAL_DAMAGE_THRESHOLD, status.TotalDamageThreshold);
|
||||
if (status.Coordinates != null)
|
||||
payload.Add(SuitSensorConstants.NET_COORDINATES, status.Coordinates);
|
||||
|
||||
@@ -429,12 +439,14 @@ public sealed class SuitSensorSystem : EntitySystem
|
||||
|
||||
// try get total damage and cords (optionals)
|
||||
payload.TryGetValue(SuitSensorConstants.NET_TOTAL_DAMAGE, out int? totalDamage);
|
||||
payload.TryGetValue(SuitSensorConstants.NET_TOTAL_DAMAGE_THRESHOLD, out int? totalDamageThreshold);
|
||||
payload.TryGetValue(SuitSensorConstants.NET_COORDINATES, out NetCoordinates? coords);
|
||||
|
||||
var status = new SuitSensorStatus(suitSensorUid, name, job, jobIcon, jobDepartments)
|
||||
{
|
||||
IsAlive = isAlive.Value,
|
||||
TotalDamage = totalDamage,
|
||||
TotalDamageThreshold = totalDamageThreshold,
|
||||
Coordinates = coords,
|
||||
};
|
||||
return status;
|
||||
|
||||
@@ -264,6 +264,11 @@ public sealed class ThrusterSystem : EntitySystem
|
||||
return;
|
||||
}
|
||||
|
||||
if (TryComp<ApcPowerReceiverComponent>(uid, out var apcPower))
|
||||
{
|
||||
apcPower.NeedsPower = true;
|
||||
}
|
||||
|
||||
component.IsOn = true;
|
||||
|
||||
if (!EntityManager.TryGetComponent(xform.GridUid, out ShuttleComponent? shuttleComponent))
|
||||
@@ -366,6 +371,11 @@ public sealed class ThrusterSystem : EntitySystem
|
||||
if (!EntityManager.TryGetComponent(gridId, out ShuttleComponent? shuttleComponent))
|
||||
return;
|
||||
|
||||
if (TryComp<ApcPowerReceiverComponent>(uid, out var apcPower))
|
||||
{
|
||||
apcPower.NeedsPower = false;
|
||||
}
|
||||
|
||||
// Logger.DebugS("thruster", $"Disabled thruster {uid}");
|
||||
|
||||
switch (component.Type)
|
||||
|
||||
@@ -1,40 +1,54 @@
|
||||
using System.Threading;
|
||||
using Robust.Shared.Prototypes;
|
||||
using Robust.Shared.Random;
|
||||
using Robust.Shared.Serialization;
|
||||
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype.List;
|
||||
|
||||
namespace Content.Server.Spawners.Components
|
||||
namespace Content.Server.Spawners.Components;
|
||||
|
||||
/// <summary>
|
||||
/// Spawns entities at a set interval.
|
||||
/// Can configure the set of entities, spawn timing, spawn chance,
|
||||
/// and min/max number of entities to spawn.
|
||||
/// </summary>
|
||||
[RegisterComponent]
|
||||
public sealed partial class TimedSpawnerComponent : Component, ISerializationHooks
|
||||
{
|
||||
[RegisterComponent]
|
||||
public sealed partial class TimedSpawnerComponent : Component, ISerializationHooks
|
||||
/// <summary>
|
||||
/// List of entities that can be spawned by this component. One will be randomly
|
||||
/// chosen for each entity spawned. When multiple entities are spawned at once,
|
||||
/// each will be randomly chosen separately.
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public List<EntProtoId> Prototypes = [];
|
||||
|
||||
/// <summary>
|
||||
/// Chance of an entity being spawned at the end of each interval.
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public float Chance = 1.0f;
|
||||
|
||||
/// <summary>
|
||||
/// Length of the interval between spawn attempts.
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public int IntervalSeconds = 60;
|
||||
|
||||
/// <summary>
|
||||
/// The minimum number of entities that can be spawned when an interval elapses.
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public int MinimumEntitiesSpawned = 1;
|
||||
|
||||
/// <summary>
|
||||
/// The maximum number of entities that can be spawned when an interval elapses.
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public int MaximumEntitiesSpawned = 1;
|
||||
|
||||
public CancellationTokenSource? TokenSource;
|
||||
|
||||
void ISerializationHooks.AfterDeserialization()
|
||||
{
|
||||
[ViewVariables(VVAccess.ReadWrite)]
|
||||
[DataField("prototypes", customTypeSerializer:typeof(PrototypeIdListSerializer<EntityPrototype>))]
|
||||
public List<string> Prototypes { get; set; } = new();
|
||||
|
||||
[ViewVariables(VVAccess.ReadWrite)]
|
||||
[DataField("chance")]
|
||||
public float Chance { get; set; } = 1.0f;
|
||||
|
||||
[ViewVariables(VVAccess.ReadWrite)]
|
||||
[DataField("intervalSeconds")]
|
||||
public int IntervalSeconds { get; set; } = 60;
|
||||
|
||||
[ViewVariables(VVAccess.ReadWrite)]
|
||||
[DataField("MinimumEntitiesSpawned")]
|
||||
public int MinimumEntitiesSpawned { get; set; } = 1;
|
||||
|
||||
[ViewVariables(VVAccess.ReadWrite)]
|
||||
[DataField("MaximumEntitiesSpawned")]
|
||||
public int MaximumEntitiesSpawned { get; set; } = 1;
|
||||
|
||||
public CancellationTokenSource? TokenSource;
|
||||
|
||||
void ISerializationHooks.AfterDeserialization()
|
||||
{
|
||||
if (MinimumEntitiesSpawned > MaximumEntitiesSpawned)
|
||||
throw new ArgumentException("MaximumEntitiesSpawned can't be lower than MinimumEntitiesSpawned!");
|
||||
}
|
||||
if (MinimumEntitiesSpawned > MaximumEntitiesSpawned)
|
||||
throw new ArgumentException("MaximumEntitiesSpawned can't be lower than MinimumEntitiesSpawned!");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
using System.Linq;
|
||||
using Content.Server.GameTicking.Rules.Components;
|
||||
using Content.Server.Silicons.Laws;
|
||||
using Content.Server.Station.Components;
|
||||
@@ -143,6 +144,24 @@ public sealed class IonStormRule : StationEventSystem<IonStormRuleComponent>
|
||||
});
|
||||
}
|
||||
|
||||
// sets all unobfuscated laws' indentifier in order from highest to lowest priority
|
||||
// This could technically override the Obfuscation from the code above, but it seems unlikely enough to basically never happen
|
||||
int orderDeduction = -1;
|
||||
|
||||
for (int i = 0; i < laws.Laws.Count; i++)
|
||||
{
|
||||
string notNullIdentifier = laws.Laws[i].LawIdentifierOverride ?? (i - orderDeduction).ToString();
|
||||
|
||||
if (notNullIdentifier.Any(char.IsSymbol))
|
||||
{
|
||||
orderDeduction += 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
laws.Laws[i].LawIdentifierOverride = (i - orderDeduction).ToString();
|
||||
}
|
||||
}
|
||||
|
||||
_adminLogger.Add(LogType.Mind, LogImpact.High, $"{ToPrettyString(ent):silicon} had its laws changed by an ion storm to {laws.LoggingString()}");
|
||||
|
||||
// laws unique to this silicon, dont use station laws anymore
|
||||
|
||||
10
Content.Server/Wires/CutWireOnMapInitComponent.cs
Normal file
10
Content.Server/Wires/CutWireOnMapInitComponent.cs
Normal file
@@ -0,0 +1,10 @@
|
||||
namespace Content.Server.Wires;
|
||||
|
||||
/// <summary>
|
||||
/// Picks a random wire on the entity's <see cref="WireComponent"/> and cuts it.
|
||||
/// Runs at MapInit and removes itself afterwards.
|
||||
/// </summary>
|
||||
[RegisterComponent]
|
||||
public sealed partial class CutWireOnMapInitComponent : Component
|
||||
{
|
||||
}
|
||||
34
Content.Server/Wires/CutWireOnMapInitSystem.cs
Normal file
34
Content.Server/Wires/CutWireOnMapInitSystem.cs
Normal file
@@ -0,0 +1,34 @@
|
||||
using Robust.Shared.Random;
|
||||
|
||||
namespace Content.Server.Wires;
|
||||
|
||||
/// <summary>
|
||||
/// Handles cutting a random wire on devices that have <see cref="CutWireOnMapInitComponent"/>.
|
||||
/// </summary>
|
||||
public sealed partial class CutWireOnMapInitSystem : EntitySystem
|
||||
{
|
||||
[Dependency] private readonly IRobustRandom _random = default!;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
|
||||
SubscribeLocalEvent<CutWireOnMapInitComponent, MapInitEvent>(OnMapInit, after: [typeof(WiresSystem)]);
|
||||
}
|
||||
|
||||
private void OnMapInit(Entity<CutWireOnMapInitComponent> entity, ref MapInitEvent args)
|
||||
{
|
||||
if (TryComp<WiresComponent>(entity, out var panel) && panel.WiresList.Count > 0)
|
||||
{
|
||||
// Pick a random wire
|
||||
var targetWire = _random.Pick(panel.WiresList);
|
||||
|
||||
// Cut the wire
|
||||
if (targetWire.Action == null || targetWire.Action.Cut(EntityUid.Invalid, targetWire))
|
||||
targetWire.IsCut = true;
|
||||
}
|
||||
|
||||
// Our work here is done
|
||||
RemCompDeferred(entity, entity.Comp);
|
||||
}
|
||||
}
|
||||
@@ -318,6 +318,7 @@ public sealed class AccessReaderSystem : EntitySystem
|
||||
{
|
||||
component.AccessLists.Add(new HashSet<ProtoId<AccessLevelPrototype>>(){access});
|
||||
}
|
||||
Dirty(uid, component);
|
||||
RaiseLocalEvent(uid, new AccessReaderConfigurationChangedEvent());
|
||||
}
|
||||
|
||||
|
||||
@@ -80,6 +80,10 @@ public abstract class AlertsSystem : EntitySystem
|
||||
/// <param name="showCooldown">if true, the cooldown will be visibly shown over the alert icon</param>
|
||||
public void ShowAlert(EntityUid euid, AlertType alertType, short? severity = null, (TimeSpan, TimeSpan)? cooldown = null, bool autoRemove = false, bool showCooldown = true )
|
||||
{
|
||||
// This should be handled as part of networking.
|
||||
if (_timing.ApplyingState)
|
||||
return;
|
||||
|
||||
if (!TryComp(euid, out AlertsComponent? alertsComponent))
|
||||
return;
|
||||
|
||||
@@ -148,6 +152,9 @@ public abstract class AlertsSystem : EntitySystem
|
||||
/// </summary>
|
||||
public void ClearAlert(EntityUid euid, AlertType alertType)
|
||||
{
|
||||
if (_timing.ApplyingState)
|
||||
return;
|
||||
|
||||
if (!EntityManager.TryGetComponent(euid, out AlertsComponent? alertsComponent))
|
||||
return;
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@ using Content.Shared.DragDrop;
|
||||
using Content.Shared.GameTicking;
|
||||
using Content.Shared.Mind;
|
||||
using Content.Shared.Mind.Components;
|
||||
using Content.Shared.Mobs.Systems;
|
||||
using Robust.Shared.Configuration;
|
||||
using Robust.Shared.Containers;
|
||||
using Robust.Shared.Map;
|
||||
@@ -22,6 +23,7 @@ public abstract class SharedCryostorageSystem : EntitySystem
|
||||
[Dependency] private readonly IMapManager _mapManager = default!;
|
||||
[Dependency] private readonly SharedAppearanceSystem _appearance = default!;
|
||||
[Dependency] protected readonly SharedMindSystem Mind = default!;
|
||||
[Dependency] private readonly MobStateSystem _mobState = default!;
|
||||
|
||||
protected EntityUid? PausedMap { get; private set; }
|
||||
|
||||
@@ -81,6 +83,12 @@ public abstract class SharedCryostorageSystem : EntitySystem
|
||||
if (args.Container.ID != comp.ContainerId)
|
||||
return;
|
||||
|
||||
if (_mobState.IsIncapacitated(args.EntityUid))
|
||||
{
|
||||
args.Cancel();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!TryComp<MindContainerComponent>(args.EntityUid, out var mindContainer))
|
||||
{
|
||||
args.Cancel();
|
||||
|
||||
@@ -543,8 +543,8 @@ namespace Content.Shared.CCVar
|
||||
* Console
|
||||
*/
|
||||
|
||||
public static readonly CVarDef<bool>
|
||||
ConsoleLoginLocal = CVarDef.Create("console.loginlocal", true, CVar.ARCHIVE | CVar.SERVERONLY);
|
||||
public static readonly CVarDef<bool> ConsoleLoginLocal =
|
||||
CVarDef.Create("console.loginlocal", true, CVar.ARCHIVE | CVar.SERVERONLY);
|
||||
|
||||
/// <summary>
|
||||
/// Automatically log in the given user as host, equivalent to the <c>promotehost</c> command.
|
||||
@@ -726,7 +726,7 @@ namespace Content.Shared.CCVar
|
||||
|
||||
public static readonly CVarDef<bool> CombatModeIndicatorsPointShow =
|
||||
CVarDef.Create("hud.combat_mode_indicators_point_show", true, CVar.ARCHIVE | CVar.CLIENTONLY);
|
||||
|
||||
|
||||
public static readonly CVarDef<bool> LoocAboveHeadShow =
|
||||
CVarDef.Create("hud.show_looc_above_head", true, CVar.ARCHIVE | CVar.CLIENTONLY);
|
||||
|
||||
@@ -836,6 +836,7 @@ namespace Content.Shared.CCVar
|
||||
|
||||
/// <summary>
|
||||
/// Should the ban details in admin channel include PII? (IP, HWID, etc)
|
||||
/// </summary>
|
||||
public static readonly CVarDef<bool> AdminShowPIIOnBan =
|
||||
CVarDef.Create("admin.show_pii_onban", false, CVar.SERVERONLY);
|
||||
|
||||
@@ -1224,6 +1225,9 @@ namespace Content.Shared.CCVar
|
||||
/// </summary>
|
||||
public static readonly CVarDef<bool> OocEnableDuringRound =
|
||||
CVarDef.Create("ooc.enable_during_round", false, CVar.NOTIFY | CVar.REPLICATED | CVar.SERVER);
|
||||
|
||||
public static readonly CVarDef<bool> ShowOocPatronColor =
|
||||
CVarDef.Create("ooc.show_ooc_patron_color", true, CVar.ARCHIVE | CVar.REPLICATED | CVar.CLIENT);
|
||||
|
||||
/*
|
||||
* LOOC
|
||||
@@ -1696,6 +1700,12 @@ namespace Content.Shared.CCVar
|
||||
public static readonly CVarDef<bool> RestrictedNames =
|
||||
CVarDef.Create("ic.restricted_names", true, CVar.SERVER | CVar.REPLICATED);
|
||||
|
||||
/// <summary>
|
||||
/// Regis for name validation if enabled RestrictedNames
|
||||
/// </summary>
|
||||
public static readonly CVarDef<string> RestrictedNameRegex =
|
||||
CVarDef.Create("ic.restricted_name_regex", @"[^А-Я,а-я,A-Z,a-z,0-9, -]", CVar.SERVER | CVar.REPLICATED);
|
||||
|
||||
/// <summary>
|
||||
/// Allows flavor text (character descriptions)
|
||||
/// </summary>
|
||||
|
||||
@@ -32,16 +32,30 @@ public sealed partial class CargoBountyConsoleComponent : Component
|
||||
/// </summary>
|
||||
[DataField("printSound")]
|
||||
public SoundSpecifier PrintSound = new SoundPathSpecifier("/Audio/Machines/printer.ogg");
|
||||
|
||||
/// <summary>
|
||||
/// The sound made when the bounty is skipped.
|
||||
/// </summary>
|
||||
[DataField("skipSound")]
|
||||
public SoundSpecifier SkipSound = new SoundPathSpecifier("/Audio/Effects/Cargo/ping.ogg");
|
||||
|
||||
/// <summary>
|
||||
/// The sound made when bounty skipping is denied due to lacking access.
|
||||
/// </summary>
|
||||
[DataField("denySound")]
|
||||
public SoundSpecifier DenySound = new SoundPathSpecifier("/Audio/Effects/Cargo/buzz_two.ogg");
|
||||
}
|
||||
|
||||
[NetSerializable, Serializable]
|
||||
public sealed class CargoBountyConsoleState : BoundUserInterfaceState
|
||||
{
|
||||
public List<CargoBountyData> Bounties;
|
||||
public TimeSpan UntilNextSkip;
|
||||
|
||||
public CargoBountyConsoleState(List<CargoBountyData> bounties)
|
||||
public CargoBountyConsoleState(List<CargoBountyData> bounties, TimeSpan untilNextSkip)
|
||||
{
|
||||
Bounties = bounties;
|
||||
UntilNextSkip = untilNextSkip;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -55,3 +69,14 @@ public sealed class BountyPrintLabelMessage : BoundUserInterfaceMessage
|
||||
BountyId = bountyId;
|
||||
}
|
||||
}
|
||||
|
||||
[Serializable, NetSerializable]
|
||||
public sealed class BountySkipMessage : BoundUserInterfaceMessage
|
||||
{
|
||||
public string BountyId;
|
||||
|
||||
public BountySkipMessage(string bountyId)
|
||||
{
|
||||
BountyId = bountyId;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -91,7 +91,7 @@ public abstract class ClothingSystem : EntitySystem
|
||||
|
||||
private void ToggleVisualLayer(EntityUid equipee, HumanoidVisualLayers layer, string tag)
|
||||
{
|
||||
InventorySystem.InventorySlotEnumerator enumerator = _invSystem.GetSlotEnumerator(equipee);
|
||||
InventorySystem.InventorySlotEnumerator enumerator = _invSystem.GetSlotEnumerator(equipee, SlotFlags.HEAD ^ SlotFlags.MASK);
|
||||
bool shouldLayerShow = true;
|
||||
|
||||
while (enumerator.NextItem(out EntityUid item))
|
||||
@@ -164,7 +164,7 @@ public abstract class ClothingSystem : EntitySystem
|
||||
{
|
||||
if (args.Handled || args.Cancelled || args.Target is not { } target)
|
||||
return;
|
||||
args.Handled = _invSystem.TryEquip(args.User, target, ent, args.Slot, clothing: ent.Comp, predicted: true, checkDoafter: false);
|
||||
args.Handled = _invSystem.TryEquip(args.User, target, ent, args.Slot, clothing: ent.Comp, predicted: true, checkDoafter: false);
|
||||
}
|
||||
|
||||
private void OnUnequipDoAfter(Entity<ClothingComponent> ent, ref ClothingUnequipDoAfterEvent args)
|
||||
|
||||
@@ -11,7 +11,7 @@ namespace Content.Shared.Communications
|
||||
public sealed class CommunicationsConsoleInterfaceState : BoundUserInterfaceState
|
||||
{
|
||||
public readonly bool CanAnnounce;
|
||||
public readonly bool CanBroadcast;
|
||||
public readonly bool CanBroadcast = true;
|
||||
public readonly bool CanCall;
|
||||
public readonly TimeSpan? ExpectedCountdownEnd;
|
||||
public readonly bool CountdownStarted;
|
||||
|
||||
@@ -29,4 +29,10 @@ public sealed partial class SpillableComponent : Component
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public FixedPoint2 MaxMeleeSpillAmount = FixedPoint2.New(20);
|
||||
|
||||
/// <summary>
|
||||
/// Should this item be spilled when thrown?
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public bool SpillWhenThrown = true;
|
||||
}
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
using System.Linq;
|
||||
using Content.Shared.Decals;
|
||||
using Content.Shared.Examine;
|
||||
using Content.Shared.Humanoid.Markings;
|
||||
using Content.Shared.Humanoid.Prototypes;
|
||||
using Content.Shared.IdentityManagement;
|
||||
using Content.Shared.Preferences;
|
||||
using Robust.Shared.GameObjects.Components.Localization;
|
||||
using Robust.Shared.Network;
|
||||
@@ -21,7 +23,7 @@ namespace Content.Shared.Humanoid;
|
||||
public abstract class SharedHumanoidAppearanceSystem : EntitySystem
|
||||
{
|
||||
[Dependency] private readonly INetManager _netManager = default!;
|
||||
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
|
||||
[Dependency] private readonly IPrototypeManager _proto = default!;
|
||||
[Dependency] private readonly MarkingManager _markingManager = default!;
|
||||
|
||||
[ValidatePrototypeId<SpeciesPrototype>]
|
||||
@@ -30,7 +32,9 @@ public abstract class SharedHumanoidAppearanceSystem : EntitySystem
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
|
||||
SubscribeLocalEvent<HumanoidAppearanceComponent, ComponentInit>(OnInit);
|
||||
SubscribeLocalEvent<HumanoidAppearanceComponent, ExaminedEvent>(OnExamined);
|
||||
}
|
||||
|
||||
private void OnInit(EntityUid uid, HumanoidAppearanceComponent humanoid, ComponentInit args)
|
||||
@@ -41,7 +45,7 @@ public abstract class SharedHumanoidAppearanceSystem : EntitySystem
|
||||
}
|
||||
|
||||
if (string.IsNullOrEmpty(humanoid.Initial)
|
||||
|| !_prototypeManager.TryIndex(humanoid.Initial, out HumanoidProfilePrototype? startingSet))
|
||||
|| !_proto.TryIndex(humanoid.Initial, out HumanoidProfilePrototype? startingSet))
|
||||
{
|
||||
LoadProfile(uid, HumanoidCharacterProfile.DefaultWithSpecies(humanoid.Species), humanoid);
|
||||
return;
|
||||
@@ -56,6 +60,15 @@ public abstract class SharedHumanoidAppearanceSystem : EntitySystem
|
||||
LoadProfile(uid, startingSet.Profile, humanoid);
|
||||
}
|
||||
|
||||
private void OnExamined(EntityUid uid, HumanoidAppearanceComponent component, ExaminedEvent args)
|
||||
{
|
||||
var identity = Identity.Entity(uid, EntityManager);
|
||||
var species = GetSpeciesRepresentation(component.Species).ToLower();
|
||||
var age = GetAgeRepresentation(component.Species, component.Age);
|
||||
|
||||
args.PushText(Loc.GetString("humanoid-appearance-component-examine", ("user", identity), ("age", age), ("species", species)));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Toggles a humanoid's sprite layer visibility.
|
||||
/// </summary>
|
||||
@@ -136,7 +149,7 @@ public abstract class SharedHumanoidAppearanceSystem : EntitySystem
|
||||
/// <param name="humanoid">Humanoid component of the entity</param>
|
||||
public void SetSpecies(EntityUid uid, string species, bool sync = true, HumanoidAppearanceComponent? humanoid = null)
|
||||
{
|
||||
if (!Resolve(uid, ref humanoid) || !_prototypeManager.TryIndex<SpeciesPrototype>(species, out var prototype))
|
||||
if (!Resolve(uid, ref humanoid) || !_proto.TryIndex<SpeciesPrototype>(species, out var prototype))
|
||||
{
|
||||
return;
|
||||
}
|
||||
@@ -144,7 +157,7 @@ public abstract class SharedHumanoidAppearanceSystem : EntitySystem
|
||||
humanoid.Species = species;
|
||||
humanoid.MarkingSet.EnsureSpecies(species, humanoid.SkinColor, _markingManager);
|
||||
var oldMarkings = humanoid.MarkingSet.GetForwardEnumerator().ToList();
|
||||
humanoid.MarkingSet = new(oldMarkings, prototype.MarkingPoints, _markingManager, _prototypeManager);
|
||||
humanoid.MarkingSet = new(oldMarkings, prototype.MarkingPoints, _markingManager, _proto);
|
||||
|
||||
if (sync)
|
||||
Dirty(uid, humanoid);
|
||||
@@ -164,7 +177,7 @@ public abstract class SharedHumanoidAppearanceSystem : EntitySystem
|
||||
if (!Resolve(uid, ref humanoid))
|
||||
return;
|
||||
|
||||
if (!_prototypeManager.TryIndex<SpeciesPrototype>(humanoid.Species, out var species))
|
||||
if (!_proto.TryIndex<SpeciesPrototype>(humanoid.Species, out var species))
|
||||
{
|
||||
return;
|
||||
}
|
||||
@@ -288,24 +301,24 @@ public abstract class SharedHumanoidAppearanceSystem : EntitySystem
|
||||
|
||||
// Hair/facial hair - this may eventually be deprecated.
|
||||
// We need to ensure hair before applying it or coloring can try depend on markings that can be invalid
|
||||
var hairColor = _markingManager.MustMatchSkin(profile.Species, HumanoidVisualLayers.Hair, out var hairAlpha, _prototypeManager)
|
||||
var hairColor = _markingManager.MustMatchSkin(profile.Species, HumanoidVisualLayers.Hair, out var hairAlpha, _proto)
|
||||
? profile.Appearance.SkinColor.WithAlpha(hairAlpha) : profile.Appearance.HairColor;
|
||||
var facialHairColor = _markingManager.MustMatchSkin(profile.Species, HumanoidVisualLayers.FacialHair, out var facialHairAlpha, _prototypeManager)
|
||||
var facialHairColor = _markingManager.MustMatchSkin(profile.Species, HumanoidVisualLayers.FacialHair, out var facialHairAlpha, _proto)
|
||||
? profile.Appearance.SkinColor.WithAlpha(facialHairAlpha) : profile.Appearance.FacialHairColor;
|
||||
|
||||
if (_markingManager.Markings.TryGetValue(profile.Appearance.HairStyleId, out var hairPrototype) &&
|
||||
_markingManager.CanBeApplied(profile.Species, profile.Sex, hairPrototype, _prototypeManager))
|
||||
_markingManager.CanBeApplied(profile.Species, profile.Sex, hairPrototype, _proto))
|
||||
{
|
||||
AddMarking(uid, profile.Appearance.HairStyleId, hairColor, false);
|
||||
}
|
||||
|
||||
if (_markingManager.Markings.TryGetValue(profile.Appearance.FacialHairStyleId, out var facialHairPrototype) &&
|
||||
_markingManager.CanBeApplied(profile.Species, profile.Sex, facialHairPrototype, _prototypeManager))
|
||||
_markingManager.CanBeApplied(profile.Species, profile.Sex, facialHairPrototype, _proto))
|
||||
{
|
||||
AddMarking(uid, profile.Appearance.FacialHairStyleId, facialHairColor, false);
|
||||
}
|
||||
|
||||
humanoid.MarkingSet.EnsureSpecies(profile.Species, profile.Appearance.SkinColor, _markingManager, _prototypeManager);
|
||||
humanoid.MarkingSet.EnsureSpecies(profile.Species, profile.Appearance.SkinColor, _markingManager, _proto);
|
||||
|
||||
// Finally adding marking with forced colors
|
||||
foreach (var (marking, prototype) in markingFColored)
|
||||
@@ -398,4 +411,39 @@ public abstract class SharedHumanoidAppearanceSystem : EntitySystem
|
||||
if (sync)
|
||||
Dirty(uid, humanoid);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Takes ID of the species prototype, returns UI-friendly name of the species.
|
||||
/// </summary>
|
||||
public string GetSpeciesRepresentation(string speciesId)
|
||||
{
|
||||
if (_proto.TryIndex<SpeciesPrototype>(speciesId, out var species))
|
||||
{
|
||||
return Loc.GetString(species.Name);
|
||||
}
|
||||
|
||||
Log.Error("Tried to get representation of unknown species: {speciesId}");
|
||||
return Loc.GetString("humanoid-appearance-component-unknown-species");
|
||||
}
|
||||
|
||||
public string GetAgeRepresentation(string species, int age)
|
||||
{
|
||||
if (!_proto.TryIndex<SpeciesPrototype>(species, out var speciesPrototype))
|
||||
{
|
||||
Log.Error("Tried to get age representation of species that couldn't be indexed: " + species);
|
||||
return Loc.GetString("identity-age-young");
|
||||
}
|
||||
|
||||
if (age < speciesPrototype.YoungAge)
|
||||
{
|
||||
return Loc.GetString("identity-age-young");
|
||||
}
|
||||
|
||||
if (age < speciesPrototype.OldAge)
|
||||
{
|
||||
return Loc.GetString("identity-age-middle-aged");
|
||||
}
|
||||
|
||||
return Loc.GetString("identity-age-old");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -682,7 +682,7 @@ namespace Content.Shared.Interaction
|
||||
if (!inRange && popup && _gameTiming.IsFirstTimePredicted)
|
||||
{
|
||||
var message = Loc.GetString("interaction-system-user-interaction-cannot-reach");
|
||||
_popupSystem.PopupEntity(message, origin, origin);
|
||||
_popupSystem.PopupClient(message, origin, origin);
|
||||
}
|
||||
|
||||
return inRange;
|
||||
|
||||
@@ -278,7 +278,7 @@ public sealed class LockSystem : EntitySystem
|
||||
//CrystallPunk Lock System Adapt End
|
||||
}
|
||||
|
||||
private void OnEmagged(EntityUid uid, LockComponent component, ref GotEmaggedEvent args)
|
||||
private void OnEmagged(EntityUid uid, LockComponent component, ref GotEmaggedEvent args)
|
||||
{
|
||||
if (!component.Locked || !component.BreakOnEmag)
|
||||
return;
|
||||
|
||||
@@ -23,6 +23,8 @@ public sealed class SuitSensorStatus
|
||||
public List<string> JobDepartments;
|
||||
public bool IsAlive;
|
||||
public int? TotalDamage;
|
||||
public int? TotalDamageThreshold;
|
||||
public float? DamagePercentage => TotalDamageThreshold == null || TotalDamage == null ? null : TotalDamage / TotalDamageThreshold;
|
||||
public NetCoordinates? Coordinates;
|
||||
}
|
||||
|
||||
@@ -58,6 +60,7 @@ public static class SuitSensorConstants
|
||||
public const string NET_JOB_DEPARTMENTS = "jobDepartments";
|
||||
public const string NET_IS_ALIVE = "alive";
|
||||
public const string NET_TOTAL_DAMAGE = "vitals";
|
||||
public const string NET_TOTAL_DAMAGE_THRESHOLD = "vitalsThreshold";
|
||||
public const string NET_COORDINATES = "coords";
|
||||
public const string NET_SUIT_SENSOR_UID = "uid";
|
||||
|
||||
|
||||
@@ -420,7 +420,7 @@ namespace Content.Shared.Preferences
|
||||
|
||||
if (configManager.GetCVar(CCVars.RestrictedNames))
|
||||
{
|
||||
name = Regex.Replace(name, @"[^A-Z,a-z,0-9, -]", string.Empty);
|
||||
name = Regex.Replace(name, configManager.GetCVar(CCVars.RestrictedNameRegex), string.Empty);
|
||||
}
|
||||
|
||||
if (configManager.GetCVar(CCVars.ICNameCase))
|
||||
|
||||
@@ -98,16 +98,6 @@ public class RCDSystem : EntitySystem
|
||||
component.ProtoId = args.ProtoId;
|
||||
UpdateCachedPrototype(uid, component);
|
||||
Dirty(uid, component);
|
||||
|
||||
if (args.Session.AttachedEntity != null)
|
||||
{
|
||||
// Popup message
|
||||
var msg = (component.CachedPrototype.Prototype != null) ?
|
||||
Loc.GetString("rcd-component-change-build-mode", ("name", Loc.GetString(component.CachedPrototype.SetName))) :
|
||||
Loc.GetString("rcd-component-change-mode", ("mode", Loc.GetString(component.CachedPrototype.SetName)));
|
||||
|
||||
_popup.PopupClient(msg, uid, args.Session.AttachedEntity.Value);
|
||||
}
|
||||
}
|
||||
|
||||
private void OnExamine(EntityUid uid, RCDComponent component, ExaminedEvent args)
|
||||
@@ -118,9 +108,18 @@ public class RCDSystem : EntitySystem
|
||||
// Update cached prototype if required
|
||||
UpdateCachedPrototype(uid, component);
|
||||
|
||||
var msg = (component.CachedPrototype.Prototype != null) ?
|
||||
Loc.GetString("rcd-component-examine-build-details", ("name", Loc.GetString(component.CachedPrototype.SetName))) :
|
||||
Loc.GetString("rcd-component-examine-mode-details", ("mode", Loc.GetString(component.CachedPrototype.SetName)));
|
||||
var msg = Loc.GetString("rcd-component-examine-mode-details", ("mode", Loc.GetString(component.CachedPrototype.SetName)));
|
||||
|
||||
if (component.CachedPrototype.Mode == RcdMode.ConstructTile || component.CachedPrototype.Mode == RcdMode.ConstructObject)
|
||||
{
|
||||
var name = Loc.GetString(component.CachedPrototype.SetName);
|
||||
|
||||
if (component.CachedPrototype.Prototype != null &&
|
||||
_protoManager.TryIndex(component.CachedPrototype.Prototype, out var proto))
|
||||
name = proto.Name;
|
||||
|
||||
msg = Loc.GetString("rcd-component-examine-build-details", ("name", name));
|
||||
}
|
||||
|
||||
args.PushMarkup(msg);
|
||||
}
|
||||
@@ -206,7 +205,7 @@ public class RCDSystem : EntitySystem
|
||||
|
||||
// Try to start the do after
|
||||
var effect = Spawn(effectPrototype, mapGridData.Value.Location);
|
||||
var ev = new RCDDoAfterEvent(GetNetCoordinates(mapGridData.Value.Location), component.ProtoId, cost, EntityManager.GetNetEntity(effect));
|
||||
var ev = new RCDDoAfterEvent(GetNetCoordinates(mapGridData.Value.Location), component.ConstructionDirection, component.ProtoId, cost, EntityManager.GetNetEntity(effect));
|
||||
|
||||
var doAfterArgs = new DoAfterArgs(EntityManager, user, delay, ev, uid, target: args.Target, used: uid)
|
||||
{
|
||||
@@ -263,7 +262,7 @@ public class RCDSystem : EntitySystem
|
||||
return;
|
||||
|
||||
// Finalize the operation
|
||||
FinalizeRCDOperation(uid, component, mapGridData.Value, args.Target, args.User);
|
||||
FinalizeRCDOperation(uid, component, mapGridData.Value, args.Direction, args.Target, args.User);
|
||||
|
||||
// Play audio and consume charges
|
||||
_audio.PlayPredicted(component.SuccessSound, uid, args.User);
|
||||
@@ -419,7 +418,7 @@ public class RCDSystem : EntitySystem
|
||||
foreach (var fixture in fixtures.Fixtures.Values)
|
||||
{
|
||||
// Continue if no collision is possible
|
||||
if (fixture.CollisionLayer <= 0 || (fixture.CollisionLayer & (int) component.CachedPrototype.CollisionMask) == 0)
|
||||
if (!fixture.Hard || fixture.CollisionLayer <= 0 || (fixture.CollisionLayer & (int) component.CachedPrototype.CollisionMask) == 0)
|
||||
continue;
|
||||
|
||||
// Continue if our custom collision bounds are not intersected
|
||||
@@ -494,7 +493,7 @@ public class RCDSystem : EntitySystem
|
||||
|
||||
#region Entity construction/deconstruction
|
||||
|
||||
private void FinalizeRCDOperation(EntityUid uid, RCDComponent component, MapGridData mapGridData, EntityUid? target, EntityUid user)
|
||||
private void FinalizeRCDOperation(EntityUid uid, RCDComponent component, MapGridData mapGridData, Direction direction, EntityUid? target, EntityUid user)
|
||||
{
|
||||
if (!_net.IsServer)
|
||||
return;
|
||||
@@ -521,7 +520,7 @@ public class RCDSystem : EntitySystem
|
||||
Transform(ent).LocalRotation = Transform(uid).LocalRotation;
|
||||
break;
|
||||
case RcdRotation.User:
|
||||
Transform(ent).LocalRotation = component.ConstructionDirection.ToAngle();
|
||||
Transform(ent).LocalRotation = direction.ToAngle();
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -617,6 +616,9 @@ public sealed partial class RCDDoAfterEvent : DoAfterEvent
|
||||
[DataField(required: true)]
|
||||
public NetCoordinates Location { get; private set; } = default!;
|
||||
|
||||
[DataField]
|
||||
public Direction Direction { get; private set; } = default!;
|
||||
|
||||
[DataField]
|
||||
public ProtoId<RCDPrototype> StartingProtoId { get; private set; } = default!;
|
||||
|
||||
@@ -628,9 +630,10 @@ public sealed partial class RCDDoAfterEvent : DoAfterEvent
|
||||
|
||||
private RCDDoAfterEvent() { }
|
||||
|
||||
public RCDDoAfterEvent(NetCoordinates location, ProtoId<RCDPrototype> startingProtoId, int cost, NetEntity? effect = null)
|
||||
public RCDDoAfterEvent(NetCoordinates location, Direction direction, ProtoId<RCDPrototype> startingProtoId, int cost, NetEntity? effect = null)
|
||||
{
|
||||
Location = location;
|
||||
Direction = direction;
|
||||
StartingProtoId = startingProtoId;
|
||||
Cost = cost;
|
||||
Effect = effect;
|
||||
|
||||
@@ -46,6 +46,12 @@ public partial class StatusIconData : IComparable<StatusIconData>
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public int Offset = 0;
|
||||
|
||||
/// <summary>
|
||||
/// Sets if the icon should be rendered with or without the effect of lighting.
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public bool IsShaded = false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -48,7 +48,7 @@ public abstract class SharedTrayScannerSystem : EntitySystem
|
||||
|
||||
private void OnTrayScannerGetState(EntityUid uid, TrayScannerComponent scanner, ref ComponentGetState args)
|
||||
{
|
||||
args.State = new TrayScannerState(scanner.Enabled);
|
||||
args.State = new TrayScannerState(scanner.Enabled, scanner.Range);
|
||||
}
|
||||
|
||||
private void OnTrayScannerHandleState(EntityUid uid, TrayScannerComponent scanner, ref ComponentHandleState args)
|
||||
@@ -56,6 +56,7 @@ public abstract class SharedTrayScannerSystem : EntitySystem
|
||||
if (args.Current is not TrayScannerState state)
|
||||
return;
|
||||
|
||||
scanner.Range = state.Range;
|
||||
SetScannerEnabled(uid, state.Enabled, scanner);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,9 +22,11 @@ public sealed partial class TrayScannerComponent : Component
|
||||
public sealed class TrayScannerState : ComponentState
|
||||
{
|
||||
public bool Enabled;
|
||||
public float Range;
|
||||
|
||||
public TrayScannerState(bool enabled)
|
||||
public TrayScannerState(bool enabled, float range)
|
||||
{
|
||||
Enabled = enabled;
|
||||
Range = range;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -114,11 +114,23 @@ public sealed partial class MeleeWeaponComponent : Component
|
||||
public bool SwingLeft;
|
||||
|
||||
/// <summary>
|
||||
/// CrystallPunk Melee improvment. Allows each attack to take turns being either left or right
|
||||
/// CrystallPunk Melee upgrade. Allows each attack to take turns being either left or right
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public bool CPSwingBeverage = true;
|
||||
|
||||
/// <summary>
|
||||
/// CrystallPunk Melee upgrade. Modifier of wide attack animation speed
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public float CPAnimationLength = 0.5f;
|
||||
|
||||
/// <summary>
|
||||
/// CrystallPunk Melee upgrade. how far away from the player the animation should be played.
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public float CPAnimationOffset = -1f;
|
||||
|
||||
// Sounds
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -385,6 +385,11 @@ public abstract class SharedMeleeWeaponSystem : EntitySystem
|
||||
var ev = new AttemptMeleeEvent();
|
||||
RaiseLocalEvent(weaponUid, ref ev);
|
||||
|
||||
//CrystallPun melee improvment
|
||||
if (weapon.CPSwingBeverage)
|
||||
weapon.SwingLeft = !weapon.SwingLeft;
|
||||
//CrystallPun melee improvment end
|
||||
|
||||
if (ev.Cancelled)
|
||||
{
|
||||
if (ev.Message != null)
|
||||
@@ -428,11 +433,6 @@ public abstract class SharedMeleeWeaponSystem : EntitySystem
|
||||
var attackEv = new MeleeAttackEvent(weaponUid);
|
||||
RaiseLocalEvent(user, ref attackEv);
|
||||
|
||||
//CrystallPun melee improvment
|
||||
if (weapon.CPSwingBeverage)
|
||||
weapon.SwingLeft = !weapon.SwingLeft;
|
||||
//CrystallPun melee improvment end
|
||||
|
||||
weapon.Attacking = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
4
Resources/Audio/_CP14/Lobby/attributions.yml
Normal file
4
Resources/Audio/_CP14/Lobby/attributions.yml
Normal file
@@ -0,0 +1,4 @@
|
||||
- files: ["crystal.ogg"]
|
||||
license: "CC-BY-NC-SA-3.0"
|
||||
copyright: "'Crystal' by Mental4815162342 (github). Converted from MP3 to OGG."
|
||||
source: "https://github.com/crystallpunk-14/crystall-punk-14"
|
||||
BIN
Resources/Audio/_CP14/Lobby/crystal.ogg
Normal file
BIN
Resources/Audio/_CP14/Lobby/crystal.ogg
Normal file
Binary file not shown.
@@ -144,5 +144,13 @@ Entries:
|
||||
id: 19
|
||||
time: '2024-03-31T02:05:44.0000000+00:00'
|
||||
url: https://github.com/space-wizards/space-station-14/pull/26546
|
||||
- author: PJB3005
|
||||
changes:
|
||||
- message: The new "grant_connect_bypass" command grants a player the ability to
|
||||
connect, bypassing whitelist, player cap and panic bunker.
|
||||
type: Add
|
||||
id: 20
|
||||
time: '2024-04-09T15:25:21.0000000+00:00'
|
||||
url: https://github.com/space-wizards/space-station-14/pull/26771
|
||||
Name: Admin
|
||||
Order: 1
|
||||
|
||||
@@ -1,236 +1,4 @@
|
||||
Entries:
|
||||
- author: ERORR404V1
|
||||
changes:
|
||||
- message: Added mime hardsuit
|
||||
type: Add
|
||||
id: 5796
|
||||
time: '2024-01-26T14:43:50.0000000+00:00'
|
||||
url: https://api.github.com/repos/space-wizards/space-station-14/pulls/24198
|
||||
- author: icekot8
|
||||
changes:
|
||||
- message: Correct display of syndicate jaws of life in hand
|
||||
type: Add
|
||||
id: 5797
|
||||
time: '2024-01-27T02:27:14.0000000+00:00'
|
||||
url: https://api.github.com/repos/space-wizards/space-station-14/pulls/24583
|
||||
- author: Agoichi
|
||||
changes:
|
||||
- message: Detective cabinet now have security holoprojector in interests of investigation
|
||||
type: Tweak
|
||||
- message: Security lockers have chance to spawn security holoprojector (0.5)
|
||||
type: Tweak
|
||||
id: 5798
|
||||
time: '2024-01-27T02:29:40.0000000+00:00'
|
||||
url: https://api.github.com/repos/space-wizards/space-station-14/pulls/24582
|
||||
- author: TheShuEd
|
||||
changes:
|
||||
- message: Flesh and Rock anomalies have been reworked to place entities more dynamically
|
||||
when spawning.
|
||||
type: Tweak
|
||||
id: 5799
|
||||
time: '2024-01-27T02:52:07.0000000+00:00'
|
||||
url: https://api.github.com/repos/space-wizards/space-station-14/pulls/24449
|
||||
- author: PJB3005
|
||||
changes:
|
||||
- message: PACMAN-type portable generators now show power statistics for the network
|
||||
they're connected to.
|
||||
type: Add
|
||||
- message: JRPACMAN has been buffed from 5 kW to 8 kW.
|
||||
type: Tweak
|
||||
id: 5800
|
||||
time: '2024-01-27T02:53:44.0000000+00:00'
|
||||
url: https://api.github.com/repos/space-wizards/space-station-14/pulls/24604
|
||||
- author: Blackern5000
|
||||
changes:
|
||||
- message: Shotgun slugs can now be printed in the security techfab.
|
||||
type: Add
|
||||
- message: Shotgun slugs now fire a single strong projectile when fired.
|
||||
type: Tweak
|
||||
id: 5801
|
||||
time: '2024-01-27T02:56:57.0000000+00:00'
|
||||
url: https://api.github.com/repos/space-wizards/space-station-14/pulls/24196
|
||||
- author: I-JustUser-I
|
||||
changes:
|
||||
- message: Zombie Outbreak event now has a minimum limit of 15 players.
|
||||
type: Tweak
|
||||
id: 5802
|
||||
time: '2024-01-27T03:53:09.0000000+00:00'
|
||||
url: https://api.github.com/repos/space-wizards/space-station-14/pulls/24577
|
||||
- author: mirrorcult
|
||||
changes:
|
||||
- message: Navmap now defaults to showing departments
|
||||
type: Tweak
|
||||
id: 5803
|
||||
time: '2024-01-27T12:08:50.0000000+00:00'
|
||||
url: https://api.github.com/repos/space-wizards/space-station-14/pulls/24613
|
||||
- author: Tayrtahn
|
||||
changes:
|
||||
- message: Vending machines can now be repaired with a welder.
|
||||
type: Tweak
|
||||
id: 5804
|
||||
time: '2024-01-27T12:12:53.0000000+00:00'
|
||||
url: https://api.github.com/repos/space-wizards/space-station-14/pulls/24603
|
||||
- author: graevy
|
||||
changes:
|
||||
- message: Added hallway screen prototypes and comms console text broadcasts.
|
||||
type: Add
|
||||
id: 5805
|
||||
time: '2024-01-27T13:51:25.0000000+00:00'
|
||||
url: https://api.github.com/repos/space-wizards/space-station-14/pulls/24189
|
||||
- author: mirrorcult
|
||||
changes:
|
||||
- message: Lights are now shaded with the same color that they glow.
|
||||
type: Tweak
|
||||
id: 5806
|
||||
time: '2024-01-27T17:43:45.0000000+00:00'
|
||||
url: https://api.github.com/repos/space-wizards/space-station-14/pulls/24612
|
||||
- author: Boaz1111
|
||||
changes:
|
||||
- message: The PKA shuttle gun now breaks rocks in one hit.
|
||||
type: Tweak
|
||||
id: 5807
|
||||
time: '2024-01-27T17:47:35.0000000+00:00'
|
||||
url: https://api.github.com/repos/space-wizards/space-station-14/pulls/24627
|
||||
- author: FungiFellow
|
||||
changes:
|
||||
- message: Ion Storms are twice as likely to occur.
|
||||
type: Tweak
|
||||
id: 5808
|
||||
time: '2024-01-27T23:14:09.0000000+00:00'
|
||||
url: https://api.github.com/repos/space-wizards/space-station-14/pulls/24633
|
||||
- author: PJB3005
|
||||
changes:
|
||||
- message: Security barriers need 5 seconds to lock and unlock.
|
||||
type: Tweak
|
||||
id: 5809
|
||||
time: '2024-01-28T00:28:02.0000000+00:00'
|
||||
url: https://api.github.com/repos/space-wizards/space-station-14/pulls/24637
|
||||
- author: themias
|
||||
changes:
|
||||
- message: Added cowboy hats and boots to autodrobe, secdrobe, and maints
|
||||
type: Add
|
||||
- message: Added cowboy accent
|
||||
type: Add
|
||||
id: 5810
|
||||
time: '2024-01-28T03:23:16.0000000+00:00'
|
||||
url: https://api.github.com/repos/space-wizards/space-station-14/pulls/24299
|
||||
- author: shampunj
|
||||
changes:
|
||||
- message: A new game preset! Can only be selected by admins. All at once.
|
||||
type: Add
|
||||
id: 5811
|
||||
time: '2024-01-28T10:41:36.0000000+00:00'
|
||||
url: https://api.github.com/repos/space-wizards/space-station-14/pulls/23171
|
||||
- author: Doctor-Cpu
|
||||
changes:
|
||||
- message: 3kliksphilips name.
|
||||
type: Fix
|
||||
id: 5812
|
||||
time: '2024-01-28T10:46:32.0000000+00:00'
|
||||
url: https://api.github.com/repos/space-wizards/space-station-14/pulls/24657
|
||||
- author: mirrorcult
|
||||
changes:
|
||||
- message: Speech sounds are now quieter
|
||||
type: Tweak
|
||||
id: 5813
|
||||
time: '2024-01-28T10:49:55.0000000+00:00'
|
||||
url: https://api.github.com/repos/space-wizards/space-station-14/pulls/24579
|
||||
- author: TheShuEd
|
||||
changes:
|
||||
- message: The fire anomaly is now heavier in content.
|
||||
type: Tweak
|
||||
- message: Artifacts no longer block projectiles.
|
||||
type: Tweak
|
||||
id: 5814
|
||||
time: '2024-01-29T01:30:55.0000000+00:00'
|
||||
url: https://api.github.com/repos/space-wizards/space-station-14/pulls/24666
|
||||
- author: Krunk
|
||||
changes:
|
||||
- message: Health analysis interfaces now also display a subject's temperature in
|
||||
Kelvin.
|
||||
type: Add
|
||||
id: 5815
|
||||
time: '2024-01-29T01:32:54.0000000+00:00'
|
||||
url: https://api.github.com/repos/space-wizards/space-station-14/pulls/24643
|
||||
- author: Ubaser
|
||||
changes:
|
||||
- message: Detectives now work as independent agents, separate from security, and
|
||||
are encouraged to answer any requests for help.
|
||||
type: Tweak
|
||||
id: 5816
|
||||
time: '2024-01-29T06:45:27.0000000+00:00'
|
||||
url: https://api.github.com/repos/space-wizards/space-station-14/pulls/23114
|
||||
- author: mirrorcult
|
||||
changes:
|
||||
- message: Rotting examine text doesn't have weird grammatical errors now
|
||||
type: Fix
|
||||
id: 5817
|
||||
time: '2024-01-29T07:50:18.0000000+00:00'
|
||||
url: https://api.github.com/repos/space-wizards/space-station-14/pulls/24689
|
||||
- author: Eden077
|
||||
changes:
|
||||
- message: Synaptizine now deals less poison damage.
|
||||
type: Tweak
|
||||
id: 5818
|
||||
time: '2024-01-29T07:55:52.0000000+00:00'
|
||||
url: https://api.github.com/repos/space-wizards/space-station-14/pulls/24676
|
||||
- author: mirrorcult
|
||||
changes:
|
||||
- message: Various annoying sounds are now a little quieter
|
||||
type: Tweak
|
||||
id: 5819
|
||||
time: '2024-01-29T09:51:31.0000000+00:00'
|
||||
url: https://api.github.com/repos/space-wizards/space-station-14/pulls/24690
|
||||
- author: SpeltIncorrectyl
|
||||
changes:
|
||||
- message: Portable generators can now be connected to the signal network and controlled
|
||||
remotely via devices like a signal transmitter.
|
||||
type: Add
|
||||
id: 5820
|
||||
time: '2024-01-29T14:56:29.0000000+00:00'
|
||||
url: https://api.github.com/repos/space-wizards/space-station-14/pulls/24157
|
||||
- author: Tayrtahn
|
||||
changes:
|
||||
- message: Welders properly display their lit status again.
|
||||
type: Fix
|
||||
id: 5821
|
||||
time: '2024-01-29T23:04:52.0000000+00:00'
|
||||
url: https://api.github.com/repos/space-wizards/space-station-14/pulls/24705
|
||||
- author: Tayrtahn
|
||||
changes:
|
||||
- message: Water bottles now display their fill level while held.
|
||||
type: Add
|
||||
id: 5822
|
||||
time: '2024-01-29T23:19:56.0000000+00:00'
|
||||
url: https://api.github.com/repos/space-wizards/space-station-14/pulls/24708
|
||||
- author: SlamBamActionman
|
||||
changes:
|
||||
- message: Arachnids slipping in water now get a cute hat!
|
||||
type: Add
|
||||
id: 5823
|
||||
time: '2024-01-30T00:21:26.0000000+00:00'
|
||||
url: https://api.github.com/repos/space-wizards/space-station-14/pulls/23822
|
||||
- author: Tayrtahn
|
||||
changes:
|
||||
- message: Pressing shift as a ghost no longer cancels following your target
|
||||
type: Fix
|
||||
id: 5824
|
||||
time: '2024-01-30T01:33:35.0000000+00:00'
|
||||
url: https://api.github.com/repos/space-wizards/space-station-14/pulls/24715
|
||||
- author: liltenhead
|
||||
changes:
|
||||
- message: Jugs are now destructible.
|
||||
type: Tweak
|
||||
id: 5825
|
||||
time: '2024-01-30T08:11:43.0000000+00:00'
|
||||
url: https://api.github.com/repos/space-wizards/space-station-14/pulls/24719
|
||||
- author: Emisse
|
||||
changes:
|
||||
- message: Aspid
|
||||
type: Remove
|
||||
id: 5826
|
||||
time: '2024-01-30T10:26:02.0000000+00:00'
|
||||
url: https://api.github.com/repos/space-wizards/space-station-14/pulls/24725
|
||||
- author: mirrorcult
|
||||
changes:
|
||||
- message: Throwing items now scale a bit when thrown to simulate rising/falling
|
||||
@@ -3810,3 +3578,250 @@
|
||||
id: 6295
|
||||
time: '2024-04-03T05:31:57.0000000+00:00'
|
||||
url: https://github.com/space-wizards/space-station-14/pull/26662
|
||||
- author: deltanedas
|
||||
changes:
|
||||
- message: Disabled scooping foam due to a reagent duplication bug.
|
||||
type: Fix
|
||||
id: 6296
|
||||
time: '2024-04-03T13:41:23.0000000+00:00'
|
||||
url: https://github.com/space-wizards/space-station-14/pull/26686
|
||||
- author: Aserovich
|
||||
changes:
|
||||
- message: New lobby art!
|
||||
type: Add
|
||||
id: 6297
|
||||
time: '2024-04-04T05:28:30.0000000+00:00'
|
||||
url: https://github.com/space-wizards/space-station-14/pull/26505
|
||||
- author: Beck Thompson
|
||||
changes:
|
||||
- message: Items thrown at disposals now have to be insertable to display the miss
|
||||
message.
|
||||
type: Fix
|
||||
id: 6298
|
||||
time: '2024-04-04T06:25:47.0000000+00:00'
|
||||
url: https://github.com/space-wizards/space-station-14/pull/26716
|
||||
- author: Tayrtahn
|
||||
changes:
|
||||
- message: Some devices may have broken wiring at the start of each round.
|
||||
type: Add
|
||||
id: 6299
|
||||
time: '2024-04-04T06:28:09.0000000+00:00'
|
||||
url: https://github.com/space-wizards/space-station-14/pull/26695
|
||||
- author: lzk228
|
||||
changes:
|
||||
- message: Turning off thrusters and gyroscopes now stop consume power.
|
||||
type: Fix
|
||||
id: 6300
|
||||
time: '2024-04-04T06:28:33.0000000+00:00'
|
||||
url: https://github.com/space-wizards/space-station-14/pull/26690
|
||||
- author: Aexxie
|
||||
changes:
|
||||
- message: Added the option to disable your OOC Patron name color.
|
||||
type: Add
|
||||
id: 6301
|
||||
time: '2024-04-04T07:20:06.0000000+00:00'
|
||||
url: https://github.com/space-wizards/space-station-14/pull/26653
|
||||
- author: DinoWattz
|
||||
changes:
|
||||
- message: Fixed pocket slots being able to hide character snout markings.
|
||||
type: Fix
|
||||
id: 6302
|
||||
time: '2024-04-04T08:35:44.0000000+00:00'
|
||||
url: https://github.com/space-wizards/space-station-14/pull/26708
|
||||
- author: VasilisThePikachu
|
||||
changes:
|
||||
- message: Mop buckets and Janitorial Trolleys will not spill their contents as
|
||||
soon as they are pushed.
|
||||
type: Fix
|
||||
- message: Mop buckets are no longer solid. So you can now walk through them.
|
||||
type: Fix
|
||||
id: 6303
|
||||
time: '2024-04-04T08:39:55.0000000+00:00'
|
||||
url: https://github.com/space-wizards/space-station-14/pull/26706
|
||||
- author: ZeroDayDaemon
|
||||
changes:
|
||||
- message: Lowered the number of ducks in the duck crate and reduced the price of
|
||||
it.
|
||||
type: Tweak
|
||||
id: 6304
|
||||
time: '2024-04-04T19:30:13.0000000+00:00'
|
||||
url: https://github.com/space-wizards/space-station-14/pull/26729
|
||||
- author: PrPleGoo
|
||||
changes:
|
||||
- message: The medical HUD's brightness now scales with lighting again.
|
||||
type: Tweak
|
||||
- message: Most HUD icon's brightness now scale with lighting.
|
||||
type: Tweak
|
||||
id: 6305
|
||||
time: '2024-04-04T23:05:01.0000000+00:00'
|
||||
url: https://github.com/space-wizards/space-station-14/pull/26726
|
||||
- author: Daemon
|
||||
changes:
|
||||
- message: Practice projectiles have been given standardized minimal damage.
|
||||
type: Tweak
|
||||
- message: The practice laser gun now works with shooting targets.
|
||||
type: Tweak
|
||||
id: 6306
|
||||
time: '2024-04-05T03:15:02.0000000+00:00'
|
||||
url: https://github.com/space-wizards/space-station-14/pull/26731
|
||||
- author: Daemon
|
||||
changes:
|
||||
- message: Shooting targets can now have their popup type changed with a left click
|
||||
to show total damage, damage of a single hit, both, or just a notice that it
|
||||
was hit.
|
||||
type: Tweak
|
||||
id: 6307
|
||||
time: '2024-04-05T07:19:41.0000000+00:00'
|
||||
url: https://github.com/space-wizards/space-station-14/pull/26734
|
||||
- author: Vermidia
|
||||
changes:
|
||||
- message: Baseball bats now require a knife to craft
|
||||
type: Tweak
|
||||
id: 6308
|
||||
time: '2024-04-05T15:41:35.0000000+00:00'
|
||||
url: https://github.com/space-wizards/space-station-14/pull/26742
|
||||
- author: deltanedas
|
||||
changes:
|
||||
- message: Making fultons now requires cloth and they are faster to make.
|
||||
type: Tweak
|
||||
id: 6309
|
||||
time: '2024-04-05T15:42:12.0000000+00:00'
|
||||
url: https://github.com/space-wizards/space-station-14/pull/26747
|
||||
- author: superjj18
|
||||
changes:
|
||||
- message: Broadcasting works again!
|
||||
type: Fix
|
||||
id: 6310
|
||||
time: '2024-04-05T17:29:22.0000000+00:00'
|
||||
url: https://github.com/space-wizards/space-station-14/pull/26750
|
||||
- author: Golinth
|
||||
changes:
|
||||
- message: Fixed mindshield icons being glow in the dark
|
||||
type: Fix
|
||||
id: 6311
|
||||
time: '2024-04-05T20:35:32.0000000+00:00'
|
||||
url: https://github.com/space-wizards/space-station-14/pull/26754
|
||||
- author: Blackern5000
|
||||
changes:
|
||||
- message: Added sap
|
||||
type: Add
|
||||
- message: Added syrup, it can be made by boiling sap.
|
||||
type: Add
|
||||
- message: Dionae now bleed sap instead of water
|
||||
type: Tweak
|
||||
id: 6312
|
||||
time: '2024-04-05T21:06:12.0000000+00:00'
|
||||
url: https://github.com/space-wizards/space-station-14/pull/25748
|
||||
- author: osjarw
|
||||
changes:
|
||||
- message: Thin firelocks are now constructable/deconstructable
|
||||
type: Fix
|
||||
id: 6313
|
||||
time: '2024-04-06T01:55:31.0000000+00:00'
|
||||
url: https://github.com/space-wizards/space-station-14/pull/26745
|
||||
- author: BITTERLYNX
|
||||
changes:
|
||||
- message: Rodents are more visually pleasing to burn
|
||||
type: Fix
|
||||
- message: mothroach and hammy also more visually pleasing to burn
|
||||
type: Fix
|
||||
id: 6314
|
||||
time: '2024-04-06T04:41:23.0000000+00:00'
|
||||
url: https://github.com/space-wizards/space-station-14/pull/26758
|
||||
- author: Plykiya
|
||||
changes:
|
||||
- message: You can now carefully walk over glass shards and D4.
|
||||
type: Tweak
|
||||
id: 6315
|
||||
time: '2024-04-06T04:49:14.0000000+00:00'
|
||||
url: https://github.com/space-wizards/space-station-14/pull/26763
|
||||
- author: PursuitInAshes
|
||||
changes:
|
||||
- message: Sake Bottles can now be found in the booze-o-mat.
|
||||
type: Tweak
|
||||
id: 6316
|
||||
time: '2024-04-06T20:16:47.0000000+00:00'
|
||||
url: https://github.com/space-wizards/space-station-14/pull/26776
|
||||
- author: osjarw
|
||||
changes:
|
||||
- message: Removed broken anom behaviour, which causes APE shots to fly through
|
||||
the anom.
|
||||
type: Remove
|
||||
id: 6317
|
||||
time: '2024-04-06T22:27:16.0000000+00:00'
|
||||
url: https://github.com/space-wizards/space-station-14/pull/26775
|
||||
- author: Vermidia
|
||||
changes:
|
||||
- message: Water coolers show how full/what they're full of again.
|
||||
type: Fix
|
||||
id: 6318
|
||||
time: '2024-04-06T23:58:57.0000000+00:00'
|
||||
url: https://github.com/space-wizards/space-station-14/pull/26784
|
||||
- author: Crotalus
|
||||
changes:
|
||||
- message: Show missing materials in lathe tooltip
|
||||
type: Add
|
||||
id: 6319
|
||||
time: '2024-04-08T03:16:11.0000000+00:00'
|
||||
url: https://github.com/space-wizards/space-station-14/pull/26795
|
||||
- author: chromiumboy
|
||||
changes:
|
||||
- message: Fixed the RCD not being able to build on top of puddles
|
||||
type: Fix
|
||||
- message: RCD constructions can no longer be rotated while in progress
|
||||
type: Tweak
|
||||
- message: The RCD now reports construction mode changes to its user
|
||||
type: Add
|
||||
id: 6320
|
||||
time: '2024-04-08T03:17:29.0000000+00:00'
|
||||
url: https://github.com/space-wizards/space-station-14/pull/26792
|
||||
- author: lzk228
|
||||
changes:
|
||||
- message: Bombsuit and jani bombsuit are similar now.
|
||||
type: Tweak
|
||||
id: 6321
|
||||
time: '2024-04-08T15:05:58.0000000+00:00'
|
||||
url: https://github.com/space-wizards/space-station-14/pull/26806
|
||||
- author: lzk228
|
||||
changes:
|
||||
- message: Clothing restock crate was splitted to clothing and autodrobe restock
|
||||
crates.
|
||||
type: Tweak
|
||||
- message: Clothing is cheaper.
|
||||
type: Tweak
|
||||
id: 6322
|
||||
time: '2024-04-08T15:10:58.0000000+00:00'
|
||||
url: https://github.com/space-wizards/space-station-14/pull/26805
|
||||
- author: Hanzdegloker
|
||||
changes:
|
||||
- message: Spears can now be quipped to your suit slot and cost slightly more to
|
||||
make.
|
||||
type: Tweak
|
||||
id: 6323
|
||||
time: '2024-04-08T15:34:35.0000000+00:00'
|
||||
url: https://github.com/space-wizards/space-station-14/pull/26724
|
||||
- author: KittenColony
|
||||
changes:
|
||||
- message: Added 13 new gauze wraps for moth that fit their twig bodies
|
||||
type: Add
|
||||
- message: Gauze markings have been moved to the Overlay category, allowing gauze
|
||||
to not take up marking points
|
||||
type: Tweak
|
||||
id: 6324
|
||||
time: '2024-04-09T08:04:51.0000000+00:00'
|
||||
url: https://github.com/space-wizards/space-station-14/pull/25481
|
||||
- author: Killerqu00
|
||||
changes:
|
||||
- message: Quartermasters can now skip a single bounty in the list once every 15
|
||||
minutes.
|
||||
type: Add
|
||||
id: 6325
|
||||
time: '2024-04-09T22:18:07.0000000+00:00'
|
||||
url: https://github.com/space-wizards/space-station-14/pull/26537
|
||||
- author: SkaldetSkaeg
|
||||
changes:
|
||||
- message: The Flippo lighter is now quieter and has a delay on use.
|
||||
type: Tweak
|
||||
id: 6326
|
||||
time: '2024-04-09T22:20:57.0000000+00:00'
|
||||
url: https://github.com/space-wizards/space-station-14/pull/26846
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -0,0 +1,16 @@
|
||||
## Strings for the "grant_connect_bypass" command.
|
||||
|
||||
cmd-grant_connect_bypass-desc = Temporarily allow a user to bypass regular connection checks.
|
||||
cmd-grant_connect_bypass-help = Usage: grant_connect_bypass <user> [duration minutes]
|
||||
Temporarily grants a user the ability to bypass regular connections restrictions.
|
||||
The bypass only applies to this game server and will expire after (by default) 1 hour.
|
||||
They will be able to join regardless of whitelist, panic bunker, or player cap.
|
||||
|
||||
cmd-grant_connect_bypass-arg-user = <user>
|
||||
cmd-grant_connect_bypass-arg-duration = [duration minutes]
|
||||
|
||||
cmd-grant_connect_bypass-invalid-args = Expected 1 or 2 arguments
|
||||
cmd-grant_connect_bypass-unknown-user = Unable to find user '{$user}'
|
||||
cmd-grant_connect_bypass-invalid-duration = Invalid duration '{$duration}'
|
||||
|
||||
cmd-grant_connect_bypass-success = Successfully added bypass for user '{$user}'
|
||||
@@ -1,5 +1,6 @@
|
||||
bounty-console-menu-title = Cargo bounty console
|
||||
bounty-console-label-button-text = Print label
|
||||
bounty-console-skip-button-text = Skip
|
||||
bounty-console-time-label = Time: [color=orange]{$time}[/color]
|
||||
bounty-console-reward-label = Reward: [color=limegreen]${$reward}[/color]
|
||||
bounty-console-manifest-label = Manifest: [color=orange]{$item}[/color]
|
||||
|
||||
@@ -42,6 +42,7 @@ ui-options-volume-percent = { TOSTRING($volume, "P0") }
|
||||
ui-options-show-held-item = Show held item next to cursor
|
||||
ui-options-show-combat-mode-indicators = Show combat mode indicators with cursor
|
||||
ui-options-opaque-storage-window = Opaque storage window
|
||||
ui-options-show-ooc-patron-color = Show OOC Patreon color
|
||||
ui-options-show-looc-on-head = Show LOOC chat above characters head
|
||||
ui-options-fancy-speech = Show names in speech bubbles
|
||||
ui-options-fancy-name-background = Add background to speech bubble names
|
||||
|
||||
@@ -13,6 +13,10 @@ lathe-menu-material-amount = { $amount ->
|
||||
[1] {NATURALFIXED($amount, 2)} {$unit}
|
||||
*[other] {NATURALFIXED($amount, 2)} {MAKEPLURAL($unit)}
|
||||
}
|
||||
lathe-menu-material-amount-missing = { $amount ->
|
||||
[1] {NATURALFIXED($amount, 2)} {$unit} of {$material} ([color=red]{NATURALFIXED($missingAmount, 2)} {$unit} missing[/color])
|
||||
*[other] {NATURALFIXED($amount, 2)} {MAKEPLURAL($unit)} of {$material} ([color=red]{NATURALFIXED($missingAmount, 2)} {MAKEPLURAL($unit)} missing[/color])
|
||||
}
|
||||
lathe-menu-no-materials-message = No materials loaded.
|
||||
lathe-menu-fabricating-message = Fabricating...
|
||||
lathe-menu-materials-title = Materials
|
||||
|
||||
@@ -1,17 +1,17 @@
|
||||
marking-GauzeLefteyePatch-gauze_lefteye_2 = Gauze eyepatch (Left)
|
||||
marking-GauzeLefteyePatch = Gauze eyepatch (Left)
|
||||
|
||||
marking-GauzeLefteyeTape-gauze_lefteye_1 = Gauze eyepad (Left)
|
||||
marking-GauzeLefteyeTape = Gauze eyepad (Left)
|
||||
marking-GauzeLefteyePad-gauze_lefteye_1 = Gauze eyepad (Left)
|
||||
marking-GauzeLefteyePad = Gauze eyepad (Left)
|
||||
|
||||
marking-GauzeRighteyePatch-gauze_righteye_2 = Gauze eyepatch (Right)
|
||||
marking-GauzeRighteyePatch = Gauze eyepatch (Right)
|
||||
|
||||
marking-GauzeRighteyeTape-gauze_righteye_1 = Gauze eyepad (Right)
|
||||
marking-GauzeRighteyeTape = Gauze eyepad (Right)
|
||||
marking-GauzeRighteyePad-gauze_righteye_1 = Gauze eyepad (Right)
|
||||
marking-GauzeRighteyePad = Gauze eyepad (Right)
|
||||
|
||||
marking-GauzeShoulder-gauze_shoulder = Gauze Shoulder
|
||||
marking-GauzeShoulder = Gauze Shoulder
|
||||
marking-GauzeShoulder-gauze_shoulder = Gauze Shoulder Sling
|
||||
marking-GauzeShoulder = Gauze Shoulder Sling
|
||||
|
||||
marking-GauzeStomach-gauze_abdomen = Gauze Stomach Wrap
|
||||
marking-GauzeStomach = Gauze Stomach Wrap
|
||||
@@ -46,17 +46,57 @@ marking-GauzeUpperLegRight = Gauze Thigh Wrap (Right)
|
||||
marking-GauzeBlindfold-gauze_blindfold = Gauze Blindfold
|
||||
marking-GauzeBlindfold = Gauze Blindfold
|
||||
|
||||
marking-GauzeLizardBlindfold-gauze_lizardblindfold = Gauze Blindfold
|
||||
marking-GauzeLizardBlindfold-gauze_lizard_blindfold = Gauze Blindfold
|
||||
marking-GauzeLizardBlindfold = Gauze Blindfold
|
||||
|
||||
marking-GauzeLizardFootRight-gauze_lizardfoot_r = Gauze Foot Wrap (Right)
|
||||
marking-GauzeLizardFootRight-gauze_lizard_foot_r = Gauze Foot Wrap (Right)
|
||||
marking-GauzeLizardFootRight = Gauze Foot Wrap (Right)
|
||||
|
||||
marking-GauzeLizardFootLeft-gauze_lizardfoot_l = Gauze Foot Wrap (Left)
|
||||
marking-GauzeLizardFootLeft-gauze_lizard_foot_l = Gauze Foot Wrap (Left)
|
||||
marking-GauzeLizardFootLeft = Gauze Foot Wrap (Left)
|
||||
|
||||
marking-GauzeLizardLefteyePatch-gauze_lizardlefteye = Adjusted Gauze eyepatch (Left)
|
||||
marking-GauzeLizardLefteyePatch = Adjusted Gauze eyepatch (Left)
|
||||
marking-GauzeLizardLefteyePatch-gauze_lizard_lefteye = Reptilian Gauze eyepatch (Left)
|
||||
marking-GauzeLizardLefteyePatch = Reptilian Gauze eyepatch (Left)
|
||||
|
||||
marking-GauzeLizardRighteyePatch-gauze_lizard_righteye = Reptilian Gauze eyepatch (Right)
|
||||
marking-GauzeLizardRighteyePatch = Reptilian Gauze Eyepatch (Right)
|
||||
|
||||
marking-GauzeMothStomach-gauze_moth_abdomen = Insectoid Stomach Wrap
|
||||
marking-GauzeMothStomach = Insectoid Stomach Wrap
|
||||
|
||||
marking-GauzeMothShoulder-gauze_moth_shoulder = Insectoid Shoulder Sling
|
||||
marking-GauzeMothShoulder = Insectoid Shoulder Sling
|
||||
|
||||
marking-GauzeMothBlindfold-gauze_moth_blindfold = Insectoid Blindfold
|
||||
marking-GauzeMothBlindfold = Insectoid Blindfold
|
||||
|
||||
marking-GauzeMothLeftEyePatch-gauze_moth_lefteye_2 = Insectoid Gauze eyepatch (Left)
|
||||
marking-GauzeMothLeftEyePatch = Insectoid Gauze eyepatch (Left)
|
||||
|
||||
marking-GauzeMothLeftEyePad-gauze_moth_lefteye_1 = Insectoid Gauze eyepad (Left)
|
||||
marking-GauzeMothLeftEyePad = Insectoid Gauze eyepad (Left)
|
||||
|
||||
marking-GauzeMothRightEyePatch-gauze_moth_righteye_2 = Insectoid Gauze eyepatch (Right)
|
||||
marking-GauzeMothRightEyePatch = Insectoid Gauze eyepatch (Right)
|
||||
|
||||
marking-GauzeMothRightEyePad-gauze_moth_righteye_1 = Insectoid Gauze eyepad (Right)
|
||||
marking-GauzeMothRightEyePad = Insectoid Gauze eyepad (Right)
|
||||
|
||||
marking-GauzeMothUpperArmRight-gauze_moth_upperarm_r = Insectoid Gauze Forearm Wrap (Right)
|
||||
marking-GauzeMothUpperArmRight = Insectoid Gauze Forearm Wrap (Right)
|
||||
|
||||
marking-GauzeMothUpperArmLeft-gauze_moth_upperarm_l = Insectoid Gauze Forearm Wrap (Left)
|
||||
marking-GauzeMothUpperArmLeft = Insectoid Gauze Forearm Wrap (Left)
|
||||
|
||||
marking-GauzeMothUpperLegRight-gauze_moth_upperleg_r = Insectoid Gauze Thigh Wrap (Right)
|
||||
marking-GauzeMothUpperLegRight = Insectoid Insectoid Gauze Thigh Wrap (Right)
|
||||
|
||||
marking-GauzeMothUpperLegLeft-gauze_moth_upperleg_l = Insectoid Gauze Thigh Wrap (Left)
|
||||
marking-GauzeMothUpperLegLeft = Insectoid Gauze Thigh Wrap (Left)
|
||||
|
||||
marking-GauzeMothLowerLegRight-gauze_moth_lowerleg_r = Insectoid Gauze Shin Wrap (Right)
|
||||
marking-GauzeMothLowerLegRight = Insectoid Gauze Shin Wrap (Right)
|
||||
|
||||
marking-GauzeMothLowerLegLeft-gauze_moth_lowerleg_l = Insectoid Gauze Shin Wrap (Left)
|
||||
marking-GauzeMothLowerLegLeft = Insectoid Gauze Shin Wrap (Left)
|
||||
|
||||
marking-GauzeLizardRighteyePatch-gauze_lizardrighteye = Adjusted Gauze eyepatch (Right)
|
||||
marking-GauzeLizardRighteyePatch = Adjusted Gauze Eyepatch (Right)
|
||||
@@ -43,24 +43,5 @@ rcd-component-lighting = Lighting
|
||||
### Prototype names (note: constructable items will be puralized)
|
||||
|
||||
rcd-component-deconstruct = deconstruct
|
||||
rcd-component-wall-solid = solid wall
|
||||
rcd-component-floor-steel = steel tile
|
||||
rcd-component-plating = hull plate
|
||||
rcd-component-catwalk = catwalk
|
||||
rcd-component-wall-reinforced = reinforced wall
|
||||
rcd-component-grille = grille
|
||||
rcd-component-window = window
|
||||
rcd-component-window-directional = directional window
|
||||
rcd-component-window-reinforced-directional = directional reinforced window
|
||||
rcd-component-reinforced-window = reinforced window
|
||||
rcd-component-airlock = standard airlock
|
||||
rcd-component-airlock-glass = glass airlock
|
||||
rcd-component-firelock = firelock
|
||||
rcd-component-computer-frame = computer frame
|
||||
rcd-component-machine-frame = machine frame
|
||||
rcd-component-tube-light = light
|
||||
rcd-component-window-bulb-light = small light
|
||||
rcd-component-window-lv-cable = LV cable
|
||||
rcd-component-window-mv-cable = MV cable
|
||||
rcd-component-window-hv-cable = HV cable
|
||||
rcd-component-window-cable-terminal = cable terminal
|
||||
|
||||
@@ -7,6 +7,9 @@ reagent-desc-insect-blood = Okay, this is really gross. It almost looks.. alive?
|
||||
reagent-name-slime = slime
|
||||
reagent-desc-slime = You thought this was gradient blood at first, but you were mistaken.
|
||||
|
||||
reagent-name-sap = sap
|
||||
reagent-desc-sap = Sticky, sweet tree blood.
|
||||
|
||||
reagent-name-hemocyanin-blood = blue blood
|
||||
reagent-desc-hemocyanin-blood = Contains copper as opposed to iron which gives it a distinct blue color.
|
||||
|
||||
|
||||
@@ -39,3 +39,6 @@ reagent-desc-soysauce = A salty soy-based flavoring.
|
||||
|
||||
reagent-name-table-salt = table salt
|
||||
reagent-desc-table-salt = Commonly known as salt, Sodium Chloride is often used to season food or kill borers instantly.
|
||||
|
||||
reagent-name-syrup = syrup
|
||||
reagent-desc-syrup = Delicious syrup made from tree sap, somehow stickier than glue.
|
||||
|
||||
@@ -117,3 +117,6 @@ chatsan-replacement-42 = of course
|
||||
|
||||
chatsan-word-43 = ig
|
||||
chatsan-replacement-43 = i guess
|
||||
|
||||
chatsan-word-44 = tbf
|
||||
chatsan-replacement-44 = to be fair
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
marking-CPHumanFacialHair3Clock = Легкая щетина
|
||||
marking-CPHumanFacialHairAbe = Серьезная щетина
|
||||
marking-CPHumanFacialHairDwarf = Дворф
|
||||
11
Resources/Locale/ru-RU/_CP14/markings/human-hair.ftl
Normal file
11
Resources/Locale/ru-RU/_CP14/markings/human-hair.ftl
Normal file
@@ -0,0 +1,11 @@
|
||||
marking-CPHumanHair80s = По плечи
|
||||
marking-CPHumanHairA = Короткая стрижка
|
||||
marking-CPHumanHairAntenna = Непослушные пряди
|
||||
marking-CPHumanHairB = Скучный пробор
|
||||
marking-CPHumanHairBedhead = С бодуна
|
||||
marking-CPHumanHairBedheadV2 = С бодуна 2
|
||||
marking-CPHumanHairBeeHive = Аристократия в крови
|
||||
marking-CPHumanHairBigBraid = Хвост во весь рост
|
||||
marking-CPHumanHairBigDoubleBun = Два пунпона
|
||||
marking-CPHumanHairBigPompadour = Бард
|
||||
marking-CPHumanHairBob = Неприметливая
|
||||
7
Resources/Locale/ru-RU/game-ticking/forcemap-command.ftl
Normal file
7
Resources/Locale/ru-RU/game-ticking/forcemap-command.ftl
Normal file
@@ -0,0 +1,7 @@
|
||||
## Forcemap command loc.
|
||||
|
||||
forcemap-command-description = Заставляет игру начать с заданной карты в следующем раунде.
|
||||
forcemap-command-help = forcemap <map ID>
|
||||
forcemap-command-need-one-argument = forcemap принимает один аргумент — путь к файлу карты.
|
||||
forcemap-command-success = В следующем раунде игра принудительно начнется с карты { $map }.
|
||||
forcemap-command-arg-map = <map ID>
|
||||
@@ -0,0 +1,77 @@
|
||||
death-match-title = Смертельная битва
|
||||
death-match-description = Убейте всё, что движется!
|
||||
death-match-name-player = [bold]{ $name }[/bold] ([italic]{ $username }[/italic])
|
||||
death-match-name-npc = [bold]{ $name }[/bold]
|
||||
death-match-assist = { $primary }, с помощью { $secondary },
|
||||
death-match-kill-callout-0 = { CAPITALIZE($killer) } убил { $victim }!
|
||||
death-match-kill-callout-1 = { CAPITALIZE($killer) } завалил { $victim }!
|
||||
death-match-kill-callout-2 = { CAPITALIZE($killer) } фрагнул { $victim }!
|
||||
death-match-kill-callout-3 = { CAPITALIZE($killer) } разнёс { $victim }!
|
||||
death-match-kill-callout-4 = { CAPITALIZE($killer) } превратил { $victim } в фарш!
|
||||
death-match-kill-callout-5 = { CAPITALIZE($killer) } вальнул { $victim }!
|
||||
death-match-kill-callout-6 = { CAPITALIZE($killer) } перевернул и вытряхнул { $victim }!
|
||||
death-match-kill-callout-7 = { CAPITALIZE($killer) } испоганил { $victim }!
|
||||
death-match-kill-callout-8 = { CAPITALIZE($killer) } отправил { $victim } в ад!
|
||||
death-match-kill-callout-9 = { CAPITALIZE($killer) } станцевал на могиле { $victim }!
|
||||
death-match-kill-callout-10 = { CAPITALIZE($killer) } стёр с лица земли { $victim }!
|
||||
death-match-kill-callout-11 = { CAPITALIZE($killer) } переробастил { $victim }!
|
||||
death-match-kill-callout-12 = { CAPITALIZE($killer) } применил тулбокс на { $victim } и получил труп!
|
||||
death-match-kill-callout-13 = { CAPITALIZE($killer) } заставил { $victim } глотать пыль!
|
||||
death-match-kill-callout-14 = { CAPITALIZE($killer) } запостил компиляцию кринжа с { $victim }!
|
||||
death-match-kill-callout-15 = { CAPITALIZE($killer) } увидел, как { $victim } постит в #предложения!
|
||||
death-match-kill-callout-16 = { CAPITALIZE($killer) } Doom (1993)-нул { $victim }!
|
||||
death-match-kill-callout-17 = { CAPITALIZE($killer) } унизил { $victim }!
|
||||
death-match-kill-callout-18 = { CAPITALIZE($killer) } небезопасно извлёк флешку { $victim }!
|
||||
death-match-kill-callout-19 = { CAPITALIZE($killer) } удалил папку System32 с ПК { $victim }!
|
||||
death-match-kill-callout-20 = { CAPITALIZE($killer) } бвоинкнул { $victim }!
|
||||
death-match-kill-callout-21 = { CAPITALIZE($killer) } воткикнул { $victim } с острова!
|
||||
death-match-kill-callout-22 = { CAPITALIZE($killer) } воткикнул { $victim } потому что sus!
|
||||
death-match-kill-callout-23 = { CAPITALIZE($killer) } заставил { $victim } кодить для SS14!
|
||||
death-match-kill-callout-24 = { CAPITALIZE($killer) } заставил { $victim } кодить для OpenDream!
|
||||
death-match-kill-callout-25 = { CAPITALIZE($killer) } заставил { $victim } кодить для BYOND!
|
||||
death-match-kill-callout-26 = { CAPITALIZE($killer) } буквально 1984 { $victim }!
|
||||
death-match-kill-callout-27 = { CAPITALIZE($killer) } устроил экспресс-доставку { $victim } к Богу!
|
||||
death-match-kill-callout-28 = { CAPITALIZE($killer) } убил { $victim } насмешкой!
|
||||
death-match-kill-callout-29 = { CAPITALIZE($killer) } похвалил причёску { $victim }!
|
||||
death-match-kill-callout-30 = { CAPITALIZE($killer) } перевернул { $victim } в гробу!
|
||||
death-match-kill-callout-31 = { CAPITALIZE($killer) } столкнул { $victim } с лестницы!
|
||||
death-match-kill-callout-32 = { CAPITALIZE($killer) } устроил для { $victim } Укус '87!
|
||||
death-match-kill-callout-33 = { CAPITALIZE($killer) } увидел пост { $victim } на реддите!
|
||||
death-match-kill-callout-34 = { CAPITALIZE($killer) } зарепортил { $victim } админ-составу!
|
||||
death-match-kill-callout-35 = { CAPITALIZE($killer) } weh'нул { $victim }!
|
||||
death-match-kill-callout-36 = { CAPITALIZE($killer) } превратил { $victim } в ремейк SS13!
|
||||
death-match-kill-callout-37 = { CAPITALIZE($killer) } заставил { $victim } играть в Xonotic!
|
||||
death-match-kill-callout-38 = { CAPITALIZE($killer) } отправил { $victim } в Бразилию!
|
||||
death-match-kill-callout-39 = { CAPITALIZE($killer) } эпично хакнул { $victim }!
|
||||
death-match-kill-callout-40 = { CAPITALIZE($killer) } закрыл PR { $victim }!
|
||||
death-match-kill-callout-41 = { CAPITALIZE($killer) } увидел, как { $victim } мержит кринж в master!
|
||||
death-match-kill-callout-42 = { CAPITALIZE($killer) } наблюдал, как { $victim } постит сергалов на главной!
|
||||
death-match-kill-callout-43 = { CAPITALIZE($killer) } не обошёлся нежно с { $victim }!
|
||||
death-match-kill-callout-44 = { CAPITALIZE($killer) } шлёпнул { $victim }!
|
||||
death-match-kill-callout-45 = { CAPITALIZE($killer) } кокнул { $victim }!
|
||||
death-match-kill-callout-46 = { CAPITALIZE($killer) } встряхнул { $victim } перед тем, как пить!
|
||||
death-match-kill-callout-47 = { CAPITALIZE($killer) } водил пьяным и сбил { $victim }!
|
||||
death-match-kill-callout-48 = { CAPITALIZE($killer) } превратил { $victim } в продаваемую фигурку!
|
||||
death-match-kill-callout-49 = { CAPITALIZE($killer) } напомнил { $victim }, что он смертен!
|
||||
death-match-kill-callout-50 = { CAPITALIZE($killer) } ratio'd-нул { $victim }!
|
||||
death-match-kill-callout-51 = { CAPITALIZE($killer) } ctrl-alt-delete-нул { $victim }!
|
||||
death-match-kill-callout-52 = { CAPITALIZE($killer) } бонкнул { $victim }!
|
||||
death-match-kill-callout-53 = { CAPITALIZE($killer) } зароллил крит по { $victim }!
|
||||
death-match-kill-callout-54 = { CAPITALIZE($killer) } преподал { $victim } ценный урок!
|
||||
death-match-kill-callout-55 = { CAPITALIZE($killer) } совершил хоум-ран по { $victim }!
|
||||
death-match-kill-callout-56 = { CAPITALIZE($killer) } данк-нул { $victim }!
|
||||
death-match-kill-callout-57 = { CAPITALIZE($killer) } уничтожил { $victim } на стиле!
|
||||
death-match-kill-callout-58 = { CAPITALIZE($killer) } нагрубил { $victim }!
|
||||
death-match-kill-callout-59 = { CAPITALIZE($killer) } послал голосовое сообщение { $victim }!
|
||||
death-match-kill-callout-60 = { CAPITALIZE($killer) } столкнул { $victim } со ступенек!
|
||||
death-match-kill-callout-env-0 = { CAPITALIZE($victim) } потерял суть!
|
||||
death-match-kill-callout-env-1 = { CAPITALIZE($victim) } был унижен!
|
||||
death-match-kill-callout-env-2 = { CAPITALIZE($victim) } просто выглядел как идиот!
|
||||
death-match-kill-callout-env-3 = { CAPITALIZE($victim) } испытал skill issue!
|
||||
death-match-kill-callout-env-4 = { CAPITALIZE($victim) } выглядел очень глупо!
|
||||
death-match-kill-callout-env-5 = { CAPITALIZE($victim) } избавил себя от страданий!
|
||||
death-match-kill-callout-env-6 = { CAPITALIZE($victim) } устал от жизни!
|
||||
death-match-kill-callout-env-7 = { CAPITALIZE($victim) } недотрайхардил!
|
||||
death-match-kill-callout-env-8 = { CAPITALIZE($victim) } вынес себя с мусором!
|
||||
death-match-kill-callout-env-9 = { CAPITALIZE($victim) } накринжил!
|
||||
death-match-kill-callout-env-10 = { CAPITALIZE($victim) } довыпендривался!
|
||||
@@ -0,0 +1,2 @@
|
||||
extended-title = Расширенный
|
||||
extended-description = Спокойный игровой опыт. Потребуется вмешательство администраторов.
|
||||
@@ -0,0 +1,2 @@
|
||||
greenshift-title = Гриншифт
|
||||
greenshift-description = Пресет без событий, чтобы мероприятия админов проходили без помех.
|
||||
@@ -0,0 +1,2 @@
|
||||
sandbox-title = Песочница
|
||||
sandbox-description = Никакого стресса, только ваш креатив!
|
||||
@@ -0,0 +1,2 @@
|
||||
secret-title = Секрет
|
||||
secret-description = Это секрет для всех. Угрозы, с которыми вы сталкиваетесь, рандомизированы.
|
||||
@@ -0,0 +1,2 @@
|
||||
survival-title = Выживание
|
||||
survival-description = Внутренние угрозы отсутствуют, но как долго экспедиция сможет продержаться в обстановке все более разрушительных и частых событий?
|
||||
@@ -0,0 +1,3 @@
|
||||
rule-death-match-added-announcement = Теперь игра превратилась в бой насмерть. Убейте всех остальных, чтобы победить!
|
||||
rule-death-match-check-winner-stalemate = Все мертвы, это патовая ситуация!
|
||||
rule-death-match-check-winner = { $winner } побеждает в смертельном матче!
|
||||
@@ -0,0 +1,2 @@
|
||||
# Sent to admin chat
|
||||
rule-secret-selected-preset = Selected { $preset } for secret.
|
||||
15
Resources/Locale/ru-RU/game-ticking/game-rules/rules.ftl
Normal file
15
Resources/Locale/ru-RU/game-ticking/game-rules/rules.ftl
Normal file
@@ -0,0 +1,15 @@
|
||||
# General
|
||||
rule-restarting-in-seconds =
|
||||
Перезапуск через { $seconds } { $seconds ->
|
||||
[one] секунду
|
||||
[few] секунды
|
||||
*[other] секунд
|
||||
}.
|
||||
rule-time-has-run-out = Время вышло!
|
||||
# Respawning
|
||||
rule-respawn-in-seconds =
|
||||
Возрождение через { $second } { $second ->
|
||||
[one] секунду
|
||||
[few] секунды
|
||||
*[other] секунд
|
||||
}...
|
||||
46
Resources/Locale/ru-RU/game-ticking/game-ticker.ftl
Normal file
46
Resources/Locale/ru-RU/game-ticking/game-ticker.ftl
Normal file
@@ -0,0 +1,46 @@
|
||||
game-ticker-restart-round = Перезапуск раунда...
|
||||
game-ticker-start-round = Раунд начинается...
|
||||
game-ticker-start-round-cannot-start-game-mode-fallback = Не удалось запустить режим { $failedGameMode }! Запускаем { $fallbackMode }...
|
||||
game-ticker-start-round-cannot-start-game-mode-restart = Не удалось запустить режим { $failedGameMode }! Перезапуск раунда...
|
||||
game-ticker-start-round-invalid-map = Выбранная карта { $map } не подходит для игрового режима { $mode }. Игровой режим может не функционировать как задумано...
|
||||
game-ticker-unknown-role = Неизвестный
|
||||
game-ticker-delay-start = Начало раунда было отложено на { $seconds } секунд.
|
||||
game-ticker-pause-start = Начало раунда было приостановлено.
|
||||
game-ticker-pause-start-resumed = Отсчет начала раунда возобновлен.
|
||||
game-ticker-player-join-game-message = Добро пожаловать на ЭД ПРИДУМАЙ НАЗВАНИЕ! Если вы играете впервые, обязательно нажмите ESC на клавиатуре и прочитайте правила игры, а также не бойтесь просить помощи в "Админ помощь".
|
||||
game-ticker-get-info-text =
|
||||
Привет и добро пожаловать в [color=white]Space Station 14![/color]
|
||||
Текущий раунд: [color=white]#{ $roundId }[/color]
|
||||
Текущее количество игроков: [color=white]{ $playerCount }[/color]
|
||||
Текущая карта: [color=white]{ $mapName }[/color]
|
||||
Текущий режим игры: [color=white]{ $gmTitle }[/color]
|
||||
>[color=yellow]{ $desc }[/color]
|
||||
game-ticker-get-info-preround-text =
|
||||
Привет и добро пожаловать в [color=white]Space Station 14![/color]
|
||||
Текущий раунд: [color=white]#{ $roundId }[/color]
|
||||
Текущее количество игроков: [color=white]{ $playerCount }[/color] ([color=white]{ $readyCount }[/color] { $readyCount ->
|
||||
[one] готов
|
||||
*[other] готовы
|
||||
})
|
||||
Текущая карта: [color=white]{ $mapName }[/color]
|
||||
Текущий режим игры: [color=white]{ $gmTitle }[/color]
|
||||
>[color=yellow]{ $desc }[/color]
|
||||
game-ticker-no-map-selected = [color=red]Карта ещё не выбрана![/color]
|
||||
game-ticker-player-no-jobs-available-when-joining = При попытке присоединиться к игре ни одной роли не было доступно.
|
||||
# Displayed in chat to admins when a player joins
|
||||
player-join-message = Игрок { $name } зашёл!
|
||||
player-first-join-message = Игрок { $name } зашёл на сервер впервые.
|
||||
# Displayed in chat to admins when a player leaves
|
||||
player-leave-message = Игрок { $name } вышел!
|
||||
latejoin-arrival-announcement =
|
||||
{ $character } ({ $job }) { $gender ->
|
||||
[male] прибыл
|
||||
[female] прибыла
|
||||
[epicene] прибыли
|
||||
*[neuter] прибыл
|
||||
} на станцию!
|
||||
latejoin-arrival-sender = Станции
|
||||
latejoin-arrivals-direction = Вскоре прибудет шаттл, который доставит вас на станцию.
|
||||
latejoin-arrivals-direction-time = Шаттл, который доставит вас на станцию, прибудет через { $time }.
|
||||
preset-not-enough-ready-players = Не удалось запустить пресет { $presetName }. Требуется { $minimumPlayers } игроков, но готовы только { $readyPlayersCount }.
|
||||
preset-no-one-ready = Не удалось запустить режим { $presetName }. Нет готовых игроков.
|
||||
@@ -0,0 +1,4 @@
|
||||
set-game-preset-command-description = Установить игровой пресет для текущего раунда.
|
||||
set-game-preset-command-help-text = setgamepreset <id>
|
||||
set-game-preset-preset-error = Не удается найти игровой пресет "{ $preset }"
|
||||
set-game-preset-preset-set = Установить игровой пресет на "{ $preset }"
|
||||
@@ -5172,7 +5172,7 @@ entities:
|
||||
- type: Transform
|
||||
pos: 3.5,8.5
|
||||
parent: 179
|
||||
- proto: SpawnPointAdventurer
|
||||
- proto: CPSpawnPointAdventurer
|
||||
entities:
|
||||
- uid: 954
|
||||
components:
|
||||
@@ -984,7 +984,7 @@ entities:
|
||||
- type: Transform
|
||||
pos: -0.5,-0.5
|
||||
parent: 2
|
||||
- proto: SpawnPointAdventurer
|
||||
- proto: CPSpawnPointAdventurer
|
||||
entities:
|
||||
- uid: 99
|
||||
components:
|
||||
12334
Resources/Maps/core.yml
12334
Resources/Maps/core.yml
File diff suppressed because it is too large
Load Diff
@@ -424,3 +424,4 @@
|
||||
chatsan-word-41: chatsan-replacement-41
|
||||
chatsan-word-42: chatsan-replacement-42
|
||||
chatsan-word-43: chatsan-replacement-43
|
||||
chatsan-word-44: chatsan-replacement-44
|
||||
|
||||
@@ -20,7 +20,6 @@
|
||||
InconstancyParticle: 0.5
|
||||
FullUnknown: 0.5
|
||||
Jumping: 0.3
|
||||
Moving: 0.1
|
||||
#Complex
|
||||
FastUnknown: 0.2
|
||||
JumpingUnknown: 0.1
|
||||
@@ -133,19 +132,6 @@
|
||||
shuffleOnParticleHit: true
|
||||
prob: 0.8
|
||||
|
||||
- type: anomalyBehavior
|
||||
id: Moving
|
||||
earnPointModifier: 2.2
|
||||
description: anomaly-behavior-moving
|
||||
components:
|
||||
- type: RandomWalk
|
||||
minSpeed: 0
|
||||
maxSpeed: 0.3
|
||||
- type: CanMoveInAir
|
||||
- type: Physics
|
||||
bodyType: Dynamic
|
||||
bodyStatus: InAir
|
||||
|
||||
- type: anomalyBehavior
|
||||
id: Jumping
|
||||
earnPointModifier: 1.8
|
||||
|
||||
@@ -37,7 +37,7 @@
|
||||
- state: lung-l-slime
|
||||
- state: lung-r-slime
|
||||
- type: Lung
|
||||
Alert: LowNitrogen
|
||||
alert: LowNitrogen
|
||||
- type: Metabolizer
|
||||
removeEmpty: true
|
||||
solutionOnBody: false
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user