Merge pull request #968 from crystallpunk-14/ed-2025-03-03-upstream-stable-2
Stable upstream sync
This commit is contained in:
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
};
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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++)
|
||||
{
|
||||
|
||||
@@ -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>
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
35
Content.Client/Implants/UI/DeimplantBoundUserInterface.cs
Normal file
35
Content.Client/Implants/UI/DeimplantBoundUserInterface.cs
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
12
Content.Client/Implants/UI/DeimplantChoiceWindow.xaml
Normal file
12
Content.Client/Implants/UI/DeimplantChoiceWindow.xaml
Normal 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>
|
||||
53
Content.Client/Implants/UI/DeimplantChoiceWindow.xaml.cs
Normal file
53
Content.Client/Implants/UI/DeimplantChoiceWindow.xaml.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)))
|
||||
|
||||
@@ -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!;
|
||||
|
||||
@@ -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 -->
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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" />
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
12
Content.Client/Options/UI/Tabs/AdminOptionsTab.xaml
Normal file
12
Content.Client/Options/UI/Tabs/AdminOptionsTab.xaml
Normal 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>
|
||||
20
Content.Client/Options/UI/Tabs/AdminOptionsTab.xaml.cs
Normal file
20
Content.Client/Options/UI/Tabs/AdminOptionsTab.xaml.cs
Normal 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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
29
Content.Client/SubFloor/TrayScanRevealSystem.cs
Normal file
29
Content.Client/SubFloor/TrayScanRevealSystem.cs
Normal 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>);
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
{
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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(() =>
|
||||
|
||||
@@ -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 =
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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!;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
{}
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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]
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -68,8 +68,6 @@ public sealed partial class ImplanterSystem : SharedImplanterSystem
|
||||
args.Handled = true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Attempt to implant someone else.
|
||||
/// </summary>
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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];
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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!;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
namespace Content.Server.Objectives.Components;
|
||||
|
||||
/// <summary>
|
||||
/// A free greentext, that's it.
|
||||
/// </summary>
|
||||
[RegisterComponent]
|
||||
public sealed partial class FreeObjectiveComponent : Component;
|
||||
20
Content.Server/Objectives/Systems/FreeObjectiveSystem.cs
Normal file
20
Content.Server/Objectives/Systems/FreeObjectiveSystem.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
7
Content.Server/Roles/WizardRoleComponent.cs
Normal file
7
Content.Server/Roles/WizardRoleComponent.cs
Normal 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;
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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();
|
||||
|
||||
|
||||
@@ -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>();
|
||||
|
||||
@@ -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
|
||||
{
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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]
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -10,5 +10,5 @@ public sealed partial class AlertCategoryPrototype : IPrototype
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
[IdDataField]
|
||||
public string ID { get; } = default!;
|
||||
public string ID { get; private set; } = default!;
|
||||
}
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -16,6 +16,8 @@ public sealed class CartridgeUiMessage : BoundUserInterfaceMessage
|
||||
[Serializable, NetSerializable]
|
||||
public abstract class CartridgeMessageEvent : EntityEventArgs
|
||||
{
|
||||
[NonSerialized]
|
||||
public EntityUid User;
|
||||
public NetEntity LoaderUid;
|
||||
|
||||
[NonSerialized]
|
||||
|
||||
@@ -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
Reference in New Issue
Block a user