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

# Conflicts:
#	Resources/Prototypes/Entities/Mobs/Cyborgs/borg_chassis.yml
#	Resources/ServerInfo/Guidebook/Mobs/SlimePerson.xml
#	Resources/Textures/Clothing/Hands/Gloves/Color/yellow.rsi/meta.json
#	Resources/Textures/Clothing/Shoes/Boots/combatboots.rsi/meta.json
#	Resources/Textures/Clothing/Shoes/Boots/magboots-science.rsi/meta.json
#	Resources/Textures/Clothing/Shoes/Boots/speedboots.rsi/meta.json
#	Resources/Textures/Structures/Wallmounts/signs.rsi/chemistry1.png
#	Resources/Textures/Structures/Wallmounts/signs.rsi/chemistry2.png
#	Resources/Textures/Structures/Wallmounts/signs.rsi/court.png
#	Resources/Textures/Structures/Wallmounts/signs.rsi/deathsposal.png
#	Resources/Textures/Structures/Wallmounts/signs.rsi/doors.png
#	Resources/Textures/Structures/Wallmounts/signs.rsi/examroom.png
#	Resources/Textures/Structures/Wallmounts/signs.rsi/hydro1.png
#	Resources/Textures/Structures/Wallmounts/signs.rsi/hydro2.png
#	Resources/Textures/Structures/Wallmounts/signs.rsi/hydro3.png
#	Resources/Textures/Structures/Wallmounts/signs.rsi/janitor.png
#	Resources/Textures/Structures/Wallmounts/signs.rsi/law.png
#	Resources/Textures/Structures/Wallmounts/signs.rsi/meta.json
#	Resources/Textures/Structures/Wallmounts/signs.rsi/psychology.png
#	Resources/Textures/Structures/Wallmounts/signs.rsi/science1.png
#	Resources/Textures/Structures/Wallmounts/signs.rsi/science2.png
#	Resources/Textures/Structures/Wallmounts/signs.rsi/security.png
#	Resources/Textures/Structures/Wallmounts/signs.rsi/space.png
#	Resources/Textures/Structures/Wallmounts/signs.rsi/xenobio.png
#	Resources/Textures/Structures/Wallmounts/signs.rsi/xenobio2.png
#	Resources/migration.yml
This commit is contained in:
Morb0
2024-07-21 07:20:43 +03:00
300 changed files with 6930 additions and 6715 deletions

View File

@@ -129,7 +129,7 @@ csharp_indent_braces = false
csharp_indent_switch_labels = true
# Space preferences
csharp_space_after_cast = true
csharp_space_after_cast = false
csharp_space_after_colon_in_inheritance_clause = true
csharp_space_after_comma = true
csharp_space_after_dot = false

View File

@@ -12,11 +12,18 @@ namespace Content.Client.Access.UI;
[GenerateTypedNameReferences]
public sealed partial class AccessLevelControl : GridContainer
{
[Dependency] private readonly ILogManager _logManager = default!;
private ISawmill _sawmill = default!;
public readonly Dictionary<ProtoId<AccessLevelPrototype>, Button> ButtonsList = new();
public AccessLevelControl()
{
RobustXamlLoader.Load(this);
IoCManager.InjectDependencies(this);
_sawmill = _logManager.GetSawmill("accesslevelcontrol");
}
public void Populate(List<ProtoId<AccessLevelPrototype>> accessLevels, IPrototypeManager prototypeManager)
@@ -25,7 +32,7 @@ public sealed partial class AccessLevelControl : GridContainer
{
if (!prototypeManager.TryIndex(access, out var accessLevel))
{
Logger.Error($"Unable to find accesslevel for {access}");
_sawmill.Error($"Unable to find accesslevel for {access}");
continue;
}

View File

@@ -107,7 +107,7 @@ namespace Content.Client.Actions
UpdateAction(uid, component);
}
protected override void UpdateAction(EntityUid? actionId, BaseActionComponent? action = null)
public override void UpdateAction(EntityUid? actionId, BaseActionComponent? action = null)
{
if (!ResolveActionData(actionId, ref action))
return;

View File

@@ -14,7 +14,6 @@ namespace Content.Client.Administration.UI.Tabs.ObjectsTab;
public sealed partial class ObjectsTab : Control
{
[Dependency] private readonly IEntityManager _entityManager = default!;
[Dependency] private readonly IGameTiming _timing = default!;
private readonly Color _altColor = Color.FromHex("#292B38");
private readonly Color _defaultColor = Color.FromHex("#2F2F3B");

View File

@@ -54,7 +54,7 @@ public sealed class AudioUIController : UIController
{
if (!string.IsNullOrEmpty(value))
{
var resource = _cache.GetResource<AudioResource>(value);
var resource = GetSoundOrFallback(value, CCVars.UIClickSound.DefaultValue);
var source =
_audioManager.CreateAudioSource(resource);
@@ -77,7 +77,7 @@ public sealed class AudioUIController : UIController
{
if (!string.IsNullOrEmpty(value))
{
var hoverResource = _cache.GetResource<AudioResource>(value);
var hoverResource = GetSoundOrFallback(value, CCVars.UIHoverSound.DefaultValue);
var hoverSource =
_audioManager.CreateAudioSource(hoverResource);
@@ -95,4 +95,12 @@ public sealed class AudioUIController : UIController
UIManager.SetHoverSound(null);
}
}
private AudioResource GetSoundOrFallback(string path, string fallback)
{
if (!_cache.TryGetResource(path, out AudioResource? resource))
return _cache.GetResource<AudioResource>(fallback);
return resource;
}
}

View File

@@ -4,6 +4,7 @@ using Content.Shared.Audio;
using Content.Shared.CCVar;
using Content.Shared.GameTicking;
using Content.Shared.Random;
using Content.Shared.Random.Rules;
using Robust.Client.GameObjects;
using Robust.Client.Player;
using Robust.Client.ResourceManagement;

View File

@@ -31,7 +31,7 @@ public sealed partial class NewsReaderUiFragment : BoxContainer
Author.Visible = true;
PageName.Text = article.Title;
PageText.SetMarkup(article.Content);
PageText.SetMarkupPermissive(article.Content);
PageNum.Text = $"{targetNum}/{totalNum}";

View File

@@ -26,7 +26,6 @@ namespace Content.Client.Construction
{
[Dependency] private readonly IPlayerManager _playerManager = default!;
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
[Dependency] private readonly SharedInteractionSystem _interactionSystem = default!;
[Dependency] private readonly ExamineSystemShared _examineSystem = default!;
[Dependency] private readonly SharedTransformSystem _transformSystem = default!;
[Dependency] private readonly PopupSystem _popupSystem = default!;

View File

@@ -2,6 +2,7 @@ using Content.Shared.Disposal;
using Robust.Client.AutoGenerated;
using Robust.Client.UserInterface.CustomControls;
using Robust.Client.UserInterface.XAML;
using Robust.Shared.Timing;
namespace Content.Client.Disposal.UI
{
@@ -11,6 +12,8 @@ namespace Content.Client.Disposal.UI
[GenerateTypedNameReferences]
public sealed partial class MailingUnitWindow : DefaultWindow
{
public TimeSpan FullPressure;
public MailingUnitWindow()
{
RobustXamlLoader.Load(this);
@@ -26,6 +29,7 @@ namespace Content.Client.Disposal.UI
Title = Loc.GetString("ui-mailing-unit-window-title", ("tag", state.Tag ?? " "));
UnitState.Text = disposalState.UnitState;
FullPressure = disposalState.FullPressureTime;
var pressureReached = PressureBar.UpdatePressure(disposalState.FullPressureTime);
Power.Pressed = disposalState.Powered;
Engage.Pressed = disposalState.Engaged;
@@ -42,9 +46,10 @@ namespace Content.Client.Disposal.UI
return !disposalState.Powered || pressureReached;
}
public bool UpdatePressure(TimeSpan stateFullPressureTime)
protected override void FrameUpdate(FrameEventArgs args)
{
return PressureBar.UpdatePressure(stateFullPressureTime);
base.FrameUpdate(args);
PressureBar.UpdatePressure(FullPressure);
}
}
}

View File

@@ -25,24 +25,30 @@ public sealed class FaxVisualsSystem : EntitySystem
if (args.Sprite == null)
return;
if (_appearance.TryGetData(uid, FaxMachineVisuals.VisualState, out FaxMachineVisualState visuals) && visuals == FaxMachineVisualState.Inserting)
if (_player.HasRunningAnimation(uid, "faxecute"))
return;
if (_appearance.TryGetData(uid, FaxMachineVisuals.VisualState, out FaxMachineVisualState visuals) &&
visuals == FaxMachineVisualState.Inserting)
{
_player.Play(uid, new Animation()
{
Length = TimeSpan.FromSeconds(2.4),
AnimationTracks =
_player.Play(uid,
new Animation()
{
new AnimationTrackSpriteFlick()
Length = TimeSpan.FromSeconds(2.4),
AnimationTracks =
{
LayerKey = FaxMachineVisuals.VisualState,
KeyFrames =
new AnimationTrackSpriteFlick()
{
new AnimationTrackSpriteFlick.KeyFrame(component.InsertingState, 0f),
new AnimationTrackSpriteFlick.KeyFrame("icon", 2.4f),
}
}
}
}, "faxecute");
LayerKey = FaxMachineVisuals.VisualState,
KeyFrames =
{
new AnimationTrackSpriteFlick.KeyFrame(component.InsertingState, 0f),
new AnimationTrackSpriteFlick.KeyFrame("icon", 2.4f),
},
},
},
},
"faxecute");
}
}
}

View File

@@ -0,0 +1,29 @@
using Content.Shared.IconSmoothing;
using Robust.Client.GameObjects;
namespace Content.Client.IconSmoothing;
public sealed class ClientRandomIconSmoothSystem : SharedRandomIconSmoothSystem
{
[Dependency] private readonly IconSmoothSystem _iconSmooth = default!;
[Dependency] private readonly AppearanceSystem _appearance = default!;
public override void Initialize()
{
base.Initialize();
SubscribeLocalEvent<RandomIconSmoothComponent, AppearanceChangeEvent>(OnAppearanceChange);
}
private void OnAppearanceChange(Entity<RandomIconSmoothComponent> ent, ref AppearanceChangeEvent args)
{
if (!TryComp<IconSmoothComponent>(ent, out var smooth))
return;
if (!_appearance.TryGetData<string>(ent, RandomIconSmoothState.State, out var state, args.Component))
return;
smooth.StateBase = state;
_iconSmooth.SetStateBase(ent, smooth, state);
}
}

View File

@@ -30,7 +30,7 @@ namespace Content.Client.IconSmoothing
/// Prepended to the RSI state.
/// </summary>
[ViewVariables(VVAccess.ReadWrite), DataField("base")]
public string StateBase { get; private set; } = string.Empty;
public string StateBase { get; set; } = string.Empty;
[DataField("shader", customTypeSerializer:typeof(PrototypeIdSerializer<ShaderPrototype>))]
public string? Shader;

View File

@@ -55,6 +55,33 @@ namespace Content.Client.IconSmoothing
if (component.Mode != IconSmoothingMode.Corners || !TryComp(uid, out SpriteComponent? sprite))
return;
SetCornerLayers(sprite, component);
if (component.Shader != null)
{
sprite.LayerSetShader(CornerLayers.SE, component.Shader);
sprite.LayerSetShader(CornerLayers.NE, component.Shader);
sprite.LayerSetShader(CornerLayers.NW, component.Shader);
sprite.LayerSetShader(CornerLayers.SW, component.Shader);
}
}
public void SetStateBase(EntityUid uid, IconSmoothComponent component, string newState)
{
if (!TryComp<SpriteComponent>(uid, out var sprite))
return;
component.StateBase = newState;
SetCornerLayers(sprite, component);
}
private void SetCornerLayers(SpriteComponent sprite, IconSmoothComponent component)
{
sprite.LayerMapRemove(CornerLayers.SE);
sprite.LayerMapRemove(CornerLayers.NE);
sprite.LayerMapRemove(CornerLayers.NW);
sprite.LayerMapRemove(CornerLayers.SW);
var state0 = $"{component.StateBase}0";
sprite.LayerMapSet(CornerLayers.SE, sprite.AddLayerState(state0));
sprite.LayerSetDirOffset(CornerLayers.SE, DirectionOffset.None);
@@ -64,14 +91,6 @@ namespace Content.Client.IconSmoothing
sprite.LayerSetDirOffset(CornerLayers.NW, DirectionOffset.Flip);
sprite.LayerMapSet(CornerLayers.SW, sprite.AddLayerState(state0));
sprite.LayerSetDirOffset(CornerLayers.SW, DirectionOffset.Clockwise);
if (component.Shader != null)
{
sprite.LayerSetShader(CornerLayers.SE, component.Shader);
sprite.LayerSetShader(CornerLayers.NE, component.Shader);
sprite.LayerSetShader(CornerLayers.NW, component.Shader);
sprite.LayerSetShader(CornerLayers.SW, component.Shader);
}
}
private void OnShutdown(EntityUid uid, IconSmoothComponent component, ComponentShutdown args)

View File

@@ -21,7 +21,6 @@ public sealed partial class LatheMenu : DefaultWindow
{
[Dependency] private readonly IEntityManager _entityManager = default!;
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
[Dependency] private readonly IResourceCache _resources = default!;
private EntityUid _owner;
private readonly SpriteSystem _spriteSystem;

View File

@@ -1,6 +1,5 @@
using Content.Shared.Research;
using Content.Shared.Research.Components;
using Robust.Client.GameObjects;
namespace Content.Client.Research.UI
{

View File

@@ -1,5 +1,4 @@
using Content.Shared.Research.Components;
using Robust.Client.GameObjects;
namespace Content.Client.Research.UI
{

View File

@@ -1,6 +1,5 @@
using Content.Shared.Research.Components;
using JetBrains.Annotations;
using Robust.Client.GameObjects;
namespace Content.Client.Research.UI;

View File

@@ -81,7 +81,7 @@ public sealed partial class ResearchConsoleMenu : FancyWindow
public void UpdateInformationPanel(ResearchConsoleBoundInterfaceState state)
{
var amountMsg = new FormattedMessage();
amountMsg.AddMarkup(Loc.GetString("research-console-menu-research-points-text",
amountMsg.AddMarkupOrThrow(Loc.GetString("research-console-menu-research-points-text",
("points", state.Points)));
ResearchAmountLabel.SetMessage(amountMsg);
@@ -98,7 +98,7 @@ public sealed partial class ResearchConsoleMenu : FancyWindow
}
var msg = new FormattedMessage();
msg.AddMarkup(Loc.GetString("research-console-menu-main-discipline",
msg.AddMarkupOrThrow(Loc.GetString("research-console-menu-main-discipline",
("name", disciplineText), ("color", disciplineColor)));
MainDisciplineLabel.SetMessage(msg);

View File

@@ -23,7 +23,7 @@ public sealed partial class TechnologyCardControl : Control
DisciplineTexture.Texture = spriteSys.Frame0(discipline.Icon);
TechnologyNameLabel.Text = Loc.GetString(technology.Name);
var message = new FormattedMessage();
message.AddMarkup(Loc.GetString("research-console-tier-discipline-info",
message.AddMarkupOrThrow(Loc.GetString("research-console-tier-discipline-info",
("tier", technology.Tier), ("color", discipline.Color), ("discipline", Loc.GetString(discipline.Name))));
TierLabel.SetMessage(message);
UnlocksLabel.SetMessage(description);

View File

@@ -1343,6 +1343,9 @@ namespace Content.Client.Stylesheets
new StyleProperty(Label.StylePropertyAlignMode, Label.AlignMode.Center),
}),
Element<PanelContainer>().Class(OptionButton.StyleClassOptionsBackground)
.Prop(PanelContainer.StylePropertyPanel, new StyleBoxFlat(Color.FromHex("#25252A"))),
new StyleRule(new SelectorElement(typeof(PanelContainer), new []{ ClassHighDivider}, null, null), new []
{
new StyleProperty(PanelContainer.StylePropertyPanel, new StyleBoxFlat { BackgroundColor = NanoGold, ContentMarginBottomOverride = 2, ContentMarginLeftOverride = 2}),

View File

@@ -1,11 +1,13 @@
using System.Linq;
using Content.Client.CharacterInfo;
using Content.Client.Gameplay;
using Content.Client.Stylesheets;
using Content.Client.UserInterface.Controls;
using Content.Client.UserInterface.Systems.Character.Controls;
using Content.Client.UserInterface.Systems.Character.Windows;
using Content.Client.UserInterface.Systems.Objectives.Controls;
using Content.Shared.Input;
using Content.Shared.Objectives.Systems;
using JetBrains.Annotations;
using Robust.Client.GameObjects;
using Robust.Client.Player;
@@ -121,11 +123,17 @@ public sealed class CharacterUIController : UIController, IOnStateEntered<Gamepl
Modulate = Color.Gray
};
objectiveControl.AddChild(new Label
var objectiveText = new FormattedMessage();
objectiveText.TryAddMarkup(groupId, out _);
var objectiveLabel = new RichTextLabel
{
Text = groupId,
Modulate = Color.LightSkyBlue
});
StyleClasses = {StyleNano.StyleClassTooltipActionTitle}
};
objectiveLabel.SetMessage(objectiveText);
objectiveControl.AddChild(objectiveLabel);
foreach (var condition in conditions)
{

View File

@@ -17,7 +17,6 @@ namespace Content.Client.VendingMachines.UI
{
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
[Dependency] private readonly IEntityManager _entityManager = default!;
[Dependency] private readonly IGameTiming _timing = default!;
private readonly Dictionary<EntProtoId, EntityUid> _dummies = [];

View File

@@ -904,6 +904,9 @@ namespace Content.Server.Database
Panic = 3,
/*
* TODO: Remove baby jail code once a more mature gateway process is established. This code is only being issued as a stopgap to help with potential tiding in the immediate future.
*
* If baby jail is removed, please reserve this value for as long as can reasonably be done to prevent causing ambiguity in connection denial reasons.
* Reservation by commenting out the value is likely sufficient for this purpose, but may impact projects which depend on SS14 like SS14.Admin.
*/
BabyJail = 4,
}

View File

@@ -12,13 +12,12 @@ using Robust.Shared.Console;
namespace Content.Server.Administration.Commands;
[AdminCommand(AdminFlags.Admin)]
public sealed class AGhost : LocalizedCommands
public sealed class AGhostCommand : LocalizedCommands
{
[Dependency] private readonly IEntityManager _entities = default!;
[Dependency] private readonly IPlayerManager _playerManager = default!;
public override string Command => "aghost";
public override string Description => LocalizationManager.GetString("aghost-description");
public override string Help => "aghost";
public override CompletionResult GetCompletion(IConsoleShell shell, string[] args)

View File

@@ -22,8 +22,6 @@ namespace Content.Server.Ame.EntitySystems;
public sealed class AmeControllerSystem : EntitySystem
{
[Dependency] private readonly IAdminLogManager _adminLogger = default!;
[Dependency] private readonly IAdminManager _adminManager = default!;
[Dependency] private readonly IChatManager _chatManager = default!;
[Dependency] private readonly IGameTiming _gameTiming = default!;
[Dependency] private readonly AppearanceSystem _appearanceSystem = default!;
[Dependency] private readonly SharedAudioSystem _audioSystem = default!;

View File

@@ -141,7 +141,7 @@ public sealed partial class AnomalySystem
var msg = new FormattedMessage();
if (component.ScannedAnomaly is not { } anomaly || !TryComp<AnomalyComponent>(anomaly, out var anomalyComp))
{
msg.AddMarkup(Loc.GetString("anomaly-scanner-no-anomaly"));
msg.AddMarkupOrThrow(Loc.GetString("anomaly-scanner-no-anomaly"));
return msg;
}
@@ -149,14 +149,14 @@ public sealed partial class AnomalySystem
//Severity
if (secret != null && secret.Secret.Contains(AnomalySecretData.Severity))
msg.AddMarkup(Loc.GetString("anomaly-scanner-severity-percentage-unknown"));
msg.AddMarkupOrThrow(Loc.GetString("anomaly-scanner-severity-percentage-unknown"));
else
msg.AddMarkup(Loc.GetString("anomaly-scanner-severity-percentage", ("percent", anomalyComp.Severity.ToString("P"))));
msg.AddMarkupOrThrow(Loc.GetString("anomaly-scanner-severity-percentage", ("percent", anomalyComp.Severity.ToString("P"))));
msg.PushNewline();
//Stability
if (secret != null && secret.Secret.Contains(AnomalySecretData.Stability))
msg.AddMarkup(Loc.GetString("anomaly-scanner-stability-unknown"));
msg.AddMarkupOrThrow(Loc.GetString("anomaly-scanner-stability-unknown"));
else
{
string stateLoc;
@@ -166,54 +166,54 @@ public sealed partial class AnomalySystem
stateLoc = Loc.GetString("anomaly-scanner-stability-high");
else
stateLoc = Loc.GetString("anomaly-scanner-stability-medium");
msg.AddMarkup(stateLoc);
msg.AddMarkupOrThrow(stateLoc);
}
msg.PushNewline();
//Point output
if (secret != null && secret.Secret.Contains(AnomalySecretData.OutputPoint))
msg.AddMarkup(Loc.GetString("anomaly-scanner-point-output-unknown"));
msg.AddMarkupOrThrow(Loc.GetString("anomaly-scanner-point-output-unknown"));
else
msg.AddMarkup(Loc.GetString("anomaly-scanner-point-output", ("point", GetAnomalyPointValue(anomaly, anomalyComp))));
msg.AddMarkupOrThrow(Loc.GetString("anomaly-scanner-point-output", ("point", GetAnomalyPointValue(anomaly, anomalyComp))));
msg.PushNewline();
msg.PushNewline();
//Particles title
msg.AddMarkup(Loc.GetString("anomaly-scanner-particle-readout"));
msg.AddMarkupOrThrow(Loc.GetString("anomaly-scanner-particle-readout"));
msg.PushNewline();
//Danger
if (secret != null && secret.Secret.Contains(AnomalySecretData.ParticleDanger))
msg.AddMarkup(Loc.GetString("anomaly-scanner-particle-danger-unknown"));
msg.AddMarkupOrThrow(Loc.GetString("anomaly-scanner-particle-danger-unknown"));
else
msg.AddMarkup(Loc.GetString("anomaly-scanner-particle-danger", ("type", GetParticleLocale(anomalyComp.SeverityParticleType))));
msg.AddMarkupOrThrow(Loc.GetString("anomaly-scanner-particle-danger", ("type", GetParticleLocale(anomalyComp.SeverityParticleType))));
msg.PushNewline();
//Unstable
if (secret != null && secret.Secret.Contains(AnomalySecretData.ParticleUnstable))
msg.AddMarkup(Loc.GetString("anomaly-scanner-particle-unstable-unknown"));
msg.AddMarkupOrThrow(Loc.GetString("anomaly-scanner-particle-unstable-unknown"));
else
msg.AddMarkup(Loc.GetString("anomaly-scanner-particle-unstable", ("type", GetParticleLocale(anomalyComp.DestabilizingParticleType))));
msg.AddMarkupOrThrow(Loc.GetString("anomaly-scanner-particle-unstable", ("type", GetParticleLocale(anomalyComp.DestabilizingParticleType))));
msg.PushNewline();
//Containment
if (secret != null && secret.Secret.Contains(AnomalySecretData.ParticleContainment))
msg.AddMarkup(Loc.GetString("anomaly-scanner-particle-containment-unknown"));
msg.AddMarkupOrThrow(Loc.GetString("anomaly-scanner-particle-containment-unknown"));
else
msg.AddMarkup(Loc.GetString("anomaly-scanner-particle-containment", ("type", GetParticleLocale(anomalyComp.WeakeningParticleType))));
msg.AddMarkupOrThrow(Loc.GetString("anomaly-scanner-particle-containment", ("type", GetParticleLocale(anomalyComp.WeakeningParticleType))));
msg.PushNewline();
//Transformation
if (secret != null && secret.Secret.Contains(AnomalySecretData.ParticleTransformation))
msg.AddMarkup(Loc.GetString("anomaly-scanner-particle-transformation-unknown"));
msg.AddMarkupOrThrow(Loc.GetString("anomaly-scanner-particle-transformation-unknown"));
else
msg.AddMarkup(Loc.GetString("anomaly-scanner-particle-transformation", ("type", GetParticleLocale(anomalyComp.TransformationParticleType))));
msg.AddMarkupOrThrow(Loc.GetString("anomaly-scanner-particle-transformation", ("type", GetParticleLocale(anomalyComp.TransformationParticleType))));
//Behavior
msg.PushNewline();
msg.PushNewline();
msg.AddMarkup(Loc.GetString("anomaly-behavior-title"));
msg.AddMarkupOrThrow(Loc.GetString("anomaly-behavior-title"));
msg.PushNewline();
if (secret != null && secret.Secret.Contains(AnomalySecretData.Behavior))
@@ -224,14 +224,14 @@ public sealed partial class AnomalySystem
{
var behavior = _prototype.Index(anomalyComp.CurrentBehavior.Value);
msg.AddMarkup("- " + Loc.GetString(behavior.Description));
msg.AddMarkupOrThrow("- " + Loc.GetString(behavior.Description));
msg.PushNewline();
var mod = Math.Floor((behavior.EarnPointModifier) * 100);
msg.AddMarkup("- " + Loc.GetString("anomaly-behavior-point", ("mod", mod)));
msg.AddMarkupOrThrow("- " + Loc.GetString("anomaly-behavior-point", ("mod", mod)));
}
else
{
msg.AddMarkup(Loc.GetString("anomaly-behavior-balanced"));
msg.AddMarkupOrThrow(Loc.GetString("anomaly-behavior-balanced"));
}
}

View File

@@ -24,7 +24,7 @@ namespace Content.Server.Botany.Components
/// <summary>
/// Name of a base seed prototype that is used if <see cref="Seed"/> is null.
/// </summary>
[DataField("seedId", customTypeSerializer:typeof(PrototypeIdSerializer<SeedPrototype>))]
[DataField("seedId", customTypeSerializer: typeof(PrototypeIdSerializer<SeedPrototype>))]
public string? SeedId;
}
}

View File

@@ -2,10 +2,8 @@ using Robust.Shared.Prototypes;
using Robust.Shared.Random;
using Content.Shared.Random;
using Content.Shared.Random.Helpers;
using Content.Shared.Chemistry.Reagent;
using System.Linq;
using Content.Shared.Atmos;
using FastAccessors;
namespace Content.Server.Botany;
@@ -42,6 +40,7 @@ public sealed class MutationSystem : EntitySystem
// Add up everything in the bits column and put the number here.
const int totalbits = 275;
#pragma warning disable IDE0055 // disable formatting warnings because this looks more readable
// Tolerances (55)
MutateFloat(ref seed.NutrientConsumption , 0.05f, 1.2f, 5, totalbits, severity);
MutateFloat(ref seed.WaterConsumption , 3f , 9f , 5, totalbits, severity);
@@ -75,6 +74,7 @@ public sealed class MutationSystem : EntitySystem
MutateBool(ref seed.TurnIntoKudzu , true , 10, totalbits, severity);
MutateBool(ref seed.CanScream , true , 10, totalbits, severity);
seed.BioluminescentColor = RandomColor(seed.BioluminescentColor, 10, totalbits, severity);
#pragma warning restore IDE0055
// ConstantUpgade (10)
MutateHarvestType(ref seed.HarvestRepeat, 10, totalbits, severity);
@@ -261,7 +261,7 @@ public sealed class MutationSystem : EntitySystem
{
var pick = _randomChems.Pick(_robustRandom);
string chemicalId = pick.reagent;
int amount = _robustRandom.Next(1, ((int)pick.quantity));
int amount = _robustRandom.Next(1, (int)pick.quantity);
SeedChemQuantity seedChemQuantity = new SeedChemQuantity();
if (chemicals.ContainsKey(chemicalId))
{
@@ -274,7 +274,7 @@ public sealed class MutationSystem : EntitySystem
seedChemQuantity.Max = 1 + amount;
seedChemQuantity.Inherent = false;
}
int potencyDivisor = (int) Math.Ceiling(100.0f / seedChemQuantity.Max);
int potencyDivisor = (int)Math.Ceiling(100.0f / seedChemQuantity.Max);
seedChemQuantity.PotencyDivisor = potencyDivisor;
chemicals[chemicalId] = seedChemQuantity;
}

View File

@@ -29,12 +29,12 @@ public sealed class SeedExtractorSystem : EntitySystem
return;
if (!_botanySystem.TryGetSeed(produce, out var seed) || seed.Seedless)
{
_popupSystem.PopupCursor(Loc.GetString("seed-extractor-component-no-seeds",("name", args.Used)),
_popupSystem.PopupCursor(Loc.GetString("seed-extractor-component-no-seeds", ("name", args.Used)),
args.User, PopupType.MediumCaution);
return;
}
_popupSystem.PopupCursor(Loc.GetString("seed-extractor-component-interact-message",("name", args.Used)),
_popupSystem.PopupCursor(Loc.GetString("seed-extractor-component-interact-message", ("name", args.Used)),
args.User, PopupType.Medium);
QueueDel(args.Used);

View File

@@ -36,14 +36,14 @@ public sealed class CharacterInfoSystem : EntitySystem
if (_minds.TryGetMind(entity, out var mindId, out var mind))
{
// Get objectives
foreach (var objective in mind.AllObjectives)
foreach (var objective in mind.Objectives)
{
var info = _objectives.GetInfo(objective, mindId, mind);
if (info == null)
continue;
// group objectives by their issuer
var issuer = Comp<ObjectiveComponent>(objective).Issuer;
var issuer = Comp<ObjectiveComponent>(objective).LocIssuer;
if (!objectives.ContainsKey(issuer))
objectives[issuer] = new List<ObjectiveInfo>();
objectives[issuer].Add(info.Value);

View File

@@ -60,7 +60,6 @@ public sealed partial class ChatSystem : SharedChatSystem
[Dependency] private readonly StationSystem _stationSystem = default!;
[Dependency] private readonly MobStateSystem _mobStateSystem = default!;
[Dependency] private readonly SharedAudioSystem _audio = default!;
[Dependency] private readonly SharedInteractionSystem _interactionSystem = default!;
[Dependency] private readonly ReplacementAccentSystem _wordreplacement = default!;
[Dependency] private readonly EntityWhitelistSystem _whitelistSystem = default!;
[Dependency] private readonly ExamineSystemShared _examineSystem = default!;

View File

@@ -29,7 +29,6 @@ public sealed class CluwneSystem : EntitySystem
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
[Dependency] private readonly ChatSystem _chat = default!;
[Dependency] private readonly AutoEmoteSystem _autoEmote = default!;
[Dependency] private readonly MetaDataSystem _metaData = default!;
[Dependency] private readonly NameModifierSystem _nameMod = default!;
public override void Initialize()

View File

@@ -337,6 +337,12 @@ namespace Content.Server.Connection
return (false, "");
var isAccountAgeInvalid = record.FirstSeenTime.CompareTo(DateTimeOffset.Now - TimeSpan.FromMinutes(maxAccountAgeMinutes)) <= 0;
if (isAccountAgeInvalid)
{
_sawmill.Debug($"Baby jail will deny {userId} for account age {record.FirstSeenTime}"); // Remove on or after 2024-09
}
if (isAccountAgeInvalid && showReason)
{
var locAccountReason = reason != string.Empty
@@ -351,7 +357,12 @@ namespace Content.Server.Connection
}
var overallTime = ( await _db.GetPlayTimes(e.UserId)).Find(p => p.Tracker == PlayTimeTrackingShared.TrackerOverall);
var isTotalPlaytimeInvalid = overallTime == null || overallTime.TimeSpent.TotalMinutes >= maxPlaytimeMinutes;
var isTotalPlaytimeInvalid = overallTime != null && overallTime.TimeSpent.TotalMinutes >= maxPlaytimeMinutes;
if (isTotalPlaytimeInvalid)
{
_sawmill.Debug($"Baby jail will deny {userId} for playtime {overallTime!.TimeSpent}"); // Remove on or after 2024-09
}
if (isTotalPlaytimeInvalid && showReason)
{

View File

@@ -32,31 +32,25 @@ namespace Content.Server.Damage.Systems
private void OnDoHit(EntityUid uid, DamageOtherOnHitComponent component, ThrowDoHitEvent args)
{
if (!TerminatingOrDeleted(args.Target))
if (TerminatingOrDeleted(args.Target))
return;
var dmg = _damageable.TryChangeDamage(args.Target, component.Damage, component.IgnoreResistances, origin: args.Component.Thrower);
// Log damage only for mobs. Useful for when people throw spears at each other, but also avoids log-spam when explosions send glass shards flying.
if (dmg != null && HasComp<MobStateComponent>(args.Target))
_adminLogger.Add(LogType.ThrowHit, $"{ToPrettyString(args.Target):target} received {dmg.GetTotal():damage} damage from collision");
if (dmg is { Empty: false })
{
var dmg = _damageable.TryChangeDamage(args.Target, component.Damage, component.IgnoreResistances, origin: args.Component.Thrower);
// Log damage only for mobs. Useful for when people throw spears at each other, but also avoids log-spam when explosions send glass shards flying.
if (dmg != null && HasComp<MobStateComponent>(args.Target))
_adminLogger.Add(LogType.ThrowHit, $"{ToPrettyString(args.Target):target} received {dmg.GetTotal():damage} damage from collision");
if (dmg is { Empty: false })
{
_color.RaiseEffect(Color.Red, new List<EntityUid>() { args.Target }, Filter.Pvs(args.Target, entityManager: EntityManager));
}
_guns.PlayImpactSound(args.Target, dmg, null, false);
if (TryComp<PhysicsComponent>(uid, out var body) && body.LinearVelocity.LengthSquared() > 0f)
{
var direction = body.LinearVelocity.Normalized();
_sharedCameraRecoil.KickCamera(args.Target, direction);
}
_color.RaiseEffect(Color.Red, new List<EntityUid>() { args.Target }, Filter.Pvs(args.Target, entityManager: EntityManager));
}
// TODO: If more stuff touches this then handle it after.
if (TryComp<PhysicsComponent>(uid, out var physics))
_guns.PlayImpactSound(args.Target, dmg, null, false);
if (TryComp<PhysicsComponent>(uid, out var body) && body.LinearVelocity.LengthSquared() > 0f)
{
_thrownItem.LandComponent(args.Thrown, args.Component, physics, false);
var direction = body.LinearVelocity.Normalized();
_sharedCameraRecoil.KickCamera(args.Target, direction);
}
}

View File

@@ -423,11 +423,11 @@ public sealed class NetworkConfiguratorSystem : SharedNetworkConfiguratorSystem
if (Delay(configurator))
return;
if (!targetUid.HasValue || !configurator.ActiveDeviceLink.HasValue || !TryComp(userUid, out ActorComponent? actor) || !AccessCheck(targetUid.Value, userUid, configurator))
if (!targetUid.HasValue || !configurator.ActiveDeviceLink.HasValue || !AccessCheck(targetUid.Value, userUid, configurator))
return;
_uiSystem.OpenUi(configuratorUid, NetworkConfiguratorUiKey.Link, actor.PlayerSession);
_uiSystem.OpenUi(configuratorUid, NetworkConfiguratorUiKey.Link, userUid);
configurator.DeviceLinkTarget = targetUid;

View File

@@ -9,6 +9,7 @@ using Content.Shared.Disposal;
using Content.Shared.Interaction;
using Robust.Server.GameObjects;
using Robust.Shared.Player;
using Robust.Shared.Utility;
namespace Content.Server.Disposal.Mailing;
@@ -35,7 +36,7 @@ public sealed class MailingUnitSystem : EntitySystem
SubscribeLocalEvent<MailingUnitComponent, DeviceNetworkPacketEvent>(OnPacketReceived);
SubscribeLocalEvent<MailingUnitComponent, BeforeDisposalFlushEvent>(OnBeforeFlush);
SubscribeLocalEvent<MailingUnitComponent, ConfigurationSystem.ConfigurationUpdatedEvent>(OnConfigurationUpdated);
SubscribeLocalEvent<MailingUnitComponent, ActivateInWorldEvent>(HandleActivate);
SubscribeLocalEvent<MailingUnitComponent, ActivateInWorldEvent>(HandleActivate, before: new[] { typeof(DisposalUnitSystem) });
SubscribeLocalEvent<MailingUnitComponent, DisposalUnitUIStateUpdatedEvent>(OnDisposalUnitUIStateChange);
SubscribeLocalEvent<MailingUnitComponent, TargetSelectedMessage>(OnTargetSelected);
}
@@ -179,7 +180,7 @@ public sealed class MailingUnitSystem : EntitySystem
if (component.DisposalUnitInterfaceState == null)
return;
var state = new MailingUnitBoundUserInterfaceState(component.DisposalUnitInterfaceState, component.Target, component.TargetList, component.Tag);
var state = new MailingUnitBoundUserInterfaceState(component.DisposalUnitInterfaceState, component.Target, component.TargetList.ShallowClone(), component.Tag);
_userInterfaceSystem.SetUiState(uid, MailingUnitUiKey.Key, state);
}

View File

@@ -16,7 +16,6 @@ namespace Content.Server.Doors.Systems
public sealed class FirelockSystem : SharedFirelockSystem
{
[Dependency] private readonly SharedDoorSystem _doorSystem = default!;
[Dependency] private readonly AtmosAlarmableSystem _atmosAlarmable = default!;
[Dependency] private readonly AtmosphereSystem _atmosSystem = default!;
[Dependency] private readonly SharedAppearanceSystem _appearance = default!;
[Dependency] private readonly SharedMapSystem _mapping = default!;

View File

@@ -24,7 +24,6 @@ public sealed partial class DragonSystem : EntitySystem
[Dependency] private readonly MovementSpeedModifierSystem _movement = default!;
[Dependency] private readonly NpcFactionSystem _faction = default!;
[Dependency] private readonly PopupSystem _popup = default!;
[Dependency] private readonly RoleSystem _role = default!;
[Dependency] private readonly SharedActionsSystem _actions = default!;
[Dependency] private readonly SharedAudioSystem _audio = default!;
[Dependency] private readonly SharedTransformSystem _transform = default!;
@@ -225,7 +224,7 @@ public sealed partial class DragonSystem : EntitySystem
return;
var mind = Comp<MindComponent>(mindContainer.Mind.Value);
foreach (var objId in mind.AllObjectives)
foreach (var objId in mind.Objectives)
{
if (_objQuery.TryGetComponent(objId, out var obj))
{
@@ -247,7 +246,7 @@ public sealed partial class DragonSystem : EntitySystem
return;
var mind = Comp<MindComponent>(mindContainer.Mind.Value);
foreach (var objId in mind.AllObjectives)
foreach (var objId in mind.Objectives)
{
if (_objQuery.TryGetComponent(objId, out var obj))
{

View File

@@ -324,6 +324,13 @@ public sealed partial class GameTicker
foreach (var rule in args)
{
if (!_prototypeManager.HasIndex(rule))
{
shell.WriteError($"Invalid game rule {rule} was skipped.");
continue;
}
if (shell.Player != null)
{
_adminLogger.Add(LogType.EventStarted, $"{shell.Player} tried to add game rule [{rule}] via command");

View File

@@ -13,7 +13,6 @@ public sealed class LoadMapRuleSystem : GameRuleSystem<LoadMapRuleComponent>
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
[Dependency] private readonly MapSystem _map = default!;
[Dependency] private readonly MapLoaderSystem _mapLoader = default!;
[Dependency] private readonly MetaDataSystem _metaData = default!;
[Dependency] private readonly TransformSystem _transform = default!;
[Dependency] private readonly GridPreloaderSystem _gridPreloader = default!;

View File

@@ -21,7 +21,6 @@ public sealed class SecretRuleSystem : GameRuleSystem<SecretRuleComponent>
[Dependency] private readonly IRobustRandom _random = default!;
[Dependency] private readonly IConfigurationManager _configurationManager = default!;
[Dependency] private readonly IAdminLogManager _adminLogger = default!;
[Dependency] private readonly IChatManager _chatManager = default!;
[Dependency] private readonly IComponentFactory _compFact = default!;
private string _ruleCompName = default!;

View File

@@ -12,10 +12,8 @@ namespace Content.Server.GameTicking.Rules;
public sealed class ThiefRuleSystem : GameRuleSystem<ThiefRuleComponent>
{
[Dependency] private readonly IRobustRandom _random = default!;
[Dependency] private readonly MindSystem _mindSystem = default!;
[Dependency] private readonly AntagSelectionSystem _antag = default!;
[Dependency] private readonly ObjectivesSystem _objectives = default!;
public override void Initialize()
{

View File

@@ -29,7 +29,6 @@ public sealed class TraitorRuleSystem : GameRuleSystem<TraitorRuleComponent>
[Dependency] private readonly MindSystem _mindSystem = default!;
[Dependency] private readonly SharedRoleSystem _roleSystem = default!;
[Dependency] private readonly SharedJobSystem _jobs = default!;
[Dependency] private readonly ObjectivesSystem _objectives = default!;
public override void Initialize()
{

View File

@@ -95,7 +95,7 @@ public sealed class RandomGiftSystem : EntitySystem
foreach (var proto in _prototype.EnumeratePrototypes<EntityPrototype>())
{
if (proto.Abstract || proto.NoSpawn || proto.Components.ContainsKey(mapGridCompName) || !proto.Components.ContainsKey(physicsCompName))
if (proto.Abstract || proto.HideSpawnMenu || proto.Components.ContainsKey(mapGridCompName) || !proto.Components.ContainsKey(physicsCompName))
continue;
_possibleGiftsUnsafe.Add(proto.ID);

View File

@@ -0,0 +1,26 @@
using Content.Shared.IconSmoothing;
using Robust.Shared.Random;
namespace Content.Server.IconSmoothing;
public sealed partial class RandomIconSmoothSystem : SharedRandomIconSmoothSystem
{
[Dependency] private readonly IRobustRandom _random = default!;
[Dependency] private readonly SharedAppearanceSystem _appearance = default!;
public override void Initialize()
{
base.Initialize();
SubscribeLocalEvent<RandomIconSmoothComponent, MapInitEvent>(OnMapInit);
}
private void OnMapInit(Entity<RandomIconSmoothComponent> ent, ref MapInitEvent args)
{
if (ent.Comp.RandomStates.Count == 0)
return;
var state = _random.Pick(ent.Comp.RandomStates);
_appearance.SetData(ent, RandomIconSmoothState.State, state);
}
}

View File

@@ -30,7 +30,6 @@ public sealed partial class InstrumentSystem : SharedInstrumentSystem
[Dependency] private readonly UserInterfaceSystem _bui = default!;
[Dependency] private readonly PopupSystem _popup = default!;
[Dependency] private readonly TransformSystem _transform = default!;
[Dependency] private readonly InteractionSystem _interactions = default!;
[Dependency] private readonly ExamineSystemShared _examineSystem = default!;
private const float MaxInstrumentBandRange = 10f;

View File

@@ -79,6 +79,7 @@ namespace Content.Server.Kitchen.EntitySystems
SubscribeLocalEvent<MicrowaveComponent, EntInsertedIntoContainerMessage>(OnContentUpdate);
SubscribeLocalEvent<MicrowaveComponent, EntRemovedFromContainerMessage>(OnContentUpdate);
SubscribeLocalEvent<MicrowaveComponent, InteractUsingEvent>(OnInteractUsing, after: new[] { typeof(AnchorableSystem) });
SubscribeLocalEvent<MicrowaveComponent, ContainerIsInsertingAttemptEvent>(OnInsertAttempt);
SubscribeLocalEvent<MicrowaveComponent, BreakageEventArgs>(OnBreak);
SubscribeLocalEvent<MicrowaveComponent, PowerChangedEvent>(OnPowerChanged);
SubscribeLocalEvent<MicrowaveComponent, AnchorStateChangedEvent>(OnAnchorChanged);
@@ -309,6 +310,32 @@ namespace Content.Server.Kitchen.EntitySystems
UpdateUserInterfaceState(uid, component);
}
private void OnInsertAttempt(Entity<MicrowaveComponent> ent, ref ContainerIsInsertingAttemptEvent args)
{
if (ent.Comp.Broken)
{
args.Cancel();
return;
}
if (TryComp<ItemComponent>(args.EntityUid, out var item))
{
if (_item.GetSizePrototype(item.Size) > _item.GetSizePrototype(ent.Comp.MaxItemSize))
{
args.Cancel();
return;
}
}
else
{
args.Cancel();
return;
}
if (ent.Comp.Storage.Count >= ent.Comp.Capacity)
args.Cancel();
}
private void OnInteractUsing(Entity<MicrowaveComponent> ent, ref InteractUsingEvent args)
{
if (args.Handled)

View File

@@ -46,7 +46,6 @@ public sealed class DefibrillatorSystem : EntitySystem
[Dependency] private readonly PowerCellSystem _powerCell = default!;
[Dependency] private readonly SharedAppearanceSystem _appearance = default!;
[Dependency] private readonly SharedAudioSystem _audio = default!;
[Dependency] private readonly UseDelaySystem _useDelay = default!;
[Dependency] private readonly SharedMindSystem _mind = default!;
/// <inheritdoc/>

View File

@@ -160,9 +160,9 @@ public sealed class HTNPlanJob : Job<HTNPlan>
{
var compound = _protoManager.Index<HTNCompoundPrototype>(compoundId.Task);
for (var i = mtrIndex; i < compound.Branches.Count; i++)
for (; mtrIndex < compound.Branches.Count; mtrIndex++)
{
var branch = compound.Branches[i];
var branch = compound.Branches[mtrIndex];
var isValid = true;
foreach (var con in branch.Preconditions)

View File

@@ -1,7 +1,6 @@
using Content.Server.NPC.Components;
using Content.Shared.CombatMode;
using Content.Shared.Interaction;
using Content.Shared.Physics;
using Content.Shared.Weapons.Ranged.Components;
using Content.Shared.Weapons.Ranged.Events;
using Robust.Shared.Map;
@@ -134,7 +133,7 @@ public sealed partial class NPCCombatSystem
{
comp.LOSAccumulator += UnoccludedCooldown;
// For consistency with NPC steering.
comp.TargetInLOS = _interaction.InRangeUnobstructed(uid, Transform(comp.Target).Coordinates, distance + 0.1f);
comp.TargetInLOS = _interaction.InRangeUnobstructed(uid, comp.Target, distance + 0.1f);
}
if (!comp.TargetInLOS)

View File

@@ -32,10 +32,7 @@ public sealed class SpaceNinjaSystem : SharedSpaceNinjaSystem
[Dependency] private readonly AlertsSystem _alerts = default!;
[Dependency] private readonly BatterySystem _battery = default!;
[Dependency] private readonly CodeConditionSystem _codeCondition = default!;
[Dependency] private readonly IChatManager _chatMan = default!;
[Dependency] private readonly PowerCellSystem _powerCell = default!;
[Dependency] private readonly RoleSystem _role = default!;
[Dependency] private readonly SharedAudioSystem _audio = default!;
[Dependency] private readonly SharedMindSystem _mind = default!;
public override void Initialize()

View File

@@ -10,7 +10,6 @@ using Content.Shared.Administration.Logs;
using Content.Shared.Body.Components;
using Content.Shared.Body.Organ;
using Content.Shared.Chemistry;
using Content.Shared.Chemistry.Reagent;
using Content.Shared.Database;
using Content.Shared.DoAfter;
using Content.Shared.FixedPoint;
@@ -31,6 +30,7 @@ using Robust.Shared.Audio;
using Robust.Shared.Audio.Systems;
using Robust.Shared.Utility;
using System.Linq;
using Content.Shared.Containers.ItemSlots;
using Robust.Server.GameObjects;
using Content.Shared.Whitelist;
@@ -138,6 +138,16 @@ public sealed class FoodSystem : EntitySystem
return (false, true);
}
// Checks for used item slots
if (TryComp<ItemSlotsComponent>(food, out var itemSlots))
{
if (itemSlots.Slots.Any(slot => slot.Value.HasItem))
{
_popup.PopupEntity(Loc.GetString("food-has-used-storage", ("food", food)), user, user);
return (false, true);
}
}
var flavors = _flavorProfile.GetLocalizedFlavorsMessage(food, user, foodSolution);
if (GetUsesRemaining(food, foodComp) <= 0)

View File

@@ -17,7 +17,6 @@ namespace Content.Server.Nutrition.EntitySystems
{
[Dependency] private readonly SolutionContainerSystem _solutionContainerSystem = default!;
[Dependency] private readonly SharedAudioSystem _audio = default!;
[Dependency] private readonly SharedContainerSystem _containerSystem = default!;
[Dependency] private readonly TransformSystem _xformSystem = default!;
public override void Initialize()

View File

@@ -33,7 +33,7 @@ namespace Content.Server.Objectives.Commands
}
shell.WriteLine($"Objectives for player {player.UserId}:");
var objectives = mind.AllObjectives.ToList();
var objectives = mind.Objectives.ToList();
if (objectives.Count == 0)
{
shell.WriteLine("None.");

View File

@@ -129,12 +129,12 @@ public sealed class ObjectivesSystem : SharedObjectivesSystem
var agentSummary = new StringBuilder();
agentSummary.AppendLine(Loc.GetString("objectives-with-objectives", ("custody", custody), ("title", title), ("agent", agent)));
foreach (var objectiveGroup in objectives.GroupBy(o => Comp<ObjectiveComponent>(o).Issuer))
foreach (var objectiveGroup in objectives.GroupBy(o => Comp<ObjectiveComponent>(o).LocIssuer))
{
//TO DO:
//check for the right group here. Getting the target issuer is easy: objectiveGroup.Key
//It should be compared to the type of the group's issuer.
agentSummary.AppendLine(Loc.GetString($"objective-issuer-{objectiveGroup.Key}"));
agentSummary.AppendLine(objectiveGroup.Key);
foreach (var objective in objectiveGroup)
{

View File

@@ -59,7 +59,7 @@ public sealed class HelpProgressConditionSystem : EntitySystem
if (!TryComp<MindComponent>(traitor, out var mind))
continue;
foreach (var objective in mind.AllObjectives)
foreach (var objective in mind.Objectives)
{
if (HasComp<HelpProgressConditionComponent>(objective))
removeList.Add(traitor);
@@ -88,7 +88,7 @@ public sealed class HelpProgressConditionSystem : EntitySystem
if (TryComp<MindComponent>(target, out var mind))
{
foreach (var objective in mind.AllObjectives)
foreach (var objective in mind.Objectives)
{
// this has the potential to loop forever, anything setting target has to check that there is no HelpProgressCondition.
var info = _objectives.GetInfo(objective, target, mind);

View File

@@ -23,7 +23,7 @@ public sealed class ObjectiveBlacklistRequirementSystem : EntitySystem
if (args.Cancelled)
return;
foreach (var objective in args.Mind.AllObjectives)
foreach (var objective in args.Mind.Objectives)
{
if (_whitelistSystem.IsBlacklistPass(comp.Blacklist, objective))
{

View File

@@ -35,7 +35,6 @@ public sealed class PlayTimeTrackingSystem : EntitySystem
[Dependency] private readonly MindSystem _minds = default!;
[Dependency] private readonly PlayTimeTrackingManager _tracking = default!;
[Dependency] private readonly IAdminManager _adminManager = default!;
[Dependency] private readonly SharedRoleSystem _role = default!;
public override void Initialize()
{

View File

@@ -152,9 +152,7 @@ namespace Content.Server.Pointing.EntitySystems
if (TryComp<PointingArrowComponent>(arrow, out var pointing))
{
if (TryComp(player, out TransformComponent? xformPlayer))
pointing.StartPosition = _transform.ToCoordinates((player, xformPlayer), _transform.ToMapCoordinates(xformPlayer.Coordinates)).Position;
pointing.StartPosition = _transform.ToCoordinates((arrow, Transform(arrow)), _transform.ToMapCoordinates(Transform(player).Coordinates)).Position;
pointing.EndTime = _gameTiming.CurTime + PointDuration;
Dirty(arrow, pointing);

View File

@@ -22,7 +22,6 @@ namespace Content.Server.Power.EntitySystems
[Dependency] private readonly PowerNetConnectorSystem _powerNetConnector = default!;
[Dependency] private readonly IConfigurationManager _cfg = default!;
[Dependency] private readonly IParallelManager _parMan = default!;
[Dependency] private readonly PowerReceiverSystem _powerReceiver = default!;
private readonly PowerState _powerState = new();
private readonly HashSet<PowerNet> _powerNetReconnectQueue = new();

View File

@@ -21,7 +21,6 @@ namespace Content.Server.Power.EntitySystems
{
[Dependency] private readonly IAdminLogManager _adminLogger = default!;
[Dependency] private readonly IAdminManager _adminManager = default!;
[Dependency] private readonly AppearanceSystem _appearance = default!;
[Dependency] private readonly AudioSystem _audio = default!;
private EntityQuery<ApcPowerReceiverComponent> _recQuery;
private EntityQuery<ApcPowerProviderComponent> _provQuery;

View File

@@ -9,7 +9,7 @@ public static class StaticPowerSystem
public static bool IsPowered(this EntitySystem system, EntityUid uid, IEntityManager entManager, ApcPowerReceiverComponent? receiver = null)
{
if (receiver == null && !entManager.TryGetComponent(uid, out receiver))
return false;
return true;
return receiver.Powered;
}

View File

@@ -118,7 +118,7 @@ public sealed partial class DungeonSystem
// go BRRNNTTT on existing stuff
if (clearExisting)
{
var gridBounds = new Box2(Vector2.Transform(Vector2.Zero, roomTransform), Vector2.Transform(room.Size, roomTransform));
var gridBounds = new Box2(Vector2.Transform(-room.Size/2, roomTransform), Vector2.Transform(room.Size/2, roomTransform));
_entitySet.Clear();
// Polygon skin moment
gridBounds = gridBounds.Enlarged(-0.05f);

View File

@@ -33,7 +33,6 @@ public sealed partial class DungeonSystem : SharedDungeonSystem
[Dependency] private readonly AnchorableSystem _anchorable = default!;
[Dependency] private readonly DecalSystem _decals = default!;
[Dependency] private readonly EntityLookupSystem _lookup = default!;
[Dependency] private readonly TagSystem _tag = default!;
[Dependency] private readonly TileSystem _tile = default!;
[Dependency] private readonly MapLoaderSystem _loader = default!;
[Dependency] private readonly SharedMapSystem _maps = default!;

View File

@@ -40,7 +40,6 @@ public sealed partial class BorgSystem : SharedBorgSystem
[Dependency] private readonly IBanManager _banManager = default!;
[Dependency] private readonly IGameTiming _timing = default!;
[Dependency] private readonly IRobustRandom _random = default!;
[Dependency] private readonly SharedAccessSystem _access = default!;
[Dependency] private readonly ActionsSystem _actions = default!;
[Dependency] private readonly AlertsSystem _alerts = default!;
[Dependency] private readonly DeviceNetworkSystem _deviceNetwork = default!;

View File

@@ -17,7 +17,6 @@ public sealed partial class StationJobsSystem
{
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
[Dependency] private readonly IBanManager _banManager = default!;
[Dependency] private readonly PlayTimeTrackingSystem _playTime = default!;
private Dictionary<int, HashSet<string>> _jobsByWeight = default!;
private List<int> _orderedWeights = default!;

View File

@@ -27,10 +27,8 @@ namespace Content.Server.Station.Systems;
[PublicAPI]
public sealed class StationSystem : EntitySystem
{
[Dependency] private readonly IConfigurationManager _cfgManager = default!;
[Dependency] private readonly ILogManager _logManager = default!;
[Dependency] private readonly IPlayerManager _player = default!;
[Dependency] private readonly IRobustRandom _random = default!;
[Dependency] private readonly ChatSystem _chatSystem = default!;
[Dependency] private readonly GameTicker _ticker = default!;
[Dependency] private readonly SharedTransformSystem _transform = default!;

View File

@@ -1,11 +0,0 @@
using Content.Server.StationEvents.Events;
namespace Content.Server.StationEvents.Components;
/// <summary>
/// This is used to keep track of hallucinated entities to remove effects when event ends
/// </summary>
[RegisterComponent, Access(typeof(MassHallucinationsRule))]
public sealed partial class MassHallucinationsComponent : Component
{
}

View File

@@ -1,5 +1,6 @@
using Content.Server.StationEvents.Events;
using Robust.Shared.Audio;
using Robust.Shared.Collections;
namespace Content.Server.StationEvents.Components;
@@ -23,4 +24,7 @@ public sealed partial class MassHallucinationsRuleComponent : Component
[DataField("sounds", required: true)]
public SoundSpecifier Sounds = default!;
[DataField, ViewVariables(VVAccess.ReadOnly)]
public List<EntityUid> AffectedEntities = new();
}

View File

@@ -2,9 +2,11 @@ using Content.Server.GameTicking.Rules.Components;
using Content.Server.StationEvents.Components;
using Content.Server.Traits.Assorted;
using Content.Shared.GameTicking.Components;
using Content.Shared.Humanoid;
using Content.Shared.Mind.Components;
using Content.Shared.Traits.Assorted;
namespace Content.Server.StationEvents.Events;
public sealed class MassHallucinationsRule : StationEventSystem<MassHallucinationsRuleComponent>
@@ -14,16 +16,17 @@ public sealed class MassHallucinationsRule : StationEventSystem<MassHallucinatio
protected override void Started(EntityUid uid, MassHallucinationsRuleComponent component, GameRuleComponent gameRule, GameRuleStartedEvent args)
{
base.Started(uid, component, gameRule, args);
var query = EntityQueryEnumerator<MindContainerComponent>();
while (query.MoveNext(out var ent, out _))
var query = EntityQueryEnumerator<MindContainerComponent, HumanoidAppearanceComponent>();
while (query.MoveNext(out var ent, out _, out _))
{
if (!HasComp<ParacusiaComponent>(ent))
if (!EnsureComp<ParacusiaComponent>(ent, out var paracusia))
{
EnsureComp<MassHallucinationsComponent>(ent);
var paracusia = EnsureComp<ParacusiaComponent>(ent);
_paracusia.SetSounds(ent, component.Sounds, paracusia);
_paracusia.SetTime(ent, component.MinTimeBetweenIncidents, component.MaxTimeBetweenIncidents, paracusia);
_paracusia.SetDistance(ent, component.MaxSoundDistance);
component.AffectedEntities.Add(ent);
}
}
}
@@ -31,10 +34,12 @@ public sealed class MassHallucinationsRule : StationEventSystem<MassHallucinatio
protected override void Ended(EntityUid uid, MassHallucinationsRuleComponent component, GameRuleComponent gameRule, GameRuleEndedEvent args)
{
base.Ended(uid, component, gameRule, args);
var query = EntityQueryEnumerator<MassHallucinationsComponent>();
while (query.MoveNext(out var ent, out _))
foreach (var ent in component.AffectedEntities)
{
RemComp<ParacusiaComponent>(ent);
}
component.AffectedEntities.Clear();
}
}

View File

@@ -11,7 +11,6 @@ namespace Content.Server.Traits;
public sealed class TraitSystem : EntitySystem
{
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
[Dependency] private readonly ISerializationManager _serializationManager = default!;
[Dependency] private readonly SharedHandsSystem _sharedHandsSystem = default!;
[Dependency] private readonly EntityWhitelistSystem _whitelistSystem = default!;

View File

@@ -155,7 +155,12 @@ public sealed class AccessReaderSystem : EntitySystem
return IsAllowedInternal(access, stationKeys, reader);
if (!_containerSystem.TryGetContainer(target, reader.ContainerAccessProvider, out var container))
return Paused(target); // when mapping, containers with electronics arent spawned
return false;
// If entity is paused then always allow it at this point.
// Door electronics is kind of a mess but yeah, it should only be an unpaused ent interacting with it
if (Paused(target))
return true;
foreach (var entity in container.ContainedEntities)
{

View File

@@ -120,7 +120,13 @@ namespace Content.Shared.ActionBlocker
var ev = new ThrowAttemptEvent(user, itemUid);
RaiseLocalEvent(user, ev);
return !ev.Cancelled;
if (ev.Cancelled)
return false;
var itemEv = new ThrowItemAttemptEvent(user);
RaiseLocalEvent(itemUid, ref itemEv);
return !itemEv.Cancelled;
}
public bool CanSpeak(EntityUid uid)

View File

@@ -25,7 +25,6 @@ public abstract class SharedActionsSystem : EntitySystem
[Dependency] private readonly ISharedAdminLogManager _adminLogger = default!;
[Dependency] private readonly SharedInteractionSystem _interactionSystem = default!;
[Dependency] private readonly ActionBlockerSystem _actionBlockerSystem = default!;
[Dependency] private readonly SharedContainerSystem _containerSystem = default!;
[Dependency] private readonly RotateToFaceSystem _rotateToFaceSystem = default!;
[Dependency] private readonly SharedAudioSystem _audio = default!;
[Dependency] private readonly SharedTransformSystem _transformSystem = default!;
@@ -238,7 +237,7 @@ public abstract class SharedActionsSystem : EntitySystem
}
#region ComponentStateManagement
protected virtual void UpdateAction(EntityUid? actionId, BaseActionComponent? action = null)
public virtual void UpdateAction(EntityUid? actionId, BaseActionComponent? action = null)
{
// See client-side code.
}

View File

@@ -1,4 +1,5 @@
using Content.Shared.Random;
using Content.Shared.Random.Rules;
using Robust.Shared.Audio;
using Robust.Shared.Prototypes;
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype;

View File

@@ -12,8 +12,6 @@ namespace Content.Shared.Beeper.Systems;
/// </summary>
public sealed class ProximityBeeperSystem : EntitySystem
{
[Dependency] private readonly SharedAppearanceSystem _appearance = default!;
[Dependency] private readonly ProximityDetectionSystem _proximity = default!;
[Dependency] private readonly BeeperSystem _beeper = default!;
/// <inheritdoc/>

View File

@@ -14,13 +14,10 @@ namespace Content.Shared.Clothing;
public sealed class ClothingSpeedModifierSystem : EntitySystem
{
[Dependency] private readonly SharedAppearanceSystem _appearance = default!;
[Dependency] private readonly ClothingSpeedModifierSystem _clothingSpeedModifier = default!;
[Dependency] private readonly SharedContainerSystem _container = default!;
[Dependency] private readonly ExamineSystemShared _examine = default!;
[Dependency] private readonly MovementSpeedModifierSystem _movementSpeed = default!;
[Dependency] private readonly ItemToggleSystem _toggle = default!;
[Dependency] private readonly SharedPowerCellSystem _powerCell = default!;
public override void Initialize()
{

View File

@@ -78,7 +78,7 @@ public abstract class SharedChameleonClothingSystem : EntitySystem
public bool IsValidTarget(EntityPrototype proto, SlotFlags chameleonSlot = SlotFlags.NONE)
{
// check if entity is valid
if (proto.Abstract || proto.NoSpawn)
if (proto.Abstract || proto.HideSpawnMenu)
return false;
// check if it is marked as valid chameleon target

View File

@@ -192,6 +192,11 @@ public sealed partial class StaminaSystem : EntitySystem
private void OnCollide(EntityUid uid, StaminaDamageOnCollideComponent component, EntityUid target)
{
// you can't inflict stamina damage on things with no stamina component
// this prevents stun batons from using up charges when throwing it at lockers or lights
if (!HasComp<StaminaComponent>(target))
return;
var ev = new StaminaDamageOnHitAttemptEvent();
RaiseLocalEvent(uid, ref ev);
if (ev.Cancelled)

View File

@@ -32,23 +32,23 @@ public sealed class PettableFriendSystem : EntitySystem
{
var (uid, comp) = ent;
var user = args.User;
if (args.Handled || !_exceptionQuery.TryGetComponent(uid, out var exceptionComp))
return;
if (_useDelayQuery.TryGetComponent(uid, out var useDelay) && !_useDelay.TryResetDelay((uid, useDelay), true))
if (args.Handled || !_exceptionQuery.TryComp(uid, out var exceptionComp))
return;
var exception = (uid, exceptionComp);
if (_factionException.IsIgnored(exception, user))
if (!_factionException.IsIgnored(exception, user))
{
_popup.PopupClient(Loc.GetString(comp.FailureString, ("target", uid)), user, user);
// you have made a new friend :)
_popup.PopupClient(Loc.GetString(comp.SuccessString, ("target", uid)), user, user);
_factionException.IgnoreEntity(exception, user);
args.Handled = true;
return;
}
// you have made a new friend :)
_popup.PopupClient(Loc.GetString(comp.SuccessString, ("target", uid)), user, user);
_factionException.IgnoreEntity(exception, user);
args.Handled = true;
if (_useDelayQuery.TryComp(uid, out var useDelay) && !_useDelay.TryResetDelay((uid, useDelay), true))
return;
_popup.PopupClient(Loc.GetString(comp.FailureString, ("target", uid)), user, user);
}
private void OnRehydrated(Entity<PettableFriendComponent> ent, ref GotRehydratedEvent args)

View File

@@ -0,0 +1,16 @@
using Robust.Shared.GameStates;
namespace Content.Shared.IconSmoothing;
/// <summary>
/// Allow randomize StateBase of IconSmoothComponent for random visual variation
/// </summary>
[RegisterComponent, NetworkedComponent]
public sealed partial class RandomIconSmoothComponent : Component
{
/// <summary>
/// StateBase will be randomly selected from this list. Allows to randomize the visual.
/// </summary>
[DataField(required: true)]
public List<string> RandomStates = new();
}

View File

@@ -0,0 +1,12 @@
using Robust.Shared.Serialization;
namespace Content.Shared.IconSmoothing;
public abstract class SharedRandomIconSmoothSystem : EntitySystem
{
}
[Serializable, NetSerializable]
public enum RandomIconSmoothState : byte
{
State
}

View File

@@ -38,8 +38,6 @@ using Robust.Shared.Serialization;
using Robust.Shared.Timing;
using Robust.Shared.Utility;
#pragma warning disable 618
namespace Content.Shared.Interaction
{
/// <summary>
@@ -522,11 +520,11 @@ namespace Content.Shared.Interaction
protected bool ValidateInteractAndFace(EntityUid user, EntityCoordinates coordinates)
{
// Verify user is on the same map as the entity they clicked on
if (coordinates.GetMapId(EntityManager) != Transform(user).MapID)
if (_transform.GetMapId(coordinates) != Transform(user).MapID)
return false;
if (!HasComp<NoRotateOnInteractComponent>(user))
_rotateToFaceSystem.TryFaceCoordinates(user, coordinates.ToMapPos(EntityManager, _transform));
_rotateToFaceSystem.TryFaceCoordinates(user, _transform.ToMapCoordinates(coordinates).Position);
return true;
}
@@ -859,7 +857,7 @@ namespace Content.Shared.Interaction
Ignored? predicate = null,
bool popup = false)
{
return InRangeUnobstructed(origin, other.ToMap(EntityManager, _transform), range, collisionMask, predicate, popup);
return InRangeUnobstructed(origin, _transform.ToMapCoordinates(other), range, collisionMask, predicate, popup);
}
/// <summary>
@@ -966,7 +964,7 @@ namespace Content.Shared.Interaction
/// </summary>
public void InteractDoAfter(EntityUid user, EntityUid used, EntityUid? target, EntityCoordinates clickLocation, bool canReach)
{
if (target is {Valid: false})
if (target is { Valid: false })
target = null;
var afterInteractEvent = new AfterInteractEvent(user, used, target, clickLocation, canReach);

View File

@@ -62,21 +62,22 @@ public sealed class SmartEquipSystem : EntitySystem
if (playerSession.AttachedEntity is not { Valid: true } uid || !Exists(uid))
return;
if (!_actionBlocker.CanInteract(uid, null))
return;
// early out if we don't have any hands or a valid inventory slot
if (!TryComp<HandsComponent>(uid, out var hands) || hands.ActiveHand == null)
return;
var handItem = hands.ActiveHand.HeldEntity;
// can the user interact, and is the item interactable? e.g. virtual items
if (!_actionBlocker.CanInteract(uid, handItem))
return;
if (!TryComp<InventoryComponent>(uid, out var inventory) || !_inventory.HasSlot(uid, equipmentSlot, inventory))
{
_popup.PopupClient(Loc.GetString("smart-equip-missing-equipment-slot", ("slotName", equipmentSlot)), uid, uid);
return;
}
var handItem = hands.ActiveHand.HeldEntity;
// early out if we have an item and cant drop it at all
if (handItem != null && !_hands.CanDropHeld(uid, hands.ActiveHand))
{

View File

@@ -2,6 +2,7 @@ using System.Diagnostics.CodeAnalysis;
using Content.Shared.Hands;
using Content.Shared.Hands.EntitySystems;
using Content.Shared.Interaction;
using Content.Shared.Interaction.Events;
using Content.Shared.Inventory.Events;
using Content.Shared.Item;
using Content.Shared.Popups;
@@ -43,6 +44,7 @@ public abstract class SharedVirtualItemSystem : EntitySystem
SubscribeLocalEvent<VirtualItemComponent, BeingUnequippedAttemptEvent>(OnBeingUnequippedAttempt);
SubscribeLocalEvent<VirtualItemComponent, BeforeRangedInteractEvent>(OnBeforeRangedInteract);
SubscribeLocalEvent<VirtualItemComponent, GettingInteractedWithAttemptEvent>(OnGettingInteractedWithAttemptEvent);
}
/// <summary>
@@ -72,6 +74,12 @@ public abstract class SharedVirtualItemSystem : EntitySystem
args.Handled = true;
}
private void OnGettingInteractedWithAttemptEvent(Entity<VirtualItemComponent> ent, ref GettingInteractedWithAttemptEvent args)
{
// No interactions with a virtual item, please.
args.Cancelled = true;
}
#region Hands
/// <summary>

View File

@@ -370,7 +370,7 @@ public abstract class SharedMindSystem : EntitySystem
if (Resolve(mindId, ref mind))
{
var query = GetEntityQuery<T>();
foreach (var uid in mind.AllObjectives)
foreach (var uid in mind.Objectives)
{
if (query.TryGetComponent(uid, out objective))
{

View File

@@ -43,7 +43,6 @@ public sealed class PullingSystem : EntitySystem
[Dependency] private readonly SharedHandsSystem _handsSystem = default!;
[Dependency] private readonly SharedInteractionSystem _interaction = default!;
[Dependency] private readonly SharedPhysicsSystem _physics = default!;
[Dependency] private readonly SharedPopupSystem _popup = default!;
[Dependency] private readonly HeldSpeedModifierSystem _clothingMoveSpeed = default!;
public override void Initialize()

View File

@@ -18,7 +18,6 @@ public sealed class DashAbilitySystem : EntitySystem
{
[Dependency] private readonly ActionContainerSystem _actionContainer = default!;
[Dependency] private readonly IGameTiming _timing = default!;
[Dependency] private readonly SharedAudioSystem _audio = default!;
[Dependency] private readonly SharedChargesSystem _charges = default!;
[Dependency] private readonly SharedHandsSystem _hands = default!;
[Dependency] private readonly ExamineSystemShared _examine = default!;

View File

@@ -22,8 +22,11 @@ public sealed partial class ObjectiveComponent : Component
/// <summary>
/// Organisation that issued this objective, used for grouping and as a header above common objectives.
/// </summary>
[DataField(required: true)]
public string Issuer = string.Empty;
[DataField("issuer", required: true)]
private LocId Issuer { get; set; }
[ViewVariables(VVAccess.ReadOnly)]
public string LocIssuer => Loc.GetString(Issuer);
/// <summary>
/// Unique objectives can only have 1 per prototype id.

View File

@@ -58,7 +58,7 @@ public enum CollisionGroup
// Tabletop machines, windoors, firelocks
TabletopMachineMask = Impassable | HighImpassable,
// Tabletop machines
TabletopMachineLayer = Opaque | HighImpassable | BulletImpassable,
TabletopMachineLayer = Opaque | BulletImpassable,
// Airlocks, windoors, firelocks
GlassAirlockLayer = HighImpassable | MidImpassable | BulletImpassable | InteractImpassable,

View File

@@ -120,7 +120,10 @@ public abstract partial class SharedProjectileSystem : EntitySystem
if (component.Offset != Vector2.Zero)
{
_transform.SetLocalPosition(uid, xform.LocalPosition + xform.LocalRotation.RotateVec(component.Offset),
var rotation = xform.LocalRotation;
if (TryComp<ThrowingAngleComponent>(uid, out var throwingAngleComp))
rotation += throwingAngleComp.Angle;
_transform.SetLocalPosition(uid, xform.LocalPosition + rotation.RotateVec(component.Offset),
xform);
}

View File

@@ -239,14 +239,14 @@ public sealed partial class EncryptionKeySystem : EntitySystem
{
var msg = Loc.GetString("examine-headset-default-channel",
("prefix", SharedChatSystem.DefaultChannelPrefix),
("channel", defaultChannel),
("channel", proto.LocalizedName),
("color", proto.Color));
examineEvent.PushMarkup(msg);
}
if (HasComp<EncryptionKeyComponent>(examineEvent.Examined))
{
var msg = Loc.GetString("examine-encryption-default-channel",
("channel", defaultChannel),
("channel", proto.LocalizedName),
("color", proto.Color));
examineEvent.PushMarkup(msg);
}

View File

@@ -9,7 +9,7 @@ public sealed partial class RadioChannelPrototype : IPrototype
/// Human-readable name for the channel.
/// </summary>
[DataField("name")]
public string Name { get; private set; } = string.Empty;
public LocId Name { get; private set; } = string.Empty;
[ViewVariables(VVAccess.ReadOnly)]
public string LocalizedName => Loc.GetString(Name);

View File

@@ -0,0 +1,12 @@
namespace Content.Shared.Random.Rules;
/// <summary>
/// Always returns true. Used for fallbacks.
/// </summary>
public sealed partial class AlwaysTrueRule : RulesRule
{
public override bool Check(EntityManager entManager, EntityUid uid)
{
return !Inverted;
}
}

View File

@@ -0,0 +1,39 @@
using System.Numerics;
using Robust.Shared.Map;
namespace Content.Shared.Random.Rules;
/// <summary>
/// Returns true if on a grid or in range of one.
/// </summary>
public sealed partial class GridInRangeRule : RulesRule
{
[DataField]
public float Range = 10f;
public override bool Check(EntityManager entManager, EntityUid uid)
{
if (!entManager.TryGetComponent(uid, out TransformComponent? xform))
{
return false;
}
if (xform.GridUid != null)
{
return !Inverted;
}
var transform = entManager.System<SharedTransformSystem>();
var mapManager = IoCManager.Resolve<IMapManager>();
var worldPos = transform.GetWorldPosition(xform);
var gridRange = new Vector2(Range, Range);
foreach (var _ in mapManager.FindGridsIntersecting(xform.MapID, new Box2(worldPos - gridRange, worldPos + gridRange)))
{
return !Inverted;
}
return false;
}
}

View File

@@ -0,0 +1,18 @@
namespace Content.Shared.Random.Rules;
/// <summary>
/// Returns true if the attached entity is in space.
/// </summary>
public sealed partial class InSpaceRule : RulesRule
{
public override bool Check(EntityManager entManager, EntityUid uid)
{
if (!entManager.TryGetComponent(uid, out TransformComponent? xform) ||
xform.GridUid != null)
{
return Inverted;
}
return !Inverted;
}
}

View File

@@ -0,0 +1,77 @@
using Content.Shared.Access;
using Content.Shared.Access.Components;
using Content.Shared.Access.Systems;
using Robust.Shared.Prototypes;
namespace Content.Shared.Random.Rules;
/// <summary>
/// Checks for an entity nearby with the specified access.
/// </summary>
public sealed partial class NearbyAccessRule : RulesRule
{
// This exists because of door electronics contained inside doors.
/// <summary>
/// Does the access entity need to be anchored.
/// </summary>
[DataField]
public bool Anchored = true;
/// <summary>
/// Count of entities that need to be nearby.
/// </summary>
[DataField]
public int Count = 1;
[DataField(required: true)]
public List<ProtoId<AccessLevelPrototype>> Access = new();
[DataField]
public float Range = 10f;
public override bool Check(EntityManager entManager, EntityUid uid)
{
var xformQuery = entManager.GetEntityQuery<TransformComponent>();
if (!xformQuery.TryGetComponent(uid, out var xform) ||
xform.MapUid == null)
{
return false;
}
var transform = entManager.System<SharedTransformSystem>();
var lookup = entManager.System<EntityLookupSystem>();
var reader = entManager.System<AccessReaderSystem>();
var found = false;
var worldPos = transform.GetWorldPosition(xform, xformQuery);
var count = 0;
// TODO: Update this when we get the callback version
var entities = new HashSet<Entity<AccessReaderComponent>>();
lookup.GetEntitiesInRange(xform.MapID, worldPos, Range, entities);
foreach (var comp in entities)
{
if (!reader.AreAccessTagsAllowed(Access, comp) ||
Anchored &&
(!xformQuery.TryGetComponent(comp, out var compXform) ||
!compXform.Anchored))
{
continue;
}
count++;
if (count < Count)
continue;
found = true;
break;
}
if (!found)
return Inverted;
return !Inverted;
}
}

View File

@@ -0,0 +1,71 @@
using Robust.Shared.Prototypes;
namespace Content.Shared.Random.Rules;
public sealed partial class NearbyComponentsRule : RulesRule
{
/// <summary>
/// Does the entity need to be anchored.
/// </summary>
[DataField]
public bool Anchored;
[DataField]
public int Count;
[DataField(required: true)]
public ComponentRegistry Components = default!;
[DataField]
public float Range = 10f;
public override bool Check(EntityManager entManager, EntityUid uid)
{
var inRange = new HashSet<Entity<IComponent>>();
var xformQuery = entManager.GetEntityQuery<TransformComponent>();
if (!xformQuery.TryGetComponent(uid, out var xform) ||
xform.MapUid == null)
{
return false;
}
var transform = entManager.System<SharedTransformSystem>();
var lookup = entManager.System<EntityLookupSystem>();
var found = false;
var worldPos = transform.GetWorldPosition(xform);
var count = 0;
foreach (var compType in Components.Values)
{
inRange.Clear();
lookup.GetEntitiesInRange(compType.Component.GetType(), xform.MapID, worldPos, Range, inRange);
foreach (var comp in inRange)
{
if (Anchored &&
(!xformQuery.TryGetComponent(comp, out var compXform) ||
!compXform.Anchored))
{
continue;
}
count++;
if (count < Count)
continue;
found = true;
break;
}
if (found)
break;
}
if (!found)
return Inverted;
return !Inverted;
}
}

View File

@@ -0,0 +1,58 @@
using Content.Shared.Whitelist;
namespace Content.Shared.Random.Rules;
/// <summary>
/// Checks for entities matching the whitelist in range.
/// This is more expensive than <see cref="NearbyComponentsRule"/> so prefer that!
/// </summary>
public sealed partial class NearbyEntitiesRule : RulesRule
{
/// <summary>
/// How many of the entity need to be nearby.
/// </summary>
[DataField]
public int Count = 1;
[DataField(required: true)]
public EntityWhitelist Whitelist = new();
[DataField]
public float Range = 10f;
public override bool Check(EntityManager entManager, EntityUid uid)
{
if (!entManager.TryGetComponent(uid, out TransformComponent? xform) ||
xform.MapUid == null)
{
return false;
}
var transform = entManager.System<SharedTransformSystem>();
var lookup = entManager.System<EntityLookupSystem>();
var whitelistSystem = entManager.System<EntityWhitelistSystem>();
var found = false;
var worldPos = transform.GetWorldPosition(xform);
var count = 0;
foreach (var ent in lookup.GetEntitiesInRange(xform.MapID, worldPos, Range))
{
if (whitelistSystem.IsWhitelistFail(Whitelist, ent))
continue;
count++;
if (count < Count)
continue;
found = true;
break;
}
if (!found)
return Inverted;
return !Inverted;
}
}

View File

@@ -0,0 +1,79 @@
using Content.Shared.Maps;
using Robust.Shared.Map;
using Robust.Shared.Map.Components;
using Robust.Shared.Physics.Components;
using Robust.Shared.Prototypes;
namespace Content.Shared.Random.Rules;
public sealed partial class NearbyTilesPercentRule : RulesRule
{
/// <summary>
/// If there are anchored entities on the tile do we ignore the tile.
/// </summary>
[DataField]
public bool IgnoreAnchored;
[DataField(required: true)]
public float Percent;
[DataField(required: true)]
public List<ProtoId<ContentTileDefinition>> Tiles = new();
[DataField]
public float Range = 10f;
public override bool Check(EntityManager entManager, EntityUid uid)
{
if (!entManager.TryGetComponent(uid, out TransformComponent? xform) ||
!entManager.TryGetComponent<MapGridComponent>(xform.GridUid, out var grid))
{
return false;
}
var transform = entManager.System<SharedTransformSystem>();
var tileDef = IoCManager.Resolve<ITileDefinitionManager>();
var physicsQuery = entManager.GetEntityQuery<PhysicsComponent>();
var tileCount = 0;
var matchingTileCount = 0;
foreach (var tile in grid.GetTilesIntersecting(new Circle(transform.GetWorldPosition(xform),
Range)))
{
// Only consider collidable anchored (for reasons some subfloor stuff has physics but non-collidable)
if (IgnoreAnchored)
{
var gridEnum = grid.GetAnchoredEntitiesEnumerator(tile.GridIndices);
var found = false;
while (gridEnum.MoveNext(out var ancUid))
{
if (!physicsQuery.TryGetComponent(ancUid, out var physics) ||
!physics.CanCollide)
{
continue;
}
found = true;
break;
}
if (found)
continue;
}
tileCount++;
if (!Tiles.Contains(tileDef[tile.Tile.TypeId].ID))
continue;
matchingTileCount++;
}
if (tileCount == 0 || matchingTileCount / (float) tileCount < Percent)
return Inverted;
return !Inverted;
}
}

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