Merge remote-tracking branch 'refs/remotes/wizards/master' into upstream-sync

# Conflicts:
#	Content.Server/Connection/ConnectionManager.cs
#	Resources/Prototypes/Catalog/Fills/Lockers/heads.yml
#	Resources/Prototypes/Entities/Stations/base.yml
This commit is contained in:
Morb0
2024-09-01 22:20:47 +03:00
114 changed files with 2132 additions and 1586 deletions

View File

@@ -1,4 +1,4 @@
using Content.Shared.Administration.Notes;
using Content.Shared.Administration.Notes;
using Robust.Client.AutoGenerated;
using Robust.Client.UserInterface;
using Robust.Client.UserInterface.XAML;
@@ -13,7 +13,7 @@ public sealed partial class AdminMessagePopupMessage : Control
{
RobustXamlLoader.Load(this);
Admin.SetMessage(FormattedMessage.FromMarkup(Loc.GetString(
Admin.SetMessage(FormattedMessage.FromMarkupOrThrow(Loc.GetString(
"admin-notes-message-admin",
("admin", message.AdminName),
("date", message.AddedOn.ToLocalTime()))));

View File

@@ -49,7 +49,7 @@ public sealed partial class AdminMessagePopupWindow : Control
MessageContainer.AddChild(new AdminMessagePopupMessage(message));
}
Description.SetMessage(FormattedMessage.FromMarkup(Loc.GetString("admin-notes-message-desc", ("count", state.Messages.Length))));
Description.SetMessage(FormattedMessage.FromMarkupOrThrow(Loc.GetString("admin-notes-message-desc", ("count", state.Messages.Length))));
}
private void OnDismissButtonPressed(BaseButton.ButtonEventArgs obj)

View File

@@ -59,7 +59,7 @@ namespace Content.Client.Administration.UI.Bwoink
Unread++;
var formatted = new FormattedMessage(1);
formatted.AddMarkup($"[color=gray]{message.SentAt.ToShortTimeString()}[/color] {message.Text}");
formatted.AddMarkupOrThrow($"[color=gray]{message.SentAt.ToShortTimeString()}[/color] {message.Text}");
TextOutput.AddMessage(formatted);
LastMessage = message.SentAt;
}

View File

@@ -1,7 +1,5 @@
using Content.Shared.Anomaly;
using Content.Shared.Gravity;
using JetBrains.Annotations;
using Robust.Client.GameObjects;
using Robust.Client.UserInterface;
namespace Content.Client.Anomaly.Ui;

View File

@@ -131,13 +131,13 @@ public sealed partial class ChangelogTab : Control
Margin = new Thickness(6, 0, 0, 0),
};
authorLabel.SetMessage(
FormattedMessage.FromMarkup(Loc.GetString("changelog-author-changed", ("author", author))));
FormattedMessage.FromMarkupOrThrow(Loc.GetString("changelog-author-changed", ("author", author))));
ChangelogBody.AddChild(authorLabel);
foreach (var change in groupedEntry.SelectMany(c => c.Changes))
{
var text = new RichTextLabel();
text.SetMessage(FormattedMessage.FromMarkup(change.Message));
text.SetMessage(FormattedMessage.FromMarkupOrThrow(change.Message));
ChangelogBody.AddChild(new BoxContainer
{
Orientation = LayoutOrientation.Horizontal,

View File

@@ -180,7 +180,7 @@ namespace Content.Client.Chat.UI
var msg = new FormattedMessage();
if (fontColor != null)
msg.PushColor(fontColor.Value);
msg.AddMarkup(message);
msg.AddMarkupOrThrow(message);
return msg;
}

View File

@@ -1,6 +1,4 @@
using Content.Client.Actions;
using Content.Client.Actions;
using Content.Client.Mapping;
using Content.Shared.Administration;
using Robust.Shared.Console;

View File

@@ -145,7 +145,7 @@ namespace Content.Client.Credits
var text = _resourceManager.ContentFileReadAllText($"/Credits/{path}");
if (markup)
{
label.SetMessage(FormattedMessage.FromMarkup(text.Trim()));
label.SetMessage(FormattedMessage.FromMarkupOrThrow(text.Trim()));
}
else
{

View File

@@ -227,7 +227,7 @@ public sealed partial class CriminalRecordsConsoleWindow : FancyWindow
StatusOptionButton.SelectId((int) criminalRecord.Status);
if (criminalRecord.Reason is {} reason)
{
var message = FormattedMessage.FromMarkup(Loc.GetString("criminal-records-console-wanted-reason"));
var message = FormattedMessage.FromMarkupOrThrow(Loc.GetString("criminal-records-console-wanted-reason"));
message.AddText($": {reason}");
WantedReason.SetMessage(message);
WantedReason.Visible = true;

View File

@@ -1,4 +1,5 @@
using Content.Shared.Gravity;
using Content.Shared.Power;
using Robust.Client.GameObjects;
namespace Content.Client.Gravity;
@@ -21,7 +22,7 @@ public sealed partial class GravitySystem : SharedGravitySystem
if (args.Sprite == null)
return;
if (_appearanceSystem.TryGetData<GravityGeneratorStatus>(uid, GravityGeneratorVisuals.State, out var state, args.Component))
if (_appearanceSystem.TryGetData<PowerChargeStatus>(uid, PowerChargeVisuals.State, out var state, args.Component))
{
if (comp.SpriteMap.TryGetValue(state, out var spriteState))
{
@@ -30,7 +31,7 @@ public sealed partial class GravitySystem : SharedGravitySystem
}
}
if (_appearanceSystem.TryGetData<float>(uid, GravityGeneratorVisuals.Charge, out var charge, args.Component))
if (_appearanceSystem.TryGetData<float>(uid, PowerChargeVisuals.Charge, out var charge, args.Component))
{
var layer = args.Sprite.LayerMapGet(GravityGeneratorVisualLayers.Core);
switch (charge)

View File

@@ -1,38 +0,0 @@
using Content.Shared.Gravity;
using JetBrains.Annotations;
using Robust.Client.UserInterface;
namespace Content.Client.Gravity.UI
{
[UsedImplicitly]
public sealed class GravityGeneratorBoundUserInterface : BoundUserInterface
{
[ViewVariables]
private GravityGeneratorWindow? _window;
public GravityGeneratorBoundUserInterface(EntityUid owner, Enum uiKey) : base(owner, uiKey)
{
}
protected override void Open()
{
base.Open();
_window = this.CreateWindow<GravityGeneratorWindow>();
_window.SetEntity(Owner);
}
protected override void UpdateState(BoundUserInterfaceState state)
{
base.UpdateState(state);
var castState = (SharedGravityGeneratorComponent.GeneratorState) state;
_window?.UpdateState(castState);
}
public void SetPowerSwitch(bool on)
{
SendMessage(new SharedGravityGeneratorComponent.SwitchGeneratorMessage(on));
}
}
}

View File

@@ -1,75 +0,0 @@
using Content.Shared.Gravity;
using Robust.Client.AutoGenerated;
using Robust.Client.GameObjects;
using Robust.Client.UserInterface.Controls;
using Robust.Client.UserInterface.XAML;
using FancyWindow = Content.Client.UserInterface.Controls.FancyWindow;
namespace Content.Client.Gravity.UI
{
[GenerateTypedNameReferences]
public sealed partial class GravityGeneratorWindow : FancyWindow
{
private readonly ButtonGroup _buttonGroup = new();
public event Action<bool>? OnPowerSwitch;
public GravityGeneratorWindow()
{
RobustXamlLoader.Load(this);
IoCManager.InjectDependencies(this);
OnButton.Group = _buttonGroup;
OffButton.Group = _buttonGroup;
OnButton.OnPressed += _ => OnPowerSwitch?.Invoke(true);
OffButton.OnPressed += _ => OnPowerSwitch?.Invoke(false);
}
public void SetEntity(EntityUid uid)
{
EntityView.SetEntity(uid);
}
public void UpdateState(SharedGravityGeneratorComponent.GeneratorState state)
{
if (state.On)
OnButton.Pressed = true;
else
OffButton.Pressed = true;
PowerLabel.Text = Loc.GetString(
"gravity-generator-window-power-label",
("draw", state.PowerDraw),
("max", state.PowerDrawMax));
PowerLabel.SetOnlyStyleClass(MathHelper.CloseTo(state.PowerDraw, state.PowerDrawMax) ? "Good" : "Caution");
ChargeBar.Value = state.Charge;
ChargeText.Text = (state.Charge / 255f).ToString("P0");
StatusLabel.Text = Loc.GetString(state.PowerStatus switch
{
GravityGeneratorPowerStatus.Off => "gravity-generator-window-status-off",
GravityGeneratorPowerStatus.Discharging => "gravity-generator-window-status-discharging",
GravityGeneratorPowerStatus.Charging => "gravity-generator-window-status-charging",
GravityGeneratorPowerStatus.FullyCharged => "gravity-generator-window-status-fully-charged",
_ => throw new ArgumentOutOfRangeException()
});
StatusLabel.SetOnlyStyleClass(state.PowerStatus switch
{
GravityGeneratorPowerStatus.Off => "Danger",
GravityGeneratorPowerStatus.Discharging => "Caution",
GravityGeneratorPowerStatus.Charging => "Caution",
GravityGeneratorPowerStatus.FullyCharged => "Good",
_ => throw new ArgumentOutOfRangeException()
});
EtaLabel.Text = state.EtaSeconds >= 0
? Loc.GetString("gravity-generator-window-eta-value", ("left", TimeSpan.FromSeconds(state.EtaSeconds)))
: Loc.GetString("gravity-generator-window-eta-none");
EtaLabel.SetOnlyStyleClass(state.EtaSeconds >= 0 ? "Caution" : "Disabled");
}
}
}

View File

@@ -140,7 +140,7 @@ public sealed partial class GuideReagentEmbed : BoxContainer, IDocumentTag, ISea
var i = 0;
foreach (var effectString in effect.EffectDescriptions)
{
descMsg.AddMarkup(effectString);
descMsg.AddMarkupOrThrow(effectString);
i++;
if (i < descriptionsCount)
descMsg.PushNewline();
@@ -174,7 +174,7 @@ public sealed partial class GuideReagentEmbed : BoxContainer, IDocumentTag, ISea
var i = 0;
foreach (var effectString in guideEntryRegistryPlant.PlantMetabolisms)
{
descMsg.AddMarkup(effectString);
descMsg.AddMarkupOrThrow(effectString);
i++;
if (i < descriptionsCount)
descMsg.PushNewline();
@@ -195,7 +195,7 @@ public sealed partial class GuideReagentEmbed : BoxContainer, IDocumentTag, ISea
FormattedMessage description = new();
description.AddText(reagent.LocalizedDescription);
description.PushNewline();
description.AddMarkup(Loc.GetString("guidebook-reagent-physical-description",
description.AddMarkupOrThrow(Loc.GetString("guidebook-reagent-physical-description",
("description", reagent.LocalizedPhysicalDescription)));
ReagentDescription.SetMessage(description);
}

View File

@@ -155,7 +155,7 @@ public sealed partial class GuideReagentReaction : BoxContainer, ISearchableCont
var i = 0;
foreach (var (product, amount) in reagents.OrderByDescending(p => p.Value))
{
msg.AddMarkup(Loc.GetString("guidebook-reagent-recipes-reagent-display",
msg.AddMarkupOrThrow(Loc.GetString("guidebook-reagent-recipes-reagent-display",
("reagent", protoMan.Index<ReagentPrototype>(product).LocalizedName), ("ratio", amount)));
i++;
if (i < reagentCount)

View File

@@ -1,4 +1,4 @@
using Robust.Client.AutoGenerated;
using Robust.Client.AutoGenerated;
using Robust.Client.UserInterface.Controls;
using Robust.Client.UserInterface.XAML;
using Robust.Shared.Utility;
@@ -18,7 +18,7 @@ public sealed partial class InfoSection : BoxContainer
{
TitleLabel.Text = title;
if (markup)
Content.SetMessage(FormattedMessage.FromMarkup(text.Trim()));
Content.SetMessage(FormattedMessage.FromMarkupOrThrow(text.Trim()));
else
Content.SetMessage(text);
}

View File

@@ -24,7 +24,7 @@ namespace Content.Client.Info
}
public void SetInfoBlob(string markup)
{
_richTextLabel.SetMessage(FormattedMessage.FromMarkup(markup));
_richTextLabel.SetMessage(FormattedMessage.FromMarkupOrThrow(markup));
}
}
}

View File

@@ -15,7 +15,7 @@ public static class RichTextLabelExt
/// </remarks>
public static RichTextLabel SetMarkup(this RichTextLabel label, string markup)
{
label.SetMessage(FormattedMessage.FromMarkup(markup));
label.SetMessage(FormattedMessage.FromMarkupOrThrow(markup));
return label;
}

View File

@@ -1,4 +1,4 @@
using System.Diagnostics.CodeAnalysis;
using System.Diagnostics.CodeAnalysis;
using Content.Client.Lobby;
using Content.Shared.CCVar;
using Content.Shared.Players;
@@ -133,7 +133,7 @@ public sealed class JobRequirementsManager : ISharedPlaytimeManager
reasons.Add(jobReason.ToMarkup());
}
reason = reasons.Count == 0 ? null : FormattedMessage.FromMarkup(string.Join('\n', reasons));
reason = reasons.Count == 0 ? null : FormattedMessage.FromMarkupOrThrow(string.Join('\n', reasons));
return reason == null;
}

View File

@@ -0,0 +1,38 @@
using Content.Shared.Power;
using Robust.Client.UserInterface;
namespace Content.Client.Power.PowerCharge;
public sealed class PowerChargeBoundUserInterface : BoundUserInterface
{
[ViewVariables]
private PowerChargeWindow? _window;
public PowerChargeBoundUserInterface(EntityUid owner, Enum uiKey) : base(owner, uiKey)
{
}
public void SetPowerSwitch(bool on)
{
SendMessage(new SwitchChargingMachineMessage(on));
}
protected override void Open()
{
base.Open();
if (!EntMan.TryGetComponent(Owner, out PowerChargeComponent? component))
return;
_window = this.CreateWindow<PowerChargeWindow>();
_window.UpdateWindow(this, Loc.GetString(component.WindowTitle));
}
protected override void UpdateState(BoundUserInterfaceState state)
{
base.UpdateState(state);
if (state is not PowerChargeState chargeState)
return;
_window?.UpdateState(chargeState);
}
}

View File

@@ -0,0 +1,10 @@
using Content.Shared.Power;
namespace Content.Client.Power.PowerCharge;
/// <inheritdoc cref="Content.Shared.Power.SharedPowerChargeComponent" />
[RegisterComponent]
public sealed partial class PowerChargeComponent : SharedPowerChargeComponent
{
}

View File

@@ -1,27 +1,26 @@
<controls:FancyWindow xmlns="https://spacestation14.io"
xmlns:controls="clr-namespace:Content.Client.UserInterface.Controls"
Title="{Loc 'gravity-generator-window-title'}"
MinSize="270 130"
SetSize="360 180">
<BoxContainer Margin="4 0" Orientation="Horizontal">
<BoxContainer Orientation="Vertical" HorizontalExpand="True">
<GridContainer Margin="2 0 0 0" Columns="2">
<!-- Power -->
<Label Text="{Loc 'gravity-generator-window-power'}" HorizontalExpand="True" StyleClasses="StatusFieldTitle" />
<Label Text="{Loc 'power-charge-window-power'}" HorizontalExpand="True" StyleClasses="StatusFieldTitle" />
<BoxContainer Orientation="Horizontal" MinWidth="120">
<Button Name="OnButton" Text="{Loc 'gravity-generator-window-power-on'}" StyleClasses="OpenRight" />
<Button Name="OffButton" Text="{Loc 'gravity-generator-window-power-off'}" StyleClasses="OpenLeft" />
<Button Name="OnButton" Text="{Loc 'power-charge-window-power-on'}" StyleClasses="OpenRight" />
<Button Name="OffButton" Text="{Loc 'power-charge-window-power-off'}" StyleClasses="OpenLeft" />
</BoxContainer>
<Control /> <!-- Empty control to act as a spacer in the grid. -->
<Label Name="PowerLabel" Text="0 / 0 W" />
<!-- Status -->
<Label Text="{Loc 'gravity-generator-window-status'}" StyleClasses="StatusFieldTitle" />
<Label Name="StatusLabel" Text="{Loc 'gravity-generator-window-status-fully-charged'}" />
<Label Text="{Loc 'power-charge-window-status'}" StyleClasses="StatusFieldTitle" />
<Label Name="StatusLabel" Text="{Loc 'power-charge-window-status-fully-charged'}" />
<!-- ETA -->
<Label Text="{Loc 'gravity-generator-window-eta'}" StyleClasses="StatusFieldTitle" />
<Label Text="{Loc 'power-charge-window-eta'}" StyleClasses="StatusFieldTitle" />
<Label Name="EtaLabel" Text="N/A" />
<!-- Charge -->
<Label Text="{Loc 'gravity-generator-window-charge'}" StyleClasses="StatusFieldTitle" />
<Label Text="{Loc 'power-charge-window-charge'}" StyleClasses="StatusFieldTitle" />
<ProgressBar Name="ChargeBar" MaxValue="255">
<Label Name="ChargeText" Margin="4 0" Text="0 %" />
</ProgressBar>
@@ -31,5 +30,4 @@
<SpriteView Name="EntityView" SetSize="96 96" OverrideDirection="South" />
</PanelContainer>
</BoxContainer>
</controls:FancyWindow>

View File

@@ -0,0 +1,72 @@
using Content.Client.UserInterface.Controls;
using Content.Shared.Power;
using Robust.Client.AutoGenerated;
using Robust.Client.UserInterface.Controls;
using Robust.Client.UserInterface.XAML;
namespace Content.Client.Power.PowerCharge;
[GenerateTypedNameReferences]
public sealed partial class PowerChargeWindow : FancyWindow
{
private readonly ButtonGroup _buttonGroup = new();
public PowerChargeWindow()
{
RobustXamlLoader.Load(this);
OnButton.Group = _buttonGroup;
OffButton.Group = _buttonGroup;
}
public void UpdateWindow(PowerChargeBoundUserInterface bui, string title)
{
Title = title;
OnButton.OnPressed += _ => bui.SetPowerSwitch(true);
OffButton.OnPressed += _ => bui.SetPowerSwitch(false);
EntityView.SetEntity(bui.Owner);
}
public void UpdateState(PowerChargeState state)
{
if (state.On)
OnButton.Pressed = true;
else
OffButton.Pressed = true;
PowerLabel.Text = Loc.GetString(
"power-charge-window-power-label",
("draw", state.PowerDraw),
("max", state.PowerDrawMax));
PowerLabel.SetOnlyStyleClass(MathHelper.CloseTo(state.PowerDraw, state.PowerDrawMax) ? "Good" : "Caution");
ChargeBar.Value = state.Charge;
ChargeText.Text = (state.Charge / 255f).ToString("P0");
StatusLabel.Text = Loc.GetString(state.PowerStatus switch
{
PowerChargePowerStatus.Off => "power-charge-window-status-off",
PowerChargePowerStatus.Discharging => "power-charge-window-status-discharging",
PowerChargePowerStatus.Charging => "power-charge-window-status-charging",
PowerChargePowerStatus.FullyCharged => "power-charge-window-status-fully-charged",
_ => throw new ArgumentOutOfRangeException()
});
StatusLabel.SetOnlyStyleClass(state.PowerStatus switch
{
PowerChargePowerStatus.Off => "Danger",
PowerChargePowerStatus.Discharging => "Caution",
PowerChargePowerStatus.Charging => "Caution",
PowerChargePowerStatus.FullyCharged => "Good",
_ => throw new ArgumentOutOfRangeException()
});
EtaLabel.Text = state.EtaSeconds >= 0
? Loc.GetString("power-charge-window-eta-value", ("left", TimeSpan.FromSeconds(state.EtaSeconds)))
: Loc.GetString("power-charge-window-eta-none");
EtaLabel.SetOnlyStyleClass(state.EtaSeconds >= 0 ? "Caution" : "Disabled");
}
}

View File

@@ -309,7 +309,7 @@ public sealed partial class PowerMonitoringWindow
BorderThickness = new Thickness(2),
};
msg.AddMarkup(Loc.GetString("power-monitoring-window-rogue-power-consumer"));
msg.AddMarkupOrThrow(Loc.GetString("power-monitoring-window-rogue-power-consumer"));
SystemWarningPanel.Visible = true;
}
@@ -322,7 +322,7 @@ public sealed partial class PowerMonitoringWindow
BorderThickness = new Thickness(2),
};
msg.AddMarkup(Loc.GetString("power-monitoring-window-power-net-abnormalities"));
msg.AddMarkupOrThrow(Loc.GetString("power-monitoring-window-power-net-abnormalities"));
SystemWarningPanel.Visible = true;
}

View File

@@ -128,12 +128,12 @@ public sealed partial class RoboticsConsoleWindow : FancyWindow
};
var text = new FormattedMessage();
text.PushMarkup(Loc.GetString("robotics-console-model", ("name", model)));
text.AddMarkup(Loc.GetString("robotics-console-designation"));
text.AddMarkupOrThrow($"{Loc.GetString("robotics-console-model", ("name", model))}\n");
text.AddMarkupOrThrow(Loc.GetString("robotics-console-designation"));
text.AddText($" {data.Name}\n"); // prevent players trolling by naming borg [color=red]satan[/color]
text.PushMarkup(Loc.GetString("robotics-console-battery", ("charge", (int) (data.Charge * 100f)), ("color", batteryColor)));
text.PushMarkup(Loc.GetString("robotics-console-brain", ("brain", data.HasBrain)));
text.AddMarkup(Loc.GetString("robotics-console-modules", ("count", data.ModuleCount)));
text.AddMarkupOrThrow($"{Loc.GetString("robotics-console-battery", ("charge", (int)(data.Charge * 100f)), ("color", batteryColor))}\n");
text.AddMarkupOrThrow($"{Loc.GetString("robotics-console-brain", ("brain", data.HasBrain))}\n");
text.AddMarkupOrThrow(Loc.GetString("robotics-console-modules", ("count", data.ModuleCount)));
BorgInfo.SetMessage(text);
// how the turntables

View File

@@ -61,9 +61,9 @@ namespace Content.Client.RoundEnd
//Gamemode Name
var gamemodeLabel = new RichTextLabel();
var gamemodeMessage = new FormattedMessage();
gamemodeMessage.AddMarkup(Loc.GetString("round-end-summary-window-round-id-label", ("roundId", roundId)));
gamemodeMessage.AddMarkupOrThrow(Loc.GetString("round-end-summary-window-round-id-label", ("roundId", roundId)));
gamemodeMessage.AddText(" ");
gamemodeMessage.AddMarkup(Loc.GetString("round-end-summary-window-gamemode-name-label", ("gamemode", gamemode)));
gamemodeMessage.AddMarkupOrThrow(Loc.GetString("round-end-summary-window-gamemode-name-label", ("gamemode", gamemode)));
gamemodeLabel.SetMessage(gamemodeMessage);
roundEndSummaryContainer.AddChild(gamemodeLabel);

View File

@@ -1,4 +1,4 @@
using System.Numerics;
using System.Numerics;
using Content.Client.Actions.UI;
using Content.Client.Cooldown;
using Content.Shared.Alert;
@@ -69,8 +69,8 @@ namespace Content.Client.UserInterface.Systems.Alerts.Controls
private Control SupplyTooltip(Control? sender)
{
var msg = FormattedMessage.FromMarkup(Loc.GetString(Alert.Name));
var desc = FormattedMessage.FromMarkup(Loc.GetString(Alert.Description));
var msg = FormattedMessage.FromMarkupOrThrow(Loc.GetString(Alert.Name));
var desc = FormattedMessage.FromMarkupOrThrow(Loc.GetString(Alert.Description));
return new ActionAlertTooltip(msg, desc) {Cooldown = Cooldown};
}

View File

@@ -102,7 +102,7 @@ public partial class ChatBox : UIWidget
{
var formatted = new FormattedMessage(3);
formatted.PushColor(color);
formatted.AddMarkup(message);
formatted.AddMarkupOrThrow(message);
formatted.Pop();
Contents.AddMessage(formatted);
}

View File

@@ -2,10 +2,8 @@ using Content.Client.UserInterface.Controls;
using Content.Client.VendingMachines.UI;
using Content.Shared.VendingMachines;
using Robust.Client.UserInterface;
using Robust.Client.UserInterface.Controls;
using Robust.Shared.Input;
using System.Linq;
using Robust.Client.UserInterface;
namespace Content.Client.VendingMachines
{

View File

@@ -139,11 +139,11 @@ public sealed partial class AnalysisConsoleMenu : FancyWindow
{
if (state.Paused)
{
message.AddMarkup(Loc.GetString("analysis-console-info-scanner-paused"));
message.AddMarkupOrThrow(Loc.GetString("analysis-console-info-scanner-paused"));
}
else
{
message.AddMarkup(Loc.GetString("analysis-console-info-scanner"));
message.AddMarkupOrThrow(Loc.GetString("analysis-console-info-scanner"));
}
Information.SetMessage(message);
UpdateArtifactIcon(null); //set it to blank
@@ -155,11 +155,11 @@ public sealed partial class AnalysisConsoleMenu : FancyWindow
if (state.ScanReport == null)
{
if (!state.AnalyzerConnected) //no analyzer connected
message.AddMarkup(Loc.GetString("analysis-console-info-no-scanner"));
message.AddMarkupOrThrow(Loc.GetString("analysis-console-info-no-scanner"));
else if (!state.CanScan) //no artifact
message.AddMarkup(Loc.GetString("analysis-console-info-no-artifact"));
message.AddMarkupOrThrow(Loc.GetString("analysis-console-info-no-artifact"));
else if (state.Artifact == null) //ready to go
message.AddMarkup(Loc.GetString("analysis-console-info-ready"));
message.AddMarkupOrThrow(Loc.GetString("analysis-console-info-ready"));
}
else
{

View File

@@ -0,0 +1,8 @@
[assembly: Parallelizable(ParallelScope.Children)]
// I don't know why this parallelism limit was originally put here.
// I *do* know that I tried removing it, and ran into the following .NET runtime problem:
// https://github.com/dotnet/runtime/issues/107197
// So we can't really parallelize integration tests harder either until the runtime fixes that,
// *or* we fix serv3 to not spam expression trees.
[assembly: LevelOfParallelism(3)]

View File

@@ -23,8 +23,6 @@ using Robust.Shared.Prototypes;
using Robust.Shared.Timing;
using Robust.UnitTesting;
[assembly: LevelOfParallelism(3)]
namespace Content.IntegrationTests;
/// <summary>

View File

@@ -1,7 +1,4 @@

[assembly: Parallelizable(ParallelScope.Children)]
namespace Content.IntegrationTests;
namespace Content.IntegrationTests;
[SetUpFixture]
public sealed class PoolManagerTestEventHandler

View File

@@ -25,6 +25,9 @@ namespace Content.IntegrationTests.Tests.Gravity
id: WeightlessGravityGeneratorDummy
components:
- type: GravityGenerator
- type: PowerCharge
windowTitle: gravity-generator-window-title
idlePower: 50
chargeRate: 1000000000 # Set this really high so it discharges in a single tick.
activePower: 500
- type: ApcPowerReceiver

View File

@@ -21,6 +21,9 @@ namespace Content.IntegrationTests.Tests
id: GridGravityGeneratorDummy
components:
- type: GravityGenerator
- type: PowerCharge
windowTitle: gravity-generator-window-title
idlePower: 50
chargeRate: 1000000000 # Set this really high so it discharges in a single tick.
activePower: 500
- type: ApcPowerReceiver

View File

@@ -658,7 +658,7 @@ public record struct CommandPermissionsUnassignedError(CommandSpec Command) : IC
{
public FormattedMessage DescribeInner()
{
return FormattedMessage.FromMarkup($"The command {Command.FullName()} is missing permission flags and cannot be executed.");
return FormattedMessage.FromMarkupOrThrow($"The command {Command.FullName()} is missing permission flags and cannot be executed.");
}
public string? Expression { get; set; }
@@ -671,7 +671,7 @@ public record struct NoPermissionError(CommandSpec Command) : IConError
{
public FormattedMessage DescribeInner()
{
return FormattedMessage.FromMarkup($"You do not have permission to execute {Command.FullName()}");
return FormattedMessage.FromMarkupOrThrow($"You do not have permission to execute {Command.FullName()}");
}
public string? Expression { get; set; }

View File

@@ -1,5 +1,4 @@
using Content.Server.Anomaly.Components;
using Content.Server.Power.Components;
using Content.Server.Power.EntitySystems;
using Content.Server.Station.Components;
using Content.Shared.Anomaly;
@@ -11,10 +10,7 @@ using Content.Shared.Physics;
using Robust.Shared.Map.Components;
using Robust.Shared.Physics;
using Robust.Shared.Physics.Components;
using Robust.Shared.Map;
using System.Numerics;
using Content.Shared.Power;
using Robust.Server.GameObjects;
namespace Content.Server.Anomaly;
@@ -115,7 +111,7 @@ public sealed partial class AnomalySystem
var valid = true;
// TODO: This should be using static lookup.
foreach (var ent in gridComp.GetAnchoredEntities(tile))
foreach (var ent in _mapSystem.GetAnchoredEntities(grid, gridComp, tile))
{
if (!physQuery.TryGetComponent(ent, out var body))
continue;
@@ -131,10 +127,10 @@ public sealed partial class AnomalySystem
continue;
var pos = _mapSystem.GridTileToLocal(grid, gridComp, tile);
var mapPos = pos.ToMap(EntityManager, _transform);
var mapPos = _transform.ToMapCoordinates(pos);
// don't spawn in AntiAnomalyZones
var antiAnomalyZonesQueue = AllEntityQuery<AntiAnomalyZoneComponent, TransformComponent>();
while (antiAnomalyZonesQueue.MoveNext(out var uid, out var zone, out var antiXform))
while (antiAnomalyZonesQueue.MoveNext(out _, out var zone, out var antiXform))
{
if (antiXform.MapID != mapPos.MapId)
continue;

View File

@@ -119,12 +119,12 @@ public sealed partial class CargoSystem
msg.PushNewline();
foreach (var entry in prototype.Entries)
{
msg.AddMarkup($"- {Loc.GetString("bounty-console-manifest-entry",
msg.AddMarkupOrThrow($"- {Loc.GetString("bounty-console-manifest-entry",
("amount", entry.Amount),
("item", Loc.GetString(entry.Name)))}");
msg.PushNewline();
}
msg.AddMarkup(Loc.GetString("bounty-console-manifest-reward", ("reward", prototype.Reward)));
msg.AddMarkupOrThrow(Loc.GetString("bounty-console-manifest-reward", ("reward", prototype.Reward)));
_paperSystem.SetContent((uid, paper), msg.ToMarkup());
}

View File

@@ -67,11 +67,6 @@ public sealed partial class CargoSystem
private void OnPalletUIOpen(EntityUid uid, CargoPalletConsoleComponent component, BoundUIOpenedEvent args)
{
var player = args.Actor;
if (player == null)
return;
UpdatePalletConsoleInterface(uid);
}
@@ -85,11 +80,6 @@ public sealed partial class CargoSystem
private void OnPalletAppraise(EntityUid uid, CargoPalletConsoleComponent component, CargoPalletAppraiseMessage args)
{
var player = args.Actor;
if (player == null)
return;
UpdatePalletConsoleInterface(uid);
}
@@ -313,11 +303,6 @@ public sealed partial class CargoSystem
private void OnPalletSale(EntityUid uid, CargoPalletConsoleComponent component, CargoPalletSellMessage args)
{
var player = args.Actor;
if (player == null)
return;
var xform = Transform(uid);
if (xform.GridUid is not EntityUid gridUid)

View File

@@ -499,7 +499,7 @@ public sealed partial class ChatSystem : SharedChatSystem
if (!_actionBlocker.CanSpeak(source) && !ignoreActionBlocker)
return;
var message = TransformSpeech(source, FormattedMessage.RemoveMarkup(originalMessage));
var message = TransformSpeech(source, FormattedMessage.RemoveMarkupOrThrow(originalMessage));
if (message.Length == 0)
return;
@@ -597,7 +597,7 @@ public sealed partial class ChatSystem : SharedChatSystem
var wrappedMessage = Loc.GetString("chat-manager-entity-me-wrap-message",
("entityName", name),
("entity", ent),
("message", FormattedMessage.RemoveMarkup(action)));
("message", FormattedMessage.RemoveMarkupOrThrow(action)));
if (checkEmote)
TryEmoteChatInput(source, action);

View File

@@ -1,11 +1,7 @@
using System.Collections.Immutable;
using System.Linq;
using System.Text.Json.Nodes;
using System.Threading.Tasks;
using Content.Server.Connection.Whitelist;
using Content.Server.Connection.Whitelist.Conditions;
using System.Runtime.InteropServices;
using System.Threading.Tasks;
using Content.Corvax.Interfaces.Server;
using Content.Corvax.Interfaces.Shared;
using Content.Server.Chat.Managers;

View File

@@ -1,4 +1,4 @@
using Content.Shared.Examine;
using Content.Shared.Examine;
using Content.Shared.IdentityManagement;
using Content.Shared.Verbs;
using Robust.Shared.Utility;
@@ -28,7 +28,7 @@ namespace Content.Server.DetailExaminable
Act = () =>
{
var markup = new FormattedMessage();
markup.AddMarkup(component.Content);
markup.AddMarkupOrThrow(component.Content);
_examineSystem.SendExamineTooltip(args.User, uid, markup, false, false);
},
Text = Loc.GetString("detail-examinable-verb-text"),

View File

@@ -71,7 +71,7 @@ public sealed class DragonRiftSystem : EntitySystem
Dirty(uid, comp);
var msg = Loc.GetString("carp-rift-warning",
("location", FormattedMessage.RemoveMarkup(_navMap.GetNearestBeaconString((uid, xform)))));
("location", FormattedMessage.RemoveMarkupOrThrow(_navMap.GetNearestBeaconString((uid, xform)))));
_chat.DispatchGlobalAnnouncement(msg, playSound: false, colorOverride: Color.Red);
_audio.PlayGlobal("/Audio/Misc/notice1.ogg", Filter.Broadcast(), true);
_navMap.SetBeaconEnabled(uid, true);

View File

@@ -2,7 +2,6 @@ using Content.Server.Body.Components;
using Content.Shared.Atmos;
using Content.Shared.EntityEffects;
using Robust.Shared.Prototypes;
using Content.Shared.EntityEffects;
namespace Content.Server.EntityEffects.Effects;

View File

@@ -4,7 +4,6 @@ using Content.Shared.EntityEffects;
using Content.Shared.Polymorph;
using Robust.Shared.Prototypes;
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype;
using Content.Shared.EntityEffects;
namespace Content.Server.EntityEffects.Effects;

View File

@@ -211,7 +211,7 @@ namespace Content.Server.Explosion.EntitySystems
return;
// Gets location of the implant
var posText = FormattedMessage.RemoveMarkup(_navMap.GetNearestBeaconString(uid));
var posText = FormattedMessage.RemoveMarkupOrThrow(_navMap.GetNearestBeaconString(uid));
var critMessage = Loc.GetString(component.CritMessage, ("user", implanted.ImplantedEntity.Value), ("position", posText));
var deathMessage = Loc.GetString(component.DeathMessage, ("user", implanted.ImplantedEntity.Value), ("position", posText));

View File

@@ -138,7 +138,7 @@ public sealed class GatewayGeneratorSystem : EntitySystem
// Create the gateway.
var gatewayUid = SpawnAtPosition(generator.Proto, originCoords);
var gatewayComp = Comp<GatewayComponent>(gatewayUid);
_gateway.SetDestinationName(gatewayUid, FormattedMessage.FromMarkup($"[color=#D381C996]{gatewayName}[/color]"), gatewayComp);
_gateway.SetDestinationName(gatewayUid, FormattedMessage.FromMarkupOrThrow($"[color=#D381C996]{gatewayName}[/color]"), gatewayComp);
_gateway.SetEnabled(gatewayUid, true, gatewayComp);
generator.Generated.Add(mapUid);
}

View File

@@ -8,42 +8,13 @@ namespace Content.Server.Gravity
[Access(typeof(GravityGeneratorSystem))]
public sealed partial class GravityGeneratorComponent : SharedGravityGeneratorComponent
{
// 1% charge per second.
[ViewVariables(VVAccess.ReadWrite)] [DataField("chargeRate")] public float ChargeRate { get; set; } = 0.01f;
// The gravity generator has two power values.
// Idle power is assumed to be the power needed to run the control systems and interface.
[DataField("idlePower")] public float IdlePowerUse { get; set; }
// Active power is the power needed to keep the gravity field stable.
[DataField("activePower")] public float ActivePowerUse { get; set; }
[DataField("lightRadiusMin")] public float LightRadiusMin { get; set; }
[DataField("lightRadiusMax")] public float LightRadiusMax { get; set; }
/// <summary>
/// Is the power switch on?
/// </summary>
[DataField("switchedOn")]
public bool SwitchedOn { get; set; } = true;
/// <summary>
/// Is the gravity generator intact?
/// </summary>
[DataField("intact")]
public bool Intact { get; set; } = true;
[DataField("maxCharge")]
public float MaxCharge { get; set; } = 1;
// 0 -> 1
[ViewVariables(VVAccess.ReadWrite)] [DataField("charge")] public float Charge { get; set; } = 1;
/// <summary>
/// Is the gravity generator currently "producing" gravity?
/// </summary>
[ViewVariables]
public bool GravityActive { get; set; } = false;
// Do we need a UI update even if the charge doesn't change? Used by power button.
[ViewVariables] public bool NeedUIUpdate { get; set; }
}
}

View File

@@ -1,290 +1,63 @@
using Content.Server.Administration.Logs;
using Content.Server.Audio;
using Content.Server.Power.Components;
using Content.Shared.Database;
using Content.Server.Power.EntitySystems;
using Content.Shared.Gravity;
using Content.Shared.Interaction;
using Robust.Server.GameObjects;
using Robust.Shared.Player;
namespace Content.Server.Gravity
namespace Content.Server.Gravity;
public sealed class GravityGeneratorSystem : EntitySystem
{
public sealed class GravityGeneratorSystem : EntitySystem
[Dependency] private readonly GravitySystem _gravitySystem = default!;
[Dependency] private readonly SharedPointLightSystem _lights = default!;
public override void Initialize()
{
[Dependency] private readonly IAdminLogManager _adminLogger = default!;
[Dependency] private readonly AmbientSoundSystem _ambientSoundSystem = default!;
[Dependency] private readonly GravitySystem _gravitySystem = default!;
[Dependency] private readonly SharedAppearanceSystem _appearance = default!;
[Dependency] private readonly SharedPointLightSystem _lights = default!;
[Dependency] private readonly UserInterfaceSystem _uiSystem = default!;
base.Initialize();
public override void Initialize()
SubscribeLocalEvent<GravityGeneratorComponent, EntParentChangedMessage>(OnParentChanged);
SubscribeLocalEvent<GravityGeneratorComponent, ChargedMachineActivatedEvent>(OnActivated);
SubscribeLocalEvent<GravityGeneratorComponent, ChargedMachineDeactivatedEvent>(OnDeactivated);
}
public override void Update(float frameTime)
{
base.Update(frameTime);
var query = EntityQueryEnumerator<GravityGeneratorComponent, PowerChargeComponent>();
while (query.MoveNext(out var uid, out var grav, out var charge))
{
base.Initialize();
if (!_lights.TryGetLight(uid, out var pointLight))
continue;
SubscribeLocalEvent<GravityGeneratorComponent, ComponentInit>(OnCompInit);
SubscribeLocalEvent<GravityGeneratorComponent, ComponentShutdown>(OnComponentShutdown);
SubscribeLocalEvent<GravityGeneratorComponent, EntParentChangedMessage>(OnParentChanged); // Or just anchor changed?
SubscribeLocalEvent<GravityGeneratorComponent, InteractHandEvent>(OnInteractHand);
SubscribeLocalEvent<GravityGeneratorComponent, SharedGravityGeneratorComponent.SwitchGeneratorMessage>(
OnSwitchGenerator);
_lights.SetEnabled(uid, charge.Charge > 0, pointLight);
_lights.SetRadius(uid, MathHelper.Lerp(grav.LightRadiusMin, grav.LightRadiusMax, charge.Charge),
pointLight);
}
}
private void OnParentChanged(EntityUid uid, GravityGeneratorComponent component, ref EntParentChangedMessage args)
private void OnActivated(Entity<GravityGeneratorComponent> ent, ref ChargedMachineActivatedEvent args)
{
ent.Comp.GravityActive = true;
if (TryComp<TransformComponent>(ent, out var xform) &&
TryComp(xform.ParentUid, out GravityComponent? gravity))
{
if (component.GravityActive && TryComp(args.OldParent, out GravityComponent? gravity))
{
_gravitySystem.RefreshGravity(args.OldParent.Value, gravity);
}
_gravitySystem.EnableGravity(xform.ParentUid, gravity);
}
}
private void OnComponentShutdown(EntityUid uid, GravityGeneratorComponent component, ComponentShutdown args)
private void OnDeactivated(Entity<GravityGeneratorComponent> ent, ref ChargedMachineDeactivatedEvent args)
{
ent.Comp.GravityActive = false;
if (TryComp<TransformComponent>(ent, out var xform) &&
TryComp(xform.ParentUid, out GravityComponent? gravity))
{
if (component.GravityActive &&
TryComp(uid, out TransformComponent? xform) &&
TryComp(xform.ParentUid, out GravityComponent? gravity))
{
component.GravityActive = false;
_gravitySystem.RefreshGravity(xform.ParentUid, gravity);
}
_gravitySystem.RefreshGravity(xform.ParentUid, gravity);
}
}
public override void Update(float frameTime)
private void OnParentChanged(EntityUid uid, GravityGeneratorComponent component, ref EntParentChangedMessage args)
{
if (component.GravityActive && TryComp(args.OldParent, out GravityComponent? gravity))
{
base.Update(frameTime);
var query = EntityQueryEnumerator<GravityGeneratorComponent, ApcPowerReceiverComponent>();
while (query.MoveNext(out var uid, out var gravGen, out var powerReceiver))
{
var ent = (uid, gravGen, powerReceiver);
if (!gravGen.Intact)
continue;
// Calculate charge rate based on power state and such.
// Negative charge rate means discharging.
float chargeRate;
if (gravGen.SwitchedOn)
{
if (powerReceiver.Powered)
{
chargeRate = gravGen.ChargeRate;
}
else
{
// Scale discharge rate such that if we're at 25% active power we discharge at 75% rate.
var receiving = powerReceiver.PowerReceived;
var mainSystemPower = Math.Max(0, receiving - gravGen.IdlePowerUse);
var ratio = 1 - mainSystemPower / (gravGen.ActivePowerUse - gravGen.IdlePowerUse);
chargeRate = -(ratio * gravGen.ChargeRate);
}
}
else
{
chargeRate = -gravGen.ChargeRate;
}
var active = gravGen.GravityActive;
var lastCharge = gravGen.Charge;
gravGen.Charge = Math.Clamp(gravGen.Charge + frameTime * chargeRate, 0, gravGen.MaxCharge);
if (chargeRate > 0)
{
// Charging.
if (MathHelper.CloseTo(gravGen.Charge, gravGen.MaxCharge) && !gravGen.GravityActive)
{
gravGen.GravityActive = true;
}
}
else
{
// Discharging
if (MathHelper.CloseTo(gravGen.Charge, 0) && gravGen.GravityActive)
{
gravGen.GravityActive = false;
}
}
var updateUI = gravGen.NeedUIUpdate;
if (!MathHelper.CloseTo(lastCharge, gravGen.Charge))
{
UpdateState(ent);
updateUI = true;
}
if (updateUI)
UpdateUI(ent, chargeRate);
if (active != gravGen.GravityActive &&
TryComp(uid, out TransformComponent? xform) &&
TryComp<GravityComponent>(xform.ParentUid, out var gravity))
{
// Force it on in the faster path.
if (gravGen.GravityActive)
{
_gravitySystem.EnableGravity(xform.ParentUid, gravity);
}
else
{
_gravitySystem.RefreshGravity(xform.ParentUid, gravity);
}
}
}
}
private void SetSwitchedOn(EntityUid uid, GravityGeneratorComponent component, bool on,
ApcPowerReceiverComponent? powerReceiver = null, EntityUid? user = null)
{
if (!Resolve(uid, ref powerReceiver))
return;
if (user != null)
_adminLogger.Add(LogType.Action, on ? LogImpact.Medium : LogImpact.High, $"{ToPrettyString(user)} set ${ToPrettyString(uid):target} to {(on ? "on" : "off")}");
component.SwitchedOn = on;
UpdatePowerState(component, powerReceiver);
component.NeedUIUpdate = true;
}
private static void UpdatePowerState(
GravityGeneratorComponent component,
ApcPowerReceiverComponent powerReceiver)
{
powerReceiver.Load = component.SwitchedOn ? component.ActivePowerUse : component.IdlePowerUse;
}
private void UpdateUI(Entity<GravityGeneratorComponent, ApcPowerReceiverComponent> ent, float chargeRate)
{
var (_, component, powerReceiver) = ent;
if (!_uiSystem.IsUiOpen(ent.Owner, SharedGravityGeneratorComponent.GravityGeneratorUiKey.Key))
return;
var chargeTarget = chargeRate < 0 ? 0 : component.MaxCharge;
short chargeEta;
var atTarget = false;
if (MathHelper.CloseTo(component.Charge, chargeTarget))
{
chargeEta = short.MinValue; // N/A
atTarget = true;
}
else
{
var diff = chargeTarget - component.Charge;
chargeEta = (short) Math.Abs(diff / chargeRate);
}
var status = chargeRate switch
{
> 0 when atTarget => GravityGeneratorPowerStatus.FullyCharged,
< 0 when atTarget => GravityGeneratorPowerStatus.Off,
> 0 => GravityGeneratorPowerStatus.Charging,
< 0 => GravityGeneratorPowerStatus.Discharging,
_ => throw new ArgumentOutOfRangeException()
};
var state = new SharedGravityGeneratorComponent.GeneratorState(
component.SwitchedOn,
(byte) (component.Charge * 255),
status,
(short) Math.Round(powerReceiver.PowerReceived),
(short) Math.Round(powerReceiver.Load),
chargeEta
);
_uiSystem.SetUiState(
ent.Owner,
SharedGravityGeneratorComponent.GravityGeneratorUiKey.Key,
state);
component.NeedUIUpdate = false;
}
private void OnCompInit(Entity<GravityGeneratorComponent> ent, ref ComponentInit args)
{
ApcPowerReceiverComponent? powerReceiver = null;
if (!Resolve(ent, ref powerReceiver, false))
return;
UpdatePowerState(ent, powerReceiver);
UpdateState((ent, ent.Comp, powerReceiver));
}
private void OnInteractHand(EntityUid uid, GravityGeneratorComponent component, InteractHandEvent args)
{
ApcPowerReceiverComponent? powerReceiver = default!;
if (!Resolve(uid, ref powerReceiver))
return;
// Do not allow opening UI if broken or unpowered.
if (!component.Intact || powerReceiver.PowerReceived < component.IdlePowerUse)
return;
_uiSystem.OpenUi(uid, SharedGravityGeneratorComponent.GravityGeneratorUiKey.Key, args.User);
component.NeedUIUpdate = true;
}
public void UpdateState(Entity<GravityGeneratorComponent, ApcPowerReceiverComponent> ent)
{
var (uid, grav, powerReceiver) = ent;
var appearance = EntityManager.GetComponentOrNull<AppearanceComponent>(uid);
_appearance.SetData(uid, GravityGeneratorVisuals.Charge, grav.Charge, appearance);
if (_lights.TryGetLight(uid, out var pointLight))
{
_lights.SetEnabled(uid, grav.Charge > 0, pointLight);
_lights.SetRadius(uid, MathHelper.Lerp(grav.LightRadiusMin, grav.LightRadiusMax, grav.Charge), pointLight);
}
if (!grav.Intact)
{
MakeBroken((uid, grav), appearance);
}
else if (powerReceiver.PowerReceived < grav.IdlePowerUse)
{
MakeUnpowered((uid, grav), appearance);
}
else if (!grav.SwitchedOn)
{
MakeOff((uid, grav), appearance);
}
else
{
MakeOn((uid, grav), appearance);
}
}
private void MakeBroken(Entity<GravityGeneratorComponent> ent, AppearanceComponent? appearance)
{
_ambientSoundSystem.SetAmbience(ent, false);
_appearance.SetData(ent, GravityGeneratorVisuals.State, GravityGeneratorStatus.Broken);
}
private void MakeUnpowered(Entity<GravityGeneratorComponent> ent, AppearanceComponent? appearance)
{
_ambientSoundSystem.SetAmbience(ent, false);
_appearance.SetData(ent, GravityGeneratorVisuals.State, GravityGeneratorStatus.Unpowered, appearance);
}
private void MakeOff(Entity<GravityGeneratorComponent> ent, AppearanceComponent? appearance)
{
_ambientSoundSystem.SetAmbience(ent, false);
_appearance.SetData(ent, GravityGeneratorVisuals.State, GravityGeneratorStatus.Off, appearance);
}
private void MakeOn(Entity<GravityGeneratorComponent> ent, AppearanceComponent? appearance)
{
_ambientSoundSystem.SetAmbience(ent, true);
_appearance.SetData(ent, GravityGeneratorVisuals.State, GravityGeneratorStatus.On, appearance);
}
private void OnSwitchGenerator(
EntityUid uid,
GravityGeneratorComponent component,
SharedGravityGeneratorComponent.SwitchGeneratorMessage args)
{
SetSwitchedOn(uid, component, args.On, user: args.Actor);
_gravitySystem.RefreshGravity(args.OldParent.Value, gravity);
}
}
}

View File

@@ -124,7 +124,7 @@ namespace Content.Server.Nuke
}
codesMessage.PushNewline();
codesMessage.AddMarkup(Loc.GetString("nuke-codes-list", ("name", MetaData(nukeUid).EntityName), ("code", nuke.Code)));
codesMessage.AddMarkupOrThrow(Loc.GetString("nuke-codes-list", ("name", MetaData(nukeUid).EntityName), ("code", nuke.Code)));
break;
}

View File

@@ -461,7 +461,7 @@ public sealed class NukeSystem : EntitySystem
// warn a crew
var announcement = Loc.GetString("nuke-component-announcement-armed",
("time", (int) component.RemainingTime),
("location", FormattedMessage.RemoveMarkup(_navMap.GetNearestBeaconString((uid, nukeXform)))));
("location", FormattedMessage.RemoveMarkupOrThrow(_navMap.GetNearestBeaconString((uid, nukeXform)))));
var sender = Loc.GetString("nuke-component-announcement-sender");
_chatSystem.DispatchStationAnnouncement(stationUid ?? uid, announcement, sender, false, null, Color.Red);

View File

@@ -1,4 +1,4 @@
using System.Linq;
using System.Linq;
using Content.Shared.FixedPoint;
using Content.Shared.Points;
using JetBrains.Annotations;
@@ -76,7 +76,7 @@ public sealed class PointSystem : SharedPointSystem
if (!_player.TryGetPlayerData(id, out var data))
continue;
msg.AddMarkup(Loc.GetString("point-scoreboard-list",
msg.AddMarkupOrThrow(Loc.GetString("point-scoreboard-list",
("place", place),
("name", data.UserName),
("points", points.Int())));

View File

@@ -0,0 +1,66 @@
using Content.Server.Power.EntitySystems;
using Content.Shared.Power;
namespace Content.Server.Power.Components;
/// <inheritdoc cref="Content.Shared.Power.SharedPowerChargeComponent" />
[RegisterComponent]
[Access(typeof(PowerChargeSystem))]
public sealed partial class PowerChargeComponent : SharedPowerChargeComponent
{
/// <summary>
/// Change in charge per second.
/// </summary>
[DataField]
public float ChargeRate { get; set; } = 0.01f;
/// <summary>
/// Baseline power that this machine consumes.
/// </summary>
[DataField("idlePower")]
public float IdlePowerUse { get; set; }
/// <summary>
/// Power consumed when <see cref="SwitchedOn"/> is true.
/// </summary>
[DataField("activePower")]
public float ActivePowerUse { get; set; }
/// <summary>
/// Is the gravity generator intact?
/// </summary>
[DataField]
public bool Intact { get; set; } = true;
/// <summary>
/// Is the power switch on?
/// </summary>
[DataField]
public bool SwitchedOn { get; set; } = true;
/// <summary>
/// Whether or not the power is switched on and the entity has charged up.
/// </summary>
[DataField]
public bool Active { get; set; }
[DataField]
public float MaxCharge { get; set; } = 1;
/// <summary>
/// The UI key of the UI that's used with this machine.<br/>
/// This is used to allow machine power charging to be integrated into any ui
/// </summary>
[DataField, ViewVariables(VVAccess.ReadOnly)]
public Enum UiKey { get; set; } = PowerChargeUiKey.Key;
/// <summary>
/// Current charge value.
/// Goes from 0 to 1.
/// </summary>
[DataField]
public float Charge { get; set; } = 1;
[ViewVariables]
public bool NeedUIUpdate { get; set; }
}

View File

@@ -31,7 +31,7 @@ namespace Content.Server.Power.EntitySystems
if (args.Handled || args.Target == null || !args.CanReach || !_toolSystem.HasQuality(args.Used, SharedToolSystem.PulseQuality))
return;
var markup = FormattedMessage.FromMarkup(GenerateCableMarkup(uid));
var markup = FormattedMessage.FromMarkupOrThrow(GenerateCableMarkup(uid));
_examineSystem.SendExamineTooltip(args.User, uid, markup, false, false);
args.Handled = true;
}
@@ -56,7 +56,7 @@ namespace Content.Server.Power.EntitySystems
Icon = new SpriteSpecifier.Texture(new ("/Textures/Interface/VerbIcons/zap.svg.192dpi.png")),
Act = () =>
{
var markup = FormattedMessage.FromMarkup(GenerateCableMarkup(uid));
var markup = FormattedMessage.FromMarkupOrThrow(GenerateCableMarkup(uid));
_examineSystem.SendExamineTooltip(args.User, uid, markup, false, false);
}
};

View File

@@ -0,0 +1,283 @@
using Content.Server.Administration.Logs;
using Content.Server.Audio;
using Content.Server.Power.Components;
using Content.Shared.Database;
using Content.Shared.Power;
using Content.Shared.UserInterface;
using Robust.Server.GameObjects;
using Robust.Shared.Player;
namespace Content.Server.Power.EntitySystems;
public sealed class PowerChargeSystem : EntitySystem
{
[Dependency] private readonly IAdminLogManager _adminLogger = default!;
[Dependency] private readonly UserInterfaceSystem _uiSystem = default!;
[Dependency] private readonly SharedAppearanceSystem _appearance = default!;
[Dependency] private readonly AmbientSoundSystem _ambientSoundSystem = default!;
public override void Initialize()
{
base.Initialize();
SubscribeLocalEvent<PowerChargeComponent, MapInitEvent>(OnMapInit);
SubscribeLocalEvent<PowerChargeComponent, ComponentShutdown>(OnComponentShutdown);
SubscribeLocalEvent<PowerChargeComponent, ActivatableUIOpenAttemptEvent>(OnUIOpenAttempt);
SubscribeLocalEvent<PowerChargeComponent, AfterActivatableUIOpenEvent>(OnAfterUiOpened);
SubscribeLocalEvent<PowerChargeComponent, AnchorStateChangedEvent>(OnAnchorStateChange);
// This needs to be ui key agnostic
SubscribeLocalEvent<PowerChargeComponent, SwitchChargingMachineMessage>(OnSwitchGenerator);
}
private void OnAnchorStateChange(EntityUid uid, PowerChargeComponent component, AnchorStateChangedEvent args)
{
if (args.Anchored || !TryComp<ApcPowerReceiverComponent>(uid, out var powerReceiverComponent))
return;
component.Active = false;
component.Charge = 0;
UpdateState(new Entity<PowerChargeComponent, ApcPowerReceiverComponent>(uid, component, powerReceiverComponent));
}
private void OnAfterUiOpened(EntityUid uid, PowerChargeComponent component, AfterActivatableUIOpenEvent args)
{
if (!TryComp<ApcPowerReceiverComponent>(uid, out var apcPowerReceiver))
return;
UpdateUI((uid, component, apcPowerReceiver), component.ChargeRate);
}
private void OnSwitchGenerator(EntityUid uid, PowerChargeComponent component, SwitchChargingMachineMessage args)
{
SetSwitchedOn(uid, component, args.On, user: args.Actor);
}
private void OnUIOpenAttempt(EntityUid uid, PowerChargeComponent component, ActivatableUIOpenAttemptEvent args)
{
if (!component.Intact)
args.Cancel();
}
private void OnComponentShutdown(EntityUid uid, PowerChargeComponent component, ComponentShutdown args)
{
if (!component.Active)
return;
component.Active = false;
var eventArgs = new ChargedMachineDeactivatedEvent();
RaiseLocalEvent(uid, ref eventArgs);
}
private void OnMapInit(Entity<PowerChargeComponent> ent, ref MapInitEvent args)
{
ApcPowerReceiverComponent? powerReceiver = null;
if (!Resolve(ent, ref powerReceiver, false))
return;
UpdatePowerState(ent, powerReceiver);
UpdateState((ent, ent.Comp, powerReceiver));
}
private void SetSwitchedOn(EntityUid uid, PowerChargeComponent component, bool on,
ApcPowerReceiverComponent? powerReceiver = null, EntityUid? user = null)
{
if (!Resolve(uid, ref powerReceiver))
return;
if (user is { } )
_adminLogger.Add(LogType.Action, on ? LogImpact.Medium : LogImpact.High, $"{ToPrettyString(user):player} set ${ToPrettyString(uid):target} to {(on ? "on" : "off")}");
component.SwitchedOn = on;
UpdatePowerState(component, powerReceiver);
component.NeedUIUpdate = true;
}
private static void UpdatePowerState(PowerChargeComponent component, ApcPowerReceiverComponent powerReceiver)
{
powerReceiver.Load = component.SwitchedOn ? component.ActivePowerUse : component.IdlePowerUse;
}
public override void Update(float frameTime)
{
base.Update(frameTime);
var query = EntityQueryEnumerator<PowerChargeComponent, ApcPowerReceiverComponent>();
while (query.MoveNext(out var uid, out var chargingMachine, out var powerReceiver))
{
var ent = (uid, gravGen: chargingMachine, powerReceiver);
if (!chargingMachine.Intact)
continue;
// Calculate charge rate based on power state and such.
// Negative charge rate means discharging.
float chargeRate;
if (chargingMachine.SwitchedOn)
{
if (powerReceiver.Powered)
{
chargeRate = chargingMachine.ChargeRate;
}
else
{
// Scale discharge rate such that if we're at 25% active power we discharge at 75% rate.
var receiving = powerReceiver.PowerReceived;
var mainSystemPower = Math.Max(0, receiving - chargingMachine.IdlePowerUse);
var ratio = 1 - mainSystemPower / (chargingMachine.ActivePowerUse - chargingMachine.IdlePowerUse);
chargeRate = -(ratio * chargingMachine.ChargeRate);
}
}
else
{
chargeRate = -chargingMachine.ChargeRate;
}
var active = chargingMachine.Active;
var lastCharge = chargingMachine.Charge;
chargingMachine.Charge = Math.Clamp(chargingMachine.Charge + frameTime * chargeRate, 0, chargingMachine.MaxCharge);
if (chargeRate > 0)
{
// Charging.
if (MathHelper.CloseTo(chargingMachine.Charge, chargingMachine.MaxCharge) && !chargingMachine.Active)
{
chargingMachine.Active = true;
}
}
else
{
// Discharging
if (MathHelper.CloseTo(chargingMachine.Charge, 0) && chargingMachine.Active)
{
chargingMachine.Active = false;
}
}
var updateUI = chargingMachine.NeedUIUpdate;
if (!MathHelper.CloseTo(lastCharge, chargingMachine.Charge))
{
UpdateState(ent);
updateUI = true;
}
if (updateUI)
UpdateUI(ent, chargeRate);
if (active == chargingMachine.Active)
continue;
if (chargingMachine.Active)
{
var eventArgs = new ChargedMachineActivatedEvent();
RaiseLocalEvent(uid, ref eventArgs);
}
else
{
var eventArgs = new ChargedMachineDeactivatedEvent();
RaiseLocalEvent(uid, ref eventArgs);
}
}
}
private void UpdateUI(Entity<PowerChargeComponent, ApcPowerReceiverComponent> ent, float chargeRate)
{
var (_, component, powerReceiver) = ent;
if (!_uiSystem.IsUiOpen(ent.Owner, component.UiKey))
return;
var chargeTarget = chargeRate < 0 ? 0 : component.MaxCharge;
short chargeEta;
var atTarget = false;
if (MathHelper.CloseTo(component.Charge, chargeTarget))
{
chargeEta = short.MinValue; // N/A
atTarget = true;
}
else
{
var diff = chargeTarget - component.Charge;
chargeEta = (short) Math.Abs(diff / chargeRate);
}
var status = chargeRate switch
{
> 0 when atTarget => PowerChargePowerStatus.FullyCharged,
< 0 when atTarget => PowerChargePowerStatus.Off,
> 0 => PowerChargePowerStatus.Charging,
< 0 => PowerChargePowerStatus.Discharging,
_ => throw new ArgumentOutOfRangeException()
};
var state = new PowerChargeState(
component.SwitchedOn,
(byte) (component.Charge * 255),
status,
(short) Math.Round(powerReceiver.PowerReceived),
(short) Math.Round(powerReceiver.Load),
chargeEta
);
_uiSystem.SetUiState(
ent.Owner,
component.UiKey,
state);
component.NeedUIUpdate = false;
}
private void UpdateState(Entity<PowerChargeComponent, ApcPowerReceiverComponent> ent)
{
var (uid, machine, powerReceiver) = ent;
var appearance = EntityManager.GetComponentOrNull<AppearanceComponent>(uid);
_appearance.SetData(uid, PowerChargeVisuals.Charge, machine.Charge, appearance);
_appearance.SetData(uid, PowerChargeVisuals.Active, machine.Active);
if (!machine.Intact)
{
MakeBroken((uid, machine), appearance);
}
else if (powerReceiver.PowerReceived < machine.IdlePowerUse)
{
MakeUnpowered((uid, machine), appearance);
}
else if (!machine.SwitchedOn)
{
MakeOff((uid, machine), appearance);
}
else
{
MakeOn((uid, machine), appearance);
}
}
private void MakeBroken(Entity<PowerChargeComponent> ent, AppearanceComponent? appearance)
{
_ambientSoundSystem.SetAmbience(ent, false);
_appearance.SetData(ent, PowerChargeVisuals.State, PowerChargeStatus.Broken, appearance);
}
private void MakeUnpowered(Entity<PowerChargeComponent> ent, AppearanceComponent? appearance)
{
_ambientSoundSystem.SetAmbience(ent, false);
_appearance.SetData(ent, PowerChargeVisuals.State, PowerChargeStatus.Unpowered, appearance);
}
private void MakeOff(Entity<PowerChargeComponent> ent, AppearanceComponent? appearance)
{
_ambientSoundSystem.SetAmbience(ent, false);
_appearance.SetData(ent, PowerChargeVisuals.State, PowerChargeStatus.Off, appearance);
}
private void MakeOn(Entity<PowerChargeComponent> ent, AppearanceComponent? appearance)
{
_ambientSoundSystem.SetAmbience(ent, true);
_appearance.SetData(ent, PowerChargeVisuals.State, PowerChargeStatus.On, appearance);
}
}
[ByRefEvent] public record struct ChargedMachineActivatedEvent;
[ByRefEvent] public record struct ChargedMachineDeactivatedEvent;

View File

@@ -0,0 +1,11 @@
using Content.Server.Shuttles.Systems;
namespace Content.Server.Shuttles.Components;
[RegisterComponent]
[Access(typeof(StationAnchorSystem))]
public sealed partial class StationAnchorComponent : Component
{
[DataField("switchedOn")]
public bool SwitchedOn { get; set; } = true;
}

View File

@@ -0,0 +1,86 @@
using Content.Server.Popups;
using Content.Server.Power.EntitySystems;
using Content.Server.Shuttles.Components;
using Content.Shared.Construction.Components;
using Content.Shared.Popups;
namespace Content.Server.Shuttles.Systems;
public sealed class StationAnchorSystem : EntitySystem
{
[Dependency] private readonly ShuttleSystem _shuttleSystem = default!;
[Dependency] private readonly PopupSystem _popupSystem = default!;
public override void Initialize()
{
base.Initialize();
SubscribeLocalEvent<StationAnchorComponent, UnanchorAttemptEvent>(OnUnanchorAttempt);
SubscribeLocalEvent<StationAnchorComponent, AnchorStateChangedEvent>(OnAnchorStationChange);
SubscribeLocalEvent<StationAnchorComponent, ChargedMachineActivatedEvent>(OnActivated);
SubscribeLocalEvent<StationAnchorComponent, ChargedMachineDeactivatedEvent>(OnDeactivated);
SubscribeLocalEvent<StationAnchorComponent, MapInitEvent>(OnMapInit);
}
private void OnMapInit(Entity<StationAnchorComponent> ent, ref MapInitEvent args)
{
if (!ent.Comp.SwitchedOn)
return;
SetStatus(ent, true);
}
private void OnActivated(Entity<StationAnchorComponent> ent, ref ChargedMachineActivatedEvent args)
{
SetStatus(ent, true);
}
private void OnDeactivated(Entity<StationAnchorComponent> ent, ref ChargedMachineDeactivatedEvent args)
{
SetStatus(ent, false);
}
/// <summary>
/// Prevent unanchoring when anchor is active
/// </summary>
private void OnUnanchorAttempt(Entity<StationAnchorComponent> ent, ref UnanchorAttemptEvent args)
{
if (!ent.Comp.SwitchedOn)
return;
_popupSystem.PopupEntity(
Loc.GetString("station-anchor-unanchoring-failed"),
ent,
args.User,
PopupType.Medium);
args.Cancel();
}
private void OnAnchorStationChange(Entity<StationAnchorComponent> ent, ref AnchorStateChangedEvent args)
{
if (!args.Anchored)
SetStatus(ent, false);
}
private void SetStatus(Entity<StationAnchorComponent> ent, bool enabled, ShuttleComponent? shuttleComponent = default)
{
var transform = Transform(ent);
var grid = transform.GridUid;
if (!grid.HasValue || !transform.Anchored && enabled || !Resolve(grid.Value, ref shuttleComponent))
return;
if (enabled)
{
_shuttleSystem.Disable(grid.Value);
}
else
{
_shuttleSystem.Enable(grid.Value);
}
shuttleComponent.Enabled = !enabled;
ent.Comp.SwitchedOn = enabled;
}
}

View File

@@ -100,19 +100,55 @@ namespace Content.Server.Stack
/// </summary>
public List<EntityUid> SpawnMultiple(string entityPrototype, int amount, EntityCoordinates spawnPosition)
{
var proto = _prototypeManager.Index<EntityPrototype>(entityPrototype);
proto.TryGetComponent<StackComponent>(out var stack);
var maxCountPerStack = GetMaxCount(stack);
var spawns = CalculateSpawns(entityPrototype, amount);
var spawnedEnts = new List<EntityUid>();
foreach (var count in spawns)
{
var entity = SpawnAtPosition(entityPrototype, spawnPosition);
spawnedEnts.Add(entity);
SetCount(entity, count);
}
return spawnedEnts;
}
/// <inheritdoc cref="SpawnMultiple(string,int,EntityCoordinates)"/>
public List<EntityUid> SpawnMultiple(string entityPrototype, int amount, EntityUid target)
{
var spawns = CalculateSpawns(entityPrototype, amount);
var spawnedEnts = new List<EntityUid>();
foreach (var count in spawns)
{
var entity = SpawnNextToOrDrop(entityPrototype, target);
spawnedEnts.Add(entity);
SetCount(entity, count);
}
return spawnedEnts;
}
/// <summary>
/// Calculates how many stacks to spawn that total up to <paramref name="amount"/>.
/// </summary>
/// <param name="entityPrototype">The stack to spawn.</param>
/// <param name="amount">The amount of pieces across all stacks.</param>
/// <returns>The list of stack counts per entity.</returns>
private List<int> CalculateSpawns(string entityPrototype, int amount)
{
var proto = _prototypeManager.Index<EntityPrototype>(entityPrototype);
proto.TryGetComponent<StackComponent>(out var stack, EntityManager.ComponentFactory);
var maxCountPerStack = GetMaxCount(stack);
var amounts = new List<int>();
while (amount > 0)
{
var entity = Spawn(entityPrototype, spawnPosition);
spawnedEnts.Add(entity);
var countAmount = Math.Min(maxCountPerStack, amount);
SetCount(entity, countAmount);
amount -= countAmount;
amounts.Add(countAmount);
}
return spawnedEnts;
return amounts;
}
private void OnStackAlternativeInteract(EntityUid uid, StackComponent stack, GetVerbsEvent<AlternativeVerb> args)

View File

@@ -1,4 +1,4 @@
using System.Diagnostics;
using System.Diagnostics;
using System.Linq;
using Content.Server.Administration;
using Content.Server.Cargo.Systems;
@@ -128,7 +128,7 @@ public record struct OnlyOneStationsError : IConError
{
public FormattedMessage DescribeInner()
{
return FormattedMessage.FromMarkup("This command doesn't function if there is more than one or no stations, explicitly specify a station with the ent command or similar.");
return FormattedMessage.FromMarkupOrThrow("This command doesn't function if there is more than one or no stations, explicitly specify a station with the ent command or similar.");
}
public string? Expression { get; set; }

View File

@@ -79,7 +79,7 @@ public sealed class TraitorCodePaperSystem : EntitySystem
break;
codesMessage.PushNewline();
codesMessage.AddMarkup(code);
codesMessage.AddMarkupOrThrow(code);
}
if (!codesMessage.IsEmpty)

View File

@@ -387,11 +387,7 @@ public sealed class WiresSystem : SharedWiresSystem
private void OnWiresActionMessage(EntityUid uid, WiresComponent component, WiresActionMessage args)
{
if (args.Actor == null)
{
return;
}
var player = (EntityUid) args.Actor;
var player = args.Actor;
if (!EntityManager.TryGetComponent(player, out HandsComponent? handsComponent))
{

View File

@@ -304,15 +304,15 @@ public sealed class ArtifactAnalyzerSystem : EntitySystem
var n = component.LastAnalyzedNode;
msg.AddMarkup(Loc.GetString("analysis-console-info-id", ("id", n.Id)));
msg.AddMarkupOrThrow(Loc.GetString("analysis-console-info-id", ("id", n.Id)));
msg.PushNewline();
msg.AddMarkup(Loc.GetString("analysis-console-info-depth", ("depth", n.Depth)));
msg.AddMarkupOrThrow(Loc.GetString("analysis-console-info-depth", ("depth", n.Depth)));
msg.PushNewline();
var activated = n.Triggered
? "analysis-console-info-triggered-true"
: "analysis-console-info-triggered-false";
msg.AddMarkup(Loc.GetString(activated));
msg.AddMarkupOrThrow(Loc.GetString(activated));
msg.PushNewline();
msg.PushNewline();
@@ -321,7 +321,7 @@ public sealed class ArtifactAnalyzerSystem : EntitySystem
var triggerProto = _prototype.Index<ArtifactTriggerPrototype>(n.Trigger);
if (triggerProto.TriggerHint != null)
{
msg.AddMarkup(Loc.GetString("analysis-console-info-trigger",
msg.AddMarkupOrThrow(Loc.GetString("analysis-console-info-trigger",
("trigger", Loc.GetString(triggerProto.TriggerHint))) + "\n");
needSecondNewline = true;
}
@@ -329,7 +329,7 @@ public sealed class ArtifactAnalyzerSystem : EntitySystem
var effectproto = _prototype.Index<ArtifactEffectPrototype>(n.Effect);
if (effectproto.EffectHint != null)
{
msg.AddMarkup(Loc.GetString("analysis-console-info-effect",
msg.AddMarkupOrThrow(Loc.GetString("analysis-console-info-effect",
("effect", Loc.GetString(effectproto.EffectHint))) + "\n");
needSecondNewline = true;
}
@@ -337,11 +337,11 @@ public sealed class ArtifactAnalyzerSystem : EntitySystem
if (needSecondNewline)
msg.PushNewline();
msg.AddMarkup(Loc.GetString("analysis-console-info-edges", ("edges", n.Edges.Count)));
msg.AddMarkupOrThrow(Loc.GetString("analysis-console-info-edges", ("edges", n.Edges.Count)));
msg.PushNewline();
if (component.LastAnalyzerPointValue != null)
msg.AddMarkup(Loc.GetString("analysis-console-info-value", ("value", component.LastAnalyzerPointValue)));
msg.AddMarkupOrThrow(Loc.GetString("analysis-console-info-value", ("value", component.LastAnalyzerPointValue)));
return msg;
}

View File

@@ -75,7 +75,7 @@ namespace Content.Shared.Examine
if (group.Title != null)
{
message.AddMarkup(Loc.GetString(group.Title));
message.AddMarkupOrThrow(Loc.GetString(group.Title));
message.PushNewline();
}
message.AddMessage(GetFormattedMessageFromExamineEntries(group.Entries));

View File

@@ -447,7 +447,7 @@ namespace Content.Shared.Examine
/// <seealso cref="PushMessage"/>
public void PushMarkup(string markup, int priority=0)
{
PushMessage(FormattedMessage.FromMarkup(markup), priority);
PushMessage(FormattedMessage.FromMarkupOrThrow(markup), priority);
}
/// <summary>
@@ -495,7 +495,7 @@ namespace Content.Shared.Examine
/// <seealso cref="AddMessage"/>
public void AddMarkup(string markup, int priority=0)
{
AddMessage(FormattedMessage.FromMarkup(markup), priority);
AddMessage(FormattedMessage.FromMarkupOrThrow(markup), priority);
}
/// <summary>

View File

@@ -1,118 +1,44 @@
using Content.Shared.Power;
using Robust.Shared.GameStates;
using Robust.Shared.Serialization;
namespace Content.Shared.Gravity
namespace Content.Shared.Gravity;
[NetworkedComponent()]
[Virtual]
public partial class SharedGravityGeneratorComponent : Component
{
[NetworkedComponent()]
[Virtual]
public partial class SharedGravityGeneratorComponent : Component
{
/// <summary>
/// A map of the sprites used by the gravity generator given its status.
/// </summary>
[DataField("spriteMap")]
[Access(typeof(SharedGravitySystem))]
public Dictionary<GravityGeneratorStatus, string> SpriteMap = new();
/// <summary>
/// A map of the sprites used by the gravity generator given its status.
/// </summary>
[DataField("spriteMap")]
[Access(typeof(SharedGravitySystem))]
public Dictionary<PowerChargeStatus, string> SpriteMap = new();
/// <summary>
/// The sprite used by the core of the gravity generator when the gravity generator is starting up.
/// </summary>
[DataField("coreStartupState")]
[ViewVariables(VVAccess.ReadWrite)]
public string CoreStartupState = "startup";
/// <summary>
/// The sprite used by the core of the gravity generator when the gravity generator is starting up.
/// </summary>
[DataField("coreStartupState")]
[ViewVariables(VVAccess.ReadWrite)]
public string CoreStartupState = "startup";
/// <summary>
/// The sprite used by the core of the gravity generator when the gravity generator is idle.
/// </summary>
[DataField("coreIdleState")]
[ViewVariables(VVAccess.ReadWrite)]
public string CoreIdleState = "idle";
/// <summary>
/// The sprite used by the core of the gravity generator when the gravity generator is idle.
/// </summary>
[DataField("coreIdleState")]
[ViewVariables(VVAccess.ReadWrite)]
public string CoreIdleState = "idle";
/// <summary>
/// The sprite used by the core of the gravity generator when the gravity generator is activating.
/// </summary>
[DataField("coreActivatingState")]
[ViewVariables(VVAccess.ReadWrite)]
public string CoreActivatingState = "activating";
/// <summary>
/// The sprite used by the core of the gravity generator when the gravity generator is activating.
/// </summary>
[DataField("coreActivatingState")]
[ViewVariables(VVAccess.ReadWrite)]
public string CoreActivatingState = "activating";
/// <summary>
/// The sprite used by the core of the gravity generator when the gravity generator is active.
/// </summary>
[DataField("coreActivatedState")]
[ViewVariables(VVAccess.ReadWrite)]
public string CoreActivatedState = "activated";
/// <summary>
/// Sent to the server to set whether the generator should be on or off
/// </summary>
[Serializable, NetSerializable]
public sealed class SwitchGeneratorMessage : BoundUserInterfaceMessage
{
public bool On;
public SwitchGeneratorMessage(bool on)
{
On = on;
}
}
[Serializable, NetSerializable]
public sealed class GeneratorState : BoundUserInterfaceState
{
public bool On;
// 0 -> 255
public byte Charge;
public GravityGeneratorPowerStatus PowerStatus;
public short PowerDraw;
public short PowerDrawMax;
public short EtaSeconds;
public GeneratorState(
bool on,
byte charge,
GravityGeneratorPowerStatus powerStatus,
short powerDraw,
short powerDrawMax,
short etaSeconds)
{
On = on;
Charge = charge;
PowerStatus = powerStatus;
PowerDraw = powerDraw;
PowerDrawMax = powerDrawMax;
EtaSeconds = etaSeconds;
}
}
[Serializable, NetSerializable]
public enum GravityGeneratorUiKey
{
Key
}
}
[Serializable, NetSerializable]
public enum GravityGeneratorVisuals
{
State,
Charge
}
[Serializable, NetSerializable]
public enum GravityGeneratorStatus
{
Broken,
Unpowered,
Off,
On
}
[Serializable, NetSerializable]
public enum GravityGeneratorPowerStatus : byte
{
Off,
Discharging,
Charging,
FullyCharged
}
/// <summary>
/// The sprite used by the core of the gravity generator when the gravity generator is active.
/// </summary>
[DataField("coreActivatedState")]
[ViewVariables(VVAccess.ReadWrite)]
public string CoreActivatedState = "activated";
}

View File

@@ -1,4 +1,4 @@
using Content.Shared.Damage;
using Content.Shared.Damage;
using Content.Shared.Examine;
using Content.Shared.FixedPoint;
using Content.Shared.IdentityManagement;
@@ -85,12 +85,12 @@ public sealed class HealthExaminableSystem : EntitySystem
{
first = false;
}
msg.AddMarkup(chosenLocStr);
msg.AddMarkupOrThrow(chosenLocStr);
}
if (msg.IsEmpty)
{
msg.AddMarkup(Loc.GetString($"health-examinable-{component.LocPrefix}-none"));
msg.AddMarkupOrThrow(Loc.GetString($"health-examinable-{component.LocPrefix}-none"));
}
// Anything else want to add on to this?

View File

@@ -0,0 +1,77 @@
using Robust.Shared.Serialization;
namespace Content.Shared.Power;
/// <summary>
/// Sent to the server to set whether the machine should be on or off
/// </summary>
[Serializable, NetSerializable]
public sealed class SwitchChargingMachineMessage : BoundUserInterfaceMessage
{
public bool On;
public SwitchChargingMachineMessage(bool on)
{
On = on;
}
}
[Serializable, NetSerializable]
public sealed class PowerChargeState : BoundUserInterfaceState
{
public bool On;
// 0 -> 255
public byte Charge;
public PowerChargePowerStatus PowerStatus;
public short PowerDraw;
public short PowerDrawMax;
public short EtaSeconds;
public PowerChargeState(
bool on,
byte charge,
PowerChargePowerStatus powerStatus,
short powerDraw,
short powerDrawMax,
short etaSeconds)
{
On = on;
Charge = charge;
PowerStatus = powerStatus;
PowerDraw = powerDraw;
PowerDrawMax = powerDrawMax;
EtaSeconds = etaSeconds;
}
}
[Serializable, NetSerializable]
public enum PowerChargeUiKey
{
Key
}
[Serializable, NetSerializable]
public enum PowerChargeVisuals
{
State,
Charge,
Active
}
[Serializable, NetSerializable]
public enum PowerChargeStatus
{
Broken,
Unpowered,
Off,
On
}
[Serializable, NetSerializable]
public enum PowerChargePowerStatus : byte
{
Off,
Discharging,
Charging,
FullyCharged
}

View File

@@ -0,0 +1,14 @@
namespace Content.Shared.Power;
/// <summary>
/// Component for a powered machine that slowly powers on and off over a period of time.
/// </summary>
public abstract partial class SharedPowerChargeComponent : Component
{
/// <summary>
/// The title used for the default charged machine window if used
/// </summary>
[DataField]
public LocId WindowTitle { get; set; } = string.Empty;
}

View File

@@ -570,11 +570,11 @@ namespace Content.Shared.Preferences
string flavortext;
if (FlavorText.Length > MaxDescLength)
{
flavortext = FormattedMessage.RemoveMarkup(FlavorText)[..MaxDescLength];
flavortext = FormattedMessage.RemoveMarkupOrThrow(FlavorText)[..MaxDescLength];
}
else
{
flavortext = FormattedMessage.RemoveMarkup(FlavorText);
flavortext = FormattedMessage.RemoveMarkupOrThrow(FlavorText);
}
var appearance = HumanoidCharacterAppearance.EnsureValid(Appearance, Species, Sex, sponsorPrototypes);

View File

@@ -26,7 +26,7 @@ public sealed partial class GroupLoadoutEffect : LoadoutEffect
reasons.Add(reason.ToMarkup());
}
reason = reasons.Count == 0 ? null : FormattedMessage.FromMarkup(string.Join('\n', reasons));
reason = reasons.Count == 0 ? null : FormattedMessage.FromMarkupOrThrow(string.Join('\n', reasons));
return reason == null;
}
}

View File

@@ -254,7 +254,7 @@ public sealed partial class RoleLoadout : IEquatable<RoleLoadout>
if (!protoManager.TryIndex(loadout, out var loadoutProto))
{
// Uhh
reason = FormattedMessage.FromMarkup("");
reason = FormattedMessage.FromMarkupOrThrow("");
return false;
}

View File

@@ -1,4 +1,4 @@
using System.Linq;
using System.Linq;
using Content.Shared.Lathe;
using Content.Shared.Research.Components;
using Content.Shared.Research.Prototypes;
@@ -157,42 +157,42 @@ public abstract class SharedResearchSystem : EntitySystem
if (includeTier)
{
disciplinePrototype ??= PrototypeManager.Index(technology.Discipline);
description.AddMarkup(Loc.GetString("research-console-tier-discipline-info",
description.AddMarkupOrThrow(Loc.GetString("research-console-tier-discipline-info",
("tier", technology.Tier), ("color", disciplinePrototype.Color), ("discipline", Loc.GetString(disciplinePrototype.Name))));
description.PushNewline();
}
if (includeCost)
{
description.AddMarkup(Loc.GetString("research-console-cost", ("amount", technology.Cost)));
description.AddMarkupOrThrow(Loc.GetString("research-console-cost", ("amount", technology.Cost)));
description.PushNewline();
}
if (includePrereqs && technology.TechnologyPrerequisites.Any())
{
description.AddMarkup(Loc.GetString("research-console-prereqs-list-start"));
description.AddMarkupOrThrow(Loc.GetString("research-console-prereqs-list-start"));
foreach (var recipe in technology.TechnologyPrerequisites)
{
var techProto = PrototypeManager.Index(recipe);
description.PushNewline();
description.AddMarkup(Loc.GetString("research-console-prereqs-list-entry",
description.AddMarkupOrThrow(Loc.GetString("research-console-prereqs-list-entry",
("text", Loc.GetString(techProto.Name))));
}
description.PushNewline();
}
description.AddMarkup(Loc.GetString("research-console-unlocks-list-start"));
description.AddMarkupOrThrow(Loc.GetString("research-console-unlocks-list-start"));
foreach (var recipe in technology.RecipeUnlocks)
{
var recipeProto = PrototypeManager.Index(recipe);
description.PushNewline();
description.AddMarkup(Loc.GetString("research-console-unlocks-list-entry",
description.AddMarkupOrThrow(Loc.GetString("research-console-unlocks-list-entry",
("name", _lathe.GetRecipeName(recipeProto))));
}
foreach (var generic in technology.GenericUnlocks)
{
description.PushNewline();
description.AddMarkup(Loc.GetString("research-console-unlocks-list-entry-generic",
description.AddMarkupOrThrow(Loc.GetString("research-console-unlocks-list-entry-generic",
("text", Loc.GetString(generic.UnlockDescription))));
}

View File

@@ -5,6 +5,7 @@ using Content.Shared.Shuttles.UI.MapObjects;
using Content.Shared.Whitelist;
using Robust.Shared.Map;
using Robust.Shared.Map.Components;
using Robust.Shared.Physics;
using Robust.Shared.Physics.Collision.Shapes;
using Robust.Shared.Physics.Components;
@@ -125,7 +126,7 @@ public abstract partial class SharedShuttleSystem : EntitySystem
if (!Resolve(gridUid, ref physics))
return true;
if (physics.Mass < 10f)
if (physics.BodyType != BodyType.Static && physics.Mass < 10f)
{
return false;
}

View File

@@ -0,0 +1,3 @@
using NUnit.Framework;
[assembly: Parallelizable(ParallelScope.Fixtures)]

View File

@@ -1,41 +1,4 @@
Entries:
- author: Keer-Sar
changes:
- message: Non-humanoids' names are now capitalized when inserting materials into
machines.
type: Fix
id: 6755
time: '2024-06-16T02:06:12.0000000+00:00'
url: https://github.com/space-wizards/space-station-14/pull/29071
- author: EmoGarbage404
changes:
- message: Magboots no longer work when off-grid.
type: Fix
id: 6756
time: '2024-06-16T03:38:18.0000000+00:00'
url: https://github.com/space-wizards/space-station-14/pull/29034
- author: deltanedas
changes:
- message: Tarantulas now use Mechanotoxin, a venom that slows you down over time.
type: Tweak
id: 6757
time: '2024-06-16T11:26:59.0000000+00:00'
url: https://github.com/space-wizards/space-station-14/pull/29066
- author: Cojoke-dot
changes:
- message: Musicians can now select instruments in their loadout
type: Add
id: 6758
time: '2024-06-16T11:27:35.0000000+00:00'
url: https://github.com/space-wizards/space-station-14/pull/29059
- author: ElectroJr
changes:
- message: Fixed pianos, office chairs & other objects not rotating while being
pulled.
type: Fix
id: 6759
time: '2024-06-16T11:30:36.0000000+00:00'
url: https://github.com/space-wizards/space-station-14/pull/29032
- author: deltanedas
changes:
- message: Added the Carp Hardsuit to the uplink which is spaceproof and makes carp
@@ -3842,3 +3805,44 @@
id: 7254
time: '2024-08-31T08:28:36.0000000+00:00'
url: https://github.com/space-wizards/space-station-14/pull/31655
- author: juliangiebel
changes:
- message: Adds the station anchor. It anchors stations in space and prevents them
from moving.
type: Add
id: 7255
time: '2024-08-31T14:40:28.0000000+00:00'
url: https://github.com/space-wizards/space-station-14/pull/26098
- author: Moomoobeef
changes:
- message: medibelts are found in the medidrobe instead of in lockers.
type: Tweak
id: 7256
time: '2024-08-31T23:22:06.0000000+00:00'
url: https://github.com/space-wizards/space-station-14/pull/31470
- author: EmoGarbage404
changes:
- message: Removed the reclaimer shuttle.
type: Remove
- message: Removed fultons and fulton beacons from the autolathe
type: Remove
- message: Adjusted equipment inside salvage lockers and vendors.
type: Tweak
id: 7257
time: '2024-08-31T23:39:32.0000000+00:00'
url: https://github.com/space-wizards/space-station-14/pull/31333
- author: Moomoobeef
changes:
- message: Added flavors to an array of previously indescribable things.
type: Add
id: 7258
time: '2024-09-01T00:03:30.0000000+00:00'
url: https://github.com/space-wizards/space-station-14/pull/31685
- author: Ilya246
changes:
- message: Fixed tip 26 being misinformation about the tesla. It now displays truthful
information.
type: Fix
id: 7259
time: '2024-09-01T11:03:23.0000000+00:00'
url: https://github.com/space-wizards/space-station-14/pull/31705

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,2 @@
station-anchor-unanchoring-failed = Can't unanchor an active station anchor
station-anchor-window-title = Station Anchor

View File

@@ -50,6 +50,7 @@ flavor-base-horrible = horrible
# lmao
flavor-base-terrible = terrible
flavor-base-mindful = mindful
flavor-base-chewy = chewy
# Complex flavors. Put a flavor here when you want something that's more
# specific.
@@ -173,6 +174,8 @@ flavor-complex-violets = like violets
flavor-complex-pyrotton = like a burning mouth
flavor-complex-mothballs = like mothballs
flavor-complex-paint-thinner = like paint thinner
flavor-complex-paper = like mushy pulp
flavor-complex-compressed-meat = like compressed meat
# Drink-specific flavors.

View File

@@ -0,0 +1,22 @@
## UI field names
power-charge-window-status = Status:
power-charge-window-power = Power:
power-charge-window-eta = ETA:
power-charge-window-charge = Charge:
## UI statuses
power-charge-window-status-fully-charged = Fully Charged
power-charge-window-status-off = Off
power-charge-window-status-charging = Charging
power-charge-window-status-discharging = Discharging
## UI Power Buttons
power-charge-window-power-on = On
power-charge-window-power-off = Off
power-charge-window-power-label = { $draw } / { $max } W
## UI ETA label
power-charge-window-eta-none = N/A
power-charge-window-eta-value = { TOSTRING($left, "m\\:ss") }

View File

@@ -23,7 +23,7 @@ tips-dataset-22 = You can hold SPACE by default to slow the movement of the shut
tips-dataset-23 = Dexalin, Dexalin Plus, and Epinephrine will all purge heartbreaker toxin from your bloodstream while metabolizing.
tips-dataset-24 = Every crewmember comes with an emergency medipen in their survival box containing epinephrine and tranexamic acid.
tips-dataset-25 = The AME is a high-priority target and is easily sabotaged. Make sure to set up the Singularity or Solars so that you don't run out of power if it blows.
tips-dataset-26 = During a teslaloose, make sure to get rid of all electronic items so you don't become a target.
tips-dataset-26 = If the tesla is loose, it will chase any people, stationary machines and computers. Turning off your electronics does not make you less of a target. Your best bet is not being close to it.
tips-dataset-27 = You can add labels to any item, including food or pill canisters, using a hand labeller.
tips-dataset-28 = Riot armor is significantly more powerful against opponents that aren't using guns compared to regular armor.
tips-dataset-29 = As a ghost, you can use the Verb Menu to orbit around and follow any entity in game automatically.

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -127,28 +127,6 @@
- id: MagazineLightRifleBox
amount: 2
- type: entity
parent: ClothingBackpackDuffel
id: ClothingBackpackDuffelSyndicateCostumeCentcom
name: CentComm official costume duffel bag
description: "Contains a full CentComm Official uniform set, headset and clipboard included. Encryption keys and ID access are not included."
suffix: DO NOT MAP
components:
- type: Tag
tags: [] # ignore "WhitelistChameleon" tag
- type: StorageFill
contents:
- id: ClothingOuterArmorBasic
- id: ClothingHeadHatCentcom
- id: ClothingEyesGlassesSunglasses
- id: ClothingUniformJumpsuitCentcomOfficial
- id: ClothingShoesBootsJack
- id: ClothingHandsGlovesColorBlack
- id: ClothingHeadsetAltCentComFake
- id: Paper
- id: Pen
- id: CentcomPDAFake
- type: entity
parent: ClothingBackpackDuffelClown
id: ClothingBackpackDuffelSyndicateCostumeClown

View File

@@ -1,48 +1,47 @@
- type: entityTable
id: FillSalvageSpecialistHardsuitSpatio
table: !type:AllSelector
children:
- id: OxygenTankFilled
- id: ClothingShoesBootsMag
- id: ClothingOuterHardsuitSpatio
- id: ClothingMaskGasExplorer
- type: entityTable
id: LockerFillSalvageSpecialist
table: !type:AllSelector
children:
- id: ClothingBeltUtilityFilled
- id: SurvivalKnife
- id: HandheldGPSBasic
- id: RadioHandheld
- id: AppraisalTool
- id: FireExtinguisher
- id: Flare
prob: 0.3
rolls: !type:ConstantNumberSelector
value: 3
- type: entity
id: LockerSalvageSpecialistFilledHardsuit
suffix: Filled, Hardsuit
parent: LockerSalvageSpecialist
components:
- type: StorageFill
contents:
- id: ClothingOuterHardsuitSpatio
- id: ClothingShoesBootsMag
- id: ClothingMaskGasExplorer
- id: ClothingBeltUtilityFilled
- id: SurvivalKnife
- id: HandheldGPSBasic
- id: RadioHandheld
- id: SeismicCharge
amount: 2
- id: OreBag
prob: 0.5
- id: Flare
prob: 0.3
- id: Flare
prob: 0.3
- id: Flare
prob: 0.3
- type: EntityTableContainerFill
containers:
entity_storage: !type:AllSelector
children:
- !type:NestedSelector
tableId: FillSalvageSpecialistHardsuitSpatio
- !type:NestedSelector
tableId: LockerFillSalvageSpecialist
- type: entity
id: LockerSalvageSpecialistFilled
suffix: Filled
parent: LockerSalvageSpecialist
components:
- type: StorageFill
contents:
# Currently do not function as 'true' mesons, so they're useless for salvagers.
# - id: ClothingEyesGlassesMeson
- id: ClothingBeltUtilityFilled
- id: SurvivalKnife
- id: HandheldGPSBasic
- id: RadioHandheld
- id: SeismicCharge
amount: 2
- id: OreBag
prob: 0.5
- id: Flare
prob: 0.3
- id: Flare
prob: 0.3
- id: Flare
prob: 0.3
- type: EntityTableContainerFill
containers:
entity_storage: !type:NestedSelector
tableId: LockerFillSalvageSpecialist

View File

@@ -16,7 +16,6 @@
- id: RubberStampApproved
- id: RubberStampDenied
- id: RubberStampQm
- id: SalvageShuttleConsoleCircuitboard
- id: PrinterDocFlatpack # Corvax-Printer
- type: entity

View File

@@ -50,7 +50,6 @@
- id: ClothingHandsGlovesLatex
- id: ClothingHeadsetMedical
- id: ClothingEyesHudMedical
- id: ClothingBeltMedical
- id: ClothingHeadHatSurgcapGreen
prob: 0.1
orGroup: Surgcaps
@@ -84,7 +83,6 @@
- id: ClothingHandsGlovesLatex
- id: ClothingHeadsetMedical
- id: ClothingEyesHudMedical
- id: ClothingBeltMedical
- id: ClothingHeadHatSurgcapGreen
prob: 0.1
orGroup: Surgcaps

View File

@@ -229,12 +229,10 @@
parent: SuitStorageBase
suffix: Salvage
components:
- type: StorageFill
contents:
- id: OxygenTankFilled
- id: ClothingShoesBootsMag
- id: ClothingOuterHardsuitSpatio
- id: ClothingMaskGasExplorer
- type: EntityTableContainerFill
containers:
entity_storage: !type:NestedSelector
tableId: FillSalvageSpecialistHardsuitSpatio
- type: AccessReader
access: [["Salvage"]]

View File

@@ -6,6 +6,7 @@
ClothingBackpackSatchelMedical: 4
ClothingUniformJumpsuitMedicalDoctor: 4
ClothingUniformJumpskirtMedicalDoctor: 4
ClothingBeltMedical: 4
ClothingHeadHatBeretMedic: 4
ClothingHeadNurseHat: 4
ClothingOuterCoatLab: 4

View File

@@ -3,13 +3,9 @@
startingInventory:
Crowbar: 2
Pickaxe: 4
OreBag: 4
OreBag: 2
Flare: 4
FlashlightLantern: 2
Floodlight: 2
HandheldGPSBasic: 2
RadioHandheld: 2
WeaponProtoKineticAccelerator: 4
SeismicCharge: 2
FultonBeacon: 1
Fulton: 2

View File

@@ -41,16 +41,6 @@
- type: Clothing
sprite: Clothing/Ears/Headsets/centcom.rsi
- type: entity
parent: ClothingHeadsetAltCentCom
id: ClothingHeadsetAltCentComFake
suffix: Fake
components:
- type: ContainerFill
containers:
key_slots:
- EncryptionKeyCommon
- type: entity
parent: [ClothingHeadsetAlt, BaseCommandContraband]
id: ClothingHeadsetAltCommand

View File

@@ -11,6 +11,9 @@
- WhitelistChameleon
- type: StaticPrice
price: 10
- type: FlavorProfile #yes not every peice of clothing is edible, but this way every edible piece of clothing should have the flavor without me having to track down what specific clothing can and cannot be eaten.
flavors:
- fiber
- type: entity
abstract: true

View File

@@ -197,6 +197,7 @@
- id: PowerCellHighPrinted
- id: RadioHandheld
- id: ClothingBeltUtility
- id: Floodlight
- id: WeaponProtoKineticAccelerator
weight: 0.5
- id: OxygenTankFilled

View File

@@ -347,6 +347,11 @@
bloodReagent: InsectBlood
bloodMaxVolume: 20
- type: Food
- type: FlavorProfile
flavors:
- horrible
- terrible
- chewy
- type: Hunger
baseDecayRate: 0.25
- type: Extractable
@@ -957,6 +962,9 @@
requiresSpecialDigestion: true
# Wooly prevents eating wool deleting the goat so its fine
requireDead: false
- type: FlavorProfile
flavors:
- fiber
- type: Butcherable
spawned:
- id: FoodMeat
@@ -1635,6 +1643,9 @@
Dead:
Base: splat-0
- type: Food
- type: FlavorProfile
flavors:
- meaty
- type: Thirst
startingThirst: 25 # spawn with Okay thirst state
thresholds:
@@ -3179,6 +3190,9 @@
Dead:
Base: splat-0
- type: Food
- type: FlavorProfile
flavors:
- meaty
- type: Hunger
baseDecayRate: 0.3
- type: Extractable

View File

@@ -585,6 +585,10 @@
- Hamster
- VimPilot
- ChefPilot
- type: FlavorProfile
flavors:
- meaty
- sadness
- type: entity
name: Shiva

View File

@@ -1214,6 +1214,22 @@
CableHV: 5
Uranium: 2
- type: entity
parent: BaseMachineCircuitboard
id: StationAnchorCircuitboard
name: station anchor machine board
description: A machine printed circuit board for a station anchor.
components:
- type: MachineBoard
prototype: StationAnchor
stackRequirements:
Capacitor: 4
MatterBin: 3
Steel: 10
Glass: 5
CableHV: 8
Uranium: 2
- type: entity
parent: BaseMachineCircuitboard
id: ReagentGrinderIndustrialMachineCircuitboard

View File

@@ -142,17 +142,6 @@
- type: StealTarget
stealGroup: CargoShuttleConsoleCircuitboard
- type: entity
parent: BaseComputerCircuitboard
id: SalvageShuttleConsoleCircuitboard
name: salvage shuttle console board
description: A computer printed circuit board for a salvage shuttle console.
components:
- type: ComputerBoard
prototype: ComputerShuttleSalvage
- type: StealTarget
stealGroup: SalvageShuttleConsoleCircuitboard
- type: entity
parent: BaseComputerCircuitboard
id: SurveillanceCameraMonitorCircuitboard

View File

@@ -689,14 +689,6 @@
- NewsReaderCartridge
- LogProbeCartridge
- type: entity
parent: CentcomPDA
id: CentcomPDAFake
suffix: Fake
components:
- type: Pda
id: CentcomIDCardSyndie
- type: entity
parent: CentcomPDA
id: DeathsquadPDA

View File

@@ -23,6 +23,10 @@
- type: Crayon
capacity: 15
- type: Food
- type: FlavorProfile
flavors:
- chewy
- bitter
- type: SolutionContainerManager
solutions:
food:

View File

@@ -117,6 +117,9 @@
- type: Appearance
- type: Food
requiresSpecialDigestion: true
- type: FlavorProfile
flavors:
- fiber
- type: SolutionContainerManager
solutions:
food:
@@ -405,6 +408,9 @@
- type: Appearance
- type: Food
requiresSpecialDigestion: true
- type: FlavorProfile
flavors:
- fiber
- type: SolutionContainerManager
solutions:
food:

View File

@@ -539,24 +539,6 @@
- type: IdCard
jobTitle: ERT Field Officer
- type: entity
parent: IDCardStandard
id: CentcomIDCardSyndie
name: command officer ID card
suffix: Fake
components:
- type: Sprite
layers:
- state: centcom
- state: idcentcom
- type: Item
heldPrefix: blue
- type: IdCard
jobTitle: Central Commander
- type: Access
tags:
- Maintenance
- type: entity
parent: IDCardStandard
id: MusicianIDCard

View File

@@ -63,6 +63,9 @@
solution: food
delay: 7
forceFeedDelay: 7
- type: FlavorProfile
flavors:
- paper
- type: BadFood
- type: SolutionContainerManager
solutions:

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