Merge pull request #968 from crystallpunk-14/ed-2025-03-03-upstream-stable-2

Stable upstream sync
This commit is contained in:
Ed
2025-03-03 23:40:02 +03:00
committed by GitHub
314 changed files with 5403 additions and 1513 deletions

View File

@@ -85,7 +85,7 @@ internal sealed class AdminNameOverlay : Overlay
{
args.ScreenHandle.DrawString(_font, screenCoordinates + (lineoffset * 2), _antagLabelClassic, uiScale, _antagColorClassic);
}
else if (!classic && _filter.Contains(playerInfo.RoleProto.ID))
else if (!classic && _filter.Contains(playerInfo.RoleProto))
{
var label = Loc.GetString(playerInfo.RoleProto.Name).ToUpper();
var color = playerInfo.RoleProto.Color;

View File

@@ -1,4 +1,5 @@
using Content.Client.UserInterface.Fragments;
using Content.Shared.CartridgeLoader;
using Content.Shared.CartridgeLoader.Cartridges;
using Robust.Client.UserInterface;
@@ -13,16 +14,23 @@ public sealed partial class LogProbeUi : UIFragment
return _fragment!;
}
public override void Setup(BoundUserInterface userInterface, EntityUid? fragmentOwner)
public override void Setup(BoundUserInterface ui, EntityUid? fragmentOwner)
{
_fragment = new LogProbeUiFragment();
_fragment.OnPrintPressed += () =>
{
var ev = new LogProbePrintMessage();
var message = new CartridgeUiMessage(ev);
ui.SendMessage(message);
};
}
public override void UpdateState(BoundUserInterfaceState state)
{
if (state is not LogProbeUiState logProbeUiState)
if (state is not LogProbeUiState cast)
return;
_fragment?.UpdateState(logProbeUiState.PulledLogs);
_fragment?.UpdateState(cast.EntityName, cast.PulledLogs);
}
}

View File

@@ -18,4 +18,9 @@
<ScrollContainer VerticalExpand="True" HScrollEnabled="True">
<BoxContainer Orientation="Vertical" Name="ProbedDeviceContainer"/>
</ScrollContainer>
<BoxContainer Orientation="Horizontal" Margin="4 8">
<Button Name="PrintButton" HorizontalAlignment="Left" Text="{Loc 'log-probe-print-button'}" Disabled="True"/>
<BoxContainer HorizontalExpand="True"/>
<Label Name="EntityName" Align="Right"/>
</BoxContainer>
</cartridges:LogProbeUiFragment>

View File

@@ -8,17 +8,24 @@ namespace Content.Client.CartridgeLoader.Cartridges;
[GenerateTypedNameReferences]
public sealed partial class LogProbeUiFragment : BoxContainer
{
/// <summary>
/// Action invoked when the print button gets pressed.
/// </summary>
public Action? OnPrintPressed;
public LogProbeUiFragment()
{
RobustXamlLoader.Load(this);
PrintButton.OnPressed += _ => OnPrintPressed?.Invoke();
}
public void UpdateState(List<PulledAccessLog> logs)
public void UpdateState(string name, List<PulledAccessLog> logs)
{
ProbedDeviceContainer.RemoveAllChildren();
EntityName.Text = name;
PrintButton.Disabled = string.IsNullOrEmpty(name);
//Reverse the list so the oldest entries appear at the bottom
logs.Reverse();
ProbedDeviceContainer.RemoveAllChildren();
var count = 1;
foreach (var log in logs)

View File

@@ -217,7 +217,7 @@ namespace Content.Client.Chat.UI
{
StyleClasses = { "speechBox", speechStyleClass },
Children = { label },
ModulateSelfOverride = Color.White.WithAlpha(0.75f)
ModulateSelfOverride = Color.White.WithAlpha(ConfigManager.GetCVar(CCVars.SpeechBubbleBackgroundOpacity))
};
return panel;
@@ -247,21 +247,23 @@ namespace Content.Client.Chat.UI
{
StyleClasses = { "speechBox", speechStyleClass },
Children = { label },
ModulateSelfOverride = Color.White.WithAlpha(0.75f)
ModulateSelfOverride = Color.White.WithAlpha(ConfigManager.GetCVar(CCVars.SpeechBubbleBackgroundOpacity)),
};
return unfanciedPanel;
}
var bubbleHeader = new RichTextLabel
{
Margin = new Thickness(1, 1, 1, 1)
ModulateSelfOverride = Color.White.WithAlpha(ConfigManager.GetCVar(CCVars.SpeechBubbleSpeakerOpacity)),
Margin = new Thickness(1, 1, 1, 1),
};
var bubbleContent = new RichTextLabel
{
ModulateSelfOverride = Color.White.WithAlpha(ConfigManager.GetCVar(CCVars.SpeechBubbleTextOpacity)),
MaxWidth = SpeechMaxWidth,
Margin = new Thickness(2, 6, 2, 2),
StyleClasses = { "bubbleContent" }
StyleClasses = { "bubbleContent" },
};
//We'll be honest. *Yes* this is hacky. Doing this in a cleaner way would require a bottom-up refactor of how saycode handles sending chat messages. -Myr
@@ -273,7 +275,7 @@ namespace Content.Client.Chat.UI
{
StyleClasses = { "speechBox", speechStyleClass },
Children = { bubbleContent },
ModulateSelfOverride = Color.White.WithAlpha(0.75f),
ModulateSelfOverride = Color.White.WithAlpha(ConfigManager.GetCVar(CCVars.SpeechBubbleBackgroundOpacity)),
HorizontalAlignment = HAlignment.Center,
VerticalAlignment = VAlignment.Bottom,
Margin = new Thickness(4, 14, 4, 2)
@@ -283,7 +285,7 @@ namespace Content.Client.Chat.UI
{
StyleClasses = { "speechBox", speechStyleClass },
Children = { bubbleHeader },
ModulateSelfOverride = Color.White.WithAlpha(ConfigManager.GetCVar(CCVars.ChatFancyNameBackground) ? 0.75f : 0f),
ModulateSelfOverride = Color.White.WithAlpha(ConfigManager.GetCVar(CCVars.ChatFancyNameBackground) ? ConfigManager.GetCVar(CCVars.SpeechBubbleBackgroundOpacity) : 0f),
HorizontalAlignment = HAlignment.Center,
VerticalAlignment = VAlignment.Top
};

View File

@@ -94,7 +94,7 @@ public sealed class ChemistryGuideDataSystem : SharedChemistryGuideDataSystem
if (entProto.Abstract || usedNames.Contains(entProto.Name))
continue;
if (!entProto.TryGetComponent<ExtractableComponent>(out var extractableComponent))
if (!entProto.TryGetComponent<ExtractableComponent>(out var extractableComponent, EntityManager.ComponentFactory))
continue;
//these bloat the hell out of blood/fat
@@ -121,7 +121,7 @@ public sealed class ChemistryGuideDataSystem : SharedChemistryGuideDataSystem
if (extractableComponent.GrindableSolution is { } grindableSolutionId &&
entProto.TryGetComponent<SolutionContainerManagerComponent>(out var manager) &&
entProto.TryGetComponent<SolutionContainerManagerComponent>(out var manager, EntityManager.ComponentFactory) &&
_solutionContainer.TryGetSolution(manager, grindableSolutionId, out var grindableSolution))
{
var data = new ReagentEntitySourceData(

View File

@@ -46,6 +46,8 @@ namespace Content.Client.Chemistry.UI
_window.CreateBottleButton.OnPressed += _ => SendMessage(
new ChemMasterOutputToBottleMessage(
(uint) _window.BottleDosage.Value, _window.LabelLine));
_window.BufferSortButton.OnPressed += _ => SendMessage(
new ChemMasterSortingTypeCycleMessage());
for (uint i = 0; i < _window.PillTypeButtons.Length; i++)
{

View File

@@ -34,6 +34,7 @@
<Label Text="{Loc 'chem-master-window-buffer-text'}" />
<Control HorizontalExpand="True" />
<Button MinSize="80 0" Name="BufferTransferButton" Access="Public" Text="{Loc 'chem-master-window-transfer-button'}" ToggleMode="True" StyleClasses="OpenRight" />
<Button MinSize="80 0" Name="BufferSortButton" Access="Public" Text="{Loc 'chem-master-window-sort-type-none'}" StyleClasses="OpenBoth" />
<Button MinSize="80 0" Name="BufferDiscardButton" Access="Public" Text="{Loc 'chem-master-window-discard-button'}" ToggleMode="True" StyleClasses="OpenLeft" />
</BoxContainer>

View File

@@ -140,17 +140,17 @@ namespace Content.Client.Chemistry.UI
// Ensure the Panel Info is updated, including UI elements for Buffer Volume, Output Container and so on
UpdatePanelInfo(castState);
BufferCurrentVolume.Text = $" {castState.BufferCurrentVolume?.Int() ?? 0}u";
InputEjectButton.Disabled = castState.InputContainerInfo is null;
OutputEjectButton.Disabled = castState.OutputContainerInfo is null;
CreateBottleButton.Disabled = castState.OutputContainerInfo?.Reagents == null;
CreatePillButton.Disabled = castState.OutputContainerInfo?.Entities == null;
UpdateDosageFields(castState);
}
//assign default values for pill and bottle fields.
private void UpdateDosageFields(ChemMasterBoundUserInterfaceState castState)
{
@@ -162,8 +162,9 @@ namespace Content.Client.Chemistry.UI
var bufferVolume = castState.BufferCurrentVolume?.Int() ?? 0;
PillDosage.Value = (int)Math.Min(bufferVolume, castState.PillDosageLimit);
PillTypeButtons[castState.SelectedPillType].Pressed = true;
PillNumber.IsValid = x => x >= 0 && x <= pillNumberMax;
PillDosage.IsValid = x => x > 0 && x <= castState.PillDosageLimit;
BottleDosage.IsValid = x => x >= 0 && x <= bottleAmountMax;
@@ -213,6 +214,17 @@ namespace Content.Client.Chemistry.UI
BufferInfo.Children.Clear();
// This has to happen here due to people possibly
// setting sorting before putting any chemicals
BufferSortButton.Text = state.SortingType switch
{
ChemMasterSortingType.Alphabetical => Loc.GetString("chem-master-window-sort-type-alphabetical"),
ChemMasterSortingType.Quantity => Loc.GetString("chem-master-window-sort-type-quantity"),
ChemMasterSortingType.Latest => Loc.GetString("chem-master-window-sort-type-latest"),
_ => Loc.GetString("chem-master-window-sort-type-none")
};
if (!state.BufferReagents.Any())
{
BufferInfo.Children.Add(new Label { Text = Loc.GetString("chem-master-window-buffer-empty-text") });
@@ -235,19 +247,48 @@ namespace Content.Client.Chemistry.UI
};
bufferHBox.AddChild(bufferVol);
// initialises rowCount to allow for striped rows
var rowCount = 0;
// This sets up the needed data for sorting later in a list
// Its done this way to not repeat having to use same code twice (once for sorting
// and once for displaying)
var reagentList = new List<(ReagentId reagentId, string name, Color color, FixedPoint2 quantity)>();
foreach (var (reagent, quantity) in state.BufferReagents)
{
var reagentId = reagent;
_prototypeManager.TryIndex(reagentId.Prototype, out ReagentPrototype? proto);
var name = proto?.LocalizedName ?? Loc.GetString("chem-master-window-unknown-reagent-text");
var reagentColor = proto?.SubstanceColor ?? default(Color);
BufferInfo.Children.Add(BuildReagentRow(reagentColor, rowCount++, name, reagentId, quantity, true, true));
reagentList.Add(new (reagentId, name, reagentColor, quantity));
}
// We sort here since we need sorted list to be filled first.
// You can easily add any new params you need to it.
switch (state.SortingType)
{
case ChemMasterSortingType.Alphabetical:
reagentList = reagentList.OrderBy(x => x.name).ToList();
break;
case ChemMasterSortingType.Quantity:
reagentList = reagentList.OrderByDescending(x => x.quantity).ToList();
break;
case ChemMasterSortingType.Latest:
reagentList = Enumerable.Reverse(reagentList).ToList();
break;
case ChemMasterSortingType.None:
default:
// This case is pointless but it is there for readability
break;
}
// initialises rowCount to allow for striped rows
var rowCount = 0;
foreach (var reagent in reagentList)
{
BufferInfo.Children.Add(BuildReagentRow(reagent.color, rowCount++, reagent.name, reagent.reagentId, reagent.quantity, true, true));
}
}
private void BuildContainerUI(Control control, ContainerInfo? info, bool addReagentButtons)
{
control.Children.Clear();
@@ -295,7 +336,7 @@ namespace Content.Client.Chemistry.UI
_prototypeManager.TryIndex(reagent.Reagent.Prototype, out ReagentPrototype? proto);
var name = proto?.LocalizedName ?? Loc.GetString("chem-master-window-unknown-reagent-text");
var reagentColor = proto?.SubstanceColor ?? default(Color);
control.Children.Add(BuildReagentRow(reagentColor, rowCount++, name, reagent.Reagent, reagent.Quantity, false, addReagentButtons));
}
}
@@ -315,7 +356,7 @@ namespace Content.Client.Chemistry.UI
}
//this calls the separated button builder, and stores the return to render after labels
var reagentButtonConstructors = CreateReagentTransferButtons(reagent, isBuffer, addReagentButtons);
// Create the row layout with the color panel
var rowContainer = new BoxContainer
{
@@ -358,7 +399,7 @@ namespace Content.Client.Chemistry.UI
Children = { rowContainer }
};
}
public string LabelLine
{
get => LabelLineEdit.Text;

View File

@@ -27,7 +27,7 @@ public sealed class FlatpackSystem : SharedFlatpackSystem
if (!PrototypeManager.TryIndex<EntityPrototype>(machineBoardId, out var machineBoardPrototype))
return;
if (!machineBoardPrototype.TryGetComponent<SpriteComponent>(out var sprite))
if (!machineBoardPrototype.TryGetComponent<SpriteComponent>(out var sprite, EntityManager.ComponentFactory))
return;
Color? color = null;

View File

@@ -59,13 +59,13 @@ namespace Content.Client.Gameplay
// Version number watermark.
_version = new Label();
_version.FontColorOverride = Color.FromHex("#FFFFFF20");
_version.Text = _changelog.GetClientVersion();
_version.Visible = VersionVisible();
UserInterfaceManager.PopupRoot.AddChild(_version);
_configurationManager.OnValueChanged(CCVars.HudVersionWatermark, (show) => { _version.Visible = VersionVisible(); });
_configurationManager.OnValueChanged(CCVars.ForceClientHudVersionWatermark, (show) => { _version.Visible = VersionVisible(); });
_configurationManager.OnValueChanged(CCVars.HudVersionWatermark, (show) => { _version.Visible = VersionVisible(); }, true);
_configurationManager.OnValueChanged(CCVars.ForceClientHudVersionWatermark, (show) => { _version.Visible = VersionVisible(); }, true);
// TODO make this centered or something
LayoutContainer.SetPosition(_version, new Vector2(800, 0));
LayoutContainer.SetPosition(_version, new Vector2(70, 0));
}
// This allows servers to force the watermark on clients

View File

@@ -155,7 +155,7 @@ namespace Content.Client.Ghost
private void OnGhostState(EntityUid uid, GhostComponent component, ref AfterAutoHandleStateEvent args)
{
if (TryComp<SpriteComponent>(uid, out var sprite))
sprite.LayerSetColor(0, component.color);
sprite.LayerSetColor(0, component.Color);
if (uid != _playerManager.LocalEntity)
return;

View File

@@ -2,11 +2,15 @@
using Content.Client.Items;
using Content.Shared.Implants;
using Content.Shared.Implants.Components;
using Robust.Shared.Prototypes;
namespace Content.Client.Implants;
public sealed class ImplanterSystem : SharedImplanterSystem
{
[Dependency] private readonly SharedUserInterfaceSystem _uiSystem = default!;
[Dependency] private readonly IPrototypeManager _proto = default!;
public override void Initialize()
{
base.Initialize();
@@ -17,6 +21,18 @@ public sealed class ImplanterSystem : SharedImplanterSystem
private void OnHandleImplanterState(EntityUid uid, ImplanterComponent component, ref AfterAutoHandleStateEvent args)
{
if (_uiSystem.TryGetOpenUi<DeimplantBoundUserInterface>(uid, DeimplantUiKey.Key, out var bui))
{
Dictionary<string, string> implants = new();
foreach (var implant in component.DeimplantWhitelist)
{
if (_proto.TryIndex(implant, out var proto))
implants.Add(proto.ID, proto.Name);
}
bui.UpdateState(implants, component.DeimplantChosen);
}
component.UiUpdateNeeded = true;
}
}

View File

@@ -0,0 +1,35 @@
using Content.Shared.Implants;
using Robust.Client.UserInterface;
using Robust.Shared.Prototypes;
namespace Content.Client.Implants.UI;
public sealed class DeimplantBoundUserInterface : BoundUserInterface
{
[Dependency] private readonly IPrototypeManager _protomanager = default!;
[ViewVariables]
private DeimplantChoiceWindow? _window;
public DeimplantBoundUserInterface(EntityUid owner, Enum uiKey) : base(owner, uiKey)
{
}
protected override void Open()
{
base.Open();
_window = this.CreateWindow<DeimplantChoiceWindow>();
_window.OnImplantChange += implant => SendMessage(new DeimplantChangeVerbMessage(implant));
}
public void UpdateState(Dictionary<string, string> implantList, string? implant)
{
if (_window != null)
{
_window.UpdateImplantList(implantList);
_window.UpdateState(implant);
}
}
}

View File

@@ -0,0 +1,12 @@
<controls:FancyWindow xmlns="https://spacestation14.io"
xmlns:controls="clr-namespace:Content.Client.UserInterface.Controls"
Title="{Loc 'implanter-set-draw-window'}"
MinSize="5 30">
<BoxContainer Orientation="Vertical" Margin="10 5">
<Label Text="{Loc 'implanter-set-draw-info'}" Margin="0 0 0 5"/>
<BoxContainer Orientation="Horizontal">
<Label Text="{Loc 'implanter-set-draw-type'}" Margin="0 0 5 0"/>
<OptionButton Name="ImplantSelector"/> <!-- Populated in LoadVerbs -->
</BoxContainer>
</BoxContainer>
</controls:FancyWindow>

View File

@@ -0,0 +1,53 @@
using Content.Client.UserInterface.Controls;
using Robust.Client.AutoGenerated;
using Robust.Client.UserInterface.XAML;
using System.Linq;
namespace Content.Client.Implants.UI;
[GenerateTypedNameReferences]
public sealed partial class DeimplantChoiceWindow : FancyWindow
{
public Action<string?>? OnImplantChange;
private Dictionary<string, string> _implants = new();
private string? _chosenImplant;
public DeimplantChoiceWindow()
{
RobustXamlLoader.Load(this);
ImplantSelector.OnItemSelected += args =>
{
OnImplantChange?.Invoke(_implants.ElementAt(args.Id).Key);
ImplantSelector.SelectId(args.Id);
};
}
public void UpdateImplantList(Dictionary<string, string> implants)
{
_implants = implants;
int i = 0;
ImplantSelector.Clear();
foreach (var implantDict in _implants)
{
ImplantSelector.AddItem(implantDict.Value, i);
i++;
}
}
public void UpdateState(string? implant)
{
_chosenImplant = implant;
for (int id = 0; id < ImplantSelector.ItemCount; id++)
{
if (_implants.ElementAt(id).Key.Equals(_chosenImplant))
{
ImplantSelector.SelectId(id);
break;
}
}
}
}

View File

@@ -4,17 +4,20 @@ using Content.Client.UserInterface.Controls;
using Content.Shared.Implants.Components;
using Robust.Client.UserInterface;
using Robust.Client.UserInterface.Controls;
using Robust.Shared.Prototypes;
using Robust.Shared.Timing;
namespace Content.Client.Implants.UI;
public sealed class ImplanterStatusControl : Control
{
[Dependency] private readonly IPrototypeManager _prototype = default!;
private readonly ImplanterComponent _parent;
private readonly RichTextLabel _label;
public ImplanterStatusControl(ImplanterComponent parent)
{
IoCManager.InjectDependencies(this);
_parent = parent;
_label = new RichTextLabel { StyleClasses = { StyleNano.StyleClassItemStatus } };
_label.MaxWidth = 350;
@@ -43,12 +46,25 @@ public sealed class ImplanterStatusControl : Control
_ => Loc.GetString("injector-invalid-injector-toggle-mode")
};
var implantName = _parent.ImplanterSlot.HasItem
? _parent.ImplantData.Item1
: Loc.GetString("implanter-empty-text");
if (_parent.CurrentMode == ImplanterToggleMode.Draw)
{
string implantName = _parent.DeimplantChosen != null
? (_prototype.TryIndex(_parent.DeimplantChosen.Value, out EntityPrototype? implantProto) ? implantProto.Name : Loc.GetString("implanter-empty-text"))
: Loc.GetString("implanter-empty-text");
_label.SetMarkup(Loc.GetString("implanter-label",
("implantName", implantName),
("modeString", modeStringLocalized)));
_label.SetMarkup(Loc.GetString("implanter-label-draw",
("implantName", implantName),
("modeString", modeStringLocalized)));
}
else
{
var implantName = _parent.ImplanterSlot.HasItem
? _parent.ImplantData.Item1
: Loc.GetString("implanter-empty-text");
_label.SetMarkup(Loc.GetString("implanter-label-inject",
("implantName", implantName),
("modeString", modeStringLocalized)));
}
}
}

View File

@@ -94,8 +94,17 @@ public sealed partial class LatheMenu : DefaultWindow
if (!_prototypeManager.TryIndex(recipe, out var proto))
continue;
if (CurrentCategory != null && proto.Category != CurrentCategory)
continue;
// Category filtering
if (CurrentCategory != null)
{
if (proto.Categories.Count <= 0)
continue;
var validRecipe = proto.Categories.Any(category => category == CurrentCategory);
if (!validRecipe)
continue;
}
if (SearchBar.Text.Trim().Length != 0)
{
@@ -179,18 +188,22 @@ public sealed partial class LatheMenu : DefaultWindow
public void UpdateCategories()
{
// Get categories from recipes
var currentCategories = new List<ProtoId<LatheCategoryPrototype>>();
foreach (var recipeId in Recipes)
{
var recipe = _prototypeManager.Index(recipeId);
if (recipe.Category == null)
if (recipe.Categories.Count <= 0)
continue;
if (currentCategories.Contains(recipe.Category.Value))
continue;
foreach (var category in recipe.Categories)
{
if (currentCategories.Contains(category))
continue;
currentCategories.Add(recipe.Category.Value);
currentCategories.Add(category);
}
}
if (Categories != null && (Categories.Count == currentCategories.Count || !Categories.All(currentCategories.Contains)))

View File

@@ -10,7 +10,7 @@ using Robust.Client.Player;
namespace Content.Client.Movement.Systems;
public partial class EyeCursorOffsetSystem : EntitySystem
public sealed partial class EyeCursorOffsetSystem : EntitySystem
{
[Dependency] private readonly IEyeManager _eyeManager = default!;
[Dependency] private readonly IInputManager _inputManager = default!;

View File

@@ -9,6 +9,7 @@
<tabs:KeyRebindTab Name="KeyRebindTab" />
<tabs:AudioTab Name="AudioTab" />
<tabs:AccessibilityTab Name="AccessibilityTab" />
<tabs:AdminOptionsTab Name="AdminOptionsTab" />
<!-- CP14-options-menu-start -->
<options:CP14OptionsMenuMainTab Name="CP14OptionsMenuTab"/>
<!-- CP14-options-menu-end -->

View File

@@ -1,4 +1,4 @@
using Content.Client.Options.UI.Tabs;
using Content.Client.Administration.Managers;
using Robust.Client.AutoGenerated;
using Robust.Client.UserInterface.CustomControls;
using Robust.Client.UserInterface.XAML;
@@ -8,6 +8,8 @@ namespace Content.Client.Options.UI
[GenerateTypedNameReferences]
public sealed partial class OptionsMenu : DefaultWindow
{
[Dependency] private readonly IClientAdminManager _adminManager = default!;
public OptionsMenu()
{
RobustXamlLoader.Load(this);
@@ -18,6 +20,7 @@ namespace Content.Client.Options.UI
Tabs.SetTabTitle(2, Loc.GetString("ui-options-tab-controls"));
Tabs.SetTabTitle(3, Loc.GetString("ui-options-tab-audio"));
Tabs.SetTabTitle(4, Loc.GetString("ui-options-tab-accessibility"));
Tabs.SetTabTitle(5, Loc.GetString("ui-options-tab-admin"));
// CP14-options-menu-start
Tabs.SetTabTitle(5, Loc.GetString("cp14-ui-options-tab-main"));
@@ -28,10 +31,14 @@ namespace Content.Client.Options.UI
public void UpdateTabs()
{
var isAdmin = _adminManager.IsAdmin(true);
Tabs.SetTabVisible(5, isAdmin);
GraphicsTab.Control.ReloadValues();
MiscTab.Control.ReloadValues();
AccessibilityTab.Control.ReloadValues();
AudioTab.Control.ReloadValues();
AdminOptionsTab.Control.ReloadValues();
}
}
}

View File

@@ -7,8 +7,11 @@
<CheckBox Name="ReducedMotionCheckBox" Text="{Loc 'ui-options-reduced-motion'}" />
<CheckBox Name="EnableColorNameCheckBox" Text="{Loc 'ui-options-enable-color-name'}" />
<CheckBox Name="ColorblindFriendlyCheckBox" Text="{Loc 'ui-options-colorblind-friendly'}" />
<ui:OptionSlider Name="ChatWindowOpacitySlider" Title="{Loc 'ui-options-chat-window-opacity'}" />
<ui:OptionSlider Name="ScreenShakeIntensitySlider" Title="{Loc 'ui-options-screen-shake-intensity'}" />
<ui:OptionSlider Name="ChatWindowOpacitySlider" Title="{Loc 'ui-options-chat-window-opacity'}" />
<ui:OptionSlider Name="SpeechBubbleTextOpacitySlider" Title="{Loc 'ui-options-speech-bubble-text-opacity'}" />
<ui:OptionSlider Name="SpeechBubbleSpeakerOpacitySlider" Title="{Loc 'ui-options-speech-bubble-speaker-opacity'}" />
<ui:OptionSlider Name="SpeechBubbleBackgroundOpacitySlider" Title="{Loc 'ui-options-speech-bubble-background-opacity'}" />
</BoxContainer>
</ScrollContainer>
<ui:OptionsTabControlRow Name="Control" Access="Public" />

View File

@@ -15,8 +15,11 @@ public sealed partial class AccessibilityTab : Control
Control.AddOptionCheckBox(CCVars.ChatEnableColorName, EnableColorNameCheckBox);
Control.AddOptionCheckBox(CCVars.AccessibilityColorblindFriendly, ColorblindFriendlyCheckBox);
Control.AddOptionCheckBox(CCVars.ReducedMotion, ReducedMotionCheckBox);
Control.AddOptionPercentSlider(CCVars.ChatWindowOpacity, ChatWindowOpacitySlider);
Control.AddOptionPercentSlider(CCVars.ScreenShakeIntensity, ScreenShakeIntensitySlider);
Control.AddOptionPercentSlider(CCVars.ChatWindowOpacity, ChatWindowOpacitySlider);
Control.AddOptionPercentSlider(CCVars.SpeechBubbleTextOpacity, SpeechBubbleTextOpacitySlider);
Control.AddOptionPercentSlider(CCVars.SpeechBubbleSpeakerOpacity, SpeechBubbleSpeakerOpacitySlider);
Control.AddOptionPercentSlider(CCVars.SpeechBubbleBackgroundOpacity, SpeechBubbleBackgroundOpacitySlider);
Control.Initialize();
}

View File

@@ -0,0 +1,12 @@
<Control xmlns="https://spacestation14.io"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:ui="clr-namespace:Content.Client.Options.UI">
<BoxContainer Orientation="Vertical">
<ScrollContainer VerticalExpand="True" HScrollEnabled="False">
<BoxContainer Orientation="Vertical" Margin="8">
<CheckBox Name="EnableClassicOverlayCheckBox" Text="{Loc 'ui-options-enable-classic-overlay'}" />
</BoxContainer>
</ScrollContainer>
<ui:OptionsTabControlRow Name="Control" Access="Public" />
</BoxContainer>
</Control>

View File

@@ -0,0 +1,20 @@
using Content.Shared.CCVar;
using Robust.Client.AutoGenerated;
using Robust.Client.UserInterface;
using Robust.Client.UserInterface.XAML;
namespace Content.Client.Options.UI.Tabs;
[GenerateTypedNameReferences]
public sealed partial class AdminOptionsTab : Control
{
public AdminOptionsTab()
{
RobustXamlLoader.Load(this);
Control.AddOptionCheckBox(CCVars.AdminOverlayClassic, EnableClassicOverlayCheckBox);
Control.Initialize();
}
}

View File

@@ -67,8 +67,11 @@ public sealed class SubFloorHideSystem : SharedSubFloorHideSystem
// allows a t-ray to show wires/pipes above carpets/puddles
if (scannerRevealed)
{
component.OriginalDrawDepth ??= args.Sprite.DrawDepth;
args.Sprite.DrawDepth = (int) Shared.DrawDepth.DrawDepth.FloorObjects + 1;
if (component.OriginalDrawDepth is not null)
return;
component.OriginalDrawDepth = args.Sprite.DrawDepth;
var drawDepthDifference = Shared.DrawDepth.DrawDepth.ThickPipe - Shared.DrawDepth.DrawDepth.Puddles;
args.Sprite.DrawDepth -= drawDepthDifference - 1;
}
else if (component.OriginalDrawDepth.HasValue)
{

View File

@@ -0,0 +1,29 @@
using System.Linq;
using Content.Shared.SubFloor;
using Robust.Shared.Map.Components;
namespace Content.Client.SubFloor;
public sealed class TrayScanRevealSystem : EntitySystem
{
[Dependency] private readonly SharedTransformSystem _transform = default!;
[Dependency] private readonly SharedMapSystem _map = default!;
public bool IsUnderRevealingEntity(EntityUid uid)
{
var gridUid = _transform.GetGrid(uid);
if (gridUid is null)
return false;
var gridComp = Comp<MapGridComponent>(gridUid.Value);
var position = _transform.GetGridOrMapTilePosition(uid);
return HasTrayScanReveal(((EntityUid)gridUid, gridComp), position);
}
private bool HasTrayScanReveal(Entity<MapGridComponent> ent, Vector2i position)
{
var anchoredEnum = _map.GetAnchoredEntities(ent, position);
return anchoredEnum.Any(HasComp<TrayScanRevealComponent>);
}
}

View File

@@ -19,6 +19,7 @@ public sealed class TrayScannerSystem : SharedTrayScannerSystem
[Dependency] private readonly SharedAppearanceSystem _appearance = default!;
[Dependency] private readonly SharedHandsSystem _hands = default!;
[Dependency] private readonly SharedTransformSystem _transform = default!;
[Dependency] private readonly TrayScanRevealSystem _trayScanReveal = default!;
private const string TRayAnimationKey = "trays";
private const double AnimationLength = 0.3;
@@ -82,7 +83,7 @@ public sealed class TrayScannerSystem : SharedTrayScannerSystem
foreach (var (uid, comp) in inRange)
{
if (comp.IsUnderCover)
if (comp.IsUnderCover || _trayScanReveal.IsUnderRevealingEntity(uid))
EnsureComp<TrayRevealedComponent>(uid);
}
}

View File

@@ -2,6 +2,7 @@ using Content.Client.Clothing;
using Content.Client.Items.Systems;
using Content.Shared.Clothing;
using Content.Shared.Hands;
using Content.Shared.Inventory;
using Content.Shared.Item;
using Content.Shared.Toggleable;
using Robust.Client.GameObjects;
@@ -62,7 +63,16 @@ public sealed class ToggleableLightVisualsSystem : VisualizerSystem<ToggleableLi
|| !enabled)
return;
if (!component.ClothingVisuals.TryGetValue(args.Slot, out var layers))
if (!TryComp(args.Equipee, out InventoryComponent? inventory))
return;
List<PrototypeLayerData>? layers = null;
// attempt to get species specific data
if (inventory.SpeciesId != null)
component.ClothingVisuals.TryGetValue($"{args.Slot}-{inventory.SpeciesId}", out layers);
// No species specific data. Try to default to generic data.
if (layers == null && !component.ClothingVisuals.TryGetValue(args.Slot, out layers))
return;
var modulate = AppearanceSystem.TryGetData<Color>(uid, ToggleableLightVisuals.Color, out var color, appearance);

View File

@@ -74,7 +74,7 @@ public sealed class CloseRecentWindowUIController : UIController
/// internal recentlyInteractedWindows tracking.
/// </summary>
/// <param name="window"></param>
private void SetMostRecentlyInteractedWindow(BaseWindow window)
public void SetMostRecentlyInteractedWindow(BaseWindow window)
{
// Search through the list and see if already added.
// (This search is backwards since it's fairly common that the user is clicking the same
@@ -134,7 +134,6 @@ public sealed class CloseRecentWindowUIController : UIController
if (window.IsOpen)
return true;
recentlyInteractedWindows.RemoveAt(i);
// continue going down the list, hoping to find a still-open window
}

View File

@@ -5,6 +5,7 @@ using Content.Client.Interaction;
using Content.Client.Storage;
using Content.Client.Storage.Systems;
using Content.Client.UserInterface.Systems.Hotbar.Widgets;
using Content.Client.UserInterface.Systems.Info;
using Content.Client.UserInterface.Systems.Storage.Controls;
using Content.Client.Verbs.UI;
using Content.Shared.CCVar;
@@ -37,6 +38,7 @@ public sealed class StorageUIController : UIController, IOnSystemChanged<Storage
[Dependency] private readonly IConfigurationManager _configuration = default!;
[Dependency] private readonly IInputManager _input = default!;
[Dependency] private readonly IPlayerManager _player = default!;
[Dependency] private readonly CloseRecentWindowUIController _closeRecentWindowUIController = default!;
[UISystemDependency] private readonly StorageSystem _storage = default!;
[UISystemDependency] private readonly UserInterfaceSystem _ui = default!;
@@ -98,6 +100,7 @@ public sealed class StorageUIController : UIController, IOnSystemChanged<Storage
if (StaticStorageUIEnabled)
{
UIManager.GetActiveUIWidgetOrNull<HotbarGui>()?.StorageContainer.AddChild(window);
_closeRecentWindowUIController.SetMostRecentlyInteractedWindow(window);
}
else
{

View File

@@ -6,10 +6,8 @@ using Content.Server.Cargo.Systems;
using Content.Server.Nutrition.Components;
using Content.Server.Nutrition.EntitySystems;
using Content.Shared.Cargo.Prototypes;
using Content.Shared.IdentityManagement;
using Content.Shared.Prototypes;
using Content.Shared.Stacks;
using Content.Shared.Tag;
using Content.Shared.Whitelist;
using Robust.Shared.GameObjects;
using Robust.Shared.Map;
@@ -67,7 +65,7 @@ public sealed class CargoTest
var testMap = await pair.CreateTestMap();
var entManager = server.ResolveDependency<IEntityManager>();
var mapManager = server.ResolveDependency<IMapManager>();
var mapSystem = server.System<SharedMapSystem>();
var protoManager = server.ResolveDependency<IPrototypeManager>();
var cargo = entManager.System<CargoSystem>();
@@ -93,7 +91,7 @@ public sealed class CargoTest
}
});
mapManager.DeleteMap(mapId);
mapSystem.DeleteMap(mapId);
});
await pair.CleanReturnAsync();
@@ -151,6 +149,7 @@ public sealed class CargoTest
var testMap = await pair.CreateTestMap();
var entManager = server.ResolveDependency<IEntityManager>();
var mapSystem = server.System<SharedMapSystem>();
var mapManager = server.ResolveDependency<IMapManager>();
var protoManager = server.ResolveDependency<IPrototypeManager>();
var componentFactory = server.ResolveDependency<IComponentFactory>();
@@ -207,7 +206,7 @@ public sealed class CargoTest
entManager.DeleteEntity(ent);
}
mapManager.DeleteMap(mapId);
mapSystem.DeleteMap(mapId);
});
await pair.CleanReturnAsync();

View File

@@ -6,7 +6,6 @@ using Robust.Server.GameObjects;
using Robust.Server.Player;
using Robust.Shared.Containers;
using Robust.Shared.GameObjects;
using Robust.Shared.Map;
namespace Content.IntegrationTests.Tests.Hands;
@@ -38,7 +37,7 @@ public sealed class HandTests
var entMan = server.ResolveDependency<IEntityManager>();
var playerMan = server.ResolveDependency<IPlayerManager>();
var mapMan = server.ResolveDependency<IMapManager>();
var mapSystem = server.System<SharedMapSystem>();
var sys = entMan.System<SharedHandsSystem>();
var tSys = entMan.System<TransformSystem>();
@@ -69,7 +68,7 @@ public sealed class HandTests
await pair.RunTicksSync(5);
Assert.That(hands.ActiveHandEntity, Is.Null);
await server.WaitPost(() => mapMan.DeleteMap(data.MapId));
await server.WaitPost(() => mapSystem.DeleteMap(data.MapId));
await pair.CleanReturnAsync();
}
@@ -87,7 +86,7 @@ public sealed class HandTests
var entMan = server.ResolveDependency<IEntityManager>();
var playerMan = server.ResolveDependency<IPlayerManager>();
var mapMan = server.ResolveDependency<IMapManager>();
var mapSystem = server.System<SharedMapSystem>();
var sys = entMan.System<SharedHandsSystem>();
var tSys = entMan.System<TransformSystem>();
var containerSystem = server.System<SharedContainerSystem>();
@@ -134,7 +133,7 @@ public sealed class HandTests
Assert.That(hands.ActiveHandEntity, Is.Not.EqualTo(item));
Assert.That(containerSystem.IsInSameOrNoContainer((player, xform), (item, itemXform)));
await server.WaitPost(() => mapMan.DeleteMap(map.MapId));
await server.WaitPost(() => mapSystem.DeleteMap(map.MapId));
await pair.CleanReturnAsync();
}
}

View File

@@ -1,6 +1,5 @@
using Content.Shared.Inventory;
using Robust.Shared.GameObjects;
using Robust.Shared.Map;
namespace Content.IntegrationTests.Tests
{
@@ -67,7 +66,7 @@ namespace Content.IntegrationTests.Tests
EntityUid pocketItem = default;
InventorySystem invSystem = default!;
var mapMan = server.ResolveDependency<IMapManager>();
var mapSystem = server.System<SharedMapSystem>();
var entityMan = server.ResolveDependency<IEntityManager>();
await server.WaitAssertion(() =>
@@ -129,7 +128,7 @@ namespace Content.IntegrationTests.Tests
Assert.That(!invSystem.TryGetSlotEntity(human, "pocket1", out _));
});
mapMan.DeleteMap(testMap.MapId);
mapSystem.DeleteMap(testMap.MapId);
});
await pair.CleanReturnAsync();

View File

@@ -260,7 +260,7 @@ public abstract partial class InteractionTest
[TearDown]
public async Task TearDownInternal()
{
await Server.WaitPost(() => MapMan.DeleteMap(MapId));
await Server.WaitPost(() => MapSystem.DeleteMap(MapId));
await Pair.CleanReturnAsync();
await TearDown();
}

View File

@@ -346,7 +346,7 @@ public sealed class MaterialArbitrageTest
}
});
await server.WaitPost(() => mapManager.DeleteMap(testMap.MapId));
await server.WaitPost(() => mapSystem.DeleteMap(testMap.MapId));
await pair.CleanReturnAsync();
async Task<double> GetSpawnedPrice(Dictionary<string, int> ents)

View File

@@ -3,7 +3,6 @@ using Content.Server.Stack;
using Content.Shared.Stacks;
using Content.Shared.Materials;
using Robust.Shared.GameObjects;
using Robust.Shared.Map;
using Robust.Shared.Prototypes;
namespace Content.IntegrationTests.Tests.Materials
@@ -24,7 +23,7 @@ namespace Content.IntegrationTests.Tests.Materials
var server = pair.Server;
await server.WaitIdleAsync();
var mapManager = server.ResolveDependency<IMapManager>();
var mapSystem = server.System<SharedMapSystem>();
var prototypeManager = server.ResolveDependency<IPrototypeManager>();
var entityManager = server.ResolveDependency<IEntityManager>();
@@ -59,7 +58,7 @@ namespace Content.IntegrationTests.Tests.Materials
}
});
mapManager.DeleteMap(testMap.MapId);
mapSystem.DeleteMap(testMap.MapId);
});
await pair.CleanReturnAsync();

View File

@@ -81,7 +81,7 @@ public sealed partial class MindTests
var testMap2 = await pair.CreateTestMap();
var entMan = server.ResolveDependency<IServerEntityManager>();
var mapManager = server.ResolveDependency<IMapManager>();
var mapSystem = server.System<SharedMapSystem>();
var playerMan = server.ResolveDependency<IPlayerManager>();
var player = playerMan.Sessions.Single();
@@ -101,7 +101,7 @@ public sealed partial class MindTests
});
await pair.RunTicksSync(5);
await server.WaitAssertion(() => mapManager.DeleteMap(testMap.MapId));
await server.WaitAssertion(() => mapSystem.DeleteMap(testMap.MapId));
await pair.RunTicksSync(5);
await server.WaitAssertion(() =>

View File

@@ -1,6 +1,7 @@
using System.Collections.Generic;
using System.IO;
using System.Linq;
using Content.Server.Administration.Systems;
using Content.Server.GameTicking;
using Content.Server.Maps;
using Content.Server.Shuttles.Components;
@@ -42,6 +43,7 @@ namespace Content.IntegrationTests.Tests
//CrystallEdge Map replacement
//CrystallEdge Map replacement end
AdminTestArenaSystem.ArenaMapPath
};
private static readonly string[] DoNotMapWhitelist =

View File

@@ -2,7 +2,6 @@ using System.Linq;
using Content.Shared.Roles;
using Content.Server.Storage.EntitySystems;
using Robust.Shared.GameObjects;
using Robust.Shared.Map;
using Robust.Shared.Collections;
namespace Content.IntegrationTests.Tests.Roles;
@@ -19,7 +18,7 @@ public sealed class StartingGearPrototypeStorageTest
var settings = new PoolSettings { Connected = true, Dirty = true };
await using var pair = await PoolManager.GetServerClient(settings);
var server = pair.Server;
var mapManager = server.ResolveDependency<IMapManager>();
var mapSystem = server.System<SharedMapSystem>();
var storageSystem = server.System<StorageSystem>();
var protos = server.ProtoMan
@@ -64,7 +63,7 @@ public sealed class StartingGearPrototypeStorageTest
}
}
mapManager.DeleteMap(testMap.MapId);
mapSystem.DeleteMap(testMap.MapId);
});
await pair.CleanReturnAsync();

View File

@@ -55,5 +55,16 @@ namespace Content.Server.Abilities.Mime
[DataField]
public ProtoId<AlertPrototype> VowBrokenAlert = "VowBroken";
/// <summary>
/// Does this component prevent the mime from writing on paper while their vow is active?
/// </summary>
[DataField]
public bool PreventWriting = false;
/// <summary>
/// What message is displayed when the mime fails to write?
/// </summary>
[DataField]
public LocId FailWriteMessage = "paper-component-illiterate-mime";
}
}

View File

@@ -5,6 +5,7 @@ using Content.Shared.Actions.Events;
using Content.Shared.Alert;
using Content.Shared.Coordinates.Helpers;
using Content.Shared.Maps;
using Content.Shared.Paper;
using Content.Shared.Physics;
using Robust.Shared.Containers;
using Robust.Shared.Map;
@@ -55,6 +56,13 @@ namespace Content.Server.Abilities.Mime
private void OnComponentInit(EntityUid uid, MimePowersComponent component, ComponentInit args)
{
EnsureComp<MutedComponent>(uid);
if (component.PreventWriting)
{
EnsureComp<BlockWritingComponent>(uid, out var illiterateComponent);
illiterateComponent.FailWriteMessage = component.FailWriteMessage;
Dirty(uid, illiterateComponent);
}
_alertsSystem.ShowAlert(uid, component.VowAlert);
_actionsSystem.AddAction(uid, ref component.InvisibleWallActionEntity, component.InvisibleWallAction, uid);
}
@@ -123,6 +131,8 @@ namespace Content.Server.Abilities.Mime
mimePowers.VowBroken = true;
mimePowers.VowRepentTime = _timing.CurTime + mimePowers.VowCooldown;
RemComp<MutedComponent>(uid);
if (mimePowers.PreventWriting)
RemComp<BlockWritingComponent>(uid);
_alertsSystem.ClearAlert(uid, mimePowers.VowAlert);
_alertsSystem.ShowAlert(uid, mimePowers.VowBrokenAlert);
_actionsSystem.RemoveAction(uid, mimePowers.InvisibleWallActionEntity);
@@ -146,6 +156,13 @@ namespace Content.Server.Abilities.Mime
mimePowers.ReadyToRepent = false;
mimePowers.VowBroken = false;
AddComp<MutedComponent>(uid);
if (mimePowers.PreventWriting)
{
EnsureComp<BlockWritingComponent>(uid, out var illiterateComponent);
illiterateComponent.FailWriteMessage = mimePowers.FailWriteMessage;
Dirty(uid, illiterateComponent);
}
_alertsSystem.ClearAlert(uid, mimePowers.VowBrokenAlert);
_alertsSystem.ShowAlert(uid, mimePowers.VowAlert);
_actionsSystem.AddAction(uid, ref mimePowers.InvisibleWallActionEntity, mimePowers.InvisibleWallAction, uid);

View File

@@ -74,5 +74,15 @@ namespace Content.Server.Administration.Commands
mindSystem.TransferTo(mind, eUid, ghostOverride);
}
public CompletionResult GetCompletion(IConsoleShell shell, string[] args)
{
if (args.Length == 2)
{
return CompletionResult.FromHintOptions(CompletionHelper.SessionNames(), Loc.GetString("cmd-mind-command-hint"));
}
return CompletionResult.Empty;
}
}
}

View File

@@ -12,6 +12,7 @@ public sealed class AdminTestArenaSystem : EntitySystem
{
[Dependency] private readonly MapLoaderSystem _loader = default!;
[Dependency] private readonly MetaDataSystem _metaDataSystem = default!;
[Dependency] private readonly SharedMapSystem _maps = default!;
public const string ArenaMapPath = "/Maps/Test/admin_test_arena.yml";
@@ -33,17 +34,20 @@ public sealed class AdminTestArenaSystem : EntitySystem
}
var path = new ResPath(ArenaMapPath);
if (!_loader.TryLoadMap(path, out var map, out var grids))
var mapUid = _maps.CreateMap(out var mapId);
if (!_loader.TryLoadGrid(mapId, path, out var grid))
{
QueueDel(mapUid);
throw new Exception($"Failed to load admin arena");
}
ArenaMap[admin.UserId] = map.Value.Owner;
_metaDataSystem.SetEntityName(map.Value.Owner, $"ATAM-{admin.Name}");
ArenaMap[admin.UserId] = mapUid;
_metaDataSystem.SetEntityName(mapUid, $"ATAM-{admin.Name}");
var grid = grids.FirstOrNull();
ArenaGrid[admin.UserId] = grid?.Owner;
if (grid != null)
_metaDataSystem.SetEntityName(grid.Value.Owner, $"ATAG-{admin.Name}");
ArenaGrid[admin.UserId] = grid.Value.Owner;
_metaDataSystem.SetEntityName(grid.Value.Owner, $"ATAG-{admin.Name}");
return (map.Value.Owner, grid?.Owner);
return (mapUid, grid.Value.Owner);
}
}

View File

@@ -759,6 +759,7 @@ namespace Content.Server.Administration.Systems
_gameTicker.RoundDuration().ToString("hh\\:mm\\:ss"),
_gameTicker.RunLevel,
playedSound: playSound,
adminOnly: message.AdminOnly,
noReceivers: nonAfkAdmins.Count == 0
);
_messageQueues[msg.UserId].Enqueue(GenerateAHelpMessage(messageParams));
@@ -790,7 +791,7 @@ namespace Content.Server.Administration.Systems
.ToList();
}
private static DiscordRelayedData GenerateAHelpMessage(AHelpMessageParams parameters)
private DiscordRelayedData GenerateAHelpMessage(AHelpMessageParams parameters)
{
var stringbuilder = new StringBuilder();
@@ -806,7 +807,7 @@ namespace Content.Server.Administration.Systems
if (parameters.RoundTime != string.Empty && parameters.RoundState == GameRunLevel.InRound)
stringbuilder.Append($" **{parameters.RoundTime}**");
if (!parameters.PlayedSound)
stringbuilder.Append(" **(S)**");
stringbuilder.Append($" **{(parameters.AdminOnly ? Loc.GetString("bwoink-message-admin-only") : Loc.GetString("bwoink-message-silent"))}**");
if (parameters.Icon == null)
stringbuilder.Append($" **{parameters.Username}:** ");
else
@@ -869,6 +870,7 @@ namespace Content.Server.Administration.Systems
public string RoundTime { get; set; }
public GameRunLevel RoundState { get; set; }
public bool PlayedSound { get; set; }
public readonly bool AdminOnly;
public bool NoReceivers { get; set; }
public string? Icon { get; set; }
@@ -879,6 +881,7 @@ namespace Content.Server.Administration.Systems
string roundTime,
GameRunLevel roundState,
bool playedSound,
bool adminOnly = false,
bool noReceivers = false,
string? icon = null)
{
@@ -888,6 +891,7 @@ namespace Content.Server.Administration.Systems
RoundTime = roundTime;
RoundState = roundState;
PlayedSound = playedSound;
AdminOnly = adminOnly;
NoReceivers = noReceivers;
Icon = icon;
}

View File

@@ -6,7 +6,7 @@ namespace Content.Server.AlertLevel;
[Prototype("alertLevels")]
public sealed partial class AlertLevelPrototype : IPrototype
{
[IdDataField] public string ID { get; } = default!;
[IdDataField] public string ID { get; private set; } = default!;
/// <summary>
/// Dictionary of alert levels. Keyed by string - the string key is the most important

View File

@@ -28,7 +28,7 @@ public sealed partial class AntagRandomObjectivesComponent : Component
/// Difficulty is checked over all sets, but each set has its own probability and pick count.
/// </summary>
[DataRecord]
public record struct AntagObjectiveSet()
public partial record struct AntagObjectiveSet()
{
/// <summary>
/// The grouping used by the objective system to pick random objectives.

View File

@@ -84,7 +84,7 @@ namespace Content.Server.Bible
}
summonableComp.AlreadySummoned = false;
_popupSystem.PopupEntity(Loc.GetString("bible-summon-respawn-ready", ("book", uid)), uid, PopupType.Medium);
_audio.PlayPvs("/Audio/Effects/radpulse9.ogg", uid, AudioParams.Default.WithVolume(-4f));
_audio.PlayPvs(summonableComp.SummonSound, uid);
// Clean up the accumulator and respawn tracking component
summonableComp.Accumulator = 0;
_remQueue.Enqueue(uid);
@@ -126,7 +126,7 @@ namespace Content.Server.Bible
var selfFailMessage = Loc.GetString(component.LocPrefix + "-heal-fail-self", ("target", Identity.Entity(args.Target.Value, EntityManager)), ("bible", uid));
_popupSystem.PopupEntity(selfFailMessage, args.User, args.User, PopupType.MediumCaution);
_audio.PlayPvs("/Audio/Effects/hit_kick.ogg", args.User);
_audio.PlayPvs(component.BibleHitSound, args.User);
_damageableSystem.TryChangeDamage(args.Target.Value, component.DamageOnFail, true, origin: uid);
_delay.TryResetDelay((uid, useDelay));
return;

View File

@@ -1,11 +1,23 @@
using Content.Shared.Damage;
using Robust.Shared.Audio;
using Robust.Shared.Prototypes;
namespace Content.Server.Bible.Components
{
[RegisterComponent]
public sealed partial class BibleComponent : Component
{
/// <summary>
/// Default sound when bible hits somebody.
/// </summary>
private static readonly ProtoId<SoundCollectionPrototype> DefaultBibleHit = new("BibleHit");
/// <summary>
/// Sound to play when bible hits somebody.
/// </summary>
[DataField]
public SoundSpecifier BibleHitSound = new SoundCollectionSpecifier(DefaultBibleHit, AudioParams.Default.WithVolume(-4f));
/// <summary>
/// Damage that will be healed on a success
/// </summary>

View File

@@ -1,3 +1,4 @@
using Robust.Shared.Audio;
using Robust.Shared.Prototypes;
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype;
@@ -9,6 +10,17 @@ namespace Content.Server.Bible.Components
[RegisterComponent]
public sealed partial class SummonableComponent : Component
{
/// <summary>
/// Default sound to play when entity is summoned.
/// </summary>
private static readonly ProtoId<SoundCollectionPrototype> DefaultSummonSound = new("Summon");
/// <summary>
/// Sound to play when entity is summoned.
/// </summary>
[DataField]
public SoundSpecifier SummonSound = new SoundCollectionSpecifier(DefaultSummonSound, AudioParams.Default.WithVolume(-4f));
/// <summary>
/// Used for a special item only the Chaplain can summon. Usually a mob, but supports regular items too.
/// </summary>

View File

@@ -14,7 +14,7 @@ namespace Content.Server.Botany;
[Prototype("seed")]
public sealed partial class SeedPrototype : SeedData, IPrototype
{
[IdDataField] public string ID { get; private init; } = default!;
[IdDataField] public string ID { get; private set; } = default!;
}
public enum HarvestType : byte

View File

@@ -427,6 +427,7 @@ public sealed class CartridgeLoaderSystem : SharedCartridgeLoaderSystem
private void OnUiMessage(EntityUid uid, CartridgeLoaderComponent component, CartridgeUiMessage args)
{
var cartridgeEvent = args.MessageEvent;
cartridgeEvent.User = args.Actor;
cartridgeEvent.LoaderUid = GetNetEntity(uid);
cartridgeEvent.Actor = args.Actor;

View File

@@ -1,12 +1,21 @@
using Content.Shared.CartridgeLoader.Cartridges;
using Content.Shared.Paper;
using Robust.Shared.Audio;
using Robust.Shared.Prototypes;
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom;
namespace Content.Server.CartridgeLoader.Cartridges;
[RegisterComponent]
[Access(typeof(LogProbeCartridgeSystem))]
[RegisterComponent, Access(typeof(LogProbeCartridgeSystem))]
[AutoGenerateComponentPause]
public sealed partial class LogProbeCartridgeComponent : Component
{
/// <summary>
/// The name of the scanned entity, sent to clients when they open the UI.
/// </summary>
[DataField]
public string EntityName = string.Empty;
/// <summary>
/// The list of pulled access logs
/// </summary>
@@ -18,4 +27,25 @@ public sealed partial class LogProbeCartridgeComponent : Component
/// </summary>
[DataField, ViewVariables(VVAccess.ReadWrite)]
public SoundSpecifier SoundScan = new SoundPathSpecifier("/Audio/Machines/scan_finish.ogg");
/// <summary>
/// Paper to spawn when printing logs.
/// </summary>
[DataField]
public EntProtoId<PaperComponent> PaperPrototype = "PaperAccessLogs";
[DataField]
public SoundSpecifier PrintSound = new SoundPathSpecifier("/Audio/Machines/diagnoser_printing.ogg");
/// <summary>
/// How long you have to wait before printing logs again.
/// </summary>
[DataField]
public TimeSpan PrintCooldown = TimeSpan.FromSeconds(5);
/// <summary>
/// When anyone is allowed to spawn another printout.
/// </summary>
[DataField(customTypeSerializer: typeof(TimeOffsetSerializer)), AutoPausedField]
public TimeSpan NextPrintAllowed = TimeSpan.Zero;
}

View File

@@ -1,25 +1,40 @@
using Content.Shared.Access.Components;
using Content.Shared.Administration.Logs;
using Content.Shared.Audio;
using Content.Shared.CartridgeLoader;
using Content.Shared.CartridgeLoader.Cartridges;
using Content.Shared.Database;
using Content.Shared.Hands.EntitySystems;
using Content.Shared.Labels.EntitySystems;
using Content.Shared.Paper;
using Content.Shared.Popups;
using Robust.Shared.Audio.Systems;
using Robust.Shared.Random;
using Robust.Shared.Timing;
using System.Text;
namespace Content.Server.CartridgeLoader.Cartridges;
public sealed class LogProbeCartridgeSystem : EntitySystem
{
[Dependency] private readonly CartridgeLoaderSystem _cartridge = default!;
[Dependency] private readonly IGameTiming _timing = default!;
[Dependency] private readonly IRobustRandom _random = default!;
[Dependency] private readonly CartridgeLoaderSystem? _cartridgeLoaderSystem = default!;
[Dependency] private readonly SharedPopupSystem _popupSystem = default!;
[Dependency] private readonly SharedAudioSystem _audioSystem = default!;
[Dependency] private readonly ISharedAdminLogManager _adminLogger = default!;
[Dependency] private readonly SharedAudioSystem _audio = default!;
[Dependency] private readonly SharedHandsSystem _hands = default!;
[Dependency] private readonly SharedLabelSystem _label = default!;
[Dependency] private readonly SharedPopupSystem _popup = default!;
[Dependency] private readonly SharedTransformSystem _transform = default!;
[Dependency] private readonly PaperSystem _paper = default!;
public override void Initialize()
{
base.Initialize();
SubscribeLocalEvent<LogProbeCartridgeComponent, CartridgeUiReadyEvent>(OnUiReady);
SubscribeLocalEvent<LogProbeCartridgeComponent, CartridgeAfterInteractEvent>(AfterInteract);
SubscribeLocalEvent<LogProbeCartridgeComponent, CartridgeMessageEvent>(OnMessage);
}
/// <summary>
@@ -37,9 +52,10 @@ public sealed class LogProbeCartridgeSystem : EntitySystem
return;
//Play scanning sound with slightly randomized pitch
_audioSystem.PlayEntity(ent.Comp.SoundScan, args.InteractEvent.User, target, AudioHelpers.WithVariation(0.25f, _random));
_popupSystem.PopupCursor(Loc.GetString("log-probe-scan", ("device", target)), args.InteractEvent.User);
_audio.PlayEntity(ent.Comp.SoundScan, args.InteractEvent.User, target, AudioHelpers.WithVariation(0.25f, _random));
_popup.PopupCursor(Loc.GetString("log-probe-scan", ("device", target)), args.InteractEvent.User);
ent.Comp.EntityName = Name(target);
ent.Comp.PulledAccessLogs.Clear();
foreach (var accessRecord in accessReaderComponent.AccessLog)
@@ -52,6 +68,9 @@ public sealed class LogProbeCartridgeSystem : EntitySystem
ent.Comp.PulledAccessLogs.Add(log);
}
// Reverse the list so the oldest is at the bottom
ent.Comp.PulledAccessLogs.Reverse();
UpdateUiState(ent, args.Loader);
}
@@ -63,9 +82,49 @@ public sealed class LogProbeCartridgeSystem : EntitySystem
UpdateUiState(ent, args.Loader);
}
private void OnMessage(Entity<LogProbeCartridgeComponent> ent, ref CartridgeMessageEvent args)
{
if (args is LogProbePrintMessage cast)
PrintLogs(ent, cast.User);
}
private void PrintLogs(Entity<LogProbeCartridgeComponent> ent, EntityUid user)
{
if (string.IsNullOrEmpty(ent.Comp.EntityName))
return;
if (_timing.CurTime < ent.Comp.NextPrintAllowed)
return;
ent.Comp.NextPrintAllowed = _timing.CurTime + ent.Comp.PrintCooldown;
var paper = Spawn(ent.Comp.PaperPrototype, _transform.GetMapCoordinates(user));
_label.Label(paper, ent.Comp.EntityName); // label it for easy identification
_audio.PlayEntity(ent.Comp.PrintSound, user, paper);
_hands.PickupOrDrop(user, paper, checkActionBlocker: false);
// generate the actual printout text
var builder = new StringBuilder();
builder.AppendLine(Loc.GetString("log-probe-printout-device", ("name", ent.Comp.EntityName)));
builder.AppendLine(Loc.GetString("log-probe-printout-header"));
var number = 1;
foreach (var log in ent.Comp.PulledAccessLogs)
{
var time = TimeSpan.FromSeconds(Math.Truncate(log.Time.TotalSeconds)).ToString();
builder.AppendLine(Loc.GetString("log-probe-printout-entry", ("number", number), ("time", time), ("accessor", log.Accessor)));
number++;
}
var paperComp = Comp<PaperComponent>(paper);
_paper.SetContent((paper, paperComp), builder.ToString());
_adminLogger.Add(LogType.EntitySpawn, LogImpact.Low, $"{ToPrettyString(user):user} printed out LogProbe logs ({paper}) of {ent.Comp.EntityName}");
}
private void UpdateUiState(Entity<LogProbeCartridgeComponent> ent, EntityUid loaderUid)
{
var state = new LogProbeUiState(ent.Comp.PulledAccessLogs);
_cartridgeLoaderSystem?.UpdateCartridgeUiState(loaderUid, state);
var state = new LogProbeUiState(ent.Comp.EntityName, ent.Comp.PulledAccessLogs);
_cartridge.UpdateCartridgeUiState(loaderUid, state);
}
}

View File

@@ -18,6 +18,9 @@ namespace Content.Server.Chemistry.Components
[DataField("mode"), ViewVariables(VVAccess.ReadWrite)]
public ChemMasterMode Mode = ChemMasterMode.Transfer;
[DataField]
public ChemMasterSortingType SortingType = ChemMasterSortingType.None;
[DataField("pillDosageLimit", required: true), ViewVariables(VVAccess.ReadWrite)]
public uint PillDosageLimit;

View File

@@ -53,6 +53,7 @@ namespace Content.Server.Chemistry.EntitySystems
SubscribeLocalEvent<ChemMasterComponent, BoundUIOpenedEvent>(SubscribeUpdateUiState);
SubscribeLocalEvent<ChemMasterComponent, ChemMasterSetModeMessage>(OnSetModeMessage);
SubscribeLocalEvent<ChemMasterComponent, ChemMasterSortingTypeCycleMessage>(OnCycleSortingTypeMessage);
SubscribeLocalEvent<ChemMasterComponent, ChemMasterSetPillTypeMessage>(OnSetPillTypeMessage);
SubscribeLocalEvent<ChemMasterComponent, ChemMasterReagentAmountButtonMessage>(OnReagentButtonMessage);
SubscribeLocalEvent<ChemMasterComponent, ChemMasterCreatePillsMessage>(OnCreatePillsMessage);
@@ -76,7 +77,7 @@ namespace Content.Server.Chemistry.EntitySystems
var bufferCurrentVolume = bufferSolution.Volume;
var state = new ChemMasterBoundUserInterfaceState(
chemMaster.Mode, BuildInputContainerInfo(inputContainer), BuildOutputContainerInfo(outputContainer),
chemMaster.Mode, chemMaster.SortingType, BuildInputContainerInfo(inputContainer), BuildOutputContainerInfo(outputContainer),
bufferReagents, bufferCurrentVolume, chemMaster.PillType, chemMaster.PillDosageLimit, updateLabel);
_userInterfaceSystem.SetUiState(owner, ChemMasterUiKey.Key, state);
@@ -93,6 +94,15 @@ namespace Content.Server.Chemistry.EntitySystems
ClickSound(chemMaster);
}
private void OnCycleSortingTypeMessage(Entity<ChemMasterComponent> chemMaster, ref ChemMasterSortingTypeCycleMessage message)
{
chemMaster.Comp.SortingType++;
if (chemMaster.Comp.SortingType > ChemMasterSortingType.Latest)
chemMaster.Comp.SortingType = ChemMasterSortingType.None;
UpdateUiState(chemMaster);
ClickSound(chemMaster);
}
private void OnSetPillTypeMessage(Entity<ChemMasterComponent> chemMaster, ref ChemMasterSetPillTypeMessage message)
{
// Ensure valid pill type. There are 20 pills selectable, 0-19.

View File

@@ -18,25 +18,25 @@ namespace Content.Server.Connection.Whitelist;
/// If the condition doesn't match, the next condition is checked.
/// </summary>
[Prototype("playerConnectionWhitelist")]
public sealed class PlayerConnectionWhitelistPrototype : IPrototype
public sealed partial class PlayerConnectionWhitelistPrototype : IPrototype
{
[IdDataField]
public string ID { get; } = default!;
public string ID { get; private set; } = default!;
/// <summary>
/// Minimum number of players required for this whitelist to be active.
/// If there are less players than this, the whitelist will be ignored and the next one in the list will be used.
/// </summary>
[DataField]
public int MinimumPlayers { get; } = 0;
public int MinimumPlayers = 0;
/// <summary>
/// Maximum number of players allowed for this whitelist to be active.
/// If there are more players than this, the whitelist will be ignored and the next one in the list will be used.
/// </summary>
[DataField]
public int MaximumPlayers { get; } = int.MaxValue;
public int MaximumPlayers = int.MaxValue;
[DataField]
public WhitelistCondition[] Conditions { get; } = default!;
public WhitelistCondition[] Conditions = default!;
}

View File

@@ -30,6 +30,12 @@ public sealed class ThrowInsertContainerSystem : EntitySystem
if (!_containerSystem.CanInsert(args.Thrown, container))
return;
var beforeThrowArgs = new BeforeThrowInsertEvent(args.Thrown);
RaiseLocalEvent(ent, ref beforeThrowArgs);
if (beforeThrowArgs.Cancelled)
return;
if (_random.Prob(ent.Comp.Probability))
{
_audio.PlayPvs(ent.Comp.MissSound, ent);
@@ -46,3 +52,10 @@ public sealed class ThrowInsertContainerSystem : EntitySystem
_adminLogger.Add(LogType.Landed, LogImpact.Low, $"{ToPrettyString(args.Thrown)} thrown by {ToPrettyString(args.Component.Thrower.Value):player} landed in {ToPrettyString(ent)}");
}
}
/// <summary>
/// Sent before the insertion is made.
/// Allows preventing the insertion if any system on the entity should need to.
/// </summary>
[ByRefEvent]
public record struct BeforeThrowInsertEvent(EntityUid ThrownEntity, bool Cancelled = false);

View File

@@ -2,6 +2,7 @@ using System.Diagnostics.CodeAnalysis;
using System.Linq;
using Content.Server.Administration.Logs;
using Content.Server.Atmos.EntitySystems;
using Content.Server.Containers;
using Content.Server.Disposal.Tube;
using Content.Server.Disposal.Tube.Components;
using Content.Server.Disposal.Unit.Components;
@@ -85,6 +86,8 @@ public sealed class DisposalUnitSystem : SharedDisposalUnitSystem
SubscribeLocalEvent<DisposalUnitComponent, DisposalDoAfterEvent>(OnDoAfter);
SubscribeLocalEvent<DisposalUnitComponent, BeforeThrowInsertEvent>(OnThrowInsert);
SubscribeLocalEvent<DisposalUnitComponent, SharedDisposalUnitComponent.UiButtonPressedMessage>(OnUiButtonPressed);
}
@@ -195,6 +198,12 @@ public sealed class DisposalUnitSystem : SharedDisposalUnitSystem
args.Handled = true;
}
private void OnThrowInsert(Entity<DisposalUnitComponent> ent, ref BeforeThrowInsertEvent args)
{
if (!CanInsert(ent, ent, args.ThrownEntity))
args.Cancelled = true;
}
public override void DoInsertDisposalUnit(EntityUid uid, EntityUid toInsert, EntityUid user, SharedDisposalUnitComponent? disposal = null)
{
if (!ResolveDisposals(uid, ref disposal))

View File

@@ -1,12 +0,0 @@
namespace Content.Server.Forensics
{
/// <summary>
/// This component is for mobs that leave fingerprints.
/// </summary>
[RegisterComponent]
public sealed partial class FingerprintComponent : Component
{
[DataField("fingerprint"), ViewVariables(VVAccess.ReadWrite)]
public string? Fingerprint;
}
}

View File

@@ -1,10 +0,0 @@
namespace Content.Server.Forensics
{
/// <summary>
/// This component stops the entity from leaving finger prints,
/// usually so fibres can be left instead.
/// </summary>
[RegisterComponent]
public sealed partial class FingerprintMaskComponent : Component
{}
}

View File

@@ -3,6 +3,7 @@ using Content.Server.Popups;
using Content.Shared.DoAfter;
using Content.Shared.Examine;
using Content.Shared.Forensics;
using Content.Shared.Forensics.Components;
using Content.Shared.IdentityManagement;
using Content.Shared.Interaction;
using Content.Shared.Inventory;

View File

@@ -63,9 +63,10 @@ namespace Content.Server.Forensics
ApplyEvidence(uid, args.Other);
}
private void OnFingerprintInit(EntityUid uid, FingerprintComponent component, MapInitEvent args)
private void OnFingerprintInit(Entity<FingerprintComponent> ent, ref MapInitEvent args)
{
component.Fingerprint = GenerateFingerprint();
ent.Comp.Fingerprint = GenerateFingerprint();
Dirty(ent);
}
private void OnDNAInit(EntityUid uid, DnaComponent component, MapInitEvent args)

View File

@@ -1,4 +1,4 @@
using Content.Server.Antag;
using Content.Server.Antag;
using Content.Server.GameTicking.Rules.Components;
using Content.Server.Mind;
using Content.Server.Roles;

View File

@@ -6,7 +6,7 @@ namespace Content.Server.Ghost.Roles.Raffles;
/// Allows getting a <see cref="IGhostRoleRaffleDecider"/> as prototype.
/// </summary>
[Prototype("ghostRoleRaffleDecider")]
public sealed class GhostRoleRaffleDeciderPrototype : IPrototype
public sealed partial class GhostRoleRaffleDeciderPrototype : IPrototype
{
/// <inheritdoc />
[IdDataField]

View File

@@ -269,6 +269,7 @@ namespace Content.Server.Guardian
component.Host,
args.DamageDelta * component.DamageShare,
origin: args.Origin,
ignoreResistances: true,
interruptsDoAfters: false);
_popupSystem.PopupEntity(Loc.GetString("guardian-entity-taking-damage"), component.Host.Value, component.Host.Value);

View File

@@ -68,8 +68,6 @@ public sealed partial class ImplanterSystem : SharedImplanterSystem
args.Handled = true;
}
/// <summary>
/// Attempt to implant someone else.
/// </summary>

View File

@@ -1,5 +1,3 @@
using Content.Shared.Kitchen;
namespace Content.Server.Kitchen.Components;
/// <summary>
@@ -8,4 +6,9 @@ namespace Content.Server.Kitchen.Components;
[RegisterComponent]
public sealed partial class ActivelyMicrowavedComponent : Component
{
/// <summary>
/// The microwave this entity is actively being microwaved by.
/// </summary>
[DataField]
public EntityUid? Microwave;
}

View File

@@ -14,6 +14,7 @@ using Content.Shared.Body.Components;
using Content.Shared.Body.Part;
using Content.Shared.Chemistry.Components.SolutionManager;
using Content.Shared.Chemistry.EntitySystems;
using Content.Shared.Chemistry.Reaction;
using Content.Shared.Construction.EntitySystems;
using Content.Shared.Database;
using Content.Shared.Destructible;
@@ -101,6 +102,7 @@ namespace Content.Server.Kitchen.EntitySystems
SubscribeLocalEvent<ActiveMicrowaveComponent, EntRemovedFromContainerMessage>(OnActiveMicrowaveRemove);
SubscribeLocalEvent<ActivelyMicrowavedComponent, OnConstructionTemperatureEvent>(OnConstructionTemp);
SubscribeLocalEvent<ActivelyMicrowavedComponent, SolutionRelayEvent<ReactionAttemptEvent>>(OnReactionAttempt);
SubscribeLocalEvent<FoodRecipeProviderComponent, GetSecretRecipesEvent>(OnGetSecretRecipes);
}
@@ -126,7 +128,8 @@ namespace Content.Server.Kitchen.EntitySystems
private void OnActiveMicrowaveInsert(Entity<ActiveMicrowaveComponent> ent, ref EntInsertedIntoContainerMessage args)
{
AddComp<ActivelyMicrowavedComponent>(args.Entity);
var microwavedComp = AddComp<ActivelyMicrowavedComponent>(args.Entity);
microwavedComp.Microwave = ent.Owner;
}
private void OnActiveMicrowaveRemove(Entity<ActiveMicrowaveComponent> ent, ref EntRemovedFromContainerMessage args)
@@ -134,10 +137,33 @@ namespace Content.Server.Kitchen.EntitySystems
EntityManager.RemoveComponentDeferred<ActivelyMicrowavedComponent>(args.Entity);
}
// Stop items from transforming through constructiongraphs while being microwaved.
// They might be reserved for a microwave recipe.
private void OnConstructionTemp(Entity<ActivelyMicrowavedComponent> ent, ref OnConstructionTemperatureEvent args)
{
args.Result = HandleResult.False;
return;
}
// Stop reagents from reacting if they are currently reserved for a microwave recipe.
// For example Egg would cook into EggCooked, causing it to not being removed once we are done microwaving.
private void OnReactionAttempt(Entity<ActivelyMicrowavedComponent> ent, ref SolutionRelayEvent<ReactionAttemptEvent> args)
{
if (!TryComp<ActiveMicrowaveComponent>(ent.Comp.Microwave, out var activeMicrowaveComp))
return;
if (activeMicrowaveComp.PortionedRecipe.Item1 == null) // no recipe selected
return;
var recipeReagents = activeMicrowaveComp.PortionedRecipe.Item1.IngredientsReagents.Keys;
foreach (var reagent in recipeReagents)
{
if (args.Event.Reaction.Reactants.ContainsKey(reagent))
{
args.Event.Cancelled = true;
return;
}
}
}
/// <summary>
@@ -176,33 +202,29 @@ namespace Content.Server.Kitchen.EntitySystems
// this is spaghetti ngl
foreach (var item in component.Storage.ContainedEntities)
{
if (!TryComp<SolutionContainerManagerComponent>(item, out var solMan))
// use the same reagents as when we selected the recipe
if (!_solutionContainer.TryGetDrainableSolution(item, out var solutionEntity, out var solution))
continue;
// go over every solution
foreach (var (_, soln) in _solutionContainer.EnumerateSolutions((item, solMan)))
foreach (var (reagent, _) in recipe.IngredientsReagents)
{
var solution = soln.Comp.Solution;
foreach (var (reagent, _) in recipe.IngredientsReagents)
// removed everything
if (!totalReagentsToRemove.ContainsKey(reagent))
continue;
var quant = solution.GetTotalPrototypeQuantity(reagent);
if (quant >= totalReagentsToRemove[reagent])
{
// removed everything
if (!totalReagentsToRemove.ContainsKey(reagent))
continue;
var quant = solution.GetTotalPrototypeQuantity(reagent);
if (quant >= totalReagentsToRemove[reagent])
{
quant = totalReagentsToRemove[reagent];
totalReagentsToRemove.Remove(reagent);
}
else
{
totalReagentsToRemove[reagent] -= quant;
}
_solutionContainer.RemoveReagent(soln, reagent, quant);
quant = totalReagentsToRemove[reagent];
totalReagentsToRemove.Remove(reagent);
}
else
{
totalReagentsToRemove[reagent] -= quant;
}
_solutionContainer.RemoveReagent(solutionEntity.Value, reagent, quant);
}
}
@@ -541,7 +563,8 @@ namespace Content.Server.Kitchen.EntitySystems
continue;
}
AddComp<ActivelyMicrowavedComponent>(item);
var microwavedComp = AddComp<ActivelyMicrowavedComponent>(item);
microwavedComp.Microwave = uid;
string? solidID = null;
int amountToAdd = 1;
@@ -560,33 +583,20 @@ namespace Content.Server.Kitchen.EntitySystems
}
if (solidID is null)
{
continue;
}
if (solidsDict.ContainsKey(solidID))
{
if (!solidsDict.TryAdd(solidID, amountToAdd))
solidsDict[solidID] += amountToAdd;
}
else
{
solidsDict.Add(solidID, amountToAdd);
}
if (!TryComp<SolutionContainerManagerComponent>(item, out var solMan))
// only use reagents we have access to
// you have to break the eggs before we can use them!
if (!_solutionContainer.TryGetDrainableSolution(item, out var _, out var solution))
continue;
foreach (var (_, soln) in _solutionContainer.EnumerateSolutions((item, solMan)))
foreach (var (reagent, quantity) in solution.Contents)
{
var solution = soln.Comp.Solution;
foreach (var (reagent, quantity) in solution.Contents)
{
if (reagentDict.ContainsKey(reagent.Prototype))
reagentDict[reagent.Prototype] += quantity;
else
reagentDict.Add(reagent.Prototype, quantity);
}
if (!reagentDict.TryAdd(reagent.Prototype, quantity))
reagentDict[reagent.Prototype] += quantity;
}
}

View File

@@ -69,7 +69,7 @@ public sealed class MaterialStorageSystem : SharedMaterialStorageSystem
if (material.StackEntity != null)
{
if (!_prototypeManager.Index<EntityPrototype>(material.StackEntity).TryGetComponent<PhysicalCompositionComponent>(out var composition))
if (!_prototypeManager.Index<EntityPrototype>(material.StackEntity).TryGetComponent<PhysicalCompositionComponent>(out var composition, EntityManager.ComponentFactory))
return;
var volumePerSheet = composition.MaterialComposition.FirstOrDefault(kvp => kvp.Key == msg.Material).Value;
@@ -169,7 +169,7 @@ public sealed class MaterialStorageSystem : SharedMaterialStorageSystem
return new List<EntityUid>();
var entProto = _prototypeManager.Index<EntityPrototype>(materialProto.StackEntity);
if (!entProto.TryGetComponent<PhysicalCompositionComponent>(out var composition))
if (!entProto.TryGetComponent<PhysicalCompositionComponent>(out var composition, EntityManager.ComponentFactory))
return new List<EntityUid>();
var materialPerStack = composition.MaterialComposition[materialProto.ID];

View File

@@ -31,6 +31,12 @@ namespace Content.Server.Medical
[Dependency] private readonly ForensicsSystem _forensics = default!;
[Dependency] private readonly BloodstreamSystem _bloodstream = default!;
[ValidatePrototypeId<SoundCollectionPrototype>]
private const string VomitCollection = "Vomit";
private readonly SoundSpecifier _vomitSound = new SoundCollectionSpecifier(VomitCollection,
AudioParams.Default.WithVariation(0.2f).WithVolume(-4f));
/// <summary>
/// Make an entity vomit, if they have a stomach.
/// </summary>
@@ -94,7 +100,7 @@ namespace Content.Server.Medical
}
// Force sound to play as spill doesn't work if solution is empty.
_audio.PlayPvs("/Audio/Effects/Fluids/splat.ogg", uid, AudioParams.Default.WithVariation(0.2f).WithVolume(-4f));
_audio.PlayPvs(_vomitSound, uid);
_popup.PopupEntity(Loc.GetString("disease-vomit", ("person", Identity.Entity(uid, EntityManager))), uid);
}
}

View File

@@ -8,7 +8,7 @@ namespace Content.Server.NPC.HTN;
[Prototype("htnCompound")]
public sealed partial class HTNCompoundPrototype : IPrototype
{
[IdDataField] public string ID { get; } = string.Empty;
[IdDataField] public string ID { get; private set; } = string.Empty;
[DataField("branches", required: true)]
public List<HTNBranch> Branches = new();

View File

@@ -5,7 +5,7 @@ namespace Content.Server.NPC.Queries.Curves;
[Prototype("utilityCurvePreset")]
public sealed partial class UtilityCurvePresetPrototype : IPrototype
{
[IdDataField] public string ID { get; } = string.Empty;
[IdDataField] public string ID { get; private set; } = string.Empty;
[DataField("curve", required: true)] public IUtilityCurve Curve = default!;
}

View File

@@ -0,0 +1,7 @@
namespace Content.Server.Objectives.Components;
/// <summary>
/// A free greentext, that's it.
/// </summary>
[RegisterComponent]
public sealed partial class FreeObjectiveComponent : Component;

View File

@@ -0,0 +1,20 @@
using Content.Server.Objectives.Components;
using Content.Shared.Objectives.Components;
namespace Content.Server.Objectives.Systems;
public sealed class FreeObjectiveSystem : EntitySystem
{
public override void Initialize()
{
base.Initialize();
SubscribeLocalEvent<FreeObjectiveComponent, ObjectiveGetProgressEvent>(OnGetProgress);
}
// You automatically greentext, there's not much else to it
private void OnGetProgress(Entity<FreeObjectiveComponent> ent, ref ObjectiveGetProgressEvent args)
{
args.Progress = 1f;
}
}

View File

@@ -0,0 +1,7 @@
namespace Content.Server.Roles;
/// <summary>
/// Mind role to tag entities that they're a Wizard
/// </summary>
[RegisterComponent]
public sealed partial class WizardRoleComponent : Component;

View File

@@ -354,7 +354,7 @@ public sealed partial class SalvageSystem
if (!TryGetSalvagePlacementLocation(magnet, mapId, attachedBounds, bounds!.Value, worldAngle, out var spawnLocation, out var spawnAngle))
{
Report(magnet.Owner, MagnetChannel, "salvage-system-announcement-spawn-no-debris-available");
_mapManager.DeleteMap(salvMapXform.MapID);
_mapSystem.DeleteMap(salvMapXform.MapID);
return;
}
@@ -391,7 +391,7 @@ public sealed partial class SalvageSystem
}
Report(magnet.Owner, MagnetChannel, "salvage-system-announcement-arrived", ("timeLeft", data.Comp.ActiveTime.TotalSeconds));
_mapManager.DeleteMap(salvMapXform.MapID);
_mapSystem.DeleteMap(salvMapXform.MapID);
data.Comp.Announced = false;

View File

@@ -62,7 +62,7 @@ public interface IGridSpawnGroup
}
[DataRecord]
public sealed class DungeonSpawnGroup : IGridSpawnGroup
public sealed partial class DungeonSpawnGroup : IGridSpawnGroup
{
/// <summary>
/// Prototypes we can choose from to spawn.
@@ -97,7 +97,7 @@ public sealed class DungeonSpawnGroup : IGridSpawnGroup
}
[DataRecord]
public sealed class GridSpawnGroup : IGridSpawnGroup
public sealed partial class GridSpawnGroup : IGridSpawnGroup
{
public List<ResPath> Paths = new();

View File

@@ -30,8 +30,10 @@ using Robust.Server.GameObjects;
using Robust.Shared.Collections;
using Robust.Shared.Configuration;
using Robust.Shared.Console;
using Robust.Shared.EntitySerialization;
using Robust.Shared.EntitySerialization.Systems;
using Robust.Shared.Map;
using Robust.Shared.Map.Components;
using Robust.Shared.Player;
using Robust.Shared.Prototypes;
using Robust.Shared.Random;
@@ -46,23 +48,23 @@ namespace Content.Server.Shuttles.Systems;
/// </summary>
public sealed class ArrivalsSystem : EntitySystem
{
[Dependency] private readonly IChatManager _chat = default!;
[Dependency] private readonly IConfigurationManager _cfgManager = default!;
[Dependency] private readonly IConsoleHost _console = default!;
[Dependency] private readonly IGameTiming _timing = default!;
[Dependency] private readonly IPrototypeManager _protoManager = default!;
[Dependency] private readonly IRobustRandom _random = default!;
[Dependency] private readonly IChatManager _chat = default!;
[Dependency] private readonly SharedMapSystem _mapSystem = default!;
[Dependency] private readonly ActorSystem _actor = default!;
[Dependency] private readonly BiomeSystem _biomes = default!;
[Dependency] private readonly DeviceNetworkSystem _deviceNetworkSystem = default!;
[Dependency] private readonly GameTicker _ticker = default!;
[Dependency] private readonly MapLoaderSystem _loader = default!;
[Dependency] private readonly MetaDataSystem _metaData = default!;
[Dependency] private readonly DeviceNetworkSystem _deviceNetworkSystem = default!;
[Dependency] private readonly SharedMapSystem _mapSystem = default!;
[Dependency] private readonly SharedTransformSystem _transform = default!;
[Dependency] private readonly ShuttleSystem _shuttles = default!;
[Dependency] private readonly StationSpawningSystem _stationSpawning = default!;
[Dependency] private readonly StationSystem _station = default!;
[Dependency] private readonly ActorSystem _actor = default!;
private EntityQuery<PendingClockInComponent> _pendingQuery;
private EntityQuery<ArrivalsBlacklistComponent> _blacklistQuery;
@@ -515,31 +517,31 @@ public sealed class ArrivalsSystem : EntitySystem
private void SetupArrivalsStation()
{
var path = new ResPath(_cfgManager.GetCVar(CCVars.ArrivalsMap));
if (!_loader.TryLoadMap(path, out var map, out var grids))
_mapSystem.CreateMap(out var mapId, runMapInit: false);
var mapUid = _mapSystem.GetMap(mapId);
if (!_loader.TryLoadGrid(mapId, path, out var grid))
return;
_metaData.SetEntityName(map.Value, Loc.GetString("map-name-terminal"));
_metaData.SetEntityName(mapUid, Loc.GetString("map-name-terminal"));
foreach (var id in grids)
{
EnsureComp<ArrivalsSourceComponent>(id);
EnsureComp<ProtectedGridComponent>(id);
EnsureComp<PreventPilotComponent>(id);
}
EnsureComp<ArrivalsSourceComponent>(grid.Value);
EnsureComp<ProtectedGridComponent>(grid.Value);
EnsureComp<PreventPilotComponent>(grid.Value);
// Setup planet arrivals if relevant
if (_cfgManager.GetCVar(CCVars.ArrivalsPlanet))
{
var template = _random.Pick(_arrivalsBiomeOptions);
_biomes.EnsurePlanet(map.Value, _protoManager.Index(template));
_biomes.EnsurePlanet(mapUid, _protoManager.Index(template));
var restricted = new RestrictedRangeComponent
{
Range = 32f
};
AddComp(map.Value, restricted);
AddComp(mapUid, restricted);
}
_mapSystem.InitializeMap(map.Value.Comp.MapId);
_mapSystem.InitializeMap(mapId);
// Handle roundstart stations.
var query = AllEntityQuery<StationArrivalsComponent>();

View File

@@ -200,11 +200,11 @@ public sealed class IonStormSystem : EntitySystem
// i dont think theres a way to do this in fluent
var (who, plural) = _robustRandom.Next(0, 5) switch
{
0 => (Loc.GetString("ion-storm-you"), false),
1 => (Loc.GetString("ion-storm-the-station"), true),
2 => (Loc.GetString("ion-storm-the-crew"), true),
3 => (Loc.GetString("ion-storm-the-job", ("job", crew2)), false),
_ => (area, true) // THE SINGULARITY REQUIRES THE HAPPY CLOWNS
0 => (Loc.GetString("ion-storm-you"), true),
1 => (Loc.GetString("ion-storm-the-station"), false),
2 => (Loc.GetString("ion-storm-the-crew"), false),
3 => (Loc.GetString("ion-storm-the-job", ("job", crew2)), true),
_ => (area, false) // THE SINGULARITY REQUIRES THE HAPPY CLOWNS
};
var jobChange = _robustRandom.Next(0, 3) switch
{

View File

@@ -1,11 +1,24 @@
using System.Threading;
using Content.Server.StationEvents.Events;
using Robust.Shared.Audio;
using Robust.Shared.Prototypes;
namespace Content.Server.StationEvents.Components;
[RegisterComponent, Access(typeof(PowerGridCheckRule))]
public sealed partial class PowerGridCheckRuleComponent : Component
{
/// <summary>
/// Default sound of the announcement when power is back on.
/// </summary>
private static readonly ProtoId<SoundCollectionPrototype> DefaultPowerOn = new("PowerOn");
/// <summary>
/// Sound of the announcement to play when power is back on.
/// </summary>
[DataField]
public SoundSpecifier PowerOnSound = new SoundCollectionSpecifier(DefaultPowerOn, AudioParams.Default.WithVolume(-4f));
public CancellationTokenSource? AnnounceCancelToken;
public EntityUid AffectedStation;

View File

@@ -210,7 +210,7 @@ public sealed class EventManagerSystem : EntitySystem
if (prototype.Abstract)
continue;
if (!prototype.TryGetComponent<StationEventComponent>(out var stationEvent))
if (!prototype.TryGetComponent<StationEventComponent>(out var stationEvent, EntityManager.ComponentFactory))
continue;
allEvents.Add(prototype, stationEvent);

View File

@@ -26,7 +26,8 @@ public sealed class ImmovableRodRule : StationEventSystem<ImmovableRodRuleCompon
var proto = _prototypeManager.Index<EntityPrototype>(protoName);
if (proto.TryGetComponent<ImmovableRodComponent>(out var rod) && proto.TryGetComponent<TimedDespawnComponent>(out var despawn))
if (proto.TryGetComponent<ImmovableRodComponent>(out var rod, EntityManager.ComponentFactory) &&
proto.TryGetComponent<TimedDespawnComponent>(out var despawn, EntityManager.ComponentFactory))
{
if (!TryFindRandomTile(out _, out _, out _, out var targetCoords))
return;

View File

@@ -59,7 +59,7 @@ namespace Content.Server.StationEvents.Events
component.AnnounceCancelToken = new CancellationTokenSource();
Timer.Spawn(3000, () =>
{
Audio.PlayGlobal("/Audio/Announcements/power_on.ogg", Filter.Broadcast(), true, AudioParams.Default.WithVolume(-4f));
Audio.PlayGlobal(component.PowerOnSound, Filter.Broadcast(), true);
}, component.AnnounceCancelToken.Token);
component.Unpowered.Clear();
}

View File

@@ -11,6 +11,7 @@ using Content.Shared.Roles;
using Content.Shared.StationRecords;
using Robust.Shared.Enums;
using Robust.Shared.Prototypes;
using Robust.Shared.Random;
namespace Content.Server.StationRecords.Systems;
@@ -39,6 +40,7 @@ public sealed class StationRecordsSystem : SharedStationRecordsSystem
[Dependency] private readonly StationRecordKeyStorageSystem _keyStorage = default!;
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
[Dependency] private readonly IdCardSystem _idCard = default!;
[Dependency] private readonly IRobustRandom _random = default!;
public override void Initialize()
{
@@ -232,6 +234,28 @@ public sealed class StationRecordsSystem : SharedStationRecordsSystem
return records.Records.TryGetRecordEntry(key.Id, out entry);
}
/// <summary>
/// Gets a random record from the station's record entries.
/// </summary>
/// <param name="ent">The EntityId of the station from which you want to get the record.</param>
/// <param name="entry">The resulting entry.</param>
/// <typeparam name="T">Type to get from the record set.</typeparam>
/// <returns>True if a record was obtained. False otherwise.</returns>
public bool TryGetRandomRecord<T>(Entity<StationRecordsComponent?> ent, [NotNullWhen(true)] out T? entry)
{
entry = default;
if (!Resolve(ent.Owner, ref ent.Comp))
return false;
if (ent.Comp.Records.Keys.Count == 0)
return false;
var key = _random.Pick(ent.Comp.Records.Keys);
return ent.Comp.Records.TryGetRecordEntry(key, out entry);
}
/// <summary>
/// Returns an id if a record with the same name exists.
/// </summary>

View File

@@ -1,4 +1,5 @@
using System.Diagnostics.CodeAnalysis;
using Content.Shared.Mind;
using Content.Shared.Store;
using Content.Shared.Store.Components;
using Robust.Shared.Prototypes;
@@ -117,7 +118,7 @@ public sealed partial class StoreSystem
if (listing.Conditions != null)
{
var args = new ListingConditionArgs(buyer, storeEntity, listing, EntityManager);
var args = new ListingConditionArgs(GetBuyerMind(buyer), storeEntity, listing, EntityManager);
var conditionsMet = true;
foreach (var condition in listing.Conditions)
@@ -137,6 +138,19 @@ public sealed partial class StoreSystem
}
}
/// <summary>
/// Returns the entity's mind entity, if it has one, to be used for listing conditions.
/// If it doesn't have one, or is a mind entity already, it returns itself.
/// </summary>
/// <param name="buyer">The buying entity.</param>
public EntityUid GetBuyerMind(EntityUid buyer)
{
if (!HasComp<MindComponent>(buyer) && _mind.TryGetMind(buyer, out var buyerMind, out var _))
return buyerMind;
return buyer;
}
/// <summary>
/// Checks if a listing appears in a list of given categories
/// </summary>

View File

@@ -146,7 +146,7 @@ public sealed partial class StoreSystem
//condition checking because why not
if (listing.Conditions != null)
{
var args = new ListingConditionArgs(component.AccountOwner ?? buyer, uid, listing, EntityManager);
var args = new ListingConditionArgs(component.AccountOwner ?? GetBuyerMind(buyer), uid, listing, EntityManager);
var conditionsMet = listing.Conditions.All(condition => condition.Condition(args));
if (!conditionsMet)

View File

@@ -20,7 +20,7 @@ public sealed partial class WireLayoutPrototype : IPrototype, IInheritingPrototy
public string[]? Parents { get; private set; }
[AbstractDataField]
public bool Abstract { get; }
public bool Abstract { get; private set; }
/// <summary>
/// How many wires in this layout will do

View File

@@ -14,12 +14,12 @@ public sealed partial class BiomePrototype : IPrototype, IInheritingPrototype
{
/// <inheritdoc />
[ParentDataField(typeof(AbstractPrototypeIdArraySerializer<EntityPrototype>))]
public string[]? Parents { get; }
public string[]? Parents { get; private set; }
/// <inheritdoc />
[NeverPushInheritance]
[AbstractDataField]
public bool Abstract { get; }
public bool Abstract { get; private set; }
/// <inheritdoc />
[IdDataField]
@@ -42,7 +42,7 @@ public sealed partial class BiomePrototype : IPrototype, IInheritingPrototype
/// </summary>
[DataField("chunkComponents")]
[AlwaysPushInheritance]
public ComponentRegistry ChunkComponents { get; } = new();
public ComponentRegistry ChunkComponents = new();
//TODO: Get someone to make this a method on componentregistry that does it Correctly.
/// <summary>

View File

@@ -84,12 +84,12 @@ public sealed partial class NoiseChannelPrototype : NoiseChannelConfig, IPrototy
{
/// <inheritdoc />
[ParentDataField(typeof(AbstractPrototypeIdArraySerializer<EntityPrototype>))]
public string[]? Parents { get; }
public string[]? Parents { get; private set; }
/// <inheritdoc />
[NeverPushInheritance]
[AbstractDataField]
public bool Abstract { get; }
public bool Abstract { get; private set; }
/// <inheritdoc />
[IdDataField]

View File

@@ -109,10 +109,16 @@ namespace Content.Shared.ActionBlocker
/// </remarks>
public bool CanUseHeldEntity(EntityUid user, EntityUid used)
{
var ev = new UseAttemptEvent(user, used);
RaiseLocalEvent(user, ev);
var useEv = new UseAttemptEvent(user, used);
RaiseLocalEvent(user, useEv);
return !ev.Cancelled;
if (useEv.Cancelled)
return false;
var usedEv = new GettingUsedAttemptEvent(user);
RaiseLocalEvent(used, usedEv);
return !usedEv.Cancelled;
}

View File

@@ -10,5 +10,5 @@ public sealed partial class AlertCategoryPrototype : IPrototype
{
/// <inheritdoc/>
[IdDataField]
public string ID { get; } = default!;
public string ID { get; private set; } = default!;
}

View File

@@ -12,7 +12,7 @@ namespace Content.Shared.Audio;
[Prototype("ambientMusic")]
public sealed partial class AmbientMusicPrototype : IPrototype
{
[IdDataField] public string ID { get; } = string.Empty;
[IdDataField] public string ID { get; private set; } = string.Empty;
/// <summary>
/// Traditionally you'd prioritise most rules to least as priority but in our case we'll just be explicit.

View File

@@ -10,7 +10,7 @@ namespace Content.Shared.Audio.Jukebox;
public sealed partial class JukeboxPrototype : IPrototype
{
[IdDataField]
public string ID { get; } = string.Empty;
public string ID { get; private set; } = string.Empty;
/// <summary>
/// User friendly name to use in UI.

View File

@@ -5,7 +5,7 @@ namespace Content.Shared.Body.Prototypes;
[Prototype("body")]
public sealed partial class BodyPrototype : IPrototype
{
[IdDataField] public string ID { get; } = default!;
[IdDataField] public string ID { get; private set; } = default!;
[DataField("name")]
public string Name { get; private set; } = "";
@@ -26,4 +26,4 @@ public sealed partial class BodyPrototype : IPrototype
}
[DataRecord]
public sealed record BodyPrototypeSlot(EntProtoId? Part, HashSet<string> Connections, Dictionary<string, string> Organs);
public sealed partial record BodyPrototypeSlot(EntProtoId? Part, HashSet<string> Connections, Dictionary<string, string> Organs);

View File

@@ -38,4 +38,27 @@ public sealed partial class CCVars
/// </summary>
public static readonly CVarDef<bool> AccessibilityColorblindFriendly =
CVarDef.Create("accessibility.colorblind_friendly", false, CVar.CLIENTONLY | CVar.ARCHIVE);
/// <summary>
/// Speech bubble text opacity slider, controlling the alpha of speech bubble's text.
/// Goes from to 0 (completely transparent) to 1 (completely opaque)
/// </summary>
public static readonly CVarDef<float> SpeechBubbleTextOpacity =
CVarDef.Create("accessibility.speech_bubble_text_opacity", 1f, CVar.CLIENTONLY | CVar.ARCHIVE);
/// <summary>
/// Speech bubble speaker opacity slider, controlling the alpha of the speaker's name in a speech bubble.
/// Goes from to 0 (completely transparent) to 1 (completely opaque)
/// </summary>
public static readonly CVarDef<float> SpeechBubbleSpeakerOpacity =
CVarDef.Create("accessibility.speech_bubble_speaker_opacity", 1f, CVar.CLIENTONLY | CVar.ARCHIVE);
/// <summary>
/// Speech bubble background opacity slider, controlling the alpha of the speech bubble's background.
/// Goes from to 0 (completely transparent) to 1 (completely opaque)
/// </summary>
public static readonly CVarDef<float> SpeechBubbleBackgroundOpacity =
CVarDef.Create("accessibility.speech_bubble_background_opacity", 0.75f, CVar.CLIENTONLY | CVar.ARCHIVE);
}

View File

@@ -5,391 +5,390 @@ namespace Content.Shared.CCVar;
public sealed partial class CCVars
{
/// <summary>
/// Disables most functionality in the GameTicker.
/// </summary>
public static readonly CVarDef<bool>
GameDummyTicker = CVarDef.Create("game.dummyticker", false, CVar.ARCHIVE | CVar.SERVERONLY);
/// <summary>
/// Disables most functionality in the GameTicker.
/// </summary>
public static readonly CVarDef<bool>
GameDummyTicker = CVarDef.Create("game.dummyticker", false, CVar.ARCHIVE | CVar.SERVERONLY);
/// <summary>
/// Controls if the lobby is enabled. If it is not, and there are no available jobs, you may get stuck on a black screen.
/// </summary>
public static readonly CVarDef<bool>
GameLobbyEnabled = CVarDef.Create("game.lobbyenabled", true, CVar.ARCHIVE);
/// <summary>
/// Controls if the lobby is enabled. If it is not, and there are no available jobs, you may get stuck on a black screen.
/// </summary>
public static readonly CVarDef<bool>
GameLobbyEnabled = CVarDef.Create("game.lobbyenabled", true, CVar.ARCHIVE);
/// <summary>
/// Controls the duration of the lobby timer in seconds. Defaults to 2 minutes and 30 seconds.
/// </summary>
public static readonly CVarDef<int>
GameLobbyDuration = CVarDef.Create("game.lobbyduration", 150, CVar.ARCHIVE);
/// <summary>
/// Controls the duration of the lobby timer in seconds. Defaults to 2 minutes and 30 seconds.
/// </summary>
public static readonly CVarDef<int>
GameLobbyDuration = CVarDef.Create("game.lobbyduration", 150, CVar.ARCHIVE);
/// <summary>
/// Controls if players can latejoin at all.
/// </summary>
public static readonly CVarDef<bool>
GameDisallowLateJoins = CVarDef.Create("game.disallowlatejoins", false, CVar.ARCHIVE | CVar.SERVERONLY);
/// <summary>
/// Controls if players can latejoin at all.
/// </summary>
public static readonly CVarDef<bool>
GameDisallowLateJoins = CVarDef.Create("game.disallowlatejoins", false, CVar.ARCHIVE | CVar.SERVERONLY);
/// <summary>
/// Controls the default game preset.
/// </summary>
public static readonly CVarDef<string>
GameLobbyDefaultPreset = CVarDef.Create("game.defaultpreset", "secret", CVar.ARCHIVE);
/// <summary>
/// Controls the default game preset.
/// </summary>
public static readonly CVarDef<string>
GameLobbyDefaultPreset = CVarDef.Create("game.defaultpreset", "secret", CVar.ARCHIVE);
/// <summary>
/// Controls if the game can force a different preset if the current preset's criteria are not met.
/// </summary>
public static readonly CVarDef<bool>
GameLobbyFallbackEnabled = CVarDef.Create("game.fallbackenabled", true, CVar.ARCHIVE);
/// <summary>
/// Controls if the game can force a different preset if the current preset's criteria are not met.
/// </summary>
public static readonly CVarDef<bool>
GameLobbyFallbackEnabled = CVarDef.Create("game.fallbackenabled", true, CVar.ARCHIVE);
/// <summary>
/// The preset for the game to fall back to if the selected preset could not be used, and fallback is enabled.
/// </summary>
public static readonly CVarDef<string>
GameLobbyFallbackPreset = CVarDef.Create("game.fallbackpreset", "Traitor,Extended", CVar.ARCHIVE);
/// <summary>
/// The preset for the game to fall back to if the selected preset could not be used, and fallback is enabled.
/// </summary>
public static readonly CVarDef<string>
GameLobbyFallbackPreset = CVarDef.Create("game.fallbackpreset", "Traitor,Extended", CVar.ARCHIVE);
/// <summary>
/// Controls if people can win the game in Suspicion or Deathmatch.
/// </summary>
public static readonly CVarDef<bool>
GameLobbyEnableWin = CVarDef.Create("game.enablewin", true, CVar.ARCHIVE);
/// <summary>
/// Controls if people can win the game in Suspicion or Deathmatch.
/// </summary>
public static readonly CVarDef<bool>
GameLobbyEnableWin = CVarDef.Create("game.enablewin", true, CVar.ARCHIVE);
/// <summary>
/// Controls the maximum number of character slots a player is allowed to have.
/// </summary>
public static readonly CVarDef<int>
GameMaxCharacterSlots = CVarDef.Create("game.maxcharacterslots", 30, CVar.ARCHIVE | CVar.SERVERONLY);
/// <summary>
/// Controls the maximum number of character slots a player is allowed to have.
/// </summary>
public static readonly CVarDef<int>
GameMaxCharacterSlots = CVarDef.Create("game.maxcharacterslots", 30, CVar.ARCHIVE | CVar.SERVERONLY);
/// <summary>
/// Controls the game map prototype to load. SS14 stores these prototypes in Prototypes/Maps.
/// </summary>
public static readonly CVarDef<string>
GameMap = CVarDef.Create("game.map", string.Empty, CVar.SERVERONLY);
/// <summary>
/// Controls the game map prototype to load. SS14 stores these prototypes in Prototypes/Maps.
/// </summary>
public static readonly CVarDef<string>
GameMap = CVarDef.Create("game.map", string.Empty, CVar.SERVERONLY);
/// <summary>
/// Controls whether to use world persistence or not.
/// </summary>
public static readonly CVarDef<bool>
UsePersistence = CVarDef.Create("game.usepersistence", false, CVar.ARCHIVE);
/// <summary>
/// Controls whether to use world persistence or not.
/// </summary>
public static readonly CVarDef<bool>
UsePersistence = CVarDef.Create("game.usepersistence", false, CVar.ARCHIVE);
/// <summary>
/// If world persistence is used, what map prototype should be initially loaded.
/// If the save file exists, it replaces MapPath but everything else stays the same (station name and such).
/// </summary>
public static readonly CVarDef<string>
PersistenceMap = CVarDef.Create("game.persistencemap", "Empty", CVar.ARCHIVE);
/// <summary>
/// If world persistence is used, what map prototype should be initially loaded.
/// If the save file exists, it replaces MapPath but everything else stays the same (station name and such).
/// </summary>
public static readonly CVarDef<string>
PersistenceMap = CVarDef.Create("game.persistencemap", "Empty", CVar.ARCHIVE);
/// <summary>
/// Prototype to use for map pool.
/// </summary>
public static readonly CVarDef<string>
GameMapPool = CVarDef.Create("game.map_pool", "DefaultMapPool", CVar.SERVERONLY);
/// <summary>
/// Prototype to use for map pool.
/// </summary>
public static readonly CVarDef<string>
GameMapPool = CVarDef.Create("game.map_pool", "DefaultMapPool", CVar.SERVERONLY);
/// <summary>
/// The depth of the queue used to calculate which map is next in rotation.
/// This is how long the game "remembers" that some map was put in play. Default is 16 rounds.
/// </summary>
public static readonly CVarDef<int>
GameMapMemoryDepth = CVarDef.Create("game.map_memory_depth", 16, CVar.SERVERONLY);
/// <summary>
/// The depth of the queue used to calculate which map is next in rotation.
/// This is how long the game "remembers" that some map was put in play. Default is 16 rounds.
/// </summary>
public static readonly CVarDef<int>
GameMapMemoryDepth = CVarDef.Create("game.map_memory_depth", 16, CVar.SERVERONLY);
/// <summary>
/// Is map rotation enabled?
/// </summary>
public static readonly CVarDef<bool>
GameMapRotation = CVarDef.Create("game.map_rotation", true, CVar.SERVERONLY);
/// <summary>
/// Is map rotation enabled?
/// </summary>
public static readonly CVarDef<bool>
GameMapRotation = CVarDef.Create("game.map_rotation", true, CVar.SERVERONLY);
/// <summary>
/// If roles should be restricted based on time.
/// </summary>
public static readonly CVarDef<bool>
GameRoleTimers = CVarDef.Create("game.role_timers", true, CVar.SERVER | CVar.REPLICATED);
/// <summary>
/// If roles should be restricted based on time.
/// </summary>
public static readonly CVarDef<bool>
GameRoleTimers = CVarDef.Create("game.role_timers", true, CVar.SERVER | CVar.REPLICATED);
/// <summary>
/// Override default role requirements using a <see cref="JobRequirementOverridePrototype"/>
/// </summary>
public static readonly CVarDef<string>
GameRoleTimerOverride = CVarDef.Create("game.role_timer_override", "", CVar.SERVER | CVar.REPLICATED);
/// <summary>
/// Override default role requirements using a <see cref="JobRequirementOverridePrototype"/>
/// </summary>
public static readonly CVarDef<string>
GameRoleTimerOverride = CVarDef.Create("game.role_timer_override", "", CVar.SERVER | CVar.REPLICATED);
/// <summary>
/// If roles should be restricted based on whether or not they are whitelisted.
/// </summary>
public static readonly CVarDef<bool>
GameRoleWhitelist = CVarDef.Create("game.role_whitelist", true, CVar.SERVER | CVar.REPLICATED);
/// <summary>
/// If roles should be restricted based on whether or not they are whitelisted.
/// </summary>
public static readonly CVarDef<bool>
GameRoleWhitelist = CVarDef.Create("game.role_whitelist", true, CVar.SERVER | CVar.REPLICATED);
/// <summary>
/// Whether or not disconnecting inside of a cryopod should remove the character or just store them until they reconnect.
/// </summary>
public static readonly CVarDef<bool>
GameCryoSleepRejoining = CVarDef.Create("game.cryo_sleep_rejoining", false, CVar.SERVER | CVar.REPLICATED);
/// <summary>
/// Whether or not disconnecting inside of a cryopod should remove the character or just store them until they reconnect.
/// </summary>
public static readonly CVarDef<bool>
GameCryoSleepRejoining = CVarDef.Create("game.cryo_sleep_rejoining", false, CVar.SERVER | CVar.REPLICATED);
/// <summary>
/// When enabled, guests will be assigned permanent UIDs and will have their preferences stored.
/// </summary>
public static readonly CVarDef<bool> GamePersistGuests =
CVarDef.Create("game.persistguests", true, CVar.ARCHIVE | CVar.SERVERONLY);
/// <summary>
/// When enabled, guests will be assigned permanent UIDs and will have their preferences stored.
/// </summary>
public static readonly CVarDef<bool> GamePersistGuests =
CVarDef.Create("game.persistguests", true, CVar.ARCHIVE | CVar.SERVERONLY);
public static readonly CVarDef<bool> GameDiagonalMovement =
CVarDef.Create("game.diagonalmovement", true, CVar.ARCHIVE);
public static readonly CVarDef<bool> GameDiagonalMovement =
CVarDef.Create("game.diagonalmovement", true, CVar.ARCHIVE);
public static readonly CVarDef<int> SoftMaxPlayers =
CVarDef.Create("game.soft_max_players", 30, CVar.SERVERONLY | CVar.ARCHIVE);
public static readonly CVarDef<int> SoftMaxPlayers =
CVarDef.Create("game.soft_max_players", 30, CVar.SERVERONLY | CVar.ARCHIVE);
/// <summary>
/// If a player gets denied connection to the server,
/// how long they are forced to wait before attempting to reconnect.
/// </summary>
public static readonly CVarDef<int> GameServerFullReconnectDelay =
CVarDef.Create("game.server_full_reconnect_delay", 30, CVar.SERVERONLY);
/// <summary>
/// If a player gets denied connection to the server,
/// how long they are forced to wait before attempting to reconnect.
/// </summary>
public static readonly CVarDef<int> GameServerFullReconnectDelay =
CVarDef.Create("game.server_full_reconnect_delay", 30, CVar.SERVERONLY);
/// <summary>
/// Whether or not panic bunker is currently enabled.
/// </summary>
public static readonly CVarDef<bool> PanicBunkerEnabled =
CVarDef.Create("game.panic_bunker.enabled", false, CVar.NOTIFY | CVar.REPLICATED | CVar.SERVER);
/// <summary>
/// Whether or not panic bunker is currently enabled.
/// </summary>
public static readonly CVarDef<bool> PanicBunkerEnabled =
CVarDef.Create("game.panic_bunker.enabled", false, CVar.NOTIFY | CVar.REPLICATED | CVar.SERVER);
/// <summary>
/// Whether or not the panic bunker will disable when an admin comes online.
/// </summary>
public static readonly CVarDef<bool> PanicBunkerDisableWithAdmins =
CVarDef.Create("game.panic_bunker.disable_with_admins", false, CVar.SERVERONLY);
/// <summary>
/// Whether or not the panic bunker will disable when an admin comes online.
/// </summary>
public static readonly CVarDef<bool> PanicBunkerDisableWithAdmins =
CVarDef.Create("game.panic_bunker.disable_with_admins", false, CVar.SERVERONLY);
/// <summary>
/// Whether or not the panic bunker will enable when no admins are online.
/// This counts everyone with the 'Admin' AdminFlag.
/// </summary>
public static readonly CVarDef<bool> PanicBunkerEnableWithoutAdmins =
CVarDef.Create("game.panic_bunker.enable_without_admins", false, CVar.SERVERONLY);
/// <summary>
/// Whether or not the panic bunker will enable when no admins are online.
/// This counts everyone with the 'Admin' AdminFlag.
/// </summary>
public static readonly CVarDef<bool> PanicBunkerEnableWithoutAdmins =
CVarDef.Create("game.panic_bunker.enable_without_admins", false, CVar.SERVERONLY);
/// <summary>
/// Whether or not the panic bunker will count deadminned admins for
/// <see cref="PanicBunkerDisableWithAdmins"/> and
/// <see cref="PanicBunkerEnableWithoutAdmins"/>
/// </summary>
public static readonly CVarDef<bool> PanicBunkerCountDeadminnedAdmins =
CVarDef.Create("game.panic_bunker.count_deadminned_admins", false, CVar.SERVERONLY);
/// <summary>
/// Whether or not the panic bunker will count deadminned admins for
/// <see cref="PanicBunkerDisableWithAdmins"/> and
/// <see cref="PanicBunkerEnableWithoutAdmins"/>
/// </summary>
public static readonly CVarDef<bool> PanicBunkerCountDeadminnedAdmins =
CVarDef.Create("game.panic_bunker.count_deadminned_admins", false, CVar.SERVERONLY);
/// <summary>
/// Show reason of disconnect for user or not.
/// </summary>
public static readonly CVarDef<bool> PanicBunkerShowReason =
CVarDef.Create("game.panic_bunker.show_reason", false, CVar.SERVERONLY);
/// <summary>
/// Show reason of disconnect for user or not.
/// </summary>
public static readonly CVarDef<bool> PanicBunkerShowReason =
CVarDef.Create("game.panic_bunker.show_reason", false, CVar.SERVERONLY);
/// <summary>
/// Minimum age of the account (from server's PoV, so from first-seen date) in minutes.
/// </summary>
public static readonly CVarDef<int> PanicBunkerMinAccountAge =
CVarDef.Create("game.panic_bunker.min_account_age", 1440, CVar.SERVERONLY);
/// <summary>
/// Minimum age of the account (from server's PoV, so from first-seen date) in minutes.
/// </summary>
public static readonly CVarDef<int> PanicBunkerMinAccountAge =
CVarDef.Create("game.panic_bunker.min_account_age", 1440, CVar.SERVERONLY);
/// <summary>
/// Minimal overall played time.
/// </summary>
public static readonly CVarDef<int> PanicBunkerMinOverallMinutes =
CVarDef.Create("game.panic_bunker.min_overall_minutes", 600, CVar.SERVERONLY);
/// <summary>
/// Minimal overall played time.
/// </summary>
public static readonly CVarDef<int> PanicBunkerMinOverallMinutes =
CVarDef.Create("game.panic_bunker.min_overall_minutes", 600, CVar.SERVERONLY);
/// <summary>
/// A custom message that will be used for connections denied to the panic bunker
/// If not empty, then will overwrite <see cref="PanicBunkerShowReason"/>
/// </summary>
public static readonly CVarDef<string> PanicBunkerCustomReason =
CVarDef.Create("game.panic_bunker.custom_reason", string.Empty, CVar.SERVERONLY);
/// <summary>
/// A custom message that will be used for connections denied to the panic bunker
/// If not empty, then will overwrite <see cref="PanicBunkerShowReason"/>
/// </summary>
public static readonly CVarDef<string> PanicBunkerCustomReason =
CVarDef.Create("game.panic_bunker.custom_reason", string.Empty, CVar.SERVERONLY);
/// <summary>
/// Allow bypassing the panic bunker if the user is whitelisted.
/// </summary>
public static readonly CVarDef<bool> BypassBunkerWhitelist =
CVarDef.Create("game.panic_bunker.whitelisted_can_bypass", true, CVar.SERVERONLY);
/// <summary>
/// Allow bypassing the panic bunker if the user is whitelisted.
/// </summary>
public static readonly CVarDef<bool> BypassBunkerWhitelist =
CVarDef.Create("game.panic_bunker.whitelisted_can_bypass", true, CVar.SERVERONLY);
/// <summary>
/// Enable IPIntel for blocking VPN connections from new players.
/// </summary>
public static readonly CVarDef<bool> GameIPIntelEnabled =
CVarDef.Create("game.ipintel_enabled", false, CVar.SERVERONLY);
/// <summary>
/// Enable IPIntel for blocking VPN connections from new players.
/// </summary>
public static readonly CVarDef<bool> GameIPIntelEnabled =
CVarDef.Create("game.ipintel_enabled", false, CVar.SERVERONLY);
/// <summary>
/// Whether clients which are flagged as a VPN will be denied
/// </summary>
public static readonly CVarDef<bool> GameIPIntelRejectBad =
CVarDef.Create("game.ipintel_reject_bad", true, CVar.SERVERONLY);
/// <summary>
/// Whether clients which are flagged as a VPN will be denied
/// </summary>
public static readonly CVarDef<bool> GameIPIntelRejectBad =
CVarDef.Create("game.ipintel_reject_bad", true, CVar.SERVERONLY);
/// <summary>
/// Whether clients which cannot be checked due to a rate limit will be denied
/// </summary>
public static readonly CVarDef<bool> GameIPIntelRejectRateLimited =
CVarDef.Create("game.ipintel_reject_ratelimited", false, CVar.SERVERONLY);
/// <summary>
/// Whether clients which cannot be checked due to a rate limit will be denied
/// </summary>
public static readonly CVarDef<bool> GameIPIntelRejectRateLimited =
CVarDef.Create("game.ipintel_reject_ratelimited", false, CVar.SERVERONLY);
/// <summary>
/// Whether clients which cannot be checked due to an error of some form will be denied
/// </summary>
public static readonly CVarDef<bool> GameIPIntelRejectUnknown =
CVarDef.Create("game.ipintel_reject_unknown", false, CVar.SERVERONLY);
/// <summary>
/// Whether clients which cannot be checked due to an error of some form will be denied
/// </summary>
public static readonly CVarDef<bool> GameIPIntelRejectUnknown =
CVarDef.Create("game.ipintel_reject_unknown", false, CVar.SERVERONLY);
/// <summary>
/// Should an admin message be made if the connection got rejected cause of ipintel?
/// </summary>
public static readonly CVarDef<bool> GameIPIntelAlertAdminReject =
CVarDef.Create("game.ipintel_alert_admin_rejected", false, CVar.SERVERONLY);
/// <summary>
/// Should an admin message be made if the connection got rejected cause of ipintel?
/// </summary>
public static readonly CVarDef<bool> GameIPIntelAlertAdminReject =
CVarDef.Create("game.ipintel_alert_admin_rejected", false, CVar.SERVERONLY);
/// <summary>
/// A contact email to be sent along with the request. Required by IPIntel
/// </summary>
public static readonly CVarDef<string> GameIPIntelEmail =
CVarDef.Create("game.ipintel_contact_email", string.Empty, CVar.SERVERONLY | CVar.CONFIDENTIAL);
/// <summary>
/// A contact email to be sent along with the request. Required by IPIntel
/// </summary>
public static readonly CVarDef<string> GameIPIntelEmail =
CVarDef.Create("game.ipintel_contact_email", string.Empty, CVar.SERVERONLY | CVar.CONFIDENTIAL);
/// <summary>
/// The URL to IPIntel to make requests to. If you pay for more queries this is what you want to change.
/// </summary>
public static readonly CVarDef<string> GameIPIntelBase =
CVarDef.Create("game.ipintel_baseurl", "https://check.getipintel.net", CVar.SERVERONLY);
/// <summary>
/// The URL to IPIntel to make requests to. If you pay for more queries this is what you want to change.
/// </summary>
public static readonly CVarDef<string> GameIPIntelBase =
CVarDef.Create("game.ipintel_baseurl", "https://check.getipintel.net", CVar.SERVERONLY);
/// <summary>
/// The flags to use in the request to IPIntel, please look here for more info. https://getipintel.net/free-proxy-vpn-tor-detection-api/#optional_settings
/// Note: Some flags may increase the chances of false positives and request time. The default should be fine for most servers.
/// </summary>
public static readonly CVarDef<string> GameIPIntelFlags =
CVarDef.Create("game.ipintel_flags", "b", CVar.SERVERONLY);
/// <summary>
/// The flags to use in the request to IPIntel, please look here for more info. https://getipintel.net/free-proxy-vpn-tor-detection-api/#optional_settings
/// Note: Some flags may increase the chances of false positives and request time. The default should be fine for most servers.
/// </summary>
public static readonly CVarDef<string> GameIPIntelFlags =
CVarDef.Create("game.ipintel_flags", "b", CVar.SERVERONLY);
/// <summary>
/// Maximum amount of requests per Minute. For free you get 15.
/// </summary>
public static readonly CVarDef<int> GameIPIntelMaxMinute =
CVarDef.Create("game.ipintel_request_limit_minute", 15, CVar.SERVERONLY);
/// <summary>
/// Maximum amount of requests per Minute. For free you get 15.
/// </summary>
public static readonly CVarDef<int> GameIPIntelMaxMinute =
CVarDef.Create("game.ipintel_request_limit_minute", 15, CVar.SERVERONLY);
/// <summary>
/// Maximum amount of requests per Day. For free you get 500.
/// </summary>
public static readonly CVarDef<int> GameIPIntelMaxDay =
CVarDef.Create("game.ipintel_request_limit_daily", 500, CVar.SERVERONLY);
/// <summary>
/// Maximum amount of requests per Day. For free you get 500.
/// </summary>
public static readonly CVarDef<int> GameIPIntelMaxDay =
CVarDef.Create("game.ipintel_request_limit_daily", 500, CVar.SERVERONLY);
/// <summary>
/// Amount of seconds to add to the exponential backoff with every failed request.
/// </summary>
public static readonly CVarDef<int> GameIPIntelBackOffSeconds =
CVarDef.Create("game.ipintel_request_backoff_seconds", 30, CVar.SERVERONLY);
/// <summary>
/// Amount of seconds to add to the exponential backoff with every failed request.
/// </summary>
public static readonly CVarDef<int> GameIPIntelBackOffSeconds =
CVarDef.Create("game.ipintel_request_backoff_seconds", 30, CVar.SERVERONLY);
/// <summary>
/// How much time should pass before we attempt to cleanup the IPIntel table for old ip addresses?
/// </summary>
public static readonly CVarDef<int> GameIPIntelCleanupMins =
CVarDef.Create("game.ipintel_database_cleanup_mins", 15, CVar.SERVERONLY);
/// <summary>
/// How much time should pass before we attempt to cleanup the IPIntel table for old ip addresses?
/// </summary>
public static readonly CVarDef<int> GameIPIntelCleanupMins =
CVarDef.Create("game.ipintel_database_cleanup_mins", 15, CVar.SERVERONLY);
/// <summary>
/// How long to store results in the cache before they must be retrieved again in days.
/// </summary>
public static readonly CVarDef<TimeSpan> GameIPIntelCacheLength =
CVarDef.Create("game.ipintel_cache_length", TimeSpan.FromDays(7), CVar.SERVERONLY);
/// <summary>
/// How long to store results in the cache before they must be retrieved again in days.
/// </summary>
public static readonly CVarDef<TimeSpan> GameIPIntelCacheLength =
CVarDef.Create("game.ipintel_cache_length", TimeSpan.FromDays(7), CVar.SERVERONLY);
/// <summary>
/// Amount of playtime in minutes to be exempt from an IP check. 0 to search everyone. 5 hours by default.
/// <remarks>
/// Trust me you want one.
/// </remarks>>
/// </summary>
public static readonly CVarDef<TimeSpan> GameIPIntelExemptPlaytime =
CVarDef.Create("game.ipintel_exempt_playtime", TimeSpan.FromMinutes(300), CVar.SERVERONLY);
/// <summary>
/// Amount of playtime in minutes to be exempt from an IP check. 0 to search everyone. 5 hours by default.
/// <remarks>
/// Trust me you want one.
/// </remarks>>
/// </summary>
public static readonly CVarDef<TimeSpan> GameIPIntelExemptPlaytime =
CVarDef.Create("game.ipintel_exempt_playtime", TimeSpan.FromMinutes(300), CVar.SERVERONLY);
/// <summary>
/// Rating to reject at. Anything equal to or higher than this will reject the connection.
/// </summary>
public static readonly CVarDef<float> GameIPIntelBadRating =
CVarDef.Create("game.ipintel_bad_rating", 0.95f, CVar.SERVERONLY);
/// <summary>
/// Rating to reject at. Anything equal to or higher than this will reject the connection.
/// </summary>
public static readonly CVarDef<float> GameIPIntelBadRating =
CVarDef.Create("game.ipintel_bad_rating", 0.95f, CVar.SERVERONLY);
/// <summary>
/// Rating to send an admin warning over, but not reject the connection. Set to 0 to disable
/// </summary>
public static readonly CVarDef<float> GameIPIntelAlertAdminWarnRating =
CVarDef.Create("game.ipintel_alert_admin_warn_rating", 0f, CVar.SERVERONLY);
/// <summary>
/// Rating to send an admin warning over, but not reject the connection. Set to 0 to disable
/// </summary>
public static readonly CVarDef<float> GameIPIntelAlertAdminWarnRating =
CVarDef.Create("game.ipintel_alert_admin_warn_rating", 0f, CVar.SERVERONLY);
/// <summary>
/// Make people bonk when trying to climb certain objects like tables.
/// </summary>
public static readonly CVarDef<bool> GameTableBonk =
CVarDef.Create("game.table_bonk", false, CVar.REPLICATED);
/// <summary>
/// Make people bonk when trying to climb certain objects like tables.
/// </summary>
public static readonly CVarDef<bool> GameTableBonk =
CVarDef.Create("game.table_bonk", false, CVar.REPLICATED);
/// <summary>
/// Whether or not status icons are rendered for everyone.
/// </summary>
public static readonly CVarDef<bool> GlobalStatusIconsEnabled =
CVarDef.Create("game.global_status_icons_enabled", true, CVar.SERVER | CVar.REPLICATED);
/// <summary>
/// Whether or not status icons are rendered for everyone.
/// </summary>
public static readonly CVarDef<bool> GlobalStatusIconsEnabled =
CVarDef.Create("game.global_status_icons_enabled", true, CVar.SERVER | CVar.REPLICATED);
/// <summary>
/// Whether or not status icons are rendered on this specific client.
/// </summary>
public static readonly CVarDef<bool> LocalStatusIconsEnabled =
CVarDef.Create("game.local_status_icons_enabled", true, CVar.CLIENTONLY);
/// <summary>
/// Whether or not status icons are rendered on this specific client.
/// </summary>
public static readonly CVarDef<bool> LocalStatusIconsEnabled =
CVarDef.Create("game.local_status_icons_enabled", true, CVar.CLIENTONLY);
/// <summary>
/// Whether or not coordinates on the Debug overlay should only be available to admins.
/// </summary>
public static readonly CVarDef<bool> DebugCoordinatesAdminOnly =
CVarDef.Create("game.debug_coordinates_admin_only", true, CVar.SERVER | CVar.REPLICATED);
/// <summary>
/// Whether or not coordinates on the Debug overlay should only be available to admins.
/// </summary>
public static readonly CVarDef<bool> DebugCoordinatesAdminOnly =
CVarDef.Create("game.debug_coordinates_admin_only", true, CVar.SERVER | CVar.REPLICATED);
#if EXCEPTION_TOLERANCE
/// <summary>
/// Amount of times round start must fail before the server is shut down.
/// Set to 0 or a negative number to disable.
/// </summary>
public static readonly CVarDef<int> RoundStartFailShutdownCount =
CVarDef.Create("game.round_start_fail_shutdown_count", 5, CVar.SERVERONLY | CVar.SERVER);
/// <summary>
/// Amount of times round start must fail before the server is shut down.
/// Set to 0 or a negative number to disable.
/// </summary>
public static readonly CVarDef<int> RoundStartFailShutdownCount =
CVarDef.Create("game.round_start_fail_shutdown_count", 5, CVar.SERVERONLY | CVar.SERVER);
#endif
/// <summary>
/// Delay between station alert level changes.
/// </summary>
public static readonly CVarDef<int> GameAlertLevelChangeDelay =
CVarDef.Create("game.alert_level_change_delay", 30, CVar.SERVERONLY);
/// <summary>
/// Delay between station alert level changes.
/// </summary>
public static readonly CVarDef<int> GameAlertLevelChangeDelay =
CVarDef.Create("game.alert_level_change_delay", 30, CVar.SERVERONLY);
/// <summary>
/// The time in seconds that the server should wait before restarting the round.
/// Defaults to 2 minutes.
/// </summary>
public static readonly CVarDef<float> RoundRestartTime =
CVarDef.Create("game.round_restart_time", 120f, CVar.SERVERONLY);
/// <summary>
/// The time in seconds that the server should wait before restarting the round.
/// Defaults to 2 minutes.
/// </summary>
public static readonly CVarDef<float> RoundRestartTime =
CVarDef.Create("game.round_restart_time", 120f, CVar.SERVERONLY);
/// <summary>
/// The prototype to use for secret weights.
/// </summary>
public static readonly CVarDef<string> SecretWeightPrototype =
CVarDef.Create("game.secret_weight_prototype", "Secret", CVar.SERVERONLY);
/// <summary>
/// The prototype to use for secret weights.
/// </summary>
public static readonly CVarDef<string> SecretWeightPrototype =
CVarDef.Create("game.secret_weight_prototype", "Secret", CVar.SERVERONLY);
/// <summary>
/// The id of the sound collection to randomly choose a sound from and play when the round ends.
/// </summary>
public static readonly CVarDef<string> RoundEndSoundCollection =
CVarDef.Create("game.round_end_sound_collection", "RoundEnd", CVar.SERVERONLY);
/// <summary>
/// The id of the sound collection to randomly choose a sound from and play when the round ends.
/// </summary>
public static readonly CVarDef<string> RoundEndSoundCollection =
CVarDef.Create("game.round_end_sound_collection", "RoundEnd", CVar.SERVERONLY);
/// <summary>
/// Whether or not to add every player as a global override to PVS at round end.
/// This will allow all players to see their clothing in the round screen player list screen,
/// but may cause lag during round end with very high player counts.
/// </summary>
public static readonly CVarDef<bool> RoundEndPVSOverrides =
CVarDef.Create("game.round_end_pvs_overrides", true, CVar.SERVERONLY);
/// <summary>
/// Whether or not to add every player as a global override to PVS at round end.
/// This will allow all players to see their clothing in the round screen player list screen,
/// but may cause lag during round end with very high player counts.
/// </summary>
public static readonly CVarDef<bool> RoundEndPVSOverrides =
CVarDef.Create("game.round_end_pvs_overrides", true, CVar.SERVERONLY);
/// <summary>
/// If true, players can place objects onto tabletop games like chess boards.
/// </summary>
/// <remarks>
/// This feature is currently highly abusable and can easily be used to crash the server,
/// so it's off by default.
/// </remarks>
public static readonly CVarDef<bool> GameTabletopPlace =
CVarDef.Create("game.tabletop_place", false, CVar.SERVERONLY);
/// <summary>
/// If true, players can place objects onto tabletop games like chess boards.
/// </summary>
/// <remarks>
/// This feature is currently highly abusable and can easily be used to crash the server,
/// so it's off by default.
/// </remarks>
public static readonly CVarDef<bool> GameTabletopPlace =
CVarDef.Create("game.tabletop_place", false, CVar.SERVERONLY);
/// <summary>
/// If true, contraband severity can be viewed in the examine menu
/// </summary>
public static readonly CVarDef<bool> ContrabandExamine =
CVarDef.Create("game.contraband_examine", true, CVar.SERVER | CVar.REPLICATED);
/// <summary>
/// If true, contraband severity can be viewed in the examine menu
/// </summary>
public static readonly CVarDef<bool> ContrabandExamine =
CVarDef.Create("game.contraband_examine", true, CVar.SERVER | CVar.REPLICATED);
/// <summary>
/// Size of the lookup area for adding entities to the context menu
/// </summary>
public static readonly CVarDef<float> GameEntityMenuLookup =
CVarDef.Create("game.entity_menu_lookup", 0.25f, CVar.CLIENTONLY | CVar.ARCHIVE);
/// <summary>
/// Should the clients window show the server hostname in the title?
/// </summary>
public static readonly CVarDef<bool> GameHostnameInTitlebar =
CVarDef.Create("game.hostname_in_titlebar", true, CVar.SERVER | CVar.REPLICATED);
/// <summary>
/// Size of the lookup area for adding entities to the context menu
/// </summary>
public static readonly CVarDef<float> GameEntityMenuLookup =
CVarDef.Create("game.entity_menu_lookup", 0.25f, CVar.CLIENTONLY | CVar.ARCHIVE);
/// <summary>
/// Should the clients window show the server hostname in the title?
/// </summary>
public static readonly CVarDef<bool> GameHostnameInTitlebar =
CVarDef.Create("game.hostname_in_titlebar", true, CVar.SERVER | CVar.REPLICATED);
}

View File

@@ -10,12 +10,12 @@ namespace Content.Shared.Cargo.Prototypes
{
/// <inheritdoc />
[ParentDataField(typeof(AbstractPrototypeIdArraySerializer<CargoProductPrototype>))]
public string[]? Parents { get; }
public string[]? Parents { get; private set; }
/// <inheritdoc />
[NeverPushInheritance]
[AbstractDataField]
public bool Abstract { get; }
public bool Abstract { get; private set; }
[DataField("name")] private string _name = string.Empty;

View File

@@ -16,6 +16,8 @@ public sealed class CartridgeUiMessage : BoundUserInterfaceMessage
[Serializable, NetSerializable]
public abstract class CartridgeMessageEvent : EntityEventArgs
{
[NonSerialized]
public EntityUid User;
public NetEntity LoaderUid;
[NonSerialized]

View File

@@ -0,0 +1,6 @@
using Robust.Shared.Serialization;
namespace Content.Shared.CartridgeLoader.Cartridges;
[Serializable, NetSerializable]
public sealed class LogProbePrintMessage : CartridgeMessageEvent;

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