diff --git a/Content.Client/Chemistry/UI/InjectorStatusControl.cs b/Content.Client/Chemistry/UI/InjectorStatusControl.cs index 979e9ea645..9cb699330c 100644 --- a/Content.Client/Chemistry/UI/InjectorStatusControl.cs +++ b/Content.Client/Chemistry/UI/InjectorStatusControl.cs @@ -2,6 +2,7 @@ using Content.Client.Message; using Content.Client.Stylesheets; using Content.Shared.Chemistry.Components; using Content.Shared.Chemistry.EntitySystems; +using Content.Shared.FixedPoint; using Robust.Client.UserInterface; using Robust.Client.UserInterface.Controls; using Robust.Shared.Timing; @@ -14,6 +15,10 @@ public sealed class InjectorStatusControl : Control private readonly SharedSolutionContainerSystem _solutionContainers; private readonly RichTextLabel _label; + private FixedPoint2 PrevVolume; + private FixedPoint2 PrevMaxVolume; + private InjectorToggleMode PrevToggleState; + public InjectorStatusControl(Entity parent, SharedSolutionContainerSystem solutionContainers) { _parent = parent; @@ -29,6 +34,16 @@ public sealed class InjectorStatusControl : Control if (!_solutionContainers.TryGetSolution(_parent.Owner, InjectorComponent.SolutionName, out _, out var solution)) return; + // only updates the UI if any of the details are different than they previously were + if (PrevVolume == solution.Volume + && PrevMaxVolume == solution.MaxVolume + && PrevToggleState == _parent.Comp.ToggleState) + return; + + PrevVolume = solution.Volume; + PrevMaxVolume = solution.MaxVolume; + PrevToggleState = _parent.Comp.ToggleState; + // Update current volume and injector state var modeStringLocalized = Loc.GetString(_parent.Comp.ToggleState switch { diff --git a/Content.Client/Chemistry/UI/ReagentDispenserWindow.xaml b/Content.Client/Chemistry/UI/ReagentDispenserWindow.xaml index d9e480f132..3b812ba56b 100644 --- a/Content.Client/Chemistry/UI/ReagentDispenserWindow.xaml +++ b/Content.Client/Chemistry/UI/ReagentDispenserWindow.xaml @@ -32,19 +32,22 @@ StyleClasses="OpenLeft"/> - - - - - - - - - + + + + + + + + + + + + diff --git a/Content.Client/Chemistry/UI/ReagentDispenserWindow.xaml.cs b/Content.Client/Chemistry/UI/ReagentDispenserWindow.xaml.cs index a36cc2fe54..7fcf0191f2 100644 --- a/Content.Client/Chemistry/UI/ReagentDispenserWindow.xaml.cs +++ b/Content.Client/Chemistry/UI/ReagentDispenserWindow.xaml.cs @@ -1,4 +1,3 @@ -using System.Linq; using Content.Client.Stylesheets; using Content.Shared.Chemistry; using Content.Shared.Chemistry.Reagent; @@ -19,6 +18,7 @@ namespace Content.Client.Chemistry.UI public sealed partial class ReagentDispenserWindow : DefaultWindow { [Dependency] private readonly IPrototypeManager _prototypeManager = default!; + [Dependency] private readonly IEntityManager _entityManager = default!; public event Action? OnDispenseReagentButtonPressed; public event Action? OnDispenseReagentButtonMouseEntered; public event Action? OnDispenseReagentButtonMouseExited; @@ -52,7 +52,7 @@ namespace Content.Client.Chemistry.UI /// Update the button grid of reagents which can be dispensed. /// /// Reagents which can be dispensed by this dispenser - public void UpdateReagentsList(List>> inventory) + public void UpdateReagentsList(List>> inventory) { if (ChemicalList == null) return; @@ -86,6 +86,9 @@ namespace Content.Client.Chemistry.UI UpdateContainerInfo(castState); UpdateReagentsList(castState.Inventory); + _entityManager.TryGetEntity(castState.OutputContainerEntity, out var outputContainerEnt); + View.SetEntity(outputContainerEnt); + // Disable the Clear & Eject button if no beaker ClearButton.Disabled = castState.OutputContainer is null; EjectButton.Disabled = castState.OutputContainer is null; @@ -134,7 +137,7 @@ namespace Content.Client.Chemistry.UI if (state.OutputContainer is null) { - ContainerInfo.Children.Add(new Label {Text = Loc.GetString("reagent-dispenser-window-no-container-loaded-text") }); + ContainerInfo.Children.Add(new Label { Text = Loc.GetString("reagent-dispenser-window-no-container-loaded-text") }); return; } @@ -159,11 +162,11 @@ namespace Content.Client.Chemistry.UI ? p.LocalizedName : Loc.GetString("reagent-dispenser-window-reagent-name-not-found-text"); - var nameLabel = new Label {Text = $"{localizedName}: "}; + var nameLabel = new Label { Text = $"{localizedName}: " }; var quantityLabel = new Label { Text = Loc.GetString("reagent-dispenser-window-quantity-label-text", ("quantity", quantity)), - StyleClasses = {StyleNano.StyleClassLabelSecondaryColor}, + StyleClasses = { StyleNano.StyleClassLabelSecondaryColor }, }; ContainerInfo.Children.Add(new BoxContainer diff --git a/Content.Client/Content.Client.csproj b/Content.Client/Content.Client.csproj index 1780cf8016..125bbac00d 100644 --- a/Content.Client/Content.Client.csproj +++ b/Content.Client/Content.Client.csproj @@ -2,7 +2,7 @@ $(TargetFramework) - 11 + 12 false false ..\bin\Content.Client\ diff --git a/Content.Client/CrewManifest/UI/CrewManifestListing.cs b/Content.Client/CrewManifest/UI/CrewManifestListing.cs index 614add536e..03d8b7168f 100644 --- a/Content.Client/CrewManifest/UI/CrewManifestListing.cs +++ b/Content.Client/CrewManifest/UI/CrewManifestListing.cs @@ -1,18 +1,14 @@ -using Content.Shared.CCVar; -using Content.Shared.CrewManifest; +using Content.Shared.CrewManifest; using Content.Shared.Roles; using Robust.Client.GameObjects; using Robust.Client.UserInterface.Controls; -using Robust.Shared.Configuration; using Robust.Shared.Prototypes; using Robust.Shared.Utility; -using System.Linq; namespace Content.Client.CrewManifest.UI; public sealed class CrewManifestListing : BoxContainer { - [Dependency] private readonly IConfigurationManager _configManager = default!; [Dependency] private readonly IEntitySystemManager _entitySystem = default!; [Dependency] private readonly IPrototypeManager _prototypeManager = default!; private readonly SpriteSystem _spriteSystem; @@ -25,7 +21,7 @@ public sealed class CrewManifestListing : BoxContainer public void AddCrewManifestEntries(CrewManifestEntries entries) { - var entryDict = new Dictionary>(); + var entryDict = new Dictionary>(); foreach (var entry in entries.Entries) { @@ -34,37 +30,19 @@ public sealed class CrewManifestListing : BoxContainer // this is a little expensive, and could be better if (department.Roles.Contains(entry.JobPrototype)) { - entryDict.GetOrNew(department.ID).Add(entry); + entryDict.GetOrNew(department).Add(entry); } } } - var entryList = new List<(string section, List entries)>(); + var entryList = new List<(DepartmentPrototype section, List entries)>(); foreach (var (section, listing) in entryDict) { entryList.Add((section, listing)); } - var sortOrder = _configManager.GetCVar(CCVars.CrewManifestOrdering).Split(",").ToList(); - - entryList.Sort((a, b) => - { - var ai = sortOrder.IndexOf(a.section); - var bi = sortOrder.IndexOf(b.section); - - // this is up here so -1 == -1 occurs first - if (ai == bi) - return 0; - - if (ai == -1) - return -1; - - if (bi == -1) - return 1; - - return ai.CompareTo(bi); - }); + entryList.Sort((a, b) => DepartmentUIComparer.Instance.Compare(a.section, b.section)); foreach (var item in entryList) { diff --git a/Content.Client/CrewManifest/UI/CrewManifestSection.cs b/Content.Client/CrewManifest/UI/CrewManifestSection.cs index 9b51b5d424..4b1b02cb75 100644 --- a/Content.Client/CrewManifest/UI/CrewManifestSection.cs +++ b/Content.Client/CrewManifest/UI/CrewManifestSection.cs @@ -4,24 +4,25 @@ using Robust.Client.GameObjects; using Robust.Client.UserInterface.Controls; using Robust.Shared.Prototypes; using System.Numerics; +using Content.Shared.Roles; namespace Content.Client.CrewManifest.UI; public sealed class CrewManifestSection : BoxContainer { - public CrewManifestSection(IPrototypeManager prototypeManager, SpriteSystem spriteSystem, string sectionTitle, + public CrewManifestSection( + IPrototypeManager prototypeManager, + SpriteSystem spriteSystem, + DepartmentPrototype section, List entries) { Orientation = LayoutOrientation.Vertical; HorizontalExpand = true; - if (Loc.TryGetString($"department-{sectionTitle}", out var localizedDepart)) - sectionTitle = localizedDepart; - AddChild(new Label() { StyleClasses = { "LabelBig" }, - Text = Loc.GetString(sectionTitle) + Text = Loc.GetString($"department-{section.ID}") }); var gridContainer = new GridContainer() @@ -55,8 +56,9 @@ public sealed class CrewManifestSection : BoxContainer var icon = new TextureRect() { TextureScale = new Vector2(2, 2), - Stretch = TextureRect.StretchMode.KeepCentered, + VerticalAlignment = VAlignment.Center, Texture = spriteSystem.Frame0(jobIcon.Icon), + Margin = new Thickness(0, 0, 4, 0) }; titleContainer.AddChild(icon); diff --git a/Content.Client/Decals/DecalSystem.cs b/Content.Client/Decals/DecalSystem.cs index be442ab8a0..901ab270fb 100644 --- a/Content.Client/Decals/DecalSystem.cs +++ b/Content.Client/Decals/DecalSystem.cs @@ -50,16 +50,8 @@ namespace Content.Client.Decals protected override void OnDecalRemoved(EntityUid gridId, uint decalId, DecalGridComponent component, Vector2i indices, DecalChunk chunk) { base.OnDecalRemoved(gridId, decalId, component, indices, chunk); - - if (!component.DecalZIndexIndex.Remove(decalId, out var zIndex)) - return; - - if (!component.DecalRenderIndex.TryGetValue(zIndex, out var renderIndex)) - return; - - renderIndex.Remove(decalId); - if (renderIndex.Count == 0) - component.DecalRenderIndex.Remove(zIndex); + DebugTools.Assert(chunk.Decals.ContainsKey(decalId)); + chunk.Decals.Remove(decalId); } private void OnHandleState(EntityUid gridUid, DecalGridComponent gridComp, ref ComponentHandleState args) @@ -133,8 +125,6 @@ namespace Content.Client.Decals private void UpdateChunks(EntityUid gridId, DecalGridComponent gridComp, Dictionary updatedGridChunks) { var chunkCollection = gridComp.ChunkCollection.ChunkCollection; - var renderIndex = gridComp.DecalRenderIndex; - var zIndexIndex = gridComp.DecalZIndexIndex; // Update any existing data / remove decals we didn't receive data for. foreach (var (indices, newChunkData) in updatedGridChunks) @@ -155,11 +145,6 @@ namespace Content.Client.Decals foreach (var (uid, decal) in newChunkData.Decals) { - if (zIndexIndex.TryGetValue(uid, out var zIndex)) - renderIndex[zIndex].Remove(uid); - - renderIndex.GetOrNew(decal.ZIndex)[uid] = decal; - zIndexIndex[uid] = decal.ZIndex; gridComp.DecalIndex[uid] = indices; } } diff --git a/Content.Client/Decals/Overlays/DecalOverlay.cs b/Content.Client/Decals/Overlays/DecalOverlay.cs index 8eb1a25664..d9904ae80b 100644 --- a/Content.Client/Decals/Overlays/DecalOverlay.cs +++ b/Content.Client/Decals/Overlays/DecalOverlay.cs @@ -3,6 +3,7 @@ using Robust.Client.GameObjects; using Robust.Client.Graphics; using Robust.Shared.Enums; using Robust.Shared.Map; +using Robust.Shared.Map.Enumerators; using Robust.Shared.Prototypes; namespace Content.Client.Decals.Overlays @@ -15,6 +16,8 @@ namespace Content.Client.Decals.Overlays private readonly Dictionary _cachedTextures = new(64); + private readonly List<(uint Id, Decal Decal)> _decals = new(); + public DecalOverlay( SpriteSystem sprites, IEntityManager entManager, @@ -30,10 +33,10 @@ namespace Content.Client.Decals.Overlays if (args.MapId == MapId.Nullspace) return; - var grid = Grid; + var owner = Grid.Owner; - if (!_entManager.TryGetComponent(grid, out DecalGridComponent? decalGrid) || - !_entManager.TryGetComponent(grid, out TransformComponent? xform)) + if (!_entManager.TryGetComponent(owner, out DecalGridComponent? decalGrid) || + !_entManager.TryGetComponent(owner, out TransformComponent? xform)) { return; } @@ -46,46 +49,68 @@ namespace Content.Client.Decals.Overlays var xformSystem = _entManager.System(); var eyeAngle = args.Viewport.Eye?.Rotation ?? Angle.Zero; - var zIndexDictionary = decalGrid.DecalRenderIndex; + var gridAABB = xformSystem.GetInvWorldMatrix(xform).TransformBox(args.WorldBounds.Enlarged(1f)); + var chunkEnumerator = new ChunkIndicesEnumerator(gridAABB, SharedDecalSystem.ChunkSize); + _decals.Clear(); - if (zIndexDictionary.Count == 0) + while (chunkEnumerator.MoveNext(out var index)) + { + if (!decalGrid.ChunkCollection.ChunkCollection.TryGetValue(index.Value, out var chunk)) + continue; + + foreach (var (id, decal) in chunk.Decals) + { + if (!gridAABB.Contains(decal.Coordinates)) + continue; + + _decals.Add((id, decal)); + } + } + + if (_decals.Count == 0) return; - var (_, worldRot, worldMatrix) = xformSystem.GetWorldPositionRotationMatrix(xform); + _decals.Sort((x, y) => + { + var zComp = x.Decal.ZIndex.CompareTo(y.Decal.ZIndex); + if (zComp != 0) + return zComp; + + return x.Id.CompareTo(y.Id); + }); + + var (_, worldRot, worldMatrix) = xformSystem.GetWorldPositionRotationMatrix(xform); handle.SetTransform(worldMatrix); - foreach (var decals in zIndexDictionary.Values) + foreach (var (_, decal) in _decals) { - foreach (var decal in decals.Values) + if (!_cachedTextures.TryGetValue(decal.Id, out var cache)) { - if (!_cachedTextures.TryGetValue(decal.Id, out var cache)) + // Nothing to cache someone messed up + if (!_prototypeManager.TryIndex(decal.Id, out var decalProto)) { - // Nothing to cache someone messed up - if (!_prototypeManager.TryIndex(decal.Id, out var decalProto)) - { - continue; - } - - cache = (_sprites.Frame0(decalProto.Sprite), decalProto.SnapCardinals); - _cachedTextures[decal.Id] = cache; + continue; } - var cardinal = Angle.Zero; - - if (cache.SnapCardinals) - { - var worldAngle = eyeAngle + worldRot; - cardinal = worldAngle.GetCardinalDir().ToAngle(); - } - - var angle = decal.Angle - cardinal; - - if (angle.Equals(Angle.Zero)) - handle.DrawTexture(cache.Texture, decal.Coordinates, decal.Color); - else - handle.DrawTexture(cache.Texture, decal.Coordinates, angle, decal.Color); + cache = (_sprites.Frame0(decalProto.Sprite), decalProto.SnapCardinals); + _cachedTextures[decal.Id] = cache; } + + var cardinal = Angle.Zero; + + if (cache.SnapCardinals) + { + var worldAngle = eyeAngle + worldRot; + cardinal = worldAngle.GetCardinalDir().ToAngle(); + } + + var angle = decal.Angle - cardinal; + + if (angle.Equals(Angle.Zero)) + handle.DrawTexture(cache.Texture, decal.Coordinates, decal.Color); + else + handle.DrawTexture(cache.Texture, decal.Coordinates, angle, decal.Color); } handle.SetTransform(Matrix3.Identity); diff --git a/Content.Client/Doors/AirlockSystem.cs b/Content.Client/Doors/AirlockSystem.cs index 4837adf460..58c8730643 100644 --- a/Content.Client/Doors/AirlockSystem.cs +++ b/Content.Client/Doors/AirlockSystem.cs @@ -1,7 +1,6 @@ using Content.Client.Wires.Visualizers; using Content.Shared.Doors.Components; using Content.Shared.Doors.Systems; -using Content.Shared.Prying.Components; using Robust.Client.Animations; using Robust.Client.GameObjects; @@ -16,13 +15,6 @@ public sealed class AirlockSystem : SharedAirlockSystem base.Initialize(); SubscribeLocalEvent(OnComponentStartup); SubscribeLocalEvent(OnAppearanceChange); - SubscribeLocalEvent(OnAirlockPryAttempt); - } - - private void OnAirlockPryAttempt(EntityUid uid, AirlockComponent component, ref BeforePryEvent args) - { - // TODO: Temporary until airlocks predicted. - args.Cancelled = true; } private void OnComponentStartup(EntityUid uid, AirlockComponent comp, ComponentStartup args) @@ -104,7 +96,7 @@ public sealed class AirlockSystem : SharedAirlockSystem || state == DoorState.Denying || (state == DoorState.Open && comp.OpenUnlitVisible) || (_appearanceSystem.TryGetData(uid, DoorVisuals.ClosedLights, out var closedLights, args.Component) && closedLights)) - && !boltedVisible && !emergencyLightsVisible; ; + && !boltedVisible && !emergencyLightsVisible; } args.Sprite.LayerSetVisible(DoorVisualLayers.BaseUnlit, unlitVisible); @@ -120,5 +112,17 @@ public sealed class AirlockSystem : SharedAirlockSystem && !boltedVisible ); } + + switch (state) + { + case DoorState.Open: + args.Sprite.LayerSetState(DoorVisualLayers.BaseUnlit, comp.ClosingSpriteState); + args.Sprite.LayerSetAnimationTime(DoorVisualLayers.BaseUnlit, 0); + break; + case DoorState.Closed: + args.Sprite.LayerSetState(DoorVisualLayers.BaseUnlit, comp.OpeningSpriteState); + args.Sprite.LayerSetAnimationTime(DoorVisualLayers.BaseUnlit, 0); + break; + } } } diff --git a/Content.Client/Doors/DoorBoltSystem.cs b/Content.Client/Doors/DoorBoltSystem.cs deleted file mode 100644 index 58144cd6e0..0000000000 --- a/Content.Client/Doors/DoorBoltSystem.cs +++ /dev/null @@ -1,12 +0,0 @@ -using Content.Client.Wires.Visualizers; -using Content.Shared.Doors.Components; -using Content.Shared.Doors.Systems; -using Robust.Client.Animations; -using Robust.Client.GameObjects; - -namespace Content.Client.Doors; - -public sealed class DoorBoltSystem : SharedDoorBoltSystem -{ - // Instantiate sub-class on client for prediction. -} diff --git a/Content.Client/Doors/DoorSystem.cs b/Content.Client/Doors/DoorSystem.cs index 80ce47e0c2..473ae97059 100644 --- a/Content.Client/Doors/DoorSystem.cs +++ b/Content.Client/Doors/DoorSystem.cs @@ -3,8 +3,6 @@ using Content.Shared.Doors.Systems; using Robust.Client.Animations; using Robust.Client.GameObjects; using Robust.Client.ResourceManagement; -using Robust.Shared.Audio; -using Robust.Shared.Player; using Robust.Shared.Serialization.TypeSerializers.Implementations; using Robust.Shared.Timing; @@ -73,7 +71,7 @@ public sealed class DoorSystem : SharedDoorSystem private void OnAppearanceChange(EntityUid uid, DoorComponent comp, ref AppearanceChangeEvent args) { - if (args.Sprite == null || !_gameTiming.IsFirstTimePredicted) + if (args.Sprite == null) return; if(!AppearanceSystem.TryGetData(uid, DoorVisuals.State, out var state, args.Component)) @@ -83,9 +81,9 @@ public sealed class DoorSystem : SharedDoorSystem { if (!_resourceCache.TryGetResource(SpriteSpecifierSerializer.TextureRoot / baseRsi, out var res)) { - Logger.Error("Unable to load RSI '{0}'. Trace:\n{1}", baseRsi, Environment.StackTrace); + Log.Error("Unable to load RSI '{0}'. Trace:\n{1}", baseRsi, Environment.StackTrace); } - foreach (ISpriteLayer layer in args.Sprite.AllLayers) + foreach (var layer in args.Sprite.AllLayers) { layer.Rsi = res?.RSI; } @@ -113,31 +111,24 @@ public sealed class DoorSystem : SharedDoorSystem break; case DoorState.Opening: if (animPlayer != null && comp.OpeningAnimationTime != 0.0) - _animationSystem.Play(uid, animPlayer, (Animation)comp.OpeningAnimation, DoorComponent.AnimationKey); + _animationSystem.Play((uid, animPlayer), (Animation)comp.OpeningAnimation, DoorComponent.AnimationKey); break; case DoorState.Closing: if (animPlayer != null && comp.ClosingAnimationTime != 0.0 && comp.CurrentlyCrushing.Count == 0) - _animationSystem.Play(uid, animPlayer, (Animation)comp.ClosingAnimation, DoorComponent.AnimationKey); + _animationSystem.Play((uid, animPlayer), (Animation)comp.ClosingAnimation, DoorComponent.AnimationKey); break; case DoorState.Denying: - if (animPlayer != null && comp.DenyingAnimation != default) - _animationSystem.Play(uid, animPlayer, (Animation)comp.DenyingAnimation, DoorComponent.AnimationKey); + if (animPlayer != null) + _animationSystem.Play((uid, animPlayer), (Animation)comp.DenyingAnimation, DoorComponent.AnimationKey); break; case DoorState.Welded: break; case DoorState.Emagging: - if (animPlayer != null && comp.EmaggingAnimation != default) - _animationSystem.Play(uid, animPlayer, (Animation)comp.EmaggingAnimation, DoorComponent.AnimationKey); + if (animPlayer != null) + _animationSystem.Play((uid, animPlayer), (Animation)comp.EmaggingAnimation, DoorComponent.AnimationKey); break; default: throw new ArgumentOutOfRangeException($"Invalid door visual state {state}"); } } - - // TODO AUDIO PREDICT see comments in server-side PlaySound() - protected override void PlaySound(EntityUid uid, SoundSpecifier soundSpecifier, AudioParams audioParams, EntityUid? predictingPlayer, bool predicted) - { - if (GameTiming.InPrediction && GameTiming.IsFirstTimePredicted) - Audio.PlayEntity(soundSpecifier, Filter.Local(), uid, false, audioParams); - } } diff --git a/Content.Client/LateJoin/LateJoinGui.cs b/Content.Client/LateJoin/LateJoinGui.cs index 65efd2944b..50347bbf64 100644 --- a/Content.Client/LateJoin/LateJoinGui.cs +++ b/Content.Client/LateJoin/LateJoinGui.cs @@ -1,3 +1,4 @@ +using System.Linq; using System.Numerics; using Content.Client.CrewManifest; using Content.Client.GameTicking.Managers; @@ -159,8 +160,10 @@ namespace Content.Client.LateJoin }; var firstCategory = true; + var departments = _prototypeManager.EnumeratePrototypes().ToArray(); + Array.Sort(departments, DepartmentUIComparer.Instance); - foreach (var department in _prototypeManager.EnumeratePrototypes()) + foreach (var department in departments) { var departmentName = Loc.GetString($"department-{department.ID}"); _jobCategories[id] = new Dictionary(); @@ -176,7 +179,7 @@ namespace Content.Client.LateJoin jobsAvailable.Add(_prototypeManager.Index(jobId)); } - jobsAvailable.Sort((x, y) => -string.Compare(x.LocalizedName, y.LocalizedName, StringComparison.CurrentCultureIgnoreCase)); + jobsAvailable.Sort(JobUIComparer.Instance); // Do not display departments with no jobs available. if (jobsAvailable.Count == 0) @@ -231,7 +234,7 @@ namespace Content.Client.LateJoin var icon = new TextureRect { TextureScale = new Vector2(2, 2), - Stretch = TextureRect.StretchMode.KeepCentered + VerticalAlignment = VAlignment.Center }; var jobIcon = _prototypeManager.Index(prototype.Icon); diff --git a/Content.Client/Medical/CrewMonitoring/CrewMonitoringWindow.xaml.cs b/Content.Client/Medical/CrewMonitoring/CrewMonitoringWindow.xaml.cs index d8c87899db..645243b0a3 100644 --- a/Content.Client/Medical/CrewMonitoring/CrewMonitoringWindow.xaml.cs +++ b/Content.Client/Medical/CrewMonitoring/CrewMonitoringWindow.xaml.cs @@ -265,7 +265,7 @@ public sealed partial class CrewMonitoringWindow : FancyWindow var jobIcon = new TextureRect() { TextureScale = new Vector2(2f, 2f), - Stretch = TextureRect.StretchMode.KeepCentered, + VerticalAlignment = VAlignment.Center, Texture = _spriteSystem.Frame0(proto.Icon), Margin = new Thickness(5, 0, 5, 0), }; diff --git a/Content.Client/Nutrition/EntitySystems/OpenableSystem.cs b/Content.Client/Nutrition/EntitySystems/OpenableSystem.cs new file mode 100644 index 0000000000..f8c3f7c447 --- /dev/null +++ b/Content.Client/Nutrition/EntitySystems/OpenableSystem.cs @@ -0,0 +1,7 @@ +using Content.Shared.Nutrition.EntitySystems; + +namespace Content.Client.Nutrition.EntitySystems; + +public sealed class OpenableSystem : SharedOpenableSystem +{ +} diff --git a/Content.Client/Preferences/ClientPreferencesManager.cs b/Content.Client/Preferences/ClientPreferencesManager.cs index 557c9aef70..3e71c97d1e 100644 --- a/Content.Client/Preferences/ClientPreferencesManager.cs +++ b/Content.Client/Preferences/ClientPreferencesManager.cs @@ -4,8 +4,10 @@ using System.Linq; using Content.Corvax.Interfaces.Client; using Content.Shared.Preferences; using Robust.Client; +using Robust.Shared.Configuration; using Robust.Shared.IoC; using Robust.Shared.Network; +using Robust.Shared.Prototypes; using Robust.Shared.Utility; namespace Content.Client.Preferences @@ -19,6 +21,8 @@ namespace Content.Client.Preferences { [Dependency] private readonly IClientNetManager _netManager = default!; [Dependency] private readonly IBaseClient _baseClient = default!; + [Dependency] private readonly IConfigurationManager _cfg = default!; + [Dependency] private readonly IPrototypeManager _prototypes = default!; private IClientSponsorsManager? _sponsorsManager; // Corvax-Sponsors public event Action? OnServerDataLoaded; @@ -65,7 +69,7 @@ namespace Content.Client.Preferences { // Corvax-Sponsors-Start var sponsorPrototypes = _sponsorsManager?.Prototypes.ToArray() ?? new string[]{}; - profile.EnsureValid(sponsorPrototypes); + profile.EnsureValid(_cfg, _prototypes, sponsorPrototypes); // Corvax-Sponsors-End var characters = new Dictionary(Preferences.Characters) {[slot] = profile}; Preferences = new PlayerPreferences(characters, Preferences.SelectedCharacterIndex, Preferences.AdminOOCColor); diff --git a/Content.Client/Preferences/UI/HumanoidProfileEditor.xaml.cs b/Content.Client/Preferences/UI/HumanoidProfileEditor.xaml.cs index c133a617b7..01d7bb6c95 100644 --- a/Content.Client/Preferences/UI/HumanoidProfileEditor.xaml.cs +++ b/Content.Client/Preferences/UI/HumanoidProfileEditor.xaml.cs @@ -553,10 +553,8 @@ namespace Content.Client.Preferences.UI _jobCategories.Clear(); var firstCategory = true; - var departments = _prototypeManager.EnumeratePrototypes() - .OrderByDescending(department => department.Weight) - .ThenBy(department => Loc.GetString($"department-{department.ID}")) - .ToList(); + var departments = _prototypeManager.EnumeratePrototypes().ToArray(); + Array.Sort(departments, DepartmentUIComparer.Instance); foreach (var department in departments) { @@ -604,9 +602,8 @@ namespace Content.Client.Preferences.UI var jobs = department.Roles.Select(jobId => _prototypeManager.Index(jobId)) .Where(job => job.SetPreference) - .OrderByDescending(job => job.Weight) - .ThenBy(job => job.LocalizedName) - .ToList(); + .ToArray(); + Array.Sort(jobs, JobUIComparer.Instance); foreach (var job in jobs) { @@ -1339,7 +1336,7 @@ namespace Content.Client.Preferences.UI var icon = new TextureRect { TextureScale = new Vector2(2, 2), - Stretch = TextureRect.StretchMode.KeepCentered + VerticalAlignment = VAlignment.Center }; var jobIcon = protoMan.Index(proto.Icon); icon.Texture = jobIcon.Icon.Frame0(); diff --git a/Content.Client/UserInterface/Systems/Storage/StorageUIController.cs b/Content.Client/UserInterface/Systems/Storage/StorageUIController.cs index c83a80b4a5..5f3ae3a2da 100644 --- a/Content.Client/UserInterface/Systems/Storage/StorageUIController.cs +++ b/Content.Client/UserInterface/Systems/Storage/StorageUIController.cs @@ -233,6 +233,8 @@ public sealed class StorageUIController : UIController, IOnSystemChanged..\bin\Content.IntegrationTests\ false false - 11 + 12 diff --git a/Content.IntegrationTests/Tests/PostMapInitTest.cs b/Content.IntegrationTests/Tests/PostMapInitTest.cs index 29761b1c3b..d254d7f0e4 100644 --- a/Content.IntegrationTests/Tests/PostMapInitTest.cs +++ b/Content.IntegrationTests/Tests/PostMapInitTest.cs @@ -239,25 +239,13 @@ namespace Content.IntegrationTests.Tests if (entManager.HasComponent(station)) { - // Test that the map has valid latejoin spawn points + // Test that the map has valid latejoin spawn points or container spawn points if (!NoSpawnMaps.Contains(mapProto)) { var lateSpawns = 0; - var query = entManager.AllEntityQueryEnumerator(); - while (query.MoveNext(out var uid, out var comp)) - { - if (comp.SpawnType != SpawnPointType.LateJoin - || !xformQuery.TryGetComponent(uid, out var xform) - || xform.GridUid == null - || !gridUids.Contains(xform.GridUid.Value)) - { - continue; - } - - lateSpawns++; - break; - } + lateSpawns += GetCountLateSpawn(gridUids, entManager); + lateSpawns += GetCountLateSpawn(gridUids, entManager); Assert.That(lateSpawns, Is.GreaterThan(0), $"Found no latejoin spawn points on {mapProto}"); } @@ -296,6 +284,32 @@ namespace Content.IntegrationTests.Tests await pair.CleanReturnAsync(); } + + + private static int GetCountLateSpawn(List gridUids, IEntityManager entManager) + where T : ISpawnPoint, IComponent + { + var resultCount = 0; + var queryPoint = entManager.AllEntityQueryEnumerator(); +#nullable enable + while (queryPoint.MoveNext(out T? comp, out var xform)) + { + var spawner = (ISpawnPoint) comp; + + if (spawner.SpawnType is not SpawnPointType.LateJoin + || xform.GridUid == null + || !gridUids.Contains(xform.GridUid.Value)) + { + continue; + } +#nullable disable + resultCount++; + break; + } + + return resultCount; + } + [Test] public async Task AllMapsTested() { diff --git a/Content.Replay/Content.Replay.csproj b/Content.Replay/Content.Replay.csproj index 4b3c85345c..9785870143 100644 --- a/Content.Replay/Content.Replay.csproj +++ b/Content.Replay/Content.Replay.csproj @@ -1,7 +1,7 @@ $(TargetFramework) - 10 + 12 false false ..\bin\Content.Replay\ diff --git a/Content.Server.Database/Content.Server.Database.csproj b/Content.Server.Database/Content.Server.Database.csproj index 31ab785c18..d98d0642db 100644 --- a/Content.Server.Database/Content.Server.Database.csproj +++ b/Content.Server.Database/Content.Server.Database.csproj @@ -2,7 +2,7 @@ $(TargetFramework) - 11 + 12 false false ..\bin\Content.Server.Database\ diff --git a/Content.Server/Administration/Systems/AdminVerbSystem.Tools.cs b/Content.Server/Administration/Systems/AdminVerbSystem.Tools.cs index 296e48274c..c68336deab 100644 --- a/Content.Server/Administration/Systems/AdminVerbSystem.Tools.cs +++ b/Content.Server/Administration/Systems/AdminVerbSystem.Tools.cs @@ -41,7 +41,7 @@ namespace Content.Server.Administration.Systems; public sealed partial class AdminVerbSystem { - [Dependency] private readonly DoorBoltSystem _boltsSystem = default!; + [Dependency] private readonly DoorSystem _door = default!; [Dependency] private readonly AirlockSystem _airlockSystem = default!; [Dependency] private readonly StackSystem _stackSystem = default!; [Dependency] private readonly SharedAccessSystem _accessSystem = default!; @@ -78,7 +78,7 @@ public sealed partial class AdminVerbSystem : new SpriteSpecifier.Texture(new("/Textures/Interface/AdminActions/bolt.png")), Act = () => { - _boltsSystem.SetBoltsWithAudio(args.Target, bolts, !bolts.BoltsDown); + _door.SetBoltsDown((args.Target, bolts), !bolts.BoltsDown); }, Impact = LogImpact.Medium, Message = Loc.GetString(bolts.BoltsDown diff --git a/Content.Server/Anomaly/AnomalySystem.Generator.cs b/Content.Server/Anomaly/AnomalySystem.Generator.cs index d07740e2f6..2053a7bbbe 100644 --- a/Content.Server/Anomaly/AnomalySystem.Generator.cs +++ b/Content.Server/Anomaly/AnomalySystem.Generator.cs @@ -33,9 +33,7 @@ public sealed partial class AnomalySystem SubscribeLocalEvent(OnGeneratorMaterialAmountChanged); SubscribeLocalEvent(OnGenerateButtonPressed); SubscribeLocalEvent(OnGeneratorPowerChanged); - SubscribeLocalEvent(OnGeneratorUnpaused); SubscribeLocalEvent(OnGeneratingStartup); - SubscribeLocalEvent(OnGeneratingUnpaused); } private void OnGeneratorPowerChanged(EntityUid uid, AnomalyGeneratorComponent component, ref PowerChangedEvent args) @@ -58,11 +56,6 @@ public sealed partial class AnomalySystem TryGeneratorCreateAnomaly(uid, component); } - private void OnGeneratorUnpaused(EntityUid uid, AnomalyGeneratorComponent component, ref EntityUnpausedEvent args) - { - component.CooldownEndTime += args.PausedTime; - } - public void UpdateGeneratorUi(EntityUid uid, AnomalyGeneratorComponent component) { var materialAmount = _material.GetMaterialAmount(uid, component.RequiredMaterial); @@ -169,11 +162,6 @@ public sealed partial class AnomalySystem Appearance.SetData(uid, AnomalyGeneratorVisuals.Generating, true); } - private void OnGeneratingUnpaused(EntityUid uid, GeneratingAnomalyGeneratorComponent component, ref EntityUnpausedEvent args) - { - component.EndTime += args.PausedTime; - } - private void OnGeneratingFinished(EntityUid uid, AnomalyGeneratorComponent component) { var xform = Transform(uid); diff --git a/Content.Server/Anomaly/AnomalySystem.Vessel.cs b/Content.Server/Anomaly/AnomalySystem.Vessel.cs index 7c7feacb87..98e56a8844 100644 --- a/Content.Server/Anomaly/AnomalySystem.Vessel.cs +++ b/Content.Server/Anomaly/AnomalySystem.Vessel.cs @@ -22,7 +22,6 @@ public sealed partial class AnomalySystem SubscribeLocalEvent(OnVesselInteractUsing); SubscribeLocalEvent(OnExamined); SubscribeLocalEvent(OnVesselGetPointsPerSecond); - SubscribeLocalEvent(OnUnpaused); SubscribeLocalEvent(OnShutdown); SubscribeLocalEvent(OnStabilityChanged); } @@ -92,11 +91,6 @@ public sealed partial class AnomalySystem args.Points += (int) (GetAnomalyPointValue(anomaly) * component.PointMultiplier); } - private void OnUnpaused(EntityUid uid, AnomalyVesselComponent component, ref EntityUnpausedEvent args) - { - component.NextBeep += args.PausedTime; - } - private void OnVesselAnomalyShutdown(ref AnomalyShutdownEvent args) { var query = EntityQueryEnumerator(); diff --git a/Content.Server/Anomaly/Components/AnomalyGeneratorComponent.cs b/Content.Server/Anomaly/Components/AnomalyGeneratorComponent.cs index 1ff0290fc9..d4acfc6150 100644 --- a/Content.Server/Anomaly/Components/AnomalyGeneratorComponent.cs +++ b/Content.Server/Anomaly/Components/AnomalyGeneratorComponent.cs @@ -12,13 +12,14 @@ namespace Content.Server.Anomaly.Components; /// This is used for a machine that is able to generate /// anomalies randomly on the station. /// -[RegisterComponent, Access(typeof(SharedAnomalySystem))] +[RegisterComponent, Access(typeof(SharedAnomalySystem)), AutoGenerateComponentPause] public sealed partial class AnomalyGeneratorComponent : Component { /// /// The time at which the cooldown for generating another anomaly will be over /// [DataField("cooldownEndTime", customTypeSerializer: typeof(TimeOffsetSerializer)), ViewVariables(VVAccess.ReadWrite)] + [AutoPausedField] public TimeSpan CooldownEndTime = TimeSpan.Zero; /// diff --git a/Content.Server/Anomaly/Components/AnomalyVesselComponent.cs b/Content.Server/Anomaly/Components/AnomalyVesselComponent.cs index 74c5e3e9ed..1225cbf116 100644 --- a/Content.Server/Anomaly/Components/AnomalyVesselComponent.cs +++ b/Content.Server/Anomaly/Components/AnomalyVesselComponent.cs @@ -10,7 +10,7 @@ namespace Content.Server.Anomaly.Components; /// they generate points for the selected server based on /// the anomaly's stability and severity. /// -[RegisterComponent, Access(typeof(SharedAnomalySystem))] +[RegisterComponent, Access(typeof(SharedAnomalySystem)), AutoGenerateComponentPause] public sealed partial class AnomalyVesselComponent : Component { /// @@ -42,6 +42,7 @@ public sealed partial class AnomalyVesselComponent : Component /// When the next beep sound will play /// [DataField("nextBeep", customTypeSerializer:typeof(TimeOffsetSerializer))] + [AutoPausedField] public TimeSpan NextBeep = TimeSpan.Zero; /// diff --git a/Content.Server/Anomaly/Components/GeneratingAnomalyGeneratorComponent.cs b/Content.Server/Anomaly/Components/GeneratingAnomalyGeneratorComponent.cs index 4233bfd7e1..ef93e8c699 100644 --- a/Content.Server/Anomaly/Components/GeneratingAnomalyGeneratorComponent.cs +++ b/Content.Server/Anomaly/Components/GeneratingAnomalyGeneratorComponent.cs @@ -4,13 +4,14 @@ using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom; namespace Content.Server.Anomaly.Components; -[RegisterComponent, Access(typeof(SharedAnomalySystem))] +[RegisterComponent, Access(typeof(SharedAnomalySystem)), AutoGenerateComponentPause] public sealed partial class GeneratingAnomalyGeneratorComponent : Component { /// /// When the generating period will end. /// [DataField("endTime", customTypeSerializer: typeof(TimeOffsetSerializer))] + [AutoPausedField] public TimeSpan EndTime = TimeSpan.Zero; public EntityUid? AudioStream; diff --git a/Content.Server/Atmos/Rotting/RottingSystem.cs b/Content.Server/Atmos/Rotting/RottingSystem.cs index e3389def66..47bac84e0c 100644 --- a/Content.Server/Atmos/Rotting/RottingSystem.cs +++ b/Content.Server/Atmos/Rotting/RottingSystem.cs @@ -29,11 +29,9 @@ public sealed class RottingSystem : SharedRottingSystem base.Initialize(); SubscribeLocalEvent(OnPerishableMapInit); - SubscribeLocalEvent(OnPerishableUnpaused); SubscribeLocalEvent(OnMobStateChanged); SubscribeLocalEvent(OnPerishableExamined); - SubscribeLocalEvent(OnRottingUnpaused); SubscribeLocalEvent(OnShutdown); SubscribeLocalEvent(OnRottingMobStateChanged); SubscribeLocalEvent(OnGibbed); @@ -47,11 +45,6 @@ public sealed class RottingSystem : SharedRottingSystem component.RotNextUpdate = _timing.CurTime + component.PerishUpdateRate; } - private void OnPerishableUnpaused(EntityUid uid, PerishableComponent component, ref EntityUnpausedEvent args) - { - component.RotNextUpdate += args.PausedTime; - } - private void OnMobStateChanged(EntityUid uid, PerishableComponent component, MobStateChangedEvent args) { if (args.NewMobState != MobState.Dead && args.OldMobState != MobState.Dead) @@ -64,11 +57,6 @@ public sealed class RottingSystem : SharedRottingSystem component.RotNextUpdate = _timing.CurTime + component.PerishUpdateRate; } - private void OnRottingUnpaused(EntityUid uid, RottingComponent component, ref EntityUnpausedEvent args) - { - component.NextRotUpdate += args.PausedTime; - } - private void OnShutdown(EntityUid uid, RottingComponent component, ComponentShutdown args) { if (TryComp(uid, out var perishable)) diff --git a/Content.Server/Cargo/Systems/CargoSystem.Orders.cs b/Content.Server/Cargo/Systems/CargoSystem.Orders.cs index a4daeb8c2d..5ecba41133 100644 --- a/Content.Server/Cargo/Systems/CargoSystem.Orders.cs +++ b/Content.Server/Cargo/Systems/CargoSystem.Orders.cs @@ -209,15 +209,19 @@ namespace Content.Server.Cargo.Systems _random.Shuffle(tradePads); var freePads = GetFreeCargoPallets(trade, tradePads); - - foreach (var pad in freePads) + if (freePads.Count >= order.OrderQuantity) //check if the station has enough free pallets { - var coordinates = new EntityCoordinates(trade, pad.Transform.LocalPosition); - - if (FulfillOrder(order, coordinates, orderDatabase.PrinterOutput)) + foreach (var pad in freePads) { - tradeDestination = trade; - break; + var coordinates = new EntityCoordinates(trade, pad.Transform.LocalPosition); + + if (FulfillOrder(order, coordinates, orderDatabase.PrinterOutput)) + { + tradeDestination = trade; + order.NumDispatched++; + if (order.OrderQuantity <= order.NumDispatched) //Spawn a crate on free pellets until the order is fulfilled. + break; + } } } diff --git a/Content.Server/Cargo/Systems/CargoSystem.Shuttle.cs b/Content.Server/Cargo/Systems/CargoSystem.Shuttle.cs index 8a661c8896..98ab633f4d 100644 --- a/Content.Server/Cargo/Systems/CargoSystem.Shuttle.cs +++ b/Content.Server/Cargo/Systems/CargoSystem.Shuttle.cs @@ -196,12 +196,14 @@ public sealed partial class CargoSystem return _pads; } - private IEnumerable<(EntityUid Entity, CargoPalletComponent Component, TransformComponent Transform)> + private List<(EntityUid Entity, CargoPalletComponent Component, TransformComponent Transform)> GetFreeCargoPallets(EntityUid gridUid, List<(EntityUid Entity, CargoPalletComponent Component, TransformComponent Transform)> pallets) { _setEnts.Clear(); + List<(EntityUid Entity, CargoPalletComponent Component, TransformComponent Transform)> outList = new(); + foreach (var pallet in pallets) { var aabb = _lookup.GetAABBNoContainer(pallet.Entity, pallet.Transform.LocalPosition, pallet.Transform.LocalRotation); @@ -209,8 +211,10 @@ public sealed partial class CargoSystem if (_lookup.AnyLocalEntitiesIntersecting(gridUid, aabb, LookupFlags.Dynamic)) continue; - yield return pallet; + outList.Add(pallet); } + + return outList; } #endregion diff --git a/Content.Server/Charges/Components/AutoRechargeComponent.cs b/Content.Server/Charges/Components/AutoRechargeComponent.cs index e23f0229bb..9dcf555ea9 100644 --- a/Content.Server/Charges/Components/AutoRechargeComponent.cs +++ b/Content.Server/Charges/Components/AutoRechargeComponent.cs @@ -7,7 +7,7 @@ namespace Content.Server.Charges.Components; /// Something with limited charges that can be recharged automatically. /// Requires LimitedChargesComponent to function. /// -[RegisterComponent] +[RegisterComponent, AutoGenerateComponentPause] [Access(typeof(ChargesSystem))] public sealed partial class AutoRechargeComponent : Component { @@ -21,5 +21,6 @@ public sealed partial class AutoRechargeComponent : Component /// The time when the next charge will be added /// [DataField("nextChargeTime", customTypeSerializer: typeof(TimeOffsetSerializer))] + [AutoPausedField] public TimeSpan NextChargeTime; } diff --git a/Content.Server/Charges/Systems/ChargesSystem.cs b/Content.Server/Charges/Systems/ChargesSystem.cs index 82758f4653..03e192e680 100644 --- a/Content.Server/Charges/Systems/ChargesSystem.cs +++ b/Content.Server/Charges/Systems/ChargesSystem.cs @@ -10,13 +10,6 @@ public sealed class ChargesSystem : SharedChargesSystem { [Dependency] private readonly IGameTiming _timing = default!; - public override void Initialize() - { - base.Initialize(); - - SubscribeLocalEvent(OnUnpaused); - } - public override void Update(float frameTime) { base.Update(frameTime); @@ -32,11 +25,6 @@ public sealed class ChargesSystem : SharedChargesSystem } } - private void OnUnpaused(EntityUid uid, AutoRechargeComponent comp, ref EntityUnpausedEvent args) - { - comp.NextChargeTime += args.PausedTime; - } - protected override void OnExamine(EntityUid uid, LimitedChargesComponent comp, ExaminedEvent args) { base.OnExamine(uid, comp, args); diff --git a/Content.Server/Chat/EmoteOnDamageComponent.cs b/Content.Server/Chat/EmoteOnDamageComponent.cs index 91eddef215..8653a4fe55 100644 --- a/Content.Server/Chat/EmoteOnDamageComponent.cs +++ b/Content.Server/Chat/EmoteOnDamageComponent.cs @@ -8,7 +8,7 @@ using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototy /// /// Causes an entity to automatically emote when taking damage. /// -[RegisterComponent, Access(typeof(EmoteOnDamageSystem))] +[RegisterComponent, Access(typeof(EmoteOnDamageSystem)), AutoGenerateComponentPause] public sealed partial class EmoteOnDamageComponent : Component { /// @@ -41,6 +41,7 @@ public sealed partial class EmoteOnDamageComponent : Component /// The simulation time of the last emote preformed due to taking damage. /// [DataField("lastEmoteTime", customTypeSerializer: typeof(TimeOffsetSerializer)), ViewVariables(VVAccess.ReadWrite)] + [AutoPausedField] public TimeSpan LastEmoteTime = TimeSpan.Zero; /// diff --git a/Content.Server/Chat/Systems/EmoteOnDamageSystem.cs b/Content.Server/Chat/Systems/EmoteOnDamageSystem.cs index 9a435971f2..878c517d92 100644 --- a/Content.Server/Chat/Systems/EmoteOnDamageSystem.cs +++ b/Content.Server/Chat/Systems/EmoteOnDamageSystem.cs @@ -18,15 +18,9 @@ public sealed class EmoteOnDamageSystem : EntitySystem { base.Initialize(); - SubscribeLocalEvent(OnUnpaused); SubscribeLocalEvent(OnDamage); } - private void OnUnpaused(EntityUid uid, EmoteOnDamageComponent emoteOnDamage, ref EntityUnpausedEvent args) - { - emoteOnDamage.LastEmoteTime += args.PausedTime; - } - private void OnDamage(EntityUid uid, EmoteOnDamageComponent emoteOnDamage, DamageChangedEvent args) { if (!args.DamageIncreased) diff --git a/Content.Server/Chemistry/Components/SolutionPurgeComponent.cs b/Content.Server/Chemistry/Components/SolutionPurgeComponent.cs index 0525542b96..9b9294b6f9 100644 --- a/Content.Server/Chemistry/Components/SolutionPurgeComponent.cs +++ b/Content.Server/Chemistry/Components/SolutionPurgeComponent.cs @@ -9,7 +9,7 @@ namespace Content.Server.Chemistry.Components; /// /// Passively decreases a solution's quantity of reagent(s). /// -[RegisterComponent] +[RegisterComponent, AutoGenerateComponentPause] [Access(typeof(SolutionPurgeSystem))] public sealed partial class SolutionPurgeComponent : Component { @@ -42,5 +42,6 @@ public sealed partial class SolutionPurgeComponent : Component /// The time when the next purge will occur. /// [DataField("nextPurgeTime", customTypeSerializer: typeof(TimeOffsetSerializer)), ViewVariables(VVAccess.ReadWrite)] + [AutoPausedField] public TimeSpan NextPurgeTime = TimeSpan.FromSeconds(0); } diff --git a/Content.Server/Chemistry/Components/SolutionRegenerationComponent.cs b/Content.Server/Chemistry/Components/SolutionRegenerationComponent.cs index 7fe2dacb67..23bf6b2157 100644 --- a/Content.Server/Chemistry/Components/SolutionRegenerationComponent.cs +++ b/Content.Server/Chemistry/Components/SolutionRegenerationComponent.cs @@ -7,7 +7,7 @@ namespace Content.Server.Chemistry.Components; /// /// Passively increases a solution's quantity of a reagent. /// -[RegisterComponent] +[RegisterComponent, AutoGenerateComponentPause] [Access(typeof(SolutionRegenerationSystem))] public sealed partial class SolutionRegenerationComponent : Component { @@ -39,5 +39,6 @@ public sealed partial class SolutionRegenerationComponent : Component /// The time when the next regeneration will occur. /// [DataField("nextChargeTime", customTypeSerializer: typeof(TimeOffsetSerializer)), ViewVariables(VVAccess.ReadWrite)] + [AutoPausedField] public TimeSpan NextRegenTime = TimeSpan.FromSeconds(0); } diff --git a/Content.Server/Chemistry/EntitySystems/ReagentDispenserSystem.cs b/Content.Server/Chemistry/EntitySystems/ReagentDispenserSystem.cs index d5ec310f87..7a09d16265 100644 --- a/Content.Server/Chemistry/EntitySystems/ReagentDispenserSystem.cs +++ b/Content.Server/Chemistry/EntitySystems/ReagentDispenserSystem.cs @@ -68,7 +68,7 @@ namespace Content.Server.Chemistry.EntitySystems var inventory = GetInventory(reagentDispenser); - var state = new ReagentDispenserBoundUserInterfaceState(outputContainerInfo, inventory, reagentDispenser.Comp.DispenseAmount); + var state = new ReagentDispenserBoundUserInterfaceState(outputContainerInfo, GetNetEntity(outputContainer), inventory, reagentDispenser.Comp.DispenseAmount); _userInterfaceSystem.TrySetUiState(reagentDispenser, ReagentDispenserUiKey.Key, state); } diff --git a/Content.Server/Chemistry/EntitySystems/SolutionPurgeSystem.cs b/Content.Server/Chemistry/EntitySystems/SolutionPurgeSystem.cs index e6e003a7f5..42b8ab374a 100644 --- a/Content.Server/Chemistry/EntitySystems/SolutionPurgeSystem.cs +++ b/Content.Server/Chemistry/EntitySystems/SolutionPurgeSystem.cs @@ -10,13 +10,6 @@ public sealed class SolutionPurgeSystem : EntitySystem [Dependency] private readonly SolutionContainerSystem _solutionContainer = default!; [Dependency] private readonly IGameTiming _timing = default!; - public override void Initialize() - { - base.Initialize(); - - SubscribeLocalEvent(OnUnpaused); - } - public override void Update(float frameTime) { base.Update(frameTime); @@ -33,9 +26,4 @@ public sealed class SolutionPurgeSystem : EntitySystem _solutionContainer.SplitSolutionWithout(solution.Value, purge.Quantity, purge.Preserve.ToArray()); } } - - private void OnUnpaused(Entity entity, ref EntityUnpausedEvent args) - { - entity.Comp.NextPurgeTime += args.PausedTime; - } } diff --git a/Content.Server/Chemistry/EntitySystems/SolutionRegenerationSystem.cs b/Content.Server/Chemistry/EntitySystems/SolutionRegenerationSystem.cs index 37458846e3..5af181e4af 100644 --- a/Content.Server/Chemistry/EntitySystems/SolutionRegenerationSystem.cs +++ b/Content.Server/Chemistry/EntitySystems/SolutionRegenerationSystem.cs @@ -12,13 +12,6 @@ public sealed class SolutionRegenerationSystem : EntitySystem [Dependency] private readonly SolutionContainerSystem _solutionContainer = default!; [Dependency] private readonly IGameTiming _timing = default!; - public override void Initialize() - { - base.Initialize(); - - SubscribeLocalEvent(OnUnpaused); - } - public override void Update(float frameTime) { base.Update(frameTime); @@ -52,9 +45,4 @@ public sealed class SolutionRegenerationSystem : EntitySystem } } } - - private void OnUnpaused(Entity entity, ref EntityUnpausedEvent args) - { - entity.Comp.NextRegenTime += args.PausedTime; - } } diff --git a/Content.Server/Chunking/ChunkingSystem.cs b/Content.Server/Chunking/ChunkingSystem.cs index e4775439cb..9bc1ab0a3b 100644 --- a/Content.Server/Chunking/ChunkingSystem.cs +++ b/Content.Server/Chunking/ChunkingSystem.cs @@ -8,6 +8,7 @@ using Robust.Shared.Map; using Robust.Shared.Map.Components; using Robust.Shared.Player; using Robust.Shared.Utility; +using ChunkIndicesEnumerator = Robust.Shared.Map.Enumerators.ChunkIndicesEnumerator; namespace Content.Shared.Chunking; diff --git a/Content.Server/Connection/ConnectionManager.cs b/Content.Server/Connection/ConnectionManager.cs index b6cf093bf5..8941924f8c 100644 --- a/Content.Server/Connection/ConnectionManager.cs +++ b/Content.Server/Connection/ConnectionManager.cs @@ -114,7 +114,7 @@ namespace Content.Server.Connection // Corvax-Start: Allow privileged players bypass bunker var isPrivileged = await HavePrivilegedJoin(e.UserId); - if (_cfg.GetCVar(CCVars.PanicBunkerEnabled) && !isPrivileged) + if (_cfg.GetCVar(CCVars.PanicBunkerEnabled) && adminData == null && !isPrivileged) // Corvax-End { var showReason = _cfg.GetCVar(CCVars.PanicBunkerShowReason); @@ -236,13 +236,11 @@ namespace Content.Server.Connection // Corvax-Queue-Start: Make these conditions in one place, for checks in the connection and in the queue public async Task HavePrivilegedJoin(NetUserId userId) { - var isAdmin = await _dbManager.GetAdminDataForAsync(userId) != null; var havePriorityJoin = _sponsorsMgr != null && _sponsorsMgr.HavePriorityJoin(userId); // Corvax-Sponsors var wasInGame = EntitySystem.TryGet(out var ticker) && ticker.PlayerGameStatuses.TryGetValue(userId, out var status) && status == PlayerGameStatus.JoinedGame; - return isAdmin || - havePriorityJoin || // Corvax-Sponsors + return havePriorityJoin || // Corvax-Sponsors wasInGame; } // Corvax-Queue-End diff --git a/Content.Server/Content.Server.csproj b/Content.Server/Content.Server.csproj index 40376944fe..320196ea0f 100644 --- a/Content.Server/Content.Server.csproj +++ b/Content.Server/Content.Server.csproj @@ -2,7 +2,7 @@ $(TargetFramework) - 11 + 12 false false ..\bin\Content.Server\ diff --git a/Content.Server/CrewManifest/CrewManifestSystem.cs b/Content.Server/CrewManifest/CrewManifestSystem.cs index 12b6984b5a..8b4cbac5c1 100644 --- a/Content.Server/CrewManifest/CrewManifestSystem.cs +++ b/Content.Server/CrewManifest/CrewManifestSystem.cs @@ -9,10 +9,12 @@ using Content.Shared.Administration; using Content.Shared.CCVar; using Content.Shared.CrewManifest; using Content.Shared.GameTicking; +using Content.Shared.Roles; using Content.Shared.StationRecords; using Robust.Shared.Configuration; using Robust.Shared.Console; using Robust.Shared.Player; +using Robust.Shared.Prototypes; using Robust.Shared.Utility; namespace Content.Server.CrewManifest; @@ -23,6 +25,7 @@ public sealed class CrewManifestSystem : EntitySystem [Dependency] private readonly StationRecordsSystem _recordsSystem = default!; [Dependency] private readonly EuiManager _euiManager = default!; [Dependency] private readonly IConfigurationManager _configManager = default!; + [Dependency] private readonly IPrototypeManager _prototypeManager = default!; /// /// Cached crew manifest entries. The alternative is to outright @@ -223,15 +226,26 @@ public sealed class CrewManifestSystem : EntitySystem var entries = new CrewManifestEntries(); + var entriesSort = new List<(JobPrototype? job, CrewManifestEntry entry)>(); foreach (var recordObject in iter) { var record = recordObject.Item2; var entry = new CrewManifestEntry(record.Name, record.JobTitle, record.JobIcon, record.JobPrototype); - entries.Entries.Add(entry); + _prototypeManager.TryIndex(record.JobPrototype, out JobPrototype? job); + entriesSort.Add((job, entry)); } - entries.Entries = entries.Entries.OrderBy(e => e.JobTitle).ThenBy(e => e.Name).ToList(); + entriesSort.Sort((a, b) => + { + var cmp = JobUIComparer.Instance.Compare(a.job, b.job); + if (cmp != 0) + return cmp; + + return string.Compare(a.entry.Name, b.entry.Name, StringComparison.CurrentCultureIgnoreCase); + }); + + entries.Entries = entriesSort.Select(x => x.entry).ToArray(); _cachedEntries[station] = entries; } } diff --git a/Content.Server/Decals/DecalSystem.cs b/Content.Server/Decals/DecalSystem.cs index 5bfd91486c..ad225afe22 100644 --- a/Content.Server/Decals/DecalSystem.cs +++ b/Content.Server/Decals/DecalSystem.cs @@ -21,6 +21,7 @@ using Robust.Shared.Threading; using Robust.Shared.Timing; using Robust.Shared.Utility; using static Content.Shared.Decals.DecalGridComponent; +using ChunkIndicesEnumerator = Robust.Shared.Map.Enumerators.ChunkIndicesEnumerator; namespace Content.Server.Decals { diff --git a/Content.Server/DeviceLinking/Systems/DoorSignalControlSystem.cs b/Content.Server/DeviceLinking/Systems/DoorSignalControlSystem.cs index 1c0c9713cf..fab9a306ae 100644 --- a/Content.Server/DeviceLinking/Systems/DoorSignalControlSystem.cs +++ b/Content.Server/DeviceLinking/Systems/DoorSignalControlSystem.cs @@ -12,7 +12,6 @@ namespace Content.Server.DeviceLinking.Systems [UsedImplicitly] public sealed class DoorSignalControlSystem : EntitySystem { - [Dependency] private readonly DoorBoltSystem _bolts = default!; [Dependency] private readonly DoorSystem _doorSystem = default!; [Dependency] private readonly DeviceLinkSystem _signalSystem = default!; @@ -79,7 +78,7 @@ namespace Content.Server.DeviceLinking.Systems bolt = state == SignalState.High; } - _bolts.SetBoltsWithAudio(uid, bolts, bolt); + _doorSystem.SetBoltsDown((uid, bolts), bolt); } } diff --git a/Content.Server/Disposal/Unit/EntitySystems/DisposalUnitSystem.cs b/Content.Server/Disposal/Unit/EntitySystems/DisposalUnitSystem.cs index 35b2afc2e0..6938792315 100644 --- a/Content.Server/Disposal/Unit/EntitySystems/DisposalUnitSystem.cs +++ b/Content.Server/Disposal/Unit/EntitySystems/DisposalUnitSystem.cs @@ -68,7 +68,6 @@ public sealed class DisposalUnitSystem : SharedDisposalUnitSystem // Shouldn't need re-anchoring. SubscribeLocalEvent(OnAnchorChanged); - SubscribeLocalEvent(OnUnpaused); // TODO: Predict me when hands predicted SubscribeLocalEvent(OnMovement); SubscribeLocalEvent(OnPowerChange); @@ -103,14 +102,6 @@ public sealed class DisposalUnitSystem : SharedDisposalUnitSystem GetNetEntityList(component.RecentlyEjected)); } - private void OnUnpaused(EntityUid uid, SharedDisposalUnitComponent component, ref EntityUnpausedEvent args) - { - if (component.NextFlush != null) - component.NextFlush = component.NextFlush.Value + args.PausedTime; - - component.NextPressurized += args.PausedTime; - } - private void AddDisposalAltVerbs(EntityUid uid, SharedDisposalUnitComponent component, GetVerbsEvent args) { if (!args.CanAccess || !args.CanInteract) diff --git a/Content.Server/Doors/Systems/AirlockSystem.cs b/Content.Server/Doors/Systems/AirlockSystem.cs index 89fcf4a0d7..607fa08e4e 100644 --- a/Content.Server/Doors/Systems/AirlockSystem.cs +++ b/Content.Server/Doors/Systems/AirlockSystem.cs @@ -1,13 +1,10 @@ using Content.Server.DeviceLinking.Events; using Content.Server.Power.Components; -using Content.Server.Power.EntitySystems; using Content.Server.Wires; -using Content.Shared.Doors; using Content.Shared.Doors.Components; using Content.Shared.Doors.Systems; using Content.Shared.Interaction; using Content.Shared.Wires; -using Content.Shared.Prying.Components; using Robust.Shared.Player; namespace Content.Server.Doors.Systems; @@ -15,8 +12,6 @@ namespace Content.Server.Doors.Systems; public sealed class AirlockSystem : SharedAirlockSystem { [Dependency] private readonly WiresSystem _wiresSystem = default!; - [Dependency] private readonly PowerReceiverSystem _power = default!; - [Dependency] private readonly DoorBoltSystem _bolts = default!; public override void Initialize() { @@ -26,13 +21,7 @@ public sealed class AirlockSystem : SharedAirlockSystem SubscribeLocalEvent(OnSignalReceived); SubscribeLocalEvent(OnPowerChanged); - SubscribeLocalEvent(OnStateChanged); - SubscribeLocalEvent(OnBeforeDoorOpened); - SubscribeLocalEvent(OnBeforeDoorDenied); SubscribeLocalEvent(OnActivate, before: new[] { typeof(DoorSystem) }); - SubscribeLocalEvent(OnGetPryMod); - SubscribeLocalEvent(OnBeforePry); - } private void OnAirlockInit(EntityUid uid, AirlockComponent component, ComponentInit args) @@ -54,6 +43,9 @@ public sealed class AirlockSystem : SharedAirlockSystem private void OnPowerChanged(EntityUid uid, AirlockComponent component, ref PowerChangedEvent args) { + component.Powered = args.Powered; + Dirty(uid, component); + if (TryComp(uid, out var appearanceComponent)) { Appearance.SetData(uid, DoorVisuals.Powered, args.Powered, appearanceComponent); @@ -74,80 +66,6 @@ public sealed class AirlockSystem : SharedAirlockSystem } } - private void OnStateChanged(EntityUid uid, AirlockComponent component, DoorStateChangedEvent args) - { - // TODO move to shared? having this be server-side, but having client-side door opening/closing & prediction - // means that sometimes the panels & bolt lights may be visible despite a door being completely open. - - // Only show the maintenance panel if the airlock is closed - if (TryComp(uid, out var wiresPanel)) - { - _wiresSystem.ChangePanelVisibility(uid, wiresPanel, component.OpenPanelVisible || args.State != DoorState.Open); - } - // If the door is closed, we should look if the bolt was locked while closing - UpdateAutoClose(uid, component); - - // Make sure the airlock auto closes again next time it is opened - if (args.State == DoorState.Closed) - component.AutoClose = true; - } - - /// - /// Updates the auto close timer. - /// - public void UpdateAutoClose(EntityUid uid, AirlockComponent? airlock = null, DoorComponent? door = null) - { - if (!Resolve(uid, ref airlock, ref door)) - return; - - if (door.State != DoorState.Open) - return; - - if (!airlock.AutoClose) - return; - - if (!CanChangeState(uid, airlock)) - return; - - var autoev = new BeforeDoorAutoCloseEvent(); - RaiseLocalEvent(uid, autoev, false); - if (autoev.Cancelled) - return; - - DoorSystem.SetNextStateChange(uid, airlock.AutoCloseDelay * airlock.AutoCloseDelayModifier); - } - - private void OnBeforeDoorOpened(EntityUid uid, AirlockComponent component, BeforeDoorOpenedEvent args) - { - if (!CanChangeState(uid, component)) - args.Cancel(); - } - - protected override void OnBeforeDoorClosed(EntityUid uid, AirlockComponent component, BeforeDoorClosedEvent args) - { - base.OnBeforeDoorClosed(uid, component, args); - - if (args.Cancelled) - return; - - // only block based on bolts / power status when initially closing the door, not when its already - // mid-transition. Particularly relevant for when the door was pried-closed with a crowbar, which bypasses - // the initial power-check. - - if (TryComp(uid, out DoorComponent? door) - && !door.Partial - && !CanChangeState(uid, component)) - { - args.Cancel(); - } - } - - private void OnBeforeDoorDenied(EntityUid uid, AirlockComponent component, BeforeDoorDeniedEvent args) - { - if (!CanChangeState(uid, component)) - args.Cancel(); - } - private void OnActivate(EntityUid uid, AirlockComponent component, ActivateInWorldEvent args) { if (TryComp(uid, out var panel) && @@ -169,32 +87,4 @@ public sealed class AirlockSystem : SharedAirlockSystem component.AutoClose = false; } } - - private void OnGetPryMod(EntityUid uid, AirlockComponent component, ref GetPryTimeModifierEvent args) - { - if (_power.IsPowered(uid)) - args.PryTimeModifier *= component.PoweredPryModifier; - - if (_bolts.IsBolted(uid)) - args.PryTimeModifier *= component.BoltedPryModifier; - } - - private void OnBeforePry(EntityUid uid, AirlockComponent component, ref BeforePryEvent args) - { - if (args.Cancelled) - return; - - if (!this.IsPowered(uid, EntityManager) || args.PryPowered) - return; - - args.Message = "airlock-component-cannot-pry-is-powered-message"; - - args.Cancelled = true; - - } - - public bool CanChangeState(EntityUid uid, AirlockComponent component) - { - return this.IsPowered(uid, EntityManager) && !_bolts.IsBolted(uid); - } } diff --git a/Content.Server/Doors/Systems/DoorBoltSystem.cs b/Content.Server/Doors/Systems/DoorBoltSystem.cs deleted file mode 100644 index 133af0013d..0000000000 --- a/Content.Server/Doors/Systems/DoorBoltSystem.cs +++ /dev/null @@ -1,90 +0,0 @@ -using Content.Server.Power.Components; -using Content.Server.Power.EntitySystems; -using Content.Shared.Doors; -using Content.Shared.Doors.Components; -using Content.Shared.Doors.Systems; - -namespace Content.Server.Doors.Systems; - -public sealed class DoorBoltSystem : SharedDoorBoltSystem -{ - - public override void Initialize() - { - base.Initialize(); - - SubscribeLocalEvent(OnPowerChanged); - SubscribeLocalEvent(OnStateChanged); - } - - private void OnPowerChanged(EntityUid uid, DoorBoltComponent component, ref PowerChangedEvent args) - { - if (args.Powered) - { - if (component.BoltWireCut) - SetBoltsWithAudio(uid, component, true); - } - - UpdateBoltLightStatus(uid, component); - } - - public void UpdateBoltLightStatus(EntityUid uid, DoorBoltComponent component) - { - if (!TryComp(uid, out var appearance)) - return; - - Appearance.SetData(uid, DoorVisuals.BoltLights, GetBoltLightsVisible(uid, component), appearance); - } - - public bool GetBoltLightsVisible(EntityUid uid, DoorBoltComponent component) - { - return component.BoltLightsEnabled && - component.BoltsDown && - this.IsPowered(uid, EntityManager); - } - - public void SetBoltLightsEnabled(EntityUid uid, DoorBoltComponent component, bool value) - { - if (component.BoltLightsEnabled == value) - return; - - component.BoltLightsEnabled = value; - UpdateBoltLightStatus(uid, component); - } - - public void SetBoltsDown(EntityUid uid, DoorBoltComponent component, bool value) - { - if (component.BoltsDown == value) - return; - - component.BoltsDown = value; - UpdateBoltLightStatus(uid, component); - } - - private void OnStateChanged(EntityUid uid, DoorBoltComponent component, DoorStateChangedEvent args) - { - // If the door is closed, we should look if the bolt was locked while closing - UpdateBoltLightStatus(uid, component); - } - - public void SetBoltsWithAudio(EntityUid uid, DoorBoltComponent component, bool newBolts) - { - if (newBolts == component.BoltsDown) - return; - - component.BoltsDown = newBolts; - Audio.PlayPvs(newBolts ? component.BoltDownSound : component.BoltUpSound, uid); - UpdateBoltLightStatus(uid, component); - } - - public bool IsBolted(EntityUid uid, DoorBoltComponent? component = null) - { - if (!Resolve(uid, ref component)) - { - return false; - } - - return component.BoltsDown; - } -} - diff --git a/Content.Server/Doors/Systems/DoorSystem.cs b/Content.Server/Doors/Systems/DoorSystem.cs index d59ea59622..5968e445c1 100644 --- a/Content.Server/Doors/Systems/DoorSystem.cs +++ b/Content.Server/Doors/Systems/DoorSystem.cs @@ -1,49 +1,22 @@ using Content.Server.Access; -using Content.Server.Administration.Logs; using Content.Server.Atmos.Components; using Content.Server.Atmos.EntitySystems; -using Content.Server.Power.EntitySystems; -using Content.Shared.Database; +using Content.Server.Power.Components; using Content.Shared.Doors.Components; using Content.Shared.Doors.Systems; -using Content.Shared.Emag.Systems; -using Content.Shared.Interaction; -using Content.Shared.Prying.Components; -using Content.Shared.Prying.Systems; -using Content.Shared.Tools.Systems; -using Robust.Shared.Audio; using Robust.Shared.Physics.Components; -using Robust.Shared.Physics.Events; namespace Content.Server.Doors.Systems; public sealed class DoorSystem : SharedDoorSystem { - [Dependency] private readonly IAdminLogManager _adminLog = default!; - [Dependency] private readonly DoorBoltSystem _bolts = default!; [Dependency] private readonly AirtightSystem _airtightSystem = default!; - [Dependency] private readonly PryingSystem _pryingSystem = default!; public override void Initialize() { base.Initialize(); - SubscribeLocalEvent(OnWeldAttempt); - SubscribeLocalEvent(OnWeldChanged); - SubscribeLocalEvent(OnEmagged); - SubscribeLocalEvent(OnAfterPry); - } - - protected override void OnActivate(EntityUid uid, DoorComponent door, ActivateInWorldEvent args) - { - // TODO once access permissions are shared, move this back to shared. - if (args.Handled || !door.ClickOpen) - return; - - if (!TryToggleDoor(uid, door, args.User)) - _pryingSystem.TryPry(uid, args.User, out _); - - args.Handled = true; + SubscribeLocalEvent(OnBoltPowerChanged); } protected override void SetCollidable( @@ -65,144 +38,16 @@ public sealed class DoorSystem : SharedDoorSystem base.SetCollidable(uid, collidable, door, physics, occluder); } - // TODO AUDIO PREDICT Figure out a better way to handle sound and prediction. For now, this works well enough? - // - // Currently a client will predict when a door is going to close automatically. So any client in PVS range can just - // play their audio locally. Playing it server-side causes an odd delay, while in shared it causes double-audio. - // - // But if we just do that, then if a door is closed prematurely as the result of an interaction (i.e., using "E" on - // an open door), then the audio would only be played for the client performing the interaction. - // - // So we do this: - // - Play audio client-side IF the closing is being predicted (auto-close or predicted interaction) - // - Server assumes automated closing is predicted by clients and does not play audio unless otherwise specified. - // - Major exception is player interactions, which other players cannot predict - // - In that case, send audio to all players, except possibly the interacting player if it was a predicted - // interaction. - - /// - /// Selectively send sound to clients, taking care to not send the double-audio. - /// - /// The audio source - /// The sound - /// The audio parameters. - /// The user (if any) that instigated an interaction - /// Whether this interaction would have been predicted. If the predicting player is null, - /// this assumes it would have been predicted by all players in PVS range. - protected override void PlaySound(EntityUid uid, SoundSpecifier soundSpecifier, AudioParams audioParams, EntityUid? predictingPlayer, bool predicted) + private void OnBoltPowerChanged(Entity ent, ref PowerChangedEvent args) { - // If this sound would have been predicted by all clients, do not play any audio. - if (predicted && predictingPlayer == null) - return; - - if (predicted) - Audio.PlayPredicted(soundSpecifier, uid, predictingPlayer, audioParams); - else - Audio.PlayPvs(soundSpecifier, uid, audioParams); - } - - #region DoAfters - private void OnWeldAttempt(EntityUid uid, DoorComponent component, WeldableAttemptEvent args) - { - if (component.CurrentlyCrushing.Count > 0) + if (args.Powered) { - args.Cancel(); - return; + if (ent.Comp.BoltWireCut) + SetBoltsDown(ent, true); } - if (component.State != DoorState.Closed && component.State != DoorState.Welded) - { - args.Cancel(); - } - } - private void OnWeldChanged(EntityUid uid, DoorComponent component, ref WeldableChangedEvent args) - { - if (component.State == DoorState.Closed) - SetState(uid, DoorState.Welded, component); - else if (component.State == DoorState.Welded) - SetState(uid, DoorState.Closed, component); - } - #endregion - - - /// - /// Open a door if a player or door-bumper (PDA, ID-card) collide with the door. Sadly, bullets no longer - /// generate "access denied" sounds as you fire at a door. - /// - protected override void HandleCollide(EntityUid uid, DoorComponent door, ref StartCollideEvent args) - { - // TODO ACCESS READER move access reader to shared and predict door opening/closing - // Then this can be moved to the shared system without mispredicting. - if (!door.BumpOpen) - return; - - if (door.State is not (DoorState.Closed or DoorState.Denying)) - return; - - var otherUid = args.OtherEntity; - - if (Tags.HasTag(otherUid, "DoorBumpOpener")) - TryOpen(uid, door, otherUid, quiet: door.State == DoorState.Denying); - } - private void OnEmagged(EntityUid uid, DoorComponent door, ref GotEmaggedEvent args) - { - if (TryComp(uid, out var airlockComponent)) - { - if (_bolts.IsBolted(uid) || !this.IsPowered(uid, EntityManager)) - return; - - if (door.State == DoorState.Closed) - { - SetState(uid, DoorState.Emagging, door); - PlaySound(uid, door.SparkSound, AudioParams.Default.WithVolume(8), args.UserUid, false); - args.Handled = true; - } - } - } - - public override void StartOpening(EntityUid uid, DoorComponent? door = null, EntityUid? user = null, bool predicted = false) - { - if (!Resolve(uid, ref door)) - return; - - var lastState = door.State; - - SetState(uid, DoorState.Opening, door); - - if (door.OpenSound != null) - PlaySound(uid, door.OpenSound, AudioParams.Default.WithVolume(-5), user, predicted); - - if (lastState == DoorState.Emagging && TryComp(uid, out var doorBoltComponent)) - _bolts.SetBoltsWithAudio(uid, doorBoltComponent, !doorBoltComponent.BoltsDown); - } - - /// - /// Open or close a door after it has been successfuly pried. - /// - private void OnAfterPry(EntityUid uid, DoorComponent door, ref PriedEvent args) - { - if (door.State == DoorState.Closed) - { - _adminLog.Add(LogType.Action, LogImpact.Medium, $"{ToPrettyString(args.User)} pried {ToPrettyString(uid)} open"); - StartOpening(uid, door, args.User); - } - else if (door.State == DoorState.Open) - { - _adminLog.Add(LogType.Action, LogImpact.Medium, $"{ToPrettyString(args.User)} pried {ToPrettyString(uid)} closed"); - StartClosing(uid, door, args.User); - } - } - - protected override void CheckDoorBump(Entity ent) - { - var (uid, door, physics) = ent; - if (door.BumpOpen) - { - foreach (var other in PhysicsSystem.GetContactingEntities(uid, physics, approximate: true)) - { - if (Tags.HasTag(other, "DoorBumpOpener") && TryOpen(uid, door, other, quiet: true)) - break; - } - } + UpdateBoltLightStatus(ent); + ent.Comp.Powered = args.Powered; + Dirty(ent, ent.Comp); } } diff --git a/Content.Server/Doors/WireActions/DoorBoltLightWireAction.cs b/Content.Server/Doors/WireActions/DoorBoltLightWireAction.cs index 233ebfed3f..c5e3aa80c9 100644 --- a/Content.Server/Doors/WireActions/DoorBoltLightWireAction.cs +++ b/Content.Server/Doors/WireActions/DoorBoltLightWireAction.cs @@ -18,19 +18,18 @@ public sealed partial class DoorBoltLightWireAction : ComponentWireAction().SetBoltLightsEnabled(wire.Owner, door, false); + EntityManager.System().SetBoltLightsEnabled((wire.Owner, door), false); return true; } public override bool Mend(EntityUid user, Wire wire, DoorBoltComponent door) { - - EntityManager.System().SetBoltLightsEnabled(wire.Owner, door, true); + EntityManager.System().SetBoltLightsEnabled((wire.Owner, door), true); return true; } public override void Pulse(EntityUid user, Wire wire, DoorBoltComponent door) { - EntityManager.System().SetBoltLightsEnabled(wire.Owner, door, !door.BoltLightsEnabled); + EntityManager.System().SetBoltLightsEnabled((wire.Owner, door), !door.BoltLightsEnabled); } } diff --git a/Content.Server/Doors/WireActions/DoorBoltWireAction.cs b/Content.Server/Doors/WireActions/DoorBoltWireAction.cs index 29b5d726a2..fc1cf50cd8 100644 --- a/Content.Server/Doors/WireActions/DoorBoltWireAction.cs +++ b/Content.Server/Doors/WireActions/DoorBoltWireAction.cs @@ -19,24 +19,24 @@ public sealed partial class DoorBoltWireAction : ComponentWireAction().SetBoltWireCut(airlock, true); + EntityManager.System().SetBoltWireCut((wire.Owner, airlock), true); if (!airlock.BoltsDown && IsPowered(wire.Owner)) - EntityManager.System().SetBoltsWithAudio(wire.Owner, airlock, true); + EntityManager.System().SetBoltsDown((wire.Owner, airlock), true, user); return true; } public override bool Mend(EntityUid user, Wire wire, DoorBoltComponent door) { - EntityManager.System().SetBoltWireCut(door, false); + EntityManager.System().SetBoltWireCut((wire.Owner, door), false); return true; } public override void Pulse(EntityUid user, Wire wire, DoorBoltComponent door) { if (IsPowered(wire.Owner)) - EntityManager.System().SetBoltsWithAudio(wire.Owner, door, !door.BoltsDown); + EntityManager.System().SetBoltsDown((wire.Owner, door), !door.BoltsDown); else if (!door.BoltsDown) - EntityManager.System().SetBoltsWithAudio(wire.Owner, door, true); + EntityManager.System().SetBoltsDown((wire.Owner, door), true); } } diff --git a/Content.Server/Emp/EmpSystem.cs b/Content.Server/Emp/EmpSystem.cs index 02a18284e8..7c1a6f9b5d 100644 --- a/Content.Server/Emp/EmpSystem.cs +++ b/Content.Server/Emp/EmpSystem.cs @@ -17,7 +17,6 @@ public sealed class EmpSystem : SharedEmpSystem public override void Initialize() { base.Initialize(); - SubscribeLocalEvent(OnUnpaused); SubscribeLocalEvent(OnExamine); SubscribeLocalEvent(HandleEmpTrigger); @@ -96,12 +95,6 @@ public sealed class EmpSystem : SharedEmpSystem } } - private void OnUnpaused(EntityUid uid, EmpDisabledComponent component, ref EntityUnpausedEvent args) - { - component.DisabledUntil += args.PausedTime; - component.TargetTime += args.PausedTime; - } - private void OnExamine(EntityUid uid, EmpDisabledComponent component, ExaminedEvent args) { args.PushMarkup(Loc.GetString("emp-disabled-comp-on-examine")); diff --git a/Content.Server/Execution/ExecutionSystem.cs b/Content.Server/Execution/ExecutionSystem.cs deleted file mode 100644 index 4354608ca3..0000000000 --- a/Content.Server/Execution/ExecutionSystem.cs +++ /dev/null @@ -1,397 +0,0 @@ -using Content.Server.Interaction; -using Content.Server.Kitchen.Components; -using Content.Server.Weapons.Ranged.Systems; -using Content.Shared.ActionBlocker; -using Content.Shared.Damage; -using Content.Shared.Database; -using Content.Shared.DoAfter; -using Content.Shared.Execution; -using Content.Shared.Interaction.Components; -using Content.Shared.Mobs.Components; -using Content.Shared.Mobs.Systems; -using Content.Shared.Popups; -using Content.Shared.Projectiles; -using Content.Shared.Verbs; -using Content.Shared.Weapons.Melee; -using Content.Shared.Weapons.Ranged; -using Content.Shared.Weapons.Ranged.Components; -using Content.Shared.Weapons.Ranged.Events; -using Content.Shared.Weapons.Ranged.Systems; -using Robust.Shared.Audio; -using Robust.Shared.Audio.Systems; -using Robust.Shared.Player; -using Robust.Shared.Prototypes; - -namespace Content.Server.Execution; - -/// -/// Verb for violently murdering cuffed creatures. -/// -public sealed class ExecutionSystem : EntitySystem -{ - [Dependency] private readonly SharedDoAfterSystem _doAfterSystem = default!; - [Dependency] private readonly SharedPopupSystem _popupSystem = default!; - [Dependency] private readonly MobStateSystem _mobStateSystem = default!; - [Dependency] private readonly InteractionSystem _interactionSystem = default!; - [Dependency] private readonly ActionBlockerSystem _actionBlockerSystem = default!; - [Dependency] private readonly DamageableSystem _damageableSystem = default!; - [Dependency] private readonly IPrototypeManager _prototypeManager = default!; - [Dependency] private readonly IComponentFactory _componentFactory = default!; - [Dependency] private readonly SharedAppearanceSystem _appearanceSystem = default!; - [Dependency] private readonly SharedAudioSystem _audioSystem = default!; - [Dependency] private readonly GunSystem _gunSystem = default!; - - private const float MeleeExecutionTimeModifier = 5.0f; - private const float GunExecutionTime = 6.0f; - private const float DamageModifier = 9.0f; - - /// - public override void Initialize() - { - base.Initialize(); - - SubscribeLocalEvent>(OnGetInteractionVerbsMelee); - SubscribeLocalEvent>(OnGetInteractionVerbsGun); - - SubscribeLocalEvent(OnDoafterMelee); - SubscribeLocalEvent(OnDoafterGun); - } - - private void OnGetInteractionVerbsMelee( - EntityUid uid, - SharpComponent component, - GetVerbsEvent args) - { - if (args.Hands == null || args.Using == null || !args.CanAccess || !args.CanInteract) - return; - - var attacker = args.User; - var weapon = args.Using!.Value; - var victim = args.Target; - - if (!CanExecuteWithMelee(weapon, victim, attacker)) - return; - - UtilityVerb verb = new() - { - Act = () => - { - TryStartMeleeExecutionDoafter(weapon, victim, attacker); - }, - Impact = LogImpact.High, - Text = Loc.GetString("execution-verb-name"), - Message = Loc.GetString("execution-verb-message"), - }; - - args.Verbs.Add(verb); - } - - private void OnGetInteractionVerbsGun( - EntityUid uid, - GunComponent component, - GetVerbsEvent args) - { - if (args.Hands == null || args.Using == null || !args.CanAccess || !args.CanInteract) - return; - - var attacker = args.User; - var weapon = args.Using!.Value; - var victim = args.Target; - - if (!CanExecuteWithGun(weapon, victim, attacker)) - return; - - UtilityVerb verb = new() - { - Act = () => - { - TryStartGunExecutionDoafter(weapon, victim, attacker); - }, - Impact = LogImpact.High, - Text = Loc.GetString("execution-verb-name"), - Message = Loc.GetString("execution-verb-message"), - }; - - args.Verbs.Add(verb); - } - - private bool CanExecuteWithAny(EntityUid weapon, EntityUid victim, EntityUid attacker) - { - // No point executing someone if they can't take damage - if (!TryComp(victim, out var damage)) - return false; - - // You can't execute something that cannot die - if (!TryComp(victim, out var mobState)) - return false; - - // You're not allowed to execute dead people (no fun allowed) - if (_mobStateSystem.IsDead(victim, mobState)) - return false; - - // You must be able to attack people to execute - if (!_actionBlockerSystem.CanAttack(attacker, victim)) - return false; - - // The victim must be incapacitated to be executed - if (victim != attacker && _actionBlockerSystem.CanInteract(victim, null)) - return false; - - // All checks passed - return true; - } - - private bool CanExecuteWithMelee(EntityUid weapon, EntityUid victim, EntityUid user) - { - if (!CanExecuteWithAny(weapon, victim, user)) return false; - - // We must be able to actually hurt people with the weapon - if (!TryComp(weapon, out var melee) && melee!.Damage.GetTotal() > 0.0f) - return false; - - return true; - } - - private bool CanExecuteWithGun(EntityUid weapon, EntityUid victim, EntityUid user) - { - if (!CanExecuteWithAny(weapon, victim, user)) return false; - - // We must be able to actually fire the gun - if (!TryComp(weapon, out var gun) && _gunSystem.CanShoot(gun!)) - return false; - - return true; - } - - private void TryStartMeleeExecutionDoafter(EntityUid weapon, EntityUid victim, EntityUid attacker) - { - if (!CanExecuteWithMelee(weapon, victim, attacker)) - return; - - var executionTime = (1.0f / Comp(weapon).AttackRate) * MeleeExecutionTimeModifier; - - if (attacker == victim) - { - ShowExecutionPopup("suicide-popup-melee-initial-internal", Filter.Entities(attacker), PopupType.Medium, attacker, victim, weapon); - ShowExecutionPopup("suicide-popup-melee-initial-external", Filter.PvsExcept(attacker), PopupType.MediumCaution, attacker, victim, weapon); - } - else - { - ShowExecutionPopup("execution-popup-melee-initial-internal", Filter.Entities(attacker), PopupType.Medium, attacker, victim, weapon); - ShowExecutionPopup("execution-popup-melee-initial-external", Filter.PvsExcept(attacker), PopupType.MediumCaution, attacker, victim, weapon); - } - - var doAfter = - new DoAfterArgs(EntityManager, attacker, executionTime, new ExecutionDoAfterEvent(), weapon, target: victim, used: weapon) - { - BreakOnTargetMove = true, - BreakOnUserMove = true, - BreakOnDamage = true, - NeedHand = true - }; - - _doAfterSystem.TryStartDoAfter(doAfter); - } - - private void TryStartGunExecutionDoafter(EntityUid weapon, EntityUid victim, EntityUid attacker) - { - if (!CanExecuteWithGun(weapon, victim, attacker)) - return; - - if (attacker == victim) - { - ShowExecutionPopup("suicide-popup-gun-initial-internal", Filter.Entities(attacker), PopupType.Medium, attacker, victim, weapon); - ShowExecutionPopup("suicide-popup-gun-initial-external", Filter.PvsExcept(attacker), PopupType.MediumCaution, attacker, victim, weapon); - } - else - { - ShowExecutionPopup("execution-popup-gun-initial-internal", Filter.Entities(attacker), PopupType.Medium, attacker, victim, weapon); - ShowExecutionPopup("execution-popup-gun-initial-external", Filter.PvsExcept(attacker), PopupType.MediumCaution, attacker, victim, weapon); - } - - var doAfter = - new DoAfterArgs(EntityManager, attacker, GunExecutionTime, new ExecutionDoAfterEvent(), weapon, target: victim, used: weapon) - { - BreakOnTargetMove = true, - BreakOnUserMove = true, - BreakOnDamage = true, - NeedHand = true - }; - - _doAfterSystem.TryStartDoAfter(doAfter); - } - - private bool OnDoafterChecks(EntityUid uid, DoAfterEvent args) - { - if (args.Handled || args.Cancelled || args.Used == null || args.Target == null) - return false; - - if (!CanExecuteWithAny(args.Used.Value, args.Target.Value, uid)) - return false; - - // All checks passed - return true; - } - - private void OnDoafterMelee(EntityUid uid, SharpComponent component, DoAfterEvent args) - { - if (args.Handled || args.Cancelled || args.Used == null || args.Target == null) - return; - - var attacker = args.User; - var victim = args.Target!.Value; - var weapon = args.Used!.Value; - - if (!CanExecuteWithMelee(weapon, victim, attacker)) return; - - if (!TryComp(weapon, out var melee) && melee!.Damage.GetTotal() > 0.0f) - return; - - _damageableSystem.TryChangeDamage(victim, melee.Damage * DamageModifier, true); - _audioSystem.PlayEntity(melee.HitSound, Filter.Pvs(weapon), weapon, true, AudioParams.Default); - - if (attacker == victim) - { - ShowExecutionPopup("suicide-popup-melee-complete-internal", Filter.Entities(attacker), PopupType.Medium, attacker, victim, weapon); - ShowExecutionPopup("suicide-popup-melee-complete-external", Filter.PvsExcept(attacker), PopupType.MediumCaution, attacker, victim, weapon); - } - else - { - ShowExecutionPopup("execution-popup-melee-complete-internal", Filter.Entities(attacker), PopupType.Medium, attacker, victim, weapon); - ShowExecutionPopup("execution-popup-melee-complete-external", Filter.PvsExcept(attacker), PopupType.MediumCaution, attacker, victim, weapon); - } - } - - // TODO: This repeats a lot of the code of the serverside GunSystem, make it not do that - private void OnDoafterGun(EntityUid uid, GunComponent component, DoAfterEvent args) - { - if (args.Handled || args.Cancelled || args.Used == null || args.Target == null) - return; - - var attacker = args.User; - var weapon = args.Used!.Value; - var victim = args.Target!.Value; - - if (!CanExecuteWithGun(weapon, victim, attacker)) return; - - // Check if any systems want to block our shot - var prevention = new ShotAttemptedEvent - { - User = attacker, - Used = weapon - }; - - RaiseLocalEvent(weapon, ref prevention); - if (prevention.Cancelled) - return; - - RaiseLocalEvent(attacker, ref prevention); - if (prevention.Cancelled) - return; - - // Not sure what this is for but gunsystem uses it so ehhh - var attemptEv = new AttemptShootEvent(attacker, null); - RaiseLocalEvent(weapon, ref attemptEv); - - if (attemptEv.Cancelled) - { - if (attemptEv.Message != null) - { - _popupSystem.PopupClient(attemptEv.Message, weapon, attacker); - return; - } - } - - // Take some ammunition for the shot (one bullet) - var fromCoordinates = Transform(attacker).Coordinates; - var ev = new TakeAmmoEvent(1, new List<(EntityUid? Entity, IShootable Shootable)>(), fromCoordinates, attacker); - RaiseLocalEvent(weapon, ev); - - // Check if there's any ammo left - if (ev.Ammo.Count <= 0) - { - _audioSystem.PlayEntity(component.SoundEmpty, Filter.Pvs(weapon), weapon, true, AudioParams.Default); - ShowExecutionPopup("execution-popup-gun-empty", Filter.Pvs(weapon), PopupType.Medium, attacker, victim, weapon); - return; - } - - // Information about the ammo like damage - DamageSpecifier damage = new DamageSpecifier(); - - // Get some information from IShootable - var ammoUid = ev.Ammo[0].Entity; - switch (ev.Ammo[0].Shootable) - { - case CartridgeAmmoComponent cartridge: - // Get the damage value - var prototype = _prototypeManager.Index(cartridge.Prototype); - prototype.TryGetComponent(out var projectileA, _componentFactory); // sloth forgive me - if (projectileA != null) - { - damage = projectileA.Damage * cartridge.Count; - } - - // Expend the cartridge - cartridge.Spent = true; - _appearanceSystem.SetData(ammoUid!.Value, AmmoVisuals.Spent, true); - Dirty(ammoUid.Value, cartridge); - - break; - - case AmmoComponent newAmmo: - TryComp(ammoUid, out var projectileB); - if (projectileB != null) - { - damage = projectileB.Damage; - } - Del(ammoUid); - break; - - case HitscanPrototype hitscan: - damage = hitscan.Damage!; - break; - - default: - throw new ArgumentOutOfRangeException(); - } - - // Clumsy people have a chance to shoot themselves - if (TryComp(attacker, out var clumsy) && component.ClumsyProof == false) - { - if (_interactionSystem.TryRollClumsy(attacker, 0.33333333f, clumsy)) - { - ShowExecutionPopup("execution-popup-gun-clumsy-internal", Filter.Entities(attacker), PopupType.Medium, attacker, victim, weapon); - ShowExecutionPopup("execution-popup-gun-clumsy-external", Filter.PvsExcept(attacker), PopupType.MediumCaution, attacker, victim, weapon); - - // You shoot yourself with the gun (no damage multiplier) - _damageableSystem.TryChangeDamage(attacker, damage, origin: attacker); - _audioSystem.PlayEntity(component.SoundGunshot, Filter.Pvs(weapon), weapon, true, AudioParams.Default); - return; - } - } - - // Gun successfully fired, deal damage - _damageableSystem.TryChangeDamage(victim, damage * DamageModifier, true); - _audioSystem.PlayEntity(component.SoundGunshot, Filter.Pvs(weapon), weapon, false, AudioParams.Default); - - // Popups - if (attacker != victim) - { - ShowExecutionPopup("execution-popup-gun-complete-internal", Filter.Entities(attacker), PopupType.Medium, attacker, victim, weapon); - ShowExecutionPopup("execution-popup-gun-complete-external", Filter.PvsExcept(attacker), PopupType.LargeCaution, attacker, victim, weapon); - } - else - { - ShowExecutionPopup("suicide-popup-gun-complete-internal", Filter.Entities(attacker), PopupType.LargeCaution, attacker, victim, weapon); - ShowExecutionPopup("suicide-popup-gun-complete-external", Filter.PvsExcept(attacker), PopupType.LargeCaution, attacker, victim, weapon); - } - } - - private void ShowExecutionPopup(string locString, Filter filter, PopupType type, - EntityUid attacker, EntityUid victim, EntityUid weapon) - { - _popupSystem.PopupEntity(Loc.GetString( - locString, ("attacker", attacker), ("victim", victim), ("weapon", weapon)), - attacker, filter, true, type); - } -} \ No newline at end of file diff --git a/Content.Server/Explosion/Components/OnTrigger/TwoStageTriggerComponent.cs b/Content.Server/Explosion/Components/OnTrigger/TwoStageTriggerComponent.cs index 357286b192..a63d6fcf66 100644 --- a/Content.Server/Explosion/Components/OnTrigger/TwoStageTriggerComponent.cs +++ b/Content.Server/Explosion/Components/OnTrigger/TwoStageTriggerComponent.cs @@ -6,7 +6,7 @@ namespace Content.Server.Explosion.Components.OnTrigger; /// /// After being triggered applies the specified components and runs triggers again. /// -[RegisterComponent] +[RegisterComponent, AutoGenerateComponentPause] public sealed partial class TwoStageTriggerComponent : Component { /// @@ -23,6 +23,7 @@ public sealed partial class TwoStageTriggerComponent : Component public ComponentRegistry SecondStageComponents = new(); [DataField("nextTriggerTime", customTypeSerializer: typeof(TimeOffsetSerializer))] + [AutoPausedField] public TimeSpan? NextTriggerTime; [DataField("triggered")] diff --git a/Content.Server/Explosion/Components/TriggerOnProximityComponent.cs b/Content.Server/Explosion/Components/TriggerOnProximityComponent.cs index 504ef4dee4..4f3fb4754e 100644 --- a/Content.Server/Explosion/Components/TriggerOnProximityComponent.cs +++ b/Content.Server/Explosion/Components/TriggerOnProximityComponent.cs @@ -13,7 +13,7 @@ namespace Content.Server.Explosion.Components /// /// Raises a whenever an entity collides with a fixture attached to the owner of this component. /// - [RegisterComponent] + [RegisterComponent, AutoGenerateComponentPause] public sealed partial class TriggerOnProximityComponent : SharedTriggerOnProximityComponent { public const string FixtureID = "trigger-on-proximity-fixture"; @@ -58,6 +58,7 @@ namespace Content.Server.Explosion.Components /// [ViewVariables(VVAccess.ReadWrite)] [DataField("nextTrigger", customTypeSerializer: typeof(TimeOffsetSerializer))] + [AutoPausedField] public TimeSpan NextTrigger = TimeSpan.Zero; /// @@ -65,6 +66,7 @@ namespace Content.Server.Explosion.Components /// [ViewVariables(VVAccess.ReadWrite)] [DataField("nextVisualUpdate", customTypeSerializer: typeof(TimeOffsetSerializer))] + [AutoPausedField] public TimeSpan NextVisualUpdate = TimeSpan.Zero; /// diff --git a/Content.Server/Explosion/EntitySystems/TriggerSystem.Proximity.cs b/Content.Server/Explosion/EntitySystems/TriggerSystem.Proximity.cs index d3d97a851e..119b1a3d36 100644 --- a/Content.Server/Explosion/EntitySystems/TriggerSystem.Proximity.cs +++ b/Content.Server/Explosion/EntitySystems/TriggerSystem.Proximity.cs @@ -17,7 +17,6 @@ public sealed partial class TriggerSystem SubscribeLocalEvent(OnProximityStartCollide); SubscribeLocalEvent(OnProximityEndCollide); SubscribeLocalEvent(OnMapInit); - SubscribeLocalEvent(OnUnpaused); SubscribeLocalEvent(OnProximityShutdown); // Shouldn't need re-anchoring. SubscribeLocalEvent(OnProximityAnchor); @@ -65,12 +64,6 @@ public sealed partial class TriggerSystem collisionLayer: component.Layer); } - private void OnUnpaused(EntityUid uid, TriggerOnProximityComponent component, ref EntityUnpausedEvent args) - { - component.NextTrigger += args.PausedTime; - component.NextVisualUpdate += args.PausedTime; - } - private void OnProximityStartCollide(EntityUid uid, TriggerOnProximityComponent component, ref StartCollideEvent args) { if (args.OurFixtureId != TriggerOnProximityComponent.FixtureID) diff --git a/Content.Server/Explosion/EntitySystems/TwoStageTriggerSystem.cs b/Content.Server/Explosion/EntitySystems/TwoStageTriggerSystem.cs index a8c48f21d6..4e95eabff0 100644 --- a/Content.Server/Explosion/EntitySystems/TwoStageTriggerSystem.cs +++ b/Content.Server/Explosion/EntitySystems/TwoStageTriggerSystem.cs @@ -14,16 +14,9 @@ public sealed class TwoStageTriggerSystem : EntitySystem public override void Initialize() { base.Initialize(); - SubscribeLocalEvent(OnTriggerUnpaused); SubscribeLocalEvent(OnTrigger); } - private void OnTriggerUnpaused(EntityUid uid, TwoStageTriggerComponent component, ref EntityUnpausedEvent args) - { - if (component.NextTriggerTime != null) - component.NextTriggerTime = component.NextTriggerTime.Value + args.PausedTime; - } - private void OnTrigger(EntityUid uid, TwoStageTriggerComponent component, TriggerEvent args) { if (component.Triggered) diff --git a/Content.Server/Extinguisher/FireExtinguisherSystem.cs b/Content.Server/Extinguisher/FireExtinguisherSystem.cs index 5adf067d9b..dfecd72398 100644 --- a/Content.Server/Extinguisher/FireExtinguisherSystem.cs +++ b/Content.Server/Extinguisher/FireExtinguisherSystem.cs @@ -93,7 +93,7 @@ public sealed class FireExtinguisherSystem : EntitySystem private void OnGetInteractionVerbs(Entity entity, ref GetVerbsEvent args) { - if (!args.CanInteract) + if (!args.CanAccess || !args.CanInteract) return; var user = args.User; diff --git a/Content.Server/Fluids/EntitySystems/SmokeSystem.cs b/Content.Server/Fluids/EntitySystems/SmokeSystem.cs index 795655068f..cb6f9c13ef 100644 --- a/Content.Server/Fluids/EntitySystems/SmokeSystem.cs +++ b/Content.Server/Fluids/EntitySystems/SmokeSystem.cs @@ -63,7 +63,6 @@ public sealed class SmokeSystem : EntitySystem SubscribeLocalEvent(OnReactionAttempt); SubscribeLocalEvent>(OnReactionAttempt); SubscribeLocalEvent(OnSmokeSpread); - SubscribeLocalEvent(OnAffectedUnpaused); } /// @@ -124,11 +123,6 @@ public sealed class SmokeSystem : EntitySystem RemComp(args.OtherEntity, smokeAffectedComponent); } - private void OnAffectedUnpaused(Entity entity, ref EntityUnpausedEvent args) - { - entity.Comp.NextSecond += args.PausedTime; - } - private void OnSmokeSpread(Entity entity, ref SpreadNeighborsEvent args) { if (entity.Comp.SpreadAmount == 0 || !_solutionContainerSystem.ResolveSolution(entity.Owner, SmokeComponent.SolutionName, ref entity.Comp.Solution, out var solution)) diff --git a/Content.Server/GameTicking/GameTicker.Replays.cs b/Content.Server/GameTicking/GameTicker.Replays.cs index e09e07b867..9109fbf96a 100644 --- a/Content.Server/GameTicking/GameTicker.Replays.cs +++ b/Content.Server/GameTicking/GameTicker.Replays.cs @@ -128,6 +128,7 @@ public sealed partial class GameTicker metadata["roundEndPlayers"] = _serialman.WriteValue(_replayRoundPlayerInfo); metadata["roundEndText"] = new ValueDataNode(_replayRoundText); metadata["server_id"] = new ValueDataNode(_configurationManager.GetCVar(CCVars.ServerId)); + metadata["server_name"] = new ValueDataNode(_configurationManager.GetCVar(CCVars.AdminLogsServerName)); metadata["roundId"] = new ValueDataNode(RoundId.ToString()); } diff --git a/Content.Server/GameTicking/Rules/ZombieRuleSystem.cs b/Content.Server/GameTicking/Rules/ZombieRuleSystem.cs index 886ff965c7..9bfdb05d31 100644 --- a/Content.Server/GameTicking/Rules/ZombieRuleSystem.cs +++ b/Content.Server/GameTicking/Rules/ZombieRuleSystem.cs @@ -7,6 +7,7 @@ using Content.Server.GameTicking.Rules.Components; using Content.Server.Popups; using Content.Server.Preferences.Managers; using Content.Server.Roles; +using Content.Server.Roles.Jobs; using Content.Server.RoundEnd; using Content.Server.Station.Components; using Content.Server.Station.Systems; @@ -49,6 +50,7 @@ public sealed class ZombieRuleSystem : GameRuleSystem [Dependency] private readonly SharedRoleSystem _roles = default!; [Dependency] private readonly StationSystem _station = default!; [Dependency] private readonly SharedAudioSystem _audio = default!; + [Dependency] private readonly JobSystem _jobs = default!; public override void Initialize() { @@ -271,7 +273,8 @@ public sealed class ZombieRuleSystem : GameRuleSystem var prefList = new List(); foreach (var player in allPlayers) { - if (player.AttachedEntity == null || !HasComp(player.AttachedEntity) || HasComp(player.AttachedEntity)) + if (player.AttachedEntity == null || !HasComp(player.AttachedEntity) || + HasComp(player.AttachedEntity) || !_jobs.CanBeAntag(player)) continue; if (HasComp(player.AttachedEntity)) diff --git a/Content.Server/Gateway/Components/GatewayComponent.cs b/Content.Server/Gateway/Components/GatewayComponent.cs index 71d070f699..9650baafa3 100644 --- a/Content.Server/Gateway/Components/GatewayComponent.cs +++ b/Content.Server/Gateway/Components/GatewayComponent.cs @@ -8,7 +8,7 @@ namespace Content.Server.Gateway.Components; /// /// Controlling gateway that links to other gateway destinations on the server. /// -[RegisterComponent, Access(typeof(GatewaySystem))] +[RegisterComponent, Access(typeof(GatewaySystem)), AutoGenerateComponentPause] public sealed partial class GatewayComponent : Component { /// @@ -61,5 +61,6 @@ public sealed partial class GatewayComponent : Component /// The time at which the portal can next be opened. /// [DataField(customTypeSerializer: typeof(TimeOffsetSerializer))] + [AutoPausedField] public TimeSpan NextReady; } diff --git a/Content.Server/Gateway/Components/GatewayGeneratorComponent.cs b/Content.Server/Gateway/Components/GatewayGeneratorComponent.cs index 670cbea307..d65760e270 100644 --- a/Content.Server/Gateway/Components/GatewayGeneratorComponent.cs +++ b/Content.Server/Gateway/Components/GatewayGeneratorComponent.cs @@ -7,7 +7,7 @@ namespace Content.Server.Gateway.Components; /// /// Generates gateway destinations at a regular interval. /// -[RegisterComponent] +[RegisterComponent, AutoGenerateComponentPause] public sealed partial class GatewayGeneratorComponent : Component { /// @@ -20,6 +20,7 @@ public sealed partial class GatewayGeneratorComponent : Component /// Next time another seed unlocks. /// [DataField(customTypeSerializer:typeof(TimeOffsetSerializer))] + [AutoPausedField] public TimeSpan NextUnlock; /// diff --git a/Content.Server/Gateway/Systems/GatewayGeneratorSystem.cs b/Content.Server/Gateway/Systems/GatewayGeneratorSystem.cs index c8b30af620..7558f7afc0 100644 --- a/Content.Server/Gateway/Systems/GatewayGeneratorSystem.cs +++ b/Content.Server/Gateway/Systems/GatewayGeneratorSystem.cs @@ -67,7 +67,6 @@ public sealed class GatewayGeneratorSystem : EntitySystem public override void Initialize() { base.Initialize(); - SubscribeLocalEvent(OnGeneratorUnpaused); SubscribeLocalEvent(OnGeneratorMapInit); SubscribeLocalEvent(OnGeneratorShutdown); SubscribeLocalEvent(OnGeneratorAttemptOpen); @@ -85,11 +84,6 @@ public sealed class GatewayGeneratorSystem : EntitySystem } } - private void OnGeneratorUnpaused(Entity ent, ref EntityUnpausedEvent args) - { - ent.Comp.NextUnlock += args.PausedTime; - } - private void OnGeneratorMapInit(EntityUid uid, GatewayGeneratorComponent generator, MapInitEvent args) { if (!_cfgManager.GetCVar(CCVars.GatewayGeneratorEnabled)) diff --git a/Content.Server/Gateway/Systems/GatewaySystem.cs b/Content.Server/Gateway/Systems/GatewaySystem.cs index 52525ee0d4..7ebc751dd2 100644 --- a/Content.Server/Gateway/Systems/GatewaySystem.cs +++ b/Content.Server/Gateway/Systems/GatewaySystem.cs @@ -32,7 +32,6 @@ public sealed class GatewaySystem : EntitySystem { base.Initialize(); - SubscribeLocalEvent(OnGatewayUnpaused); SubscribeLocalEvent(OnStartup); SubscribeLocalEvent(OnGatewayOpenAttempt); SubscribeLocalEvent(UpdateUserInterface); @@ -48,11 +47,6 @@ public sealed class GatewaySystem : EntitySystem UpdateAllGateways(); } - private void OnGatewayUnpaused(EntityUid uid, GatewayComponent component, ref EntityUnpausedEvent args) - { - component.NextReady += args.PausedTime; - } - private void OnStartup(EntityUid uid, GatewayComponent comp, ComponentStartup args) { // no need to update ui since its just been created, just do portal diff --git a/Content.Server/Hands/Systems/HandsSystem.cs b/Content.Server/Hands/Systems/HandsSystem.cs index 77b5e3970c..62278064b6 100644 --- a/Content.Server/Hands/Systems/HandsSystem.cs +++ b/Content.Server/Hands/Systems/HandsSystem.cs @@ -52,7 +52,6 @@ namespace Content.Server.Hands.Systems SubscribeLocalEvent(HandleBodyPartRemoved); SubscribeLocalEvent(GetComponentState); - SubscribeLocalEvent(OnUnpaused); SubscribeLocalEvent(OnExploded); @@ -73,10 +72,6 @@ namespace Content.Server.Hands.Systems args.State = new HandsComponentState(hands); } - private void OnUnpaused(Entity ent, ref EntityUnpausedEvent args) - { - ent.Comp.NextThrowTime += args.PausedTime; - } private void OnExploded(Entity ent, ref BeforeExplodeEvent args) { diff --git a/Content.Server/Kitchen/Components/ActiveMicrowaveComponent.cs b/Content.Server/Kitchen/Components/ActiveMicrowaveComponent.cs index bd5449dde6..1e32e039db 100644 --- a/Content.Server/Kitchen/Components/ActiveMicrowaveComponent.cs +++ b/Content.Server/Kitchen/Components/ActiveMicrowaveComponent.cs @@ -6,7 +6,7 @@ namespace Content.Server.Kitchen.Components; /// /// Attached to a microwave that is currently in the process of cooking /// -[RegisterComponent] +[RegisterComponent, AutoGenerateComponentPause] public sealed partial class ActiveMicrowaveComponent : Component { [ViewVariables(VVAccess.ReadWrite)] @@ -17,6 +17,7 @@ public sealed partial class ActiveMicrowaveComponent : Component [ViewVariables(VVAccess.ReadWrite)] [DataField(customTypeSerializer: typeof(TimeOffsetSerializer))] + [AutoPausedField] public TimeSpan MalfunctionTime = TimeSpan.Zero; [ViewVariables] diff --git a/Content.Server/Kitchen/EntitySystems/MicrowaveSystem.cs b/Content.Server/Kitchen/EntitySystems/MicrowaveSystem.cs index cf3544a7e1..212383c463 100644 --- a/Content.Server/Kitchen/EntitySystems/MicrowaveSystem.cs +++ b/Content.Server/Kitchen/EntitySystems/MicrowaveSystem.cs @@ -86,7 +86,6 @@ namespace Content.Server.Kitchen.EntitySystems SubscribeLocalEvent(OnCookStart); SubscribeLocalEvent(OnCookStop); - SubscribeLocalEvent(OnEntityUnpaused); SubscribeLocalEvent(OnActiveMicrowaveInsert); SubscribeLocalEvent(OnActiveMicrowaveRemove); @@ -112,11 +111,6 @@ namespace Content.Server.Kitchen.EntitySystems microwaveComponent.PlayingStream = _audio.Stop(microwaveComponent.PlayingStream); } - private void OnEntityUnpaused(Entity ent, ref EntityUnpausedEvent args) - { - ent.Comp.MalfunctionTime += args.PausedTime; - } - private void OnActiveMicrowaveInsert(Entity ent, ref EntInsertedIntoContainerMessage args) { AddComp(args.Entity); diff --git a/Content.Server/Magic/MagicSystem.cs b/Content.Server/Magic/MagicSystem.cs index d8febe0d1f..2c9b11dbd3 100644 --- a/Content.Server/Magic/MagicSystem.cs +++ b/Content.Server/Magic/MagicSystem.cs @@ -36,7 +36,6 @@ public sealed class MagicSystem : EntitySystem [Dependency] private readonly IComponentFactory _compFact = default!; [Dependency] private readonly IMapManager _mapManager = default!; [Dependency] private readonly IRobustRandom _random = default!; - [Dependency] private readonly DoorBoltSystem _boltsSystem = default!; [Dependency] private readonly BodySystem _bodySystem = default!; [Dependency] private readonly EntityLookupSystem _lookup = default!; [Dependency] private readonly SharedDoorSystem _doorSystem = default!; @@ -307,7 +306,7 @@ public sealed class MagicSystem : EntitySystem foreach (var entity in _lookup.GetEntitiesInRange(coords, args.Range)) { if (TryComp(entity, out var bolts)) - _boltsSystem.SetBoltsDown(entity, bolts, false); + _doorSystem.SetBoltsDown((entity, bolts), false); if (TryComp(entity, out var doorComp) && doorComp.State is not DoorState.Open) _doorSystem.StartOpening(entity); diff --git a/Content.Server/Medical/Components/HealthAnalyzerComponent.cs b/Content.Server/Medical/Components/HealthAnalyzerComponent.cs index a7fed0cae3..6380b71c8a 100644 --- a/Content.Server/Medical/Components/HealthAnalyzerComponent.cs +++ b/Content.Server/Medical/Components/HealthAnalyzerComponent.cs @@ -6,7 +6,7 @@ namespace Content.Server.Medical.Components; /// /// After scanning, retrieves the target Uid to use with its related UI. /// -[RegisterComponent] +[RegisterComponent, AutoGenerateComponentPause] [Access(typeof(HealthAnalyzerSystem), typeof(CryoPodSystem))] public sealed partial class HealthAnalyzerComponent : Component { @@ -14,6 +14,7 @@ public sealed partial class HealthAnalyzerComponent : Component /// When should the next update be sent for the patient /// [DataField(customTypeSerializer: typeof(TimeOffsetSerializer))] + [AutoPausedField] public TimeSpan NextUpdate = TimeSpan.Zero; /// diff --git a/Content.Server/Medical/DefibrillatorSystem.cs b/Content.Server/Medical/DefibrillatorSystem.cs index e6ef8bf96a..467085f49e 100644 --- a/Content.Server/Medical/DefibrillatorSystem.cs +++ b/Content.Server/Medical/DefibrillatorSystem.cs @@ -50,21 +50,12 @@ public sealed class DefibrillatorSystem : EntitySystem /// public override void Initialize() { - SubscribeLocalEvent(OnUnpaused); SubscribeLocalEvent(OnUseInHand); SubscribeLocalEvent(OnPowerCellSlotEmpty); SubscribeLocalEvent(OnAfterInteract); SubscribeLocalEvent(OnDoAfter); } - private void OnUnpaused(EntityUid uid, DefibrillatorComponent component, ref EntityUnpausedEvent args) - { - if (component.NextZapTime == null) - return; - - component.NextZapTime = component.NextZapTime.Value + args.PausedTime; - } - private void OnUseInHand(EntityUid uid, DefibrillatorComponent component, UseInHandEvent args) { if (args.Handled || !TryComp(uid, out UseDelayComponent? useDelay) || _useDelay.IsDelayed((uid, useDelay))) diff --git a/Content.Server/Medical/HealthAnalyzerSystem.cs b/Content.Server/Medical/HealthAnalyzerSystem.cs index 5c7d265e61..a8abc4752d 100644 --- a/Content.Server/Medical/HealthAnalyzerSystem.cs +++ b/Content.Server/Medical/HealthAnalyzerSystem.cs @@ -30,7 +30,6 @@ public sealed class HealthAnalyzerSystem : EntitySystem public override void Initialize() { - SubscribeLocalEvent(OnEntityUnpaused); SubscribeLocalEvent(OnAfterInteract); SubscribeLocalEvent(OnDoAfter); SubscribeLocalEvent(OnInsertedIntoContainer); @@ -65,11 +64,6 @@ public sealed class HealthAnalyzerSystem : EntitySystem } } - private void OnEntityUnpaused(Entity ent, ref EntityUnpausedEvent args) - { - ent.Comp.NextUpdate += args.PausedTime; - } - /// /// Trigger the doafter for scanning /// diff --git a/Content.Server/Medical/SuitSensors/SuitSensorComponent.cs b/Content.Server/Medical/SuitSensors/SuitSensorComponent.cs index 5de11f848c..9079655c80 100644 --- a/Content.Server/Medical/SuitSensors/SuitSensorComponent.cs +++ b/Content.Server/Medical/SuitSensors/SuitSensorComponent.cs @@ -7,7 +7,7 @@ namespace Content.Server.Medical.SuitSensors; /// Tracking device, embedded in almost all uniforms and jumpsuits. /// If enabled, will report to crew monitoring console owners position and status. /// -[RegisterComponent] +[RegisterComponent, AutoGenerateComponentPause] [Access(typeof(SuitSensorSystem))] public sealed partial class SuitSensorComponent : Component { @@ -57,6 +57,7 @@ public sealed partial class SuitSensorComponent : Component /// Next time when sensor updated owners status /// [DataField("nextUpdate", customTypeSerializer:typeof(TimeOffsetSerializer))] + [AutoPausedField] public TimeSpan NextUpdate = TimeSpan.Zero; /// diff --git a/Content.Server/Medical/SuitSensors/SuitSensorSystem.cs b/Content.Server/Medical/SuitSensors/SuitSensorSystem.cs index 38a7b0a451..94ecf5fd0e 100644 --- a/Content.Server/Medical/SuitSensors/SuitSensorSystem.cs +++ b/Content.Server/Medical/SuitSensors/SuitSensorSystem.cs @@ -40,7 +40,6 @@ public sealed class SuitSensorSystem : EntitySystem base.Initialize(); SubscribeLocalEvent(OnPlayerSpawn); SubscribeLocalEvent(OnMapInit); - SubscribeLocalEvent(OnUnpaused); SubscribeLocalEvent(OnEquipped); SubscribeLocalEvent(OnUnequipped); SubscribeLocalEvent(OnExamine); @@ -51,11 +50,6 @@ public sealed class SuitSensorSystem : EntitySystem SubscribeLocalEvent(OnEmpFinished); } - private void OnUnpaused(EntityUid uid, SuitSensorComponent component, ref EntityUnpausedEvent args) - { - component.NextUpdate += args.PausedTime; - } - public override void Update(float frameTime) { base.Update(frameTime); diff --git a/Content.Server/NPC/Components/NPCJukeComponent.cs b/Content.Server/NPC/Components/NPCJukeComponent.cs index 4cbd8017f2..2c4136c24b 100644 --- a/Content.Server/NPC/Components/NPCJukeComponent.cs +++ b/Content.Server/NPC/Components/NPCJukeComponent.cs @@ -3,7 +3,7 @@ using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom; namespace Content.Server.NPC.Components; -[RegisterComponent] +[RegisterComponent, AutoGenerateComponentPause] public sealed partial class NPCJukeComponent : Component { [DataField("jukeType")] @@ -13,6 +13,7 @@ public sealed partial class NPCJukeComponent : Component public float JukeDuration = 0.5f; [DataField("nextJuke", customTypeSerializer:typeof(TimeOffsetSerializer))] + [AutoPausedField] public TimeSpan NextJuke; [DataField("targetTile")] diff --git a/Content.Server/NPC/Components/NPCSteeringComponent.cs b/Content.Server/NPC/Components/NPCSteeringComponent.cs index 52f96e9c55..397b7fb032 100644 --- a/Content.Server/NPC/Components/NPCSteeringComponent.cs +++ b/Content.Server/NPC/Components/NPCSteeringComponent.cs @@ -11,7 +11,7 @@ namespace Content.Server.NPC.Components; /// /// Added to NPCs that are moving. /// -[RegisterComponent] +[RegisterComponent, AutoGenerateComponentPause] public sealed partial class NPCSteeringComponent : Component { #region Context Steering @@ -49,6 +49,7 @@ public sealed partial class NPCSteeringComponent : Component /// Next time we can change our steering direction. /// [DataField("nextSteer", customTypeSerializer:typeof(TimeOffsetSerializer))] + [AutoPausedField] public TimeSpan NextSteer = TimeSpan.Zero; [DataField("lastSteerIndex")] @@ -66,6 +67,7 @@ public sealed partial class NPCSteeringComponent : Component public EntityCoordinates LastStuckCoordinates; [DataField("lastStuckTime", customTypeSerializer:typeof(TimeOffsetSerializer))] + [AutoPausedField] public TimeSpan LastStuckTime; public const float StuckDistance = 1f; diff --git a/Content.Server/NPC/Pathfinding/GridPathfindingComponent.cs b/Content.Server/NPC/Pathfinding/GridPathfindingComponent.cs index 335a2bbaa1..dac07ea842 100644 --- a/Content.Server/NPC/Pathfinding/GridPathfindingComponent.cs +++ b/Content.Server/NPC/Pathfinding/GridPathfindingComponent.cs @@ -5,7 +5,7 @@ namespace Content.Server.NPC.Pathfinding; /// /// Stores the relevant pathfinding data for grids. /// -[RegisterComponent, Access(typeof(PathfindingSystem))] +[RegisterComponent, Access(typeof(PathfindingSystem)), AutoGenerateComponentPause] public sealed partial class GridPathfindingComponent : Component { [ViewVariables] @@ -15,6 +15,7 @@ public sealed partial class GridPathfindingComponent : Component /// Next time the graph is allowed to update. /// /// Removing this datafield is the lazy fix HOWEVER I want to purge this anyway and do pathfinding at runtime. + [AutoPausedField] public TimeSpan NextUpdate; [ViewVariables] diff --git a/Content.Server/NPC/Pathfinding/PathfindingSystem.Grid.cs b/Content.Server/NPC/Pathfinding/PathfindingSystem.Grid.cs index c27947dedb..6462c10fe5 100644 --- a/Content.Server/NPC/Pathfinding/PathfindingSystem.Grid.cs +++ b/Content.Server/NPC/Pathfinding/PathfindingSystem.Grid.cs @@ -44,7 +44,6 @@ public sealed partial class PathfindingSystem { SubscribeLocalEvent(OnGridInit); SubscribeLocalEvent(OnGridRemoved); - SubscribeLocalEvent(OnGridPathPause); SubscribeLocalEvent(OnGridPathShutdown); SubscribeLocalEvent(OnCollisionChange); SubscribeLocalEvent(OnCollisionLayerChange); @@ -61,10 +60,6 @@ public sealed partial class PathfindingSystem DirtyChunk(ev.Entity, Comp(ev.Entity).GridTileToLocal(ev.NewTile.GridIndices)); } - private void OnGridPathPause(EntityUid uid, GridPathfindingComponent component, ref EntityUnpausedEvent args) - { - component.NextUpdate += args.PausedTime; - } private void OnGridPathShutdown(EntityUid uid, GridPathfindingComponent component, ComponentShutdown args) { diff --git a/Content.Server/NPC/Systems/NPCJukeSystem.cs b/Content.Server/NPC/Systems/NPCJukeSystem.cs index 19f566405a..da9fa1f761 100644 --- a/Content.Server/NPC/Systems/NPCJukeSystem.cs +++ b/Content.Server/NPC/Systems/NPCJukeSystem.cs @@ -33,15 +33,9 @@ public sealed class NPCJukeSystem : EntitySystem _npcRangedQuery = GetEntityQuery(); _physicsQuery = GetEntityQuery(); - SubscribeLocalEvent(OnJukeUnpaused); SubscribeLocalEvent(OnJukeSteering); } - private void OnJukeUnpaused(EntityUid uid, NPCJukeComponent component, ref EntityUnpausedEvent args) - { - component.NextJuke += args.PausedTime; - } - private void OnJukeSteering(EntityUid uid, NPCJukeComponent component, ref NPCSteeringEvent args) { if (component.JukeType == JukeType.AdjacentTile) diff --git a/Content.Server/NPC/Systems/NPCSteeringSystem.cs b/Content.Server/NPC/Systems/NPCSteeringSystem.cs index 149a330919..aca2411d8a 100644 --- a/Content.Server/NPC/Systems/NPCSteeringSystem.cs +++ b/Content.Server/NPC/Systems/NPCSteeringSystem.cs @@ -107,7 +107,6 @@ public sealed partial class NPCSteeringSystem : SharedNPCSteeringSystem Subs.CVar(_configManager, CCVars.NPCPathfinding, SetNPCPathfinding, true); SubscribeLocalEvent(OnSteeringShutdown); - SubscribeLocalEvent(OnSteeringUnpaused); SubscribeNetworkEvent(OnDebugRequest); } @@ -158,12 +157,6 @@ public sealed partial class NPCSteeringSystem : SharedNPCSteeringSystem component.PathfindToken = null; } - private void OnSteeringUnpaused(EntityUid uid, NPCSteeringComponent component, ref EntityUnpausedEvent args) - { - component.LastStuckTime += args.PausedTime; - component.NextSteer += args.PausedTime; - } - /// /// Adds the AI to the steering system to move towards a specific target /// diff --git a/Content.Server/Nutrition/Components/FatExtractorComponent.cs b/Content.Server/Nutrition/Components/FatExtractorComponent.cs index bf81a173e4..e23c557236 100644 --- a/Content.Server/Nutrition/Components/FatExtractorComponent.cs +++ b/Content.Server/Nutrition/Components/FatExtractorComponent.cs @@ -10,7 +10,7 @@ namespace Content.Server.Nutrition.Components; /// /// This is used for a machine that extracts hunger from entities and creates meat. Yum! /// -[RegisterComponent, Access(typeof(FatExtractorSystem))] +[RegisterComponent, Access(typeof(FatExtractorSystem)), AutoGenerateComponentPause] public sealed partial class FatExtractorComponent : Component { /// @@ -48,6 +48,7 @@ public sealed partial class FatExtractorComponent : Component /// When the next update will occur /// [DataField("nextUpdate", customTypeSerializer: typeof(TimeOffsetSerializer)), ViewVariables(VVAccess.ReadWrite)] + [AutoPausedField] public TimeSpan NextUpdate; /// diff --git a/Content.Server/Nutrition/EntitySystems/AnimalHusbandrySystem.cs b/Content.Server/Nutrition/EntitySystems/AnimalHusbandrySystem.cs index 1271c57a23..d0fcd11359 100644 --- a/Content.Server/Nutrition/EntitySystems/AnimalHusbandrySystem.cs +++ b/Content.Server/Nutrition/EntitySystems/AnimalHusbandrySystem.cs @@ -40,23 +40,11 @@ public sealed class AnimalHusbandrySystem : EntitySystem /// public override void Initialize() { - SubscribeLocalEvent(OnUnpaused); SubscribeLocalEvent(OnMindAdded); - SubscribeLocalEvent(OnInfantUnpaused); SubscribeLocalEvent(OnInfantStartup); SubscribeLocalEvent(OnInfantShutdown); } - private void OnUnpaused(EntityUid uid, ReproductiveComponent component, ref EntityUnpausedEvent args) - { - component.NextBreedAttempt += args.PausedTime; - } - - private void OnInfantUnpaused(EntityUid uid, InfantComponent component, ref EntityUnpausedEvent args) - { - component.InfantEndTime += args.PausedTime; - } - // we express EZ-pass terminate the pregnancy if a player takes the role private void OnMindAdded(EntityUid uid, ReproductiveComponent component, MindAddedMessage args) { diff --git a/Content.Server/Nutrition/EntitySystems/DrinkSystem.cs b/Content.Server/Nutrition/EntitySystems/DrinkSystem.cs index f41ca44437..925e50b949 100644 --- a/Content.Server/Nutrition/EntitySystems/DrinkSystem.cs +++ b/Content.Server/Nutrition/EntitySystems/DrinkSystem.cs @@ -130,21 +130,18 @@ public sealed class DrinkSystem : EntitySystem private void OnExamined(Entity entity, ref ExaminedEvent args) { - var hasOpenable = TryComp(entity, out var openable); + TryComp(entity, out var openable); if (_openable.IsClosed(entity.Owner, null, openable) || !args.IsInDetailsRange || !entity.Comp.Examinable) return; - // put Empty / Xu after Opened, or start a new line - args.AddMarkup(hasOpenable ? " - " : "\n"); - var empty = IsEmpty(entity, entity.Comp); if (empty) { - args.AddMarkup(Loc.GetString("drink-component-on-examine-is-empty")); + args.PushMarkup(Loc.GetString("drink-component-on-examine-is-empty")); return; } - if (TryComp(entity, out var comp)) + if (HasComp(entity)) { //provide exact measurement for beakers args.PushText(Loc.GetString("drink-component-on-examine-exact-volume", ("amount", DrinkVolume(entity, entity.Comp)))); @@ -159,7 +156,7 @@ public sealed class DrinkSystem : EntitySystem > 33 => HalfEmptyOrHalfFull(args), _ => "drink-component-on-examine-is-mostly-empty", }; - args.AddMarkup(Loc.GetString(remainingString)); + args.PushMarkup(Loc.GetString(remainingString)); } } diff --git a/Content.Server/Nutrition/EntitySystems/FatExtractorSystem.cs b/Content.Server/Nutrition/EntitySystems/FatExtractorSystem.cs index 4bd8c94ac8..180e40d1e4 100644 --- a/Content.Server/Nutrition/EntitySystems/FatExtractorSystem.cs +++ b/Content.Server/Nutrition/EntitySystems/FatExtractorSystem.cs @@ -27,18 +27,12 @@ public sealed class FatExtractorSystem : EntitySystem /// public override void Initialize() { - SubscribeLocalEvent(OnUnpaused); SubscribeLocalEvent(OnGotEmagged); SubscribeLocalEvent(OnClosed); SubscribeLocalEvent(OnOpen); SubscribeLocalEvent(OnPowerChanged); } - private void OnUnpaused(EntityUid uid, FatExtractorComponent component, ref EntityUnpausedEvent args) - { - component.NextUpdate += args.PausedTime; - } - private void OnGotEmagged(EntityUid uid, FatExtractorComponent component, ref GotEmaggedEvent args) { args.Handled = true; diff --git a/Content.Server/Nutrition/EntitySystems/OpenableSystem.cs b/Content.Server/Nutrition/EntitySystems/OpenableSystem.cs index 373b97700f..8037b61572 100644 --- a/Content.Server/Nutrition/EntitySystems/OpenableSystem.cs +++ b/Content.Server/Nutrition/EntitySystems/OpenableSystem.cs @@ -1,16 +1,6 @@ using Content.Server.Chemistry.EntitySystems; -using Content.Server.Fluids.EntitySystems; using Content.Shared.Nutrition.EntitySystems; -using Content.Server.Nutrition.Components; -using Content.Shared.Examine; -using Content.Shared.Interaction; -using Content.Shared.Interaction.Events; using Content.Shared.Nutrition.Components; -using Content.Shared.Popups; -using Content.Shared.Verbs; -using Content.Shared.Weapons.Melee.Events; -using Robust.Shared.Audio.Systems; -using Robust.Shared.Utility; namespace Content.Server.Nutrition.EntitySystems; @@ -19,43 +9,11 @@ namespace Content.Server.Nutrition.EntitySystems; /// public sealed class OpenableSystem : SharedOpenableSystem { - [Dependency] private readonly SharedAppearanceSystem _appearance = default!; - [Dependency] private readonly SharedAudioSystem _audio = default!; - [Dependency] private readonly SharedPopupSystem _popup = default!; - public override void Initialize() { base.Initialize(); - SubscribeLocalEvent(OnInit); - SubscribeLocalEvent(OnUse); - SubscribeLocalEvent(OnExamined, after: new[] { typeof(PuddleSystem) }); SubscribeLocalEvent(OnTransferAttempt); - SubscribeLocalEvent(HandleIfClosed); - SubscribeLocalEvent(HandleIfClosed); - SubscribeLocalEvent>(AddOpenCloseVerbs); - } - - private void OnInit(EntityUid uid, OpenableComponent comp, ComponentInit args) - { - UpdateAppearance(uid, comp); - } - - private void OnUse(EntityUid uid, OpenableComponent comp, UseInHandEvent args) - { - if (args.Handled || !comp.OpenableByHand) - return; - - args.Handled = TryOpen(uid, comp); - } - - private void OnExamined(EntityUid uid, OpenableComponent comp, ExaminedEvent args) - { - if (!comp.Opened || !args.IsInDetailsRange) - return; - - var text = Loc.GetString(comp.ExamineText); - args.PushMarkup(text); } private void OnTransferAttempt(EntityUid uid, OpenableComponent comp, SolutionTransferAttemptEvent args) @@ -66,135 +24,4 @@ public sealed class OpenableSystem : SharedOpenableSystem args.Cancel(Loc.GetString("drink-component-try-use-drink-not-open", ("owner", uid))); } } - - private void HandleIfClosed(EntityUid uid, OpenableComponent comp, HandledEntityEventArgs args) - { - // prevent spilling/pouring/whatever drinks when closed - args.Handled = !comp.Opened; - } - - private void AddOpenCloseVerbs(EntityUid uid, OpenableComponent comp, GetVerbsEvent args) - { - if (args.Hands == null || !args.CanAccess || !args.CanInteract) - return; - - Verb verb; - if (comp.Opened) - { - if (!comp.Closeable) - return; - - verb = new() - { - Text = Loc.GetString(comp.CloseVerbText), - Icon = new SpriteSpecifier.Texture(new("/Textures/Interface/VerbIcons/close.svg.192dpi.png")), - Act = () => TryClose(args.Target, comp) - }; - } - else - { - verb = new() - { - Text = Loc.GetString(comp.OpenVerbText), - Icon = new SpriteSpecifier.Texture(new("/Textures/Interface/VerbIcons/open.svg.192dpi.png")), - Act = () => TryOpen(args.Target, comp) - }; - } - args.Verbs.Add(verb); - } - - /// - /// Returns true if the entity either does not have OpenableComponent or it is opened. - /// Drinks that don't have OpenableComponent are automatically open, so it returns true. - /// - public bool IsOpen(EntityUid uid, OpenableComponent? comp = null) - { - if (!Resolve(uid, ref comp, false)) - return true; - - return comp.Opened; - } - - /// - /// Returns true if the entity both has OpenableComponent and is not opened. - /// Drinks that don't have OpenableComponent are automatically open, so it returns false. - /// If user is not null a popup will be shown to them. - /// - public bool IsClosed(EntityUid uid, EntityUid? user = null, OpenableComponent? comp = null) - { - if (!Resolve(uid, ref comp, false)) - return false; - - if (comp.Opened) - return false; - - if (user != null) - _popup.PopupEntity(Loc.GetString(comp.ClosedPopup, ("owner", uid)), user.Value, user.Value); - - return true; - } - - /// - /// Update open visuals to the current value. - /// - public void UpdateAppearance(EntityUid uid, OpenableComponent? comp = null, AppearanceComponent? appearance = null) - { - if (!Resolve(uid, ref comp)) - return; - - _appearance.SetData(uid, OpenableVisuals.Opened, comp.Opened, appearance); - } - - /// - /// Sets the opened field and updates open visuals. - /// - public void SetOpen(EntityUid uid, bool opened = true, OpenableComponent? comp = null) - { - if (!Resolve(uid, ref comp, false) || opened == comp.Opened) - return; - - comp.Opened = opened; - - if (opened) - { - var ev = new OpenableOpenedEvent(); - RaiseLocalEvent(uid, ref ev); - } - else - { - var ev = new OpenableClosedEvent(); - RaiseLocalEvent(uid, ref ev); - } - - UpdateAppearance(uid, comp); - } - - /// - /// If closed, opens it and plays the sound. - /// - /// Whether it got opened - public bool TryOpen(EntityUid uid, OpenableComponent? comp = null) - { - if (!Resolve(uid, ref comp, false) || comp.Opened) - return false; - - SetOpen(uid, true, comp); - _audio.PlayPvs(comp.Sound, uid); - return true; - } - - /// - /// If opened, closes it and plays the close sound, if one is defined. - /// - /// Whether it got closed - public bool TryClose(EntityUid uid, OpenableComponent? comp = null) - { - if (!Resolve(uid, ref comp, false) || !comp.Opened || !comp.Closeable) - return false; - - SetOpen(uid, false, comp); - if (comp.CloseSound != null) - _audio.PlayPvs(comp.CloseSound, uid); - return true; - } } diff --git a/Content.Server/Parallax/BiomeSystem.cs b/Content.Server/Parallax/BiomeSystem.cs index 0b8c7a4d82..c4c2300870 100644 --- a/Content.Server/Parallax/BiomeSystem.cs +++ b/Content.Server/Parallax/BiomeSystem.cs @@ -29,6 +29,7 @@ using Robust.Shared.Prototypes; using Robust.Shared.Random; using Robust.Shared.Threading; using Robust.Shared.Utility; +using ChunkIndicesEnumerator = Robust.Shared.Map.Enumerators.ChunkIndicesEnumerator; namespace Content.Server.Parallax; diff --git a/Content.Server/Physics/Components/ChasingWalkComponent.cs b/Content.Server/Physics/Components/ChasingWalkComponent.cs index ca7a027544..222c9d64db 100644 --- a/Content.Server/Physics/Components/ChasingWalkComponent.cs +++ b/Content.Server/Physics/Components/ChasingWalkComponent.cs @@ -8,13 +8,14 @@ namespace Content.Server.Physics.Components; /// /// A component which makes its entity chasing entity with selected component. /// -[RegisterComponent, Access(typeof(ChasingWalkSystem))] +[RegisterComponent, Access(typeof(ChasingWalkSystem)), AutoGenerateComponentPause] public sealed partial class ChasingWalkComponent : Component { /// /// The next moment in time when the entity is pushed toward its goal /// [DataField, ViewVariables(VVAccess.ReadWrite)] + [AutoPausedField] public TimeSpan NextImpulseTime; /// @@ -57,6 +58,7 @@ public sealed partial class ChasingWalkComponent : Component /// The next change of direction time. /// [DataField(customTypeSerializer: typeof(TimeOffsetSerializer)), ViewVariables(VVAccess.ReadWrite)] + [AutoPausedField] public TimeSpan NextChangeVectorTime; /// diff --git a/Content.Server/Physics/Controllers/ChasingWalkSystem.cs b/Content.Server/Physics/Controllers/ChasingWalkSystem.cs index 8835b44ab7..215e7e3124 100644 --- a/Content.Server/Physics/Controllers/ChasingWalkSystem.cs +++ b/Content.Server/Physics/Controllers/ChasingWalkSystem.cs @@ -27,7 +27,6 @@ public sealed class ChasingWalkSystem : VirtualController base.Initialize(); SubscribeLocalEvent(OnChasingMapInit); - SubscribeLocalEvent(OnChasingUnpaused); } private void OnChasingMapInit(EntityUid uid, ChasingWalkComponent component, MapInitEvent args) @@ -36,12 +35,6 @@ public sealed class ChasingWalkSystem : VirtualController component.NextChangeVectorTime = _gameTiming.CurTime; } - private void OnChasingUnpaused(EntityUid uid, ChasingWalkComponent component, ref EntityUnpausedEvent args) - { - component.NextImpulseTime += args.PausedTime; - component.NextChangeVectorTime += args.PausedTime; - } - public override void UpdateBeforeSolve(bool prediction, float frameTime) { base.UpdateBeforeSolve(prediction, frameTime); diff --git a/Content.Server/PowerCell/PowerCellSystem.Draw.cs b/Content.Server/PowerCell/PowerCellSystem.Draw.cs index c6d8e1e709..8e960357b7 100644 --- a/Content.Server/PowerCell/PowerCellSystem.Draw.cs +++ b/Content.Server/PowerCell/PowerCellSystem.Draw.cs @@ -39,11 +39,6 @@ public sealed partial class PowerCellSystem } } - private void OnUnpaused(EntityUid uid, PowerCellDrawComponent component, ref EntityUnpausedEvent args) - { - component.NextUpdateTime += args.PausedTime; - } - private void OnDrawChargeChanged(EntityUid uid, PowerCellDrawComponent component, ref ChargeChangedEvent args) { // Update the bools for client prediction. diff --git a/Content.Server/PowerCell/PowerCellSystem.cs b/Content.Server/PowerCell/PowerCellSystem.cs index b424f34de5..d501a1bda3 100644 --- a/Content.Server/PowerCell/PowerCellSystem.cs +++ b/Content.Server/PowerCell/PowerCellSystem.cs @@ -35,7 +35,6 @@ public sealed partial class PowerCellSystem : SharedPowerCellSystem SubscribeLocalEvent(OnCellExamined); SubscribeLocalEvent(OnCellEmpAttempt); - SubscribeLocalEvent(OnUnpaused); SubscribeLocalEvent(OnDrawChargeChanged); SubscribeLocalEvent(OnDrawCellChanged); diff --git a/Content.Server/PowerSink/PowerSinkComponent.cs b/Content.Server/PowerSink/PowerSinkComponent.cs index f1df042179..a55d368c6e 100644 --- a/Content.Server/PowerSink/PowerSinkComponent.cs +++ b/Content.Server/PowerSink/PowerSinkComponent.cs @@ -6,7 +6,7 @@ namespace Content.Server.PowerSink /// /// Absorbs power up to its capacity when anchored then explodes. /// - [RegisterComponent] + [RegisterComponent, AutoGenerateComponentPause] public sealed partial class PowerSinkComponent : Component { /// @@ -21,6 +21,7 @@ namespace Content.Server.PowerSink /// If explosion has been triggered, time at which to explode. /// [DataField("explosionTime", customTypeSerializer:typeof(TimeOffsetSerializer))] + [AutoPausedField] public System.TimeSpan? ExplosionTime = null; /// diff --git a/Content.Server/PowerSink/PowerSinkSystem.cs b/Content.Server/PowerSink/PowerSinkSystem.cs index deb6693500..dddfd33967 100644 --- a/Content.Server/PowerSink/PowerSinkSystem.cs +++ b/Content.Server/PowerSink/PowerSinkSystem.cs @@ -37,7 +37,6 @@ namespace Content.Server.PowerSink base.Initialize(); SubscribeLocalEvent(OnExamine); - SubscribeLocalEvent(OnUnpaused); } private void OnExamine(EntityUid uid, PowerSinkComponent component, ExaminedEvent args) @@ -54,14 +53,6 @@ namespace Content.Server.PowerSink ); } - private void OnUnpaused(EntityUid uid, PowerSinkComponent component, ref EntityUnpausedEvent args) - { - if (component.ExplosionTime == null) - return; - - component.ExplosionTime = component.ExplosionTime + args.PausedTime; - } - public override void Update(float frameTime) { var toRemove = new RemQueue<(EntityUid Entity, PowerSinkComponent Sink)>(); diff --git a/Content.Server/Preferences/Managers/ServerPreferencesManager.cs b/Content.Server/Preferences/Managers/ServerPreferencesManager.cs index f25883a07c..cd800e21b2 100644 --- a/Content.Server/Preferences/Managers/ServerPreferencesManager.cs +++ b/Content.Server/Preferences/Managers/ServerPreferencesManager.cs @@ -107,7 +107,7 @@ namespace Content.Server.Preferences.Managers var sponsorPrototypes = _sponsors != null && _sponsors.TryGetPrototypes(message.MsgChannel.UserId, out var prototypes) ? prototypes.ToArray() : new string[]{}; - profile.EnsureValid(sponsorPrototypes); + profile.EnsureValid(_cfg, _protos, sponsorPrototypes); // Corvax-Sponsors-End var profiles = new Dictionary(curPrefs.Characters) { @@ -295,34 +295,7 @@ namespace Content.Server.Preferences.Managers return new PlayerPreferences(prefs.Characters.Select(p => { - ICharacterProfile newProf; - switch (p.Value) - { - case HumanoidCharacterProfile hp: - { - var prototypeManager = IoCManager.Resolve(); - var selectedSpecies = HumanoidAppearanceSystem.DefaultSpecies; - - if (prototypeManager.TryIndex(hp.Species, out var species) && species.RoundStart) - { - selectedSpecies = hp.Species; - } - - newProf = hp - .WithJobPriorities( - hp.JobPriorities.Where(job => - _protos.HasIndex(job.Key))) - .WithAntagPreferences( - hp.AntagPreferences.Where(antag => - _protos.HasIndex(antag))) - .WithSpecies(selectedSpecies); - break; - } - default: - throw new NotSupportedException(); - } - - return new KeyValuePair(p.Key, newProf); + return new KeyValuePair(p.Key, p.Value.Validated(_cfg, _protos)); }), prefs.SelectedCharacterIndex, prefs.AdminOOCColor); } diff --git a/Content.Server/Remotes/DoorRemoteSystem.cs b/Content.Server/Remotes/DoorRemoteSystem.cs index a88508ce53..9be7e5e96b 100644 --- a/Content.Server/Remotes/DoorRemoteSystem.cs +++ b/Content.Server/Remotes/DoorRemoteSystem.cs @@ -18,7 +18,6 @@ namespace Content.Server.Remotes public sealed class DoorRemoteSystem : EntitySystem { [Dependency] private readonly IAdminLogManager _adminLogger = default!; - [Dependency] private readonly DoorBoltSystem _bolts = default!; [Dependency] private readonly AirlockSystem _airlock = default!; [Dependency] private readonly SharedPopupSystem _popupSystem = default!; [Dependency] private readonly DoorSystem _doorSystem = default!; @@ -105,7 +104,7 @@ namespace Content.Server.Remotes { if (!boltsComp.BoltWireCut) { - _bolts.SetBoltsWithAudio(args.Target.Value, boltsComp, !boltsComp.BoltsDown); + _doorSystem.SetBoltsDown((args.Target.Value, boltsComp), !boltsComp.BoltsDown, args.User); _adminLogger.Add(LogType.Action, LogImpact.Medium, $"{ToPrettyString(args.User):player} used {ToPrettyString(args.Used)} on {ToPrettyString(args.Target.Value)} to {(boltsComp.BoltsDown ? "" : "un")}bolt it"); } } diff --git a/Content.Server/RequiresGrid/RequiresGridComponent.cs b/Content.Server/RequiresGrid/RequiresGridComponent.cs new file mode 100644 index 0000000000..0e956c9ad9 --- /dev/null +++ b/Content.Server/RequiresGrid/RequiresGridComponent.cs @@ -0,0 +1,11 @@ +namespace Content.Server.RequiresGrid; + +/// +/// Destroys an entity when they no longer are part of a Grid +/// +[RegisterComponent] +[Access(typeof(RequiresGridSystem))] +public sealed partial class RequiresGridComponent : Component +{ + +} diff --git a/Content.Server/RequiresGrid/RequiresGridSystem.cs b/Content.Server/RequiresGrid/RequiresGridSystem.cs new file mode 100644 index 0000000000..16a20c9a8a --- /dev/null +++ b/Content.Server/RequiresGrid/RequiresGridSystem.cs @@ -0,0 +1,29 @@ +using Content.Server.Destructible; + +namespace Content.Server.RequiresGrid; + +public sealed class RequiresGridSystem : EntitySystem +{ + [Dependency] private readonly DestructibleSystem _destructible = default!; + + public override void Initialize() + { + base.Initialize(); + + SubscribeLocalEvent(OnEntParentChanged); + } + + private void OnEntParentChanged(EntityUid owner, RequiresGridComponent component, EntParentChangedMessage args) + { + if (args.OldParent == null) + return; + + if (args.Transform.GridUid != null) + return; + + if (TerminatingOrDeleted(owner)) + return; + + _destructible.DestroyEntity(owner); + } +} diff --git a/Content.Server/Salvage/Expeditions/SalvageExpeditionComponent.cs b/Content.Server/Salvage/Expeditions/SalvageExpeditionComponent.cs index 6d3d831a2d..6a58c209cf 100644 --- a/Content.Server/Salvage/Expeditions/SalvageExpeditionComponent.cs +++ b/Content.Server/Salvage/Expeditions/SalvageExpeditionComponent.cs @@ -11,7 +11,7 @@ namespace Content.Server.Salvage.Expeditions; /// /// Designates this entity as holding a salvage expedition. /// -[RegisterComponent] +[RegisterComponent, AutoGenerateComponentPause] public sealed partial class SalvageExpeditionComponent : SharedSalvageExpeditionComponent { public SalvageMissionParams MissionParams = default!; @@ -26,6 +26,7 @@ public sealed partial class SalvageExpeditionComponent : SharedSalvageExpedition /// When the expeditions ends. /// [ViewVariables(VVAccess.ReadWrite), DataField("endTime", customTypeSerializer: typeof(TimeOffsetSerializer))] + [AutoPausedField] public TimeSpan EndTime; /// diff --git a/Content.Server/Salvage/SalvageSystem.Expeditions.cs b/Content.Server/Salvage/SalvageSystem.Expeditions.cs index 1eb1cc3027..7e4a9c9310 100644 --- a/Content.Server/Salvage/SalvageSystem.Expeditions.cs +++ b/Content.Server/Salvage/SalvageSystem.Expeditions.cs @@ -31,10 +31,7 @@ public sealed partial class SalvageSystem SubscribeLocalEvent(OnSalvageConsoleParent); SubscribeLocalEvent(OnSalvageClaimMessage); - SubscribeLocalEvent(OnDataUnpaused); - SubscribeLocalEvent(OnExpeditionShutdown); - SubscribeLocalEvent(OnExpeditionUnpaused); SubscribeLocalEvent(OnExpeditionGetState); SubscribeLocalEvent(OnStructureExamine); @@ -89,16 +86,6 @@ public sealed partial class SalvageSystem } } - private void OnDataUnpaused(EntityUid uid, SalvageExpeditionDataComponent component, ref EntityUnpausedEvent args) - { - component.NextOffer += args.PausedTime; - } - - private void OnExpeditionUnpaused(EntityUid uid, SalvageExpeditionComponent component, ref EntityUnpausedEvent args) - { - component.EndTime += args.PausedTime; - } - private void UpdateExpeditions() { var currentTime = _timing.CurTime; diff --git a/Content.Server/Shuttles/Components/ArrivalsShuttleComponent.cs b/Content.Server/Shuttles/Components/ArrivalsShuttleComponent.cs index 99cdcbc3b6..b9ff375507 100644 --- a/Content.Server/Shuttles/Components/ArrivalsShuttleComponent.cs +++ b/Content.Server/Shuttles/Components/ArrivalsShuttleComponent.cs @@ -3,13 +3,14 @@ using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom; namespace Content.Server.Shuttles.Components; -[RegisterComponent, Access(typeof(ArrivalsSystem))] +[RegisterComponent, Access(typeof(ArrivalsSystem)), AutoGenerateComponentPause] public sealed partial class ArrivalsShuttleComponent : Component { [DataField("station")] public EntityUid Station; [DataField("nextTransfer", customTypeSerializer: typeof(TimeOffsetSerializer))] + [AutoPausedField] public TimeSpan NextTransfer; [DataField("nextArrivalsTime", customTypeSerializer: typeof(TimeOffsetSerializer))] diff --git a/Content.Server/Shuttles/Components/EscapePodComponent.cs b/Content.Server/Shuttles/Components/EscapePodComponent.cs index d68065fc00..72c8024e12 100644 --- a/Content.Server/Shuttles/Components/EscapePodComponent.cs +++ b/Content.Server/Shuttles/Components/EscapePodComponent.cs @@ -6,9 +6,10 @@ namespace Content.Server.Shuttles.Components; /// /// If added to a grid gets launched when the emergency shuttle launches. /// -[RegisterComponent, Access(typeof(EmergencyShuttleSystem))] +[RegisterComponent, Access(typeof(EmergencyShuttleSystem)), AutoGenerateComponentPause] public sealed partial class EscapePodComponent : Component { [DataField("launchTime", customTypeSerializer:typeof(TimeOffsetSerializer))] + [AutoPausedField] public TimeSpan? LaunchTime; } diff --git a/Content.Server/Shuttles/Systems/ArrivalsSystem.cs b/Content.Server/Shuttles/Systems/ArrivalsSystem.cs index 7d63b83588..037fcc7566 100644 --- a/Content.Server/Shuttles/Systems/ArrivalsSystem.cs +++ b/Content.Server/Shuttles/Systems/ArrivalsSystem.cs @@ -85,7 +85,6 @@ public sealed class ArrivalsSystem : EntitySystem SubscribeLocalEvent(OnArrivalsStartup); SubscribeLocalEvent(OnShuttleStartup); - SubscribeLocalEvent(OnShuttleUnpaused); SubscribeLocalEvent(OnShuttleTag); SubscribeLocalEvent(OnRoundStarting); @@ -384,11 +383,6 @@ public sealed class ArrivalsSystem : EntitySystem EnsureComp(uid); } - private void OnShuttleUnpaused(EntityUid uid, ArrivalsShuttleComponent component, ref EntityUnpausedEvent args) - { - component.NextTransfer += args.PausedTime; - } - private bool TryGetArrivals(out EntityUid uid) { var arrivalsQuery = EntityQueryEnumerator(); diff --git a/Content.Server/Shuttles/Systems/DockingSystem.cs b/Content.Server/Shuttles/Systems/DockingSystem.cs index 778d244376..7f69885045 100644 --- a/Content.Server/Shuttles/Systems/DockingSystem.cs +++ b/Content.Server/Shuttles/Systems/DockingSystem.cs @@ -20,7 +20,6 @@ namespace Content.Server.Shuttles.Systems public sealed partial class DockingSystem : EntitySystem { [Dependency] private readonly IMapManager _mapManager = default!; - [Dependency] private readonly DoorBoltSystem _bolts = default!; [Dependency] private readonly DoorSystem _doorSystem = default!; [Dependency] private readonly FixtureSystem _fixtureSystem = default!; [Dependency] private readonly PathfindingSystem _pathfinding = default!; @@ -363,7 +362,7 @@ namespace Content.Server.Shuttles.Systems doorA.ChangeAirtight = false; if (TryComp(dockAUid, out var airlockA)) { - _bolts.SetBoltsWithAudio(dockAUid, airlockA, true); + _doorSystem.SetBoltsDown((dockAUid, airlockA), true); } } } @@ -375,7 +374,7 @@ namespace Content.Server.Shuttles.Systems doorB.ChangeAirtight = false; if (TryComp(dockBUid, out var airlockB)) { - _bolts.SetBoltsWithAudio(dockBUid, airlockB, true); + _doorSystem.SetBoltsDown((dockBUid, airlockB), true); } } } @@ -470,7 +469,7 @@ namespace Content.Server.Shuttles.Systems return; if (TryComp(dockUid, out var airlock)) - _bolts.SetBoltsWithAudio(dockUid, airlock, false); + _doorSystem.SetBoltsDown((dockUid, airlock), false); if (TryComp(dockUid, out DoorComponent? door) && _doorSystem.TryClose(dockUid, door)) door.ChangeAirtight = true; diff --git a/Content.Server/Shuttles/Systems/EmergencyShuttleSystem.Console.cs b/Content.Server/Shuttles/Systems/EmergencyShuttleSystem.Console.cs index f8e6f2423f..6fb939d94a 100644 --- a/Content.Server/Shuttles/Systems/EmergencyShuttleSystem.Console.cs +++ b/Content.Server/Shuttles/Systems/EmergencyShuttleSystem.Console.cs @@ -93,8 +93,6 @@ public sealed partial class EmergencyShuttleSystem SubscribeLocalEvent(OnEmergencyRepeal); SubscribeLocalEvent(OnEmergencyRepealAll); SubscribeLocalEvent(OnEmergencyOpenAttempt); - - SubscribeLocalEvent(OnEscapeUnpaused); } private void OnEmergencyOpenAttempt(EntityUid uid, EmergencyShuttleConsoleComponent component, ActivatableUIOpenAttemptEvent args) diff --git a/Content.Server/Shuttles/Systems/EmergencyShuttleSystem.cs b/Content.Server/Shuttles/Systems/EmergencyShuttleSystem.cs index 66214b0577..8b2c268300 100644 --- a/Content.Server/Shuttles/Systems/EmergencyShuttleSystem.cs +++ b/Content.Server/Shuttles/Systems/EmergencyShuttleSystem.cs @@ -507,14 +507,6 @@ public sealed partial class EmergencyShuttleSystem : EntitySystem EnsureComp(shuttle.Value); } - private void OnEscapeUnpaused(EntityUid uid, EscapePodComponent component, ref EntityUnpausedEvent args) - { - if (component.LaunchTime == null) - return; - - component.LaunchTime = component.LaunchTime.Value + args.PausedTime; - } - /// /// Returns whether a target is escaping on the emergency shuttle, but only if evac has arrived. /// diff --git a/Content.Server/Shuttles/Systems/ShuttleSystem.FasterThanLight.cs b/Content.Server/Shuttles/Systems/ShuttleSystem.FasterThanLight.cs index 99ce4a044d..d976b634d5 100644 --- a/Content.Server/Shuttles/Systems/ShuttleSystem.FasterThanLight.cs +++ b/Content.Server/Shuttles/Systems/ShuttleSystem.FasterThanLight.cs @@ -459,7 +459,7 @@ public sealed partial class ShuttleSystem continue; _doors.TryClose(doorUid); - _bolts.SetBoltsWithAudio(doorUid, door, enabled); + _doors.SetBoltsDown((doorUid, door), enabled); } } diff --git a/Content.Server/Shuttles/Systems/ShuttleSystem.cs b/Content.Server/Shuttles/Systems/ShuttleSystem.cs index 471b46e507..5f11ce25a4 100644 --- a/Content.Server/Shuttles/Systems/ShuttleSystem.cs +++ b/Content.Server/Shuttles/Systems/ShuttleSystem.cs @@ -34,7 +34,6 @@ public sealed partial class ShuttleSystem : SharedShuttleSystem [Dependency] private readonly BodySystem _bobby = default!; [Dependency] private readonly DockingSystem _dockSystem = default!; [Dependency] private readonly DoorSystem _doors = default!; - [Dependency] private readonly DoorBoltSystem _bolts = default!; [Dependency] private readonly EntityLookupSystem _lookup = default!; [Dependency] private readonly FixtureSystem _fixtures = default!; [Dependency] private readonly MapLoaderSystem _loader = default!; diff --git a/Content.Server/Singularity/EntitySystems/EventHorizonSystem.cs b/Content.Server/Singularity/EntitySystems/EventHorizonSystem.cs index bbe19614a3..e346ae9300 100644 --- a/Content.Server/Singularity/EntitySystems/EventHorizonSystem.cs +++ b/Content.Server/Singularity/EntitySystems/EventHorizonSystem.cs @@ -40,7 +40,6 @@ public sealed class EventHorizonSystem : SharedEventHorizonSystem SubscribeLocalEvent(PreventConsume); SubscribeLocalEvent(PreventConsume); SubscribeLocalEvent(OnHorizonMapInit); - SubscribeLocalEvent(OnHorizonUnpaused); SubscribeLocalEvent(OnStartCollide); SubscribeLocalEvent(OnEventHorizonContained); SubscribeLocalEvent(OnEventHorizonContained); @@ -57,11 +56,6 @@ public sealed class EventHorizonSystem : SharedEventHorizonSystem component.NextConsumeWaveTime = _timing.CurTime; } - private void OnHorizonUnpaused(EntityUid uid, EventHorizonComponent component, ref EntityUnpausedEvent args) - { - component.NextConsumeWaveTime += args.PausedTime; - } - public override void Shutdown() { var vvHandle = Vvm.GetTypeHandler(); diff --git a/Content.Server/Spawners/Components/ContainerSpawnPointComponent.cs b/Content.Server/Spawners/Components/ContainerSpawnPointComponent.cs index 9782becc27..5c8e3c4186 100644 --- a/Content.Server/Spawners/Components/ContainerSpawnPointComponent.cs +++ b/Content.Server/Spawners/Components/ContainerSpawnPointComponent.cs @@ -8,7 +8,7 @@ namespace Content.Server.Spawners.Components; /// [RegisterComponent] [Access(typeof(ContainerSpawnPointSystem))] -public sealed partial class ContainerSpawnPointComponent : Component +public sealed partial class ContainerSpawnPointComponent : Component, ISpawnPoint { /// /// The ID of the container that this entity will spawn players into @@ -26,5 +26,5 @@ public sealed partial class ContainerSpawnPointComponent : Component /// The type of spawn point /// [DataField, ViewVariables(VVAccess.ReadWrite)] - public SpawnPointType SpawnType = SpawnPointType.Unset; + public SpawnPointType SpawnType { get; set; } = SpawnPointType.Unset; } diff --git a/Content.Server/Spawners/Components/ISpawnPoint.cs b/Content.Server/Spawners/Components/ISpawnPoint.cs new file mode 100644 index 0000000000..e01841ef99 --- /dev/null +++ b/Content.Server/Spawners/Components/ISpawnPoint.cs @@ -0,0 +1,7 @@ +namespace Content.Server.Spawners.Components; + +public interface ISpawnPoint +{ + SpawnPointType SpawnType { get; set; } +} + diff --git a/Content.Server/Spawners/Components/SpawnPointComponent.cs b/Content.Server/Spawners/Components/SpawnPointComponent.cs index 5a86175a1d..5cf231f224 100644 --- a/Content.Server/Spawners/Components/SpawnPointComponent.cs +++ b/Content.Server/Spawners/Components/SpawnPointComponent.cs @@ -4,7 +4,7 @@ using Robust.Shared.Prototypes; namespace Content.Server.Spawners.Components; [RegisterComponent] -public sealed partial class SpawnPointComponent : Component +public sealed partial class SpawnPointComponent : Component, ISpawnPoint { [Dependency] private readonly IPrototypeManager _prototypeManager = default!; @@ -12,9 +12,11 @@ public sealed partial class SpawnPointComponent : Component [DataField("job_id")] private string? _jobId; - [ViewVariables(VVAccess.ReadWrite)] - [DataField("spawn_type")] - public SpawnPointType SpawnType { get; private set; } = SpawnPointType.Unset; + /// + /// The type of spawn point + /// + [DataField("spawn_type"), ViewVariables(VVAccess.ReadWrite)] + public SpawnPointType SpawnType { get; set; } = SpawnPointType.Unset; public JobPrototype? Job => string.IsNullOrEmpty(_jobId) ? null : _prototypeManager.Index(_jobId); diff --git a/Content.Server/Spreader/GrowingKudzuComponent.cs b/Content.Server/Spreader/GrowingKudzuComponent.cs index d2cd6d6404..8cda21234f 100644 --- a/Content.Server/Spreader/GrowingKudzuComponent.cs +++ b/Content.Server/Spreader/GrowingKudzuComponent.cs @@ -2,12 +2,13 @@ using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom; namespace Content.Server.Spreader; -[RegisterComponent, Access(typeof(KudzuSystem))] +[RegisterComponent, Access(typeof(KudzuSystem)), AutoGenerateComponentPause] public sealed partial class GrowingKudzuComponent : Component { /// /// The next time kudzu will try to tick its growth level. /// [DataField("nextTick", customTypeSerializer:typeof(TimeOffsetSerializer))] + [AutoPausedField] public TimeSpan NextTick = TimeSpan.Zero; } diff --git a/Content.Server/Spreader/KudzuSystem.cs b/Content.Server/Spreader/KudzuSystem.cs index d15a2c667f..49698ea673 100644 --- a/Content.Server/Spreader/KudzuSystem.cs +++ b/Content.Server/Spreader/KudzuSystem.cs @@ -21,7 +21,6 @@ public sealed class KudzuSystem : EntitySystem { SubscribeLocalEvent(SetupKudzu); SubscribeLocalEvent(OnKudzuSpread); - SubscribeLocalEvent(OnKudzuUnpaused); SubscribeLocalEvent(OnDamageChanged); } @@ -80,11 +79,6 @@ public sealed class KudzuSystem : EntitySystem } } - private void OnKudzuUnpaused(EntityUid uid, GrowingKudzuComponent component, ref EntityUnpausedEvent args) - { - component.NextTick += args.PausedTime; - } - private void SetupKudzu(EntityUid uid, KudzuComponent component, ComponentStartup args) { if (!EntityManager.TryGetComponent(uid, out var appearance)) diff --git a/Content.Server/StationEvents/Components/StationEventComponent.cs b/Content.Server/StationEvents/Components/StationEventComponent.cs index de0dc1c28a..b4456a4b5b 100644 --- a/Content.Server/StationEvents/Components/StationEventComponent.cs +++ b/Content.Server/StationEvents/Components/StationEventComponent.cs @@ -6,7 +6,7 @@ namespace Content.Server.StationEvents.Components; /// /// Defines basic data for a station event /// -[RegisterComponent] +[RegisterComponent, AutoGenerateComponentPause] public sealed partial class StationEventComponent : Component { public const float WeightVeryLow = 0.0f; @@ -79,11 +79,13 @@ public sealed partial class StationEventComponent : Component /// When the station event starts. /// [DataField("startTime", customTypeSerializer: typeof(TimeOffsetSerializer))] + [AutoPausedField] public TimeSpan StartTime; /// /// When the station event ends. /// [DataField("endTime", customTypeSerializer: typeof(TimeOffsetSerializer))] + [AutoPausedField] public TimeSpan? EndTime; } diff --git a/Content.Server/StationEvents/EventManagerSystem.cs b/Content.Server/StationEvents/EventManagerSystem.cs index fb3590dcd5..a0ab037755 100644 --- a/Content.Server/StationEvents/EventManagerSystem.cs +++ b/Content.Server/StationEvents/EventManagerSystem.cs @@ -29,15 +29,6 @@ public sealed class EventManagerSystem : EntitySystem _sawmill = Logger.GetSawmill("events"); Subs.CVar(_configurationManager, CCVars.EventsEnabled, SetEnabled, true); - - SubscribeLocalEvent(OnUnpaused); - } - - private void OnUnpaused(EntityUid uid, StationEventComponent component, ref EntityUnpausedEvent args) - { - component.StartTime += args.PausedTime; - if (component.EndTime != null) - component.EndTime = component.EndTime.Value + args.PausedTime; } /// diff --git a/Content.Server/StationEvents/Events/AnomalySpawnRule.cs b/Content.Server/StationEvents/Events/AnomalySpawnRule.cs index a59af52f6d..48a3b900c4 100644 --- a/Content.Server/StationEvents/Events/AnomalySpawnRule.cs +++ b/Content.Server/StationEvents/Events/AnomalySpawnRule.cs @@ -33,7 +33,7 @@ public sealed class AnomalySpawnRule : StationEventSystem(uid, out var stationEvent)) return; - var mod = MathF.Sqrt(GetSeverityModifier()); - // Essentially we'll pick out a target amount of gas to leak, then a rate to leak it at, then work out the duration from there. if (TryFindRandomTile(out component.TargetTile, out var target, out component.TargetGrid, out component.TargetCoords)) { @@ -29,7 +27,7 @@ namespace Content.Server.StationEvents.Events component.LeakGas = RobustRandom.Pick(component.LeakableGases); // Was 50-50 on using normal distribution. - var totalGas = RobustRandom.Next(component.MinimumGas, component.MaximumGas) * mod; + var totalGas = RobustRandom.Next(component.MinimumGas, component.MaximumGas); var startAfter = stationEvent.StartDelay; component.MolesPerSecond = RobustRandom.Next(component.MinimumMolesPerSecond, component.MaximumMolesPerSecond); diff --git a/Content.Server/StationEvents/Events/MeteorSwarmRule.cs b/Content.Server/StationEvents/Events/MeteorSwarmRule.cs index ef84d0a9ae..192a620c9f 100644 --- a/Content.Server/StationEvents/Events/MeteorSwarmRule.cs +++ b/Content.Server/StationEvents/Events/MeteorSwarmRule.cs @@ -17,8 +17,7 @@ namespace Content.Server.StationEvents.Events { base.Started(uid, component, gameRule, args); - var mod = Math.Sqrt(GetSeverityModifier()); - component.WaveCounter = (int) (RobustRandom.Next(component.MinimumWaves, component.MaximumWaves) * mod); + component.WaveCounter = RobustRandom.Next(component.MinimumWaves, component.MaximumWaves); } protected override void ActiveTick(EntityUid uid, MeteorSwarmRuleComponent component, GameRuleComponent gameRule, float frameTime) @@ -29,8 +28,6 @@ namespace Content.Server.StationEvents.Events return; } - var mod = GetSeverityModifier(); - component.Cooldown -= frameTime; if (component.Cooldown > 0f) @@ -38,7 +35,7 @@ namespace Content.Server.StationEvents.Events component.WaveCounter--; - component.Cooldown += (component.MaximumCooldown - component.MinimumCooldown) * RobustRandom.NextFloat() / mod + component.MinimumCooldown; + component.Cooldown += (component.MaximumCooldown - component.MinimumCooldown) * RobustRandom.NextFloat() + component.MinimumCooldown; Box2? playableArea = null; var mapId = GameTicker.DefaultMap; diff --git a/Content.Server/StationEvents/Events/RandomSentienceRule.cs b/Content.Server/StationEvents/Events/RandomSentienceRule.cs index d90361fe96..4b7606d01f 100644 --- a/Content.Server/StationEvents/Events/RandomSentienceRule.cs +++ b/Content.Server/StationEvents/Events/RandomSentienceRule.cs @@ -11,7 +11,6 @@ public sealed class RandomSentienceRule : StationEventSystem stationsToNotify = new(); - var mod = GetSeverityModifier(); var targetList = new List>(); var query = EntityQueryEnumerator(); while (query.MoveNext(out var targetUid, out var target)) @@ -21,7 +20,7 @@ public sealed class RandomSentienceRule : StationEventSystem(); foreach (var target in targetList) diff --git a/Content.Server/StationEvents/Events/StationEventSystem.cs b/Content.Server/StationEvents/Events/StationEventSystem.cs index 221beccee7..a4f6bc70df 100644 --- a/Content.Server/StationEvents/Events/StationEventSystem.cs +++ b/Content.Server/StationEvents/Events/StationEventSystem.cs @@ -134,25 +134,5 @@ public abstract partial class StationEventSystem : GameRuleSystem where T GameTicker.EndGameRule(uid, component); } - public float GetSeverityModifier() - { - var ev = new GetSeverityModifierEvent(); - RaiseLocalEvent(ev); - return ev.Modifier; - } - #endregion } - -/// -/// Raised broadcast to determine what the severity modifier should be for an event, some positive number that can be multiplied with various things. -/// Handled by usually other game rules (like the ramping scheduler). -/// Most events should try and make use of this if possible. -/// -public sealed class GetSeverityModifierEvent : EntityEventArgs -{ - /// - /// Should be multiplied/added to rather than set, for commutativity. - /// - public float Modifier = 1.0f; -} diff --git a/Content.Server/StationEvents/Events/VentClogRule.cs b/Content.Server/StationEvents/Events/VentClogRule.cs index f378aec3fb..e263a5f4f6 100644 --- a/Content.Server/StationEvents/Events/VentClogRule.cs +++ b/Content.Server/StationEvents/Events/VentClogRule.cs @@ -28,9 +28,6 @@ public sealed class VentClogRule : StationEventSystem .Where(x => !x.Abstract) .Select(x => x.ID).ToList(); - // TODO: This is gross, but not much can be done until event refactor, which needs Dynamic. - var mod = (float) Math.Sqrt(GetSeverityModifier()); - foreach (var (_, transform) in EntityManager.EntityQuery()) { if (CompOrNull(transform.GridUid)?.Station != chosenStation) @@ -40,14 +37,14 @@ public sealed class VentClogRule : StationEventSystem var solution = new Solution(); - if (!RobustRandom.Prob(Math.Min(0.33f * mod, 1.0f))) + if (!RobustRandom.Prob(0.33f)) continue; - var pickAny = RobustRandom.Prob(Math.Min(0.05f * mod, 1.0f)); + var pickAny = RobustRandom.Prob(0.05f); var reagent = RobustRandom.Pick(pickAny ? allReagents : component.SafeishVentChemicals); var weak = component.WeakReagents.Contains(reagent); - var quantity = (weak ? component.WeakReagentQuantity : component.ReagentQuantity) * mod; + var quantity = weak ? component.WeakReagentQuantity : component.ReagentQuantity; solution.AddReagent(reagent, quantity); var foamEnt = Spawn("Foam", transform.Coordinates); diff --git a/Content.Server/StationEvents/RampingStationEventSchedulerSystem.cs b/Content.Server/StationEvents/RampingStationEventSchedulerSystem.cs index 5c972df52e..ef3b5cf18a 100644 --- a/Content.Server/StationEvents/RampingStationEventSchedulerSystem.cs +++ b/Content.Server/StationEvents/RampingStationEventSchedulerSystem.cs @@ -25,13 +25,6 @@ public sealed class RampingStationEventSchedulerSystem : GameRuleSystem(OnGetSeverityModifier); - } - protected override void Started(EntityUid uid, RampingStationEventSchedulerComponent component, GameRuleComponent gameRule, GameRuleStartedEvent args) { base.Started(uid, component, gameRule, args); @@ -73,19 +66,6 @@ public sealed class RampingStationEventSchedulerSystem : GameRuleSystem(); - while (query.MoveNext(out var uid, out var scheduler, out var gameRule)) - { - if (!GameTicker.IsGameRuleActive(uid, gameRule)) - return; - - ev.Modifier *= GetChaosModifier(uid, scheduler); - Logger.Info($"Ramping set modifier to {ev.Modifier}"); - } - } - private void PickNextEventTime(EntityUid uid, RampingStationEventSchedulerComponent component) { var mod = GetChaosModifier(uid, component); diff --git a/Content.Server/StationRecords/Systems/StationRecordsSystem.cs b/Content.Server/StationRecords/Systems/StationRecordsSystem.cs index 09a00e5967..67f50d7a4e 100644 --- a/Content.Server/StationRecords/Systems/StationRecordsSystem.cs +++ b/Content.Server/StationRecords/Systems/StationRecordsSystem.cs @@ -129,7 +129,7 @@ public sealed class StationRecordsSystem : SharedStationRecordsSystem JobPrototype = jobId, Species = species, Gender = gender, - DisplayPriority = jobPrototype.Weight, + DisplayPriority = jobPrototype.RealDisplayWeight, Fingerprint = mobFingerprint, DNA = dna }; diff --git a/Content.Server/Tesla/Components/LightningArcShooterComponent.cs b/Content.Server/Tesla/Components/LightningArcShooterComponent.cs index 641dc59e8c..add7bf88e4 100644 --- a/Content.Server/Tesla/Components/LightningArcShooterComponent.cs +++ b/Content.Server/Tesla/Components/LightningArcShooterComponent.cs @@ -6,7 +6,7 @@ namespace Content.Server.Tesla.Components; /// /// Periodically fires electric arcs at surrounding objects. /// -[RegisterComponent, Access(typeof(LightningArcShooterSystem))] +[RegisterComponent, Access(typeof(LightningArcShooterSystem)), AutoGenerateComponentPause] public sealed partial class LightningArcShooterComponent : Component { /// @@ -45,6 +45,7 @@ public sealed partial class LightningArcShooterComponent : Component /// The time, upon reaching which the next batch of lightning bolts will be fired. /// [DataField, ViewVariables(VVAccess.ReadWrite)] + [AutoPausedField] public TimeSpan NextShootTime; /// diff --git a/Content.Server/Tesla/Components/LightningSparkingComponent.cs b/Content.Server/Tesla/Components/LightningSparkingComponent.cs index bb954de89a..e56c59f196 100644 --- a/Content.Server/Tesla/Components/LightningSparkingComponent.cs +++ b/Content.Server/Tesla/Components/LightningSparkingComponent.cs @@ -7,7 +7,7 @@ namespace Content.Server.Tesla.Components; /// /// The component changes the visual of an object after it is struck by lightning /// -[RegisterComponent, Access(typeof(LightningSparkingSystem))] +[RegisterComponent, Access(typeof(LightningSparkingSystem)), AutoGenerateComponentPause] public sealed partial class LightningSparkingComponent : Component { /// @@ -20,6 +20,7 @@ public sealed partial class LightningSparkingComponent : Component /// When the spark visual should turn off. /// [DataField(customTypeSerializer: typeof(TimeOffsetSerializer))] + [AutoPausedField] public TimeSpan LightningEndTime; [DataField, ViewVariables(VVAccess.ReadWrite)] diff --git a/Content.Server/Tesla/EntitySystem/LightningArcShooterSystem.cs b/Content.Server/Tesla/EntitySystem/LightningArcShooterSystem.cs index e901a93288..9948537c3c 100644 --- a/Content.Server/Tesla/EntitySystem/LightningArcShooterSystem.cs +++ b/Content.Server/Tesla/EntitySystem/LightningArcShooterSystem.cs @@ -18,7 +18,6 @@ public sealed class LightningArcShooterSystem : EntitySystem { base.Initialize(); SubscribeLocalEvent(OnShooterMapInit); - SubscribeLocalEvent(OnShooterUnpaused); } private void OnShooterMapInit(EntityUid uid, LightningArcShooterComponent component, ref MapInitEvent args) @@ -26,11 +25,6 @@ public sealed class LightningArcShooterSystem : EntitySystem component.NextShootTime = _gameTiming.CurTime + TimeSpan.FromSeconds(component.ShootMaxInterval); } - private void OnShooterUnpaused(EntityUid uid, LightningArcShooterComponent component, ref EntityUnpausedEvent args) - { - component.NextShootTime += args.PausedTime; - } - public override void Update(float frameTime) { base.Update(frameTime); diff --git a/Content.Server/Tesla/EntitySystem/LightningSparkingSystem.cs b/Content.Server/Tesla/EntitySystem/LightningSparkingSystem.cs index 7b569e66b3..c07472c8b3 100644 --- a/Content.Server/Tesla/EntitySystem/LightningSparkingSystem.cs +++ b/Content.Server/Tesla/EntitySystem/LightningSparkingSystem.cs @@ -18,12 +18,6 @@ public sealed class LightningSparkingSystem : EntitySystem base.Initialize(); SubscribeLocalEvent(OnHitByLightning); - SubscribeLocalEvent(OnLightningUnpaused); - } - - private void OnLightningUnpaused(EntityUid uid, LightningSparkingComponent component, ref EntityUnpausedEvent args) - { - component.LightningEndTime += args.PausedTime; } private void OnHitByLightning(Entity uid, ref HitByLightningEvent args) diff --git a/Content.Server/Wires/WiresSystem.cs b/Content.Server/Wires/WiresSystem.cs index 2b23b09360..0f9ee8b0f7 100644 --- a/Content.Server/Wires/WiresSystem.cs +++ b/Content.Server/Wires/WiresSystem.cs @@ -620,13 +620,6 @@ public sealed class WiresSystem : SharedWiresSystem } } - public void ChangePanelVisibility(EntityUid uid, WiresPanelComponent component, bool visible) - { - component.Visible = visible; - UpdateAppearance(uid, component); - Dirty(uid, component); - } - public void SetWiresPanelSecurity(EntityUid uid, WiresPanelSecurityComponent component, WiresPanelSecurityEvent args) { component.Examine = args.Examine; diff --git a/Content.Shared/Anomaly/Components/AnomalyComponent.cs b/Content.Shared/Anomaly/Components/AnomalyComponent.cs index 89afbb0122..bafdf12360 100644 --- a/Content.Shared/Anomaly/Components/AnomalyComponent.cs +++ b/Content.Shared/Anomaly/Components/AnomalyComponent.cs @@ -14,7 +14,7 @@ namespace Content.Shared.Anomaly.Components; /// /// Anomalies and their related components were designed here: https://hackmd.io/@ss14-design/r1sQbkJOs /// -[RegisterComponent, NetworkedComponent, AutoGenerateComponentState] +[RegisterComponent, NetworkedComponent, AutoGenerateComponentState, AutoGenerateComponentPause] [Access(typeof(SharedAnomalySystem))] public sealed partial class AnomalyComponent : Component { @@ -86,7 +86,7 @@ public sealed partial class AnomalyComponent : Component /// /// The time at which the next artifact pulse will occur. /// - [DataField(customTypeSerializer: typeof(TimeOffsetSerializer)), AutoNetworkedField] + [DataField(customTypeSerializer: typeof(TimeOffsetSerializer)), AutoNetworkedField, AutoPausedField] [ViewVariables(VVAccess.ReadWrite)] public TimeSpan NextPulseTime = TimeSpan.Zero; diff --git a/Content.Shared/Anomaly/Components/AnomalyPulsingComponent.cs b/Content.Shared/Anomaly/Components/AnomalyPulsingComponent.cs index 7326118b3c..a7fedb821b 100644 --- a/Content.Shared/Anomaly/Components/AnomalyPulsingComponent.cs +++ b/Content.Shared/Anomaly/Components/AnomalyPulsingComponent.cs @@ -5,13 +5,14 @@ namespace Content.Shared.Anomaly.Components; /// /// This component tracks anomalies that are currently pulsing /// -[RegisterComponent, Access(typeof(SharedAnomalySystem))] +[RegisterComponent, Access(typeof(SharedAnomalySystem)), AutoGenerateComponentPause] public sealed partial class AnomalyPulsingComponent : Component { /// /// The time at which the pulse will be over. /// [DataField("endTime", customTypeSerializer: typeof(TimeOffsetSerializer)), ViewVariables(VVAccess.ReadWrite)] + [AutoPausedField] public TimeSpan EndTime; /// diff --git a/Content.Shared/Anomaly/Components/AnomalySupercriticalComponent.cs b/Content.Shared/Anomaly/Components/AnomalySupercriticalComponent.cs index bd8f40852d..00ea882ad2 100644 --- a/Content.Shared/Anomaly/Components/AnomalySupercriticalComponent.cs +++ b/Content.Shared/Anomaly/Components/AnomalySupercriticalComponent.cs @@ -8,6 +8,7 @@ namespace Content.Shared.Anomaly.Components; /// [RegisterComponent, NetworkedComponent, AutoGenerateComponentState] [Access(typeof(SharedAnomalySystem))] +[AutoGenerateComponentPause] public sealed partial class AnomalySupercriticalComponent : Component { /// @@ -15,6 +16,7 @@ public sealed partial class AnomalySupercriticalComponent : Component /// [DataField(customTypeSerializer: typeof(TimeOffsetSerializer)), AutoNetworkedField] [ViewVariables(VVAccess.ReadWrite)] + [AutoPausedField] public TimeSpan EndTime; /// diff --git a/Content.Shared/Anomaly/SharedAnomalySystem.cs b/Content.Shared/Anomaly/SharedAnomalySystem.cs index 6eba4221b4..6cdcdf305b 100644 --- a/Content.Shared/Anomaly/SharedAnomalySystem.cs +++ b/Content.Shared/Anomaly/SharedAnomalySystem.cs @@ -46,10 +46,6 @@ public abstract class SharedAnomalySystem : EntitySystem SubscribeLocalEvent(OnAnomalyThrowStart); SubscribeLocalEvent(OnAnomalyThrowEnd); - SubscribeLocalEvent(OnAnomalyUnpause); - SubscribeLocalEvent(OnPulsingUnpause); - SubscribeLocalEvent(OnSupercriticalUnpause); - _sawmill = Logger.GetSawmill("anomaly"); } @@ -89,23 +85,6 @@ public abstract class SharedAnomalySystem : EntitySystem Popup.PopupEntity(Loc.GetString("anomaly-component-contact-damage"), target, target); } - private void OnAnomalyUnpause(EntityUid uid, AnomalyComponent component, ref EntityUnpausedEvent args) - { - component.NextPulseTime += args.PausedTime; - Dirty(uid, component); - } - - private void OnPulsingUnpause(EntityUid uid, AnomalyPulsingComponent component, ref EntityUnpausedEvent args) - { - component.EndTime += args.PausedTime; - } - - private void OnSupercriticalUnpause(EntityUid uid, AnomalySupercriticalComponent component, ref EntityUnpausedEvent args) - { - component.EndTime += args.PausedTime; - Dirty(uid, component); - } - public void DoAnomalyPulse(EntityUid uid, AnomalyComponent? component = null) { if (!Resolve(uid, ref component)) diff --git a/Content.Shared/Atmos/Rotting/PerishableComponent.cs b/Content.Shared/Atmos/Rotting/PerishableComponent.cs index 1c5c4bc4ae..6983b872b8 100644 --- a/Content.Shared/Atmos/Rotting/PerishableComponent.cs +++ b/Content.Shared/Atmos/Rotting/PerishableComponent.cs @@ -7,7 +7,7 @@ namespace Content.Shared.Atmos.Rotting; /// This makes mobs eventually start rotting when they die. /// It may be expanded to food at some point, but it's just for mobs right now. /// -[RegisterComponent, NetworkedComponent, AutoGenerateComponentState] +[RegisterComponent, NetworkedComponent, AutoGenerateComponentState, AutoGenerateComponentPause] [Access(typeof(SharedRottingSystem))] public sealed partial class PerishableComponent : Component { @@ -27,6 +27,7 @@ public sealed partial class PerishableComponent : Component /// Gasses are released, this is when the next gas release update will be. /// [DataField(customTypeSerializer: typeof(TimeOffsetSerializer))] + [AutoPausedField] public TimeSpan RotNextUpdate = TimeSpan.Zero; /// diff --git a/Content.Shared/Atmos/Rotting/RottingComponent.cs b/Content.Shared/Atmos/Rotting/RottingComponent.cs index d4ba79bb89..d21fac88a2 100644 --- a/Content.Shared/Atmos/Rotting/RottingComponent.cs +++ b/Content.Shared/Atmos/Rotting/RottingComponent.cs @@ -8,7 +8,7 @@ namespace Content.Shared.Atmos.Rotting; /// Tracking component for stuff that has started to rot. /// Only the current stage is networked to the client. /// -[RegisterComponent, NetworkedComponent] +[RegisterComponent, NetworkedComponent, AutoGenerateComponentPause] [Access(typeof(SharedRottingSystem))] public sealed partial class RottingComponent : Component { @@ -22,6 +22,7 @@ public sealed partial class RottingComponent : Component /// When the next check will happen for rot progression + effects like damage and ammonia /// [DataField(customTypeSerializer: typeof(TimeOffsetSerializer))] + [AutoPausedField] public TimeSpan NextRotUpdate = TimeSpan.Zero; /// diff --git a/Content.Shared/Bed/Cryostorage/CryostorageContainedComponent.cs b/Content.Shared/Bed/Cryostorage/CryostorageContainedComponent.cs index 5ab639bd3c..9c73b59e9a 100644 --- a/Content.Shared/Bed/Cryostorage/CryostorageContainedComponent.cs +++ b/Content.Shared/Bed/Cryostorage/CryostorageContainedComponent.cs @@ -8,7 +8,7 @@ namespace Content.Shared.Bed.Cryostorage; /// This is used to track an entity that is currently being held in Cryostorage. /// [RegisterComponent, NetworkedComponent] -[AutoGenerateComponentState] +[AutoGenerateComponentState, AutoGenerateComponentPause] public sealed partial class CryostorageContainedComponent : Component { /// @@ -22,6 +22,7 @@ public sealed partial class CryostorageContainedComponent : Component /// The time at which the cryostorage grace period ends. /// [DataField(customTypeSerializer: typeof(TimeOffsetSerializer)), ViewVariables(VVAccess.ReadWrite), AutoNetworkedField] + [AutoPausedField] public TimeSpan? GracePeriodEndTime; /// diff --git a/Content.Shared/Bed/Cryostorage/SharedCryostorageSystem.cs b/Content.Shared/Bed/Cryostorage/SharedCryostorageSystem.cs index 1197e019d0..f14dc21c48 100644 --- a/Content.Shared/Bed/Cryostorage/SharedCryostorageSystem.cs +++ b/Content.Shared/Bed/Cryostorage/SharedCryostorageSystem.cs @@ -37,7 +37,6 @@ public abstract class SharedCryostorageSystem : EntitySystem SubscribeLocalEvent(OnCanDropTarget); SubscribeLocalEvent(OnRemovedContained); - SubscribeLocalEvent(OnUnpaused); SubscribeLocalEvent(OnShutdownContained); SubscribeLocalEvent(OnRoundRestart); @@ -130,13 +129,6 @@ public abstract class SharedCryostorageSystem : EntitySystem RemCompDeferred(ent, comp); } - private void OnUnpaused(Entity ent, ref EntityUnpausedEvent args) - { - var comp = ent.Comp; - if (comp.GracePeriodEndTime != null) - comp.GracePeriodEndTime = comp.GracePeriodEndTime.Value + args.PausedTime; - } - private void OnShutdownContained(Entity ent, ref ComponentShutdown args) { var comp = ent.Comp; diff --git a/Content.Shared/Bed/Sleep/SharedSleepingSystem.cs b/Content.Shared/Bed/Sleep/SharedSleepingSystem.cs index 8e76ce3a3e..4e4bc2c574 100644 --- a/Content.Shared/Bed/Sleep/SharedSleepingSystem.cs +++ b/Content.Shared/Bed/Sleep/SharedSleepingSystem.cs @@ -26,14 +26,8 @@ namespace Content.Server.Bed.Sleep SubscribeLocalEvent(OnSpeakAttempt); SubscribeLocalEvent(OnSeeAttempt); SubscribeLocalEvent(OnPointAttempt); - SubscribeLocalEvent(OnSleepUnpaused); } - private void OnSleepUnpaused(EntityUid uid, SleepingComponent component, ref EntityUnpausedEvent args) - { - component.CoolDownEnd += args.PausedTime; - Dirty(uid, component); - } private void OnMapInit(EntityUid uid, SleepingComponent component, MapInitEvent args) { diff --git a/Content.Shared/Bed/Sleep/SleepingComponent.cs b/Content.Shared/Bed/Sleep/SleepingComponent.cs index 94838b658f..cd468440f4 100644 --- a/Content.Shared/Bed/Sleep/SleepingComponent.cs +++ b/Content.Shared/Bed/Sleep/SleepingComponent.cs @@ -7,7 +7,7 @@ namespace Content.Shared.Bed.Sleep; /// /// Added to entities when they go to sleep. /// -[NetworkedComponent, RegisterComponent] +[NetworkedComponent, RegisterComponent, AutoGenerateComponentPause(Dirty = true)] public sealed partial class SleepingComponent : Component { /// @@ -24,6 +24,7 @@ public sealed partial class SleepingComponent : Component public TimeSpan Cooldown = TimeSpan.FromSeconds(1f); [DataField("cooldownEnd", customTypeSerializer:typeof(TimeOffsetSerializer))] + [AutoPausedField] public TimeSpan CoolDownEnd; [DataField("wakeAction")] public EntityUid? WakeAction; diff --git a/Content.Shared/CCVar/CCVars.cs b/Content.Shared/CCVar/CCVars.cs index bc90d7942c..552db94f4d 100644 --- a/Content.Shared/CCVar/CCVars.cs +++ b/Content.Shared/CCVar/CCVars.cs @@ -1479,15 +1479,6 @@ namespace Content.Shared.CCVar public static readonly CVarDef CrewManifestUnsecure = CVarDef.Create("crewmanifest.unsecure", true, CVar.REPLICATED); - /// - /// Dictates the order the crew manifest will appear in, in terms of its sections. - /// Sections not in this list will appear at the end of the list, in no - /// specific order. - /// - public static readonly CVarDef CrewManifestOrdering = - CVarDef.Create("crewmanifest.ordering", "Command,Security,Science,Medical,Engineering,Cargo,Civilian,Unknown", - CVar.REPLICATED); - /* * Biomass */ diff --git a/Content.Shared/Chasm/ChasmFallingComponent.cs b/Content.Shared/Chasm/ChasmFallingComponent.cs index 69b1c8e308..09377864c4 100644 --- a/Content.Shared/Chasm/ChasmFallingComponent.cs +++ b/Content.Shared/Chasm/ChasmFallingComponent.cs @@ -7,7 +7,7 @@ namespace Content.Shared.Chasm; /// /// Added to entities which have started falling into a chasm. /// -[RegisterComponent, NetworkedComponent] +[RegisterComponent, NetworkedComponent, AutoGenerateComponentPause] public sealed partial class ChasmFallingComponent : Component { /// @@ -23,6 +23,7 @@ public sealed partial class ChasmFallingComponent : Component public TimeSpan DeletionTime = TimeSpan.FromSeconds(1.8f); [DataField("nextDeletionTime", customTypeSerializer:typeof(TimeOffsetSerializer))] + [AutoPausedField] public TimeSpan NextDeletionTime = TimeSpan.Zero; /// diff --git a/Content.Shared/Chasm/ChasmSystem.cs b/Content.Shared/Chasm/ChasmSystem.cs index 4045a27078..51299557db 100644 --- a/Content.Shared/Chasm/ChasmSystem.cs +++ b/Content.Shared/Chasm/ChasmSystem.cs @@ -26,7 +26,6 @@ public sealed class ChasmSystem : EntitySystem SubscribeLocalEvent(OnStepTriggered); SubscribeLocalEvent(OnStepTriggerAttempt); - SubscribeLocalEvent(OnUnpaused); SubscribeLocalEvent(OnUpdateCanMove); } @@ -73,11 +72,6 @@ public sealed class ChasmSystem : EntitySystem args.Continue = true; } - private void OnUnpaused(EntityUid uid, ChasmFallingComponent component, ref EntityUnpausedEvent args) - { - component.NextDeletionTime += args.PausedTime; - } - private void OnUpdateCanMove(EntityUid uid, ChasmFallingComponent component, UpdateCanMoveEvent args) { args.Cancel(); diff --git a/Content.Shared/Chemistry/Components/SmokeAffectedComponent.cs b/Content.Shared/Chemistry/Components/SmokeAffectedComponent.cs index def6940ee1..fdc46dfbef 100644 --- a/Content.Shared/Chemistry/Components/SmokeAffectedComponent.cs +++ b/Content.Shared/Chemistry/Components/SmokeAffectedComponent.cs @@ -7,13 +7,14 @@ namespace Content.Shared.Chemistry.Components; /// This is used for entities which are currently being affected by smoke. /// Manages the gradual metabolism every second. /// -[RegisterComponent, NetworkedComponent] +[RegisterComponent, NetworkedComponent, AutoGenerateComponentPause] public sealed partial class SmokeAffectedComponent : Component { /// /// The time at which the next smoke metabolism will occur. /// [DataField(customTypeSerializer: typeof(TimeOffsetSerializer))] + [AutoPausedField] public TimeSpan NextSecond; /// diff --git a/Content.Shared/Chemistry/SharedReagentDispenser.cs b/Content.Shared/Chemistry/SharedReagentDispenser.cs index 22cb87dcdb..2b9c318c58 100644 --- a/Content.Shared/Chemistry/SharedReagentDispenser.cs +++ b/Content.Shared/Chemistry/SharedReagentDispenser.cs @@ -56,6 +56,8 @@ namespace Content.Shared.Chemistry public sealed class ReagentDispenserBoundUserInterfaceState : BoundUserInterfaceState { public readonly ContainerInfo? OutputContainer; + + public readonly NetEntity? OutputContainerEntity; /// /// A list of the reagents which this dispenser can dispense. /// @@ -63,9 +65,10 @@ namespace Content.Shared.Chemistry public readonly ReagentDispenserDispenseAmount SelectedDispenseAmount; - public ReagentDispenserBoundUserInterfaceState(ContainerInfo? outputContainer, List>> inventory, ReagentDispenserDispenseAmount selectedDispenseAmount) + public ReagentDispenserBoundUserInterfaceState(ContainerInfo? outputContainer, NetEntity? outputContainerEntity, List>> inventory, ReagentDispenserDispenseAmount selectedDispenseAmount) { OutputContainer = outputContainer; + OutputContainerEntity = outputContainerEntity; Inventory = inventory; SelectedDispenseAmount = selectedDispenseAmount; } diff --git a/Content.Shared/Climbing/Components/ClimbingComponent.cs b/Content.Shared/Climbing/Components/ClimbingComponent.cs index 2af2c89feb..89320eabc8 100644 --- a/Content.Shared/Climbing/Components/ClimbingComponent.cs +++ b/Content.Shared/Climbing/Components/ClimbingComponent.cs @@ -4,7 +4,7 @@ using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom; namespace Content.Shared.Climbing.Components; -[RegisterComponent, NetworkedComponent, AutoGenerateComponentState] +[RegisterComponent, NetworkedComponent, AutoGenerateComponentState, AutoGenerateComponentPause] public sealed partial class ClimbingComponent : Component { /// @@ -17,6 +17,7 @@ public sealed partial class ClimbingComponent : Component /// Whether the owner is being moved onto the climbed entity. /// [AutoNetworkedField, DataField(customTypeSerializer: typeof(TimeOffsetSerializer))] + [AutoPausedField] public TimeSpan? NextTransition; /// diff --git a/Content.Shared/Climbing/Systems/ClimbSystem.cs b/Content.Shared/Climbing/Systems/ClimbSystem.cs index 23bc54b8f8..7c760f2c5d 100644 --- a/Content.Shared/Climbing/Systems/ClimbSystem.cs +++ b/Content.Shared/Climbing/Systems/ClimbSystem.cs @@ -62,7 +62,6 @@ public sealed partial class ClimbSystem : VirtualController SubscribeLocalEvent(OnDoAfter); SubscribeLocalEvent(OnClimbEndCollide); SubscribeLocalEvent(OnBuckleChange); - SubscribeLocalEvent(OnClimbableUnpaused); SubscribeLocalEvent(OnCanDragDropOn); SubscribeLocalEvent>(AddClimbableVerb); @@ -71,15 +70,6 @@ public sealed partial class ClimbSystem : VirtualController SubscribeLocalEvent(OnGlassClimbed); } - private void OnClimbableUnpaused(EntityUid uid, ClimbingComponent component, ref EntityUnpausedEvent args) - { - if (component.NextTransition == null) - return; - - component.NextTransition = component.NextTransition.Value + args.PausedTime; - Dirty(uid, component); - } - public override void UpdateBeforeSolve(bool prediction, float frameTime) { base.UpdateBeforeSolve(prediction, frameTime); diff --git a/Content.Shared/CombatMode/Pacification/PacificationSystem.cs b/Content.Shared/CombatMode/Pacification/PacificationSystem.cs index 0c5e12e6f0..6d94c087af 100644 --- a/Content.Shared/CombatMode/Pacification/PacificationSystem.cs +++ b/Content.Shared/CombatMode/Pacification/PacificationSystem.cs @@ -28,16 +28,9 @@ public sealed class PacificationSystem : EntitySystem SubscribeLocalEvent(OnBeforeThrow); SubscribeLocalEvent(OnAttackAttempt); SubscribeLocalEvent(OnShootAttempt); - SubscribeLocalEvent(OnUnpaused); SubscribeLocalEvent(OnPacifiedDangerousAttack); } - private void OnUnpaused(Entity ent, ref EntityUnpausedEvent args) - { - if (ent.Comp.NextPopupTime != null) - ent.Comp.NextPopupTime = ent.Comp.NextPopupTime.Value + args.PausedTime; - } - private bool PacifiedCanAttack(EntityUid user, EntityUid target, [NotNullWhen(false)] out string? reason) { var ev = new AttemptPacifiedAttackEvent(user); diff --git a/Content.Shared/CombatMode/Pacification/PacifiedComponent.cs b/Content.Shared/CombatMode/Pacification/PacifiedComponent.cs index e271628fcb..464ef77885 100644 --- a/Content.Shared/CombatMode/Pacification/PacifiedComponent.cs +++ b/Content.Shared/CombatMode/Pacification/PacifiedComponent.cs @@ -11,7 +11,7 @@ namespace Content.Shared.CombatMode.Pacification; /// /// If you want full-pacifism (no combat mode at all), you can simply set before adding. /// -[RegisterComponent, NetworkedComponent] +[RegisterComponent, NetworkedComponent, AutoGenerateComponentPause] [Access(typeof(PacificationSystem))] public sealed partial class PacifiedComponent : Component { @@ -33,6 +33,7 @@ public sealed partial class PacifiedComponent : Component public TimeSpan PopupCooldown = TimeSpan.FromSeconds(3.0); [DataField] + [AutoPausedField] public TimeSpan? NextPopupTime = null; /// diff --git a/Content.Shared/Construction/Components/FlatpackCreatorComponent.cs b/Content.Shared/Construction/Components/FlatpackCreatorComponent.cs index 1270591548..ed084b39b5 100644 --- a/Content.Shared/Construction/Components/FlatpackCreatorComponent.cs +++ b/Content.Shared/Construction/Components/FlatpackCreatorComponent.cs @@ -11,7 +11,7 @@ namespace Content.Shared.Construction.Components; /// [RegisterComponent, NetworkedComponent] [Access(typeof(SharedFlatpackSystem))] -[AutoGenerateComponentState] +[AutoGenerateComponentState, AutoGenerateComponentPause] public sealed partial class FlatpackCreatorComponent : Component { /// @@ -26,6 +26,7 @@ public sealed partial class FlatpackCreatorComponent : Component /// [DataField(customTypeSerializer: typeof(TimeOffsetSerializer)), ViewVariables(VVAccess.ReadWrite)] [AutoNetworkedField] + [AutoPausedField] public TimeSpan PackEndTime; /// diff --git a/Content.Shared/Construction/SharedFlatpackSystem.cs b/Content.Shared/Construction/SharedFlatpackSystem.cs index d4c2513cd3..a62488d6f3 100644 --- a/Content.Shared/Construction/SharedFlatpackSystem.cs +++ b/Content.Shared/Construction/SharedFlatpackSystem.cs @@ -40,7 +40,6 @@ public abstract class SharedFlatpackSystem : EntitySystem SubscribeLocalEvent(OnFlatpackExamined); SubscribeLocalEvent(OnCreatorRemovingAttempt); - SubscribeLocalEvent(OnCreatorUnpaused); } private void OnFlatpackInteractUsing(Entity ent, ref InteractUsingEvent args) @@ -110,11 +109,6 @@ public abstract class SharedFlatpackSystem : EntitySystem args.Cancel(); } - private void OnCreatorUnpaused(Entity ent, ref EntityUnpausedEvent args) - { - ent.Comp.PackEndTime += args.PausedTime; - } - public void SetupFlatpack(Entity ent, EntityUid? board) { if (!Resolve(ent, ref ent.Comp)) diff --git a/Content.Shared/Containers/ItemSlot/ItemSlotsSystem.cs b/Content.Shared/Containers/ItemSlot/ItemSlotsSystem.cs index d832cdfef8..90f4f2a900 100644 --- a/Content.Shared/Containers/ItemSlot/ItemSlotsSystem.cs +++ b/Content.Shared/Containers/ItemSlot/ItemSlotsSystem.cs @@ -274,7 +274,7 @@ namespace Content.Shared.Containers.ItemSlots if (ev.Cancelled) return false; - return _containers.CanInsert(usedUid, slot.ContainerSlot, assumeEmpty: true); + return _containers.CanInsert(usedUid, slot.ContainerSlot); } /// diff --git a/Content.Shared/Content.Shared.csproj b/Content.Shared/Content.Shared.csproj index 8ae2f70ce0..88e338ffd2 100644 --- a/Content.Shared/Content.Shared.csproj +++ b/Content.Shared/Content.Shared.csproj @@ -2,7 +2,7 @@ $(TargetFramework) - 11 + 12 false false nullable diff --git a/Content.Shared/CrewManifest/SharedCrewManifestSystem.cs b/Content.Shared/CrewManifest/SharedCrewManifestSystem.cs index 7e4c824e20..a9279cc7f1 100644 --- a/Content.Shared/CrewManifest/SharedCrewManifestSystem.cs +++ b/Content.Shared/CrewManifest/SharedCrewManifestSystem.cs @@ -1,4 +1,5 @@ using Content.Shared.Eui; +using NetSerializer; using Robust.Shared.Serialization; namespace Content.Shared.CrewManifest; @@ -39,7 +40,7 @@ public sealed class CrewManifestEntries /// Entries in the crew manifest. Goes by department ID. /// // public Dictionary> Entries = new(); - public List Entries = new(); + public CrewManifestEntry[] Entries = Array.Empty(); } [Serializable, NetSerializable] diff --git a/Content.Shared/Cuffs/Components/HandcuffComponent.cs b/Content.Shared/Cuffs/Components/HandcuffComponent.cs index a91692389f..91d5a412eb 100644 --- a/Content.Shared/Cuffs/Components/HandcuffComponent.cs +++ b/Content.Shared/Cuffs/Components/HandcuffComponent.cs @@ -52,15 +52,6 @@ public sealed partial class HandcuffComponent : Component [DataField] public bool Removing; - [DataField, ViewVariables(VVAccess.ReadWrite)] - public DamageSpecifier DamageOnResist = new() - { - DamageDict = new() - { - { "Blunt", 3.0 }, - } - }; - /// /// The path of the RSI file used for the player cuffed overlay. /// diff --git a/Content.Shared/Cuffs/SharedCuffableSystem.cs b/Content.Shared/Cuffs/SharedCuffableSystem.cs index 99657c87aa..fc005fd30f 100644 --- a/Content.Shared/Cuffs/SharedCuffableSystem.cs +++ b/Content.Shared/Cuffs/SharedCuffableSystem.cs @@ -6,7 +6,6 @@ using Content.Shared.Alert; using Content.Shared.Atmos.Piping.Unary.Components; using Content.Shared.Buckle.Components; using Content.Shared.Cuffs.Components; -using Content.Shared.Damage; using Content.Shared.Database; using Content.Shared.DoAfter; using Content.Shared.Effects; @@ -28,6 +27,7 @@ using Content.Shared.Pulling.Components; using Content.Shared.Pulling.Events; using Content.Shared.Rejuvenate; using Content.Shared.Stunnable; +using Content.Shared.Timing; using Content.Shared.Verbs; using Content.Shared.Weapons.Melee.Events; using Robust.Shared.Audio; @@ -48,7 +48,6 @@ namespace Content.Shared.Cuffs [Dependency] private readonly ActionBlockerSystem _actionBlocker = default!; [Dependency] private readonly AlertsSystem _alerts = default!; [Dependency] private readonly SharedColorFlashEffectSystem _color = default!; - [Dependency] private readonly DamageableSystem _damageSystem = default!; [Dependency] private readonly MobStateSystem _mobState = default!; [Dependency] private readonly SharedAudioSystem _audio = default!; [Dependency] private readonly SharedContainerSystem _container = default!; @@ -58,6 +57,7 @@ namespace Content.Shared.Cuffs [Dependency] private readonly SharedInteractionSystem _interaction = default!; [Dependency] private readonly SharedPopupSystem _popup = default!; [Dependency] private readonly SharedTransformSystem _transform = default!; + [Dependency] private readonly UseDelaySystem _delay = default!; public override void Initialize() { @@ -128,9 +128,9 @@ namespace Content.Shared.Cuffs } } - if (args.Cancelled && _net.IsServer) + if (args.Cancelled) { - _popup.PopupEntity(Loc.GetString("cuffable-component-cannot-interact-message"), args.Target, args.User); + _popup.PopupClient(Loc.GetString("cuffable-component-cannot-interact-message"), args.Target, args.User); } } @@ -202,8 +202,8 @@ namespace Content.Shared.Cuffs var message = args.Buckling ? Loc.GetString("handcuff-component-cuff-interrupt-buckled-message") : Loc.GetString("handcuff-component-cuff-interrupt-unbuckled-message"); - if (_net.IsServer) - _popup.PopupEntity(message, uid, args.UserEntity); + + _popup.PopupClient(message, uid, args.UserEntity); } private void OnPull(EntityUid uid, CuffableComponent component, PullMessage args) @@ -265,9 +265,9 @@ namespace Content.Shared.Cuffs { Uncuff(target, user, used, component); } - else if (_net.IsServer) + else { - _popup.PopupEntity(Loc.GetString("cuffable-component-remove-cuffs-fail-message"), user, user); + _popup.PopupClient(Loc.GetString("cuffable-component-remove-cuffs-fail-message"), user, user); } } @@ -278,8 +278,7 @@ namespace Content.Shared.Cuffs if (!args.CanReach) { - if (_net.IsServer) - _popup.PopupEntity(Loc.GetString("handcuff-component-too-far-away-error"), args.User, args.User); + _popup.PopupClient(Loc.GetString("handcuff-component-too-far-away-error"), args.User, args.User); return; } @@ -312,8 +311,6 @@ namespace Content.Shared.Cuffs if (!args.Cancelled && TryAddNewCuffs(target, user, uid, cuffable)) { _audio.PlayPredicted(component.EndCuffSound, uid, user); - if (!_net.IsServer) - return; _popup.PopupEntity(Loc.GetString("handcuff-component-cuff-observer-success-message", ("user", Identity.Name(user, EntityManager)), ("target", Identity.Name(target, EntityManager))), @@ -322,15 +319,15 @@ namespace Content.Shared.Cuffs if (target == user) { - _popup.PopupEntity(Loc.GetString("handcuff-component-cuff-self-success-message"), user, user); + _popup.PopupClient(Loc.GetString("handcuff-component-cuff-self-success-message"), user, user); _adminLog.Add(LogType.Action, LogImpact.Medium, $"{ToPrettyString(user):player} has cuffed himself"); } else { - _popup.PopupEntity(Loc.GetString("handcuff-component-cuff-other-success-message", + _popup.PopupClient(Loc.GetString("handcuff-component-cuff-other-success-message", ("otherName", Identity.Name(target, EntityManager, user))), user, user); - _popup.PopupEntity(Loc.GetString("handcuff-component-cuff-by-other-success-message", + _popup.PopupClient(Loc.GetString("handcuff-component-cuff-by-other-success-message", ("otherName", Identity.Name(user, EntityManager, target))), target, target); _adminLog.Add(LogType.Action, LogImpact.Medium, $"{ToPrettyString(user):player} has cuffed {ToPrettyString(target):player}"); @@ -338,20 +335,18 @@ namespace Content.Shared.Cuffs } else { - if (!_net.IsServer) - return; if (target == user) { - _popup.PopupEntity(Loc.GetString("handcuff-component-cuff-interrupt-self-message"), user, user); + _popup.PopupClient(Loc.GetString("handcuff-component-cuff-interrupt-self-message"), user, user); } else { // TODO Fix popup message wording // This message assumes that the user being handcuffed is the one that caused the handcuff to fail. - _popup.PopupEntity(Loc.GetString("handcuff-component-cuff-interrupt-message", + _popup.PopupClient(Loc.GetString("handcuff-component-cuff-interrupt-message", ("targetName", Identity.Name(target, EntityManager, user))), user, user); - _popup.PopupEntity(Loc.GetString("handcuff-component-cuff-interrupt-other-message", + _popup.PopupClient(Loc.GetString("handcuff-component-cuff-interrupt-other-message", ("otherName", Identity.Name(user, EntityManager, target))), target, target); } } @@ -462,21 +457,15 @@ namespace Content.Shared.Cuffs if (!TryComp(target, out var hands)) { - if (_net.IsServer) - { - _popup.PopupEntity(Loc.GetString("handcuff-component-target-has-no-hands-error", - ("targetName", Identity.Name(target, EntityManager, user))), user, user); - } + _popup.PopupClient(Loc.GetString("handcuff-component-target-has-no-hands-error", + ("targetName", Identity.Name(target, EntityManager, user))), user, user); return true; } if (cuffable.CuffedHandCount >= hands.Count) { - if (_net.IsServer) - { - _popup.PopupEntity(Loc.GetString("handcuff-component-target-has-no-free-hands-error", - ("targetName", Identity.Name(target, EntityManager, user))), user, user); - } + _popup.PopupClient(Loc.GetString("handcuff-component-target-has-no-free-hands-error", + ("targetName", Identity.Name(target, EntityManager, user))), user, user); return true; } @@ -499,24 +488,21 @@ namespace Content.Shared.Cuffs if (!_doAfter.TryStartDoAfter(doAfterEventArgs)) return true; - if (_net.IsServer) - { - _popup.PopupEntity(Loc.GetString("handcuff-component-start-cuffing-observer", + _popup.PopupEntity(Loc.GetString("handcuff-component-start-cuffing-observer", ("user", Identity.Name(user, EntityManager)), ("target", Identity.Name(target, EntityManager))), - target, Filter.Pvs(target, entityManager: EntityManager) + target, Filter.Pvs(target, entityManager: EntityManager) .RemoveWhere(e => e.AttachedEntity == target || e.AttachedEntity == user), true); - if (target == user) - { - _popup.PopupEntity(Loc.GetString("handcuff-component-target-self"), user, user); - } - else - { - _popup.PopupEntity(Loc.GetString("handcuff-component-start-cuffing-target-message", - ("targetName", Identity.Name(target, EntityManager, user))), user, user); - _popup.PopupEntity(Loc.GetString("handcuff-component-start-cuffing-by-other-message", - ("otherName", Identity.Name(user, EntityManager, target))), target, target); - } + if (target == user) + { + _popup.PopupClient(Loc.GetString("handcuff-component-target-self"), user, user); + } + else + { + _popup.PopupClient(Loc.GetString("handcuff-component-start-cuffing-target-message", + ("targetName", Identity.Name(target, EntityManager, user))), user, user); + _popup.PopupClient(Loc.GetString("handcuff-component-start-cuffing-by-other-message", + ("otherName", Identity.Name(user, EntityManager, target))), target, target); } _audio.PlayPredicted(handcuffComponent.StartCuffSound, handcuff, user); @@ -569,12 +555,23 @@ namespace Content.Shared.Cuffs if (!isOwner && !_interaction.InRangeUnobstructed(user, target)) { - if (_net.IsServer) - _popup.PopupEntity(Loc.GetString("cuffable-component-cannot-remove-cuffs-too-far-message"), user, user); + _popup.PopupClient(Loc.GetString("cuffable-component-cannot-remove-cuffs-too-far-message"), user, user); return; } var uncuffTime = isOwner ? cuff.BreakoutTime : cuff.UncuffTime; + + if (isOwner) + { + if (!TryComp(cuffsToRemove.Value, out UseDelayComponent? useDelay)) + return; + + if (!_delay.TryResetDelay((cuffsToRemove.Value, useDelay), true)) + { + return; + } + } + var doAfterEventArgs = new DoAfterArgs(EntityManager, user, uncuffTime, new UnCuffDoAfterEvent(), target, target, cuffsToRemove) { BreakOnUserMove = true, @@ -589,31 +586,23 @@ namespace Content.Shared.Cuffs _adminLog.Add(LogType.Action, LogImpact.Low, $"{ToPrettyString(user)} is trying to uncuff {ToPrettyString(target)}"); - if (isOwner) + _popup.PopupEntity(Loc.GetString("cuffable-component-start-uncuffing-observer", + ("user", Identity.Name(user, EntityManager)), ("target", Identity.Name(target, EntityManager))), + target, Filter.Pvs(target, entityManager: EntityManager) + .RemoveWhere(e => e.AttachedEntity == target || e.AttachedEntity == user), true); + + if (target == user) { - _damageSystem.TryChangeDamage(target, cuff.DamageOnResist, true, false); + _popup.PopupClient(Loc.GetString("cuffable-component-start-uncuffing-self"), user, user); + } + else + { + _popup.PopupClient(Loc.GetString("cuffable-component-start-uncuffing-target-message", + ("targetName", Identity.Name(target, EntityManager, user))), user, user); + _popup.PopupClient(Loc.GetString("cuffable-component-start-uncuffing-by-other-message", + ("otherName", Identity.Name(user, EntityManager, target))), target, target); } - if (_net.IsServer) - { - _popup.PopupEntity(Loc.GetString("cuffable-component-start-uncuffing-observer", - ("user", Identity.Name(user, EntityManager)), ("target", Identity.Name(target, EntityManager))), - target, Filter.Pvs(target, entityManager: EntityManager) - .RemoveWhere(e => e.AttachedEntity == target || e.AttachedEntity == user), true); - - if (target == user) - { - _color.RaiseEffect(Color.Red, new List() { user }, Filter.Pvs(user, entityManager: EntityManager)); - _popup.PopupEntity(Loc.GetString("cuffable-component-start-uncuffing-self"), user, user); - } - else - { - _popup.PopupEntity(Loc.GetString("cuffable-component-start-uncuffing-target-message", - ("targetName", Identity.Name(target, EntityManager, user))), user, user); - _popup.PopupEntity(Loc.GetString("cuffable-component-start-uncuffing-by-other-message", - ("otherName", Identity.Name(user, EntityManager, target))), target, target); - } - } _audio.PlayPredicted(isOwner ? cuff.StartBreakoutSound : cuff.StartUncuffSound, target, user); } @@ -636,6 +625,8 @@ namespace Content.Shared.Cuffs cuff.Removing = true; _audio.PlayPredicted(cuff.EndUncuffSound, target, user); + var isOwner = user == target; + _container.Remove(cuffsToRemove, cuffable.Container); if (_net.IsServer) diff --git a/Content.Shared/Damage/Components/DamageOnHoldingComponent.cs b/Content.Shared/Damage/Components/DamageOnHoldingComponent.cs index fe28b7e7f0..8af477c30b 100644 --- a/Content.Shared/Damage/Components/DamageOnHoldingComponent.cs +++ b/Content.Shared/Damage/Components/DamageOnHoldingComponent.cs @@ -5,7 +5,7 @@ using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom; namespace Content.Shared.Damage.Components; [RegisterComponent, NetworkedComponent] -[AutoGenerateComponentState] +[AutoGenerateComponentState, AutoGenerateComponentPause] [Access(typeof(DamageOnHoldingSystem))] public sealed partial class DamageOnHoldingComponent : Component { @@ -29,5 +29,6 @@ public sealed partial class DamageOnHoldingComponent : Component [DataField("nextDamage", customTypeSerializer: typeof(TimeOffsetSerializer)), ViewVariables(VVAccess.ReadWrite)] [AutoNetworkedField] + [AutoPausedField] public TimeSpan NextDamage = TimeSpan.Zero; } diff --git a/Content.Shared/Damage/Components/StaminaComponent.cs b/Content.Shared/Damage/Components/StaminaComponent.cs index 74e0f6c852..5a2fba4970 100644 --- a/Content.Shared/Damage/Components/StaminaComponent.cs +++ b/Content.Shared/Damage/Components/StaminaComponent.cs @@ -6,7 +6,7 @@ namespace Content.Shared.Damage.Components; /// /// Add to an entity to paralyze it whenever it reaches critical amounts of Stamina DamageType. /// -[RegisterComponent, NetworkedComponent, AutoGenerateComponentState(true)] +[RegisterComponent, NetworkedComponent, AutoGenerateComponentState(true), AutoGenerateComponentPause] public sealed partial class StaminaComponent : Component { /// @@ -49,5 +49,6 @@ public sealed partial class StaminaComponent : Component /// To avoid continuously updating our data we track the last time we updated so we can extrapolate our current stamina. /// [DataField(customTypeSerializer: typeof(TimeOffsetSerializer)), AutoNetworkedField] + [AutoPausedField] public TimeSpan NextUpdate = TimeSpan.Zero; } diff --git a/Content.Shared/Damage/Systems/DamageOnHoldingSystem.cs b/Content.Shared/Damage/Systems/DamageOnHoldingSystem.cs index e22be2fbbf..c13ec0a1b9 100644 --- a/Content.Shared/Damage/Systems/DamageOnHoldingSystem.cs +++ b/Content.Shared/Damage/Systems/DamageOnHoldingSystem.cs @@ -13,7 +13,6 @@ public sealed class DamageOnHoldingSystem : EntitySystem public override void Initialize() { base.Initialize(); - SubscribeLocalEvent(OnUnpaused); SubscribeLocalEvent(OnMapInit); } @@ -26,11 +25,6 @@ public sealed class DamageOnHoldingSystem : EntitySystem } } - private void OnUnpaused(EntityUid uid, DamageOnHoldingComponent component, ref EntityUnpausedEvent args) - { - component.NextDamage += args.PausedTime; - } - private void OnMapInit(EntityUid uid, DamageOnHoldingComponent component, MapInitEvent args) { component.NextDamage = _timing.CurTime; @@ -50,4 +44,4 @@ public sealed class DamageOnHoldingSystem : EntitySystem component.NextDamage = _timing.CurTime + TimeSpan.FromSeconds(component.Interval); } } -} \ No newline at end of file +} diff --git a/Content.Shared/Damage/Systems/StaminaSystem.cs b/Content.Shared/Damage/Systems/StaminaSystem.cs index 9ac23f1af8..b8ea953f25 100644 --- a/Content.Shared/Damage/Systems/StaminaSystem.cs +++ b/Content.Shared/Damage/Systems/StaminaSystem.cs @@ -46,7 +46,6 @@ public sealed partial class StaminaSystem : EntitySystem InitializeModifier(); - SubscribeLocalEvent(OnStamUnpaused); SubscribeLocalEvent(OnStartup); SubscribeLocalEvent(OnShutdown); SubscribeLocalEvent(OnStamHandleState); @@ -61,11 +60,6 @@ public sealed partial class StaminaSystem : EntitySystem SubscribeLocalEvent(OnMeleeHit); } - private void OnStamUnpaused(EntityUid uid, StaminaComponent component, ref EntityUnpausedEvent args) - { - component.NextUpdate += args.PausedTime; - } - private void OnStamHandleState(EntityUid uid, StaminaComponent component, ref AfterAutoHandleStateEvent args) { if (component.Critical) diff --git a/Content.Shared/Decals/Decal.cs b/Content.Shared/Decals/Decal.cs index 56ecc829e7..cb6f944c65 100644 --- a/Content.Shared/Decals/Decal.cs +++ b/Content.Shared/Decals/Decal.cs @@ -8,7 +8,7 @@ namespace Content.Shared.Decals public sealed partial class Decal { // if these are made not-readonly, then decal grid state handling needs to be updated to clone decals. - [DataField("coordinates")] public Vector2 Coordinates = Vector2.Zero; + [DataField("coordinates")] public Vector2 Coordinates = Vector2.Zero; [DataField("id")] public string Id = string.Empty; [DataField("color")] public Color? Color; [DataField("angle")] public Angle Angle = Angle.Zero; diff --git a/Content.Shared/Decals/DecalGridComponent.cs b/Content.Shared/Decals/DecalGridComponent.cs index 140eb5bafc..8ac05cb280 100644 --- a/Content.Shared/Decals/DecalGridComponent.cs +++ b/Content.Shared/Decals/DecalGridComponent.cs @@ -12,7 +12,8 @@ namespace Content.Shared.Decals [NetworkedComponent] public sealed partial class DecalGridComponent : Component { - [DataField("chunkCollection", serverOnly: true)] + [Access(Other = AccessPermissions.ReadExecute)] + [DataField(serverOnly: true)] public DecalGridChunkCollection ChunkCollection = new(new ()); /// @@ -25,10 +26,6 @@ namespace Content.Shared.Decals /// public GameTick ForceTick { get; set; } - // client-side data. I CBF creating a separate client-side comp for this. The server can survive with some empty dictionaries. - public readonly Dictionary DecalZIndexIndex = new(); - public readonly SortedDictionary> DecalRenderIndex = new(); - [DataDefinition] [Serializable, NetSerializable] public sealed partial class DecalChunk diff --git a/Content.Shared/Decals/SharedDecalSystem.cs b/Content.Shared/Decals/SharedDecalSystem.cs index 02f73bdacb..76fa9d64db 100644 --- a/Content.Shared/Decals/SharedDecalSystem.cs +++ b/Content.Shared/Decals/SharedDecalSystem.cs @@ -122,39 +122,6 @@ namespace Content.Shared.Decals } } - // TODO: Pretty sure paul was moving this somewhere but just so people know - public struct ChunkIndicesEnumerator - { - private Vector2i _chunkLB; - private Vector2i _chunkRT; - - private int _xIndex; - private int _yIndex; - - public ChunkIndicesEnumerator(Box2 localAABB, int chunkSize) - { - _chunkLB = new Vector2i((int)Math.Floor(localAABB.Left / chunkSize), (int)Math.Floor(localAABB.Bottom / chunkSize)); - _chunkRT = new Vector2i((int)Math.Floor(localAABB.Right / chunkSize), (int)Math.Floor(localAABB.Top / chunkSize)); - - _xIndex = _chunkLB.X; - _yIndex = _chunkLB.Y; - } - - public bool MoveNext([NotNullWhen(true)] out Vector2i? indices) - { - if (_yIndex > _chunkRT.Y) - { - _yIndex = _chunkLB.Y; - _xIndex += 1; - } - - indices = new Vector2i(_xIndex, _yIndex); - _yIndex += 1; - - return _xIndex <= _chunkRT.X; - } - } - /// /// Sent by clients to request that a decal is placed on the server. /// diff --git a/Content.Shared/Doors/Components/AirlockComponent.cs b/Content.Shared/Doors/Components/AirlockComponent.cs index 332df2ac77..dd8241c64e 100644 --- a/Content.Shared/Doors/Components/AirlockComponent.cs +++ b/Content.Shared/Doors/Components/AirlockComponent.cs @@ -12,6 +12,9 @@ namespace Content.Shared.Doors.Components; [Access(typeof(SharedAirlockSystem), Friend = AccessPermissions.ReadWriteExecute, Other = AccessPermissions.Read)] public sealed partial class AirlockComponent : Component { + [DataField, AutoNetworkedField] + public bool Powered; + // Need to network airlock safety state to avoid mis-predicts when a door auto-closes as the client walks through the door. [ViewVariables(VVAccess.ReadWrite)] [DataField, AutoNetworkedField] diff --git a/Content.Shared/Doors/Components/DoorBoltComponent.cs b/Content.Shared/Doors/Components/DoorBoltComponent.cs index 52f7d56db5..a5b0621ff4 100644 --- a/Content.Shared/Doors/Components/DoorBoltComponent.cs +++ b/Content.Shared/Doors/Components/DoorBoltComponent.cs @@ -8,36 +8,43 @@ namespace Content.Shared.Doors.Components; /// Companion component to DoorComponent that handles bolt-specific behavior. /// [RegisterComponent, NetworkedComponent] -[Access(typeof(SharedDoorBoltSystem))] +[Access(typeof(SharedDoorSystem))] +[AutoGenerateComponentState] public sealed partial class DoorBoltComponent : Component { /// /// Sound to play when the bolts on the airlock go up. /// - [DataField("boltUpSound"), ViewVariables(VVAccess.ReadWrite)] + [DataField, ViewVariables(VVAccess.ReadWrite)] public SoundSpecifier BoltUpSound = new SoundPathSpecifier("/Audio/Machines/boltsup.ogg"); /// /// Sound to play when the bolts on the airlock go down. /// - [DataField("boltDownSound"), ViewVariables(VVAccess.ReadWrite)] + [DataField, ViewVariables(VVAccess.ReadWrite)] public SoundSpecifier BoltDownSound = new SoundPathSpecifier("/Audio/Machines/boltsdown.ogg"); /// /// Whether the door bolts are currently deployed. /// - [ViewVariables(VVAccess.ReadWrite)] + [DataField, AutoNetworkedField] public bool BoltsDown; /// /// Whether the bolt lights are currently enabled. /// - [ViewVariables(VVAccess.ReadWrite)] + [DataField, AutoNetworkedField] public bool BoltLightsEnabled = true; /// /// True if the bolt wire is cut, which will force the airlock to always be bolted as long as it has power. /// - [ViewVariables(VVAccess.ReadWrite)] + [DataField, AutoNetworkedField] public bool BoltWireCut; + + /// + /// Used for prediction. true if the door has power. + /// + [DataField, AutoNetworkedField] + public bool Powered; } diff --git a/Content.Shared/Doors/Components/DoorComponent.cs b/Content.Shared/Doors/Components/DoorComponent.cs index 135f8b0856..d1b93d845d 100644 --- a/Content.Shared/Doors/Components/DoorComponent.cs +++ b/Content.Shared/Doors/Components/DoorComponent.cs @@ -124,14 +124,14 @@ public sealed partial class DoorComponent : Component /// If false, this door is incapable of crushing entities. This just determines whether it will apply damage and /// stun, not whether it can close despite entities being in the way. /// - [DataField] + [DataField, AutoNetworkedField] public bool CanCrush = true; /// /// Whether to check for colliding entities before closing. This may be overridden by other system by subscribing to /// . For example, hacked airlocks will set this to false. /// - [DataField] + [DataField, AutoNetworkedField] public bool PerformCollisionCheck = true; /// @@ -190,7 +190,7 @@ public sealed partial class DoorComponent : Component /// The sprite state used for the door when it's being emagged. /// [DataField] - public string EmaggingSpriteState = "emagging"; + public string EmaggingSpriteState = "sparks"; /// /// The sprite state used for the door when it's open. diff --git a/Content.Shared/Doors/Systems/SharedAirlockSystem.cs b/Content.Shared/Doors/Systems/SharedAirlockSystem.cs index 9e1273b784..a3172bb8c3 100644 --- a/Content.Shared/Doors/Systems/SharedAirlockSystem.cs +++ b/Content.Shared/Doors/Systems/SharedAirlockSystem.cs @@ -1,5 +1,7 @@ using Content.Shared.Doors.Components; using Content.Shared.Popups; +using Content.Shared.Prying.Components; +using Content.Shared.Wires; namespace Content.Shared.Doors.Systems; @@ -8,18 +10,112 @@ public abstract class SharedAirlockSystem : EntitySystem [Dependency] protected readonly SharedAppearanceSystem Appearance = default!; [Dependency] protected readonly SharedDoorSystem DoorSystem = default!; [Dependency] protected readonly SharedPopupSystem Popup = default!; + [Dependency] private readonly SharedWiresSystem _wiresSystem = default!; public override void Initialize() { base.Initialize(); SubscribeLocalEvent(OnBeforeDoorClosed); + SubscribeLocalEvent(OnStateChanged); + SubscribeLocalEvent(OnBeforeDoorOpened); + SubscribeLocalEvent(OnBeforeDoorDenied); + SubscribeLocalEvent(OnGetPryMod); + SubscribeLocalEvent(OnBeforePry); } - protected virtual void OnBeforeDoorClosed(EntityUid uid, AirlockComponent airlock, BeforeDoorClosedEvent args) + private void OnBeforeDoorClosed(EntityUid uid, AirlockComponent airlock, BeforeDoorClosedEvent args) { + if (args.Cancelled) + return; + if (!airlock.Safety) args.PerformCollisionCheck = false; + + // only block based on bolts / power status when initially closing the door, not when its already + // mid-transition. Particularly relevant for when the door was pried-closed with a crowbar, which bypasses + // the initial power-check. + + if (TryComp(uid, out DoorComponent? door) + && !door.Partial + && !CanChangeState(uid, airlock)) + { + args.Cancel(); + } + } + + private void OnStateChanged(EntityUid uid, AirlockComponent component, DoorStateChangedEvent args) + { + // Only show the maintenance panel if the airlock is closed + if (TryComp(uid, out var wiresPanel)) + { + _wiresSystem.ChangePanelVisibility(uid, wiresPanel, component.OpenPanelVisible || args.State != DoorState.Open); + } + // If the door is closed, we should look if the bolt was locked while closing + UpdateAutoClose(uid, component); + + // Make sure the airlock auto closes again next time it is opened + if (args.State == DoorState.Closed) + component.AutoClose = true; + } + + private void OnBeforeDoorOpened(EntityUid uid, AirlockComponent component, BeforeDoorOpenedEvent args) + { + if (!CanChangeState(uid, component)) + args.Cancel(); + } + + private void OnBeforeDoorDenied(EntityUid uid, AirlockComponent component, BeforeDoorDeniedEvent args) + { + if (!CanChangeState(uid, component)) + args.Cancel(); + } + + private void OnGetPryMod(EntityUid uid, AirlockComponent component, ref GetPryTimeModifierEvent args) + { + if (component.Powered) + args.PryTimeModifier *= component.PoweredPryModifier; + + if (DoorSystem.IsBolted(uid)) + args.PryTimeModifier *= component.BoltedPryModifier; + } + + /// + /// Updates the auto close timer. + /// + public void UpdateAutoClose(EntityUid uid, AirlockComponent? airlock = null, DoorComponent? door = null) + { + if (!Resolve(uid, ref airlock, ref door)) + return; + + if (door.State != DoorState.Open) + return; + + if (!airlock.AutoClose) + return; + + if (!CanChangeState(uid, airlock)) + return; + + var autoev = new BeforeDoorAutoCloseEvent(); + RaiseLocalEvent(uid, autoev); + if (autoev.Cancelled) + return; + + DoorSystem.SetNextStateChange(uid, airlock.AutoCloseDelay * airlock.AutoCloseDelayModifier); + } + + private void OnBeforePry(EntityUid uid, AirlockComponent component, ref BeforePryEvent args) + { + if (args.Cancelled) + return; + + if (!component.Powered || args.PryPowered) + return; + + args.Message = "airlock-component-cannot-pry-is-powered-message"; + + args.Cancelled = true; } public void UpdateEmergencyLightStatus(EntityUid uid, AirlockComponent component) @@ -45,4 +141,9 @@ public abstract class SharedAirlockSystem : EntitySystem { component.Safety = value; } + + public bool CanChangeState(EntityUid uid, AirlockComponent component) + { + return component.Powered && !DoorSystem.IsBolted(uid); + } } diff --git a/Content.Shared/Doors/Systems/SharedDoorBoltSystem.cs b/Content.Shared/Doors/Systems/SharedDoorBoltSystem.cs deleted file mode 100644 index 7c5ef45275..0000000000 --- a/Content.Shared/Doors/Systems/SharedDoorBoltSystem.cs +++ /dev/null @@ -1,61 +0,0 @@ -using Content.Shared.Doors.Components; -using Content.Shared.Popups; -using Content.Shared.Prying.Components; -using Robust.Shared.Audio; -using Robust.Shared.Audio.Systems; - -namespace Content.Shared.Doors.Systems; - -public abstract class SharedDoorBoltSystem : EntitySystem -{ - - [Dependency] protected readonly SharedAppearanceSystem Appearance = default!; - [Dependency] protected readonly SharedAudioSystem Audio = default!; - [Dependency] protected readonly SharedPopupSystem Popup = default!; - public override void Initialize() - { - base.Initialize(); - - SubscribeLocalEvent(OnBeforeDoorOpened); - SubscribeLocalEvent(OnBeforeDoorClosed); - SubscribeLocalEvent(OnBeforeDoorDenied); - SubscribeLocalEvent(OnDoorPry); - - } - - private void OnDoorPry(EntityUid uid, DoorBoltComponent component, ref BeforePryEvent args) - { - if (args.Cancelled) - return; - - if (!component.BoltsDown || args.Force) - return; - - args.Message = "airlock-component-cannot-pry-is-bolted-message"; - - args.Cancelled = true; - } - - private void OnBeforeDoorOpened(EntityUid uid, DoorBoltComponent component, BeforeDoorOpenedEvent args) - { - if (component.BoltsDown) - args.Cancel(); - } - - private void OnBeforeDoorClosed(EntityUid uid, DoorBoltComponent component, BeforeDoorClosedEvent args) - { - if (component.BoltsDown) - args.Cancel(); - } - - private void OnBeforeDoorDenied(EntityUid uid, DoorBoltComponent component, BeforeDoorDeniedEvent args) - { - if (component.BoltsDown) - args.Cancel(); - } - - public void SetBoltWireCut(DoorBoltComponent component, bool value) - { - component.BoltWireCut = value; - } -} diff --git a/Content.Shared/Doors/Systems/SharedDoorSystem.Bolts.cs b/Content.Shared/Doors/Systems/SharedDoorSystem.Bolts.cs new file mode 100644 index 0000000000..35681bfd82 --- /dev/null +++ b/Content.Shared/Doors/Systems/SharedDoorSystem.Bolts.cs @@ -0,0 +1,109 @@ +using Content.Shared.Doors.Components; +using Content.Shared.Prying.Components; + +namespace Content.Shared.Doors.Systems; + +public abstract partial class SharedDoorSystem +{ + public void InitializeBolts() + { + base.Initialize(); + + SubscribeLocalEvent(OnBeforeDoorOpened); + SubscribeLocalEvent(OnBeforeDoorClosed); + SubscribeLocalEvent(OnBeforeDoorDenied); + SubscribeLocalEvent(OnDoorPry); + SubscribeLocalEvent(OnStateChanged); + } + + private void OnDoorPry(EntityUid uid, DoorBoltComponent component, ref BeforePryEvent args) + { + if (args.Cancelled) + return; + + if (!component.BoltsDown || args.Force) + return; + + args.Message = "airlock-component-cannot-pry-is-bolted-message"; + + args.Cancelled = true; + } + + private void OnBeforeDoorOpened(EntityUid uid, DoorBoltComponent component, BeforeDoorOpenedEvent args) + { + if (component.BoltsDown) + args.Cancel(); + } + + private void OnBeforeDoorClosed(EntityUid uid, DoorBoltComponent component, BeforeDoorClosedEvent args) + { + if (component.BoltsDown) + args.Cancel(); + } + + private void OnBeforeDoorDenied(EntityUid uid, DoorBoltComponent component, BeforeDoorDeniedEvent args) + { + if (component.BoltsDown) + args.Cancel(); + } + + public void SetBoltWireCut(Entity ent, bool value) + { + ent.Comp.BoltWireCut = value; + Dirty(ent, ent.Comp); + } + + public void UpdateBoltLightStatus(Entity ent) + { + AppearanceSystem.SetData(ent, DoorVisuals.BoltLights, GetBoltLightsVisible(ent)); + } + + public bool GetBoltLightsVisible(Entity ent) + { + return ent.Comp.BoltLightsEnabled && + ent.Comp.BoltsDown && + ent.Comp.Powered; + } + + public void SetBoltLightsEnabled(Entity ent, bool value) + { + if (ent.Comp.BoltLightsEnabled == value) + return; + + ent.Comp.BoltLightsEnabled = value; + Dirty(ent, ent.Comp); + UpdateBoltLightStatus(ent); + } + + public void SetBoltsDown(Entity ent, bool value, EntityUid? user = null, bool predicted = false) + { + if (ent.Comp.BoltsDown == value) + return; + + ent.Comp.BoltsDown = value; + Dirty(ent, ent.Comp); + UpdateBoltLightStatus(ent); + + var sound = value ? ent.Comp.BoltDownSound : ent.Comp.BoltUpSound; + if (predicted) + Audio.PlayPredicted(sound, ent, user: user); + else + Audio.PlayPvs(sound, ent); + } + + private void OnStateChanged(Entity entity, ref DoorStateChangedEvent args) + { + // If the door is closed, we should look if the bolt was locked while closing + UpdateBoltLightStatus(entity); + } + + public bool IsBolted(EntityUid uid, DoorBoltComponent? component = null) + { + if (!Resolve(uid, ref component)) + { + return false; + } + + return component.BoltsDown; + } +} diff --git a/Content.Shared/Doors/Systems/SharedDoorSystem.cs b/Content.Shared/Doors/Systems/SharedDoorSystem.cs index f04f6c6dfe..6a2a25f614 100644 --- a/Content.Shared/Doors/Systems/SharedDoorSystem.cs +++ b/Content.Shared/Doors/Systems/SharedDoorSystem.cs @@ -1,26 +1,35 @@ using System.Linq; using Content.Shared.Access.Components; using Content.Shared.Access.Systems; +using Content.Shared.Administration.Logs; using Content.Shared.Damage; +using Content.Shared.Database; using Content.Shared.Doors.Components; +using Content.Shared.Emag.Systems; using Content.Shared.Hands.Components; using Content.Shared.Interaction; using Content.Shared.Physics; +using Content.Shared.Popups; using Content.Shared.Prying.Components; +using Content.Shared.Prying.Systems; using Content.Shared.Stunnable; using Content.Shared.Tag; +using Content.Shared.Tools.Systems; using Robust.Shared.Audio; using Robust.Shared.Physics.Components; using Robust.Shared.Physics.Events; using Robust.Shared.Physics.Systems; using Robust.Shared.Timing; using Robust.Shared.Audio.Systems; +using Robust.Shared.Network; namespace Content.Shared.Doors.Systems; -public abstract class SharedDoorSystem : EntitySystem +public abstract partial class SharedDoorSystem : EntitySystem { + [Dependency] private readonly ISharedAdminLogManager _adminLog = default!; [Dependency] protected readonly IGameTiming GameTiming = default!; + [Dependency] private readonly INetManager _net = default!; [Dependency] protected readonly SharedPhysicsSystem PhysicsSystem = default!; [Dependency] private readonly DamageableSystem _damageableSystem = default!; [Dependency] private readonly SharedStunSystem _stunSystem = default!; @@ -30,6 +39,11 @@ public abstract class SharedDoorSystem : EntitySystem [Dependency] protected readonly SharedAppearanceSystem AppearanceSystem = default!; [Dependency] private readonly OccluderSystem _occluder = default!; [Dependency] private readonly AccessReaderSystem _accessReaderSystem = default!; + [Dependency] private readonly PryingSystem _pryingSystem = default!; + [Dependency] protected readonly SharedPopupSystem Popup = default!; + + [ValidatePrototypeId] + public const string DoorBumpTag = "DoorBumpOpener"; /// /// A body must have an intersection percentage larger than this in order to be considered as colliding with a @@ -50,6 +64,8 @@ public abstract class SharedDoorSystem : EntitySystem { base.Initialize(); + InitializeBolts(); + SubscribeLocalEvent(OnComponentInit); SubscribeLocalEvent(OnRemove); @@ -60,8 +76,12 @@ public abstract class SharedDoorSystem : EntitySystem SubscribeLocalEvent(HandleCollide); SubscribeLocalEvent(PreventCollision); SubscribeLocalEvent(OnBeforePry); + SubscribeLocalEvent(OnAfterPry); + SubscribeLocalEvent(OnWeldAttempt); + SubscribeLocalEvent(OnWeldChanged); SubscribeLocalEvent(OnPryTimeModifier); + SubscribeLocalEvent(OnEmagged); } protected virtual void OnComponentInit(Entity ent, ref ComponentInit args) @@ -100,6 +120,23 @@ public abstract class SharedDoorSystem : EntitySystem _activeDoors.Remove(door); } + private void OnEmagged(EntityUid uid, DoorComponent door, ref GotEmaggedEvent args) + { + if (!TryComp(uid, out var airlock)) + return; + + if (IsBolted(uid) || !airlock.Powered) + return; + + if (door.State == DoorState.Closed) + { + if (!SetState(uid, DoorState.Emagging, door)) + return; + Audio.PlayPredicted(door.SparkSound, uid, args.UserUid, AudioParams.Default.WithVolume(8)); + args.Handled = true; + } + } + #region StateManagement private void OnHandleState(Entity ent, ref AfterAutoHandleStateEvent args) { @@ -113,14 +150,14 @@ public abstract class SharedDoorSystem : EntitySystem AppearanceSystem.SetData(ent, DoorVisuals.State, door.State); } - protected void SetState(EntityUid uid, DoorState state, DoorComponent? door = null) + protected bool SetState(EntityUid uid, DoorState state, DoorComponent? door = null) { if (!Resolve(uid, ref door)) - return; + return false; // If no change, return to avoid firing a new DoorStateChangedEvent. if (state == door.State) - return; + return false; switch (state) { @@ -159,14 +196,20 @@ public abstract class SharedDoorSystem : EntitySystem Dirty(uid, door); RaiseLocalEvent(uid, new DoorStateChangedEvent(state)); AppearanceSystem.SetData(uid, DoorVisuals.State, door.State); + return true; } #endregion #region Interactions - protected virtual void OnActivate(EntityUid uid, DoorComponent door, ActivateInWorldEvent args) + protected void OnActivate(EntityUid uid, DoorComponent door, ActivateInWorldEvent args) { - // avoid client-mispredicts, as the server will definitely handle this event + if (args.Handled || !door.ClickOpen) + return; + + if (!TryToggleDoor(uid, door, args.User, predicted: true)) + _pryingSystem.TryPry(uid, args.User, out _); + args.Handled = true; } @@ -181,6 +224,44 @@ public abstract class SharedDoorSystem : EntitySystem args.Cancelled = true; } + /// + /// Open or close a door after it has been successfully pried. + /// + private void OnAfterPry(EntityUid uid, DoorComponent door, ref PriedEvent args) + { + if (door.State == DoorState.Closed) + { + _adminLog.Add(LogType.Action, LogImpact.Medium, $"{ToPrettyString(args.User)} pried {ToPrettyString(uid)} open"); + StartOpening(uid, door, args.User, true); + } + else if (door.State == DoorState.Open) + { + _adminLog.Add(LogType.Action, LogImpact.Medium, $"{ToPrettyString(args.User)} pried {ToPrettyString(uid)} closed"); + StartClosing(uid, door, args.User, true); + } + } + + private void OnWeldAttempt(EntityUid uid, DoorComponent component, WeldableAttemptEvent args) + { + if (component.CurrentlyCrushing.Count > 0) + { + args.Cancel(); + return; + } + if (component.State != DoorState.Closed && component.State != DoorState.Welded) + { + args.Cancel(); + } + } + + private void OnWeldChanged(EntityUid uid, DoorComponent component, ref WeldableChangedEvent args) + { + if (component.State == DoorState.Closed) + SetState(uid, DoorState.Welded, component); + else if (component.State == DoorState.Welded) + SetState(uid, DoorState.Closed, component); + } + /// /// Update the door state/visuals and play an access denied sound when a user without access interacts with the /// door. @@ -199,13 +280,15 @@ public abstract class SharedDoorSystem : EntitySystem if (ev.Cancelled) return; - SetState(uid, DoorState.Denying, door); + if (!SetState(uid, DoorState.Denying, door)) + return; - if (door.DenySound != null) - PlaySound(uid, door.DenySound, AudioParams.Default.WithVolume(-3), user, predicted); + if (predicted) + Audio.PlayPredicted(door.DenySound, uid, user, AudioParams.Default.WithVolume(-3)); + else if (_net.IsServer) + Audio.PlayPvs(door.DenySound, uid, AudioParams.Default.WithVolume(-3)); } - public bool TryToggleDoor(EntityUid uid, DoorComponent? door = null, EntityUid? user = null, bool predicted = false) { if (!Resolve(uid, ref door)) @@ -215,7 +298,8 @@ public abstract class SharedDoorSystem : EntitySystem { return TryOpen(uid, door, user, predicted, quiet: door.State == DoorState.Denying); } - else if (door.State == DoorState.Open) + + if (door.State == DoorState.Open) { return TryClose(uid, door, user, predicted); } @@ -254,7 +338,7 @@ public abstract class SharedDoorSystem : EntitySystem if (!HasAccess(uid, user, door)) { if (!quiet) - Deny(uid, door); + Deny(uid, door, user, predicted: true); return false; } @@ -269,22 +353,29 @@ public abstract class SharedDoorSystem : EntitySystem /// The user (if any) opening the door /// Whether the interaction would have been /// predicted. See comments in the PlaySound method on the Server system for details - public virtual void StartOpening(EntityUid uid, DoorComponent? door = null, EntityUid? user = null, bool predicted = false) + public void StartOpening(EntityUid uid, DoorComponent? door = null, EntityUid? user = null, bool predicted = false) { if (!Resolve(uid, ref door)) return; - SetState(uid, DoorState.Opening, door); + var lastState = door.State; - if (door.OpenSound != null) - PlaySound(uid, door.OpenSound, AudioParams.Default.WithVolume(-5), user, predicted); + if (!SetState(uid, DoorState.Opening, door)) + return; + + if (predicted) + Audio.PlayPredicted(door.OpenSound, uid, user, AudioParams.Default.WithVolume(-5)); + else if (_net.IsServer) + Audio.PlayPvs(door.OpenSound, uid, AudioParams.Default.WithVolume(-5)); + + if (lastState == DoorState.Emagging && TryComp(uid, out var doorBoltComponent)) + SetBoltsDown((uid, doorBoltComponent), !doorBoltComponent.BoltsDown, user, true); // I'm not sure what the intent here is/was? It plays a sound if the user is opening a door with a hands // component, but no actual hands!? What!? Is this the sound of them head-butting the door to get it to open?? // I'm 99% sure something is wrong here, but I kind of want to keep it this way. - - if (user != null && TryComp(user.Value, out HandsComponent? hands) && hands.Hands.Count == 0) - PlaySound(uid, door.TryOpenDoorSound, AudioParams.Default.WithVolume(-2), user, predicted); + if (user != null && (!TryComp(user.Value, out HandsComponent? hands) || hands.Hands.Count == 0)) + Audio.PlayPredicted(door.TryOpenDoorSound, uid, user, AudioParams.Default.WithVolume(-2)); } /// @@ -310,7 +401,7 @@ public abstract class SharedDoorSystem : EntitySystem if (!Resolve(uid, ref door)) return false; - if (!CanClose(uid, door, user, false)) + if (!CanClose(uid, door, user)) return false; StartClosing(uid, door, user, predicted); @@ -323,9 +414,7 @@ public abstract class SharedDoorSystem : EntitySystem /// The uid of the door /// The doorcomponent of the door /// The user (if any) opening the door - /// Whether the interaction would have been - /// predicted. See comments in the PlaySound method on the Server system for details - public bool CanClose(EntityUid uid, DoorComponent? door = null, EntityUid? user = null, bool quiet = true) + public bool CanClose(EntityUid uid, DoorComponent? door = null, EntityUid? user = null) { if (!Resolve(uid, ref door)) return false; @@ -336,7 +425,7 @@ public abstract class SharedDoorSystem : EntitySystem return false; var ev = new BeforeDoorClosedEvent(door.PerformCollisionCheck); - RaiseLocalEvent(uid, ev, false); + RaiseLocalEvent(uid, ev); if (ev.Cancelled) return false; @@ -346,15 +435,18 @@ public abstract class SharedDoorSystem : EntitySystem return !ev.PerformCollisionCheck || !GetColliding(uid).Any(); } - public virtual void StartClosing(EntityUid uid, DoorComponent? door = null, EntityUid? user = null, bool predicted = false) + public void StartClosing(EntityUid uid, DoorComponent? door = null, EntityUid? user = null, bool predicted = false) { if (!Resolve(uid, ref door)) return; - SetState(uid, DoorState.Closing, door); + if (!SetState(uid, DoorState.Closing, door)) + return; - if (door.CloseSound != null) - PlaySound(uid, door.CloseSound, AudioParams.Default.WithVolume(-5), user, predicted); + if (predicted) + Audio.PlayPredicted(door.CloseSound, uid, user, AudioParams.Default.WithVolume(-5)); + else if (_net.IsServer) + Audio.PlayPvs(door.CloseSound, uid, AudioParams.Default.WithVolume(-5)); } /// @@ -367,7 +459,6 @@ public abstract class SharedDoorSystem : EntitySystem return false; door.Partial = true; - Dirty(uid, door); // Make sure no entity waled into the airlock when it started closing. if (!CanClose(uid, door)) @@ -380,6 +471,7 @@ public abstract class SharedDoorSystem : EntitySystem SetCollidable(uid, true, door, physics); door.NextStateChange = GameTiming.CurTime + door.CloseTimeTwo; + Dirty(uid, door); _activeDoors.Add((uid, door)); // Crush any entities. Note that we don't check airlock safety here. This should have been checked before @@ -489,10 +581,22 @@ public abstract class SharedDoorSystem : EntitySystem } } - protected virtual void HandleCollide(EntityUid uid, DoorComponent door, ref StartCollideEvent args) + /// + /// Open a door if a player or door-bumper (PDA, ID-card) collide with the door. Sadly, bullets no longer + /// generate "access denied" sounds as you fire at a door. + /// + private void HandleCollide(EntityUid uid, DoorComponent door, ref StartCollideEvent args) { - // TODO ACCESS READER move access reader to shared and predict door opening/closing - // Then this can be moved to the shared system without mispredicting. + if (!door.BumpOpen) + return; + + if (door.State is not (DoorState.Closed or DoorState.Denying)) + return; + + var otherUid = args.OtherEntity; + + if (Tags.HasTag(otherUid, DoorBumpTag)) + TryOpen(uid, door, otherUid, quiet: door.State == DoorState.Denying); } #endregion @@ -587,6 +691,19 @@ public abstract class SharedDoorSystem : EntitySystem _activeDoors.Add((uid, door)); } + protected void CheckDoorBump(Entity ent) + { + var (uid, door, physics) = ent; + if (door.BumpOpen) + { + foreach (var other in PhysicsSystem.GetContactingEntities(uid, physics, approximate: true)) + { + if (Tags.HasTag(other, DoorBumpTag) && TryOpen(uid, door, other, quiet: true)) + break; + } + } + } + /// /// Iterate over active doors and progress them to the next state if they need to be updated. /// @@ -619,8 +736,6 @@ public abstract class SharedDoorSystem : EntitySystem } } - protected virtual void CheckDoorBump(Entity ent) { } - /// /// Makes a door proceed to the next state (if applicable). /// @@ -632,7 +747,7 @@ public abstract class SharedDoorSystem : EntitySystem if (door.CurrentlyCrushing.Count > 0) // This is a closed door that is crushing people and needs to auto-open. Note that we don't check "can open" // here. The door never actually finished closing and we don't want people to get stuck inside of doors. - StartOpening(ent, door, predicted: true); + StartOpening(ent, door); switch (door.State) { @@ -665,7 +780,7 @@ public abstract class SharedDoorSystem : EntitySystem case DoorState.Open: // This door is open, and queued for an auto-close. - if (!TryClose(ent, door, predicted: true)) + if (!TryClose(ent, door)) { // The door failed to close (blocked?). Try again in one second. door.NextStateChange = time + TimeSpan.FromSeconds(1); @@ -679,6 +794,4 @@ public abstract class SharedDoorSystem : EntitySystem } } #endregion - - protected abstract void PlaySound(EntityUid uid, SoundSpecifier soundSpecifier, AudioParams audioParams, EntityUid? predictingPlayer, bool predicted); } diff --git a/Content.Shared/Emp/EmpDisabledComponent.cs b/Content.Shared/Emp/EmpDisabledComponent.cs index 33ba619a0d..9e5a56de83 100644 --- a/Content.Shared/Emp/EmpDisabledComponent.cs +++ b/Content.Shared/Emp/EmpDisabledComponent.cs @@ -7,7 +7,7 @@ namespace Content.Shared.Emp; /// While entity has this component it is "disabled" by EMP. /// Add desired behaviour in other systems /// -[RegisterComponent, NetworkedComponent] +[RegisterComponent, NetworkedComponent, AutoGenerateComponentPause] [Access(typeof(SharedEmpSystem))] public sealed partial class EmpDisabledComponent : Component { @@ -15,6 +15,7 @@ public sealed partial class EmpDisabledComponent : Component /// Moment of time when component is removed and entity stops being "disabled" /// [DataField("timeLeft", customTypeSerializer: typeof(TimeOffsetSerializer)), ViewVariables(VVAccess.ReadWrite)] + [AutoPausedField] public TimeSpan DisabledUntil; [DataField("effectCoolDown"), ViewVariables(VVAccess.ReadWrite)] @@ -23,5 +24,6 @@ public sealed partial class EmpDisabledComponent : Component /// /// When next effect will be spawned /// + [AutoPausedField] public TimeSpan TargetTime = TimeSpan.Zero; } diff --git a/Content.Shared/Execution/DoafterEvent.cs b/Content.Shared/Execution/DoafterEvent.cs deleted file mode 100644 index 7854974527..0000000000 --- a/Content.Shared/Execution/DoafterEvent.cs +++ /dev/null @@ -1,9 +0,0 @@ -using Content.Shared.DoAfter; -using Robust.Shared.Serialization; - -namespace Content.Shared.Execution; - -[Serializable, NetSerializable] -public sealed partial class ExecutionDoAfterEvent : SimpleDoAfterEvent -{ -} diff --git a/Content.Shared/Gravity/GravityShakeComponent.cs b/Content.Shared/Gravity/GravityShakeComponent.cs index e8608a9681..c910320a2f 100644 --- a/Content.Shared/Gravity/GravityShakeComponent.cs +++ b/Content.Shared/Gravity/GravityShakeComponent.cs @@ -6,12 +6,13 @@ namespace Content.Shared.Gravity; /// /// Indicates this entity is shaking due to gravity changes. /// -[RegisterComponent, NetworkedComponent, AutoGenerateComponentState] +[RegisterComponent, NetworkedComponent, AutoGenerateComponentState, AutoGenerateComponentPause] public sealed partial class GravityShakeComponent : Component { [ViewVariables(VVAccess.ReadWrite), DataField, AutoNetworkedField] public int ShakeTimes; [DataField(customTypeSerializer: typeof(TimeOffsetSerializer)), AutoNetworkedField] + [AutoPausedField] public TimeSpan NextShake; } diff --git a/Content.Shared/Gravity/SharedGravitySystem.Shake.cs b/Content.Shared/Gravity/SharedGravitySystem.Shake.cs index e590baae44..ad2e0e3ad5 100644 --- a/Content.Shared/Gravity/SharedGravitySystem.Shake.cs +++ b/Content.Shared/Gravity/SharedGravitySystem.Shake.cs @@ -5,16 +5,6 @@ public abstract partial class SharedGravitySystem protected const float GravityKick = 100.0f; protected const float ShakeCooldown = 0.2f; - private void InitializeShake() - { - SubscribeLocalEvent(OnShakeUnpaused); - } - - private void OnShakeUnpaused(EntityUid uid, GravityShakeComponent component, ref EntityUnpausedEvent args) - { - component.NextShake += args.PausedTime; - } - private void UpdateShake() { var curTime = Timing.CurTime; diff --git a/Content.Shared/Gravity/SharedGravitySystem.cs b/Content.Shared/Gravity/SharedGravitySystem.cs index a65c386ae5..100d2ee74f 100644 --- a/Content.Shared/Gravity/SharedGravitySystem.cs +++ b/Content.Shared/Gravity/SharedGravitySystem.cs @@ -61,8 +61,6 @@ namespace Content.Shared.Gravity SubscribeLocalEvent(OnGravityChange); SubscribeLocalEvent(OnGetState); SubscribeLocalEvent(OnHandleState); - - InitializeShake(); } public override void Update(float frameTime) diff --git a/Content.Shared/Hands/Components/HandsComponent.cs b/Content.Shared/Hands/Components/HandsComponent.cs index ef3b2a6a0e..904b10b3bd 100644 --- a/Content.Shared/Hands/Components/HandsComponent.cs +++ b/Content.Shared/Hands/Components/HandsComponent.cs @@ -5,7 +5,7 @@ using Robust.Shared.Serialization; namespace Content.Shared.Hands.Components; -[RegisterComponent, NetworkedComponent] +[RegisterComponent, NetworkedComponent, AutoGenerateComponentPause] [Access(typeof(SharedHandsSystem))] public sealed partial class HandsComponent : Component { @@ -62,6 +62,7 @@ public sealed partial class HandsComponent : Component /// The time at which throws will be allowed again. /// [DataField, ViewVariables(VVAccess.ReadWrite)] + [AutoPausedField] public TimeSpan NextThrowTime; /// diff --git a/Content.Shared/Item/ItemToggle/Components/ItemToggleSizeComponent.cs b/Content.Shared/Item/ItemToggle/Components/ItemToggleSizeComponent.cs index 353f3d6fd5..b7b47a0732 100644 --- a/Content.Shared/Item/ItemToggle/Components/ItemToggleSizeComponent.cs +++ b/Content.Shared/Item/ItemToggle/Components/ItemToggleSizeComponent.cs @@ -18,9 +18,21 @@ public sealed partial class ItemToggleSizeComponent : Component [ViewVariables(VVAccess.ReadWrite), DataField, AutoNetworkedField] public ProtoId? ActivatedSize = null; + /// + /// Item's shape when activated + /// + [ViewVariables(VVAccess.ReadWrite), DataField] + public List? ActivatedShape = null; + /// /// Item's size when deactivated. If none is mentioned, it uses the item's default size instead. /// [ViewVariables(VVAccess.ReadWrite), DataField, AutoNetworkedField] public ProtoId? DeactivatedSize = null; + + /// + /// Item's shape when deactivated. If none is mentioned, it uses the item's default shape instead. + /// + [ViewVariables(VVAccess.ReadWrite), DataField] + public List? DeactivatedShape = null; } diff --git a/Content.Shared/Item/SharedItemSystem.cs b/Content.Shared/Item/SharedItemSystem.cs index c6a86c5011..29e82f8ade 100644 --- a/Content.Shared/Item/SharedItemSystem.cs +++ b/Content.Shared/Item/SharedItemSystem.cs @@ -46,6 +46,15 @@ public abstract class SharedItemSystem : EntitySystem Dirty(uid, component); } + public void SetShape(EntityUid uid, List? shape, ItemComponent? component = null) + { + if (!Resolve(uid, ref component, false)) + return; + + component.Shape = shape; + Dirty(uid, component); + } + public void SetHeldPrefix(EntityUid uid, string? heldPrefix, bool force = false, ItemComponent? component = null) { if (!Resolve(uid, ref component, false)) @@ -209,6 +218,13 @@ public abstract class SharedItemSystem : EntitySystem if (args.Activated) { + if (itemToggleSize.ActivatedShape != null) + { + // Set the deactivated shape to the default item's shape before it gets changed. + itemToggleSize.DeactivatedShape ??= new List(GetItemShape(item)); + SetShape(uid, itemToggleSize.ActivatedShape, item); + } + if (itemToggleSize.ActivatedSize != null) { // Set the deactivated size to the default item's size before it gets changed. @@ -218,6 +234,11 @@ public abstract class SharedItemSystem : EntitySystem } else { + if (itemToggleSize.DeactivatedShape != null) + { + SetShape(uid, itemToggleSize.DeactivatedShape, item); + } + if (itemToggleSize.DeactivatedSize != null) { SetSize(uid, (ProtoId) itemToggleSize.DeactivatedSize, item); diff --git a/Content.Shared/Materials/ActiveMaterialReclaimerComponent.cs b/Content.Shared/Materials/ActiveMaterialReclaimerComponent.cs index 9c2ee9632e..2beeed5d1e 100644 --- a/Content.Shared/Materials/ActiveMaterialReclaimerComponent.cs +++ b/Content.Shared/Materials/ActiveMaterialReclaimerComponent.cs @@ -8,7 +8,7 @@ namespace Content.Shared.Materials; /// Tracker component for the process of reclaiming entities /// /// -[RegisterComponent, NetworkedComponent, Access(typeof(SharedMaterialReclaimerSystem))] +[RegisterComponent, NetworkedComponent, Access(typeof(SharedMaterialReclaimerSystem)), AutoGenerateComponentPause] public sealed partial class ActiveMaterialReclaimerComponent : Component { /// @@ -21,6 +21,7 @@ public sealed partial class ActiveMaterialReclaimerComponent : Component /// When the reclaiming process ends. /// [DataField("endTime", customTypeSerializer: typeof(TimeOffsetSerializer)), ViewVariables(VVAccess.ReadWrite)] + [AutoPausedField] public TimeSpan EndTime; /// diff --git a/Content.Shared/Materials/InsertingMaterialStorageComponent.cs b/Content.Shared/Materials/InsertingMaterialStorageComponent.cs index 007dc73345..8ff96c17a7 100644 --- a/Content.Shared/Materials/InsertingMaterialStorageComponent.cs +++ b/Content.Shared/Materials/InsertingMaterialStorageComponent.cs @@ -3,7 +3,7 @@ using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom; namespace Content.Shared.Materials; -[RegisterComponent, NetworkedComponent, AutoGenerateComponentState] +[RegisterComponent, NetworkedComponent, AutoGenerateComponentState, AutoGenerateComponentPause] public sealed partial class InsertingMaterialStorageComponent : Component { /// @@ -11,6 +11,7 @@ public sealed partial class InsertingMaterialStorageComponent : Component /// [DataField(customTypeSerializer: typeof(TimeOffsetSerializer)), AutoNetworkedField] [ViewVariables(VVAccess.ReadWrite)] + [AutoPausedField] public TimeSpan EndTime; [ViewVariables, AutoNetworkedField] diff --git a/Content.Shared/Materials/MaterialReclaimerComponent.cs b/Content.Shared/Materials/MaterialReclaimerComponent.cs index 6c625e2fa2..3e72baf604 100644 --- a/Content.Shared/Materials/MaterialReclaimerComponent.cs +++ b/Content.Shared/Materials/MaterialReclaimerComponent.cs @@ -10,7 +10,7 @@ namespace Content.Shared.Materials; /// This is a machine that handles converting entities /// into the raw materials and chemicals that make them up. /// -[RegisterComponent, NetworkedComponent, AutoGenerateComponentState] +[RegisterComponent, NetworkedComponent, AutoGenerateComponentState, AutoGenerateComponentPause] [Access(typeof(SharedMaterialReclaimerSystem))] public sealed partial class MaterialReclaimerComponent : Component { @@ -90,6 +90,7 @@ public sealed partial class MaterialReclaimerComponent : Component /// When the next sound will be allowed to be played. Used to prevent spam. /// [DataField(customTypeSerializer: typeof(TimeOffsetSerializer))] + [AutoPausedField] public TimeSpan NextSound; /// diff --git a/Content.Shared/Materials/SharedMaterialReclaimerSystem.cs b/Content.Shared/Materials/SharedMaterialReclaimerSystem.cs index 66cb25f530..ad8547acc0 100644 --- a/Content.Shared/Materials/SharedMaterialReclaimerSystem.cs +++ b/Content.Shared/Materials/SharedMaterialReclaimerSystem.cs @@ -34,13 +34,11 @@ public abstract class SharedMaterialReclaimerSystem : EntitySystem public override void Initialize() { SubscribeLocalEvent(OnShutdown); - SubscribeLocalEvent(OnUnpaused); SubscribeLocalEvent(OnExamined); SubscribeLocalEvent(OnEmagged); SubscribeLocalEvent(OnMapInit); SubscribeLocalEvent(OnCollide); SubscribeLocalEvent(OnActiveStartup); - SubscribeLocalEvent(OnActiveUnpaused); } private void OnMapInit(EntityUid uid, MaterialReclaimerComponent component, MapInitEvent args) @@ -53,11 +51,6 @@ public abstract class SharedMaterialReclaimerSystem : EntitySystem _audio.Stop(component.Stream); } - private void OnUnpaused(EntityUid uid, MaterialReclaimerComponent component, ref EntityUnpausedEvent args) - { - component.NextSound += args.PausedTime; - } - private void OnExamined(EntityUid uid, MaterialReclaimerComponent component, ExaminedEvent args) { args.PushMarkup(Loc.GetString("recycler-count-items", ("items", component.ItemsProcessed))); @@ -82,11 +75,6 @@ public abstract class SharedMaterialReclaimerSystem : EntitySystem component.ReclaimingContainer = Container.EnsureContainer(uid, ActiveReclaimerContainerId); } - private void OnActiveUnpaused(EntityUid uid, ActiveMaterialReclaimerComponent component, ref EntityUnpausedEvent args) - { - component.EndTime += args.PausedTime; - } - /// /// Tries to start processing an item via a . /// diff --git a/Content.Shared/Materials/SharedMaterialStorageSystem.cs b/Content.Shared/Materials/SharedMaterialStorageSystem.cs index 9f7c87df3c..b1de77d971 100644 --- a/Content.Shared/Materials/SharedMaterialStorageSystem.cs +++ b/Content.Shared/Materials/SharedMaterialStorageSystem.cs @@ -30,7 +30,6 @@ public abstract class SharedMaterialStorageSystem : EntitySystem SubscribeLocalEvent(OnMapInit); SubscribeLocalEvent(OnInteractUsing); - SubscribeLocalEvent(OnUnpaused); } public override void Update(float frameTime) @@ -52,11 +51,6 @@ public abstract class SharedMaterialStorageSystem : EntitySystem _appearance.SetData(uid, MaterialStorageVisuals.Inserting, false); } - private void OnUnpaused(EntityUid uid, InsertingMaterialStorageComponent component, ref EntityUnpausedEvent args) - { - component.EndTime += args.PausedTime; - } - /// /// Gets the volume of a specified material contained in this storage. /// diff --git a/Content.Shared/Medical/DefibrillatorComponent.cs b/Content.Shared/Medical/DefibrillatorComponent.cs index afd1e0cc96..2da5285285 100644 --- a/Content.Shared/Medical/DefibrillatorComponent.cs +++ b/Content.Shared/Medical/DefibrillatorComponent.cs @@ -11,7 +11,7 @@ namespace Content.Shared.Medical; /// This is used for defibrillators; a machine that shocks a dead /// person back into the world of the living. /// -[RegisterComponent, NetworkedComponent] +[RegisterComponent, NetworkedComponent, AutoGenerateComponentPause] public sealed partial class DefibrillatorComponent : Component { /// @@ -24,6 +24,7 @@ public sealed partial class DefibrillatorComponent : Component /// The time at which the zap cooldown will be completed /// [DataField("nextZapTime", customTypeSerializer: typeof(TimeOffsetSerializer)), ViewVariables(VVAccess.ReadWrite)] + [AutoPausedField] public TimeSpan? NextZapTime; /// diff --git a/Content.Shared/Ninja/Components/NinjaSuitComponent.cs b/Content.Shared/Ninja/Components/NinjaSuitComponent.cs index b6fac57b0b..7e7b1ffcd3 100644 --- a/Content.Shared/Ninja/Components/NinjaSuitComponent.cs +++ b/Content.Shared/Ninja/Components/NinjaSuitComponent.cs @@ -15,6 +15,7 @@ namespace Content.Shared.Ninja.Components; /// As an implementation detail, dashing with katana is a suit action which isn't ideal. /// [RegisterComponent, NetworkedComponent, Access(typeof(SharedNinjaSuitSystem)), AutoGenerateComponentState] +[AutoGenerateComponentPause] public sealed partial class NinjaSuitComponent : Component { /// @@ -46,6 +47,7 @@ public sealed partial class NinjaSuitComponent : Component /// Time at which we will be able to use our abilities again /// [DataField(customTypeSerializer: typeof(TimeOffsetSerializer))] + [AutoPausedField] public TimeSpan DisableCooldown; /// diff --git a/Content.Shared/Ninja/Systems/SharedNinjaSuitSystem.cs b/Content.Shared/Ninja/Systems/SharedNinjaSuitSystem.cs index 1449157538..fed41eaed8 100644 --- a/Content.Shared/Ninja/Systems/SharedNinjaSuitSystem.cs +++ b/Content.Shared/Ninja/Systems/SharedNinjaSuitSystem.cs @@ -27,7 +27,6 @@ public abstract class SharedNinjaSuitSystem : EntitySystem base.Initialize(); SubscribeLocalEvent(OnMapInit); - SubscribeLocalEvent(OnEntityUnpaused); SubscribeLocalEvent(OnEquipped); SubscribeLocalEvent(OnGetItemActions); @@ -43,11 +42,6 @@ public abstract class SharedNinjaSuitSystem : EntitySystem Dirty(uid, component); } - private void OnEntityUnpaused(Entity ent, ref EntityUnpausedEvent args) - { - ent.Comp.DisableCooldown += args.PausedTime; - } - /// /// Call the shared and serverside code for when a ninja equips the suit. /// diff --git a/Content.Shared/Nutrition/AnimalHusbandry/InfantComponent.cs b/Content.Shared/Nutrition/AnimalHusbandry/InfantComponent.cs index c6406a0866..2708c823d2 100644 --- a/Content.Shared/Nutrition/AnimalHusbandry/InfantComponent.cs +++ b/Content.Shared/Nutrition/AnimalHusbandry/InfantComponent.cs @@ -8,7 +8,7 @@ namespace Content.Shared.Nutrition.AnimalHusbandry; /// This is used for marking entities as infants. /// Infants have half the size, visually, and cannot breed. /// -[RegisterComponent, NetworkedComponent] +[RegisterComponent, NetworkedComponent, AutoGenerateComponentPause] public sealed partial class InfantComponent : Component { /// @@ -33,6 +33,7 @@ public sealed partial class InfantComponent : Component /// When the entity will stop being an infant. /// [DataField("infantEndTime", customTypeSerializer: typeof(TimeOffsetSerializer))] + [AutoPausedField] public TimeSpan InfantEndTime; /// diff --git a/Content.Shared/Nutrition/AnimalHusbandry/ReproductiveComponent.cs b/Content.Shared/Nutrition/AnimalHusbandry/ReproductiveComponent.cs index ea9edcb507..8d128f547e 100644 --- a/Content.Shared/Nutrition/AnimalHusbandry/ReproductiveComponent.cs +++ b/Content.Shared/Nutrition/AnimalHusbandry/ReproductiveComponent.cs @@ -9,13 +9,14 @@ namespace Content.Shared.Nutrition.AnimalHusbandry; /// given they are next to a particular entity that fulfills a whitelist, /// can create several "child" entities. /// -[RegisterComponent] +[RegisterComponent, AutoGenerateComponentPause] public sealed partial class ReproductiveComponent : Component { /// /// The next time when breeding will be attempted. /// [DataField(customTypeSerializer: typeof(TimeOffsetSerializer)), ViewVariables(VVAccess.ReadWrite)] + [AutoPausedField] public TimeSpan NextBreedAttempt; /// diff --git a/Content.Shared/Nutrition/Components/HungerComponent.cs b/Content.Shared/Nutrition/Components/HungerComponent.cs index 11197d8b42..9ac82ba283 100644 --- a/Content.Shared/Nutrition/Components/HungerComponent.cs +++ b/Content.Shared/Nutrition/Components/HungerComponent.cs @@ -9,7 +9,7 @@ using Robust.Shared.Serialization.TypeSerializers.Implementations.Generic; namespace Content.Shared.Nutrition.Components; [RegisterComponent, NetworkedComponent, Access(typeof(HungerSystem))] -[AutoGenerateComponentState] +[AutoGenerateComponentState, AutoGenerateComponentPause] public sealed partial class HungerComponent : Component { /// @@ -106,6 +106,7 @@ public sealed partial class HungerComponent : Component /// [DataField("nextUpdateTime", customTypeSerializer: typeof(TimeOffsetSerializer)), ViewVariables(VVAccess.ReadWrite)] [AutoNetworkedField] + [AutoPausedField] public TimeSpan NextUpdateTime; /// diff --git a/Content.Server/Nutrition/Components/OpenableComponent.cs b/Content.Shared/Nutrition/Components/OpenableComponent.cs similarity index 86% rename from Content.Server/Nutrition/Components/OpenableComponent.cs rename to Content.Shared/Nutrition/Components/OpenableComponent.cs index cc24bf44dc..3a230fc765 100644 --- a/Content.Server/Nutrition/Components/OpenableComponent.cs +++ b/Content.Shared/Nutrition/Components/OpenableComponent.cs @@ -1,27 +1,29 @@ -using Content.Server.Nutrition.EntitySystems; +using Content.Shared.Nutrition.EntitySystems; using Robust.Shared.Audio; +using Robust.Shared.GameStates; -namespace Content.Server.Nutrition.Components; +namespace Content.Shared.Nutrition.Components; /// /// A drink or food that can be opened. /// Starts closed, open it with Z or E. /// -[RegisterComponent, Access(typeof(OpenableSystem))] +[NetworkedComponent, AutoGenerateComponentState] +[RegisterComponent, Access(typeof(SharedOpenableSystem))] public sealed partial class OpenableComponent : Component { /// /// Whether this drink or food is opened or not. /// Drinks can only be drunk or poured from/into when open, and food can only be eaten when open. /// - [DataField] + [DataField, AutoNetworkedField] public bool Opened; /// /// If this is false you cant press Z to open it. /// Requires an OpenBehavior damage threshold or other logic to open. /// - [DataField] + [DataField, AutoNetworkedField] public bool OpenableByHand = true; /// @@ -61,7 +63,7 @@ public sealed partial class OpenableComponent : Component /// /// Can this item be closed again after opening? /// - [DataField] + [DataField, AutoNetworkedField] public bool Closeable; /// diff --git a/Content.Shared/Nutrition/Components/ThirstComponent.cs b/Content.Shared/Nutrition/Components/ThirstComponent.cs index 35eb4d2614..731346401f 100644 --- a/Content.Shared/Nutrition/Components/ThirstComponent.cs +++ b/Content.Shared/Nutrition/Components/ThirstComponent.cs @@ -6,7 +6,7 @@ using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom; namespace Content.Shared.Nutrition.Components; [RegisterComponent, NetworkedComponent, Access(typeof(ThirstSystem))] -[AutoGenerateComponentState] +[AutoGenerateComponentState, AutoGenerateComponentPause] public sealed partial class ThirstComponent : Component { // Base stuff @@ -35,6 +35,7 @@ public sealed partial class ThirstComponent : Component /// [DataField("nextUpdateTime", customTypeSerializer: typeof(TimeOffsetSerializer)), ViewVariables(VVAccess.ReadWrite)] [AutoNetworkedField] + [AutoPausedField] public TimeSpan NextUpdateTime; /// diff --git a/Content.Shared/Nutrition/EntitySystems/HungerSystem.cs b/Content.Shared/Nutrition/EntitySystems/HungerSystem.cs index 9c09603510..d8808b6e4a 100644 --- a/Content.Shared/Nutrition/EntitySystems/HungerSystem.cs +++ b/Content.Shared/Nutrition/EntitySystems/HungerSystem.cs @@ -23,18 +23,12 @@ public sealed class HungerSystem : EntitySystem { base.Initialize(); - SubscribeLocalEvent(OnUnpaused); SubscribeLocalEvent(OnMapInit); SubscribeLocalEvent(OnShutdown); SubscribeLocalEvent(OnRefreshMovespeed); SubscribeLocalEvent(OnRejuvenate); } - private void OnUnpaused(EntityUid uid, HungerComponent component, ref EntityUnpausedEvent args) - { - component.NextUpdateTime += args.PausedTime; - } - private void OnMapInit(EntityUid uid, HungerComponent component, MapInitEvent args) { var amount = _random.Next( diff --git a/Content.Shared/Nutrition/EntitySystems/SharedOpenableSystem.cs b/Content.Shared/Nutrition/EntitySystems/SharedOpenableSystem.cs index 274de89003..f3b1127578 100644 --- a/Content.Shared/Nutrition/EntitySystems/SharedOpenableSystem.cs +++ b/Content.Shared/Nutrition/EntitySystems/SharedOpenableSystem.cs @@ -1,7 +1,189 @@ +using Content.Shared.Examine; +using Content.Shared.Interaction; +using Content.Shared.Interaction.Events; +using Content.Shared.Nutrition.Components; +using Content.Shared.Popups; +using Content.Shared.Verbs; +using Content.Shared.Weapons.Melee.Events; +using Robust.Shared.Audio.Systems; +using Robust.Shared.Utility; + namespace Content.Shared.Nutrition.EntitySystems; +/// +/// Provides API for openable food and drinks, handles opening on use and preventing transfer when closed. +/// public abstract partial class SharedOpenableSystem : EntitySystem { + [Dependency] protected readonly SharedAppearanceSystem Appearance = default!; + [Dependency] protected readonly SharedAudioSystem Audio = default!; + [Dependency] protected readonly SharedPopupSystem Popup = default!; + + public override void Initialize() + { + base.Initialize(); + + SubscribeLocalEvent(OnInit); + SubscribeLocalEvent(OnUse); + SubscribeLocalEvent(OnExamined); + SubscribeLocalEvent(HandleIfClosed); + SubscribeLocalEvent(HandleIfClosed); + SubscribeLocalEvent>(AddOpenCloseVerbs); + } + + private void OnInit(EntityUid uid, OpenableComponent comp, ComponentInit args) + { + UpdateAppearance(uid, comp); + } + + private void OnUse(EntityUid uid, OpenableComponent comp, UseInHandEvent args) + { + if (args.Handled || !comp.OpenableByHand) + return; + + args.Handled = TryOpen(uid, comp, args.User); + } + + private void OnExamined(EntityUid uid, OpenableComponent comp, ExaminedEvent args) + { + if (!comp.Opened || !args.IsInDetailsRange) + return; + + var text = Loc.GetString(comp.ExamineText); + args.PushMarkup(text); + } + + private void HandleIfClosed(EntityUid uid, OpenableComponent comp, HandledEntityEventArgs args) + { + // prevent spilling/pouring/whatever drinks when closed + args.Handled = !comp.Opened; + } + + private void AddOpenCloseVerbs(EntityUid uid, OpenableComponent comp, GetVerbsEvent args) + { + if (args.Hands == null || !args.CanAccess || !args.CanInteract) + return; + + Verb verb; + if (comp.Opened) + { + if (!comp.Closeable) + return; + + verb = new() + { + Text = Loc.GetString(comp.CloseVerbText), + Icon = new SpriteSpecifier.Texture(new("/Textures/Interface/VerbIcons/close.svg.192dpi.png")), + Act = () => TryClose(args.Target, comp, args.User) + }; + } + else + { + verb = new() + { + Text = Loc.GetString(comp.OpenVerbText), + Icon = new SpriteSpecifier.Texture(new("/Textures/Interface/VerbIcons/open.svg.192dpi.png")), + Act = () => TryOpen(args.Target, comp, args.User) + }; + } + args.Verbs.Add(verb); + } + + /// + /// Returns true if the entity either does not have OpenableComponent or it is opened. + /// Drinks that don't have OpenableComponent are automatically open, so it returns true. + /// + public bool IsOpen(EntityUid uid, OpenableComponent? comp = null) + { + if (!Resolve(uid, ref comp, false)) + return true; + + return comp.Opened; + } + + /// + /// Returns true if the entity both has OpenableComponent and is not opened. + /// Drinks that don't have OpenableComponent are automatically open, so it returns false. + /// If user is not null a popup will be shown to them. + /// + public bool IsClosed(EntityUid uid, EntityUid? user = null, OpenableComponent? comp = null) + { + if (!Resolve(uid, ref comp, false)) + return false; + + if (comp.Opened) + return false; + + if (user != null) + Popup.PopupEntity(Loc.GetString(comp.ClosedPopup, ("owner", uid)), user.Value, user.Value); + + return true; + } + + /// + /// Update open visuals to the current value. + /// + public void UpdateAppearance(EntityUid uid, OpenableComponent? comp = null, AppearanceComponent? appearance = null) + { + if (!Resolve(uid, ref comp)) + return; + + Appearance.SetData(uid, OpenableVisuals.Opened, comp.Opened, appearance); + } + + /// + /// Sets the opened field and updates open visuals. + /// + public void SetOpen(EntityUid uid, bool opened = true, OpenableComponent? comp = null) + { + if (!Resolve(uid, ref comp, false) || opened == comp.Opened) + return; + + comp.Opened = opened; + Dirty(uid, comp); + + if (opened) + { + var ev = new OpenableOpenedEvent(); + RaiseLocalEvent(uid, ref ev); + } + else + { + var ev = new OpenableClosedEvent(); + RaiseLocalEvent(uid, ref ev); + } + + UpdateAppearance(uid, comp); + } + + /// + /// If closed, opens it and plays the sound. + /// + /// Whether it got opened + public bool TryOpen(EntityUid uid, OpenableComponent? comp = null, EntityUid? user = null) + { + if (!Resolve(uid, ref comp, false) || comp.Opened) + return false; + + SetOpen(uid, true, comp); + Audio.PlayPredicted(comp.Sound, uid, user); + return true; + } + + /// + /// If opened, closes it and plays the close sound, if one is defined. + /// + /// Whether it got closed + public bool TryClose(EntityUid uid, OpenableComponent? comp = null, EntityUid? user = null) + { + if (!Resolve(uid, ref comp, false) || !comp.Opened || !comp.Closeable) + return false; + + SetOpen(uid, false, comp); + if (comp.CloseSound != null) + Audio.PlayPredicted(comp.CloseSound, uid, user); + return true; + } } /// diff --git a/Content.Shared/Nutrition/EntitySystems/ThirstSystem.cs b/Content.Shared/Nutrition/EntitySystems/ThirstSystem.cs index 05a2338768..b070cee283 100644 --- a/Content.Shared/Nutrition/EntitySystems/ThirstSystem.cs +++ b/Content.Shared/Nutrition/EntitySystems/ThirstSystem.cs @@ -29,7 +29,6 @@ public sealed class ThirstSystem : EntitySystem SubscribeLocalEvent(OnRefreshMovespeed); SubscribeLocalEvent(OnMapInit); SubscribeLocalEvent(OnRejuvenate); - SubscribeLocalEvent(OnUnpaused); } private void OnMapInit(EntityUid uid, ThirstComponent component, MapInitEvent args) @@ -184,9 +183,4 @@ public sealed class ThirstSystem : EntitySystem UpdateEffects(uid, thirst); } } - - private void OnUnpaused(EntityUid uid, ThirstComponent component, ref EntityUnpausedEvent args) - { - component.NextUpdateTime += args.PausedTime; - } } diff --git a/Content.Shared/PowerCell/PowerCellDrawComponent.cs b/Content.Shared/PowerCell/PowerCellDrawComponent.cs index 6963326b70..708a86a8ea 100644 --- a/Content.Shared/PowerCell/PowerCellDrawComponent.cs +++ b/Content.Shared/PowerCell/PowerCellDrawComponent.cs @@ -6,7 +6,7 @@ namespace Content.Shared.PowerCell; /// /// Indicates that the entity's ActivatableUI requires power or else it closes. /// -[RegisterComponent, NetworkedComponent, AutoGenerateComponentState] +[RegisterComponent, NetworkedComponent, AutoGenerateComponentState, AutoGenerateComponentPause] public sealed partial class PowerCellDrawComponent : Component { #region Prediction @@ -49,5 +49,6 @@ public sealed partial class PowerCellDrawComponent : Component /// When the next automatic power draw will occur /// [DataField("nextUpdate", customTypeSerializer: typeof(TimeOffsetSerializer))] + [AutoPausedField] public TimeSpan NextUpdateTime; } diff --git a/Content.Shared/Preferences/HumanoidCharacterProfile.cs b/Content.Shared/Preferences/HumanoidCharacterProfile.cs index dff8734555..d5fc702037 100644 --- a/Content.Shared/Preferences/HumanoidCharacterProfile.cs +++ b/Content.Shared/Preferences/HumanoidCharacterProfile.cs @@ -391,11 +391,9 @@ namespace Content.Shared.Preferences return Appearance.MemberwiseEquals(other.Appearance); } - public void EnsureValid(string[] sponsorPrototypes) + public void EnsureValid(IConfigurationManager configManager, IPrototypeManager prototypeManager, string[] sponsorPrototypes) { - var prototypeManager = IoCManager.Resolve(); - - if (!prototypeManager.TryIndex(Species, out var speciesPrototype)) + if (!prototypeManager.TryIndex(Species, out var speciesPrototype) || speciesPrototype.RoundStart == false) { Species = SharedHumanoidAppearanceSystem.DefaultSpecies; speciesPrototype = prototypeManager.Index(Species); @@ -418,15 +416,10 @@ namespace Content.Shared.Preferences }; // ensure the species can be that sex and their age fits the founds - var age = Age; - if (speciesPrototype != null) - { - if (!speciesPrototype.Sexes.Contains(sex)) - { - sex = speciesPrototype.Sexes[0]; - } - age = Math.Clamp(Age, speciesPrototype.MinAge, speciesPrototype.MaxAge); - } + if (!speciesPrototype.Sexes.Contains(sex)) + sex = speciesPrototype.Sexes[0]; + + var age = Math.Clamp(Age, speciesPrototype.MinAge, speciesPrototype.MaxAge); var gender = Gender switch { @@ -453,7 +446,6 @@ namespace Content.Shared.Preferences name = name.Trim(); - var configManager = IoCManager.Resolve(); if (configManager.GetCVar(CCVars.RestrictedNames)) { name = Regex.Replace(name, @"[^А-Яа-яёЁ0-9' -]", string.Empty); // Corvax: Only cyrillic names @@ -515,7 +507,7 @@ namespace Content.Shared.Preferences }; var priorities = new Dictionary(JobPriorities - .Where(p => prototypeManager.HasIndex(p.Key) && p.Value switch + .Where(p => prototypeManager.TryIndex(p.Key, out var job) && job.SetPreference && p.Value switch { JobPriority.Never => false, // Drop never since that's assumed default. JobPriority.Low => true, @@ -525,7 +517,7 @@ namespace Content.Shared.Preferences })); var antags = AntagPreferences - .Where(prototypeManager.HasIndex) + .Where(id => prototypeManager.TryIndex(id, out var antag) && antag.SetPreference) .ToList(); var traits = TraitPreferences @@ -572,6 +564,13 @@ namespace Content.Shared.Preferences } // Corvax-TTS-End + public ICharacterProfile Validated(IConfigurationManager configManager, IPrototypeManager prototypeManager) + { + var profile = new HumanoidCharacterProfile(this); + profile.EnsureValid(configManager, prototypeManager); + return profile; + } + // sorry this is kind of weird and duplicated, /// working inside these non entity systems is a bit wack public static string GetName(string species, Gender gender) diff --git a/Content.Shared/Preferences/ICharacterProfile.cs b/Content.Shared/Preferences/ICharacterProfile.cs index 9c4f87da60..bdbdd66498 100644 --- a/Content.Shared/Preferences/ICharacterProfile.cs +++ b/Content.Shared/Preferences/ICharacterProfile.cs @@ -1,4 +1,6 @@ using Content.Shared.Humanoid; +using Robust.Shared.Configuration; +using Robust.Shared.Prototypes; namespace Content.Shared.Preferences { @@ -13,6 +15,11 @@ namespace Content.Shared.Preferences /// /// Makes this profile valid so there's no bad data like negative ages. /// - void EnsureValid(string[] sponsorPrototypes); // Corvax-Sponsors: Integrated filtering for sponsor prototypes (markings/species/etc) + void EnsureValid(IConfigurationManager configManager, IPrototypeManager prototypeManager, string[] sponsorPrototypes); // Corvax-Sponsors: Integrated filtering for sponsor prototypes (markings/species/etc) + + /// + /// Gets a copy of this profile that has applied, i.e. no invalid data. + /// + ICharacterProfile Validated(IConfigurationManager configManager, IPrototypeManager prototypeManager); } } diff --git a/Content.Shared/Projectiles/CanPenetrateComponent.cs b/Content.Shared/Projectiles/CanPenetrateComponent.cs deleted file mode 100644 index 6134978b1b..0000000000 --- a/Content.Shared/Projectiles/CanPenetrateComponent.cs +++ /dev/null @@ -1,42 +0,0 @@ -using Content.Shared.FixedPoint; -using Content.Shared.Physics; -using Robust.Shared.GameStates; - -namespace Content.Shared.Projectiles; - -[RegisterComponent, NetworkedComponent] -public sealed partial class CanPenetrateComponent : Component -{ - /// - /// Should the projectile keep the ability to deal damage after colliding. - /// - [DataField] - public bool DamageAfterCollide = true; - - /// - /// The CollisionLayer, up to and including the one set, the projectile is allowed to penetrate. - /// - /// - /// Can penetrate everything if this value is not set. - /// - [DataField] - public CollisionGroup? PenetrationLayer; - - /// - /// How many times the projectile is allowed to deal damage. - /// - /// - /// Can deal damage on every collision if this value is not set. - /// - [DataField] - public float? PenetrationPower; - - /// - /// Modifies the damage of a projectile after it has penetrated an entity. - /// - /// - /// Won't modify the projectile's damage if this value is not set. - /// - [DataField] - public FixedPoint2? DamageModifier; -} diff --git a/Content.Shared/Projectiles/SharedProjectileSystem.cs b/Content.Shared/Projectiles/SharedProjectileSystem.cs index 2fa5ee1c8c..f57e873653 100644 --- a/Content.Shared/Projectiles/SharedProjectileSystem.cs +++ b/Content.Shared/Projectiles/SharedProjectileSystem.cs @@ -169,33 +169,6 @@ public abstract partial class SharedProjectileSystem : EntitySystem /// private void AfterProjectileHit(EntityUid uid, ProjectileComponent component, ref AfterProjectileHitEvent args) { - if (!TryComp(uid, out var damageAfterCollide)) - return; - - //Delete the projectile if it hits an entity with a CollisionLayer that has a higher value than it's PenetrationLayer. - //This allows a projectile to only penetrate a specific set of entities. - if (damageAfterCollide.PenetrationLayer != null) - { - if (args.Fixture.CollisionLayer > (int) damageAfterCollide.PenetrationLayer || - damageAfterCollide.PenetrationPower == 0) - { - QueueDel(uid); - return; - } - } - - //Allow the projectile to deal damage again. - if(damageAfterCollide.DamageAfterCollide) - component.DamagedEntity = false; - - //If the projectile has a limit on the amount of penetrations, reduce it. - if (damageAfterCollide.PenetrationPower != null) - damageAfterCollide.PenetrationPower -= 1; - - //Apply the penetration damage modifier if the projectile has one. - if (damageAfterCollide.DamageModifier != null) - component.Damage *= damageAfterCollide.DamageModifier.Value; - //Overrides the original DeleteOnCollide if the projectile passes all penetration checks. //This is to prevent having to set DeleteOnCollide to false on every prototype //you want to give the ability to penetrate entities. diff --git a/Content.Shared/Prying/Systems/PryingSystem.cs b/Content.Shared/Prying/Systems/PryingSystem.cs index 7271258f5c..fa7a135e6c 100644 --- a/Content.Shared/Prying/Systems/PryingSystem.cs +++ b/Content.Shared/Prying/Systems/PryingSystem.cs @@ -74,8 +74,8 @@ public sealed class PryingSystem : EntitySystem if (!CanPry(target, user, out var message, comp)) { - if (message != null) - Popup.PopupEntity(Loc.GetString(message), target, user); + if (!string.IsNullOrWhiteSpace(message)) + Popup.PopupClient(Loc.GetString(message), target, user); // If we have reached this point we want the event that caused this // to be marked as handled. return true; @@ -162,23 +162,14 @@ public sealed class PryingSystem : EntitySystem if (!CanPry(uid, args.User, out var message, comp)) { - if (message != null) - Popup.PopupEntity(Loc.GetString(message), uid, args.User); + if (!string.IsNullOrWhiteSpace(message)) + Popup.PopupClient(Loc.GetString(message), uid, args.User); return; } - // TODO: When we get airlock prediction make this fully predicted. - // When that happens also fix the checking function in the Client AirlockSystem. if (args.Used != null && comp != null) { - if (HasComp(uid)) - { - _audioSystem.PlayPvs(comp.UseSound, args.Used.Value); - } - else - { - _audioSystem.PlayPredicted(comp.UseSound, args.Used.Value, args.User); - } + _audioSystem.PlayPredicted(comp.UseSound, args.Used.Value, args.User); } var ev = new PriedEvent(args.User); diff --git a/Content.Shared/Roles/DepartmentPrototype.cs b/Content.Shared/Roles/DepartmentPrototype.cs index f79b03f4a6..024eca37fa 100644 --- a/Content.Shared/Roles/DepartmentPrototype.cs +++ b/Content.Shared/Roles/DepartmentPrototype.cs @@ -37,3 +37,27 @@ public sealed partial class DepartmentPrototype : IPrototype [DataField("weight")] public int Weight { get; private set; } = 0; } + +/// +/// Sorts appropriately for display in the UI, +/// respecting their . +/// +public sealed class DepartmentUIComparer : IComparer +{ + public static readonly DepartmentUIComparer Instance = new(); + + public int Compare(DepartmentPrototype? x, DepartmentPrototype? y) + { + if (ReferenceEquals(x, y)) + return 0; + if (ReferenceEquals(null, y)) + return 1; + if (ReferenceEquals(null, x)) + return -1; + + var cmp = -x.Weight.CompareTo(y.Weight); + if (cmp != 0) + return cmp; + return string.Compare(x.ID, y.ID, StringComparison.Ordinal); + } +} diff --git a/Content.Shared/Roles/JobPrototype.cs b/Content.Shared/Roles/JobPrototype.cs index acb88e16f0..0064fcdf17 100644 --- a/Content.Shared/Roles/JobPrototype.cs +++ b/Content.Shared/Roles/JobPrototype.cs @@ -1,5 +1,6 @@ using Content.Shared.Access; using Content.Shared.Players.PlayTimeTracking; +using Content.Shared.Roles; using Content.Shared.StatusIcon; using Robust.Shared.Prototypes; using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype; @@ -70,6 +71,16 @@ namespace Content.Shared.Roles [DataField("weight")] public int Weight { get; private set; } + /// + /// How to sort this job relative to other jobs in the UI. + /// Jobs with a higher value with sort before jobs with a lower value. + /// If not set, is used as a fallback. + /// + [DataField] + public int? DisplayWeight { get; private set; } + + public int RealDisplayWeight => DisplayWeight ?? Weight; + /// /// A numerical score for how much easier this job is for antagonists. /// For traitors, reduces starting TC by this amount. Other gamemodes can use it for whatever they find fitting. @@ -106,4 +117,28 @@ namespace Content.Shared.Roles [DataField("extendedAccessGroups", customTypeSerializer: typeof(PrototypeIdListSerializer))] public IReadOnlyCollection ExtendedAccessGroups { get; private set; } = Array.Empty(); } + + /// + /// Sorts s appropriately for display in the UI, + /// respecting their . + /// + public sealed class JobUIComparer : IComparer + { + public static readonly JobUIComparer Instance = new(); + + public int Compare(JobPrototype? x, JobPrototype? y) + { + if (ReferenceEquals(x, y)) + return 0; + if (ReferenceEquals(null, y)) + return 1; + if (ReferenceEquals(null, x)) + return -1; + + var cmp = -x.RealDisplayWeight.CompareTo(y.RealDisplayWeight); + if (cmp != 0) + return cmp; + return string.Compare(x.ID, y.ID, StringComparison.Ordinal); + } + } } diff --git a/Content.Shared/Salvage/Expeditions/SalvageExpeditions.cs b/Content.Shared/Salvage/Expeditions/SalvageExpeditions.cs index 41f44f672b..fe4d59b81a 100644 --- a/Content.Shared/Salvage/Expeditions/SalvageExpeditions.cs +++ b/Content.Shared/Salvage/Expeditions/SalvageExpeditions.cs @@ -42,7 +42,7 @@ public sealed class ClaimSalvageMessage : BoundUserInterfaceMessage /// /// Added per station to store data on their available salvage missions. /// -[RegisterComponent] +[RegisterComponent, AutoGenerateComponentPause] public sealed partial class SalvageExpeditionDataComponent : Component { /// @@ -61,6 +61,7 @@ public sealed partial class SalvageExpeditionDataComponent : Component /// Nexy time salvage missions are offered. /// [ViewVariables(VVAccess.ReadWrite), DataField("nextOffer", customTypeSerializer:typeof(TimeOffsetSerializer))] + [AutoPausedField] public TimeSpan NextOffer; [ViewVariables] diff --git a/Content.Shared/Salvage/Fulton/FultonedComponent.cs b/Content.Shared/Salvage/Fulton/FultonedComponent.cs index 3070249eee..c73237a366 100644 --- a/Content.Shared/Salvage/Fulton/FultonedComponent.cs +++ b/Content.Shared/Salvage/Fulton/FultonedComponent.cs @@ -7,7 +7,7 @@ namespace Content.Shared.Salvage.Fulton; /// /// Marks an entity as pending being fultoned. /// -[RegisterComponent, NetworkedComponent, AutoGenerateComponentState(true)] +[RegisterComponent, NetworkedComponent, AutoGenerateComponentState(true), AutoGenerateComponentPause] public sealed partial class FultonedComponent : Component { /// @@ -26,6 +26,7 @@ public sealed partial class FultonedComponent : Component /// When the fulton is travelling to the beacon. /// [ViewVariables(VVAccess.ReadWrite), DataField("nextFulton", customTypeSerializer:typeof(TimeOffsetSerializer)), AutoNetworkedField] + [AutoPausedField] public TimeSpan NextFulton; [ViewVariables(VVAccess.ReadWrite), DataField("sound"), AutoNetworkedField] diff --git a/Content.Shared/Salvage/Fulton/SharedFultonSystem.cs b/Content.Shared/Salvage/Fulton/SharedFultonSystem.cs index adaef16608..0599482bbe 100644 --- a/Content.Shared/Salvage/Fulton/SharedFultonSystem.cs +++ b/Content.Shared/Salvage/Fulton/SharedFultonSystem.cs @@ -40,7 +40,6 @@ public abstract partial class SharedFultonSystem : EntitySystem SubscribeLocalEvent(OnFultonDoAfter); - SubscribeLocalEvent(OnFultonUnpaused); SubscribeLocalEvent>(OnFultonedGetVerbs); SubscribeLocalEvent(OnFultonedExamine); SubscribeLocalEvent(OnFultonContainerInserted); @@ -106,11 +105,6 @@ public abstract partial class SharedFultonSystem : EntitySystem Audio.PlayPredicted(fulton.FultonSound, args.Target.Value, args.User); } - private void OnFultonUnpaused(EntityUid uid, FultonedComponent component, ref EntityUnpausedEvent args) - { - component.NextFulton += args.PausedTime; - } - private void OnFultonInteract(EntityUid uid, FultonComponent component, AfterInteractEvent args) { if (args.Target == null || args.Handled || !args.CanReach) diff --git a/Content.Shared/Singularity/Components/EventHorizonComponent.cs b/Content.Shared/Singularity/Components/EventHorizonComponent.cs index 2aa081915b..106d790ccb 100644 --- a/Content.Shared/Singularity/Components/EventHorizonComponent.cs +++ b/Content.Shared/Singularity/Components/EventHorizonComponent.cs @@ -10,7 +10,7 @@ namespace Content.Shared.Singularity.Components; /// Primarily managed by and its server/client versions. /// [Access(friends: typeof(SharedEventHorizonSystem))] -[RegisterComponent, NetworkedComponent] +[RegisterComponent, NetworkedComponent, AutoGenerateComponentPause] public sealed partial class EventHorizonComponent : Component { /// @@ -78,6 +78,7 @@ public sealed partial class EventHorizonComponent : Component /// The next time at which this consumed everything it overlapped with. /// [ViewVariables(VVAccess.ReadOnly), DataField("nextConsumeWaveTime", customTypeSerializer:typeof(TimeOffsetSerializer))] + [AutoPausedField] public TimeSpan NextConsumeWaveTime; #endregion Update Timing diff --git a/Content.Shared/Sound/Components/EmitSoundOnCollideComponent.cs b/Content.Shared/Sound/Components/EmitSoundOnCollideComponent.cs index f2c71ad120..a2cdd63ab7 100644 --- a/Content.Shared/Sound/Components/EmitSoundOnCollideComponent.cs +++ b/Content.Shared/Sound/Components/EmitSoundOnCollideComponent.cs @@ -3,7 +3,7 @@ using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom; namespace Content.Shared.Sound.Components; -[RegisterComponent, NetworkedComponent] +[RegisterComponent, NetworkedComponent, AutoGenerateComponentPause] public sealed partial class EmitSoundOnCollideComponent : BaseEmitSoundComponent { public static readonly TimeSpan CollideCooldown = TimeSpan.FromSeconds(0.2); @@ -18,5 +18,6 @@ public sealed partial class EmitSoundOnCollideComponent : BaseEmitSoundComponent /// To avoid sound spam add a cooldown to it. /// [ViewVariables(VVAccess.ReadWrite), DataField("nextSound", customTypeSerializer: typeof(TimeOffsetSerializer))] + [AutoPausedField] public TimeSpan NextSound; } diff --git a/Content.Shared/Sound/SharedEmitSoundSystem.cs b/Content.Shared/Sound/SharedEmitSoundSystem.cs index 5e131a1355..22ba8e0e3e 100644 --- a/Content.Shared/Sound/SharedEmitSoundSystem.cs +++ b/Content.Shared/Sound/SharedEmitSoundSystem.cs @@ -42,7 +42,6 @@ public abstract class SharedEmitSoundSystem : EntitySystem SubscribeLocalEvent(OnEmitSoundOnPickup); SubscribeLocalEvent(OnEmitSoundOnDrop); - SubscribeLocalEvent(OnEmitSoundUnpaused); SubscribeLocalEvent(OnEmitSoundOnCollide); } @@ -119,11 +118,6 @@ public abstract class SharedEmitSoundSystem : EntitySystem } } - private void OnEmitSoundUnpaused(EntityUid uid, EmitSoundOnCollideComponent component, ref EntityUnpausedEvent args) - { - component.NextSound += args.PausedTime; - } - private void OnEmitSoundOnCollide(EntityUid uid, EmitSoundOnCollideComponent component, ref StartCollideEvent args) { if (!args.OurFixture.Hard || diff --git a/Content.Shared/Storage/Components/MagnetPickupComponent.cs b/Content.Shared/Storage/Components/MagnetPickupComponent.cs index c57b7c4e85..3467439a6d 100644 --- a/Content.Shared/Storage/Components/MagnetPickupComponent.cs +++ b/Content.Shared/Storage/Components/MagnetPickupComponent.cs @@ -5,10 +5,11 @@ namespace Content.Server.Storage.Components; /// /// Applies an ongoing pickup area around the attached entity. /// -[RegisterComponent] +[RegisterComponent, AutoGenerateComponentPause] public sealed partial class MagnetPickupComponent : Component { [ViewVariables(VVAccess.ReadWrite), DataField("nextScan")] + [AutoPausedField] public TimeSpan NextScan = TimeSpan.Zero; /// diff --git a/Content.Shared/Storage/EntitySystems/BinSystem.cs b/Content.Shared/Storage/EntitySystems/BinSystem.cs index afb1e52881..17c3eb4288 100644 --- a/Content.Shared/Storage/EntitySystems/BinSystem.cs +++ b/Content.Shared/Storage/EntitySystems/BinSystem.cs @@ -4,12 +4,11 @@ using Content.Shared.Database; using Content.Shared.Examine; using Content.Shared.Hands.EntitySystems; using Content.Shared.Interaction; +using Content.Shared.Item; using Content.Shared.Storage.Components; using Content.Shared.Verbs; using Robust.Shared.Containers; -using Robust.Shared.Map; using Robust.Shared.Network; -using Robust.Shared.Timing; namespace Content.Shared.Storage.EntitySystems; @@ -18,7 +17,6 @@ namespace Content.Shared.Storage.EntitySystems; /// public sealed class BinSystem : EntitySystem { - [Dependency] private readonly IGameTiming _timing = default!; [Dependency] private readonly INetManager _net = default!; [Dependency] private readonly ISharedAdminLogManager _admin = default!; [Dependency] private readonly SharedContainerSystem _container = default!; @@ -32,7 +30,7 @@ public sealed class BinSystem : EntitySystem SubscribeLocalEvent(OnStartup); SubscribeLocalEvent(OnMapInit); SubscribeLocalEvent(OnEntRemoved); - SubscribeLocalEvent(OnInteractHand); + SubscribeLocalEvent(OnInteractHand, before: new[] { typeof(SharedItemSystem) }); SubscribeLocalEvent(OnAfterInteractUsing); SubscribeLocalEvent>(OnAltInteractHand); SubscribeLocalEvent(OnExamined); @@ -73,7 +71,7 @@ public sealed class BinSystem : EntitySystem private void OnInteractHand(EntityUid uid, BinComponent component, InteractHandEvent args) { - if (args.Handled || !_timing.IsFirstTimePredicted) + if (args.Handled) return; EntityUid? toGrab = component.Items.LastOrDefault(); @@ -111,9 +109,6 @@ public sealed class BinSystem : EntitySystem if (handled || !canReach) return; - if (!_timing.IsFirstTimePredicted) - return; - if (!TryInsertIntoBin(target, itemInHand, component)) return; diff --git a/Content.Shared/Storage/EntitySystems/MagnetPickupSystem.cs b/Content.Shared/Storage/EntitySystems/MagnetPickupSystem.cs index 1703db25f3..21861f57da 100644 --- a/Content.Shared/Storage/EntitySystems/MagnetPickupSystem.cs +++ b/Content.Shared/Storage/EntitySystems/MagnetPickupSystem.cs @@ -26,12 +26,6 @@ public sealed class MagnetPickupSystem : EntitySystem base.Initialize(); _physicsQuery = GetEntityQuery(); SubscribeLocalEvent(OnMagnetMapInit); - SubscribeLocalEvent(OnMagnetUnpaused); - } - - private void OnMagnetUnpaused(EntityUid uid, MagnetPickupComponent component, ref EntityUnpausedEvent args) - { - component.NextScan += args.PausedTime; } private void OnMagnetMapInit(EntityUid uid, MagnetPickupComponent component, MapInitEvent args) diff --git a/Content.Shared/Teleportation/Components/SwapTeleporterComponent.cs b/Content.Shared/Teleportation/Components/SwapTeleporterComponent.cs index 7a7bac83f4..a080a83aaa 100644 --- a/Content.Shared/Teleportation/Components/SwapTeleporterComponent.cs +++ b/Content.Shared/Teleportation/Components/SwapTeleporterComponent.cs @@ -11,7 +11,7 @@ namespace Content.Shared.Teleportation.Components; /// This is used for an entity that, when linked to another valid entity, allows the two to swap positions, /// additionally swapping the positions of the parents. /// -[RegisterComponent, NetworkedComponent, AutoGenerateComponentState] +[RegisterComponent, NetworkedComponent, AutoGenerateComponentState, AutoGenerateComponentPause] [Access(typeof(SwapTeleporterSystem))] public sealed partial class SwapTeleporterComponent : Component { @@ -37,6 +37,7 @@ public sealed partial class SwapTeleporterComponent : Component /// The time at which ends and teleportation can occur again. /// [DataField(customTypeSerializer: typeof(TimeOffsetSerializer)), ViewVariables(VVAccess.ReadWrite), AutoNetworkedField] + [AutoPausedField] public TimeSpan NextTeleportUse; /// diff --git a/Content.Shared/Teleportation/Systems/SwapTeleporterSystem.cs b/Content.Shared/Teleportation/Systems/SwapTeleporterSystem.cs index e900700e11..98a8955c7b 100644 --- a/Content.Shared/Teleportation/Systems/SwapTeleporterSystem.cs +++ b/Content.Shared/Teleportation/Systems/SwapTeleporterSystem.cs @@ -33,7 +33,6 @@ public sealed class SwapTeleporterSystem : EntitySystem SubscribeLocalEvent(OnActivateInWorld); SubscribeLocalEvent(OnExamined); - SubscribeLocalEvent(OnUnpaused); SubscribeLocalEvent(OnShutdown); _xformQuery = GetEntityQuery(); @@ -217,11 +216,6 @@ public sealed class SwapTeleporterSystem : EntitySystem } } - private void OnUnpaused(Entity ent, ref EntityUnpausedEvent args) - { - ent.Comp.NextTeleportUse += args.PausedTime; - } - private void OnShutdown(Entity ent, ref ComponentShutdown args) { DestroyLink((ent, ent), null); diff --git a/Content.Shared/Throwing/ThrownItemComponent.cs b/Content.Shared/Throwing/ThrownItemComponent.cs index ab80e07938..16c9b13254 100644 --- a/Content.Shared/Throwing/ThrownItemComponent.cs +++ b/Content.Shared/Throwing/ThrownItemComponent.cs @@ -5,7 +5,7 @@ using Robust.Shared.Timing; namespace Content.Shared.Throwing { - [RegisterComponent, NetworkedComponent, AutoGenerateComponentState(true)] + [RegisterComponent, NetworkedComponent, AutoGenerateComponentState(true), AutoGenerateComponentPause] public sealed partial class ThrownItemComponent : Component { /// @@ -24,6 +24,7 @@ namespace Content.Shared.Throwing /// Compared to to land this entity, if any. /// [DataField, ViewVariables(VVAccess.ReadWrite), AutoNetworkedField] + [AutoPausedField] public TimeSpan? LandTime; /// diff --git a/Content.Shared/Throwing/ThrownItemSystem.cs b/Content.Shared/Throwing/ThrownItemSystem.cs index 8d84cf36fa..0f38c4d753 100644 --- a/Content.Shared/Throwing/ThrownItemSystem.cs +++ b/Content.Shared/Throwing/ThrownItemSystem.cs @@ -35,7 +35,6 @@ namespace Content.Shared.Throwing SubscribeLocalEvent(HandleCollision); SubscribeLocalEvent(PreventCollision); SubscribeLocalEvent(ThrowItem); - SubscribeLocalEvent(OnThrownUnpaused); SubscribeLocalEvent(HandlePullStarted); } @@ -59,14 +58,6 @@ namespace Content.Shared.Throwing _fixtures.TryCreateFixture(uid, shape, ThrowingFixture, hard: false, collisionMask: (int) CollisionGroup.ThrownItem, manager: fixturesComponent, body: body); } - private void OnThrownUnpaused(EntityUid uid, ThrownItemComponent component, ref EntityUnpausedEvent args) - { - if (component.LandTime != null) - { - component.LandTime = component.LandTime.Value + args.PausedTime; - } - } - private void HandleCollision(EntityUid uid, ThrownItemComponent component, ref StartCollideEvent args) { if (!args.OtherFixture.Hard) diff --git a/Content.Shared/Timing/UseDelayComponent.cs b/Content.Shared/Timing/UseDelayComponent.cs index 784fd6632f..1560d4dd0b 100644 --- a/Content.Shared/Timing/UseDelayComponent.cs +++ b/Content.Shared/Timing/UseDelayComponent.cs @@ -10,7 +10,7 @@ namespace Content.Shared.Timing; /// Currently it only supports a single delay per entity, this means that for things that have two delay interactions they will share one timer, so this can cause issues. For example, the bible has a delay when opening the storage UI and when applying it's interaction effect, and they share the same delay. /// [RegisterComponent] -[NetworkedComponent, AutoGenerateComponentState] +[NetworkedComponent, AutoGenerateComponentState, AutoGenerateComponentPause] [Access(typeof(UseDelaySystem))] public sealed partial class UseDelayComponent : Component { @@ -18,12 +18,14 @@ public sealed partial class UseDelayComponent : Component /// When the delay starts. /// [ViewVariables(VVAccess.ReadWrite), DataField(customTypeSerializer: typeof(TimeOffsetSerializer)), AutoNetworkedField] + [AutoPausedField] public TimeSpan DelayStartTime; /// /// When the delay ends. /// [ViewVariables(VVAccess.ReadWrite), DataField(customTypeSerializer: typeof(TimeOffsetSerializer)), AutoNetworkedField] + [AutoPausedField] public TimeSpan DelayEndTime; /// diff --git a/Content.Shared/Timing/UseDelaySystem.cs b/Content.Shared/Timing/UseDelaySystem.cs index 34f12fa55e..388f31079c 100644 --- a/Content.Shared/Timing/UseDelaySystem.cs +++ b/Content.Shared/Timing/UseDelaySystem.cs @@ -7,19 +7,6 @@ public sealed class UseDelaySystem : EntitySystem [Dependency] private readonly IGameTiming _gameTiming = default!; [Dependency] private readonly MetaDataSystem _metadata = default!; - public override void Initialize() - { - SubscribeLocalEvent(OnUnpaused); - } - - private void OnUnpaused(Entity ent, ref EntityUnpausedEvent args) - { - // We got unpaused, resume the delay - ent.Comp.DelayStartTime += args.PausedTime; - ent.Comp.DelayEndTime += args.PausedTime; - Dirty(ent); - } - public void SetDelay(Entity ent, TimeSpan delay) { if (ent.Comp.Delay == delay) diff --git a/Content.Shared/Weapons/Marker/DamageMarkerComponent.cs b/Content.Shared/Weapons/Marker/DamageMarkerComponent.cs index ef3b712f60..87ad6519d0 100644 --- a/Content.Shared/Weapons/Marker/DamageMarkerComponent.cs +++ b/Content.Shared/Weapons/Marker/DamageMarkerComponent.cs @@ -10,6 +10,7 @@ namespace Content.Shared.Weapons.Marker; /// Marks an entity to take additional damage /// [RegisterComponent, NetworkedComponent, AutoGenerateComponentState, Access(typeof(SharedDamageMarkerSystem))] +[AutoGenerateComponentPause] public sealed partial class DamageMarkerComponent : Component { /// @@ -34,5 +35,6 @@ public sealed partial class DamageMarkerComponent : Component public EntityUid Marker; [ViewVariables(VVAccess.ReadWrite), DataField("endTime", customTypeSerializer:typeof(TimeOffsetSerializer)), AutoNetworkedField] + [AutoPausedField] public TimeSpan EndTime; } diff --git a/Content.Shared/Weapons/Marker/SharedDamageMarkerSystem.cs b/Content.Shared/Weapons/Marker/SharedDamageMarkerSystem.cs index 3a6afce363..63b2d5f211 100644 --- a/Content.Shared/Weapons/Marker/SharedDamageMarkerSystem.cs +++ b/Content.Shared/Weapons/Marker/SharedDamageMarkerSystem.cs @@ -20,7 +20,6 @@ public abstract class SharedDamageMarkerSystem : EntitySystem { base.Initialize(); SubscribeLocalEvent(OnMarkerCollide); - SubscribeLocalEvent(OnMarkerUnpaused); SubscribeLocalEvent(OnMarkerAttacked); } @@ -54,11 +53,6 @@ public abstract class SharedDamageMarkerSystem : EntitySystem } } - private void OnMarkerUnpaused(EntityUid uid, DamageMarkerComponent component, ref EntityUnpausedEvent args) - { - component.EndTime += args.PausedTime; - } - private void OnMarkerCollide(EntityUid uid, DamageMarkerOnCollideComponent component, ref StartCollideEvent args) { if (!args.OtherFixture.Hard || diff --git a/Content.Shared/Weapons/Melee/MeleeWeaponComponent.cs b/Content.Shared/Weapons/Melee/MeleeWeaponComponent.cs index 27c3a5f0df..e5b35f6c0b 100644 --- a/Content.Shared/Weapons/Melee/MeleeWeaponComponent.cs +++ b/Content.Shared/Weapons/Melee/MeleeWeaponComponent.cs @@ -10,7 +10,7 @@ namespace Content.Shared.Weapons.Melee; /// /// When given to a mob lets them do unarmed attacks, or when given to an item lets someone wield it to do attacks. /// -[RegisterComponent, NetworkedComponent, AutoGenerateComponentState] +[RegisterComponent, NetworkedComponent, AutoGenerateComponentState, AutoGenerateComponentPause] public sealed partial class MeleeWeaponComponent : Component { // TODO: This is becoming bloated as shit. @@ -33,6 +33,7 @@ public sealed partial class MeleeWeaponComponent : Component /// [DataField(customTypeSerializer: typeof(TimeOffsetSerializer)), AutoNetworkedField] [ViewVariables(VVAccess.ReadWrite)] + [AutoPausedField] public TimeSpan NextAttack; /// diff --git a/Content.Shared/Weapons/Melee/SharedMeleeWeaponSystem.cs b/Content.Shared/Weapons/Melee/SharedMeleeWeaponSystem.cs index 12455a1f49..6a5127f2c9 100644 --- a/Content.Shared/Weapons/Melee/SharedMeleeWeaponSystem.cs +++ b/Content.Shared/Weapons/Melee/SharedMeleeWeaponSystem.cs @@ -68,7 +68,6 @@ public abstract class SharedMeleeWeaponSystem : EntitySystem { base.Initialize(); - SubscribeLocalEvent(OnMeleeUnpaused); SubscribeLocalEvent(OnMeleeSelected); SubscribeLocalEvent(OnMeleeShotAttempted); SubscribeLocalEvent(OnMeleeShot); @@ -112,11 +111,6 @@ public abstract class SharedMeleeWeaponSystem : EntitySystem } } - private void OnMeleeUnpaused(EntityUid uid, MeleeWeaponComponent component, ref EntityUnpausedEvent args) - { - component.NextAttack += args.PausedTime; - } - private void OnMeleeSelected(EntityUid uid, MeleeWeaponComponent component, HandSelectedEvent args) { var attackRate = GetAttackRate(uid, args.User, component); diff --git a/Content.Shared/Weapons/Ranged/Components/GunComponent.cs b/Content.Shared/Weapons/Ranged/Components/GunComponent.cs index 8d7d548ad8..5a335e7e5c 100644 --- a/Content.Shared/Weapons/Ranged/Components/GunComponent.cs +++ b/Content.Shared/Weapons/Ranged/Components/GunComponent.cs @@ -9,7 +9,7 @@ using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom; namespace Content.Shared.Weapons.Ranged.Components; -[RegisterComponent, NetworkedComponent, AutoGenerateComponentState] +[RegisterComponent, NetworkedComponent, AutoGenerateComponentState, AutoGenerateComponentPause] [Access(typeof(SharedGunSystem))] public sealed partial class GunComponent : Component { @@ -198,6 +198,7 @@ public sealed partial class GunComponent : Component /// [DataField(customTypeSerializer:typeof(TimeOffsetSerializer))] [AutoNetworkedField] + [AutoPausedField] public TimeSpan NextFire = TimeSpan.Zero; /// diff --git a/Content.Shared/Weapons/Ranged/Components/RechargeBasicEntityAmmoComponent.cs b/Content.Shared/Weapons/Ranged/Components/RechargeBasicEntityAmmoComponent.cs index 923f95e207..f478405bec 100644 --- a/Content.Shared/Weapons/Ranged/Components/RechargeBasicEntityAmmoComponent.cs +++ b/Content.Shared/Weapons/Ranged/Components/RechargeBasicEntityAmmoComponent.cs @@ -7,7 +7,7 @@ namespace Content.Shared.Weapons.Ranged.Components; /// /// Responsible for handling recharging a basic entity ammo provider over time. /// -[RegisterComponent, NetworkedComponent, AutoGenerateComponentState] +[RegisterComponent, NetworkedComponent, AutoGenerateComponentState, AutoGenerateComponentPause] public sealed partial class RechargeBasicEntityAmmoComponent : Component { [ViewVariables(VVAccess.ReadWrite)] @@ -25,5 +25,6 @@ public sealed partial class RechargeBasicEntityAmmoComponent : Component [ViewVariables(VVAccess.ReadWrite), DataField("nextCharge", customTypeSerializer:typeof(TimeOffsetSerializer)), AutoNetworkedField] + [AutoPausedField] public TimeSpan? NextCharge; } diff --git a/Content.Shared/Weapons/Ranged/Systems/RechargeBasicEntityAmmoSystem.cs b/Content.Shared/Weapons/Ranged/Systems/RechargeBasicEntityAmmoSystem.cs index 536f3da811..b774c8ab45 100644 --- a/Content.Shared/Weapons/Ranged/Systems/RechargeBasicEntityAmmoSystem.cs +++ b/Content.Shared/Weapons/Ranged/Systems/RechargeBasicEntityAmmoSystem.cs @@ -21,19 +21,10 @@ public sealed class RechargeBasicEntityAmmoSystem : EntitySystem { base.Initialize(); - SubscribeLocalEvent(OnUnpaused); SubscribeLocalEvent(OnInit); SubscribeLocalEvent(OnExamined); } - private void OnUnpaused(EntityUid uid, RechargeBasicEntityAmmoComponent component, ref EntityUnpausedEvent args) - { - if (component.NextCharge == null) - return; - - component.NextCharge = component.NextCharge.Value + args.PausedTime; - } - public override void Update(float frameTime) { base.Update(frameTime); diff --git a/Content.Shared/Weapons/Ranged/Systems/SharedGunSystem.cs b/Content.Shared/Weapons/Ranged/Systems/SharedGunSystem.cs index ba22ba2cdc..71e3e80764 100644 --- a/Content.Shared/Weapons/Ranged/Systems/SharedGunSystem.cs +++ b/Content.Shared/Weapons/Ranged/Systems/SharedGunSystem.cs @@ -94,7 +94,6 @@ public abstract partial class SharedGunSystem : EntitySystem SubscribeLocalEvent(OnExamine); SubscribeLocalEvent(OnCycleMode); SubscribeLocalEvent(OnGunSelected); - SubscribeLocalEvent(OnGunUnpaused); SubscribeLocalEvent(OnMapInit); } @@ -122,11 +121,6 @@ public abstract partial class SharedGunSystem : EntitySystem } } - private void OnGunUnpaused(EntityUid uid, GunComponent component, ref EntityUnpausedEvent args) - { - component.NextFire += args.PausedTime; - } - private void OnShootRequest(RequestShootEvent msg, EntitySessionEventArgs args) { var user = args.SenderSession.AttachedEntity; diff --git a/Content.Shared/Wires/SharedWiresSystem.cs b/Content.Shared/Wires/SharedWiresSystem.cs index a40f428329..f069687ffb 100644 --- a/Content.Shared/Wires/SharedWiresSystem.cs +++ b/Content.Shared/Wires/SharedWiresSystem.cs @@ -76,6 +76,13 @@ public abstract class SharedWiresSystem : EntitySystem } } + public void ChangePanelVisibility(EntityUid uid, WiresPanelComponent component, bool visible) + { + component.Visible = visible; + UpdateAppearance(uid, component); + Dirty(uid, component); + } + protected void UpdateAppearance(EntityUid uid, WiresPanelComponent panel) { if (TryComp(uid, out var appearance)) diff --git a/Content.Tests/Content.Tests.csproj b/Content.Tests/Content.Tests.csproj index a883892d87..ff295728fc 100644 --- a/Content.Tests/Content.Tests.csproj +++ b/Content.Tests/Content.Tests.csproj @@ -2,7 +2,7 @@ $(TargetFramework) - 11 + 12 false false ..\bin\Content.Tests\ diff --git a/Resources/Audio/Misc/attributions.yml b/Resources/Audio/Misc/attributions.yml index 2599cf8083..db13d28d83 100644 --- a/Resources/Audio/Misc/attributions.yml +++ b/Resources/Audio/Misc/attributions.yml @@ -18,6 +18,16 @@ copyright: "Taken from TG station." source: "https://github.com/tgstation/tgstation/blob/b44fcdedfb7c7d8425bd75b9caf71644a86375d1/sound/creatures/narsie_rises.ogg" +- files: ["ratvar_rises.ogg"] + license: "CC-BY-SA-3.0" + copyright: "Taken from TG station." + source: "https://github.com/tgstation/tgstation/blob/2f63c779cb43543cfde76fa7ddaeacfde185fded/sound/effects/ratvar_rises.ogg" + +- files: ["ratvar_reveal.ogg"] + license: "CC-BY-SA-3.0" + copyright: "Taken from TG station." + source: "https://github.com/tgstation/tgstation/blob/2f63c779cb43543cfde76fa7ddaeacfde185fded/sound/effects/ratvar_reveal.ogg" + - files: ["epsilon.ogg"] license: "CC-BY-SA-3.0" copyright: "Made by dj-34 (https://github.com/dj-34)" diff --git a/Resources/Audio/Misc/ratvar_reveal.ogg b/Resources/Audio/Misc/ratvar_reveal.ogg new file mode 100644 index 0000000000..e70cd9873c Binary files /dev/null and b/Resources/Audio/Misc/ratvar_reveal.ogg differ diff --git a/Resources/Audio/Misc/ratvar_rises.ogg b/Resources/Audio/Misc/ratvar_rises.ogg new file mode 100644 index 0000000000..4c22d250c3 Binary files /dev/null and b/Resources/Audio/Misc/ratvar_rises.ogg differ diff --git a/Resources/Changelog/Changelog.yml b/Resources/Changelog/Changelog.yml index 630c043017..3f651b0304 100644 --- a/Resources/Changelog/Changelog.yml +++ b/Resources/Changelog/Changelog.yml @@ -1,198 +1,4 @@ Entries: -- author: Ubaser - changes: - - message: Reptilians can now use up to two (top) head markings. - type: Tweak - id: 5506 - time: '2024-01-01T23:27:14.0000000+00:00' - url: https://api.github.com/repos/space-wizards/space-station-14/pulls/23219 -- author: Lukasz825700516 - changes: - - message: Zombiefied reptilians no longer can pull objects with their tail. - type: Fix - id: 5507 - time: '2024-01-01T23:31:36.0000000+00:00' - url: https://api.github.com/repos/space-wizards/space-station-14/pulls/23066 -- author: SonicHDC - changes: - - message: Changed shape of Pistols to L! - type: Tweak - id: 5508 - time: '2024-01-01T23:32:16.0000000+00:00' - url: https://api.github.com/repos/space-wizards/space-station-14/pulls/23104 -- author: Alekshhh - changes: - - message: Changed some hairs visually - type: Tweak - id: 5509 - time: '2024-01-02T00:12:05.0000000+00:00' - url: https://api.github.com/repos/space-wizards/space-station-14/pulls/23304 -- author: EmoGarbage404 - changes: - - message: Defibrillators no longer reset the rot timer when failing to revive a - body. - type: Fix - - message: Slimes now rot. - type: Tweak - id: 5510 - time: '2024-01-02T02:12:32.0000000+00:00' - url: https://api.github.com/repos/space-wizards/space-station-14/pulls/23340 -- author: Ubaser - changes: - - message: Salvage mobs can no longer be ghost roles. - type: Remove - id: 5511 - time: '2024-01-02T08:15:29.0000000+00:00' - url: https://api.github.com/repos/space-wizards/space-station-14/pulls/23355 -- author: Rainbeon - changes: - - message: The ChemMaster buffer no longer shuffles list ordering when removing - a reagent. - type: Fix - id: 5512 - time: '2024-01-02T15:51:22.0000000+00:00' - url: https://api.github.com/repos/space-wizards/space-station-14/pulls/23352 -- author: DrMelon - changes: - - message: Fixed the Tesla Ball moving too fast by being pushed with explosions. - Now it moves as-designed. - type: Fix - id: 5513 - time: '2024-01-02T18:09:06.0000000+00:00' - url: https://api.github.com/repos/space-wizards/space-station-14/pulls/23377 -- author: tday - changes: - - message: The admin log will now include attempts to draw from mobs with a syringe. - type: Add - id: 5514 - time: '2024-01-02T18:47:31.0000000+00:00' - url: https://api.github.com/repos/space-wizards/space-station-14/pulls/23333 -- author: 778b - changes: - - message: Improved mice's eating everything behavior, now they can stop! - type: Tweak - id: 5515 - time: '2024-01-02T18:49:20.0000000+00:00' - url: https://api.github.com/repos/space-wizards/space-station-14/pulls/23322 -- author: Ilya246 - changes: - - message: Science may now research the Biofabricator, which can make animal cubes - from biomass! - type: Add - id: 5516 - time: '2024-01-02T18:53:35.0000000+00:00' - url: https://api.github.com/repos/space-wizards/space-station-14/pulls/23319 -- author: themias - changes: - - message: Welders can be refilled directly from wall fuel dispensers - type: Tweak - id: 5517 - time: '2024-01-02T21:11:10.0000000+00:00' - url: https://api.github.com/repos/space-wizards/space-station-14/pulls/23376 -- author: Admiral-Obvious-001 - changes: - - message: Added a few words to body bag descriptor so you know they stop rot. - type: Add - id: 5518 - time: '2024-01-03T01:36:18.0000000+00:00' - url: https://api.github.com/repos/space-wizards/space-station-14/pulls/23407 -- author: CaasGit - changes: - - message: Give slimes their custom speech bubble! - type: Tweak - id: 5519 - time: '2024-01-03T05:12:56.0000000+00:00' - url: https://api.github.com/repos/space-wizards/space-station-14/pulls/23415 -- author: zzylex - changes: - - message: You can now make plungers stick to walls. - type: Tweak - - message: A sound is made when a plunger gets stuck to something. - type: Add - - message: You can now shoot plungers with bows. - type: Tweak - id: 5520 - time: '2024-01-03T05:36:17.0000000+00:00' - url: https://api.github.com/repos/space-wizards/space-station-14/pulls/23406 -- author: EmoGarbage404 - changes: - - message: Added flatpacks, boxes that unpack into a full-sized machine when activated - with a multitool. - type: Add - - message: Added the Flatpacker 1001 to industrial research. A machine capable of - creating flatpacks from machine boards. - type: Add - id: 5521 - time: '2024-01-03T06:16:03.0000000+00:00' - url: https://api.github.com/repos/space-wizards/space-station-14/pulls/23338 -- author: themias - changes: - - message: Cyborgs can interact with shuttle consoles, gas mixers and gas filters. - type: Fix - id: 5522 - time: '2024-01-03T06:31:58.0000000+00:00' - url: https://api.github.com/repos/space-wizards/space-station-14/pulls/23391 -- author: metalgearsloth - changes: - - message: Fix solution injections considering the fly-by sound range and not the - collision range. - type: Fix - id: 5523 - time: '2024-01-03T07:57:36.0000000+00:00' - url: https://api.github.com/repos/space-wizards/space-station-14/pulls/23429 -- author: Bhijn and Myr - changes: - - message: Light fixtures now actually glow when they're powered on. Like. Their - sprite actually glows if the lighting is dim. Revolutionary technology, yes. - type: Tweak - id: 5524 - time: '2024-01-03T08:46:11.0000000+00:00' - url: https://api.github.com/repos/space-wizards/space-station-14/pulls/23428 -- author: Bhijn and Myr - changes: - - message: 'Blindness has been completely reworked, top to bottom. Eye damage is - no longer a mere dimming of the screen, but rather, a hyperstylized (read: not - at all realistic) simulation of the symptoms described by those living with - various types of real-world blindness.' - type: Add - - message: When your eyes have reached a critical state of damage, you are now capable - of simply closing them. - type: Add - - message: The settings menu now has a "Reduce motion of visual effects" setting! - Currently, the only thing this does is swap the eye damage effect out for a - far more straight-forward one akin to the blindness overlays seen across various - SS13 servers. - type: Add - - message: The amount of damage that eyes can take has been greatly increased. Total - blindness now takes 9 damage, up from 3. Additionally, eyes are considered to - be in a critical state once they hit 6 damage. - type: Tweak - - message: Glasses no longer actively increase the eye damage effect. They now actively - reduce the eye damage effect, with their effectiveness dropping off as you take - more eye damage, until they eventually do nothing once your eyes are in critical - condition. - type: Tweak - - message: The blind trait is now legal blindness, rather than complete blindness. - The blind trait permanently prevents your eyes from being reduced below the - critical state threshold. - type: Tweak - id: 5525 - time: '2024-01-03T09:07:02.0000000+00:00' - url: https://api.github.com/repos/space-wizards/space-station-14/pulls/23212 -- author: BurninDreamer - changes: - - message: Hand labelers can now be printed by autolathes. - type: Tweak - id: 5526 - time: '2024-01-03T18:24:02.0000000+00:00' - url: https://api.github.com/repos/space-wizards/space-station-14/pulls/23457 -- author: themias - changes: - - message: Fixed refueling a lit welder not detonating the fuel tank - type: Fix - id: 5527 - time: '2024-01-03T21:23:36.0000000+00:00' - url: https://api.github.com/repos/space-wizards/space-station-14/pulls/23469 - author: Alekshhh changes: - message: Changed monkeys visually @@ -3853,3 +3659,164 @@ id: 6005 time: '2024-02-22T11:15:10.0000000+00:00' url: https://github.com/space-wizards/space-station-14/pull/25465 +- author: lzk228 + changes: + - message: Fix some items becomes bigger after turning in trash. + type: Fix + id: 6006 + time: '2024-02-22T11:28:03.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/25461 +- author: ps3moira + changes: + - message: Added Large Wooden floors + type: Add + id: 6007 + time: '2024-02-22T11:59:41.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/25462 +- author: Whisper + changes: + - message: Fixed reagent slime ghost role description. + type: Fix + id: 6008 + time: '2024-02-22T12:18:46.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/25466 +- author: lzk228 + changes: + - message: Galoshes are added to the Janidrobe. + type: Tweak + - message: Galoshes now make you slower. + type: Tweak + id: 6009 + time: '2024-02-23T01:05:11.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/25484 +- author: PJB3005 + changes: + - message: sorting of departments and jobs has been made consistent in various menus. + type: Tweak + id: 6010 + time: '2024-02-23T04:04:44.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/25486 +- author: liltenhead + changes: + - message: Changed emergency welder's fuel count from 25 -> 50 + type: Tweak + id: 6011 + time: '2024-02-23T06:53:39.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/25483 +- author: Vasilis + changes: + - message: Fixed a bug where the centcom official/any job that is not supposed to + have a preference option appeared anyway. + type: Fix + id: 6012 + time: '2024-02-23T13:19:52.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/25496 +- author: Erisfiregamer1 + changes: + - message: Fixed a typo when forcefeeding someone. + type: Fix + id: 6013 + time: '2024-02-24T01:45:02.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/25512 +- author: Beck Thompson + changes: + - message: The Fire Extinguishers safety can now only be toggled when in range. + type: Fix + id: 6014 + time: '2024-02-25T02:29:16.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/25534 +- author: ArchPigeon + changes: + - message: Removed the ability for command or any antag-safe role to be initial + infected in zombie mode + type: Remove + id: 6015 + time: '2024-02-25T02:40:49.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/25529 +- author: PolterTzi + changes: + - message: Cargo ordering multiple crates in one order should work now. + type: Fix + id: 6016 + time: '2024-02-25T07:36:22.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/25518 +- author: metalgearsloth + changes: + - message: Remove executions pending code rewrite. + type: Remove + id: 6017 + time: '2024-02-25T11:36:17.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/25555 +- author: Krunk + changes: + - message: Candy bowls function properly again! + type: Fix + id: 6018 + time: '2024-02-25T13:08:15.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/25514 +- author: Whisper + changes: + - message: Added juice that makes you Weh! Juice a lizard plushie today! + type: Add + id: 6019 + time: '2024-02-25T13:54:07.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/25132 +- author: wafehling + changes: + - message: Secret mode has become more secret, with the 4th option Survival added + to the rotation. + type: Tweak + id: 6020 + time: '2024-02-25T21:15:35.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/25568 +- author: Tayrtahn + changes: + - message: Added a live preview display to reagent dispensers. + type: Add + id: 6021 + time: '2024-02-25T23:03:22.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/25391 +- author: Krunk + changes: + - message: Fixed grid inventory occasionally messing with your item rotation. + type: Fix + id: 6022 + time: '2024-02-25T23:24:21.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/25510 +- author: Ubaser + changes: + - message: Satchels no longer have darkened space representing a gap, and is instead + transparent. + type: Tweak + id: 6023 + time: '2024-02-25T23:24:59.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/25147 +- author: TheShuEd + changes: + - message: Huge flora anomaly nerf + type: Tweak + id: 6024 + time: '2024-02-25T23:41:24.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/25499 +- author: OctoRocket + changes: + - message: Removed the hands requirement to read paper. + type: Tweak + id: 6025 + time: '2024-02-26T02:40:22.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/25580 +- author: SlamBamActionman + changes: + - message: Self-uncuff damage has been removed, but attempting to self-uncuff now + has a cooldown instead. + type: Tweak + id: 6026 + time: '2024-02-26T02:41:20.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/25161 +- author: deltanedas + changes: + - message: Traitors can now be asked to steal the CMO's Handheld Crew Monitor. + type: Tweak + id: 6027 + time: '2024-02-26T03:40:48.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/25563 diff --git a/Resources/Credits/GitHub.txt b/Resources/Credits/GitHub.txt index 7cfd4c7364..5be3d24ecf 100644 --- a/Resources/Credits/GitHub.txt +++ b/Resources/Credits/GitHub.txt @@ -1 +1 @@ -08A, 0x6273, 2013HORSEMEATSCANDAL, 20kdc, 21Melkuu, 4dplanner, 612git, 778b, Ablankmann, Acruid, actioninja, ada-please, adamsong, Admiral-Obvious-001, Adrian16199, Aerocrux, Aexxie, africalimedrop, Agoichi, Ahion, AJCM-git, AjexRose, Alekshhh, AlexMorgan3817, AlmondFlour, AlphaQwerty, Altoids1, amylizzle, ancientpower, areitpog, Arendian, arimah, artak10t, Arteben, AruMoon, as334, AsikKEsel, asperger-sind, astriloqua, avghdev, AzzyIsNotHere, BananaFlambe, BasedUser, BGare, bhespiritu, BingoJohnson-zz, BismarckShuffle, Bixkitts, Blackern5000, Blazeror, Boaz1111, BobdaBiscuit, brainfood1183, Brandon-Huu, Bright0, brndd, BubblegumBlue, BYONDFuckery, c0rigin, c4llv07e, CakeQ, CaptainSqrBeard, Carbonhell, casperr04, CatTheSystem, Centronias, chairbender, Charlese2, Cheackraze, cheesePizza2, Chief-Engineer, chromiumboy, Chronophylos, civilCornball, clement-or, Clyybber, ColdAutumnRain, collinlunn, ComicIronic, coolmankid12345, corentt, crazybrain23, creadth, CrigCrag, Crotalus, CrudeWax, CrzyPotato, Cyberboss, d34d10cc, Daemon, daerSeebaer, dahnte, dakamakat, DamianX, DangerRevolution, daniel-cr, Darkenson, DawBla, dch-GH, Deahaka, DEATHB4DEFEAT, DeathCamel58, deathride58, DebugOk, Decappi, deepy, degradka, Delete69, deltanedas, DerbyX, DmitriyMX, DoctorBeard, DogZeroX, dontbetank, Doru991, DoubleRiceEddiedd, DrMelon, drongood12, DrSmugleaf, drteaspoon420, DTanxxx, DubiousDoggo, Duddino, Dutch-VanDerLinde, Easypoller, eclips_e, EdenTheLiznerd, EEASAS, Efruit, efzapa, ElectroSR, elthundercloud, Emisse, EmoGarbage404, Endecc, enumerate0, eoineoineoin, ERORR404V1, Errant-4, estacaoespacialpirata, exp111, Fahasor, FairlySadPanda, ficcialfaint, FillerVK, Fishfish458, Flareguy, FluffiestFloof, FluidRock, FoLoKe, fooberticus, Fortune117, freeman2651, Fromoriss, FungiFellow, GalacticChimp, gbasood, Geekyhobo, Genkail, Git-Nivrak, github-actions[bot], gituhabu, GNF54, GoodWheatley, Gotimanga, graevy, GreyMario, gusxyz, h3half, Hanzdegloker, Hardly3D, harikattar, Hebiman, Henry12116, HerCoyote23, Hmeister-real, HoofedEar, hord-brayden, hubismal, Hugal31, Hyenh, iacore, IamVelcroboy, icekot8, igorsaux, ike709, Illiux, Ilya246, IlyaElDunaev, Injazz, Insineer, IntegerTempest, Interrobang01, IProduceWidgets, ItsMeThom, j-giebel, Jackal298, Jackrost, jamessimo, janekvap, JerryImMouse, Jessetriesagain, jessicamaybe, Jezithyr, jicksaw, JiimBob, JoeHammad1844, joelhed, JohnGinnane, johnku1, joshepvodka, jproads, Jrpl, juliangiebel, JustCone14, JustinTether, JustinTrotter, Kadeo64, KaiShibaa, kalane15, kalanosh, KEEYNy, Keikiru, Kelrak, kerisargit, keronshb, KIBORG04, KingFroozy, kira-er, Kit0vras, KittenColony, Kmc2000, komunre, koteq, Krunklehorn, kxvvv, Lamrr, LankLTE, lapatison, Leander-0, LetterN, Level10Cybermancer, lever1209, LightVillet, liltenhead, LittleBuilderJane, Lomcastar, LordCarve, LordEclipse, luckyshotpictures, LudwigVonChesterfield, Lukasz825700516, lunarcomets, luringens, lvvova1, lzimann, lzk228, M3739, MACMAN2003, Macoron, MagnusCrowe, ManelNavola, Mangohydra, matthst, Matz05, MehimoNemo, MeltedPixel, MemeProof, Menshin, Mervill, metalgearsloth, mhamsterr, MilenVolf, Minty642, Mirino97, mirrorcult, MishaUnity, MisterMecky, Mith-randalf, ModeratelyAware, Moneyl, Moomoobeef, moony, Morb0, Mr0maks, Myakot, Myctai, N3X15, Nails-n-Tape, Nairodian, Naive817, namespace-Memory, NickPowers43, nikthechampiongr, Nimfar11, Nirnael, nmajask, nok-ko, Nopey, notafet, notquitehadouken, noudoit, noverd, nuke-haus, NULL882, Nylux, OctoRocket, OldDanceJacket, OliverOtter, onoira, Owai-Seek, pali6, Pangogie, patrikturi, PaulRitter, Peptide90, peptron1, Phantom-Lily, Phill101, PixelTheKermit, PJB3005, Plykiya, pofitlo, pointer-to-null, PolterTzi, PoorMansDreams, potato1234x, ProfanedBane, ProPandaBear, PrPleGoo, Psychpsyo, psykzz, PuroSlavKing, PursuitInAshes, Putnam3145, quatre, QuietlyWhisper, qwerltaz, Radosvik, Radrark, Rainbeon, Rainfey, Rane, Ranger6012, ravage123321, rbertoche, Redict, RedlineTriad, RednoWCirabrab, RemberBM, RemieRichards, RemTim, rene-descartes2021, renodubois, RiceMar1244, RieBi, RIKELOLDABOSS, Rinkashikachi, Rockdtben, rolfero, Saakra, SadAways, Samsterious, SamV522, SaphireLattice, ScalyChimp, scrato, Scribbles0, ScumbagDog, Serkket, SethLafuente, ShadowCommander, Shadowtheprotogen546, SignalWalker, Simyon264, SirDragooon, Sirionaut, siyengar04, Skarletto, Skrauz, Skyedra, SlamBamActionman, Slava0135, snebl, Snowni, snowsignal, SonicHDC, SoulSloth, SpaceManiac, SpeltIncorrectyl, spoogemonster, ssdaniel24, Stanislav4ix, Stealthbomber16, StrawberryMoses, Subversionary, SweptWasTaken, Szunti, TaralGit, Tayrtahn, tday93, TekuNut, TemporalOroboros, tentekal, tgrkzus, thatrandomcanadianguy, TheArturZh, theashtronaut, thedraccx, themias, Theomund, theOperand, TheShuEd, ThunderBear2006, timothyteakettle, TimrodDX, Titian3, TK-A369, tkdrg, tmtmtl30, tom-leys, tomasalves8, Tomeno, tosatur, Tryded, TsjipTsjip, Tunguso4ka, TurboTrackerss14, Tyler-IN, Tyzemol, UbaserB, UKNOWH, Uriende, UristMcDorf, Vaaankas, Varen, VasilisThePikachu, veliebm, Veritius, Verslebas, VigersRay, Visne, Volotomite, volundr-, Vordenburg, vulppine, Warentan, waylon531, weaversam8, Willhelm53, wixoaGit, WlarusFromDaSpace, wrexbe, WTCWR68, xRiriq, yathxyz, Ygg01, YotaXP, youarereadingthis, YuriyKiss, zach-hill, Zandario, Zap527, ZelteHonor, zerorulez, ZeWaka, zionnBE, zlodo, ZNixian, ZoldorfTheWizard, Zth--, Zumorica, Zymem +08A, 0x6273, 2013HORSEMEATSCANDAL, 20kdc, 21Melkuu, 4dplanner, 612git, 778b, Ablankmann, Acruid, actioninja, ada-please, adamsong, Admiral-Obvious-001, Adrian16199, Aerocrux, Aexxie, africalimedrop, Agoichi, Ahion, AJCM-git, AjexRose, Alekshhh, AlexMorgan3817, AlmondFlour, AlphaQwerty, Altoids1, amylizzle, ancientpower, ArchPigeon, areitpog, Arendian, arimah, artak10t, Arteben, AruMoon, as334, AsikKEsel, asperger-sind, avghdev, AzzyIsNotHere, BananaFlambe, BasedUser, BGare, BingoJohnson-zz, BismarckShuffle, Bixkitts, Blackern5000, Blazeror, Boaz1111, BobdaBiscuit, brainfood1183, Brandon-Huu, Bright0, brndd, BubblegumBlue, BYONDFuckery, c4llv07e, CakeQ, CaptainSqrBeard, Carbonhell, casperr04, CatTheSystem, Centronias, chairbender, Charlese2, Cheackraze, cheesePizza2, Chief-Engineer, chromiumboy, Chronophylos, clement-or, Clyybber, ColdAutumnRain, collinlunn, ComicIronic, coolmankid12345, corentt, crazybrain23, creadth, CrigCrag, Crotalus, CrudeWax, CrzyPotato, Cyberboss, d34d10cc, Daemon, daerSeebaer, dahnte, dakamakat, DamianX, DangerRevolution, daniel-cr, Darkenson, DawBla, dch-GH, Deahaka, DEATHB4DEFEAT, DeathCamel58, deathride58, DebugOk, Decappi, deepy, Delete69, deltanedas, DerbyX, DmitriyMX, DoctorBeard, DogZeroX, dontbetank, Doru991, DoubleRiceEddiedd, DrMelon, DrSmugleaf, drteaspoon420, DTanxxx, DubiousDoggo, Duddino, Dutch-VanDerLinde, Easypoller, eclips_e, EdenTheLiznerd, EEASAS, Efruit, ElectroSR, elthundercloud, Emisse, EmoGarbage404, Endecc, enumerate0, eoineoineoin, ERORR404V1, Errant-4, estacaoespacialpirata, exp111, Fahasor, FairlySadPanda, ficcialfaint, FillerVK, Fishfish458, Flareguy, FluffiestFloof, FluidRock, FoLoKe, fooberticus, Fortune117, freeman2651, Fromoriss, FungiFellow, GalacticChimp, gbasood, Geekyhobo, Genkail, Git-Nivrak, github-actions[bot], gituhabu, GNF54, Golinth, GoodWheatley, Gotimanga, graevy, GreyMario, gusxyz, h3half, Hanzdegloker, Hardly3D, harikattar, Hebiman, Henry12116, HerCoyote23, Hmeister-real, HoofedEar, hord-brayden, hubismal, Hugal31, Hyenh, iacore, IamVelcroboy, icekot8, igorsaux, ike709, Illiux, Ilya246, IlyaElDunaev, Injazz, Insineer, IntegerTempest, Interrobang01, IProduceWidgets, ItsMeThom, j-giebel, Jackal298, Jackrost, jamessimo, janekvap, JerryImMouse, Jessetriesagain, jessicamaybe, Jezithyr, jicksaw, JiimBob, JoeHammad1844, joelhed, JohnGinnane, johnku1, joshepvodka, jproads, Jrpl, juliangiebel, JustCone14, JustinTether, JustinTrotter, Kadeo64, KaiShibaa, kalane15, kalanosh, KEEYNy, Keikiru, Kelrak, kerisargit, keronshb, KIBORG04, Killerqu00, KingFroozy, kira-er, Kit0vras, KittenColony, Kmc2000, Ko4ergaPunk, komunre, koteq, Krunklehorn, kxvvv, Lamrr, LankLTE, lapatison, Leander-0, LetterN, Level10Cybermancer, lever1209, LightVillet, liltenhead, LittleBuilderJane, Lomcastar, LordCarve, LordEclipse, luckyshotpictures, LudwigVonChesterfield, Lukasz825700516, lunarcomets, luringens, lvvova1, lzimann, lzk228, M3739, MACMAN2003, Macoron, MagnusCrowe, ManelNavola, Mangohydra, matthst, Matz05, MehimoNemo, MeltedPixel, MemeProof, Menshin, Mervill, metalgearsloth, mhamsterr, MilenVolf, Minty642, Mirino97, mirrorcult, MishaUnity, MisterMecky, Mith-randalf, MjrLandWhale, ModeratelyAware, Moneyl, Moomoobeef, moony, Morb0, Mr0maks, musicmanvr, Myakot, Myctai, N3X15, Nails-n-Tape, Nairodian, Naive817, namespace-Memory, NickPowers43, nikthechampiongr, Nimfar11, Nirnael, nmajask, nok-ko, Nopey, notafet, notquitehadouken, noudoit, noverd, nuke-haus, NULL882, Nylux, OctoRocket, OldDanceJacket, OliverOtter, onoira, Owai-Seek, pali6, Pangogie, patrikturi, PaulRitter, Peptide90, peptron1, Phantom-Lily, Phill101, PixelTheKermit, PJB3005, Plykiya, pofitlo, pointer-to-null, PolterTzi, PoorMansDreams, potato1234x, PotentiallyTom, ProfanedBane, ProPandaBear, PrPleGoo, ps3moira, Psychpsyo, psykzz, PuroSlavKing, PursuitInAshes, Putnam3145, quatre, QuietlyWhisper, qwerltaz, Radosvik, Radrark, Rainbeon, Rainfey, Rane, Ranger6012, ravage123321, rbertoche, Redict, RedlineTriad, RednoWCirabrab, RemberBM, RemieRichards, RemTim, rene-descartes2021, renodubois, RiceMar1244, RieBi, RIKELOLDABOSS, Rinkashikachi, Rockdtben, rolfero, Saakra, SadAways, Samsterious, SamV522, SaphireLattice, ScalyChimp, scrato, Scribbles0, ScumbagDog, Serkket, SethLafuente, ShadowCommander, Shadowtheprotogen546, SignalWalker, Simyon264, SirDragooon, Sirionaut, siyengar04, Skarletto, Skrauz, Skyedra, SlamBamActionman, Slava0135, snebl, Snowni, snowsignal, SonicHDC, SoulSloth, SpaceManiac, SpeltIncorrectyl, spoogemonster, ssdaniel24, Stanislav4ix, Stealthbomber16, StrawberryMoses, Subversionary, SweptWasTaken, Szunti, takemysoult, TaralGit, Tayrtahn, tday93, TekuNut, TemporalOroboros, tentekal, tgrkzus, thatrandomcanadianguy, TheArturZh, theashtronaut, thedraccx, themias, Theomund, theOperand, TheShuEd, ThunderBear2006, timothyteakettle, TimrodDX, Titian3, TK-A369, tkdrg, tmtmtl30, tom-leys, tomasalves8, Tomeno, tosatur, Tryded, TsjipTsjip, Tunguso4ka, TurboTrackerss14, Tyler-IN, Tyzemol, UbaserB, UKNOWH, Uriende, UristMcDorf, Vaaankas, Varen, VasilisThePikachu, veliebm, Veritius, Verslebas, VigersRay, Visne, Volotomite, volundr-, Vordenburg, vulppine, Warentan, waylon531, weaversam8, Willhelm53, wixoaGit, WlarusFromDaSpace, wrexbe, WTCWR68, xRiriq, yathxyz, Ygg01, YotaXP, youarereadingthis, YuriyKiss, zach-hill, Zandario, Zap527, ZelteHonor, zerorulez, ZeWaka, zionnBE, zlodo, ZNixian, ZoldorfTheWizard, Zth--, Zumorica, Zymem diff --git a/Resources/Locale/en-US/execution/execution.ftl b/Resources/Locale/en-US/execution/execution.ftl deleted file mode 100644 index 8bdf326166..0000000000 --- a/Resources/Locale/en-US/execution/execution.ftl +++ /dev/null @@ -1,30 +0,0 @@ -execution-verb-name = Execute -execution-verb-message = Use your weapon to execute someone. - -# All the below localisation strings have access to the following variables -# attacker (the person committing the execution) -# victim (the person being executed) -# weapon (the weapon used for the execution) - -execution-popup-gun-initial-internal = You ready the muzzle of {THE($weapon)} against {$victim}'s head. -execution-popup-gun-initial-external = {$attacker} readies the muzzle of {THE($weapon)} against {$victim}'s head. -execution-popup-gun-complete-internal = You blast {$victim} in the head! -execution-popup-gun-complete-external = {$attacker} blasts {$victim} in the head! -execution-popup-gun-clumsy-internal = You miss {$victim}'s head and shoot your foot instead! -execution-popup-gun-clumsy-external = {$attacker} misses {$victim} and shoots {POSS-ADJ($attacker)} foot instead! -execution-popup-gun-empty = {CAPITALIZE(THE($weapon))} clicks. - -suicide-popup-gun-initial-internal = You place the muzzle of {THE($weapon)} in your mouth. -suicide-popup-gun-initial-external = {$attacker} places the muzzle of {THE($weapon)} in {POSS-ADJ($attacker)} mouth. -suicide-popup-gun-complete-internal = You shoot yourself in the head! -suicide-popup-gun-complete-external = {$attacker} shoots {REFLEXIVE($attacker)} in the head! - -execution-popup-melee-initial-internal = You ready {THE($weapon)} against {$victim}'s throat. -execution-popup-melee-initial-external = {$attacker} readies {POSS-ADJ($attacker)} {$weapon} against the throat of {$victim}. -execution-popup-melee-complete-internal = You slit the throat of {$victim}! -execution-popup-melee-complete-external = {$attacker} slits the throat of {$victim}! - -suicide-popup-melee-initial-internal = You ready {THE($weapon)} against your throat. -suicide-popup-melee-initial-external = {$attacker} readies {POSS-ADJ($attacker)} {$weapon} against {POSS-ADJ($attacker)} throat. -suicide-popup-melee-complete-internal = You slit your throat with {THE($weapon)}! -suicide-popup-melee-complete-external = {$attacker} slits {POSS-ADJ($attacker)} throat with {THE($weapon)}! \ No newline at end of file diff --git a/Resources/Locale/en-US/flavors/flavor-profiles.ftl b/Resources/Locale/en-US/flavors/flavor-profiles.ftl index f2bbd60bed..5d42146f74 100644 --- a/Resources/Locale/en-US/flavors/flavor-profiles.ftl +++ b/Resources/Locale/en-US/flavors/flavor-profiles.ftl @@ -252,3 +252,4 @@ flavor-complex-bee = unbeelievable flavor-complex-sax = like jazz flavor-complex-bottledlightning = like lightning in a bottle flavor-complex-punishment = like punishment +flavor-weh = like weh diff --git a/Resources/Locale/en-US/nutrition/components/food-component.ftl b/Resources/Locale/en-US/nutrition/components/food-component.ftl index 1d8a793d4d..4eae610085 100644 --- a/Resources/Locale/en-US/nutrition/components/food-component.ftl +++ b/Resources/Locale/en-US/nutrition/components/food-component.ftl @@ -24,6 +24,6 @@ food-system-verb-eat = Eat ## Force feeding -food-system-force-feed = {CAPITALIZE(THE($user))} is trying feed you something! +food-system-force-feed = {CAPITALIZE(THE($user))} is trying to feed you something! food-system-force-feed-success = {CAPITALIZE(THE($user))} forced you to eat something! {$flavors} food-system-force-feed-success-user = You successfully feed {THE($target)} diff --git a/Resources/Locale/en-US/ratvar/ratvar.ftl b/Resources/Locale/en-US/ratvar/ratvar.ftl new file mode 100644 index 0000000000..aad9497bb5 --- /dev/null +++ b/Resources/Locale/en-US/ratvar/ratvar.ftl @@ -0,0 +1,2 @@ +ratvar-has-risen = RATVAR HAS AWOKEN +ratvar-has-risen-sender = ??? diff --git a/Resources/Locale/en-US/reagents/meta/fun.ftl b/Resources/Locale/en-US/reagents/meta/fun.ftl index 68de618a36..8764a3d28a 100644 --- a/Resources/Locale/en-US/reagents/meta/fun.ftl +++ b/Resources/Locale/en-US/reagents/meta/fun.ftl @@ -25,3 +25,5 @@ reagent-desc-fresium = A mysterious compound that slows the vibration of atoms a reagent-name-laughter = Laughter reagent-desc-laughter = Some say that this is the best medicine, but recent studies have proven that to be untrue. +reagent-name-weh = juice that makes you Weh +reagent-desc-weh = Pure essence of lizard plush. Makes you Weh! diff --git a/Resources/Locale/en-US/tiles/tiles.ftl b/Resources/Locale/en-US/tiles/tiles.ftl index 478175fc67..0a0558b3cb 100644 --- a/Resources/Locale/en-US/tiles/tiles.ftl +++ b/Resources/Locale/en-US/tiles/tiles.ftl @@ -120,3 +120,4 @@ tiles-web = web tile tiles-chromite = chromite tiles-astro-grass = astro-grass tiles-astro-ice = astro-ice +tiles-wood-large = large wood \ No newline at end of file diff --git a/Resources/Prototypes/Catalog/Cargo/cargo_shuttle.yml b/Resources/Prototypes/Catalog/Cargo/cargo_shuttle.yml index 58c6f99494..bc0f60fcf3 100644 --- a/Resources/Prototypes/Catalog/Cargo/cargo_shuttle.yml +++ b/Resources/Prototypes/Catalog/Cargo/cargo_shuttle.yml @@ -3,7 +3,7 @@ icon: sprite: Structures/Shuttles/thruster.rsi state: base - product: Thruster + product: ThrusterUnanchored cost: 1500 category: Shuttle group: market @@ -13,7 +13,7 @@ icon: sprite: Structures/Shuttles/gyroscope.rsi state: base - product: Gyroscope + product: GyroscopeUnanchored cost: 4000 category: Shuttle group: market diff --git a/Resources/Prototypes/Catalog/VendingMachines/Inventories/janidrobe.yml b/Resources/Prototypes/Catalog/VendingMachines/Inventories/janidrobe.yml index 0a3dc6a3a6..233a77b865 100644 --- a/Resources/Prototypes/Catalog/VendingMachines/Inventories/janidrobe.yml +++ b/Resources/Prototypes/Catalog/VendingMachines/Inventories/janidrobe.yml @@ -5,7 +5,7 @@ ClothingUniformJumpskirtJanitor: 2 ClothingHandsGlovesJanitor: 2 ClothingShoesColorBlack: 2 - ClothingShoesGaloshes: 2 # Corvax-MRP + ClothingShoesGaloshes: 2 ClothingHeadHatPurplesoft: 2 ClothingBeltJanitor: 2 ClothingHeadsetService: 2 diff --git a/Resources/Prototypes/Entities/Clothing/Head/welding.yml b/Resources/Prototypes/Entities/Clothing/Head/welding.yml index 753646757e..fb791ae567 100644 --- a/Resources/Prototypes/Entities/Clothing/Head/welding.yml +++ b/Resources/Prototypes/Entities/Clothing/Head/welding.yml @@ -4,6 +4,8 @@ name: welding mask abstract: true components: + - type: Item + storedRotation: 0 - type: IngestionBlocker - type: FlashImmunity - type: IdentityBlocker diff --git a/Resources/Prototypes/Entities/Markers/Spawners/Random/posters.yml b/Resources/Prototypes/Entities/Markers/Spawners/Random/posters.yml index 792aef20f2..b7460c7bd1 100644 --- a/Resources/Prototypes/Entities/Markers/Spawners/Random/posters.yml +++ b/Resources/Prototypes/Entities/Markers/Spawners/Random/posters.yml @@ -92,6 +92,7 @@ - PosterContrabandEnlistGorlex - PosterContrabandInterdyne - PosterContrabandWaffleCorp + - PosterContrabandMissingSpacepen chance: 1 - type: entity diff --git a/Resources/Prototypes/Entities/Mobs/NPCs/elemental.yml b/Resources/Prototypes/Entities/Mobs/NPCs/elemental.yml index 3631510fff..01fce382e3 100644 --- a/Resources/Prototypes/Entities/Mobs/NPCs/elemental.yml +++ b/Resources/Prototypes/Entities/Mobs/NPCs/elemental.yml @@ -228,6 +228,8 @@ parent: [ MobAdultSlimes, MobCombat ] description: It consists of a liquid, and it wants to dissolve you in itself. components: + - type: GhostRole + description: ghost-role-information-angry-slimes-description - type: NpcFactionMember factions: - SimpleHostile diff --git a/Resources/Prototypes/Entities/Mobs/NPCs/living_light.yml b/Resources/Prototypes/Entities/Mobs/NPCs/living_light.yml index cc75405e10..9b90d202f3 100644 --- a/Resources/Prototypes/Entities/Mobs/NPCs/living_light.yml +++ b/Resources/Prototypes/Entities/Mobs/NPCs/living_light.yml @@ -30,10 +30,6 @@ state: glow shader: unshaded - type: MobState - - type: MobThresholds - thresholds: - 0: Alive - 50: Dead - type: SlowOnDamage speedModifierThresholds: 20: 0.5 @@ -94,7 +90,7 @@ thresholds: - trigger: !type:DamageTrigger - damage: 50 + damage: 25 behaviors: - !type:DoActsBehavior acts: [ "Destruction" ] @@ -128,10 +124,6 @@ - map: [ "enum.DamageStateVisualLayers.BaseUnshaded" ] state: glow shader: unshaded - - type: MobThresholds - thresholds: - 0: Alive - 50: Dead - type: DamageStateVisuals states: Alive: @@ -159,10 +151,6 @@ - map: [ "enum.DamageStateVisualLayers.BaseUnshaded" ] state: glow shader: unshaded - - type: MobThresholds - thresholds: - 0: Alive - 40: Dead - type: DamageStateVisuals states: Alive: diff --git a/Resources/Prototypes/Entities/Mobs/Player/ratvar.yml b/Resources/Prototypes/Entities/Mobs/Player/ratvar.yml new file mode 100644 index 0000000000..5a45bff295 --- /dev/null +++ b/Resources/Prototypes/Entities/Mobs/Player/ratvar.yml @@ -0,0 +1,94 @@ +- type: entity + abstract: true + id: MobRatvarBase #can't have the clockwork justiciar be associated with his (im)mortal enemy + name: Ratvar + description: Your mind aches as it fails to understand the complex mechanics of what is before you. + components: + - type: Sprite + sprite: Mobs/Demons/ratvar.rsi + drawdepth: Ghosts + scale: 1.15,1.15 + layers: + - state: ratvar + shader: unshaded + +- type: entity + parent: MobRatvarBase + id: MobRatvarSpawn + suffix: Spawn + components: + - type: Sprite + layers: + - state: spawn + shader: unshaded + - type: TimedDespawn + lifetime: 3.5 + - type: SpawnOnDespawn + prototype: MobRatvar + +- type: entity + parent: [MobRatvarBase, BaseMob] + id: MobRatvar + components: + - type: AnnounceOnSpawn + message: ratvar-has-risen + sender: ratvar-has-risen-sender + sound: + path: /Audio/Misc/ratvar_reveal.ogg + color: "#BE8700" + - type: CargoSellBlacklist + - type: ContentEye + maxZoom: 2.0,2.0 + - type: Fixtures + fixtures: + EventHorizonCollider: + shape: + !type:PhysShapeCircle + radius: 5 + hard: false + restitution: 0.8 + density: 1 + mask: + - AllMask + layer: + - AllMask + EventHorizonConsumer: + shape: + !type:PhysShapeCircle + radius: 5 + hard: false + mask: + - AllMask + layer: + - AllMask + - type: Input + context: "ghost" + - type: MovementIgnoreGravity + - type: IntrinsicRadioReceiver + - type: ActiveRadio + channels: + - Binary + - Common + - Command + - CentCom + - Engineering + - Medical + - Science + - Security + - Service + - Supply + - Syndicate + globalReceive: true + - type: Physics + bodyType: Dynamic + bodyStatus: InAir + - type: CanMoveInAir + - type: EventHorizon + radius: 5 + canBreachContainment: true + - type: GravityWell + baseRadialAcceleration: 6 + maxRange: 8 + - type: WarpPoint + follow: true + location: Ratvar \ No newline at end of file diff --git a/Resources/Prototypes/Entities/Objects/Consumable/Food/Baked/pie.yml b/Resources/Prototypes/Entities/Objects/Consumable/Food/Baked/pie.yml index ba70efb205..fe88859584 100644 --- a/Resources/Prototypes/Entities/Objects/Consumable/Food/Baked/pie.yml +++ b/Resources/Prototypes/Entities/Objects/Consumable/Food/Baked/pie.yml @@ -6,6 +6,8 @@ id: FoodPieBase abstract: true components: + - type: Item + storedRotation: -90 - type: FlavorProfile flavors: - sweet @@ -34,6 +36,8 @@ abstract: true description: A slice of pie. Tasty! components: + - type: Item + size: Tiny - type: FlavorProfile flavors: - sweet diff --git a/Resources/Prototypes/Entities/Objects/Consumable/Food/Containers/bowl.yml b/Resources/Prototypes/Entities/Objects/Consumable/Food/Containers/bowl.yml index eb05133a38..52f6d42dc8 100644 --- a/Resources/Prototypes/Entities/Objects/Consumable/Food/Containers/bowl.yml +++ b/Resources/Prototypes/Entities/Objects/Consumable/Food/Containers/bowl.yml @@ -6,6 +6,8 @@ id: FoodBowlBig description: A simple bowl, used for soups and salads. components: + - type: Item + storedRotation: -90 - type: SolutionContainerManager solutions: food: diff --git a/Resources/Prototypes/Entities/Objects/Consumable/Food/Containers/box.yml b/Resources/Prototypes/Entities/Objects/Consumable/Food/Containers/box.yml index 8b6df79b9f..6ce0c7a443 100644 --- a/Resources/Prototypes/Entities/Objects/Consumable/Food/Containers/box.yml +++ b/Resources/Prototypes/Entities/Objects/Consumable/Food/Containers/box.yml @@ -214,6 +214,8 @@ - type: Item sprite: Objects/Consumable/Food/Baked/pizza.rsi heldPrefix: box + shape: + - 0,0,1,1 - type: Appearance - type: EntityStorageVisuals stateDoorOpen: box-open diff --git a/Resources/Prototypes/Entities/Objects/Consumable/Food/meals.yml b/Resources/Prototypes/Entities/Objects/Consumable/Food/meals.yml index 8a90468199..33c2a39d7f 100644 --- a/Resources/Prototypes/Entities/Objects/Consumable/Food/meals.yml +++ b/Resources/Prototypes/Entities/Objects/Consumable/Food/meals.yml @@ -10,6 +10,8 @@ abstract: true description: A delicious meal, cooked with love. components: + - type: Item + storedRotation: -90 - type: Food - type: Sprite sprite: Objects/Consumable/Food/meals.rsi diff --git a/Resources/Prototypes/Entities/Objects/Consumable/Food/noodles.yml b/Resources/Prototypes/Entities/Objects/Consumable/Food/noodles.yml index d8817ab86d..6e588a3efc 100644 --- a/Resources/Prototypes/Entities/Objects/Consumable/Food/noodles.yml +++ b/Resources/Prototypes/Entities/Objects/Consumable/Food/noodles.yml @@ -7,6 +7,8 @@ abstract: true description: Now that's a nice pasta! components: + - type: Item + storedRotation: -90 - type: Sprite sprite: Objects/Consumable/Food/noodles.rsi - type: SolutionContainerManager diff --git a/Resources/Prototypes/Entities/Objects/Consumable/Food/skewer.yml b/Resources/Prototypes/Entities/Objects/Consumable/Food/skewer.yml index c313f2d046..51bf229f2c 100644 --- a/Resources/Prototypes/Entities/Objects/Consumable/Food/skewer.yml +++ b/Resources/Prototypes/Entities/Objects/Consumable/Food/skewer.yml @@ -19,6 +19,7 @@ Quantity: 8 - type: Item size: Small + storedRotation: -90 # Kebabs diff --git a/Resources/Prototypes/Entities/Objects/Consumable/Food/snacks.yml b/Resources/Prototypes/Entities/Objects/Consumable/Food/snacks.yml index f9cf223114..27f2bdbce2 100644 --- a/Resources/Prototypes/Entities/Objects/Consumable/Food/snacks.yml +++ b/Resources/Prototypes/Entities/Objects/Consumable/Food/snacks.yml @@ -451,6 +451,7 @@ - type: Item sprite: Objects/Consumable/Food/snacks.rsi heldPrefix: packet + size: Tiny - type: Tag tags: - Trash @@ -469,7 +470,6 @@ components: - type: Sprite state: boritos-trash - - type: Item - type: entity noSpawn: true @@ -479,7 +479,6 @@ components: - type: Sprite state: cnds-trash - - type: Item - type: entity noSpawn: true @@ -489,7 +488,6 @@ components: - type: Sprite state: cheesiehonkers-trash - - type: Item - type: entity noSpawn: true @@ -499,7 +497,6 @@ components: - type: Sprite state: chips-trash - - type: Item - type: entity noSpawn: true @@ -509,7 +506,6 @@ components: - type: Sprite state: chocolatebar-trash - - type: Item - type: entity noSpawn: true @@ -519,7 +515,6 @@ components: - type: Sprite state: energybar-trash - - type: Item - type: entity noSpawn: true @@ -529,7 +524,6 @@ components: - type: Sprite state: pistachio-trash - - type: Item - type: entity noSpawn: true @@ -539,7 +533,6 @@ components: - type: Sprite state: popcorn-trash - - type: Item - type: entity noSpawn: true @@ -549,7 +542,6 @@ components: - type: Sprite state: raisins-trash - - type: Item - type: entity noSpawn: true @@ -559,7 +551,6 @@ components: - type: Sprite state: semki-trash - - type: Item - type: entity noSpawn: true @@ -569,7 +560,6 @@ components: - type: Sprite state: susjerky-trash - - type: Item - type: entity noSpawn: true @@ -579,7 +569,6 @@ components: - type: Sprite state: syndicakes-trash - - type: Item - type: entity noSpawn: true @@ -589,7 +578,6 @@ components: - type: Sprite state: chinese1 - - type: Item - type: entity noSpawn: true @@ -599,7 +587,6 @@ components: - type: Sprite state: chinese2 - - type: Item - type: entity noSpawn: true diff --git a/Resources/Prototypes/Entities/Objects/Consumable/Food/soup.yml b/Resources/Prototypes/Entities/Objects/Consumable/Food/soup.yml index 0dca39ea48..3b080e843b 100644 --- a/Resources/Prototypes/Entities/Objects/Consumable/Food/soup.yml +++ b/Resources/Prototypes/Entities/Objects/Consumable/Food/soup.yml @@ -5,6 +5,8 @@ id: FoodBowlBase abstract: true components: + - type: Item + storedRotation: -90 - type: Food trash: FoodBowlBig utensil: Spoon diff --git a/Resources/Prototypes/Entities/Objects/Consumable/Food/taco.yml b/Resources/Prototypes/Entities/Objects/Consumable/Food/taco.yml index 72d20624a4..9df2f3039e 100644 --- a/Resources/Prototypes/Entities/Objects/Consumable/Food/taco.yml +++ b/Resources/Prototypes/Entities/Objects/Consumable/Food/taco.yml @@ -6,6 +6,8 @@ id: FoodTacoShell description: A taco shell, easy to hold, but falls on its side when put down. components: + - type: Item + storedRotation: -90 - type: Food - type: Sprite sprite: Objects/Consumable/Food/taco.rsi @@ -44,6 +46,7 @@ Quantity: 4 - type: Item sprite: Objects/Consumable/Food/taco.rsi + storedRotation: -90 - type: Tag tags: - Meat diff --git a/Resources/Prototypes/Entities/Objects/Decoration/flora.yml b/Resources/Prototypes/Entities/Objects/Decoration/flora.yml index 791127170f..6a622d7bea 100644 --- a/Resources/Prototypes/Entities/Objects/Decoration/flora.yml +++ b/Resources/Prototypes/Entities/Objects/Decoration/flora.yml @@ -484,3 +484,87 @@ components: - type: Sprite state: tree06 + +- type: entity + parent: BaseTree + id: LightTree01 + name: glowing tree + description: a marvelous tree filled with strange energy. + components: + - type: PointLight + radius: 2.0 + energy: 4.5 + color: "#6270bb" + - type: Sprite + sprite: Objects/Decoration/Flora/flora_treeslight.rsi + state: tree01 + - type: Destructible + thresholds: + - trigger: + !type:DamageTrigger + damage: 400 + behaviors: + - !type:DoActsBehavior + acts: [ "Destruction" ] + - trigger: + !type:DamageTrigger + damage: 25 + behaviors: + - !type:PlaySoundBehavior + sound: + path: /Audio/Effects/tree_fell.ogg + params: + volume: 5 + variation: 0.05 + - !type:DoActsBehavior + acts: [ "Destruction" ] + - !type:SpawnEntitiesBehavior + spawn: + Log: + min: 0 + max: 1 + - !type:SpawnEntitiesBehavior + spawn: + MobLuminousObject: + min: 0 + max: 1 + +- type: entity + parent: LightTree01 + id: LightTree02 + components: + - type: Sprite + sprite: Objects/Decoration/Flora/flora_treeslight.rsi + state: tree02 + +- type: entity + parent: LightTree01 + id: LightTree03 + components: + - type: Sprite + sprite: Objects/Decoration/Flora/flora_treeslight.rsi + state: tree03 + +- type: entity + parent: LightTree01 + id: LightTree04 + components: + - type: Sprite + sprite: Objects/Decoration/Flora/flora_treeslight.rsi + state: tree04 + +- type: entity + parent: LightTree01 + id: LightTree05 + components: + - type: Sprite + sprite: Objects/Decoration/Flora/flora_treeslight.rsi + state: tree05 + +- type: entity + parent: LightTree01 + id: LightTree06 + components: + - type: Sprite + sprite: Objects/Decoration/Flora/flora_treeslight.rsi + state: tree06 diff --git a/Resources/Prototypes/Entities/Objects/Devices/Circuitboards/misc.yml b/Resources/Prototypes/Entities/Objects/Devices/Circuitboards/misc.yml index a4275995dc..cb35219eb0 100644 --- a/Resources/Prototypes/Entities/Objects/Devices/Circuitboards/misc.yml +++ b/Resources/Prototypes/Entities/Objects/Devices/Circuitboards/misc.yml @@ -4,6 +4,8 @@ name: station map electronics description: An electronics board used in station maps. components: + - type: Item + storedRotation: 0 - type: Sprite sprite: Objects/Misc/module.rsi state: airalarm_electronics diff --git a/Resources/Prototypes/Entities/Objects/Devices/Electronics/atmos_alarms.yml b/Resources/Prototypes/Entities/Objects/Devices/Electronics/atmos_alarms.yml index b54d21750d..838ec637d3 100644 --- a/Resources/Prototypes/Entities/Objects/Devices/Electronics/atmos_alarms.yml +++ b/Resources/Prototypes/Entities/Objects/Devices/Electronics/atmos_alarms.yml @@ -19,6 +19,8 @@ name: fire alarm electronics description: An electronics board used in fire alarms components: + - type: Item + storedRotation: 0 - type: Sprite sprite: Objects/Misc/module.rsi state: airalarm_electronics diff --git a/Resources/Prototypes/Entities/Objects/Devices/Electronics/base_electronics.yml b/Resources/Prototypes/Entities/Objects/Devices/Electronics/base_electronics.yml index 8ee76d43e9..7848d987e5 100644 --- a/Resources/Prototypes/Entities/Objects/Devices/Electronics/base_electronics.yml +++ b/Resources/Prototypes/Entities/Objects/Devices/Electronics/base_electronics.yml @@ -1,17 +1,19 @@ -- type: entity +- type: entity id: BaseElectronics parent: BaseItem name: base electronics abstract: true suffix: Electronics components: - - type: Sprite - sprite: Objects/Misc/module.rsi - state: generic - - type: StaticPrice - price: 100 - - type: PhysicalComposition - materialComposition: - Glass: 200 - chemicalComposition: - Silicon: 20 + - type: Item + storedRotation: -90 + - type: Sprite + sprite: Objects/Misc/module.rsi + state: generic + - type: StaticPrice + price: 100 + - type: PhysicalComposition + materialComposition: + Glass: 200 + chemicalComposition: + Silicon: 20 diff --git a/Resources/Prototypes/Entities/Objects/Devices/Electronics/firelock.yml b/Resources/Prototypes/Entities/Objects/Devices/Electronics/firelock.yml index 00b928f2ec..c7fa8f9ecd 100644 --- a/Resources/Prototypes/Entities/Objects/Devices/Electronics/firelock.yml +++ b/Resources/Prototypes/Entities/Objects/Devices/Electronics/firelock.yml @@ -4,6 +4,8 @@ name: firelock electronics description: An electronics board used to detect differences in pressure, temperature and gas concentrations between the two sides of the door. components: + - type: Item + storedRotation: 0 - type: Sprite sprite: Objects/Misc/module.rsi state: mainboard diff --git a/Resources/Prototypes/Entities/Objects/Devices/Electronics/mech.yml b/Resources/Prototypes/Entities/Objects/Devices/Electronics/mech.yml index 6657418488..f224c1c2bf 100644 --- a/Resources/Prototypes/Entities/Objects/Devices/Electronics/mech.yml +++ b/Resources/Prototypes/Entities/Objects/Devices/Electronics/mech.yml @@ -6,6 +6,8 @@ name: ripley central control module description: The electrical control center for the ripley mech. components: + - type: Item + storedRotation: 0 - type: Sprite sprite: Objects/Misc/module.rsi state: mainboard @@ -40,6 +42,8 @@ name: H.O.N.K. central control module description: The electrical control center for the H.O.N.K. mech. components: + - type: Item + storedRotation: 0 - type: Sprite sprite: Objects/Misc/module.rsi state: mainboard @@ -90,6 +94,8 @@ name: HAMTR central control module description: The electrical control center for the HAMTR mech. components: + - type: Item + storedRotation: 0 - type: Sprite sprite: Objects/Misc/module.rsi state: mainboard diff --git a/Resources/Prototypes/Entities/Objects/Devices/holoprojectors.yml b/Resources/Prototypes/Entities/Objects/Devices/holoprojectors.yml index 4924a46fe8..0066e3fbe8 100644 --- a/Resources/Prototypes/Entities/Objects/Devices/holoprojectors.yml +++ b/Resources/Prototypes/Entities/Objects/Devices/holoprojectors.yml @@ -4,6 +4,8 @@ name: holographic sign projector description: A handy-dandy holographic projector that displays a janitorial sign. components: + - type: Item + storedRotation: -90 - type: HolosignProjector - type: UseDelay - type: ContainerContainer diff --git a/Resources/Prototypes/Entities/Objects/Fun/toys.yml b/Resources/Prototypes/Entities/Objects/Fun/toys.yml index 3e1c056419..5566b65bf4 100644 --- a/Resources/Prototypes/Entities/Objects/Fun/toys.yml +++ b/Resources/Prototypes/Entities/Objects/Fun/toys.yml @@ -51,7 +51,7 @@ reagents: - ReagentId: Fiber Quantity: 10 - + - type: entity parent: BasePlushie id: PlushieGhost @@ -273,6 +273,11 @@ wideAnimationRotation: 180 soundHit: path: /Audio/Items/Toys/weh.ogg + - type: Extractable + juiceSolution: + reagents: + - ReagentId: JuiceThatMakesYouWeh + Quantity: 30 - type: entity parent: PlushieLizard @@ -311,6 +316,11 @@ wideAnimationRotation: 180 soundHit: path: /Audio/Items/Toys/muffled_weh.ogg + - type: Extractable + juiceSolution: + reagents: + - ReagentId: JuiceThatMakesYouWeh + Quantity: 30 - type: entity parent: BasePlushie @@ -398,6 +408,7 @@ state: blue - type: Item heldPrefix: blue + storedRotation: -90 - type: Tag tags: - PlushieSharkBlue @@ -467,6 +478,7 @@ state: carpplush - type: Item heldPrefix: carpplush + storedRotation: -90 - type: EmitSoundOnUse sound: path: /Audio/Effects/bite.ogg @@ -679,7 +691,7 @@ - type: EmitSoundOnTrigger sound: path: /Audio/Voice/Human/malescream_5.ogg - + - type: entity parent: BasePlushie id: PlushieMoth diff --git a/Resources/Prototypes/Entities/Objects/Misc/candy_bowl.yml b/Resources/Prototypes/Entities/Objects/Misc/candy_bowl.yml index 843b402a6c..fe275e3be3 100644 --- a/Resources/Prototypes/Entities/Objects/Misc/candy_bowl.yml +++ b/Resources/Prototypes/Entities/Objects/Misc/candy_bowl.yml @@ -55,9 +55,11 @@ shape: !type:PhysShapeAabb bounds: "-0.10,-0.10,0.10,0.10" - density: 3 + density: 20 mask: - - TabletopMachineMask + - TabletopMachineMask + restitution: 0.3 + friction: 0.2 - type: InteractionOutline - type: ItemMapper sprite: Objects/Misc/candy_bowl.rsi diff --git a/Resources/Prototypes/Entities/Objects/Misc/handcuffs.yml b/Resources/Prototypes/Entities/Objects/Misc/handcuffs.yml index 2e33ef24a3..ad0e724358 100644 --- a/Resources/Prototypes/Entities/Objects/Misc/handcuffs.yml +++ b/Resources/Prototypes/Entities/Objects/Misc/handcuffs.yml @@ -25,6 +25,8 @@ - type: GuideHelp guides: - Security + - type: UseDelay + delay: 6 - type: entity name: makeshift handcuffs @@ -148,9 +150,6 @@ - type: Handcuff cuffedRSI: Clothing/OuterClothing/Misc/straight_jacket.rsi breakoutTime: 100 - damageOnResist: - types: - Blunt: 0 cuffTime: 10 uncuffTime: 10 stunBonus: 4 diff --git a/Resources/Prototypes/Entities/Objects/Misc/kudzu.yml b/Resources/Prototypes/Entities/Objects/Misc/kudzu.yml index 6ebf095117..5de1f0b7f9 100644 --- a/Resources/Prototypes/Entities/Objects/Misc/kudzu.yml +++ b/Resources/Prototypes/Entities/Objects/Misc/kudzu.yml @@ -135,15 +135,12 @@ offset: 0.2 chance: 0.05 prototypes: - - FloraTree01 - - FloraTree02 - - FloraTree03 - - FloraTree04 - - FloraTree05 - - FloraTree06 - - FloraTreeLarge01 - - FloraTreeLarge02 - - FloraTreeLarge03 + - LightTree01 + - LightTree02 + - LightTree03 + - LightTree04 + - LightTree05 + - LightTree06 - CrystalCyan rarePrototypes: - AnomalyFloraBulb @@ -154,13 +151,15 @@ parent: KudzuFlowerFriendly components: - type: Kudzu - spreadChance: 0.4 + spreadChance: 0.2 - type: RandomSpawner - chance: 0.1 + chance: 0.05 rarePrototypes: - AnomalyFloraBulb + - AnomalyFloraBulb - MobLuminousEntity - MobLuminousObject + - MobLuminousPerson - type: entity id: FleshKudzu diff --git a/Resources/Prototypes/Entities/Objects/Misc/paper.yml b/Resources/Prototypes/Entities/Objects/Misc/paper.yml index aeef66624b..28cf22118e 100644 --- a/Resources/Prototypes/Entities/Objects/Misc/paper.yml +++ b/Resources/Prototypes/Entities/Objects/Misc/paper.yml @@ -18,6 +18,7 @@ - type: ActivatableUI key: enum.PaperUiKey.Key closeOnHandDeselect: false + requireHands: false - type: UserInterface interfaces: - key: enum.PaperUiKey.Key diff --git a/Resources/Prototypes/Entities/Objects/Misc/tiles.yml b/Resources/Prototypes/Entities/Objects/Misc/tiles.yml index 286e28c53d..9a2196612d 100644 --- a/Resources/Prototypes/Entities/Objects/Misc/tiles.yml +++ b/Resources/Prototypes/Entities/Objects/Misc/tiles.yml @@ -1026,3 +1026,22 @@ - FloorAstroIce - type: Stack stackType: FloorTileAstroIce + +- type: entity + name: large wood floor + parent: FloorTileItemBase + id: FloorTileItemWoodLarge + components: + - type: Sprite + state: wood-large + - type: Item + heldPrefix: wood + - type: FloorTile + outputs: + - Plating + - FloorWoodLarge + - type: Stack + stackType: FloorTileWoodLarge + - type: Construction + graph: TileWoodLarge + node: woodtilelarge \ No newline at end of file diff --git a/Resources/Prototypes/Entities/Objects/Power/powercells.yml b/Resources/Prototypes/Entities/Objects/Power/powercells.yml index 8aefe5e931..7397bcaa51 100644 --- a/Resources/Prototypes/Entities/Objects/Power/powercells.yml +++ b/Resources/Prototypes/Entities/Objects/Power/powercells.yml @@ -3,6 +3,8 @@ abstract: true parent: BaseItem components: + - type: Item + storedRotation: -90 - type: Battery pricePerJoule: 0.15 - type: PowerCell diff --git a/Resources/Prototypes/Entities/Objects/Specific/Medical/handheld_crew_monitor.yml b/Resources/Prototypes/Entities/Objects/Specific/Medical/handheld_crew_monitor.yml index 72e8373cab..6dfe039cc0 100644 --- a/Resources/Prototypes/Entities/Objects/Specific/Medical/handheld_crew_monitor.yml +++ b/Resources/Prototypes/Entities/Objects/Specific/Medical/handheld_crew_monitor.yml @@ -1,5 +1,6 @@ - type: entity name: handheld crew monitor + suffix: DO NOT MAP parent: - BaseItem - PowerCellSlotSmallItem @@ -30,6 +31,11 @@ - type: StationLimitedNetwork - type: StaticPrice price: 500 + - type: Tag + tags: + - HighRiskItem + - type: StealTarget + stealGroup: HandheldCrewMonitor - type: entity id: HandheldCrewMonitorEmpty diff --git a/Resources/Prototypes/Entities/Objects/Specific/Medical/healing.yml b/Resources/Prototypes/Entities/Objects/Specific/Medical/healing.yml index 9b17d7ed32..de014c8912 100644 --- a/Resources/Prototypes/Entities/Objects/Specific/Medical/healing.yml +++ b/Resources/Prototypes/Entities/Objects/Specific/Medical/healing.yml @@ -166,6 +166,7 @@ state: medicated-suture - type: Item heldPrefix: medicated-suture + storedRotation: -90 - type: Healing damageContainers: - Biological diff --git a/Resources/Prototypes/Entities/Objects/Specific/Medical/morgue.yml b/Resources/Prototypes/Entities/Objects/Specific/Medical/morgue.yml index 9d1398c6ca..bafcd928bf 100644 --- a/Resources/Prototypes/Entities/Objects/Specific/Medical/morgue.yml +++ b/Resources/Prototypes/Entities/Objects/Specific/Medical/morgue.yml @@ -102,6 +102,8 @@ name: ash description: This used to be something, but now it's not. components: + - type: Item + size: Tiny - type: Sprite sprite: Objects/Materials/materials.rsi state: ash diff --git a/Resources/Prototypes/Entities/Objects/Specific/Robotics/borg_modules.yml b/Resources/Prototypes/Entities/Objects/Specific/Robotics/borg_modules.yml index 943fdad518..2519611c68 100644 --- a/Resources/Prototypes/Entities/Objects/Specific/Robotics/borg_modules.yml +++ b/Resources/Prototypes/Entities/Objects/Specific/Robotics/borg_modules.yml @@ -5,6 +5,8 @@ description: A piece of tech that gives cyborgs new abilities. abstract: true components: + - type: Item + storedRotation: -90 - type: Sprite sprite: Objects/Specific/Robotics/borgmodule.rsi - type: BorgModule @@ -238,7 +240,7 @@ - WelderExperimental - NetworkConfigurator - RemoteSignaller - - GasAnalyzer + - GasAnalyzer - GeigerCounter - type: entity @@ -490,7 +492,7 @@ - BikeHorn - ClownRecorder - BikeHornInstrument - + #syndicate modules - type: entity id: BorgModuleSyndicateWeapon diff --git a/Resources/Prototypes/Entities/Objects/Tools/emag.yml b/Resources/Prototypes/Entities/Objects/Tools/emag.yml index 702b7c86be..0117d44d6d 100644 --- a/Resources/Prototypes/Entities/Objects/Tools/emag.yml +++ b/Resources/Prototypes/Entities/Objects/Tools/emag.yml @@ -1,18 +1,3 @@ -- type: entity - parent: BaseItem - id: Emag - name: cryptographic sequencer - description: The all-in-one hacking solution. The thinking man's lockpick. The iconic EMAG. - components: - - type: Emag - - type: LimitedCharges - - type: AutoRecharge - - type: Sprite - sprite: Objects/Tools/emag.rsi - state: icon - - type: Item - sprite: Objects/Tools/emag.rsi - - type: entity parent: BaseItem id: EmagUnlimited @@ -26,3 +11,12 @@ state: icon - type: Item sprite: Objects/Tools/emag.rsi + storedRotation: -90 + +- type: entity + parent: EmagUnlimited + id: Emag + suffix: Limited + components: + - type: LimitedCharges + - type: AutoRecharge diff --git a/Resources/Prototypes/Entities/Objects/Tools/welders.yml b/Resources/Prototypes/Entities/Objects/Tools/welders.yml index 60dfe0f136..42b16ba053 100644 --- a/Resources/Prototypes/Entities/Objects/Tools/welders.yml +++ b/Resources/Prototypes/Entities/Objects/Tools/welders.yml @@ -183,8 +183,8 @@ Welder: reagents: - ReagentId: WeldingFuel - Quantity: 25 - maxVol: 25 + Quantity: 50 + maxVol: 50 - type: Tool speed: 0.7 - type: PointLight diff --git a/Resources/Prototypes/Entities/Objects/Weapons/Guns/Ammunition/Projectiles/grenade.yml b/Resources/Prototypes/Entities/Objects/Weapons/Guns/Ammunition/Projectiles/grenade.yml index ec62121c6b..7f0507d686 100644 --- a/Resources/Prototypes/Entities/Objects/Weapons/Guns/Ammunition/Projectiles/grenade.yml +++ b/Resources/Prototypes/Entities/Objects/Weapons/Guns/Ammunition/Projectiles/grenade.yml @@ -12,8 +12,6 @@ damage: types: Blunt: 4 - - type: CanPenetrate - penetrationLayer: MobLayer - type: StaminaDamageOnCollide damage: 55 - type: TimedDespawn @@ -33,8 +31,6 @@ damage: types: Piercing: 45 - - type: CanPenetrate - penetrationLayer: MobLayer - type: TimedDespawn lifetime: 0.25 @@ -53,8 +49,6 @@ types: Blunt: 1 Heat: 2 - - type: CanPenetrate - penetrationLayer: MobLayer - type: IgniteOnCollide fireStacks: 3 count: 10 diff --git a/Resources/Prototypes/Entities/Objects/Weapons/Guns/Launchers/launchers.yml b/Resources/Prototypes/Entities/Objects/Weapons/Guns/Launchers/launchers.yml index ecabe2a4ab..8b31bf40ed 100644 --- a/Resources/Prototypes/Entities/Objects/Weapons/Guns/Launchers/launchers.yml +++ b/Resources/Prototypes/Entities/Objects/Weapons/Guns/Launchers/launchers.yml @@ -158,6 +158,8 @@ id: WeaponTetherGun description: Manipulates gravity around objects to fling them at high velocities. components: + - type: Item + storedRotation: -90 - type: TetherGun frequency: 5 dampingRatio: 4 @@ -195,6 +197,8 @@ id: WeaponForceGun description: Manipulates gravity around objects to fling them at high velocities. components: + - type: Item + storedRotation: -90 - type: ForceGun frequency: 15 dampingRatio: 4 diff --git a/Resources/Prototypes/Entities/Objects/Weapons/Guns/Projectiles/projectiles.yml b/Resources/Prototypes/Entities/Objects/Weapons/Guns/Projectiles/projectiles.yml index a5b0a8ffa3..9445a3cfe1 100644 --- a/Resources/Prototypes/Entities/Objects/Weapons/Guns/Projectiles/projectiles.yml +++ b/Resources/Prototypes/Entities/Objects/Weapons/Guns/Projectiles/projectiles.yml @@ -738,7 +738,7 @@ - type: PointLight radius: 3.5 color: blue - energy: 0.5 + energy: 0.5 - type: entity id: BulletCap @@ -810,8 +810,6 @@ mask: - Impassable - BulletImpassable - - type: CanPenetrate - penetrationLayer: MobLayer - type: Vapor active: true - type: Appearance diff --git a/Resources/Prototypes/Entities/Objects/Weapons/Melee/pickaxe.yml b/Resources/Prototypes/Entities/Objects/Weapons/Melee/pickaxe.yml index 21c1cedd01..cb9defccd9 100644 --- a/Resources/Prototypes/Entities/Objects/Weapons/Melee/pickaxe.yml +++ b/Resources/Prototypes/Entities/Objects/Weapons/Melee/pickaxe.yml @@ -42,9 +42,11 @@ id: MiningDrill description: Powerful tool used to quickly drill through rocks components: + - type: Item + storedRotation: -90 - type: Tag tags: - - Pickaxe + - Pickaxe - type: Sprite sprite: Objects/Tools/handdrill.rsi state: handdrill diff --git a/Resources/Prototypes/Entities/Structures/Power/Generation/PA/particles.yml b/Resources/Prototypes/Entities/Structures/Power/Generation/PA/particles.yml index 8f89c900ca..8d889ee5cb 100644 --- a/Resources/Prototypes/Entities/Structures/Power/Generation/PA/particles.yml +++ b/Resources/Prototypes/Entities/Structures/Power/Generation/PA/particles.yml @@ -19,7 +19,6 @@ damage: types: Radiation: 25 - - type: CanPenetrate - type: Physics - type: Fixtures fixtures: diff --git a/Resources/Prototypes/Entities/Structures/Wallmounts/Signs/posters.yml b/Resources/Prototypes/Entities/Structures/Wallmounts/Signs/posters.yml index f12cc613ce..cd4850d488 100644 --- a/Resources/Prototypes/Entities/Structures/Wallmounts/Signs/posters.yml +++ b/Resources/Prototypes/Entities/Structures/Wallmounts/Signs/posters.yml @@ -590,6 +590,15 @@ components: - type: Sprite state: poster62_contraband + +- type: entity + parent: PosterBase + id: PosterContrabandMissingSpacepen + name: "Missing Spacepen" + description: "This poster depicts something you will never find." + components: + - type: Sprite + state: poster63_contraband # Legit - type: entity diff --git a/Resources/Prototypes/Flavors/flavors.yml b/Resources/Prototypes/Flavors/flavors.yml index 9015d0a6bd..44d8847bae 100644 --- a/Resources/Prototypes/Flavors/flavors.yml +++ b/Resources/Prototypes/Flavors/flavors.yml @@ -1004,6 +1004,11 @@ flavorType: Complex description: flavor-complex-profits +- type: flavor + id: weh + flavorType: Base + description: flavor-weh + - type: flavor id: fishops flavorType: Complex diff --git a/Resources/Prototypes/Objectives/objectiveGroups.yml b/Resources/Prototypes/Objectives/objectiveGroups.yml index 7100fc34f3..abdc54fc5a 100644 --- a/Resources/Prototypes/Objectives/objectiveGroups.yml +++ b/Resources/Prototypes/Objectives/objectiveGroups.yml @@ -12,6 +12,7 @@ weights: CaptainIDStealObjective: 1 CMOHyposprayStealObjective: 1 + CMOCrewMonitorStealObjective: 1 RDHardsuitStealObjective: 1 NukeDiskStealObjective: 1 MagbootsStealObjective: 1 diff --git a/Resources/Prototypes/Objectives/stealTargetGroups.yml b/Resources/Prototypes/Objectives/stealTargetGroups.yml index 028c7c1939..d11478d1f9 100644 --- a/Resources/Prototypes/Objectives/stealTargetGroups.yml +++ b/Resources/Prototypes/Objectives/stealTargetGroups.yml @@ -7,6 +7,13 @@ sprite: Objects/Specific/Medical/hypospray.rsi state: hypo +- type: stealTargetGroup + id: HandheldCrewMonitor + name: handheld crew monitor + sprite: + sprite: Objects/Specific/Medical/handheldcrewmonitor.rsi + state: scanner + - type: stealTargetGroup id: ClothingOuterHardsuitRd name: experimental research hardsuit diff --git a/Resources/Prototypes/Objectives/traitor.yml b/Resources/Prototypes/Objectives/traitor.yml index 5a2d6880b8..6dc2ed46e7 100644 --- a/Resources/Prototypes/Objectives/traitor.yml +++ b/Resources/Prototypes/Objectives/traitor.yml @@ -147,35 +147,58 @@ ## cmo - type: entity - noSpawn: true + abstract: true parent: BaseTraitorStealObjective - id: CMOHyposprayStealObjective + id: BaseCMOStealObjective components: - type: NotJobRequirement job: ChiefMedicalOfficer - type: StealCondition - stealGroup: Hypospray owner: job-name-cmo +- type: entity + noSpawn: true + parent: BaseCMOStealObjective + id: CMOHyposprayStealObjective + components: + - type: StealCondition + stealGroup: Hypospray + +- type: entity + noSpawn: true + parent: BaseCMOStealObjective + id: CMOCrewMonitorStealObjective + components: + - type: StealCondition + stealGroup: HandheldCrewMonitor + ## rd - type: entity - noSpawn: true + abstract: true parent: BaseTraitorStealObjective - id: RDHardsuitStealObjective + id: BaseRDStealObjective components: + - type: NotJobRequirement + job: ResearchDirector - type: StealCondition - stealGroup: ClothingOuterHardsuitRd owner: job-name-rd - type: entity noSpawn: true - parent: BaseTraitorStealObjective + parent: BaseRDStealObjective + id: RDHardsuitStealObjective + components: + - type: StealCondition + stealGroup: ClothingOuterHardsuitRd + +- type: entity + noSpawn: true + parent: BaseRDStealObjective id: HandTeleporterStealObjective components: - type: StealCondition stealGroup: HandTeleporter - owner: job-name-rd ## hos diff --git a/Resources/Prototypes/Reagents/fun.yml b/Resources/Prototypes/Reagents/fun.yml index 25b0e8da80..9597627e87 100644 --- a/Resources/Prototypes/Reagents/fun.yml +++ b/Resources/Prototypes/Reagents/fun.yml @@ -41,7 +41,6 @@ conditions: - !type:OrganType type: Moth - - type: reagent id: BuzzochloricBees @@ -222,13 +221,13 @@ entity: IceCrust maxOnTileWhitelist: tags: [ Ice ] - - !type:ExtinguishTileReaction { } + - !type:ExtinguishTileReaction { } reactiveEffects: Acidic: methods: [ Touch ] effects: - !type:HealthChange - scaleByQuantity: true + scaleByQuantity: true ignoreResistances: false damage: types: @@ -236,7 +235,7 @@ - !type:AdjustTemperature conditions: - !type:Temperature - min: 160.15 + min: 160.15 amount: -30000 Extinguish: methods: [ Touch ] @@ -319,3 +318,33 @@ messages: [ "laughter-effect-control-laughter" ] probability: 0.2 +- type: reagent + id: JuiceThatMakesYouWeh + name: reagent-name-weh + group: Toxins + desc: reagent-desc-weh + physicalDesc: reagent-physical-desc-vibrant + flavor: weh + color: "#59b23a" + metabolisms: + Poison: + metabolismRate: 0.25 + effects: + - !type:Emote + emote: Weh + showInChat: true + probability: 0.5 + - !type:Polymorph + prototype: ArtifactLizard # Does the same thing as the original YML I made for this reagent. + conditions: + - !type:OrganType + type: Animal + shouldHave: false + - !type:ReagentThreshold + min: 50 + - !type:AdjustReagent + reagent: JuiceThatMakesYouWeh + amount: -20 + conditions: + - !type:ReagentThreshold + min: 50 diff --git a/Resources/Prototypes/Recipes/Crafting/Graphs/tiles.yml b/Resources/Prototypes/Recipes/Crafting/Graphs/tiles.yml index caff139192..4cb5d6c0f8 100644 --- a/Resources/Prototypes/Recipes/Crafting/Graphs/tiles.yml +++ b/Resources/Prototypes/Recipes/Crafting/Graphs/tiles.yml @@ -78,3 +78,19 @@ amount: 1 - node: fleshTile entity: FloorTileItemFlesh + +- type: constructionGraph + id: TileWoodLarge + start: start + graph: + - node: start + edges: + - to: woodtilelarge + completed: + - !type:SetStackCount + amount: 4 + steps: + - material: WoodPlank + amount: 2 + - node: woodtilelarge + entity: FloorTileItemWoodLarge \ No newline at end of file diff --git a/Resources/Prototypes/Recipes/Crafting/tiles.yml b/Resources/Prototypes/Recipes/Crafting/tiles.yml index 6050306597..1cabb7dedd 100644 --- a/Resources/Prototypes/Recipes/Crafting/tiles.yml +++ b/Resources/Prototypes/Recipes/Crafting/tiles.yml @@ -164,3 +164,14 @@ # description: "A dirty station tile." # icon: { sprite: Objects/Tiles/tile.rsi, state: dirty } # objectType: Item + +- type: construction + name: large wood floor + id: TileWoodLarge + graph: TileWoodLarge + startNode: start + targetNode: woodtilelarge + category: construction-category-tiles + description: "Four pieces of wooden station flooring." + icon: { sprite: Objects/Tiles/tile.rsi, state: wood-large } + objectType: Item \ No newline at end of file diff --git a/Resources/Prototypes/SoundCollections/emotes.yml b/Resources/Prototypes/SoundCollections/emotes.yml index 19b1b0e33d..1fbd88b48f 100644 --- a/Resources/Prototypes/SoundCollections/emotes.yml +++ b/Resources/Prototypes/SoundCollections/emotes.yml @@ -74,3 +74,8 @@ id: Squishes files: - /Audio/Voice/Slime/slime_squish.ogg + +- type: soundCollection + id: Weh + files: + - /Audio/Items/Toys/weh.ogg diff --git a/Resources/Prototypes/Stacks/floor_tile_stacks.yml b/Resources/Prototypes/Stacks/floor_tile_stacks.yml index 01acfd13f8..3b4efaff11 100644 --- a/Resources/Prototypes/Stacks/floor_tile_stacks.yml +++ b/Resources/Prototypes/Stacks/floor_tile_stacks.yml @@ -453,3 +453,9 @@ spawn: FloorTileItemAstroIce maxCount: 30 itemSize: 5 + +- type: stack + id: FloorTileWoodLarge + name: large wood floor + spawn: FloorTileItemWoodLarge + maxCount: 30 \ No newline at end of file diff --git a/Resources/Prototypes/Tiles/floors.yml b/Resources/Prototypes/Tiles/floors.yml index 431345b7bc..93d3aee34c 100644 --- a/Resources/Prototypes/Tiles/floors.yml +++ b/Resources/Prototypes/Tiles/floors.yml @@ -1862,3 +1862,23 @@ mobFrictionNoInput: 0.05 mobAcceleration: 2 itemDrop: FloorTileItemAstroIce + +- type: tile + id: FloorWoodLarge + name: tiles-wood-large + sprite: /Textures/Tiles/wood_large.png + variants: 4 + placementVariants: + - 1.0 + - 1.0 + - 1.0 + - 1.0 + baseTurf: Plating + isSubfloor: false + deconstructTools: [ Prying ] + footstepSounds: + collection: FootstepWood + barestepSounds: + collection: BarestepWood + itemDrop: FloorTileItemWoodLarge + heatCapacity: 10000 \ No newline at end of file diff --git a/Resources/Prototypes/Voice/speech_emote_sounds.yml b/Resources/Prototypes/Voice/speech_emote_sounds.yml index 3740b99521..ee76fa33d2 100644 --- a/Resources/Prototypes/Voice/speech_emote_sounds.yml +++ b/Resources/Prototypes/Voice/speech_emote_sounds.yml @@ -32,6 +32,8 @@ collection: MaleCry Whistle: collection: Whistles + Weh: + collection: Weh - type: emoteSounds id: FemaleHuman @@ -66,6 +68,8 @@ collection: FemaleCry Whistle: collection: Whistles + Weh: + collection: Weh - type: emoteSounds id: UnisexReptilian @@ -82,6 +86,8 @@ collection: Whistles Crying: collection: MaleCry + Weh: + collection: Weh - type: emoteSounds id: MaleSlime @@ -116,6 +122,8 @@ collection: MaleCry Whistle: collection: Whistles + Weh: + collection: Weh params: variation: 0.125 @@ -152,6 +160,8 @@ collection: FemaleCry Whistle: collection: Whistles + Weh: + collection: Weh params: variation: 0.125 @@ -175,10 +185,11 @@ collection: DionaLaugh Honk: collection: BikeHorn + Weh: + collection: Weh params: variation: 0.125 - - type: emoteSounds id: UnisexArachnid params: @@ -192,6 +203,8 @@ path: /Audio/Voice/Arachnid/arachnid_chitter.ogg Click: path: /Audio/Voice/Arachnid/arachnid_click.ogg + Weh: + collection: Weh - type: emoteSounds id: UnisexDwarf @@ -224,6 +237,8 @@ collection: MaleCry Whistle: collection: Whistles + Weh: + collection: Weh params: variation: 0.125 pitch: 0.75 @@ -259,6 +274,8 @@ collection: FemaleCry Whistle: collection: Whistles + Weh: + collection: Weh params: variation: 0.125 pitch: 0.75 @@ -278,6 +295,8 @@ path: /Audio/Voice/Moth/moth_chitter.ogg Squeak: path: /Audio/Voice/Moth/moth_squeak.ogg + Weh: + collection: Weh # body emotes - type: emoteSounds diff --git a/Resources/Prototypes/Voice/speech_emotes.yml b/Resources/Prototypes/Voice/speech_emotes.yml index 8f2cadf20d..fb6b0fbdcf 100644 --- a/Resources/Prototypes/Voice/speech_emotes.yml +++ b/Resources/Prototypes/Voice/speech_emotes.yml @@ -379,6 +379,11 @@ - зажужжала! # Corvax-Localization-End +- type: emote + id: Weh + category: Vocal + chatMessages: [Weh!] + - type: emote id: Chirp category: Vocal diff --git a/Resources/Prototypes/secret_weights.yml b/Resources/Prototypes/secret_weights.yml index 9e651a1044..ebeb784e42 100644 --- a/Resources/Prototypes/secret_weights.yml +++ b/Resources/Prototypes/secret_weights.yml @@ -1,7 +1,8 @@ - type: weightedRandom id: Secret weights: - Nukeops: 0.25 - Traitor: 0.65 + Nukeops: 0.20 + Traitor: 0.60 Zombie: 0.10 + Survival: 0.10 diff --git a/Resources/Textures/Interface/Ashen/slot_highlight.png b/Resources/Textures/Interface/Ashen/slot_highlight.png index 49d4c58f8a..0664478069 100644 Binary files a/Resources/Textures/Interface/Ashen/slot_highlight.png and b/Resources/Textures/Interface/Ashen/slot_highlight.png differ diff --git a/Resources/Textures/Interface/Clockwork/Storage/tile_blocked.png b/Resources/Textures/Interface/Clockwork/Storage/tile_blocked.png deleted file mode 100644 index 9a553a3e7b..0000000000 Binary files a/Resources/Textures/Interface/Clockwork/Storage/tile_blocked.png and /dev/null differ diff --git a/Resources/Textures/Interface/Clockwork/Storage/tile_blocked_opaque.png b/Resources/Textures/Interface/Clockwork/Storage/tile_blocked_opaque.png deleted file mode 100644 index c198cd3f97..0000000000 Binary files a/Resources/Textures/Interface/Clockwork/Storage/tile_blocked_opaque.png and /dev/null differ diff --git a/Resources/Textures/Interface/Default/Storage/tile_blocked.png b/Resources/Textures/Interface/Default/Storage/tile_blocked.png index 663f9b5ec5..d6896f1feb 100644 Binary files a/Resources/Textures/Interface/Default/Storage/tile_blocked.png and b/Resources/Textures/Interface/Default/Storage/tile_blocked.png differ diff --git a/Resources/Textures/Interface/Default/Storage/tile_blocked_opaque.png b/Resources/Textures/Interface/Default/Storage/tile_blocked_opaque.png index 16a65e36db..d6896f1feb 100644 Binary files a/Resources/Textures/Interface/Default/Storage/tile_blocked_opaque.png and b/Resources/Textures/Interface/Default/Storage/tile_blocked_opaque.png differ diff --git a/Resources/Textures/Interface/Plasmafire/Storage/tile_blocked.png b/Resources/Textures/Interface/Plasmafire/Storage/tile_blocked.png deleted file mode 100644 index 8c8303cd2e..0000000000 Binary files a/Resources/Textures/Interface/Plasmafire/Storage/tile_blocked.png and /dev/null differ diff --git a/Resources/Textures/Interface/Plasmafire/Storage/tile_blocked_opaque.png b/Resources/Textures/Interface/Plasmafire/Storage/tile_blocked_opaque.png deleted file mode 100644 index ed269d6023..0000000000 Binary files a/Resources/Textures/Interface/Plasmafire/Storage/tile_blocked_opaque.png and /dev/null differ diff --git a/Resources/Textures/Interface/Retro/Storage/tile_blocked.png b/Resources/Textures/Interface/Retro/Storage/tile_blocked.png deleted file mode 100644 index cedfcffb2b..0000000000 Binary files a/Resources/Textures/Interface/Retro/Storage/tile_blocked.png and /dev/null differ diff --git a/Resources/Textures/Interface/Retro/Storage/tile_blocked_opaque.png b/Resources/Textures/Interface/Retro/Storage/tile_blocked_opaque.png deleted file mode 100644 index cedfcffb2b..0000000000 Binary files a/Resources/Textures/Interface/Retro/Storage/tile_blocked_opaque.png and /dev/null differ diff --git a/Resources/Textures/Interface/Slimecore/Storage/tile_blocked.png b/Resources/Textures/Interface/Slimecore/Storage/tile_blocked.png deleted file mode 100644 index c5b1701f39..0000000000 Binary files a/Resources/Textures/Interface/Slimecore/Storage/tile_blocked.png and /dev/null differ diff --git a/Resources/Textures/Interface/Slimecore/Storage/tile_blocked_opaque.png b/Resources/Textures/Interface/Slimecore/Storage/tile_blocked_opaque.png deleted file mode 100644 index d7dd48d5a6..0000000000 Binary files a/Resources/Textures/Interface/Slimecore/Storage/tile_blocked_opaque.png and /dev/null differ diff --git a/Resources/Textures/Interface/home.png b/Resources/Textures/Interface/home.png index ccddb03caa..c1479f67cd 100644 Binary files a/Resources/Textures/Interface/home.png and b/Resources/Textures/Interface/home.png differ diff --git a/Resources/Textures/Mobs/Demons/ratvar.rsi/meta.json b/Resources/Textures/Mobs/Demons/ratvar.rsi/meta.json new file mode 100644 index 0000000000..3d85e4a650 --- /dev/null +++ b/Resources/Textures/Mobs/Demons/ratvar.rsi/meta.json @@ -0,0 +1,63 @@ +{ + "version": 1, + "license": "CC-BY-SA-3.0", + "copyright": "Taken from tgstation at https://github.com/tgstation/tgstation/blob/a28a7680cba9142ab80abc5ed480474ed0310462/icons/effects/512x512.dmi spawn animation kitbashed by MACMAN2003", + "size": { + "x": 512, + "y": 512 + }, + "states": [ + { + "name": "ratvar", + "delays": [ + [ + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1 + ] + ] + }, + { + "name": "spawn", + "delays": [ + [ + 0.3, + 0.3, + 0.25, + 0.25, + 1, + + 0.3, + 0.3, + 0.2, + 0.1, + 0.05, + + 0.05, + 0.05, + 0.05, + 0.05, + 0.05, + + 0.05, + 0.05, + 0.05, + 0.05 + ] + ] + } + ] +} \ No newline at end of file diff --git a/Resources/Textures/Mobs/Demons/ratvar.rsi/ratvar.png b/Resources/Textures/Mobs/Demons/ratvar.rsi/ratvar.png new file mode 100644 index 0000000000..bee7cdd1f0 Binary files /dev/null and b/Resources/Textures/Mobs/Demons/ratvar.rsi/ratvar.png differ diff --git a/Resources/Textures/Mobs/Demons/ratvar.rsi/spawn.png b/Resources/Textures/Mobs/Demons/ratvar.rsi/spawn.png new file mode 100644 index 0000000000..4f1c25b69c Binary files /dev/null and b/Resources/Textures/Mobs/Demons/ratvar.rsi/spawn.png differ diff --git a/Resources/Textures/Objects/Decoration/Flora/flora_treeslight.rsi/meta.json b/Resources/Textures/Objects/Decoration/Flora/flora_treeslight.rsi/meta.json new file mode 100644 index 0000000000..4820db2c63 --- /dev/null +++ b/Resources/Textures/Objects/Decoration/Flora/flora_treeslight.rsi/meta.json @@ -0,0 +1,29 @@ +{ + "version": 1, + "license": "CC-BY-SA-3.0", + "copyright": "Created by TheShuEd for Space Station 14", + "size": { + "x": 96, + "y": 96 + }, + "states": [ + { + "name": "tree01" + }, + { + "name": "tree02" + }, + { + "name": "tree03" + }, + { + "name": "tree04" + }, + { + "name": "tree05" + }, + { + "name": "tree06" + } + ] +} \ No newline at end of file diff --git a/Resources/Textures/Objects/Decoration/Flora/flora_treeslight.rsi/tree01.png b/Resources/Textures/Objects/Decoration/Flora/flora_treeslight.rsi/tree01.png new file mode 100644 index 0000000000..986b78b0cc Binary files /dev/null and b/Resources/Textures/Objects/Decoration/Flora/flora_treeslight.rsi/tree01.png differ diff --git a/Resources/Textures/Objects/Decoration/Flora/flora_treeslight.rsi/tree02.png b/Resources/Textures/Objects/Decoration/Flora/flora_treeslight.rsi/tree02.png new file mode 100644 index 0000000000..ffbf2c44ff Binary files /dev/null and b/Resources/Textures/Objects/Decoration/Flora/flora_treeslight.rsi/tree02.png differ diff --git a/Resources/Textures/Objects/Decoration/Flora/flora_treeslight.rsi/tree03.png b/Resources/Textures/Objects/Decoration/Flora/flora_treeslight.rsi/tree03.png new file mode 100644 index 0000000000..f37059eb97 Binary files /dev/null and b/Resources/Textures/Objects/Decoration/Flora/flora_treeslight.rsi/tree03.png differ diff --git a/Resources/Textures/Objects/Decoration/Flora/flora_treeslight.rsi/tree04.png b/Resources/Textures/Objects/Decoration/Flora/flora_treeslight.rsi/tree04.png new file mode 100644 index 0000000000..0461766bcd Binary files /dev/null and b/Resources/Textures/Objects/Decoration/Flora/flora_treeslight.rsi/tree04.png differ diff --git a/Resources/Textures/Objects/Decoration/Flora/flora_treeslight.rsi/tree05.png b/Resources/Textures/Objects/Decoration/Flora/flora_treeslight.rsi/tree05.png new file mode 100644 index 0000000000..26ac7f8b40 Binary files /dev/null and b/Resources/Textures/Objects/Decoration/Flora/flora_treeslight.rsi/tree05.png differ diff --git a/Resources/Textures/Objects/Decoration/Flora/flora_treeslight.rsi/tree06.png b/Resources/Textures/Objects/Decoration/Flora/flora_treeslight.rsi/tree06.png new file mode 100644 index 0000000000..01cda92099 Binary files /dev/null and b/Resources/Textures/Objects/Decoration/Flora/flora_treeslight.rsi/tree06.png differ diff --git a/Resources/Textures/Objects/Tiles/tile.rsi/meta.json b/Resources/Textures/Objects/Tiles/tile.rsi/meta.json index 9fc66d78b9..99b32632f1 100644 --- a/Resources/Textures/Objects/Tiles/tile.rsi/meta.json +++ b/Resources/Textures/Objects/Tiles/tile.rsi/meta.json @@ -414,6 +414,9 @@ { "name": "hydro-inhand-left", "directions": 4 + }, + { + "name": "wood-large" } ] } diff --git a/Resources/Textures/Objects/Tiles/tile.rsi/wood-large.png b/Resources/Textures/Objects/Tiles/tile.rsi/wood-large.png new file mode 100644 index 0000000000..429d0e1e8d Binary files /dev/null and b/Resources/Textures/Objects/Tiles/tile.rsi/wood-large.png differ diff --git a/Resources/Textures/Structures/Machines/computers.rsi/solar_screen.png b/Resources/Textures/Structures/Machines/computers.rsi/solar_screen.png index 90eb9eb5c6..47c9c9340f 100644 Binary files a/Resources/Textures/Structures/Machines/computers.rsi/solar_screen.png and b/Resources/Textures/Structures/Machines/computers.rsi/solar_screen.png differ diff --git a/Resources/Textures/Structures/Wallmounts/posters.rsi/meta.json b/Resources/Textures/Structures/Wallmounts/posters.rsi/meta.json index 5a9939041e..82d315b441 100644 --- a/Resources/Textures/Structures/Wallmounts/posters.rsi/meta.json +++ b/Resources/Textures/Structures/Wallmounts/posters.rsi/meta.json @@ -1 +1,436 @@ -{"version": 1, "license": "CC-BY-SA-3.0", "copyright": "Taken from at commit https://github.com/tgstation/tgstation/commit/f01de25493e2bd2706ef9b0303cb0d7b5e3e471b. poster52_contraband, poster53_contraband and poster54_contraband taken from https://github.com/vgstation-coders/vgstation13/blob/435ed5f2a7926e91cc31abac3a0d47d7e9ad7ed4/icons/obj/posters.dmi. originmap, poster55_contraband, poster56_contraband, poster57_contraband and poster39_legit by discord brainfood#7460. poster1_legit, poster3_contraband, poster3_legit, poster4_contraband, poster4_legit, poster5_contraband, poster5_legit, poster6_contraband, poster6_legit, poster7_contraband, poster7_legit, poster8_contraband, poster8_legit, poster9_contraband, poster9_legit, poster10_legit, poster11_legit, poster12_legit, poster13_legit, poster14_contraband, poster15_legit, poster16_contraband, poster16_legit, poster17_legit, poster19_legit, poster20_contraband, poster20_legit, poster21_contraband, poster21_legit, poster22_contraband, poster22_legit, poster23_contraband, poster23_legit, poster24_legit, poster25_contraband, poster26_legit, poster28_legit, poster29_contraband, poster29_legit, poster30_contraband, poster31_contraband, poster31_legit, poster32_contraband, poster32_legit, poster33_contraband, poster33_legit, poster34_legit, poster35_contraband, poster36_legit, poster37_legit, poster43_contraband, poster44_contraband, poster46_contraband, poster48_contraband, poster50_legit, poster51_legit, poster53_contraband, poster55_contraband, poster56_contraband, poster59_contraband, poster60_contraband edited and localised by github:lapatison", "size": {"x": 32, "y": 32}, "states": [{"name": "rolled_contraband"}, {"name": "rolled_legit"}, {"name": "poster_being_set", "delays": [[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]]}, {"name": "pinningposter"}, {"name": "poster_broken"}, {"name": "poster1_contraband"}, {"name": "poster2_contraband"}, {"name": "poster3_contraband"}, {"name": "poster4_contraband"}, {"name": "poster5_contraband"}, {"name": "poster6_contraband"}, {"name": "poster7_contraband"}, {"name": "poster8_contraband"}, {"name": "poster9_contraband"}, {"name": "poster10_contraband"}, {"name": "poster11_contraband"}, {"name": "poster12_contraband"}, {"name": "poster13_contraband"}, {"name": "poster14_contraband"}, {"name": "poster15_contraband"}, {"name": "poster16_contraband"}, {"name": "poster17_contraband"}, {"name": "poster18_contraband"}, {"name": "poster19_contraband"}, {"name": "poster20_contraband"}, {"name": "poster21_contraband"}, {"name": "poster22_contraband"}, {"name": "poster23_contraband"}, {"name": "poster24_contraband"}, {"name": "poster25_contraband"}, {"name": "poster26_contraband"}, {"name": "poster27_contraband"}, {"name": "poster28_contraband"}, {"name": "poster29_contraband"}, {"name": "poster30_contraband"}, {"name": "poster31_contraband"}, {"name": "poster32_contraband"}, {"name": "poster33_contraband"}, {"name": "poster35_contraband"}, {"name": "poster36_contraband"}, {"name": "poster37_contraband"}, {"name": "poster38_contraband"}, {"name": "poster39_contraband"}, {"name": "poster40_contraband"}, {"name": "poster41_contraband"}, {"name": "poster42_contraband"}, {"name": "poster43_contraband"}, {"name": "poster44_contraband"}, {"name": "poster45_contraband"}, {"name": "poster46_contraband"}, {"name": "poster47_contraband"}, {"name": "poster48_contraband"}, {"name": "poster50_contraband"}, {"name": "poster55_contraband"}, {"name": "poster56_contraband"}, {"name": "poster57_contraband"}, {"name": "poster58_contraband"}, {"name": "poster59_contraband"}, {"name": "poster60_contraband"}, {"name": "poster61_contraband"}, {"name": "poster62_contraband"}, {"name": "poster51_contraband"}, {"name": "poster1_legit"}, {"name": "poster2_legit"}, {"name": "poster3_legit"}, {"name": "poster4_legit"}, {"name": "poster5_legit"}, {"name": "poster6_legit"}, {"name": "poster7_legit"}, {"name": "poster8_legit"}, {"name": "poster9_legit"}, {"name": "poster10_legit"}, {"name": "poster11_legit"}, {"name": "poster12_legit"}, {"name": "poster13_legit"}, {"name": "poster14_legit"}, {"name": "poster15_legit"}, {"name": "poster16_legit"}, {"name": "poster17_legit"}, {"name": "poster18_legit"}, {"name": "poster19_legit"}, {"name": "poster20_legit"}, {"name": "poster21_legit"}, {"name": "poster22_legit"}, {"name": "poster23_legit"}, {"name": "poster24_legit"}, {"name": "poster25_legit"}, {"name": "poster26_legit"}, {"name": "poster27_legit"}, {"name": "poster28_legit"}, {"name": "poster29_legit"}, {"name": "poster30_legit"}, {"name": "poster31_legit"}, {"name": "poster32_legit"}, {"name": "poster33_legit"}, {"name": "poster34_legit"}, {"name": "poster35_legit"}, {"name": "poster36_legit"}, {"name": "poster37_legit"}, {"name": "poster38_legit"}, {"name": "poster39_legit"}, {"name": "poster40_legit"}, {"name": "poster41_legit"}, {"name": "poster42_legit"}, {"name": "poster43_legit"}, {"name": "poster44_legit"}, {"name": "poster45_legit"}, {"name": "poster46_legit"}, {"name": "poster47_legit"}, {"name": "poster48_legit"}, {"name": "poster49_legit"}, {"name": "poster50_legit"}, {"name": "poster51_legit"}, {"name": "random_legit"}, {"name": "random_contraband"}, {"name": "random_anything"}, {"name": "poster52_contraband", "directions": 1, "delays": [[1.0]]}, {"name": "poster53_contraband", "directions": 1, "delays": [[1.0]]}, {"name": "poster54_contraband", "directions": 1, "delays": [[1.0]]}, {"name": "bagelmap", "directions": 1, "delays": [[1.0]]}, {"name": "deltamap", "directions": 1, "delays": [[1.0]]}, {"name": "marathonmap", "directions": 1, "delays": [[1.0]]}, {"name": "originmap", "delays": [[1.0]]}, {"name": "moosemap", "directions": 1, "delays": [[1.0]]}, {"name": "packedmap", "directions": 1, "delays": [[1.0]]}, {"name": "pillarmap", "directions": 1, "delays": [[1.0]]}, {"name": "salternmap", "directions": 1, "delays": [[1.0]]}, {"name": "splitmap", "directions": 1, "delays": [[1.0]]}, {"name": "lighthousemap", "directions": 1, "delays": [[1.0]]}, {"name": "waystationmap", "directions": 1, "delays": [[1.0]]}]} +{ + "version": 1, + "license": "CC-BY-SA-3.0", + "copyright": "Taken from at commit https://github.com/tgstation/tgstation/commit/f01de25493e2bd2706ef9b0303cb0d7b5e3e471b. poster52_contraband, poster53_contraband and poster54_contraband taken from https://github.com/vgstation-coders/vgstation13/blob/435ed5f2a7926e91cc31abac3a0d47d7e9ad7ed4/icons/obj/posters.dmi. originmap, poster55_contraband, poster56_contraband, poster57_contraband and poster39_legit by discord brainfood#7460, poster63_contraband by discord foboscheshir_. poster1_legit, poster3_contraband, poster3_legit, poster4_contraband, poster4_legit, poster5_contraband, poster5_legit, poster6_contraband, poster6_legit, poster7_contraband, poster7_legit, poster8_contraband, poster8_legit, poster9_contraband, poster9_legit, poster10_legit, poster11_legit, poster12_legit, poster13_legit, poster14_contraband, poster15_legit, poster16_contraband, poster16_legit, poster17_legit, poster19_legit, poster20_contraband, poster20_legit, poster21_contraband, poster21_legit, poster22_contraband, poster22_legit, poster23_contraband, poster23_legit, poster24_legit, poster25_contraband, poster26_legit, poster28_legit, poster29_contraband, poster29_legit, poster30_contraband, poster31_contraband, poster31_legit, poster32_contraband, poster32_legit, poster33_contraband, poster33_legit, poster34_legit, poster35_contraband, poster36_legit, poster37_legit, poster43_contraband, poster44_contraband, poster46_contraband, poster48_contraband, poster50_legit, poster51_legit, poster53_contraband, poster55_contraband, poster56_contraband, poster59_contraband, poster60_contraband edited and localised by github:lapatison", + "size": { + "x": 32, + "y": 32 + }, + "states": [ + { + "name": "rolled_contraband" + }, + { + "name": "rolled_legit" + }, + { + "name": "poster_being_set", + "delays": [ + [ + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1 + ] + ] + }, + { + "name": "pinningposter" + }, + { + "name": "poster_broken" + }, + { + "name": "poster1_contraband" + }, + { + "name": "poster2_contraband" + }, + { + "name": "poster3_contraband" + }, + { + "name": "poster4_contraband" + }, + { + "name": "poster5_contraband" + }, + { + "name": "poster6_contraband" + }, + { + "name": "poster7_contraband" + }, + { + "name": "poster8_contraband" + }, + { + "name": "poster9_contraband" + }, + { + "name": "poster10_contraband" + }, + { + "name": "poster11_contraband" + }, + { + "name": "poster12_contraband" + }, + { + "name": "poster13_contraband" + }, + { + "name": "poster14_contraband" + }, + { + "name": "poster15_contraband" + }, + { + "name": "poster16_contraband" + }, + { + "name": "poster17_contraband" + }, + { + "name": "poster18_contraband" + }, + { + "name": "poster19_contraband" + }, + { + "name": "poster20_contraband" + }, + { + "name": "poster21_contraband" + }, + { + "name": "poster22_contraband" + }, + { + "name": "poster23_contraband" + }, + { + "name": "poster24_contraband" + }, + { + "name": "poster25_contraband" + }, + { + "name": "poster26_contraband" + }, + { + "name": "poster27_contraband" + }, + { + "name": "poster28_contraband" + }, + { + "name": "poster29_contraband" + }, + { + "name": "poster30_contraband" + }, + { + "name": "poster31_contraband" + }, + { + "name": "poster32_contraband" + }, + { + "name": "poster33_contraband" + }, + { + "name": "poster35_contraband" + }, + { + "name": "poster36_contraband" + }, + { + "name": "poster37_contraband" + }, + { + "name": "poster38_contraband" + }, + { + "name": "poster39_contraband" + }, + { + "name": "poster40_contraband" + }, + { + "name": "poster41_contraband" + }, + { + "name": "poster42_contraband" + }, + { + "name": "poster43_contraband" + }, + { + "name": "poster44_contraband" + }, + { + "name": "poster45_contraband" + }, + { + "name": "poster46_contraband" + }, + { + "name": "poster47_contraband" + }, + { + "name": "poster48_contraband" + }, + { + "name": "poster50_contraband" + }, + { + "name": "poster55_contraband" + }, + { + "name": "poster56_contraband" + }, + { + "name": "poster57_contraband" + }, + { + "name": "poster58_contraband" + }, + { + "name": "poster59_contraband" + }, + { + "name": "poster60_contraband" + }, + { + "name": "poster61_contraband" + }, + { + "name": "poster62_contraband" + }, + { + "name": "poster63_contraband" + }, + { + "name": "poster51_contraband" + }, + { + "name": "poster1_legit" + }, + { + "name": "poster2_legit" + }, + { + "name": "poster3_legit" + }, + { + "name": "poster4_legit" + }, + { + "name": "poster5_legit" + }, + { + "name": "poster6_legit" + }, + { + "name": "poster7_legit" + }, + { + "name": "poster8_legit" + }, + { + "name": "poster9_legit" + }, + { + "name": "poster10_legit" + }, + { + "name": "poster11_legit" + }, + { + "name": "poster12_legit" + }, + { + "name": "poster13_legit" + }, + { + "name": "poster14_legit" + }, + { + "name": "poster15_legit" + }, + { + "name": "poster16_legit" + }, + { + "name": "poster17_legit" + }, + { + "name": "poster18_legit" + }, + { + "name": "poster19_legit" + }, + { + "name": "poster20_legit" + }, + { + "name": "poster21_legit" + }, + { + "name": "poster22_legit" + }, + { + "name": "poster23_legit" + }, + { + "name": "poster24_legit" + }, + { + "name": "poster25_legit" + }, + { + "name": "poster26_legit" + }, + { + "name": "poster27_legit" + }, + { + "name": "poster28_legit" + }, + { + "name": "poster29_legit" + }, + { + "name": "poster30_legit" + }, + { + "name": "poster31_legit" + }, + { + "name": "poster32_legit" + }, + { + "name": "poster33_legit" + }, + { + "name": "poster34_legit" + }, + { + "name": "poster35_legit" + }, + { + "name": "poster36_legit" + }, + { + "name": "poster37_legit" + }, + { + "name": "poster38_legit" + }, + { + "name": "poster39_legit" + }, + { + "name": "poster40_legit" + }, + { + "name": "poster41_legit" + }, + { + "name": "poster42_legit" + }, + { + "name": "poster43_legit" + }, + { + "name": "poster44_legit" + }, + { + "name": "poster45_legit" + }, + { + "name": "poster46_legit" + }, + { + "name": "poster47_legit" + }, + { + "name": "poster48_legit" + }, + { + "name": "poster49_legit" + }, + { + "name": "poster50_legit" + }, + { + "name": "poster51_legit" + }, + { + "name": "random_legit" + }, + { + "name": "random_contraband" + }, + { + "name": "random_anything" + }, + { + "name": "poster52_contraband" + }, + { + "name": "poster53_contraband" + }, + { + "name": "poster54_contraband" + }, + { + "name": "bagelmap" + }, + { + "name": "deltamap" + }, + { + "name": "marathonmap" + }, + { + "name": "originmap" + }, + { + "name": "moosemap" + }, + { + "name": "packedmap" + }, + { + "name": "pillarmap" + }, + { + "name": "salternmap" + }, + { + "name": "splitmap" + }, + { + "name": "lighthousemap" + }, + { + "name": "waystationmap" + } + ] +} diff --git a/Resources/Textures/Structures/Wallmounts/posters.rsi/poster63_contraband.png b/Resources/Textures/Structures/Wallmounts/posters.rsi/poster63_contraband.png new file mode 100644 index 0000000000..3ecb203059 Binary files /dev/null and b/Resources/Textures/Structures/Wallmounts/posters.rsi/poster63_contraband.png differ diff --git a/Resources/Textures/Tiles/attributions.yml b/Resources/Textures/Tiles/attributions.yml index 417d3936f7..38351de3ee 100644 --- a/Resources/Textures/Tiles/attributions.yml +++ b/Resources/Textures/Tiles/attributions.yml @@ -124,4 +124,9 @@ - files: ["latticeTrain.png"] license: "CC0-1.0" copyright: "Created by TheShuEd (github) for space-station-14." - source: "https://github.com/space-wizards/space-station-14/pull/ED_INSERT_PR_CODE_HERE!" + source: "https://github.com/space-wizards/space-station-14/pull/24927" + +- files: ["wood_large.png"] + license: "CC0-1.0" + copyright: "Created by ps3moira (github) for space-station-14." + source: "https://github.com/space-wizards/space-station-14/" diff --git a/Resources/Textures/Tiles/wood_large.png b/Resources/Textures/Tiles/wood_large.png new file mode 100644 index 0000000000..722c462a08 Binary files /dev/null and b/Resources/Textures/Tiles/wood_large.png differ diff --git a/RobustToolbox b/RobustToolbox index ef0bc1a2e4..2694dce076 160000 --- a/RobustToolbox +++ b/RobustToolbox @@ -1 +1 @@ -Subproject commit ef0bc1a2e4878eedc24dd6fedc0631be56aca072 +Subproject commit 2694dce0766239075c92911dbd9b39efcc86e31d diff --git a/SpaceStation14.sln b/SpaceStation14.sln index b8ca8e3a9b..7af148ef24 100644 --- a/SpaceStation14.sln +++ b/SpaceStation14.sln @@ -129,6 +129,11 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Content.PatreonParser", "Co EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Robust.Analyzers.Tests", "RobustToolbox\Robust.Analyzers.Tests\Robust.Analyzers.Tests.csproj", "{83F510FE-9B50-4D96-AFAB-CC13998D6AFE}" EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Roslyn", "Roslyn", "{7844DA69-B0F0-49FB-A05E-ECA37372277A}" + ProjectSection(SolutionItems) = preProject + RobustToolbox\Robust.Roslyn.Shared\Robust.Roslyn.Shared.props = RobustToolbox\Robust.Roslyn.Shared\Robust.Roslyn.Shared.props + EndProjectSection +EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Corvax Interfaces", "Corvax Interfaces", "{DA6E23AF-5AC1-43C8-831D-812A2A758731}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Content.Corvax.Interfaces.Shared", "Corvax\Content.Corvax.Interfaces.Shared\Content.Corvax.Interfaces.Shared.csproj", "{F9F78EE1-1FBE-43F9-8E86-78327FE330DB}" @@ -489,17 +494,21 @@ Global {41B450C0-A361-4CD7-8121-7072B8995CFC} = {83B4CBBA-547A-42F0-A7CD-8A67D93196CE} {7B9472D3-79D4-48D1-9B22-BCDE518FE842} = {83B4CBBA-547A-42F0-A7CD-8A67D93196CE} {1FAE651D-29D8-437A-9864-47CE0D180016} = {83B4CBBA-547A-42F0-A7CD-8A67D93196CE} - {3CFEB7DB-12C6-46F3-89FC-1450F3016FFA} = {83B4CBBA-547A-42F0-A7CD-8A67D93196CE} {8922428F-17C3-47A7-BFE9-570DEB2464DA} = {83B4CBBA-547A-42F0-A7CD-8A67D93196CE} {16F7DE32-0186-44B9-9345-0C20D1BF2422} = {AFF53804-115F-4E67-B81F-26265EA27880} {AFF53804-115F-4E67-B81F-26265EA27880} = {83B4CBBA-547A-42F0-A7CD-8A67D93196CE} {23F09C45-950E-4DB7-A465-E937450FF008} = {AFF53804-115F-4E67-B81F-26265EA27880} {440426C1-8DCA-43F6-967F-94439B8DAF47} = {AFF53804-115F-4E67-B81F-26265EA27880} - {88B0FC0F-7209-40E2-AF16-EB90AF727C5B} = {83B4CBBA-547A-42F0-A7CD-8A67D93196CE} {A3C5B00A-D232-4A01-B82E-B0E58BFD5C12} = {83B4CBBA-547A-42F0-A7CD-8A67D93196CE} {8A21C7CA-2EB8-40E5-8043-33582C06D139} = {83B4CBBA-547A-42F0-A7CD-8A67D93196CE} {952AAF2A-DF63-4A7D-8094-3453893EBA80} = {83B4CBBA-547A-42F0-A7CD-8A67D93196CE} {A965CB3B-FD31-44AF-8872-85ABA436098D} = {83B4CBBA-547A-42F0-A7CD-8A67D93196CE} + {7844DA69-B0F0-49FB-A05E-ECA37372277A} = {83B4CBBA-547A-42F0-A7CD-8A67D93196CE} + {3CFEB7DB-12C6-46F3-89FC-1450F3016FFA} = {7844DA69-B0F0-49FB-A05E-ECA37372277A} + {6FBF108E-5CB5-47DE-8D7E-B496ABA9E3E2} = {7844DA69-B0F0-49FB-A05E-ECA37372277A} + {07CA34A1-1D37-4771-A2E3-495A1044AE0B} = {7844DA69-B0F0-49FB-A05E-ECA37372277A} + {88B0FC0F-7209-40E2-AF16-EB90AF727C5B} = {7844DA69-B0F0-49FB-A05E-ECA37372277A} + {83F510FE-9B50-4D96-AFAB-CC13998D6AFE} = {7844DA69-B0F0-49FB-A05E-ECA37372277A} {07CA34A1-1D37-4771-A2E3-495A1044AE0B} = {83B4CBBA-547A-42F0-A7CD-8A67D93196CE} {6FBF108E-5CB5-47DE-8D7E-B496ABA9E3E2} = {83B4CBBA-547A-42F0-A7CD-8A67D93196CE} {83F510FE-9B50-4D96-AFAB-CC13998D6AFE} = {83B4CBBA-547A-42F0-A7CD-8A67D93196CE}